Commits

Mike Orr committed 441f6dc

Move minify dependencies inside functions per WebHelpers policy.

Comments (0)

Files changed (3)

tests/test_pylonslib_minify.py

 # -*- coding: utf-8 -*-
 
 import os
+import shutil
+import tempfile
 from unittest import TestCase
 
-import minwebhelpers
-from minwebhelpers import javascript_link, stylesheet_link, beaker_kwargs
+from nose.plugins.skip import SkipTest
 
-from fixtures import config, beaker_cache, fixture_path
-minwebhelpers.config = config
-minwebhelpers.beaker_cache = beaker_cache
+
+### BEGIN inlined fixtures.py
+import os
+
+fixture_path = os.path.dirname(os.path.abspath(__file__))
+global beaker_container
+beaker_container = dict()
+
+config = {
+    'pylons.paths': {'static_files': fixture_path},
+    'debug': False,
+}
+
+def beaker_cache(*args, **kwargs):
+    beaker_container.update(kwargs)
+
+    try:
+        from decorator import decorator
+    except ImportError:
+        raise SkipTest("decorator not installed")
+
+    @decorator
+    def wrapper(f, *a, **kw):
+        return f(*a, **kw)
+
+    return wrapper
+### END inlined fixtures.py
+
+#from fixtures import config, beaker_cache, fixture_path
 
 
 class MinificationTestCase(TestCase):
 
+    def setUp(self):
+        # See if we can import minify's dependencies
+        try:
+            import pylons
+        except ImportError:
+            raise SkipTest("Pylons not installed")
+        try:
+            import cssutils
+        except ImportError:
+            raise SkipTest("cssutils not installed")
+        try:
+            import beaker
+        except ImportError:
+            raise SkipTest("Beaker not installed")
+        try:
+            import decorator
+        except ImportError:
+            raise SkipTest("decorator not installed")
+        # OK, finish initialization
+        import webhelpers.pylonslib.minify as minify
+        minify.config = config
+        minify.beaker_cache = beaker_cache
+        self.minify = minify
+        self.tmpdir = tempfile.mkdtemp()
+
+    def tearDown(self):
+        shutil.rmtree(self.tmpdir)
+
     def purge_files(self, *files):
         for file_ in files:
             path = os.path.join(fixture_path, file_)
     def test_paths(self):
         """Testing if paths are constructed correctly"""
         # minify and combine
-        js_source = javascript_link('/deep/a.js', '/b.js', combined=True, minified=True)
-        css_source = stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True)
+        js_source = self.minify.javascript_link('/deep/a.js', '/b.js', combined=True, minified=True)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True)
         self.assert_('"/a.b.COMBINED.min.css"' in css_source)
         self.assert_('"/a.b.COMBINED.min.js"' in js_source)
         
         # combine
-        js_source = javascript_link('/deep/a.js', '/b.js', combined=True)
-        css_source = stylesheet_link('/deep/a.css', '/b.css', combined=True)
+        js_source = self.minify.javascript_link('/deep/a.js', '/b.js', combined=True)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/b.css', combined=True)
         self.assert_('"/a.b.COMBINED.css"' in css_source)
         self.assert_('"/a.b.COMBINED.js"' in js_source)
 
         # minify
-        js_source = javascript_link('/deep/a.js', '/b.js', minified=True)
-        css_source = stylesheet_link('/deep/a.css', '/b.css', minified=True)
+        js_source = self.minify.javascript_link('/deep/a.js', '/b.js', minified=True)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/b.css', minified=True)
         self.assert_('"/deep/a.min.css"' in css_source)
         self.assert_('"/b.min.css"' in css_source)
         self.assert_('"/deep/a.min.js"' in js_source)
         self.assert_('"/b.min.js"' in js_source)
 
         # root minify and combined
-        js_source = javascript_link('/c.js', '/b.js', combined=True, minified=True)
-        css_source = stylesheet_link('/c.css', '/b.css', combined=True, minified=True)
+        js_source = self.minify.javascript_link('/c.js', '/b.js', combined=True, minified=True)
+        css_source = self.minify.stylesheet_link('/c.css', '/b.css', combined=True, minified=True)
         self.assert_('"/c.b.COMBINED.min.css"' in css_source)
         self.assert_('"/c.b.COMBINED.min.js"' in js_source)
 
         # root minify
-        js_source = javascript_link('/c.js', '/b.js', minified=True)
-        css_source = stylesheet_link('/c.css', '/b.css', minified=True)
+        js_source = self.minify.javascript_link('/c.js', '/b.js', minified=True)
+        css_source = self.minify.stylesheet_link('/c.css', '/b.css', minified=True)
         self.assert_('"/b.min.css"' in css_source)
         self.assert_('"/b.min.js"' in js_source)
         self.assert_('"/c.min.js"' in js_source)
         self.assert_('"/c.min.js"' in js_source)
 
         # both root minify and combined
-        js_source = javascript_link('/deep/a.js', '/deep/d.js', combined=True, minified=True)
-        css_source = stylesheet_link('/deep/a.css', '/deep/d.css', combined=True, minified=True)
+        js_source = self.minify.javascript_link('/deep/a.js', '/deep/d.js', combined=True, minified=True)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/deep/d.css', combined=True, minified=True)
         self.assert_('"/deep/a.d.COMBINED.min.css"' in css_source)
         self.assert_('"/deep/a.d.COMBINED.min.js"' in js_source)
 
-        # Cleanup
-        self.purge_files('a.b.COMBINED.min.js', 'a.b.COMBINED.min.css')
-        self.purge_files('a.b.COMBINED.js', 'a.b.COMBINED.css')
-        self.purge_files('deep/a.min.css', 'deep/a.min.js', 'b.min.js', 'b.min.css')
-        self.purge_files('c.b.COMBINED.min.js', 'c.b.COMBINED.min.css')
-        #self.purge_files('b.min.js', 'b.min.css', 'c.min.js', 'c.min.css')
-        self.purge_files('deep/a.d.COMBINED.min.js', 'deep/a.d.COMBINED.min.css')
+        # Cleanup -- done by .tearDown()
+        #self.purge_files('a.b.COMBINED.min.js', 'a.b.COMBINED.min.css')
+        #self.purge_files('a.b.COMBINED.js', 'a.b.COMBINED.css')
+        #self.purge_files('deep/a.min.css', 'deep/a.min.js', 'b.min.js', 'b.min.css')
+        #self.purge_files('c.b.COMBINED.min.js', 'c.b.COMBINED.min.css')
+        ##self.purge_files('b.min.js', 'b.min.css', 'c.min.js', 'c.min.css')
+        #self.purge_files('deep/a.d.COMBINED.min.js', 'deep/a.d.COMBINED.min.css')
 
     def test_beaker_kwargs(self):
         """Testing for proper beaker kwargs usage"""
-        css_source = stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True)
-        from fixtures import beaker_container
-        self.assertEqual(beaker_container, beaker_kwargs)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True)
+        self.assertEqual(beaker_container, self.minify.beaker_kwargs)
 
-        css_source = stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True, beaker_kwargs={'foo': 'bar'})
-        from fixtures import beaker_container
-        beaker_kwargs.update({'foo': 'bar'})
-        self.assertEqual(beaker_container, beaker_kwargs)
+        css_source = self.minify.stylesheet_link('/deep/a.css', '/b.css', combined=True, minified=True, beaker_kwargs={'foo': 'bar'})
+        self.minify.beaker_kwargs.update({'foo': 'bar'})
+        self.assertEqual(beaker_container, self.minify.beaker_kwargs)

webhelpers/pylonslib/jsmin.py

 #!/usr/bin/python
+"""A Javascript minification utility.
+
+Minification squeezes out spaces and other characters not significant to
+Javascript.  This results in a shorter file size.
+
+Usage::
+
+    jsm = JavascriptMinify()
+    jsm.minify(input_file_object, output_file_object)
+
+Or if the Javascript is in a string (slightly less efficient)::
+
+    js = jsmin(js)
+
+This is a wrapper around ``JavscriptMinify``, so if your input and output are
+already file objects, it's more efficient to use ``JavascriptMinify`` directly.
+
+Originally written in C by Douglas Crockford, and ported to Python by Baruch 
+Even.
+"""
 
 # This code is original from jsmin by Douglas Crockford, it was translated to
 # Python by Baruch Even. The original code had the following copyright and

webhelpers/pylonslib/minify.py

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 # vim: sw=4 ts=4 fenc=utf-8
+"""Minification helpers.
+
+This module provides enhanced versions of the ``javascript_link`` and
+``stylesheet_link`` helpers in ``webhelpers.html.tags``.  These versions add
+three additional arguments:
+
+* **minified**: If true, reduce the file size by squeezing out
+  whitespace and other characters insignificant to the Javascript or CSS syntax.
+* **combined**: If true, concatenate the specified files into one file to
+  reduce page load time.
+* **beaker_kwargs** (dict): arguments to pass to ``beaker_cache``.
+
+Dependencies: ``Pylons``, ``Beaker``, and ``cssutils`` (all available in PyPI).
+
+Contributed by Pedro Algarvio and Domen Kozar <ufs@ufsoft.org>.
+URL: http://docs.fubar.si/minwebhelpers/
+"""
 
 import re
 import os
 import logging
 import StringIO
 
-import cssutils
-from jsmin import JavascriptMinify
-from cssutils.serialize import CSSSerializer
-from pylons import config
-from pylons.decorators.cache import beaker_cache
-
 from webhelpers.html.tags import javascript_link as __javascript_link
 from webhelpers.html.tags import stylesheet_link as __stylesheet_link
+from webhelpers.pylonslib.jsmin import JavascriptMinify
 
 
 __all__ = ['javascript_link', 'stylesheet_link']
     return [os.path.join(base, fname)]
 
 def minify_sources(sources, ext, fs_root=''):
+    import cssutils 
+
     if 'js' in ext:
         js_minify = JavascriptMinify()
     minified_sources = []
             js_minify.minify(open(full_source, 'r'), f_minified_source)
         # minify css source
         if 'css' in ext:
+            serializer = get_serializer()
             sheet = cssutils.parseFile(full_source)
-            sheet.setSerializer(CSSUtilsMinificationSerializer())
+            sheet.setSerializer(serializer)
             cssutils.ser.prefs.useMinified()
             f_minified_source.write(sheet.cssText)
 
     return minified_sources
 
 def base_link(ext, *sources, **options):
+    from pylons import config
+    from pylons.decorators.cache import beaker_cache
+
     combined = options.pop('combined', False)
     minified = options.pop('minified', False)
     beaker_options = options.pop('beaker_kwargs', False)
     return base_link('css', *sources, **options)
 
 
-class CSSUtilsMinificationSerializer(CSSSerializer):
-    def __init__(self, prefs=None):
-        CSSSerializer.__init__(self, prefs)
+_serializer_class = None
 
-    def do_css_CSSStyleDeclaration(self, style, separator=None):
-        try:
-            color = style.getPropertyValue('color')
-            if color and color is not u'':
-                color = self.change_colors(color)
-                style.setProperty('color', color)
-        except:
-            pass
-        return re.sub(r'0\.([\d])+', r'.\1',
-                      re.sub(r'(([^\d][0])+(px|em)+)+', r'\2',
-                      CSSSerializer.do_css_CSSStyleDeclaration(self, style,
-                                                               separator)))
+def get_serializer():
+    # This is in a function to prevent a global import of ``cssutils``,
+    # which is not a WebHelpers dependency.
+    # The class is cached in a global variable so that it will be 
+    # compiled only once.
 
-    def change_colors(self, color):
-        colours = {
-            'black': '#000000',
-            'fuchia': '#ff00ff',
-            'yellow': '#ffff00',
-            '#808080': 'gray',
-            '#008000': 'green',
-            '#800000': 'maroon',
-            '#000800': 'navy',
-            '#808000': 'olive',
-            '#800080': 'purple',
-            '#ff0000': 'red',
-            '#c0c0c0': 'silver',
-            '#008080': 'teal'
-        }
-        if color.lower() in colours:
-            color = colours[color.lower()]
+    import cssutils
 
-        if color.startswith('#') and len(color) == 7:
-            if color[1]==color[2] and color[3]==color[4] and color[5]==color[6]:
-                color = '#%s%s%s' % (color[1], color[3], color[5])
-        return color
+    global _serializer_class
+    if not _serializer_class:
+        class CSSUtilsMinificationSerializer(cssutils.CSSSerializer):
+            def __init__(self, prefs=None):
+                CSSSerializer.__init__(self, prefs)
+
+            def do_css_CSSStyleDeclaration(self, style, separator=None):
+                try:
+                    color = style.getPropertyValue('color')
+                    if color and color is not u'':
+                        color = self.change_colors(color)
+                        style.setProperty('color', color)
+                except:
+                    pass
+                return re.sub(r'0\.([\d])+', r'.\1',
+                              re.sub(r'(([^\d][0])+(px|em)+)+', r'\2',
+                              cssutils.CSSSerializer.do_css_CSSStyleDeclaration(
+                                  self, style, separator)))
+
+            def change_colors(self, color):
+                colours = {
+                    'black': '#000000',
+                    'fuchia': '#ff00ff',
+                    'yellow': '#ffff00',
+                    '#808080': 'gray',
+                    '#008000': 'green',
+                    '#800000': 'maroon',
+                    '#000800': 'navy',
+                    '#808000': 'olive',
+                    '#800080': 'purple',
+                    '#ff0000': 'red',
+                    '#c0c0c0': 'silver',
+                    '#008080': 'teal'
+                }
+                if color.lower() in colours:
+                    color = colours[color.lower()]
+
+                if color.startswith('#') and len(color) == 7:
+                    if color[1]==color[2] and color[3]==color[4] and color[5]==color[6]:
+                        color = '#%s%s%s' % (color[1], color[3], color[5])
+                return color
+        # End of class CSSUtilsMinificationSerializer
+        _serializer_class = CSSUtilsMinificationSerializer
+    return _serializer_class()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.