Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make staticfy modular #5

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
*.pyc
*.htm
*.html
*-info
dist/
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ python:
# command to install dependencies
install: "pip install -r requirements.txt"
# command to run tests
script: python tests.py
script: python -m unittest
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
### Status

[![Build Status](https://travis-ci.org/danidee10/Staticfy.svg?branch=master)](https://travis-ci.org/danidee10/Staticfy) [![Code Climate](https://codeclimate.com/github/danidee10/Staticfy/badges/gpa.svg)](https://codeclimate.com/github/danidee10/Staticfy)

# Staticfy

You just got a brand new template fron the front-end designer, Everything's going well, Until you realize the amount of time you'll spend manually changing the links in the html templates you until all the static files and assets are properly linked and the file looks exactly like the demo he/she showed you.
with Staticfy you can save that time (and some of your hair) by automatically converting the static urls in your template to dynamic url's that wouldn't break if you decide to move your file to another location.

Expand All @@ -16,14 +18,17 @@ To this:
and then your web framework's templating language can resolve the tags to the right url.

# Get it in 10 seconds!

It's available as a package on PyPi so you can install it with

```bash
pip install staticfy
```

That's all!

Run it straight from the command line with:

```bash
staticfy staticfy.html --static-endpoint=static --add-tags='{"img": "data-url"}'
```
Expand All @@ -37,16 +42,19 @@ staticfy staticfy.html -o new.html
```

### Before Staticfying

![alt tag](assets/before.png)
---------------------------------------------------------------------------------------------------------------------------------
### After Staticfying

![alt tag](assets/after.png)

Notice how it preserves the font-awesome css link at the top of the file?, external resources (images, scripts, font-awesome, google-fonts, bootstrap files, disqus e.t.c) which aren't hosted locally with your website won't be staticfied. Staticfy also accepts an optional argument `--static-endpoint` in case you're not using the default static endpoint.

Staticy also preserves the indentation and formatting of any html file given to it, so your html file(s) are still look the same way and are still readablebe just the way they were before you staticfied them.

# Additional tags and attributes

By default staticfy identifies and staticfies the following tags:
1. img tags with src attributes -- `<img src="" />`
2. link tags with rel attributes -- `<link rel="" />`
Expand All @@ -61,9 +69,11 @@ staticfy staticfy.html --add-tags='{"div": "data-src"}'
Sure enough it gets staticfied.

### Before staticfying

![alt tag](assets/before_add_tag.png)

### After staticfying

![alt tag](assets/after_add_tag.png)

You can exclude certain tags you don't want to be staticfied by specifying the `--exc-tags` parameter, like `--add-tags` it expects a valid JSON string.
Expand All @@ -78,6 +88,7 @@ It should be noted that sub folders containing html files won't be staticfied, o
Whenever you run staticfy on a template or on a folder, a staticfy folder is generated in the present working directory and the staticfied file(s) is placed in that folder, you also need to copy the file(s) over to the appropriate directory to overwrite the existing file with the new one.

# Namespacing

When your project gets big, It's necessary to namespace static assets to avoid name collision, you can achieve this by passing a string to the `--namespace` argument. The string would automatically be prepended to the url. For example in django

```bash
Expand All @@ -88,6 +99,7 @@ Would convert `<img src="img/staticfy.jpg" />` to this `<img src="{% url static


# Inconsistency with single and double quotes in html

Staticfy also converts all single quoted html attributes to double quoted attributes. It's very common to see html files that look like this.

``` html
Expand All @@ -104,6 +116,7 @@ Staticfy also converts all single quoted html attributes to double quoted attrib

</html>
```

You can easily fix all the inconsistencies by running staticfy on that file. There also *little* performance benefits to be gained when you gzip an html file that has consistent use of quotes (either double or single) against an inconsistent one. Don't believe it...Look at this

![alt tag](assets/staticfy.gif)
Expand All @@ -113,7 +126,9 @@ You can see a reduction from `219 bytes` to `204 bytes`, of course this differen
HTML is a very forgiving, and you're allowed to use single quotes or double quotes. but the double quotes are the **Unofficial Standard**

# Using staticfy with other frameworks

Staticfy was initially built with flask in mind, but it can also be extended to support other frameworks easily, out of the box it supports:

1. flask
2. django and
3. laravel
Expand All @@ -128,27 +143,30 @@ export STATICFY_FRAMEWORK=django
If you specify a framework that isn't found, staticfy would cry and gracefully fall back to it's flask roots.

# Tests
The tests are located in the `test.py` file and can be run with:

`python3 test.py`
The tests can be run with the standard `unittest` module using:

`python -m unittest`

# Python support

Staticfy supports both python2 and python3
**(python 2.7 >)**

# Requirements and 3rd party stuff
Beautiful soup 4
`pip3 install bs4`

You can use the requirements file `pip3 install -r requirements.txt`
The only dependency is `Beautiful soup 4`

If you have issues with importing HTML.parser on python 3.5, upgrade beautifulSoup:
You can use the requirements file `pip install -r requirements.txt`

If you have issues with importing `HTML.parser` on `python 3.5`, upgrade `beautifulSoup` with:

`pip install --upgrade beautifulsoup4`

# Contribution

Pull requests and issues are highly welcome. I'm still looking to support as many web frameworks as possible.

Describe clearly what your PR attempts to fix (if it's a bug) or improve (If it's an existing feature).

If you want to add support for a new web framework, add the required pattern for the framework to the `frameworks` dictionary in `__config__.py`, make your tests pass and submit your Pull request.
If you want to add support for a new web framework, add the required pattern for the framework to the `frameworks` dictionary in `__config__.py`, (You may also need to create a plugin if it's not a simple transform) make your tests pass and submit your Pull request.
23 changes: 20 additions & 3 deletions bin/staticfy
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
#!/usr/bin/env/ python
#! /usr/bin/env/ python

from staticfy.staticfy import main
import yaml

main()
from staticfy import main


def load_config():
"""Load and Parse staticfy.yaml file."""
try:
with open('staticfy.yaml') as yaml_config_file:
config = yaml.load(yaml_config_file)
return config
except FileNotFoundError:
print(
'Warning: staticfy.yaml file was not found in the current directory'
)
return {'plugins': []}


config = load_config()
main(config)
Empty file added plugins/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions plugins/django_posthtml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""django plugin."""

from .posthtml import transform
57 changes: 57 additions & 0 deletions plugins/django_posthtml/posthtml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Django plugin for django templates."""

import re


def transform_extends_tag(html):
"""
Convert <extends src=".*" /> to {% extends ".*" %}.

Also remove the closing </extends> tag
"""
opening_regex = r'<extends src=[\'"](.*)[\'"]>'
closing_regex = r'</extends>'

html = re.sub(opening_regex, r'{% extends "\1" %}', html)
html = re.sub(closing_regex, '', html)

return html


def transform_include_tag(html):
"""Convert <include src=".*"></include> to {% include ".*" %}."""
include_regex = r'<include src=[\'"](.*/\w+/)*(\w+.html)[\'"]></include>'

html = re.sub(include_regex, r'{% include "\2" %}', html)

return html


def transform_block_tag(html):
"""
Convert <block src=".*" /> to {% extends ".*" %}.

Also convert the closing </block> to {% endblock %}
"""
opening_regex = r'<block name=[\'"](.*)[\'"]>'
closing_regex = r'</block>'

html = re.sub(opening_regex, r'{% block \1 %}', html)
html = re.sub(closing_regex, '{% endblock %}', html)

return html


def transform(file):
"""Transform posthtml to django templates."""
result = []

for line in file:
# Apply transforms
line = transform_extends_tag(line)
line = transform_include_tag(line)
line = transform_block_tag(line)

result.append(line)

return result
54 changes: 54 additions & 0 deletions plugins/django_posthtml/test_posthtml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Tests for the django plugin."""

import unittest

from .posthtml import transform


class DjangoTestCase(unittest.TestCase):
"""Tests for the django plugin."""

def test_extends_tag(self):
"""
The <extends> tag should be converted to {% extends ".*" %}.

The closing </extends> tag should also be removed.
"""
result = transform(
['<extends src="base.html">', '<p>Hello world</p>', '</extends>']
)

expected = ['{% extends "base.html" %}', '<p>Hello world</p>', '']

self.assertEqual(result, expected)

def test_include_tag(self):
"""The <include> tag should be converted to {% include ".*" %}."""
result = transform(
['<include src="base.html"></include>', '<p>Hello world</p>']
)

expected = ['{% include "base.html" %}', '<p>Hello world</p>']

self.assertEqual(result, expected)

def test_block_tag(self):
"""
The <block> tag should be converted to {% block .* %}.

The closing </block> tag should be converted to {% endblock %}
"""
result = transform(
['<block name="content">', '<p>Hello world</p>', '</block>']
)

expected = ['{% block content %}', '<p>Hello world</p>', '{% endblock %}']

self.assertEqual(result, expected)

def test_include_static_tag(self):
pass


if __name__ == '__main__':
unittest.main()
9 changes: 9 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
astroid==1.6.1
beautifulsoup4==4.5.1
isort==4.3.1
lazy-object-proxy==1.3.1
mccabe==0.6.1
pep8==1.7.1
pylint==1.8.2
PyYAML==3.12
six==1.11.0
wrapt==1.10.11
10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#!/usr/bin/env python

from setuptools import setup
from setuptools import setup, find_packages

setup(name='Staticfy',
version='1.7',
version='2.0',
description='Convert static assets links to dynamic web framework links',
url='https://github.com/danidee10/Staticfy',
author='Osaetin Daniel',
author_email='[email protected]',
license='GPL',
scripts = ['bin/staticfy'],
packages=['staticfy'],
scripts=['bin/staticfy'],
packages=find_packages(),
install_requires=[
'beautifulsoup4',
'beautifulsoup4', 'pyyaml'
],
zip_safe=False)
1 change: 1 addition & 0 deletions staticfy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins: [django_posthtml]
3 changes: 3 additions & 0 deletions staticfy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Initialize functions"""

from .staticfy import staticfy, main
Loading