├── .gitignore ├── AUTHORS ├── CHANGES.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── coffeescript ├── __init__.py ├── cache.py ├── finders.py ├── models.py ├── settings.py ├── storage.py ├── templatetags │ ├── __init__.py │ └── coffeescript.py └── tests │ ├── __init__.py │ ├── django_settings.py │ ├── static │ └── scripts │ │ └── test.coffee │ ├── staticfiles_dir │ └── another_test.coffee │ ├── staticfiles_dir_with_prefix │ └── another_test.coffee │ └── tests.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | *.pyc 4 | *.egg-info 5 | *.egg 6 | .idea 7 | virtualenv 8 | COFFEESCRIPT_CACHE -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Andrey Fedoseev [https://github.com/andreyfedoseev] 2 | 3 | 4 | Contributors: 5 | 6 | Roman Vorushin [https://github.com/vorushin] 7 | Richard Plangger [https://github.com/planrich] 8 | Jacek Bzdak [https://github.com/jbzdak] 9 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | Changes 2 | ******* 3 | 4 | 0.7.2 5 | ------ 6 | 7 | - Use hashlib instead of django.utils.hashcompat which is deprecated in Django 1.5 8 | 9 | 0.7.1 10 | ------ 11 | 12 | - Always create a compiled file, even if no output was received from compiler 13 | 14 | 0.7 15 | ---- 16 | 17 | - Add COFFEESCRIPT_ROOT setting 18 | - Add staticfiles finder to serve compiled files in dev mode 19 | 20 | 21 | 0.6 22 | ---- 23 | 24 | - Switch to staticfiles.finders when looking up the files in DEBUG mode. 25 | 26 | 27 | 0.5.1 28 | ----- 29 | 30 | - Add support for STATICFILES_DIRS with prefixes 31 | 32 | 0.5 33 | ---- 34 | 35 | - When in DEBUG mode lookup coffee scripts in all STATICFILES_DIRS 36 | 37 | 0.4 38 | ---- 39 | 40 | - Log coffeescript compilation errors 41 | - Fixed bug with paths on Windows (by syabro) 42 | 43 | 0.3 44 | ---- 45 | 46 | - Use STATIC_ROOT / STATIC_URL settings when possible instead of MEDIA_ROOT / MEDIA_URL (by Roman Vorushin) 47 | 48 | 0.2.1 49 | ----- 50 | 51 | - Add CHANGES.rst to MANIFEST.in 52 | 53 | 0.2 54 | ---- 55 | 56 | - Automatically remove old files from COFFEESCRIPT_CACHE 57 | - Add basic unit tests 58 | 59 | 0.1 60 | ---- 61 | 62 | - Initial release 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | django-coffeescript 2 | ------------------- 3 | Copyright (c) 2011 django-coffeescript authors (see AUTHORS file) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | 24 | django-coffeescript contains code from Jannis Leidel's django_compressor 25 | ------------------------------------------------------------------------ 26 | Copyright (c) 2009-2011 django_compressor authors (see django_compressor AUTHORS file) 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in 36 | all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include README.rst 3 | include CHANGES.rst 4 | include LICENSE 5 | recursive-include coffeescript/tests/media *.coffee -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | **THIS PACKAGE IS NOT MAINTAINED.** 2 | 3 | Please use `django-static-precompiler `_ 4 | 5 | 6 | Django CoffeeScript 7 | =================== 8 | 9 | Django CoffeeScript provides template tags to compile CoffeeScript into JavaScript from templates. 10 | It works with both inline code and extenal files. 11 | 12 | Installation 13 | ************ 14 | 15 | 1. Add ``"coffeescript"`` to ``INSTALLED_APPS`` setting. 16 | 2. Make sure that you have ``coffee`` executable installed. See 17 | `CoffeeScript official site `_ for details. 18 | 3. Optionally, you can specify the full path to ``coffee`` executable with ``COFFEESCRIPT_EXECUTABLE`` setting. 19 | By default it's set to ``coffee``. 20 | 4. In case you use Django’s staticfiles contrib app you have to add django-coffeescript’s file finder to the ``STATICFILES_FINDERS`` setting, for example : 21 | 22 | :: 23 | 24 | STATICFILES_FINDERS = ( 25 | 'django.contrib.staticfiles.finders.FileSystemFinder', 26 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 27 | # other finders.. 28 | 'coffeescript.finders.CoffeescriptFinder', 29 | ) 30 | 31 | Example Usage 32 | ************* 33 | 34 | Inline 35 | ------ 36 | 37 | :: 38 | 39 | {% load coffeescript %} 40 | 41 | 46 | 47 | renders to 48 | 49 | :: 50 | 51 | 57 | 58 | External file 59 | ------------- 60 | 61 | :: 62 | 63 | {% load coffeescript %} 64 | 65 | 68 | 69 | renders to 70 | 71 | :: 72 | 73 | 76 | 77 | Note that by default compiled files are saved into ``COFFEESCRIPT_CACHE`` folder under your ``STATIC_ROOT`` (or ``MEDIA_ROOT`` if you have no ``STATIC_ROOT`` in your settings). 78 | You can change this folder name with ``COFFEESCRIPT_ROOT`` and ``COFFEESCRIPT_OUTPUT_DIR`` settings. 79 | 80 | 81 | Settings 82 | ******** 83 | 84 | ``COFFEESCRIPT_EXECUTABLE`` 85 | Path to CoffeeScript compiler executable. Default: ``"coffee"``. 86 | 87 | ``COFFEESCRIPT_ROOT`` 88 | Controls the absolute file path that compiled files will be written to. Default: ``STATIC_ROOT``. 89 | 90 | ``COFFEESCRIPT_OUTPUT_DIR`` 91 | Controls the directory inside ``COFFEESCRIPT_ROOT`` that compiled files will be written to. Default: ``"COFFEESCRIPT_CACHE"``. 92 | 93 | ``COFFEESCRIPT_USE_CACHE`` 94 | Whether to use cache for inline scripts. Default: ``True``. 95 | 96 | ``COFFEESCRIPT_CACHE_TIMEOUT`` 97 | Cache timeout for inline scripts (in seconds). Default: 30 days. 98 | 99 | ``COFFEESCRIPT_MTIME_DELAY`` 100 | Cache timeout for reading the modification time of external scripts (in seconds). Default: 10 seconds. 101 | -------------------------------------------------------------------------------- /coffeescript/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreyfedoseev/django-coffeescript/a2849dcef270bbc91ca74daa29e39cc157b33cc8/coffeescript/__init__.py -------------------------------------------------------------------------------- /coffeescript/cache.py: -------------------------------------------------------------------------------- 1 | from coffeescript.settings import COFFEESCRIPT_MTIME_DELAY 2 | from django.core.cache import cache 3 | from django.utils.encoding import smart_str 4 | from hashlib import md5 5 | import os.path 6 | import socket 7 | 8 | 9 | def get_hexdigest(plaintext, length=None): 10 | digest = md5(smart_str(plaintext)).hexdigest() 11 | if length: 12 | return digest[:length] 13 | return digest 14 | 15 | 16 | def get_cache_key(key): 17 | return ("django_coffescript.%s.%s" % (socket.gethostname(), key)) 18 | 19 | 20 | def get_mtime_cachekey(filename): 21 | return get_cache_key("mtime.%s" % get_hexdigest(filename)) 22 | 23 | 24 | def get_mtime(filename): 25 | if COFFEESCRIPT_MTIME_DELAY: 26 | key = get_mtime_cachekey(filename) 27 | mtime = cache.get(key) 28 | if mtime is None: 29 | mtime = os.path.getmtime(filename) 30 | cache.set(key, mtime, COFFEESCRIPT_MTIME_DELAY) 31 | return mtime 32 | return os.path.getmtime(filename) 33 | 34 | 35 | def get_hashed_mtime(filename, length=12): 36 | try: 37 | filename = os.path.realpath(filename) 38 | mtime = str(int(get_mtime(filename))) 39 | except OSError: 40 | return None 41 | return get_hexdigest(mtime, length) 42 | -------------------------------------------------------------------------------- /coffeescript/finders.py: -------------------------------------------------------------------------------- 1 | from coffeescript.storage import CoffeescriptFileStorage 2 | from django.contrib.staticfiles.finders import BaseStorageFinder 3 | 4 | 5 | class CoffeescriptFinder(BaseStorageFinder): 6 | """ 7 | A staticfiles finder that looks in COFFEESCRIPT_ROOT 8 | for compiled files, to be used during development 9 | with staticfiles development file server or during 10 | deployment. 11 | """ 12 | storage = CoffeescriptFileStorage 13 | 14 | def list(self, ignore_patterns): 15 | return [] 16 | -------------------------------------------------------------------------------- /coffeescript/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreyfedoseev/django-coffeescript/a2849dcef270bbc91ca74daa29e39cc157b33cc8/coffeescript/models.py -------------------------------------------------------------------------------- /coffeescript/settings.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | import os 3 | 4 | 5 | POSIX_COMPATIBLE = True if os.name == 'posix' else False 6 | COFFEESCRIPT_EXECUTABLE = getattr(settings, "COFFEESCRIPT_EXECUTABLE", "coffee") 7 | COFFEESCRIPT_USE_CACHE = getattr(settings, "COFFEESCRIPT_USE_CACHE", True) 8 | COFFEESCRIPT_CACHE_TIMEOUT = getattr(settings, "COFFEESCRIPT_CACHE_TIMEOUT", 60 * 60 * 24 * 30) # 30 days 9 | COFFEESCRIPT_MTIME_DELAY = getattr(settings, "COFFEESCRIPT_MTIME_DELAY", 10) # 10 seconds 10 | COFFEESCRIPT_ROOT = getattr(settings, "COFFEESCRIPT_ROOT", getattr(settings, "STATIC_ROOT", getattr(settings, "MEDIA_ROOT"))) 11 | COFFEESCRIPT_OUTPUT_DIR = getattr(settings, "COFFEESCRIPT_OUTPUT_DIR", "COFFEESCRIPT_CACHE") 12 | -------------------------------------------------------------------------------- /coffeescript/storage.py: -------------------------------------------------------------------------------- 1 | from django.core.files.storage import FileSystemStorage 2 | from coffeescript.settings import COFFEESCRIPT_ROOT 3 | 4 | 5 | class CoffeescriptFileStorage(FileSystemStorage): 6 | """ 7 | Standard file system storage for files handled by django-coffeescript. 8 | 9 | The default for ``location`` is ``COFFEESCRIPT_ROOT`` 10 | """ 11 | def __init__(self, location=None, base_url=None, *args, **kwargs): 12 | if location is None: 13 | location = COFFEESCRIPT_ROOT 14 | super(CoffeescriptFileStorage, self).__init__(location, base_url, 15 | *args, **kwargs) 16 | -------------------------------------------------------------------------------- /coffeescript/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreyfedoseev/django-coffeescript/a2849dcef270bbc91ca74daa29e39cc157b33cc8/coffeescript/templatetags/__init__.py -------------------------------------------------------------------------------- /coffeescript/templatetags/coffeescript.py: -------------------------------------------------------------------------------- 1 | from ..cache import get_cache_key, get_hexdigest, get_hashed_mtime 2 | from django.contrib.staticfiles import finders 3 | from ..settings import COFFEESCRIPT_EXECUTABLE, COFFEESCRIPT_USE_CACHE,\ 4 | COFFEESCRIPT_CACHE_TIMEOUT, COFFEESCRIPT_ROOT, COFFEESCRIPT_OUTPUT_DIR,\ 5 | POSIX_COMPATIBLE 6 | from django.conf import settings 7 | from django.core.cache import cache 8 | from django.template.base import Library, Node, TemplateSyntaxError 9 | import logging 10 | import shlex 11 | import subprocess 12 | import os 13 | 14 | 15 | STATIC_ROOT = getattr(settings, "STATIC_ROOT", getattr(settings, "MEDIA_ROOT")) 16 | 17 | 18 | logger = logging.getLogger("coffeescript") 19 | 20 | 21 | register = Library() 22 | 23 | 24 | class InlineCoffeescriptNode(Node): 25 | 26 | def __init__(self, nodelist): 27 | self.nodelist = nodelist 28 | 29 | def compile(self, source): 30 | args = shlex.split( 31 | "%s -c -s -p" % COFFEESCRIPT_EXECUTABLE, posix=POSIX_COMPATIBLE 32 | ) 33 | 34 | p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 35 | out, errors = p.communicate(source.encode("utf-8")) 36 | if out: 37 | return out.decode("utf-8") 38 | elif errors: 39 | return errors.decode("utf-8") 40 | 41 | return u"" 42 | 43 | def render(self, context): 44 | output = self.nodelist.render(context) 45 | 46 | if COFFEESCRIPT_USE_CACHE: 47 | cache_key = get_cache_key(get_hexdigest(output)) 48 | cached = cache.get(cache_key, None) 49 | if cached is not None: 50 | return cached 51 | output = self.compile(output) 52 | cache.set(cache_key, output, COFFEESCRIPT_CACHE_TIMEOUT) 53 | return output 54 | else: 55 | return self.compile(output) 56 | 57 | 58 | @register.tag(name="inlinecoffeescript") 59 | def do_inlinecoffeescript(parser, token): 60 | nodelist = parser.parse(("endinlinecoffeescript",)) 61 | parser.delete_first_token() 62 | return InlineCoffeescriptNode(nodelist) 63 | 64 | 65 | def coffeescript_paths(path): 66 | 67 | full_path = os.path.join(STATIC_ROOT, path) 68 | 69 | if settings.DEBUG and not os.path.exists(full_path): 70 | # while developing it is more confortable 71 | # searching for the coffeescript files rather then 72 | # doing collectstatics all the time 73 | full_path = finders.find(path) 74 | 75 | if full_path is None: 76 | raise TemplateSyntaxError("Can't find staticfile named: {}".format(path)) 77 | 78 | file_name = os.path.split(path)[-1] 79 | output_dir = os.path.join(COFFEESCRIPT_ROOT, COFFEESCRIPT_OUTPUT_DIR, os.path.dirname(path)) 80 | 81 | return full_path, file_name, output_dir 82 | 83 | 84 | @register.simple_tag 85 | def coffeescript(path): 86 | logger.info("processing file %s" % path) 87 | 88 | full_path, file_name, output_dir = coffeescript_paths(path) 89 | 90 | hashed_mtime = get_hashed_mtime(full_path) 91 | 92 | base_file_name = file_name.replace(".coffee","") 93 | 94 | output_file = "%s-%s.js" % (base_file_name, hashed_mtime) 95 | output_path = os.path.join(output_dir, output_file) 96 | 97 | if not os.path.exists(output_path): 98 | source_file = open(full_path) 99 | source = source_file.read() 100 | source_file.close() 101 | 102 | args = shlex.split( 103 | "%s -c -s -p" % COFFEESCRIPT_EXECUTABLE, 104 | posix=POSIX_COMPATIBLE 105 | ) 106 | p = subprocess.Popen(args, stdin=subprocess.PIPE, 107 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) 108 | out, errors = p.communicate(source) 109 | 110 | if errors: 111 | logger.error(errors) 112 | return path 113 | 114 | if not os.path.exists(output_dir): 115 | os.makedirs(output_dir) 116 | compiled_file = open(output_path, "w+") 117 | compiled_file.write(out) 118 | compiled_file.close() 119 | 120 | # Remove old files 121 | compiled_filename = os.path.split(output_path)[-1] 122 | for filename in os.listdir(output_dir): 123 | if filename.startswith(base_file_name) and filename != compiled_filename: 124 | os.remove(os.path.join(output_dir, filename)) 125 | 126 | return os.path.join(COFFEESCRIPT_OUTPUT_DIR, os.path.dirname(path), output_file) 127 | -------------------------------------------------------------------------------- /coffeescript/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreyfedoseev/django-coffeescript/a2849dcef270bbc91ca74daa29e39cc157b33cc8/coffeescript/tests/__init__.py -------------------------------------------------------------------------------- /coffeescript/tests/django_settings.py: -------------------------------------------------------------------------------- 1 | from django.conf.global_settings import * 2 | import os 3 | 4 | DEBUG = True 5 | 6 | STATIC_ROOT = MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'static') 7 | 8 | STATICFILES_DIRS = ( 9 | os.path.join(os.path.dirname(__file__), 'staticfiles_dir'), 10 | ("prefix", os.path.join(os.path.dirname(__file__), 'staticfiles_dir_with_prefix')), 11 | ) 12 | 13 | INSTALLED_APPS = ( 14 | "coffeescript", 15 | ) 16 | COFFEESCRIPT_MTIME_DELAY = 2 17 | COFFEESCRIPT_OUTPUT_DIR = "COFFEESCRIPT_CACHE" 18 | 19 | LOGGING = { 20 | 'version': 1, 21 | 'disable_existing_loggers': False, 22 | 'handlers': { 23 | 'console':{ 24 | 'level':'DEBUG', 25 | 'class':'logging.StreamHandler', 26 | }, 27 | }, 28 | 'loggers': { 29 | 'coffeescript': { 30 | 'handlers': ['console'], 31 | 'level': 'DEBUG', 32 | }, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /coffeescript/tests/static/scripts/test.coffee: -------------------------------------------------------------------------------- 1 | console.log "Hello, World!" -------------------------------------------------------------------------------- /coffeescript/tests/staticfiles_dir/another_test.coffee: -------------------------------------------------------------------------------- 1 | console.log "Hello, World from STATICFILES_DIRS!" 2 | -------------------------------------------------------------------------------- /coffeescript/tests/staticfiles_dir_with_prefix/another_test.coffee: -------------------------------------------------------------------------------- 1 | console.log "Hello, World from STATICFILES_DIRS with prefix!" 2 | -------------------------------------------------------------------------------- /coffeescript/tests/tests.py: -------------------------------------------------------------------------------- 1 | from unittest import main, TestCase 2 | from django.http import HttpRequest 3 | from django.template.base import Template 4 | from django.template.context import RequestContext 5 | import os 6 | import re 7 | import time 8 | import shutil 9 | 10 | 11 | os.environ["DJANGO_SETTINGS_MODULE"] = "coffeescript.tests.django_settings" 12 | 13 | 14 | class CoffeeScriptTestCase(TestCase): 15 | 16 | def setUp(self): 17 | from django.conf import settings as django_settings 18 | self.django_settings = django_settings 19 | 20 | output_dir = os.path.join(self.django_settings.STATIC_ROOT, 21 | self.django_settings.COFFEESCRIPT_OUTPUT_DIR) 22 | 23 | # Remove the output directory if it exists to start from scratch 24 | if os.path.exists(output_dir): 25 | shutil.rmtree(output_dir) 26 | 27 | def _get_request_context(self): 28 | return RequestContext(HttpRequest()) 29 | 30 | def _clean_javascript(self, js): 31 | """ Remove comments and all blank lines. """ 32 | return "\n".join(line for line in js.split("\n") if line.strip() and not line.startswith("//")) 33 | 34 | def test_inline_coffeescript(self): 35 | template = Template(""" 36 | {% load coffeescript %} 37 | {% inlinecoffeescript %} 38 | console.log "Hello, World" 39 | {% endinlinecoffeescript %} 40 | """) 41 | rendered = """(function() { 42 | console.log("Hello, World"); 43 | }).call(this);""" 44 | self.assertEqual( 45 | self._clean_javascript(template.render(self._get_request_context()).strip()), 46 | self._clean_javascript(rendered) 47 | ) 48 | 49 | def test_external_coffeescript(self): 50 | 51 | template = Template(""" 52 | {% load coffeescript %} 53 | {% coffeescript "scripts/test.coffee" %} 54 | """) 55 | compiled_filename_re = re.compile(r"COFFEESCRIPT_CACHE/scripts/test-[a-f0-9]{12}.js") 56 | compiled_filename = template.render(self._get_request_context()).strip() 57 | self.assertTrue(bool(compiled_filename_re.match(compiled_filename))) 58 | 59 | compiled_path = os.path.join(self.django_settings.STATIC_ROOT, compiled_filename) 60 | compiled_content = open(compiled_path).read() 61 | compiled = """(function() { 62 | console.log("Hello, World!"); 63 | }).call(this); 64 | """ 65 | self.assertEquals( 66 | self._clean_javascript(compiled_content), 67 | self._clean_javascript(compiled) 68 | ) 69 | 70 | # Change the modification time 71 | source_path = os.path.join(self.django_settings.STATIC_ROOT, "scripts/test.coffee") 72 | os.utime(source_path, None) 73 | 74 | # The modification time is cached so the compiled file is not updated 75 | compiled_filename_2 = template.render(self._get_request_context()).strip() 76 | self.assertTrue(bool(compiled_filename_re.match(compiled_filename_2))) 77 | self.assertEquals(compiled_filename, compiled_filename_2) 78 | 79 | # Wait to invalidate the cached modification time 80 | time.sleep(self.django_settings.COFFEESCRIPT_MTIME_DELAY) 81 | 82 | # Now the file is re-compiled 83 | compiled_filename_3 = template.render(self._get_request_context()).strip() 84 | self.assertTrue(bool(compiled_filename_re.match(compiled_filename_3))) 85 | self.assertNotEquals(compiled_filename, compiled_filename_3) 86 | 87 | # Check that we have only one compiled file, old files should be removed 88 | 89 | compiled_file_dir = os.path.dirname(os.path.join(self.django_settings.STATIC_ROOT, 90 | compiled_filename_3)) 91 | self.assertEquals(len(os.listdir(compiled_file_dir)), 1) 92 | 93 | def test_lookup_in_staticfiles_dirs(self): 94 | template = Template(""" 95 | {% load coffeescript %} 96 | {% coffeescript "another_test.coffee" %} 97 | """) 98 | compiled_filename_re = re.compile(r"COFFEESCRIPT_CACHE/another_test-[a-f0-9]{12}.js") 99 | compiled_filename = template.render(self._get_request_context()).strip() 100 | self.assertTrue(bool(compiled_filename_re.match(compiled_filename))) 101 | 102 | compiled_path = os.path.join(self.django_settings.STATIC_ROOT, compiled_filename) 103 | compiled_content = open(compiled_path).read() 104 | compiled = """(function() { 105 | console.log("Hello, World from STATICFILES_DIRS!"); 106 | }).call(this); 107 | """ 108 | self.assertEquals( 109 | self._clean_javascript(compiled_content), 110 | self._clean_javascript(compiled) 111 | ) 112 | 113 | 114 | template = Template(""" 115 | {% load coffeescript %} 116 | {% coffeescript "prefix/another_test.coffee" %} 117 | """) 118 | compiled_filename_re = re.compile(r"COFFEESCRIPT_CACHE/prefix/another_test-[a-f0-9]{12}.js") 119 | compiled_filename = template.render(self._get_request_context()).strip() 120 | self.assertTrue(bool(compiled_filename_re.match(compiled_filename))) 121 | 122 | compiled_path = os.path.join(self.django_settings.STATIC_ROOT, compiled_filename) 123 | compiled_content = open(compiled_path).read() 124 | compiled = """(function() { 125 | console.log("Hello, World from STATICFILES_DIRS with prefix!"); 126 | }).call(this); 127 | """ 128 | self.assertEquals( 129 | self._clean_javascript(compiled_content), 130 | self._clean_javascript(compiled) 131 | ) 132 | 133 | if __name__ == '__main__': 134 | main() 135 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | import os 3 | 4 | 5 | def read(fname): 6 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 7 | 8 | 9 | README = read('README.rst') 10 | CHANGES = read('CHANGES.rst') 11 | 12 | 13 | setup( 14 | name = "django-coffeescript", 15 | packages = find_packages(), 16 | version = "0.7.2", 17 | author = "Andrey Fedoseev", 18 | author_email = "andrey.fedoseev@gmail.com", 19 | url = "https://github.com/andreyfedoseev/django-coffeescript", 20 | description = "Django template tags to compile CoffeeScript", 21 | long_description = "\n\n".join([README, CHANGES]), 22 | classifiers = [ 23 | 'Development Status :: 4 - Beta', 24 | 'Framework :: Django', 25 | 'Intended Audience :: Developers', 26 | 'License :: OSI Approved :: BSD License', 27 | 'Operating System :: OS Independent', 28 | 'Programming Language :: Python', 29 | 'Topic :: Internet :: WWW/HTTP', 30 | ], 31 | keywords = ["coffeescript"], 32 | ) 33 | --------------------------------------------------------------------------------