← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sidnei/lazr-js/assignment-for-better-compression into lp:lazr-js

 

Sidnei da Silva has proposed merging lp:~sidnei/lazr-js/assignment-for-better-compression into lp:lazr-js.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #736553 in LAZR Javascript Library: "make metadata more compressable by using assignment"
  https://bugs.launchpad.net/lazr-js/+bug/736553

For more details, see:
https://code.launchpad.net/~sidnei/lazr-js/assignment-for-better-compression/+merge/53735

Uses assignment for building up the modules structure, in hope of achieving better minification of the generated metadata file.
-- 
https://code.launchpad.net/~sidnei/lazr-js/assignment-for-better-compression/+merge/53735
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sidnei/lazr-js/assignment-for-better-compression into lp:lazr-js.
=== modified file 'src-py/lazr/js/meta.py'
--- src-py/lazr/js/meta.py	2010-03-16 19:07:19 +0000
+++ src-py/lazr/js/meta.py	2011-03-17 03:14:23 +0000
@@ -2,7 +2,6 @@
 import re
 import sys
 import glob
-import itertools
 import optparse
 
 import simplejson
@@ -108,7 +107,10 @@
             metadata.extend(meta)
 
         modules = {}
-        all_literals = []
+
+        # Include config keys in literals.
+        all_literals = ["use", "requires", "after", "type",
+                        "ext", "path", "css", "js", "skinnable"]
         for meta in metadata:
             name = meta.pop("name")
             modules[name] = meta
@@ -118,13 +120,6 @@
             all_literals.extend(meta.get("after", ()))
             all_literals.append(meta["type"])
 
-        # Only optimize string literals if they are used more than
-        # once, since otherwise the optimization is pointless. This
-        # loop here is basically filtering out those that only occur
-        # once.
-        literals = [k for k, g in itertools.groupby(sorted(all_literals))
-                    if len(list(g)) > 1]
-
         # For each string literal we are interested in, generate a
         # variable declaration for the string literal, to improve
         # minification.
@@ -136,10 +131,7 @@
         # We'll save a mapping of literal -> variable name here for
         # reuse below on the re.sub() helper function.
         literals_map = dict([(literal, NAME_RE.sub("_", literal).upper())
-                             for literal in literals])
-        variables_decl = "var %s" % ",\n  ".join(
-            ["%s = \"%s\"" % (variable, literal)
-             for literal, variable in sorted(literals_map.iteritems())])
+                             for literal in set(all_literals)])
 
         # This re.sub() helper function operates on the JSON-ified
         # representation of the modules, by looking for string
@@ -156,13 +148,60 @@
                 return match.group(1) + literals_map[literal] + match.group(3)
             return match.group(0)
 
-        modules_decl = LITERAL_RE.sub(literal_sub, simplejson.dumps(modules))
+        variables_decl = ",\n  ".join(
+            ["var SKIN_SAM_PREFIX = 'skin-sam-'",
+             "LAZR = 'lazr'"] +
+            ["%s = %s" % (
+                variable, ('"%s"' % literal).replace(
+                    '"skin-sam-', 'SKIN_SAM_PREFIX + "').replace(
+                    '"lazr', 'LAZR + "'))
+                for literal, variable in sorted(literals_map.iteritems())])
+
+        # Default 'after' modules from YUI Loader. Might have to
+        # be changed in the future, if YUI itself changes.
+        core_css = ["cssreset", "cssfonts",
+                    "cssgrids", "cssreset-context",
+                    "cssfonts-context",
+                    "cssgrids-context"]
+
+        # Append a few more helper variables for our own use.
+        variables_decl += ",\n  ".join(
+            ["",
+             "modules = {}",
+             "TRUE = true",
+             "FALSE = false",
+             "CORE_CSS = %s" % LITERAL_RE.sub(literal_sub,
+                                              simplejson.dumps(core_css)),
+             "module_info"])
+
+        modules_decl = []
+        for module_name, module_info in sorted(modules.iteritems()):
+            module_decl = [
+                "modules[%s] = module_info = {}" %
+                NAME_RE.sub("_", module_name).upper()]
+            for key, value in sorted(module_info.iteritems()):
+                if value is True or value is False:
+                    value = str(value).upper()
+                elif value in ("css", "js"):
+                    value = value.upper()
+                else:
+                    value = LITERAL_RE.sub(literal_sub, simplejson.dumps(value))
+                if key == "after" and module_info["type"] == "css":
+                    value = "CORE_CSS + %s" % value
+                module_decl.append("module_info[%s] = %s" %
+                                   (key.upper(), value))
+            modules_decl.append(";\n  ".join(module_decl))
+
+        modules_decl = ";\n\n  ".join(modules_decl)
 
         module_config = open(out, "w")
         try:
             module_config.write("""var %s = (function(){
   %s;
-  return %s;
+
+  %s;
+
+  return modules;
 })();""" % (var_name, variables_decl, modules_decl))
         finally:
             module_config.close()
@@ -181,19 +220,12 @@
         if self.prefix and not prefix.endswith("/"):
             prefix = self.prefix + "/"
 
-        # Default 'after' modules from YUI Loader. Might have to
-        # be changed in the future, if YUI itself changes.
-        after = ["cssreset", "cssfonts",
-                 "cssgrids", "cssreset-context",
-                 "cssfonts-context",
-                 "cssgrids-context"]
-
         if entry.get("requires"):
             # If the base module requires other modules, extend
             # the after entry with the (expected) skins for those
             # modules to force our skin to be loaded after those.
-            after.extend(["skin-sam-%s" % s
-                          for s in entry["requires"]])
+            after = ["skin-sam-%s" % s
+                     for s in entry["requires"]]
 
         assets = os.path.join(
             os.path.dirname(entry["path"][len(prefix):]), "assets")

=== modified file 'src-py/lazr/js/tests/test_meta.py'
--- src-py/lazr/js/tests/test_meta.py	2010-03-16 19:07:19 +0000
+++ src-py/lazr/js/tests/test_meta.py	2011-03-17 03:14:23 +0000
@@ -2,7 +2,6 @@
 from unittest import defaultTestLoader, TestCase
 
 import mocker
-import simplejson
 
 from lazr.js.meta import Builder, extract_metadata
 
@@ -220,13 +219,13 @@
 
         got = open(output, "r").read()
         prefix = got[:18]
-        modules = got.splitlines()[-2].strip()[7:-1]
+        modules = "\n\n".join(got.split("\n\n")[1:-1])
         self.assertEquals(prefix, "var LAZR_CONFIG = ")
-        self.assertTrue('"path": "anim/anim-min.js"' in modules)
-        self.assertFalse('"skinnable": false' in modules)
-        self.assertTrue('"type": "js"' in modules)
-        self.assertTrue('"use": ["dom"]' in modules)
-        self.assertTrue('"ext": true' in modules)
+        self.assertTrue('[PATH] = "anim/anim-min.js"' in modules)
+        self.assertFalse('[SKINNABLE] = FALSE' in modules)
+        self.assertTrue('[TYPE] = JS' in modules)
+        self.assertTrue('[USE] = [DOM]' in modules)
+        self.assertTrue('[EXT] = TRUE' in modules)
 
     def test_extract_skinnable(self):
         """
@@ -256,22 +255,20 @@
 
         got = open(output, "r").read()
         prefix = got[:18]
-        modules = got.splitlines()[-2].strip()[7:-1]
+        modules = "\n\n".join(got.split("\n\n")[1:-1])
         self.assertEquals(prefix, "var LAZR_CONFIG = ")
         self.assertTrue(
-            '"path": "lazr/anim/assets/skins/sam/anim-skin.css"' in modules)
-        self.assertTrue(
-            '"path": "lazr/anim/anim-min.js"' in modules)
-        self.assertTrue('"skinnable": true' in modules)
-        self.assertTrue('"type": "js"' in modules)
-        self.assertTrue('"type": "css"' in modules)
-        self.assertTrue('"use": ["dom"]' in modules)
-        self.assertTrue('"requires": ["widget"]' in modules)
-        self.assertTrue(
-            ('"after": ["cssreset", "cssfonts", "cssgrids", '
-             '"cssreset-context", "cssfonts-context", "cssgrids-context", '
-             '"skin-sam-widget"]') in modules)
-        self.assertTrue('"ext": true' in modules)
+            '[PATH] = "lazr/anim/assets/skins/sam/anim-skin.css"' in modules)
+        self.assertTrue(
+            '[PATH] = "lazr/anim/anim-min.js"' in modules)
+        self.assertTrue('[SKINNABLE] = TRUE' in modules)
+        self.assertTrue('[TYPE] = JS' in modules)
+        self.assertTrue('[TYPE] = CSS' in modules)
+        self.assertTrue('[USE] = [DOM]' in modules)
+        self.assertTrue('[REQUIRES] = [WIDGET]' in modules)
+        self.assertTrue(
+            ('[AFTER] = CORE_CSS + [SKIN_SAM_WIDGET]') in modules)
+        self.assertTrue('[EXT] = TRUE' in modules)
 
     def test_extract_skinnable_with_lazr_conventions(self):
         """
@@ -308,49 +305,26 @@
 
         got = open(output, "r").read()
         prefix = got[:18]
-        lines = got.splitlines()
-        modules = lines[-2].strip()[7:-1]
-        variables = {}
-        for line in lines[1:-2]:
-            variable, literal = line.split("=")
-            variable = variable.strip(" ").split(" ")[-1]
-            variables[variable] = literal.strip(" ").split("\"")[1]
+        blocks = got.split("\n\n")
+        modules = "\n\n".join(blocks[1:-1])
         self.assertEquals(prefix, "var LAZR_CONFIG = ")
 
-        # Variables are only defined for optimizing minification if
-        # they are used more than once, see how "dom" and "js" are not
-        # included in this list, even though they are used by the
-        # module.  All the other names are used more than once due to
-        # the two CSS files that are part of the skin for this module.
-        self.assertEquals(variables, {
-            "CSS": "css",
-            "CSSFONTS": "cssfonts",
-            "CSSFONTS_CONTEXT": "cssfonts-context",
-            "CSSGRIDS": "cssgrids",
-            "CSSGRIDS_CONTEXT": "cssgrids-context",
-            "CSSRESET": "cssreset",
-            "CSSRESET_CONTEXT": "cssreset-context",
-            "SKIN_SAM_LAZR_ANIM_CORE": "skin-sam-lazr.anim+core",
-            "SKIN_SAM_WIDGET": "skin-sam-widget"})
-
-        self.assertTrue(
-            '"path": "lazr/anim/assets/purty-anim-core.css"' in modules)
-        self.assertTrue(
-            '"path": "lazr/anim/assets/skins/sam/purty-anim-skin.css"'
+        self.assertTrue(
+            '[PATH] = "lazr/anim/assets/purty-anim-core.css"' in modules)
+        self.assertTrue(
+            '[PATH] = "lazr/anim/assets/skins/sam/purty-anim-skin.css"'
             in modules)
         self.assertTrue(
-            '"path": "lazr/anim/anim-min.js"' in modules)
-        self.assertTrue('"skinnable": true' in modules)
-        self.assertTrue('"type": "js"' in modules)
-        self.assertTrue('"type": CSS' in modules)
-        self.assertTrue('"use": ["dom"]' in modules)
-        self.assertTrue('"requires": ["widget"]' in modules)
-        self.assertTrue('"requires": [SKIN_SAM_LAZR_ANIM_CORE]' in modules)
+            '[PATH] = "lazr/anim/anim-min.js"' in modules)
+        self.assertTrue('[SKINNABLE] = TRUE' in modules)
+        self.assertTrue('[TYPE] = JS' in modules)
+        self.assertTrue('[TYPE] = CSS' in modules)
+        self.assertTrue('[USE] = [DOM]' in modules)
+        self.assertTrue('[REQUIRES] = [WIDGET]' in modules)
+        self.assertTrue('[REQUIRES] = [SKIN_SAM_LAZR_ANIM_CORE]' in modules)
         self.assertTrue(
-            ('"after": [CSSRESET, CSSFONTS, CSSGRIDS, '
-            'CSSRESET_CONTEXT, CSSFONTS_CONTEXT, CSSGRIDS_CONTEXT, '
-            'SKIN_SAM_WIDGET, SKIN_SAM_LAZR_ANIM_CORE]') in modules)
-        self.assertTrue('"ext": true' in modules)
+            ('[AFTER] = CORE_CSS + [SKIN_SAM_WIDGET, SKIN_SAM_LAZR_ANIM_CORE]') in modules)
+        self.assertTrue('[EXT] = TRUE' in modules)
 
 
 def test_suite():