Commits

Anonymous committed ff1f5e6

Split inclusion into a standalone python module.

Comments (0)

Files changed (4)

fanstatic/__init__.py

                                 CompilerRegistry,
                                 MinifierRegistry)
 from fanstatic.codegen import generate_code
-from fanstatic.injector import (
-    Inclusion,
-    Injector,
-    make_injector,
-    bundle_resources,
-    sort_resources)
+from fanstatic.injector import (Injector,
+                                make_injector)
+from fanstatic.inclusion import (Inclusion,
+                                 bundle_resources,
+                                 sort_resources)
 from fanstatic.publisher import (Publisher, Delegator, make_publisher,
                                  LibraryPublisher)
 from fanstatic.wsgi import Fanstatic, make_fanstatic, Serf, make_serf

fanstatic/inclusion.py

+
+from fanstatic.core import Bundle
+
+def bundle_resources(resources):
+    """Bundle sorted resources together.
+
+    resources is expected to be a list previously sorted by sorted_resources.
+
+    Returns a list of renderable resources, which can include several
+    resources bundled together into Bundles.
+    """
+    result = []
+    bundle = Bundle()
+    for resource in resources:
+        if bundle.fits(resource):
+            bundle.append(resource)
+        else:
+            # add the previous bundle to the list and create new bundle
+            bundle.add_to_list(result)
+            bundle = Bundle()
+            if resource.dont_bundle:
+                result.append(resource)
+            else:
+                bundle.append(resource)
+    # add the last bundle to the list
+    bundle.add_to_list(result)
+    return result
+
+
+def rollup_resources(resources):
+    """Rollup resources together: if a resource include multiple
+    separate ones (i.e. is a rollup) and all the separate ones are
+    included the rollup will be used instead.
+    """
+    # keep track of rollups: rollup key -> set of resource keys
+    potential_rollups = {}
+    for resource in resources:
+        for rollup in resource.rollups:
+            s = potential_rollups.setdefault(
+                (rollup.library, rollup.relpath), set())
+            s.add((resource.library, resource.relpath))
+
+    # now go through resources, replacing them with rollups if
+    # conditions match
+    result = set()
+    for resource in resources:
+        superseders = []
+        for rollup in resource.rollups:
+            s = potential_rollups[(rollup.library, rollup.relpath)]
+            if len(s) == len(rollup.supersedes):
+                superseders.append(rollup)
+        if superseders:
+            # use the exact superseder that rolls up the most
+            superseders = sorted(superseders, key=lambda i: len(i.supersedes))
+            result.add(superseders[-1])
+        else:
+            # nothing to supersede resource so use it directly
+            result.add(resource)
+    return result
+
+
+def sort_resources(resources):
+    """Sort resources for inclusion on web page.
+
+    A number of rules are followed:
+
+    * resources are always grouped per renderer (.js, .css, etc)
+    * resources that depend on other resources are sorted later
+    * resources are grouped by library, if the dependencies allow it
+    * libraries are sorted by name, if dependencies allow it
+    * resources are sorted by resource path if they both would be
+      sorted the same otherwise.
+
+    The only purpose of sorting on library is so we can
+    group resources per library, so that bundles can later be created
+    of them if bundling support is enabled.
+
+    Note this sorting algorithm guarantees a consistent ordering, no
+    matter in what order resources were needed.
+    """
+    for resource in resources:
+        resource.library.init_library_nr()
+
+    def key(resource):
+        return (
+            resource.order,
+            resource.library.library_nr,
+            resource.library.name,
+            resource.dependency_nr,
+            resource.relpath)
+    return sorted(resources, key=key)
+
+
+class Inclusion(object):
+    """Will be instantiated for every request.
+
+    :param minified: If set to ``True``, Fanstatic will include all
+      resources in ``minified`` form. If a Resource instance does not
+      provide a ``minified`` mode, the "main" (non-named) mode is used.
+
+    :param debug: If set to ``True``, Fanstatic will include all
+      resources in ``debug`` form. If a Resource instance does not
+      provide a ``debug`` mode, the "main" (non-named) mode is used.
+      An exception is raised when both the ``debug`` and ``minified``
+      parameters are ``True``.
+
+    :param rollup: If set to True (default is False) rolled up
+      combined resources will be served if they exist and supersede
+      existing resources that are needed.
+
+    :param bundle: If set to True, Fanstatic will attempt to bundle
+      resources that fit together into larger Bundle objects. These
+      can then be rendered as single URLs to these bundles.
+
+    :param compile: XXX
+    """
+    def __init__(self, needed, resources=None,
+            compile=False, bundle=False,
+            mode=None, rollup=False):
+        # Needed is basically the context object.
+        self.needed = needed
+
+        if resources is None:
+            resources = needed.resources()
+
+        if rollup:
+            resources = rollup_resources(resources)
+
+        if mode is not None:
+            resources = [resource.mode(mode) for resource in resources]
+
+        resources = sort_resources(resources)
+
+        if compile:
+            for resource in resources:
+                resource.compile()
+
+        if bundle:
+            resources = bundle_resources(resources)
+
+        self.resources = resources
+
+    def __len__(self):
+        return len(self.resources)
+
+    def render(self):
+        result = []
+        for resource in self.resources:
+            result.append(
+                resource.render(
+                    self.needed.library_url(resource.library)))
+        return '\n'.join(result)
+

fanstatic/injector.py

 import webob
 
 from fanstatic.config import convert_config
+from fanstatic.inclusion import Inclusion
 from fanstatic import ConfigurationError
 from fanstatic import compat
-from fanstatic.core import Bundle
 from fanstatic import DEBUG, MINIFIED
 import fanstatic
 
 
         return response(environ, start_response)
 
-
-class Inclusion(object):
-    """Will be instantiated for every request.
-
-    :param minified: If set to ``True``, Fanstatic will include all
-      resources in ``minified`` form. If a Resource instance does not
-      provide a ``minified`` mode, the "main" (non-named) mode is used.
-
-    :param debug: If set to ``True``, Fanstatic will include all
-      resources in ``debug`` form. If a Resource instance does not
-      provide a ``debug`` mode, the "main" (non-named) mode is used.
-      An exception is raised when both the ``debug`` and ``minified``
-      parameters are ``True``.
-
-    :param rollup: If set to True (default is False) rolled up
-      combined resources will be served if they exist and supersede
-      existing resources that are needed.
-
-    :param bundle: If set to True, Fanstatic will attempt to bundle
-      resources that fit together into larger Bundle objects. These
-      can then be rendered as single URLs to these bundles.
-
-    :param compile: XXX
-    """
-    def __init__(self, needed, resources=None,
-            compile=False, bundle=False,
-            mode=None, rollup=False):
-
-        # Needed is basically the context object.
-        self.needed = needed
-
-        if resources is None:
-            resources = needed.resources()
-
-        if rollup:
-            resources = rollup_resources(resources)
-
-        if mode is not None:
-            resources = [resource.mode(mode) for resource in resources]
-
-        resources = sort_resources(resources)
-
-        if compile:
-            for resource in resources:
-                resource.compile()
-
-        if bundle:
-            resources = bundle_resources(resources)
-
-        self.resources = resources
-
-    def __len__(self):
-        return len(self.resources)
-
-    def render(self):
-        result = []
-        for resource in self.resources:
-            result.append(
-                resource.render(
-                    self.needed.library_url(resource.library)))
-        return '\n'.join(result)
-
-
 class InjectorPlugin(object):
     """Base class that can be use to write an injector plugin. It will
     take out from the configuration the common options that can be
         return html
 
 
-
-def bundle_resources(resources):
-    """Bundle sorted resources together.
-
-    resources is expected to be a list previously sorted by sorted_resources.
-
-    Returns a list of renderable resources, which can include several
-    resources bundled together into Bundles.
-    """
-    result = []
-    bundle = Bundle()
-    for resource in resources:
-        if bundle.fits(resource):
-            bundle.append(resource)
-        else:
-            # add the previous bundle to the list and create new bundle
-            bundle.add_to_list(result)
-            bundle = Bundle()
-            if resource.dont_bundle:
-                result.append(resource)
-            else:
-                bundle.append(resource)
-    # add the last bundle to the list
-    bundle.add_to_list(result)
-    return result
-
-
-def rollup_resources(resources):
-    """Rollup resources together: if a resource include multiple
-    separate ones (i.e. is a rollup) and all the separate ones are
-    included the rollup will be used instead.
-    """
-    # keep track of rollups: rollup key -> set of resource keys
-    potential_rollups = {}
-    for resource in resources:
-        for rollup in resource.rollups:
-            s = potential_rollups.setdefault(
-                (rollup.library, rollup.relpath), set())
-            s.add((resource.library, resource.relpath))
-
-    # now go through resources, replacing them with rollups if
-    # conditions match
-    result = set()
-    for resource in resources:
-        superseders = []
-        for rollup in resource.rollups:
-            s = potential_rollups[(rollup.library, rollup.relpath)]
-            if len(s) == len(rollup.supersedes):
-                superseders.append(rollup)
-        if superseders:
-            # use the exact superseder that rolls up the most
-            superseders = sorted(superseders, key=lambda i: len(i.supersedes))
-            result.add(superseders[-1])
-        else:
-            # nothing to supersede resource so use it directly
-            result.add(resource)
-    return result
-
-
-def sort_resources(resources):
-    """Sort resources for inclusion on web page.
-
-    A number of rules are followed:
-
-    * resources are always grouped per renderer (.js, .css, etc)
-    * resources that depend on other resources are sorted later
-    * resources are grouped by library, if the dependencies allow it
-    * libraries are sorted by name, if dependencies allow it
-    * resources are sorted by resource path if they both would be
-      sorted the same otherwise.
-
-    The only purpose of sorting on library is so we can
-    group resources per library, so that bundles can later be created
-    of them if bundling support is enabled.
-
-    Note this sorting algorithm guarantees a consistent ordering, no
-    matter in what order resources were needed.
-    """
-    for resource in resources:
-        resource.library.init_library_nr()
-
-    def key(resource):
-        return (
-            resource.order,
-            resource.library.library_nr,
-            resource.library.name,
-            resource.dependency_nr,
-            resource.relpath)
-    return sorted(resources, key=key)
-
-
 def make_injector(app, global_config, **local_config):
     local_config = convert_config(local_config)
     # Look up injector factory by name.

tests/test_core.py

 from fanstatic.core import thread_local_needed_data
 from fanstatic.core import ModeResourceDependencyError
 from fanstatic.codegen import sort_resources_topological
-from fanstatic.injector import (bundle_resources,
-                                sort_resources,
-                                rollup_resources)
+from fanstatic.inclusion import (bundle_resources,
+                                 sort_resources,
+                                 rollup_resources)
 
 
 def test_resource():