Changeset 234
- Timestamp:
- 04/21/08 19:35:22 (7 months ago)
- Location:
- trunk/yui
- Files:
-
- 4 modified
-
components.py (modified) (3 diffs)
-
middleware.py (modified) (10 diffs)
-
module_info_2_5_1.py (modified) (1 diff)
-
tests/test_middleware.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/yui/components.py
r231 r234 34 34 return self.data.get('rollup', 1) 35 35 36 @property 37 def skinnable(self): 38 return self.data.get('skinnable', False) 39 40 @property 41 def fullpath(self): 42 return self.data.get('fullpath', None) 43 36 44 def __getattr__(self, attname): 37 45 return self.data[attname] … … 40 48 class Components(dict): 41 49 def __init__(self, components_dict): 42 super(Components, self).__init__( components_dict)50 super(Components, self).__init__() 43 51 self.rollup_mapping = {} 44 52 for component_name, data in components_dict.items(): 45 self.rollup_mapping.setdefault(component_name, set()) 46 if 'rollup' not in data: 47 continue 48 for rolled_up in data['supersedes']: 49 self.rollup_mapping.setdefault(rolled_up, set()).add( 50 component_name) 53 self.add(component_name, data) 51 54 52 55 def __getitem__(self, component_name): … … 66 69 return [name for name, data in self.items() 67 70 if data['type'] == 'css'] 71 72 def add(self, component_name, data): 73 self[component_name] = data 74 self.rollup_mapping.setdefault(component_name, set()) 75 if 'rollup' not in data: 76 return 77 for rolled_up in data['supersedes']: 78 self.rollup_mapping.setdefault(rolled_up, set()).add( 79 component_name) -
trunk/yui/middleware.py
r233 r234 69 69 70 70 import re 71 from shlex import shlex 71 72 72 73 from django.conf import settings 73 74 74 from module_info_2_5_1 import MODULE_INFO 75 from module_info_2_5_1 import MODULE_INFO, SKIN 75 76 from components import Components 76 77 … … 87 88 VERSIONS = {'raw': '', '': '', 'min': '-min', 'debug': '-debug'} 88 89 89 COMPONENTS = Components(MODULE_INFO)90 91 90 92 91 class YUILoader: 93 92 94 93 def __init__(self): 94 self._module_info = Components(MODULE_INFO) 95 95 self._components = set() 96 96 self._rolled_up_components = {} … … 112 112 self._roll_up_superseded(new_component_name) 113 113 114 def add_module(self, module_def): 115 module_data = {} 116 lexer = shlex(module_def, posix=True) 117 118 def expect(*patterns): 119 token = lexer.get_token() 120 if token not in patterns: 121 raise ValueError, '%s expected instead of %s' % \ 122 (' or '.join(repr(s) for s in patterns), 123 token and repr(token) or 'end of data') 124 return token 125 126 str_attrs = 'name', 'type', 'path', 'fullpath', 'varName' 127 list_attrs = 'requires', 'optional', 'after' 128 state = 'ATTR' 129 expect('{') 130 while state != 'STOP': 131 if state == 'ATTR': 132 token = expect(*str_attrs+list_attrs) 133 expect(':') 134 if token in str_attrs: 135 module_data[token] = lexer.get_token() 136 if module_data[token] is None: 137 raise ValueError, \ 138 'string expected instead of end of data' 139 state = 'DELIM' 140 elif token in list_attrs: 141 expect('[') 142 lst = module_data[token] = [] 143 state = 'LIST' 144 elif state == 'LIST': 145 lst.append(lexer.get_token()) 146 if re.search(r'\W', lst[-1]): 147 raise ValueError, 'invalid component name %r' % token 148 if expect(',', ']') == ']': 149 state = 'DELIM' 150 elif state == 'DELIM': 151 if expect(',', '}') == '}': 152 expect(None) 153 state = 'STOP' 154 else: 155 state = 'ATTR' 156 157 if 'type' not in module_data: 158 raise ValueError, 'type missing in %r' % module_def 159 self._module_info.add(module_data['name'], module_data) 160 return module_data 161 114 162 def render(self): 115 163 return '\n'.join(self._render_component(component) … … 122 170 def _get_satisfied_rollup(self, component_name): 123 171 if self._version == '-min': 124 for rollup_name in COMPONENTS.get_rollups(component_name):172 for rollup_name in self._module_info.get_rollups(component_name): 125 173 rollup_status = self._rollup_counters.get(rollup_name, set()) 126 if len(rollup_status) >= COMPONENTS[rollup_name].rollup:174 if len(rollup_status) >= self._module_info[rollup_name].rollup: 127 175 return rollup_name 128 176 129 177 def _count_in_rollups(self, component_name): 130 for rollup_name in COMPONENTS.get_rollups(component_name):178 for rollup_name in self._module_info.get_rollups(component_name): 131 179 rolled_up = self._rollup_counters.setdefault(rollup_name, set()) 132 180 rolled_up.add(component_name) 133 for superseded in COMPONENTS[component_name].supersedes:181 for superseded in self._module_info[component_name].supersedes: 134 182 self._count_in_rollups(superseded) 135 183 136 184 def _roll_up_superseded(self, component_name): 137 for superseded in COMPONENTS[component_name].supersedes:185 for superseded in self._module_info[component_name].supersedes: 138 186 self._rolled_up_components[superseded] = component_name 139 187 if superseded in self._components: … … 141 189 142 190 def _add_requirements(self, component_name): 143 for requirement in COMPONENTS[component_name].requires: 191 component = self._module_info[component_name] 192 for requirement in component.requires: 144 193 self.add_component(requirement) 194 if component.skinnable: 195 self.add_component(SKIN['defaultSkin']) 145 196 146 197 def _render_component(self, component_name): 147 component = COMPONENTS[component_name]148 path = component. path198 component = self._module_info[component_name] 199 path = component.fullpath or YUI_BASE + component.path 149 200 if component.type == 'js': 150 201 if self._version != '-min' and path.endswith('-min.js'): … … 153 204 if self._version == '' and path.endswith('-min.css'): 154 205 path = path[:-8] + '.css' 155 return TAGS[component.type] % (YUI_BASE + path,)206 return TAGS[component.type] % path 156 207 157 208 def _sort_components(self, component_names=None): … … 162 213 while comps: 163 214 component_name = comps.pop() 164 component = COMPONENTS[component_name]215 component = self._module_info[component_name] 165 216 direct_deps = component.requires + component.after 166 217 indirect_deps = [ … … 177 228 YUI_RE = re.compile( 178 229 r'%s(include|version) +(.*?)%s' % (PREFIX_RE, SUFFIX_RE)) 230 YUI_ADDMODULE_RE = re.compile( 231 r'(?s)%saddModule\s*(\{\s*.*?\s*})\s*%s' % (PREFIX_RE, SUFFIX_RE)) 179 232 YUI_INIT_RE = re.compile( 180 233 '%sinit%s' % (PREFIX_RE, SUFFIX_RE)) … … 183 236 def process_response(self, request, response): 184 237 components = set() 185 node = YUILoader() 238 loader = YUILoader() 239 240 def add_module(match): 241 loader.add_module(match.group(1)) 242 return '' 243 content = YUI_ADDMODULE_RE.sub(add_module, response.content) 244 186 245 def collect(match): 187 246 cmd, data = match.groups() … … 189 248 components.update(data.split()) 190 249 elif cmd == 'version': 191 node.set_version(data)250 loader.set_version(data) 192 251 else: 193 252 return '<!-- UNKNOWN COMMAND YUI_%s -->' % cmd 194 253 return '' 195 content = YUI_RE.sub(collect, response.content) 254 content = YUI_RE.sub(collect, content) 255 196 256 for component in components: 197 node.add_component(component) 198 content = YUI_INIT_RE.sub(node.render(), content, 1) 257 loader.add_component(component) 258 259 content = YUI_INIT_RE.sub(loader.render(), content, 1) 199 260 response.content = YUI_INIT_RE.sub( 200 261 '<!-- WARNING: MULTIPLE YUI_init STATEMENTS -->', content) 262 201 263 return response -
trunk/yui/module_info_2_5_1.py
r231 r234 193 193 'skinnable': True, 194 194 'type': 'js'}} 195 196 SKIN = { 197 'defaultSkin': 'sam', 198 'base': 'assets/skins/', 199 'path': 'skin.css', 200 'after': ['reset', 'fonts', 'grids', 'base'], 201 'rollup': 3 } 202 203 MODULE_INFO[SKIN['defaultSkin']] = { 204 'type': 'css', 205 'path': SKIN['base'] + SKIN['defaultSkin'] + '/' + SKIN['path'], 206 'after': SKIN['after'] } -
trunk/yui/tests/test_middleware.py
r231 r234 3 3 __doc__ = r""" 4 4 >>> import sys ; sys.setrecursionlimit(100) 5 >>> from pprint import pprint 5 6 >>> from ambidjangolib.yui.middleware import \ 6 ... COMPONENTS, YUILoader 7 >>> COMPONENTS['yahoo'].requires 7 ... YUILoader 8 9 >>> n = YUILoader() 10 11 >>> n._module_info['yahoo'].requires 8 12 [] 9 >>> COMPONENTS['yahoo'].after10 [' grids', 'reset-fonts', 'reset-fonts-grids', 'base', 'reset', 'fonts']11 >>> COMPONENTS['event'].requires13 >>> n._module_info['yahoo'].after 14 ['sam', 'reset-fonts', 'grids', 'reset-fonts-grids', 'base', 'reset', 'fonts'] 15 >>> n._module_info['event'].requires 12 16 ['yahoo'] 13 >>> COMPONENTS['yuiloader-dom-event'].after14 [' grids', 'reset-fonts', 'reset-fonts-grids', 'base', 'reset', 'fonts']15 >>> COMPONENTS.get_rollups('event')17 >>> n._module_info['yuiloader-dom-event'].after 18 ['sam', 'reset-fonts', 'grids', 'reset-fonts-grids', 'base', 'reset', 'fonts'] 19 >>> n._module_info.get_rollups('event') 16 20 set(['utilities', 'yuiloader-dom-event', 'yahoo-dom-event']) 17 21 18 >>> n = YUILoader() 22 >>> pprint(n.add_module('''{ 23 ... name: 'name', type: 'type', path: 'path', fullpath: 'fullpath', 24 ... requires: ['req1', 'req2'], after: ['after1', 'after2'], 25 ... optional: ['opt1', 'opt2'] }''')) 26 {'after': ['after1', 'after2'], 27 'fullpath': 'fullpath', 28 'name': 'name', 29 'optional': ['opt1', 'opt2'], 30 'path': 'path', 31 'requires': ['req1', 'req2'], 32 'type': 'type'} 33 34 >>> n.add_module('[') 35 Traceback (most recent call last): 36 ValueError: '{' expected instead of '[' 37 38 >>> n.add_module('{') 39 Traceback (most recent call last): 40 ValueError: 'name' or 'type' or 'path' or 'fullpath' or 'varName' or 'requires' or 'optional' or 'after' expected instead of end of data 41 42 >>> n.add_module('{,') 43 Traceback (most recent call last): 44 ValueError: 'name' or 'type' or 'path' or 'fullpath' or 'varName' or 'requires' or 'optional' or 'after' expected instead of ',' 45 46 >>> n.add_module('{name') 47 Traceback (most recent call last): 48 ValueError: ':' expected instead of end of data 19 49 20 50 >>> def test_sort(*c): return list(n._sort_components(set(c))) … … 69 99 >>> add(d, 'reset-fonts') 70 100 ['reset-fonts-grids'] 101 102 >>> d.add_module("{name:'added',requires:['dom']}") 103 Traceback (most recent call last): 104 ValueError: type missing in "{name:'added',requires:['dom']}" 105 106 >>> pprint(d.add_module("{type:'js',name:'added',requires:['dom']}")) 107 {'name': 'added', 'requires': ['dom'], 'type': 'js'} 108 109 >>> add(d, 'added') 110 ['reset-fonts-grids', 'yahoo', 'dom', 'added'] 71 111 """ 72 112
