├── .gitignore ├── .travis.yml ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── django_gears ├── __init__.py ├── finders.py ├── handlers.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── collectassets.py │ │ └── runserver.py ├── settings.py ├── templatetags │ ├── __init__.py │ └── gears.py ├── urls.py ├── utils.py └── views.py ├── docs ├── Makefile ├── _ext │ └── djangodoc.py ├── conf.py ├── deploying.rst ├── finders.rst ├── index.rst ├── installation.rst ├── make.bat ├── processing.rst ├── settings.rst ├── template-tags.rst ├── tutorial.rst └── views.rst ├── example ├── articles │ ├── __init__.py │ ├── assets │ │ └── js │ │ │ └── articles │ │ │ └── app.coffee │ └── models.py ├── manage.py ├── project │ ├── __init__.py │ ├── assets │ │ ├── css │ │ │ ├── application.styl │ │ │ └── style.styl │ │ └── js │ │ │ └── script.js │ ├── settings.py │ ├── static │ │ └── .gitkeep │ ├── templates │ │ └── index.html │ ├── urls.py │ └── wsgi.py └── requirements.txt ├── setup.py ├── tests ├── __init__.py ├── fixtures │ ├── serve │ │ ├── js │ │ │ ├── application.js │ │ │ └── script.js │ │ ├── output.js │ │ └── output_body.js │ └── templatetags │ │ └── css │ │ ├── base.css │ │ ├── reset.css │ │ └── style.css ├── runtests.sh ├── settings.py ├── settings_app_finder.py ├── settings_get_asset_handler.py ├── settings_get_finder.py ├── settings_serve.py ├── settings_templatetags.py ├── test_app_finder │ ├── __init__.py │ ├── assets │ │ └── js │ │ │ └── test_app_finder.js │ ├── models.py │ └── tests.py ├── test_get_asset_handler │ ├── __init__.py │ ├── asset_handlers.py │ ├── models.py │ └── tests.py ├── test_get_finder │ ├── __init__.py │ ├── finders.py │ ├── models.py │ └── tests.py ├── test_serve │ ├── __init__.py │ ├── models.py │ └── tests.py └── test_templatetags │ ├── __init__.py │ ├── models.py │ └── tests.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | .tox 4 | dist 5 | example/node_modules 6 | example/project/sqlite.db 7 | docs/_build 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | install: 6 | - pip install mock --use-mirrors 7 | - pip install Django==1.5.5 --use-mirrors 8 | - pip install git+git://github.com/gears/gears.git --use-mirrors 9 | - pip install . --use-mirrors 10 | script: make test 11 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Mike Yumatov 2 | Yakov Borevich 3 | Dima Kukushkin 4 | Preston Timmons 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Mike Yumatov 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | cd tests && ./runtests.sh 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Django Gears 2 | ============ 3 | 4 | .. image:: https://secure.travis-ci.org/gears/django-gears.png?branch=develop 5 | 6 | Gears_ for Django_. 7 | 8 | .. _Gears: https://github.com/gears/gears 9 | .. _Django: https://www.djangoproject.com/ 10 | -------------------------------------------------------------------------------- /django_gears/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/django_gears/__init__.py -------------------------------------------------------------------------------- /django_gears/finders.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from django.conf import settings 5 | from django.core.exceptions import ImproperlyConfigured 6 | from django.utils import six 7 | from django.utils.importlib import import_module 8 | 9 | from gears.finders import FileSystemFinder 10 | 11 | 12 | class AppFinder(FileSystemFinder): 13 | 14 | def __init__(self): 15 | super(AppFinder, self).__init__(self.get_app_assets_dirs()) 16 | 17 | def get_app_assets_dirs(self): 18 | if not six.PY3: 19 | fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() 20 | app_assets_dirs = [] 21 | for app in settings.INSTALLED_APPS: 22 | try: 23 | mod = import_module(app) 24 | except ImportError as e: 25 | raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0])) 26 | assets_dir = os.path.join(os.path.dirname(mod.__file__), 'assets') 27 | if os.path.isdir(assets_dir): 28 | if not six.PY3: 29 | assets_dir = assets_dir.decode(fs_encoding) 30 | app_assets_dirs.append(assets_dir) 31 | app_assets_dirs = tuple(app_assets_dirs) 32 | return app_assets_dirs 33 | -------------------------------------------------------------------------------- /django_gears/handlers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.staticfiles.handlers import StaticFilesHandler 2 | from .views import serve 3 | 4 | 5 | class AssetFilesHandler(StaticFilesHandler): 6 | 7 | def serve(self, request): 8 | return serve(request, self.file_path(request.path), insecure=True) 9 | -------------------------------------------------------------------------------- /django_gears/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/django_gears/management/__init__.py -------------------------------------------------------------------------------- /django_gears/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/django_gears/management/commands/__init__.py -------------------------------------------------------------------------------- /django_gears/management/commands/collectassets.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import NoArgsCommand 2 | from django_gears.settings import environment 3 | 4 | 5 | class Command(NoArgsCommand): 6 | 7 | help = 'Collect assets in a single location.' 8 | 9 | def handle_noargs(self, **options): 10 | environment.save() 11 | -------------------------------------------------------------------------------- /django_gears/management/commands/runserver.py: -------------------------------------------------------------------------------- 1 | from optparse import make_option 2 | 3 | from django.conf import settings 4 | from django.contrib.staticfiles.handlers import StaticFilesHandler 5 | from django.core.management.commands.runserver import BaseRunserverCommand 6 | 7 | from django_gears.handlers import AssetFilesHandler 8 | 9 | 10 | class Command(BaseRunserverCommand): 11 | 12 | option_list = BaseRunserverCommand.option_list + ( 13 | make_option('--noassets', action='store_false', 14 | dest='use_assets_handler', default=True, 15 | help='Tells Django to NOT automatically serve asset files ' 16 | 'at STATIC_URL.'), 17 | make_option('--nostatic', action='store_false', 18 | dest='use_static_handler', default=True, 19 | help='Tells Django to NOT automatically serve static ' 20 | 'files at STATIC_URL.'), 21 | make_option('--insecure', action='store_true', dest='insecure_serving', 22 | default=False, help='Allows serving static files even if ' 23 | 'DEBUG is False'), 24 | ) 25 | help = ('Starts a lightweight Web server for development and also serves ' 26 | 'static files.') 27 | 28 | def get_handler(self, *args, **options): 29 | handler = super(Command, self).get_handler(*args, **options) 30 | use_assets_handler = options.get('use_assets_handler', True) 31 | use_static_handler = options.get('use_static_handler', True) 32 | insecure_serving = options.get('insecure_serving', False) 33 | if use_static_handler and (settings.DEBUG or insecure_serving): 34 | if use_assets_handler: 35 | return AssetFilesHandler(handler) 36 | return StaticFilesHandler(handler) 37 | return handler 38 | -------------------------------------------------------------------------------- /django_gears/settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from gears.environment import Environment, DEFAULT_PUBLIC_ASSETS 3 | from .utils import get_cache, get_finder, get_asset_handler 4 | 5 | 6 | DEFAULT_CACHE = 'gears.cache.SimpleCache' 7 | 8 | DEFAULT_FINDERS = ( 9 | ('gears.finders.FileSystemFinder', { 10 | 'directories': getattr(settings, 'GEARS_DIRS', ()), 11 | }), 12 | ('django_gears.finders.AppFinder', {}), 13 | ) 14 | 15 | DEFAULT_MIMETYPES = { 16 | '.css': 'text/css', 17 | '.js': 'application/javascript', 18 | } 19 | 20 | DEFAULT_PREPROCESSORS = { 21 | 'text/css': 'gears.processors.DirectivesProcessor', 22 | 'application/javascript': 'gears.processors.DirectivesProcessor', 23 | } 24 | 25 | DEFAULT_POSTPROCESSORS = { 26 | 'text/css': 'gears.processors.HexdigestPathsProcessor', 27 | } 28 | 29 | GEARS_DEBUG = getattr(settings, 'GEARS_DEBUG', settings.DEBUG) 30 | 31 | GEARS_URL = getattr(settings, 'GEARS_URL', settings.STATIC_URL) 32 | 33 | GEARS_ROOT = getattr(settings, 'GEARS_ROOT', settings.STATIC_ROOT) 34 | 35 | 36 | path = getattr(settings, 'GEARS_CACHE', DEFAULT_CACHE) 37 | if isinstance(path, (list, tuple)): 38 | path, options = path 39 | else: 40 | options = None 41 | cache = get_cache(path, options) 42 | 43 | environment = Environment( 44 | root=GEARS_ROOT, 45 | public_assets=getattr(settings, 'GEARS_PUBLIC_ASSETS', DEFAULT_PUBLIC_ASSETS), 46 | cache=cache, 47 | gzip=getattr(settings, 'GEARS_GZIP', False), 48 | fingerprinting=getattr(settings, 'GEARS_FINGERPRINTING', True), 49 | ) 50 | 51 | if getattr(settings, 'GEARS_REGISTER_ENTRY_POINTS', False): 52 | environment.register_entry_points() 53 | 54 | for path in getattr(settings, 'GEARS_FINDERS', DEFAULT_FINDERS): 55 | if isinstance(path, (list, tuple)): 56 | path, options = path 57 | else: 58 | options = None 59 | environment.finders.register(get_finder(path, options)) 60 | 61 | mimetypes = getattr(settings, 'GEARS_MIMETYPES', DEFAULT_MIMETYPES) 62 | for extension, mimetype in mimetypes.items(): 63 | environment.mimetypes.register(extension, mimetype) 64 | 65 | for extension, path in getattr(settings, 'GEARS_COMPILERS', {}).items(): 66 | if isinstance(path, (list, tuple)): 67 | path, options = path 68 | else: 69 | options = {} 70 | environment.compilers.register(extension, get_asset_handler(path, options)) 71 | 72 | preprocessors = getattr(settings, 'GEARS_PREPROCESSORS', DEFAULT_PREPROCESSORS) 73 | for mimetype, paths in preprocessors.items(): 74 | if not isinstance(paths, (list, tuple)): 75 | paths = [paths] 76 | for path in paths: 77 | environment.preprocessors.register(mimetype, get_asset_handler(path)) 78 | 79 | postprocessors = getattr(settings, 'GEARS_POSTPROCESSORS', DEFAULT_POSTPROCESSORS) 80 | for mimetype, paths in postprocessors.items(): 81 | if not isinstance(paths, (list, tuple)): 82 | paths = [paths] 83 | for path in paths: 84 | environment.postprocessors.register(mimetype, get_asset_handler(path)) 85 | 86 | compressors = getattr(settings, 'GEARS_COMPRESSORS', {}) 87 | for mimetype, path in compressors.items(): 88 | environment.compressors.register(mimetype, get_asset_handler(path)) 89 | -------------------------------------------------------------------------------- /django_gears/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/django_gears/templatetags/__init__.py -------------------------------------------------------------------------------- /django_gears/templatetags/gears.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from django.template import Node, Library, TemplateSyntaxError 3 | from gears.assets import build_asset 4 | from ..settings import environment, GEARS_URL, GEARS_DEBUG 5 | 6 | 7 | register = Library() 8 | 9 | 10 | class AssetTagNode(Node): 11 | 12 | def __init__(self, logical_path, debug): 13 | self.logical_path = logical_path 14 | self.debug = debug 15 | 16 | @classmethod 17 | def handle_token(cls, parser, token): 18 | bits = token.split_contents() 19 | if len(bits) not in (2, 3): 20 | msg = '%r tag takes one argument: the logical path to the public asset' 21 | raise TemplateSyntaxError(msg % bits[0]) 22 | debug = (len(bits) == 3) 23 | if debug and bits[2] != 'debug': 24 | msg = "Second (optional) argument to %r tag must be 'debug'" 25 | raise TemplateSyntaxError(msg % bits[0]) 26 | logical_path = parser.compile_filter(bits[1]) 27 | return cls(logical_path, debug) 28 | 29 | 30 | def render(self, context): 31 | logical_path = self.logical_path.resolve(context) 32 | if self.debug or GEARS_DEBUG: 33 | asset = build_asset(environment, logical_path) 34 | paths = (('%s?body=1&v=%s' % (r.attributes.logical_path, r.mtime))\ 35 | for r in asset.requirements) 36 | else: 37 | if logical_path in environment.manifest.files: 38 | logical_path = environment.manifest.files[logical_path] 39 | paths = (logical_path,) 40 | return '\n'.join((self.template % path) for path in paths) 41 | 42 | 43 | class CSSAssetTagNode(AssetTagNode): 44 | 45 | template = u'' % GEARS_URL 46 | 47 | 48 | class JSAssetTagNode(AssetTagNode): 49 | 50 | template = u'' % GEARS_URL 51 | 52 | 53 | @register.tag 54 | def css_asset_tag(parser, token): 55 | return CSSAssetTagNode.handle_token(parser, token) 56 | 57 | 58 | @register.tag 59 | def js_asset_tag(parser, token): 60 | return JSAssetTagNode.handle_token(parser, token) 61 | -------------------------------------------------------------------------------- /django_gears/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls import patterns, url 3 | 4 | from .settings import GEARS_URL 5 | from .views import serve 6 | 7 | 8 | def gears_urlpatterns(prefix=None): 9 | prefix = prefix or GEARS_URL.strip("/") 10 | 11 | if settings.DEBUG: 12 | return patterns("", 13 | url( 14 | regex=r"^{0}/(?P.*)$".format(prefix), 15 | view=serve, 16 | ), 17 | ) 18 | else: 19 | return patterns("") 20 | -------------------------------------------------------------------------------- /django_gears/utils.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from django.core.exceptions import ImproperlyConfigured 4 | from django.utils.importlib import import_module 5 | 6 | from gears.asset_handler import BaseAssetHandler 7 | from gears.finders import BaseFinder 8 | 9 | 10 | _cache = {} 11 | 12 | 13 | def _get_module(path): 14 | try: 15 | return import_module(path) 16 | except ImportError, e: 17 | raise ImproperlyConfigured('Error importing module %s: "%s".' % (path, e)) 18 | 19 | 20 | def _get_module_attr(module_path, name): 21 | try: 22 | return getattr(_get_module(module_path), name) 23 | except AttributeError: 24 | raise ImproperlyConfigured('Module "%s" does not define a "%s" obj.' % (module_path, name)) 25 | 26 | 27 | def _get_object(path): 28 | if path not in _cache: 29 | _cache[path] = _get_module_attr(*path.rsplit('.', 1)) 30 | return _cache[path] 31 | 32 | 33 | def get_cache(path, options=None): 34 | cls = _get_object(path) 35 | return cls(**(options or {})) 36 | 37 | 38 | def get_finder(path, options=None): 39 | cls = _get_object(path) 40 | if not issubclass(cls, BaseFinder): 41 | raise ImproperlyConfigured('"%s" is not a subclass of BaseFinder.' % path) 42 | return cls(**(options or {})) 43 | 44 | 45 | def get_asset_handler(path, options=None): 46 | obj = _get_object(path) 47 | try: 48 | if issubclass(obj, BaseAssetHandler): 49 | return obj.as_handler(**(options or {})) 50 | except TypeError: 51 | pass 52 | if callable(obj): 53 | if options is not None: 54 | warnings.warn('%r is provided as %r handler options, but not used ' 55 | 'because this handler is not a BaseAssethandler subclass.' 56 | % (options, path)) 57 | return obj 58 | raise ImproperlyConfigured('"%s" must be a BaseAssetHandler subclass or callable object' % path) 59 | -------------------------------------------------------------------------------- /django_gears/views.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import posixpath 3 | import time 4 | import urllib 5 | 6 | from django.conf import settings 7 | from django.core.exceptions import ImproperlyConfigured 8 | from django.contrib.staticfiles.views import serve as staticfiles_serve 9 | from django.http import HttpResponse 10 | from django.utils.http import http_date 11 | 12 | from gears.assets import build_asset 13 | from gears.compat import bytes 14 | from gears.exceptions import FileNotFound 15 | 16 | from .settings import environment 17 | 18 | MAX_AGE = 60 * 60 * 24 * 7 # 1 week 19 | 20 | 21 | def serve(request, path, **kwargs): 22 | if not settings.DEBUG and not kwargs.get('insecure'): 23 | raise ImproperlyConfigured( 24 | "The gears view can only be used in debug mode or if the " 25 | "--insecure option of 'runserver' is used.") 26 | 27 | # It is only required check because we generate 28 | # version arg for each file 29 | if 'HTTP_IF_MODIFIED_SINCE' in request.META: 30 | response = HttpResponse() 31 | response['Expires'] = http_date(time.time() + MAX_AGE) 32 | response.status_code = 304 33 | return response 34 | 35 | normalized_path = posixpath.normpath(urllib.unquote(path)).lstrip('/') 36 | try: 37 | asset = build_asset(environment, normalized_path) 38 | except FileNotFound: 39 | return staticfiles_serve(request, path, **kwargs) 40 | 41 | last_modified = asset.mtime 42 | if request.GET.get('body'): 43 | asset = asset.processed_source 44 | mimetype, encoding = mimetypes.guess_type(normalized_path) 45 | mimetype = mimetype or 'application/octet-stream' 46 | response = HttpResponse(bytes(asset), content_type=mimetype) 47 | if encoding: 48 | response['Content-Encoding'] = encoding 49 | response['Last-Modified'] = http_date(last_modified) 50 | return response 51 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | htmlall: 58 | $(SPHINXBUILD) -b html -a $(ALLSPHINXOPTS) $(BUILDDIR)/html 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 61 | 62 | dirhtml: 63 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 64 | @echo 65 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 66 | 67 | singlehtml: 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | pickle: 73 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 74 | @echo 75 | @echo "Build finished; now you can process the pickle files." 76 | 77 | json: 78 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 79 | @echo 80 | @echo "Build finished; now you can process the JSON files." 81 | 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | qthelp: 89 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 90 | @echo 91 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 92 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 93 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DjangoGears.qhcp" 94 | @echo "To view the help file:" 95 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoGears.qhc" 96 | 97 | devhelp: 98 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 99 | @echo 100 | @echo "Build finished." 101 | @echo "To view the help file:" 102 | @echo "# mkdir -p $$HOME/.local/share/devhelp/DjangoGears" 103 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DjangoGears" 104 | @echo "# devhelp" 105 | 106 | epub: 107 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 108 | @echo 109 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 110 | 111 | latex: 112 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 113 | @echo 114 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 115 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 116 | "(use \`make latexpdf' here to do that automatically)." 117 | 118 | latexpdf: 119 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 120 | @echo "Running LaTeX files through pdflatex..." 121 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 122 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 123 | 124 | latexpdfja: 125 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 126 | @echo "Running LaTeX files through platex and dvipdfmx..." 127 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 128 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 129 | 130 | text: 131 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 132 | @echo 133 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 134 | 135 | man: 136 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 137 | @echo 138 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 139 | 140 | texinfo: 141 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 142 | @echo 143 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 144 | @echo "Run \`make' in that directory to run these through makeinfo" \ 145 | "(use \`make info' here to do that automatically)." 146 | 147 | info: 148 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 149 | @echo "Running Texinfo files through makeinfo..." 150 | make -C $(BUILDDIR)/texinfo info 151 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 152 | 153 | gettext: 154 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 155 | @echo 156 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 157 | 158 | changes: 159 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 160 | @echo 161 | @echo "The overview file is in $(BUILDDIR)/changes." 162 | 163 | linkcheck: 164 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 165 | @echo 166 | @echo "Link check complete; look for any errors in the above output " \ 167 | "or in $(BUILDDIR)/linkcheck/output.txt." 168 | 169 | doctest: 170 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 171 | @echo "Testing of doctests in the sources finished, look at the " \ 172 | "results in $(BUILDDIR)/doctest/output.txt." 173 | 174 | xml: 175 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 176 | @echo 177 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 178 | 179 | pseudoxml: 180 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 181 | @echo 182 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 183 | -------------------------------------------------------------------------------- /docs/_ext/djangodoc.py: -------------------------------------------------------------------------------- 1 | def setup(app): 2 | app.add_crossref_type( 3 | directivename="setting", 4 | rolename="setting", 5 | indextemplate="pair: %s; setting", 6 | ) 7 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Django Gears documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Mar 26 20:17:03 2014. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | 18 | # If extensions (or modules to document with autodoc) are in another directory, 19 | # add these directories to sys.path here. If the directory is relative to the 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. 21 | sys.path.insert(0, os.path.abspath('_ext')) 22 | 23 | # -- General configuration ------------------------------------------------ 24 | 25 | # If your documentation needs a minimal Sphinx version, state it here. 26 | #needs_sphinx = '1.0' 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 30 | # ones. 31 | extensions = ["djangodoc", ] 32 | 33 | # Add any paths that contain templates here, relative to this directory. 34 | templates_path = [] 35 | 36 | # The suffix of source filenames. 37 | source_suffix = '.rst' 38 | 39 | # The encoding of source files. 40 | #source_encoding = 'utf-8-sig' 41 | 42 | # The master toctree document. 43 | master_doc = 'index' 44 | 45 | # General information about the project. 46 | project = u'Django Gears' 47 | copyright = u'2014, Gears' 48 | 49 | # The version info for the project you're documenting, acts as replacement for 50 | # |version| and |release|, also used in various other places throughout the 51 | # built documents. 52 | # 53 | # The short X.Y version. 54 | version = '0.7' 55 | # The full version, including alpha/beta/rc tags. 56 | release = '0.7.1' 57 | 58 | # The language for content autogenerated by Sphinx. Refer to documentation 59 | # for a list of supported languages. 60 | #language = None 61 | 62 | # There are two options for replacing |today|: either, you set today to some 63 | # non-false value, then it is used: 64 | #today = '' 65 | # Else, today_fmt is used as the format for a strftime call. 66 | #today_fmt = '%B %d, %Y' 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | exclude_patterns = ['_build'] 71 | 72 | # The reST default role (used for this markup: `text`) to use for all 73 | # documents. 74 | #default_role = None 75 | 76 | # If true, '()' will be appended to :func: etc. cross-reference text. 77 | #add_function_parentheses = True 78 | 79 | # If true, the current module name will be prepended to all description 80 | # unit titles (such as .. function::). 81 | #add_module_names = True 82 | 83 | # If true, sectionauthor and moduleauthor directives will be shown in the 84 | # output. They are ignored by default. 85 | #show_authors = False 86 | 87 | # The name of the Pygments (syntax highlighting) style to use. 88 | pygments_style = 'sphinx' 89 | 90 | # A list of ignored prefixes for module index sorting. 91 | #modindex_common_prefix = [] 92 | 93 | # If true, keep warnings as "system message" paragraphs in the built documents. 94 | #keep_warnings = False 95 | 96 | 97 | # -- Options for HTML output ---------------------------------------------- 98 | 99 | # The theme to use for HTML and HTML Help pages. See the documentation for 100 | # a list of builtin themes. 101 | # html_theme = 'default' 102 | 103 | # Theme options are theme-specific and customize the look and feel of a theme 104 | # further. For a list of options available for each theme, see the 105 | # documentation. 106 | #html_theme_options = {} 107 | 108 | # Add any paths that contain custom themes here, relative to this directory. 109 | #html_theme_path = [] 110 | 111 | # The name for this set of Sphinx documents. If None, it defaults to 112 | # " v documentation". 113 | #html_title = None 114 | 115 | # A shorter title for the navigation bar. Default is the same as html_title. 116 | #html_short_title = None 117 | 118 | # The name of an image file (relative to this directory) to place at the top 119 | # of the sidebar. 120 | #html_logo = None 121 | 122 | # The name of an image file (within the static path) to use as favicon of the 123 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 124 | # pixels large. 125 | #html_favicon = None 126 | 127 | # Add any paths that contain custom static files (such as style sheets) here, 128 | # relative to this directory. They are copied after the builtin static files, 129 | # so a file named "default.css" will overwrite the builtin "default.css". 130 | # html_static_path = [] 131 | 132 | # Add any extra paths that contain custom files (such as robots.txt or 133 | # .htaccess) here, relative to this directory. These files are copied 134 | # directly to the root of the documentation. 135 | #html_extra_path = [] 136 | 137 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 138 | # using the given strftime format. 139 | #html_last_updated_fmt = '%b %d, %Y' 140 | 141 | # If true, SmartyPants will be used to convert quotes and dashes to 142 | # typographically correct entities. 143 | #html_use_smartypants = True 144 | 145 | # Custom sidebar templates, maps document names to template names. 146 | #html_sidebars = {} 147 | 148 | # Additional templates that should be rendered to pages, maps page names to 149 | # template names. 150 | #html_additional_pages = {} 151 | 152 | # If false, no module index is generated. 153 | #html_domain_indices = True 154 | 155 | # If false, no index is generated. 156 | #html_use_index = True 157 | 158 | # If true, the index is split into individual pages for each letter. 159 | #html_split_index = False 160 | 161 | # If true, links to the reST sources are added to the pages. 162 | #html_show_sourcelink = True 163 | 164 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 165 | #html_show_sphinx = True 166 | 167 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 168 | #html_show_copyright = True 169 | 170 | # If true, an OpenSearch description file will be output, and all pages will 171 | # contain a tag referring to it. The value of this option must be the 172 | # base URL from which the finished HTML is served. 173 | #html_use_opensearch = '' 174 | 175 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 176 | #html_file_suffix = None 177 | 178 | # Output file base name for HTML help builder. 179 | htmlhelp_basename = 'DjangoGearsdoc' 180 | 181 | 182 | # -- Options for LaTeX output --------------------------------------------- 183 | 184 | latex_elements = { 185 | # The paper size ('letterpaper' or 'a4paper'). 186 | #'papersize': 'letterpaper', 187 | 188 | # The font size ('10pt', '11pt' or '12pt'). 189 | #'pointsize': '10pt', 190 | 191 | # Additional stuff for the LaTeX preamble. 192 | #'preamble': '', 193 | } 194 | 195 | # Grouping the document tree into LaTeX files. List of tuples 196 | # (source start file, target name, title, 197 | # author, documentclass [howto, manual, or own class]). 198 | latex_documents = [ 199 | ('index', 'DjangoGears.tex', u'Django Gears Documentation', 200 | u'Gears', 'manual'), 201 | ] 202 | 203 | # The name of an image file (relative to this directory) to place at the top of 204 | # the title page. 205 | #latex_logo = None 206 | 207 | # For "manual" documents, if this is true, then toplevel headings are parts, 208 | # not chapters. 209 | #latex_use_parts = False 210 | 211 | # If true, show page references after internal links. 212 | #latex_show_pagerefs = False 213 | 214 | # If true, show URL addresses after external links. 215 | #latex_show_urls = False 216 | 217 | # Documents to append as an appendix to all manuals. 218 | #latex_appendices = [] 219 | 220 | # If false, no module index is generated. 221 | #latex_domain_indices = True 222 | 223 | 224 | # -- Options for manual page output --------------------------------------- 225 | 226 | # One entry per manual page. List of tuples 227 | # (source start file, name, description, authors, manual section). 228 | man_pages = [ 229 | ('index', 'djangogears', u'Django Gears Documentation', 230 | [u'Gears'], 1) 231 | ] 232 | 233 | # If true, show URL addresses after external links. 234 | #man_show_urls = False 235 | 236 | 237 | # -- Options for Texinfo output ------------------------------------------- 238 | 239 | # Grouping the document tree into Texinfo files. List of tuples 240 | # (source start file, target name, title, author, 241 | # dir menu entry, description, category) 242 | texinfo_documents = [ 243 | ('index', 'DjangoGears', u'Django Gears Documentation', 244 | u'Gears', 'DjangoGears', 'Django and Gears integration', 245 | 'Miscellaneous'), 246 | ] 247 | 248 | # Documents to append as an appendix to all manuals. 249 | #texinfo_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | #texinfo_domain_indices = True 253 | 254 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 255 | #texinfo_show_urls = 'footnote' 256 | 257 | # If true, do not generate a @detailmenu in the "Top" node's menu. 258 | #texinfo_no_detailmenu = False 259 | 260 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 261 | if not on_rtd: 262 | import sphinx_rtd_theme 263 | html_theme = "sphinx_rtd_theme" 264 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 265 | -------------------------------------------------------------------------------- /docs/deploying.rst: -------------------------------------------------------------------------------- 1 | Deploying 2 | ========= 3 | 4 | The :func:`~django_gears.urls.gears_urlpatterns` work great in development, 5 | but you don't want to build files during the request cycle in production. 6 | Instead, the files should be built once and served as static files by your 7 | web server. The ``collectassets`` command lets you do that. 8 | 9 | 10 | Collecting assets 11 | ----------------- 12 | 13 | The ``collectassets`` command is a `Django management command`_ that is 14 | invoked using the manage.py script:: 15 | 16 | python manage.py collectassets 17 | 18 | 19 | .. _Django management command: https://docs.djangoproject.com/en/dev/ref/django-admin/ 20 | 21 | This command collects all public assets, processes them, and saves them to 22 | the directory specified by the :setting:`GEARS_ROOT` setting. 23 | 24 | In addition to processing the assets, Gears adds a ``.manifest.json`` file 25 | to the directory root. An example manifest file looks like:: 26 | 27 | { 28 | "files": { 29 | "css/styles.css": "css/style.588bb73e7fff720ac360b924fd9b33ddd2fa71c7.css", 30 | "js/script.js": "js/script.d78f84d27230e157031fc8ed26d1099f44d878dd.js" 31 | } 32 | } 33 | 34 | This file is a map between asset names and processed files. When an 35 | asset is included using a ``{% gears %}`` tag in production, instead of 36 | producing a url to the development view, it produces a url to the asset as 37 | specified in the manifest file. 38 | 39 | 40 | Defining public assets 41 | ---------------------- 42 | 43 | .. note:: Note, that since Gears 0.7.1 there is ``public`` directive, which you 44 | can use to mark assets as public:: 45 | 46 | //= public 47 | 48 | When ``collectassets`` is run, Gears will only process assets that are 49 | public. Gears considers any asset public that matches the 50 | :setting:`GEARS_PUBLIC_ASSETS` setting. 51 | 52 | For instance, you may have a script.js file that includes many dependencies. 53 | After processing script.js, there is no need to Gears to additionally 54 | process the individual dependencies and collect them as separate files 55 | into :setting:`GEARS_ROOT`. This is an optimization that results in faster 56 | build times. 57 | 58 | The default rules for collecting public assets: 59 | 60 | * include all files that either aren't css or javascript or aren't set to 61 | compile to css or javascript (less, style, coffee, etc.) 62 | * include css/style.css 63 | * include js/script.js 64 | 65 | If you namespace your assets, or use a different naming convention, you'll 66 | want to specify your own public asset patterns. For instance, if you want 67 | to process all files mapping to site.css or site.js, you could do:: 68 | 69 | GEARS_PUBLIC_ASSETS = ( 70 | lambda path: not any(path.endswith(ext) for ext in ('.css', '.js')), 71 | r'site\.css$', 72 | r'site\.js$', 73 | ) 74 | 75 | 76 | Serving files with your web server 77 | ---------------------------------- 78 | 79 | By default, Django Gears collects assets into the ``STATIC_ROOT`` 80 | directory. If your web server is configured to serve static files already, 81 | no additional configuration is needed. If you haven't configured this, 82 | you can follow Django's advice on `deploying static files`_ or use a 83 | wsgi app like `dj‑static`_. 84 | 85 | .. _deploying static files: https://docs.djangoproject.com/en/dev/howto/static-files/deployment/ 86 | .. _dj‑static: https://github.com/kennethreitz/dj-static 87 | 88 | If you specify a custom directory in :setting:`GEARS_ROOT`, you'll need to 89 | update your server accordingly. 90 | -------------------------------------------------------------------------------- /docs/finders.rst: -------------------------------------------------------------------------------- 1 | Asset finders 2 | ============= 3 | 4 | Django Gears searches for assets to build in the defined assets directories. 5 | By default, this includes: 6 | 7 | * all assets directories in your installed applications 8 | * all assets directories listed in the :setting:`GEARS_DIRS` setting 9 | 10 | We'll cover how both of these work below. 11 | 12 | 13 | Application finder 14 | ------------------ 15 | 16 | Consider a directory structure like the following, where ``myapp1`` 17 | and ``myapp1`` are installed applications:: 18 | 19 | myapp1/ 20 | assets/ 21 | js/ 22 | script.js 23 | app.js 24 | 25 | myapp2/ 26 | assets/ 27 | js/ 28 | test.js 29 | 30 | Next, consider that script.js has the following directives:: 31 | 32 | /* 33 | *= require test 34 | *= require app 35 | */ 36 | 37 | When script.js is processed it will include test.js from ``myapp2`` and 38 | app.js from ``myapp1``. 39 | 40 | 41 | How does this happen? 42 | ~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | Directives, as written, are always relative to the asset file. The idea of 45 | relative isn't solely based on the filesystem, though. In the above example, 46 | both ``myapp1/assets`` and ``myapp2/assets`` are on the search paths. This 47 | means when test.js isn't found in the current directory, the directive 48 | processor continues on through the rest of the directories on the search 49 | path. Here, it is found in myapp2. 50 | 51 | Note, Gears will use the first asset it finds that matches the given path. 52 | Therefore, if you have multiple assets whose name and location is the same, 53 | Gears won't distinguish between them. The easiest way to ensure this doesn't happen is to place assets in custom 54 | named directories within the assets folder. 55 | 56 | 57 | File System Finder 58 | ------------------ 59 | 60 | In addition to the application finder, Django Gears will look for static 61 | files in specified directories in the filesystem. These directories are 62 | controlled through the :setting:`GEARS_DIRS` setting. 63 | 64 | For example, you may add an assets directory in your project root: 65 | 66 | .. code-block:: python 67 | 68 | import os 69 | SITE_ROOT = os.path.realpath(os.path.dirname(__file__)) 70 | GEARS_DIRS = ( 71 | os.path.join(SITE_ROOT, "assets"), 72 | ) 73 | 74 | By default, the file system finder has precedence over the application 75 | finders. 76 | 77 | 78 | Configuring finders 79 | ------------------- 80 | 81 | If you want to configure or add custom finders of your own, see the 82 | docs on the :setting:`GEARS_FINDERS` setting. 83 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Django Gears 2 | ============ 3 | 4 | This application provides integration with `Django`_ and `Gears`_. Gears is 5 | a Python application that compiles and concatenates JavaScript and CSS 6 | assets. Inspired by Ruby's Sprockets. 7 | 8 | .. _Django: http://www.djangoproject.com 9 | .. _Gears: http://gears.readthedocs.org/en/latest/ 10 | 11 | Source code is available on github: https://github.com/gears/django-gears 12 | 13 | 14 | Contents 15 | -------- 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | installation 21 | tutorial 22 | finders 23 | views 24 | template-tags 25 | processing 26 | deploying 27 | settings 28 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Get the code 5 | ------------ 6 | 7 | You can install Django Gears with pip_:: 8 | 9 | $ pip install django-gears 10 | 11 | It's strongly recommended to install Django Gears within an activated 12 | virtualenv_. 13 | 14 | If you want to work with the latest version of Django Gears, install it from 15 | the public repository:: 16 | 17 | $ pip install -e git+https://github.com/gears/django-gears@develop#egg=django-gears 18 | 19 | .. _pip: http://www.pip-installer.org/ 20 | .. _virtualenv: http://virtualenv.org/ 21 | 22 | 23 | Add to settings 24 | --------------- 25 | 26 | Add ``django_gears`` to your ``INSTALLED_APPS`` settings: 27 | 28 | .. code-block:: python 29 | 30 | INSTALLED_APPS = ( 31 | # ... 32 | 'django_gears', 33 | # ... 34 | ) 35 | 36 | 37 | Configure development urls 38 | -------------------------- 39 | 40 | .. code-block:: python 41 | 42 | from django_gears.urls import gears_urlpatterns 43 | 44 | # url definitions here 45 | 46 | urlpatterns += gears_urlpatterns() 47 | 48 | .. note:: 49 | 50 | If you use Django's `staticfiles_urlpatterns`_, you should replace that 51 | with gears_urlpatterns. Django Gears falls back to serving static files 52 | when matching assets aren't found. 53 | 54 | .. _staticfiles_urlpatterns: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/# django.contrib.staticfiles.urls.staticfiles_urlpatterns 55 | 56 | Moving on 57 | --------- 58 | 59 | Congratulations. You have a working installation. Now, continue to the 60 | tutorial to learn how to use Gears in your templates. 61 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\DjangoGears.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\DjangoGears.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/processing.rst: -------------------------------------------------------------------------------- 1 | Asset compilers and processors 2 | ============================== 3 | 4 | The asset building process consists of multiple steps. At it's simplest, 5 | only the directives are processed and dependencies are included into the 6 | build files. The build process can do much more though, like compiling 7 | less files with lessjs or compressing js files with uglifyjs. 8 | 9 | Each build follows these fives steps that can be customized for your 10 | environment. 11 | 12 | 1. Preprocess 13 | 2. Compile 14 | 3. Postprocess 15 | 4. Compress 16 | 5. Save to filesystem 17 | 18 | 19 | 1. Preprocess 20 | ------------- 21 | 22 | The first step is where dependencies are managed. Gears looks for 23 | directives within assets and includes them within the asset file. As 24 | explained elsewhere, directives are simple comments in the header of 25 | script or css files. For example:: 26 | 27 | /* 28 | *= require jquery 29 | *= require underscore 30 | *= require backbone 31 | */ 32 | 33 | It's not common to change the preprocess step, but if you wish to do 34 | so, this can be done by modifying the :setting:`GEARS_PREPROCESSORS` 35 | setting. 36 | 37 | 38 | 2. Compile 39 | ---------- 40 | 41 | The second step compiles source files like CoffeeScript, Stylus, or Less 42 | into javascript and css. Compilers are defined in the 43 | :setting:`GEARS_COMPILERS` setting. 44 | 45 | Various compilers are just a ``pip`` install away. You can browse plugins 46 | that are available at the `Gears repositories github page`_. If you find 47 | a compiler not supported, it's easy to create a plugin of your own. 48 | 49 | 50 | 3. Postprocess 51 | -------------- 52 | 53 | The third step is where files are postprocessed. By default, Django Gears 54 | runs the ``gears.processors.HexdigestPathsProcessor`` for css files. This 55 | processor replaces ``url`` declarations in the css with fingerprinted 56 | versions. Note, this processor only works if all paths in ``url`` 57 | declarations refer to local files. 58 | 59 | The post processors can be modified with the :setting:`GEARS_POSTPROCESSORS` 60 | setting. 61 | 62 | 63 | 4. Compress 64 | ----------- 65 | 66 | The fourth step is where tools like SlimIt, UglifyJS, or clean-css are run. 67 | These produce minified files and minimize bandwidth requirements. 68 | 69 | For users of Python 2.X, Gears has built-in support for SlimIt and cssmin. 70 | 71 | Other compilers are just a ``pip`` install away. You can browse plugins 72 | that are available at the `Gears repositories github page`_. 73 | 74 | 75 | 5. Save to filesystem 76 | --------------------- 77 | 78 | The fifth step is where processed files are saved to the file system. 79 | The destination directory is controlled by the :setting:`GEARS_ROOT` 80 | setting. 81 | 82 | Unless :setting:`GEARS_FINGERPRINTING` is set to false, the asset will be 83 | fingerprinted and added to the ``.manifest.json`` file. 84 | 85 | During this step, the file can optionally be gzipped. This is controlled 86 | by the :setting:`GEARS_GZIP` setting. 87 | 88 | 89 | .. _gears repositories github page: https://github.com/gears/ 90 | -------------------------------------------------------------------------------- /docs/settings.rst: -------------------------------------------------------------------------------- 1 | Settings 2 | ======== 3 | 4 | .. setting:: GEARS_CACHE 5 | 6 | GEARS_CACHE 7 | ----------- 8 | 9 | This defines the cache used in the Gears environment. The default 10 | values is ``gears.cache.SimpleCache``. 11 | 12 | 13 | .. setting:: GEARS_COMPRESSORS 14 | 15 | GEARS_COMPRESSORS 16 | ----------------- 17 | 18 | A mapping of mimetype to compressors. For example: 19 | 20 | .. code-block:: python 21 | 22 | GEARS_COMPRESSORS = { 23 | 'application/javascript': 'gears_uglifyjs.UglifyJSCompressor', 24 | 'text/css': 'gears_clean_css.CleanCSSCompressor', 25 | } 26 | 27 | By default, this setting is equal to ``{}``. No compressors are defined. 28 | 29 | 30 | .. setting:: GEARS_COMPILERS 31 | 32 | GEARS_COMPILERS 33 | --------------- 34 | 35 | A mapping of file extension to compilers. For example: 36 | 37 | .. code-block:: python 38 | 39 | GEARS_COMPILERS = { 40 | '.styl': 'gears_stylus.StylusCompiler', 41 | '.coffee': 'gears_coffeescript.CoffeeScriptCompiler', 42 | } 43 | 44 | By default, this setting is equal to ``{}``. No compilers are defined. 45 | 46 | 47 | .. setting:: GEARS_DEBUG 48 | 49 | GEARS_DEBUG 50 | ----------- 51 | 52 | Whether Gears is in debug mode or not. Defaults to the value of 53 | ``settings.DEBUG``. This affects how the template tags process assets. 54 | See the :doc:`template-tags` docs for more information. 55 | 56 | 57 | .. setting:: GEARS_DIRS 58 | 59 | GEARS_DIRS 60 | ---------- 61 | 62 | The list of directories to search for assets. This is used when the 63 | ``gears.finders.FileSystemFinder`` is specified in 64 | :setting:`GEARS_FINDERS`. Defaults to ``[]``. No directories are defined. 65 | 66 | 67 | .. setting:: GEARS_FINDERS 68 | 69 | GEARS_FINDERS 70 | ------------- 71 | 72 | The list of finders to use when searching for assets. The default finders 73 | are: 74 | 75 | .. code-block:: python 76 | 77 | GEARS_FINDERS = ( 78 | ('gears.finders.FileSystemFinder', { 79 | 'directories': getattr(settings, 'GEARS_DIRS', ()), 80 | }), 81 | ('django_gears.finders.AppFinder', {}), 82 | ) 83 | 84 | 85 | .. setting:: GEARS_FINGERPRINTING 86 | 87 | GEARS_FINGERPRINTING 88 | -------------------- 89 | 90 | Whether Gears should save a fingerprinted version of the asset in the 91 | build directory. A fingerprint is based on the contents of the file and 92 | thus unique for each version of it. Fingerprinted files are also added to 93 | the ``.manifest.json`` file. Defaults to ``True``. 94 | 95 | 96 | .. setting:: GEARS_GZIP 97 | 98 | GEARS_GZIP 99 | ---------- 100 | 101 | Whether Gears should gzip processed files at the end of the build process. 102 | Defaults to ``False``. 103 | 104 | 105 | .. setting:: GEARS_MIMETYPES 106 | 107 | GEARS_MIMETYPES 108 | --------------- 109 | 110 | The mimetypes for asset file extensions. Mimetypes are used by post and 111 | preprocessors as well as compressors. The default mimetypes are: 112 | 113 | .. code-block:: python 114 | 115 | GEARS_MIMETYPES = { 116 | '.css': 'text/css', 117 | '.js': 'application/javascript', 118 | } 119 | 120 | 121 | .. setting:: GEARS_POSTPROCESSORS 122 | 123 | GEARS_POSTPROCESSORS 124 | -------------------- 125 | 126 | The list of postprocessors to run when assets are served or collected. 127 | The default postprocessors are: 128 | 129 | .. code-block:: python 130 | 131 | GEARS_POSTPROCESSORS = { 132 | 'text/css': 'gears.processors.HexdigestPathsProcessor', 133 | } 134 | 135 | 136 | .. setting:: GEARS_PREPROCESSORS 137 | 138 | GEARS_PREPROCESSORS 139 | ------------------- 140 | 141 | The list of preprocessors to run when assets are served or collected. The 142 | default preprocessors handle dependency management through directives. 143 | 144 | .. code-block:: python 145 | 146 | GEARS_PREPROCESSORS = { 147 | 'text/css': 'gears.processors.DirectivesProcessor', 148 | 'application/javascript': 'gears.processors.DirectivesProcessor', 149 | } 150 | 151 | 152 | .. setting:: GEARS_PUBLIC_ASSETS 153 | 154 | GEARS_PUBLIC_ASSETS 155 | ------------------- 156 | 157 | .. note:: Note, that since Gears 0.7.1 there is ``public`` directive, which you 158 | can use to mark assets as public:: 159 | 160 | //= public 161 | 162 | The patterns that define public assets. Only assets matching one of these 163 | patterns will be processed when ``collectassets`` is run. The default 164 | values are: 165 | 166 | .. code-block:: python 167 | 168 | GEARS_PUBLIC_ASSETS = ( 169 | lambda path: not any(path.endswith(ext) for ext in ('.css', '.js')), 170 | r'^css/style\.css$', 171 | r'^js/script\.js$', 172 | ) 173 | 174 | Each pattern can either be a regular expression or a function that takes a 175 | path and returns a boolean. 176 | 177 | .. setting:: GEARS_REGISTER_ENTRY_POINTS 178 | 179 | GEARS_REGISTER_ENTRY_POINTS 180 | --------------------------- 181 | 182 | If set to ``True`` plugins will be searched and registered using `entry 183 | points`_. ``False`` by default. 184 | 185 | .. _entry points: http://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins 186 | 187 | .. setting:: GEARS_ROOT 188 | 189 | GEARS_ROOT 190 | ---------- 191 | 192 | The directory where built assets are stored. Defaults to 193 | ``settings.STATIC_ROOT``. 194 | 195 | 196 | .. setting:: GEARS_URL 197 | 198 | GEARS_URL 199 | --------- 200 | 201 | The url to serve processed assets under. Defaults to ``settings.STATIC_URL``. 202 | -------------------------------------------------------------------------------- /docs/template-tags.rst: -------------------------------------------------------------------------------- 1 | Asset template tags 2 | =================== 3 | 4 | Loading assets 5 | -------------- 6 | 7 | Django Gears provides two template tags for use in templates: one for 8 | css and one for javascript. 9 | 10 | The usage of these tags looks like: 11 | 12 | .. code-block:: django 13 | 14 | {% load gears %} 15 | {% css_asset_tag "css/style.css" %} 16 | {% js_asset_tag "js/script.js" %} 17 | 18 | This outputs script and link tags like the following: 19 | 20 | .. code-block:: html 21 | 22 | 23 | 24 | 25 | 26 | Debug settings 27 | -------------- 28 | 29 | If :setting:`GEARS_DEBUG` is true, the directives will not be processed 30 | into a single file. Instead, each asset will be processed and linked to 31 | individually. 32 | 33 | For example, consider the directives: 34 | 35 | :: 36 | 37 | /* 38 | *= require jquery 39 | *= require underscore 40 | */ 41 | 42 | The output when :setting:`GEARS_DEBUG` is true looks like: 43 | 44 | .. code-block:: html 45 | 46 | 47 | 48 | 49 | 50 | This behavior can also be triggered from within a template by adding a 51 | ``debug`` argument to the asset tags: 52 | 53 | .. code-block:: django 54 | 55 | {% css_asset_tag "css/style.css" debug %} 56 | {% js_asset_tag "js/script.js" debug %} 57 | -------------------------------------------------------------------------------- /docs/tutorial.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | The assets directories 5 | ---------------------- 6 | 7 | Django Gears searches for assets in the defined assets directories. 8 | By default, this includes all ``assets`` folders defined in your installed 9 | applications. You'll find this approach familiar if you've used Django's 10 | application template loader or static files finder. 11 | 12 | For this tutorial, imagine you have an assets directory like this:: 13 | 14 | assets/ 15 | css/ 16 | buttons.css 17 | styles.css 18 | js/ 19 | script.js 20 | app.js 21 | vendor/ 22 | jquery.js 23 | underscore.js 24 | 25 | 26 | Using directives 27 | ---------------- 28 | 29 | The primary Gears preprocessor is based on directives. Directives are 30 | a way to handle dependencies in your css and scripts. 31 | 32 | For example, ``script.js`` in the example folder may look like this:: 33 | 34 | /* Dependencies: 35 | *= require ../vendor/jquery 36 | *= require ../vendor/underscore 37 | *= require app 38 | */ 39 | 40 | Each line that starts with ``*=`` is a directive. Directives let you 41 | include files, trees, or directory contents into a single file. Directives 42 | are always relative to the file that contains them. 43 | 44 | For another example, the style.css file may look like this:: 45 | 46 | /* Dependencies: 47 | *= require buttons 48 | *= require_self 49 | */ 50 | 51 | # more styles here 52 | 53 | You can see a list of `available directives here `_. 54 | 55 | 56 | Adding scripts and css to templates 57 | ----------------------------------- 58 | 59 | Now that the script.js and styles.css files are defined they can be 60 | included in your templates. You can do this with the ``{% gears %}`` 61 | template tags. 62 | 63 | .. code-block:: django 64 | 65 | {% load gears %} 66 | {% css_asset_tag "css/style.css" %} 67 | {% js_asset_tag "js/script.js" %} 68 | 69 | 70 | What happened? 71 | ~~~~~~~~~~~~~~ 72 | 73 | Gears will construct link or script tags to the proper assets. When using 74 | the :func:`~django_gears.urls.gears_urlpatterns`, the :func:`django_gears.views.serve` view will be 75 | called. This will process and serve the assets at the time of the request. 76 | You can edit the assets and reload the page to immediately see the changes. 77 | 78 | For production, the assets will be pre-built using the ``collectassets`` 79 | command. The urls will point to these files that should be served as 80 | static files by the web server. We'll discuss this more later. 81 | -------------------------------------------------------------------------------- /docs/views.rst: -------------------------------------------------------------------------------- 1 | Asset views 2 | =========== 3 | 4 | Serving assets in development 5 | ----------------------------- 6 | 7 | .. module:: django_gears.views 8 | 9 | .. py:function:: serve(request, path, **kwargs) 10 | 11 | Django Gears provides the :py:func:`serve` view for use in development. 12 | This view will process and serve any matching assets on the fly. This means 13 | you can simply reload your pages to see the latest changes. 14 | 15 | Further, if no matching asset is found, :func:`serve` falls back to Django's 16 | ``staticfiles.views.serve`` view. This means your application can happily 17 | serve static files alongside Gear's assets. 18 | 19 | The easiest way to make use of the :func:`serve` view in your application 20 | is to use the included :func:`~django_gears.urls.gears_urlpatterns` function. 21 | 22 | .. code-block:: python 23 | 24 | from django_gears.urls import gears_urlpatterns 25 | 26 | # url definitions here 27 | 28 | urlpatterns += gears_urlpatterns() 29 | 30 | Sites using these urlpatterns will not need to use `Django's staticfiles urlpatterns`_. 31 | 32 | .. _Django's staticfiles urlpatterns: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/# django.contrib.staticfiles.urls.staticfiles_urlpatterns 33 | 34 | .. warning:: 35 | 36 | Like staticfiles_urlpatterns, gears_urlpatterns only registers 37 | patterns when settings.Debug is True. This isn't for production 38 | use. See the :doc:`Deployment docs ` for more information. 39 | 40 | 41 | Gears urlpatterns 42 | ----------------- 43 | 44 | .. module:: django_gears.urls 45 | 46 | .. py:function:: gears_urlpatterns(prefix=None) 47 | 48 | Returns development urlpatterns for serving assets. 49 | 50 | If ``settings.DEBUG`` is false, the returned urlpatterns will be empty. 51 | 52 | :param prefix: The url prefix to server assets under. Defaults to the :setting:`GEARS_URL` setting. 53 | -------------------------------------------------------------------------------- /example/articles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/example/articles/__init__.py -------------------------------------------------------------------------------- /example/articles/assets/js/articles/app.coffee: -------------------------------------------------------------------------------- 1 | jQuery -> 2 | console.log 'Hello, articles!' 3 | -------------------------------------------------------------------------------- /example/articles/models.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /example/project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/example/project/__init__.py -------------------------------------------------------------------------------- /example/project/assets/css/application.styl: -------------------------------------------------------------------------------- 1 | body 2 | margin: 0 3 | padding: 0 4 | color: #333 5 | 6 | h1 7 | margin: 0 8 | padding: 1em 9 | text-align: center 10 | font-family: monospace 11 | -------------------------------------------------------------------------------- /example/project/assets/css/style.styl: -------------------------------------------------------------------------------- 1 | //= require application 2 | -------------------------------------------------------------------------------- /example/project/assets/js/script.js: -------------------------------------------------------------------------------- 1 | /* 2 | *= require articles/app 3 | *= require_self 4 | */ 5 | 6 | console.log('Hello script!'); 7 | -------------------------------------------------------------------------------- /example/project/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | DEBUG = True 7 | TEMPLATE_DEBUG = DEBUG 8 | 9 | ADMINS = ( 10 | # ('Your Name', 'your_email@example.com'), 11 | ) 12 | 13 | MANAGERS = ADMINS 14 | 15 | DATABASES = { 16 | 'default': { 17 | 'ENGINE': 'django.db.backends.sqlite3', 18 | 'NAME': os.path.join(PROJECT_ROOT, 'sqlite.db'), 19 | } 20 | } 21 | 22 | # Local time zone for this installation. Choices can be found here: 23 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 24 | # although not all choices may be available on all operating systems. 25 | # On Unix systems, a value of None will cause Django to use the same 26 | # timezone as the operating system. 27 | # If running in a Windows environment this must be set to the same as your 28 | # system time zone. 29 | TIME_ZONE = 'America/Chicago' 30 | 31 | # Language code for this installation. All choices can be found here: 32 | # http://www.i18nguy.com/unicode/language-identifiers.html 33 | LANGUAGE_CODE = 'en-us' 34 | 35 | SITE_ID = 1 36 | 37 | # If you set this to False, Django will make some optimizations so as not 38 | # to load the internationalization machinery. 39 | USE_I18N = True 40 | 41 | # If you set this to False, Django will not format dates, numbers and 42 | # calendars according to the current locale. 43 | USE_L10N = True 44 | 45 | # If you set this to False, Django will not use timezone-aware datetimes. 46 | USE_TZ = True 47 | 48 | # Absolute filesystem path to the directory that will hold user-uploaded files. 49 | # Example: "/home/media/media.lawrence.com/media/" 50 | MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'public', 'media') 51 | 52 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 53 | # trailing slash. 54 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 55 | MEDIA_URL = '/media/' 56 | 57 | # Absolute path to the directory static files should be collected to. 58 | # Don't put anything in this directory yourself; store your static files 59 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 60 | # Example: "/home/media/media.lawrence.com/static/" 61 | STATIC_ROOT = os.path.join(PROJECT_ROOT, 'public', 'static') 62 | 63 | # URL prefix for static files. 64 | # Example: "http://media.lawrence.com/static/" 65 | STATIC_URL = '/static/' 66 | 67 | # Additional locations of static files 68 | STATICFILES_DIRS = ( 69 | os.path.join(PROJECT_ROOT, 'static'), 70 | ) 71 | 72 | # List of finder classes that know how to find static files in 73 | # various locations. 74 | STATICFILES_FINDERS = ( 75 | 'django.contrib.staticfiles.finders.FileSystemFinder', 76 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 77 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 78 | ) 79 | 80 | # Make this unique, and don't share it with anybody. 81 | SECRET_KEY = '_8zx853=z=onz1)+anjvz6!zfepi*ud^5)t9uhl_-e-r4(pgq%' 82 | 83 | # List of callables that know how to import templates from various sources. 84 | TEMPLATE_LOADERS = ( 85 | 'django.template.loaders.filesystem.Loader', 86 | 'django.template.loaders.app_directories.Loader', 87 | # 'django.template.loaders.eggs.Loader', 88 | ) 89 | 90 | MIDDLEWARE_CLASSES = ( 91 | 'django.middleware.common.CommonMiddleware', 92 | 'django.contrib.sessions.middleware.SessionMiddleware', 93 | 'django.middleware.csrf.CsrfViewMiddleware', 94 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 95 | 'django.contrib.messages.middleware.MessageMiddleware', 96 | # Uncomment the next line for simple clickjacking protection: 97 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 98 | ) 99 | 100 | ROOT_URLCONF = 'project.urls' 101 | 102 | # Python dotted path to the WSGI application used by Django's runserver. 103 | WSGI_APPLICATION = 'project.wsgi.application' 104 | 105 | TEMPLATE_DIRS = ( 106 | os.path.join(PROJECT_ROOT, 'templates'), 107 | ) 108 | 109 | INSTALLED_APPS = ( 110 | 'django.contrib.staticfiles', 111 | 'django_gears', 112 | 'articles', 113 | ) 114 | 115 | # A sample logging configuration. The only tangible logging 116 | # performed by this configuration is to send an email to 117 | # the site admins on every HTTP 500 error when DEBUG=False. 118 | # See http://docs.djangoproject.com/en/dev/topics/logging for 119 | # more details on how to customize your logging configuration. 120 | LOGGING = { 121 | 'version': 1, 122 | 'disable_existing_loggers': False, 123 | 'filters': { 124 | 'require_debug_false': { 125 | '()': 'django.utils.log.RequireDebugFalse' 126 | } 127 | }, 128 | 'handlers': { 129 | 'mail_admins': { 130 | 'level': 'ERROR', 131 | 'filters': ['require_debug_false'], 132 | 'class': 'django.utils.log.AdminEmailHandler' 133 | } 134 | }, 135 | 'loggers': { 136 | 'django.request': { 137 | 'handlers': ['mail_admins'], 138 | 'level': 'ERROR', 139 | 'propagate': True, 140 | }, 141 | } 142 | } 143 | 144 | GEARS_ROOT = os.path.join(PROJECT_ROOT, 'static') 145 | 146 | GEARS_DIRS = ( 147 | os.path.join(PROJECT_ROOT, 'assets'), 148 | ) 149 | 150 | GEARS_COMPILERS = { 151 | '.styl': 'gears_stylus.StylusCompiler', 152 | '.coffee': 'gears_coffeescript.CoffeeScriptCompiler', 153 | } 154 | -------------------------------------------------------------------------------- /example/project/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/example/project/static/.gitkeep -------------------------------------------------------------------------------- /example/project/templates/index.html: -------------------------------------------------------------------------------- 1 | {% load gears %} 2 | 3 | 4 | 5 | Example app 6 | {% css_asset_tag 'css/style.css' %} 7 | 8 | 9 |

Example app

10 | 11 | 12 | -------------------------------------------------------------------------------- /example/project/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | from django.views.generic import TemplateView 3 | 4 | 5 | urlpatterns = patterns('', 6 | url(r'^$', TemplateView.as_view(template_name='index.html')), 7 | ) 8 | -------------------------------------------------------------------------------- /example/project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for project project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) 29 | -------------------------------------------------------------------------------- /example/requirements.txt: -------------------------------------------------------------------------------- 1 | Django<1.6 2 | gears-stylus 3 | gears-coffeescript 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | 4 | 5 | def read(filename): 6 | return open(os.path.join(os.path.dirname(__file__), filename)).read() 7 | 8 | 9 | setup( 10 | name='django-gears', 11 | version='0.7.1', 12 | license='ISC', 13 | description='Compiles and concatenates JavaScript and CSS assets.', 14 | long_description=read('README.rst'), 15 | url='https://github.com/gears/django-gears', 16 | author='Mike Yumatov', 17 | author_email='mike@yumatov.org', 18 | packages=find_packages(exclude=['tests', 'tests.*']), 19 | include_package_data=True, 20 | install_requires=[ 21 | 'Gears>=0.7', 22 | ], 23 | classifiers=[ 24 | 'Development Status :: 3 - Alpha', 25 | 'Framework :: Django', 26 | 'Intended Audience :: Developers', 27 | 'License :: OSI Approved :: ISC License (ISCL)', 28 | 'Operating System :: OS Independent', 29 | 'Programming Language :: Python', 30 | 'Programming Language :: Python :: 2.6', 31 | 'Programming Language :: Python :: 2.7', 32 | 'Topic :: Internet :: WWW/HTTP'], 33 | ) 34 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/serve/js/application.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | console.log("Приложение"); 3 | }).call(this); 4 | -------------------------------------------------------------------------------- /tests/fixtures/serve/js/script.js: -------------------------------------------------------------------------------- 1 | //= require application 2 | 3 | (function() { 4 | console.log("Hello, World!"); 5 | }).call(this); 6 | -------------------------------------------------------------------------------- /tests/fixtures/serve/output.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | console.log("Приложение"); 3 | }).call(this); 4 | 5 | (function() { 6 | console.log("Hello, World!"); 7 | }).call(this); 8 | -------------------------------------------------------------------------------- /tests/fixtures/serve/output_body.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | console.log("Hello, World!"); 3 | }).call(this); 4 | -------------------------------------------------------------------------------- /tests/fixtures/templatetags/css/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #444; 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/templatetags/css/reset.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | -------------------------------------------------------------------------------- /tests/fixtures/templatetags/css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * = require reset 3 | * = require base 4 | */ 5 | 6 | .b-application { 7 | width: 940px; 8 | } 9 | -------------------------------------------------------------------------------- /tests/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export PYTHONPATH=$PWD:$PWD/..:$PYTHONPATH 6 | 7 | django-admin.py test --settings=tests.settings_get_asset_handler 8 | django-admin.py test --settings=tests.settings_get_finder 9 | django-admin.py test --settings=tests.settings_templatetags 10 | django-admin.py test --settings=tests.settings_serve 11 | django-admin.py test --settings=tests.settings_app_finder 12 | -------------------------------------------------------------------------------- /tests/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | TESTS_DIR = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | DATABASES = { 7 | 'default': { 8 | 'ENGINE': 'django.db.backends.sqlite3', 9 | }, 10 | } 11 | 12 | MEDIA_ROOT = os.path.join(TESTS_DIR, 'public', 'media') 13 | MEDIA_URL = '/media/' 14 | 15 | STATIC_ROOT = os.path.join(TESTS_DIR, 'public', 'static') 16 | STATIC_URL = '/static/' 17 | 18 | STATICFILES_DIRS = ( 19 | os.path.join(TESTS_DIR, 'static'), 20 | ) 21 | 22 | SECRET_KEY = 'secret key' 23 | 24 | INSTALLED_APPS = ( 25 | 'django.contrib.staticfiles', 26 | 'django_gears', 27 | ) 28 | 29 | GEARS_ROOT = os.path.join(TESTS_DIR, 'static') 30 | -------------------------------------------------------------------------------- /tests/settings_app_finder.py: -------------------------------------------------------------------------------- 1 | import os 2 | from tests.settings import * 3 | 4 | 5 | DEBUG = True 6 | 7 | INSTALLED_APPS += ('test_app_finder',) 8 | -------------------------------------------------------------------------------- /tests/settings_get_asset_handler.py: -------------------------------------------------------------------------------- 1 | from tests.settings import * 2 | 3 | 4 | INSTALLED_APPS += ('test_get_asset_handler',) 5 | -------------------------------------------------------------------------------- /tests/settings_get_finder.py: -------------------------------------------------------------------------------- 1 | from tests.settings import * 2 | 3 | 4 | INSTALLED_APPS += ('test_get_finder',) 5 | -------------------------------------------------------------------------------- /tests/settings_serve.py: -------------------------------------------------------------------------------- 1 | import os 2 | from tests.settings import * 3 | 4 | 5 | DEBUG = True 6 | 7 | INSTALLED_APPS += ('test_serve',) 8 | 9 | GEARS_DIRS = ( 10 | os.path.join(TESTS_DIR, 'fixtures', 'serve'), 11 | ) 12 | -------------------------------------------------------------------------------- /tests/settings_templatetags.py: -------------------------------------------------------------------------------- 1 | from tests.settings import * 2 | 3 | 4 | INSTALLED_APPS += ('test_templatetags',) 5 | 6 | GEARS_DIRS = ( 7 | os.path.join(TESTS_DIR, 'fixtures', 'templatetags'), 8 | ) 9 | -------------------------------------------------------------------------------- /tests/test_app_finder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_app_finder/__init__.py -------------------------------------------------------------------------------- /tests/test_app_finder/assets/js/test_app_finder.js: -------------------------------------------------------------------------------- 1 | console.log('Hello!'); 2 | -------------------------------------------------------------------------------- /tests/test_app_finder/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_app_finder/models.py -------------------------------------------------------------------------------- /tests/test_app_finder/tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | import codecs 4 | import os 5 | 6 | from django.conf import settings 7 | from django.test import TestCase, RequestFactory 8 | from django.utils.encoding import smart_str 9 | 10 | from django_gears.finders import AppFinder 11 | from django_gears.views import serve 12 | 13 | 14 | TESTS_DIR = os.path.dirname(__file__) 15 | FIXTURES_DIR = os.path.join(TESTS_DIR, 'fixtures') 16 | APP_ASSETS= os.path.join(os.path.dirname(__file__), 'assets') 17 | 18 | 19 | def read(file): 20 | with codecs.open(file, encoding='utf-8') as f: 21 | return f.read() 22 | 23 | 24 | class AppFinderTests(TestCase): 25 | 26 | def setUp(self): 27 | self.factory = RequestFactory() 28 | self.old_DEBUG = settings.DEBUG 29 | settings.DEBUG = True 30 | 31 | def tearDown(self): 32 | settings.DEBUG = self.old_DEBUG 33 | 34 | def get_response(self, path, data=None): 35 | request = self.factory.get('/static/' + path, data or {}) 36 | return serve(request, path) 37 | 38 | def get_app_asset(self, path): 39 | return smart_str(read(os.path.join(APP_ASSETS, path)), 'utf-8') 40 | 41 | def test_finder(self): 42 | finder = AppFinder() 43 | self.assertItemsEqual(finder.list('js'), ( 44 | ('js/test_app_finder.js', os.path.join(APP_ASSETS, 'js', 'test_app_finder.js')), 45 | )) 46 | 47 | def test_serve(self): 48 | response = self.get_response('js/test_app_finder.js') 49 | self.assertEqual(response.content, self.get_app_asset('js/test_app_finder.js')) 50 | -------------------------------------------------------------------------------- /tests/test_get_asset_handler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_get_asset_handler/__init__.py -------------------------------------------------------------------------------- /tests/test_get_asset_handler/asset_handlers.py: -------------------------------------------------------------------------------- 1 | from gears.compilers import BaseCompiler 2 | 3 | 4 | class PythonCompiler(BaseCompiler): 5 | 6 | def __call__(self, asset): 7 | pass 8 | 9 | 10 | class CompilerWithOptions(BaseCompiler): 11 | 12 | def __init__(self, level): 13 | self.level = level 14 | 15 | def __call__(self, asset): 16 | pass 17 | 18 | 19 | def simple_compiler(asset): 20 | pass 21 | 22 | 23 | incorrect_handler = 'incorrect handler' 24 | -------------------------------------------------------------------------------- /tests/test_get_asset_handler/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_get_asset_handler/models.py -------------------------------------------------------------------------------- /tests/test_get_asset_handler/tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | import warnings 4 | 5 | from django.core.exceptions import ImproperlyConfigured 6 | from django.test import TestCase 7 | 8 | from django_gears.utils import get_asset_handler 9 | from mock import patch 10 | from . import asset_handlers 11 | 12 | 13 | class GetAssetHandlerTests(TestCase): 14 | 15 | def test_asset_handler_is_a_class(self): 16 | asset_handler = get_asset_handler('test_get_asset_handler.asset_handlers.PythonCompiler') 17 | self.assertIs(asset_handler.handler_class, asset_handlers.PythonCompiler) 18 | 19 | def test_asset_handler_class_with_options(self): 20 | asset_handler = get_asset_handler( 21 | path='test_get_asset_handler.asset_handlers.CompilerWithOptions', 22 | options={'level': 9}) 23 | self.assertIs(asset_handler.handler_class, asset_handlers.CompilerWithOptions) 24 | 25 | def test_asset_handler_is_a_callable(self): 26 | asset_handler = get_asset_handler('test_get_asset_handler.asset_handlers.simple_compiler') 27 | self.assertIs(asset_handler, asset_handlers.simple_compiler) 28 | 29 | @patch('warnings.warn') 30 | def test_callable_asset_handler_with_options(self, warn): 31 | get_asset_handler( 32 | path='test_get_asset_handler.asset_handlers.simple_compiler', 33 | options={'level': 9}) 34 | self.assertEqual(warn.call_count, 1) 35 | self.assertIn("{'level': 9} is provided as 'test_get_asset_handler." 36 | "asset_handlers.simple_compiler' handler", 37 | warn.call_args[0][0]) 38 | 39 | def test_asset_handler_does_not_exist(self): 40 | with self.assertRaises(ImproperlyConfigured): 41 | get_asset_handler('test_get_asset_handler.asset_handlers.nonexistent_handler') 42 | 43 | def test_asset_handler_module_does_not_exist(self): 44 | with self.assertRaises(ImproperlyConfigured): 45 | get_asset_handler('test_get_asset_handler.nonexistent_module.handler') 46 | 47 | def test_asset_handler_is_not_a_class_or_callable(self): 48 | with self.assertRaises(ImproperlyConfigured): 49 | get_asset_handler('test_get_asset_handler.asset_handlers.incorrect_handler') 50 | -------------------------------------------------------------------------------- /tests/test_get_finder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_get_finder/__init__.py -------------------------------------------------------------------------------- /tests/test_get_finder/finders.py: -------------------------------------------------------------------------------- 1 | from gears.finders import BaseFinder 2 | 3 | 4 | class GoodFinder(BaseFinder): 5 | pass 6 | 7 | 8 | class BadFinder(object): 9 | pass 10 | -------------------------------------------------------------------------------- /tests/test_get_finder/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_get_finder/models.py -------------------------------------------------------------------------------- /tests/test_get_finder/tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | from django.core.exceptions import ImproperlyConfigured 4 | from django.test import TestCase 5 | 6 | from django_gears.utils import get_finder 7 | from . import finders 8 | 9 | 10 | class GetFinderTests(TestCase): 11 | 12 | def test_if_it_is_a_subclass_of_base_finder(self): 13 | finder = get_finder('test_get_finder.finders.GoodFinder') 14 | self.assertIsInstance(finder, finders.GoodFinder) 15 | 16 | def test_if_it_is_not_a_subclass_of_base_finder(self): 17 | with self.assertRaises(ImproperlyConfigured): 18 | get_finder('test_get_finder.finders.BadFinder') 19 | -------------------------------------------------------------------------------- /tests/test_serve/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_serve/__init__.py -------------------------------------------------------------------------------- /tests/test_serve/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_serve/models.py -------------------------------------------------------------------------------- /tests/test_serve/tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | import codecs 4 | import os 5 | 6 | from django.conf import settings 7 | from django.test import TestCase, RequestFactory 8 | from django.utils.encoding import smart_str 9 | 10 | from django_gears.views import serve 11 | 12 | 13 | TESTS_DIR = os.path.join(os.path.dirname(__file__), '..') 14 | FIXTURES_DIR = os.path.join(TESTS_DIR, 'fixtures', 'serve') 15 | 16 | 17 | def read(file): 18 | with codecs.open(file, encoding='utf-8') as f: 19 | return f.read() 20 | 21 | 22 | class ServeViewTests(TestCase): 23 | 24 | def setUp(self): 25 | self.factory = RequestFactory() 26 | self.old_DEBUG = settings.DEBUG 27 | settings.DEBUG = True 28 | 29 | def tearDown(self): 30 | settings.DEBUG = self.old_DEBUG 31 | 32 | def get_response(self, path, data=None): 33 | request = self.factory.get('/static/' + path, data or {}) 34 | return serve(request, path) 35 | 36 | def get_fixture(self, path): 37 | return smart_str(read(os.path.join(FIXTURES_DIR, path)), 'utf-8') 38 | 39 | def test_returns_asset(self): 40 | response = self.get_response('js/script.js') 41 | self.assertEqual(response.content, self.get_fixture('output.js')) 42 | 43 | def test_returns_processed_source_if_body_requested(self): 44 | response = self.get_response('js/script.js', {'body': 1}) 45 | self.assertEqual(response.content, self.get_fixture('output_body.js')) 46 | -------------------------------------------------------------------------------- /tests/test_templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_templatetags/__init__.py -------------------------------------------------------------------------------- /tests/test_templatetags/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gears/django-gears/80a5cb085c5c4edac481228765edcfda3d6309f7/tests/test_templatetags/models.py -------------------------------------------------------------------------------- /tests/test_templatetags/tests.py: -------------------------------------------------------------------------------- 1 | from mock import patch, Mock 2 | 3 | from django.template import Template, Context 4 | from django.test import TestCase 5 | 6 | from gears.assets import Asset 7 | 8 | class CSSAssetTagTests(TestCase): 9 | 10 | def render(self, code, **context): 11 | return Template(u'{% load gears %}' + code).render(Context(context)) 12 | 13 | def test_outputs_public_asset_in_normal_mode(self): 14 | self.assertEqual( 15 | self.render(u'{% css_asset_tag "css/script.css" %}'), 16 | u'') 17 | 18 | def test_outputs_all_requirements_in_debug_mode(self): 19 | 20 | with patch.object(Asset, 'mtime') as mtime: 21 | mtime.__get__ = Mock(return_value = 123) 22 | 23 | self.assertEqual( 24 | self.render(u'{% css_asset_tag "css/style.css" debug %}'), 25 | (u'\n' 26 | u'\n' 27 | u'')) 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py26,py27 3 | 4 | [testenv] 5 | setenv = 6 | PYTHONPATH = {toxinidir}:{toxinidir}/tests 7 | deps = 8 | mock 9 | Django<1.6 10 | git+git://github.com/gears/gears.git 11 | commands = 12 | django-admin.py test --settings=tests.settings_get_asset_handler 13 | django-admin.py test --settings=tests.settings_get_finder 14 | django-admin.py test --settings=tests.settings_templatetags 15 | django-admin.py test --settings=tests.settings_serve 16 | django-admin.py test --settings=tests.settings_app_finder 17 | 18 | [flake8] 19 | ignore = E501 20 | max-line-length = 90 21 | --------------------------------------------------------------------------------