slimmer-0.1.30/0000755000175000017500000000000011275116110013074 5ustar peterbepeterbeslimmer-0.1.30/README.txt0000644000175000017500000000155711114250774014611 0ustar peterbepeterbeslimmer.py is a whitespace optimizer for CSS, HTML and XHTML output. It's written by Peter Bengtsson, peter@fry-it.com in 2004-2005. Still maintained in 2008. INSTALLATION:: $ sudo easy_install slimmer Alternative:: $ tar -zxvf slimmer-x.x.x.tgz $ cd slimmer/ $ sudo python setup.py install USAGE:: >>> import slimmer >>> from slimmer import css_slimmer >>> css_slimmer("h1, h2 { font-family: 'Courier New', Courier; }") "h1,h2{font-family:'Courier New',Courier;border:1px solid black;}" >>> html_slimmer(' one
') >>> from slimmer import html_slimmer, xhtml_slimmer >>> html_slimmer(''' one
''') ' one
' UNITTESTS:: $ cd slimmer/tests $ python testSlimmer.py $ python testSlimmer.py --verbose slimmer-0.1.30/setup.py0000644000175000017500000000275711114250677014632 0ustar peterbepeterbefrom setuptools import setup, find_packages import sys, os import slimmer version = slimmer.__version__ # hate repeating myself README = os.path.join(os.path.dirname(__file__), 'README.txt') long_description = open(README).read().strip() + "\n\n" setup(name='slimmer', version=version, description="HTML,XHTML,CSS,JavaScript optimizer", long_description=long_description, keywords='slimmer optimizer optimiser whitespace', author='Peter Bengtsson', author_email='peter@fry-it.com', url='http://www.fry-it.com', download_url='http://pypi.python.org/pypi/slimmer/', license='Python', classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Other Environment", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: Python Software Foundation License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Communications", "Topic :: Internet :: WWW/HTTP", "Topic :: Other/Nonlisted Topic", "Topic :: Software Development :: Libraries :: Python Modules", ], packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), include_package_data=True, test_suite='slimmer.tests', zip_safe=True, install_requires=[ # -*- Extra requirements: -*- ], entry_points=""" # -*- Entry points: -*- """, ) slimmer-0.1.30/setup.cfg0000644000175000017500000000007311275116111014716 0ustar peterbepeterbe[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 slimmer-0.1.30/slimmer.egg-info/0000755000175000017500000000000011275116110016236 5ustar peterbepeterbeslimmer-0.1.30/slimmer.egg-info/top_level.txt0000644000175000017500000000001011275116110020757 0ustar peterbepeterbeslimmer slimmer-0.1.30/slimmer.egg-info/SOURCES.txt0000644000175000017500000000060011275116110020116 0ustar peterbepeterbeREADME.txt setup.cfg setup.py slimmer/__init__.py slimmer/js_function_slimmer.py slimmer/slimit.py slimmer/slimmer.py slimmer.egg-info/PKG-INFO slimmer.egg-info/SOURCES.txt slimmer.egg-info/dependency_links.txt slimmer.egg-info/entry_points.txt slimmer.egg-info/top_level.txt slimmer.egg-info/zip-safe slimmer/tests/__init__.py slimmer/tests/codechunks.py slimmer/tests/testSlimmer.pyslimmer-0.1.30/slimmer.egg-info/entry_points.txt0000644000175000017500000000004511275116110021533 0ustar peterbepeterbe # -*- Entry points: -*- slimmer-0.1.30/slimmer.egg-info/PKG-INFO0000644000175000017500000000367711275116110017350 0ustar peterbepeterbeMetadata-Version: 1.0 Name: slimmer Version: 0.1.30 Summary: HTML,XHTML,CSS,JavaScript optimizer Home-page: http://www.fry-it.com Author: Peter Bengtsson Author-email: peter@fry-it.com License: Python Download-URL: http://pypi.python.org/pypi/slimmer/ Description: slimmer.py is a whitespace optimizer for CSS, HTML and XHTML output. It's written by Peter Bengtsson, peter@fry-it.com in 2004-2005. Still maintained in 2008. INSTALLATION:: $ sudo easy_install slimmer Alternative:: $ tar -zxvf slimmer-x.x.x.tgz $ cd slimmer/ $ sudo python setup.py install USAGE:: >>> import slimmer >>> from slimmer import css_slimmer >>> css_slimmer("h1, h2 { font-family: 'Courier New', Courier; }") "h1,h2{font-family:'Courier New',Courier;border:1px solid black;}" >>> html_slimmer(' one
') >>> from slimmer import html_slimmer, xhtml_slimmer >>> html_slimmer(''' one
''') ' one
' UNITTESTS:: $ cd slimmer/tests $ python testSlimmer.py $ python testSlimmer.py --verbose Keywords: slimmer optimizer optimiser whitespace Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Communications Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Other/Nonlisted Topic Classifier: Topic :: Software Development :: Libraries :: Python Modules slimmer-0.1.30/slimmer.egg-info/zip-safe0000644000175000017500000000000111114012023017654 0ustar peterbepeterbe slimmer-0.1.30/slimmer.egg-info/dependency_links.txt0000644000175000017500000000000111275116110022304 0ustar peterbepeterbe slimmer-0.1.30/PKG-INFO0000644000175000017500000000367711275116110014206 0ustar peterbepeterbeMetadata-Version: 1.0 Name: slimmer Version: 0.1.30 Summary: HTML,XHTML,CSS,JavaScript optimizer Home-page: http://www.fry-it.com Author: Peter Bengtsson Author-email: peter@fry-it.com License: Python Download-URL: http://pypi.python.org/pypi/slimmer/ Description: slimmer.py is a whitespace optimizer for CSS, HTML and XHTML output. It's written by Peter Bengtsson, peter@fry-it.com in 2004-2005. Still maintained in 2008. INSTALLATION:: $ sudo easy_install slimmer Alternative:: $ tar -zxvf slimmer-x.x.x.tgz $ cd slimmer/ $ sudo python setup.py install USAGE:: >>> import slimmer >>> from slimmer import css_slimmer >>> css_slimmer("h1, h2 { font-family: 'Courier New', Courier; }") "h1,h2{font-family:'Courier New',Courier;border:1px solid black;}" >>> html_slimmer(' one
') >>> from slimmer import html_slimmer, xhtml_slimmer >>> html_slimmer(''' one
''') ' one
' UNITTESTS:: $ cd slimmer/tests $ python testSlimmer.py $ python testSlimmer.py --verbose Keywords: slimmer optimizer optimiser whitespace Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Communications Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Other/Nonlisted Topic Classifier: Topic :: Software Development :: Libraries :: Python Modules slimmer-0.1.30/slimmer/0000755000175000017500000000000011275116110014544 5ustar peterbepeterbeslimmer-0.1.30/slimmer/__init__.py0000644000175000017500000000007211114011722016647 0ustar peterbepeterbefrom slimmer import * # slimmer.py has an __all__ variableslimmer-0.1.30/slimmer/slimmer.py0000644000175000017500000005425011275116001016573 0ustar peterbepeterbe#!/usr/bin/python """ slimmer.py Peter Bengtsson, mail@peterbe.com, 2004-2006 slimmer.py is a simple set of functions for compressing/optimizing HTML, XHTML and CSS documents as strings. Ideally used from other modules used something like this:: >>> import slimmer >>> code = open('file.html').read() >>> slimmed = slimmer.xhtml_slimmer(code) >>> print len(code), len(slimmed) You have to estimate yourself if you think it's worth using slimmer on your documents if you're running a dynamic setting such as a web application (e.g. Zope with CheckoutableTemplates). On my PC I slimmed a 1MB .html document in 2.2 seconds and saved 100KB. Saved 31KB on a 110KB .css file in 0.063 seconds. And lastly, saved 17% in size in 0.016 seconds for www.python.org. Changes:: 0.1.30 Nov 2009 Better at guessing HTML or XHTML 0.1.29 Nov 2008 New distutils release 0.1.28 Nov 2008 Added some tests that tests UTF-8 and EUC-JP HTML 0.1.27 Nov 2008 As a new distutils package 0.1.26 Oct 2007 Minor improvement to js_slimmer for 'var x = [...]' 0.1.25 Oct 2007 Slimming unicode text with hex colours like #FFFFFF caused an error relating to string.translate() 0.1.24 Sep 2007 0.1.11 Feb 2005 Fixed js_slimmer() for some curly bracket endings 0.1.10 Jan 2005 (Major patch by Baruch Even) - Fixed the -t option for testing, it didn't work, --test did work. - Fixed a typo s/whatspace/whitespace/ - Fixed a bug were more than one consecutive space turned into nothing, added test 6 for this. - Revamped other code to completely eliminate end of lines. It works in FireFox 1.0 - Changed the test cases to fit - Removed the last ; before } -> s/;}/}/ - Changed the test cases to fit 0.1.9 Jan 2005 CLI interface can accept URLs 0.1.8 Dec 2004 Added an option (UNQUOTE_HTML_ATTRIBUTES) to remove quotes from HTML attributes. (default is off) 0.1.7 Dec 2004 Separate out from CheckoutableTemplates and __all__ variable fixed for js_slimmer. 0.1.6 Dec 2004 Care for MacIE5 CSS Hack (http://www.sam-i-am.com/work/sandbox/css/mac_ie5_hack.html) 0.1.5 Nov 2004 Some improvements to js_slimmer() 0.1.4 Nov 2004 Added first draft of js_slimmer() 0.1.3 Nov 2004 Much improved CLI functions 0.1.2 Sep 2004 Added basic CLI functions (see run()) 0.1.1 Sep 2004 Major speed improvment by removing the unquote_numerical feature. 0.1.0 Sep 2004 First version numbering """ __version__='0.1.30' __all__=['acceptableSyntax','guessSyntax','slimmer','css_slimmer', 'html_slimmer','xhtml_slimmer','js_slimmer', '__version__'] import re, os, sys, getopt import urllib2 try: from js_function_slimmer import slim as js_function_slimmer except ImportError: js_function_slimmer = None ## Options # # If you're slimming HTML docs and really want to # convert border="0" to border=0, be aware that this # can take 5 times longer than without but compresses # the document at least twice as good. UNQUOTE_HTML_ATTRIBUTES = 0 # Define the syntax options we accept HTML = 'html' XHTML = 'xhtml' CSS = 'css' JS = 'js' OK_SYNTAX = (HTML, XHTML, CSS, JS) def acceptableSyntax(syntax): """ return the syntax as we recognize it or None """ syntax = str(syntax).lower().strip().replace(' ','').replace('-','') syntax = syntax.replace('stylesheet','css') # allow for alias syntax = syntax.replace('javascript','js') # allow for alias if syntax in OK_SYNTAX: return syntax else: return None some_javascript_code_regex = re.compile( 'function\(\)\s*{|var \w|return false;|return true;|'\ 'function \w{2,15}\(|}\s*else if\s*\(') some_css_code_regex = re.compile('^#\w+\s*{|body\s*{|font-family:|margin:0|display:'\ '|height:\s*\d|border:1px') _html_doctypes = ('||\s/>|<input|<a\s+', re.I) some_html_code_regex = re.compile('|'.join([re.escape(x) for x in _html_doctypes])+\ '|<table|background=\"|<script|border=0|<!--', re.I) def guessSyntax(code): code = code.strip() if some_html_code_regex.findall(code): return HTML elif some_xhtml_code_regex.findall(code): return XHTML elif some_javascript_code_regex.findall(code): return JS elif some_css_code_regex.findall(code): return CSS else: # getting desperate but we shall prevail! if '</' in code: if '/>' in code or '/ >' in code: return XHTML return HTML return None def slimmer(code, syntax=XHTML, hardcore=False): """ wrap all function we have """ if syntax == XHTML: return _xhtml_slimmer(code) elif syntax == HTML: return _html_slimmer(code) elif syntax == CSS: return _css_slimmer(code) elif syntax == JS: return _js_slimmer(code, slim_functions=bool(hardcore)) try: import itertools def anyTrue(pred, seq): return True in itertools.imap(pred,seq) except ImportError: def anyTrue(pred, seq): for e in seq: if pred(e): return True return False # CSS css_comments = re.compile(r'/\*.*?\*/', re.MULTILINE|re.DOTALL) hex_colour = re.compile(r'#\w{2}\w{2}\w{2}') def _css_slimmer(css): """ remove repeating whitespace ( \t\n) """ #css = css_comments.sub('', css) # remove comments remove_next_comment = 1 for css_comment in css_comments.findall(css): if css_comment[-3:]=='\*/': remove_next_comment=0 continue if remove_next_comment: css = css.replace(css_comment, '') else: remove_next_comment = 1 css = re.sub(r'\s\s+', ' ', css) # >= 2 whitespace becomes one whitespace css = re.sub(r'\s+\n', '', css) # no whitespace before end of line # Remove space before and after certain chars for char in ('{', '}', ':', ';', ','): css = re.sub(char+r'\s', char, css) css = re.sub(r'\s'+char, char, css) css = re.sub(r'\s+</',r'</', css) # no extraspace before </style> css = re.sub(r'}\s(#|\w)', r'}\1', css) css = re.sub(r';}', r'}', css) # no need for the ; before end of attributes css = re.sub(r'}//-->', r'}\n//-->', css) css = simplifyHexColours(css) # voice-family hack. The declation: '''voice-family: "\"}\""''' requires # that extra space between the ':' and the first '"' which _css_slimmer() # removed. Put it back (http://real.issuetrackerproduct.com/0168) css = re.sub(r'voice-family:"\\"}\\""', r'voice-family: "\\"}\\""', css) return css.strip() # HTML f_IMD = re.I|re.MULTILINE|re.DOTALL f_MD = re.MULTILINE|re.DOTALL f_M = re.MULTILINE # the comment has to start with a space or a charater # otherwise me might remove a SSI include which can look like this: # <!--#include virtual="/include/myinclude.asp"--> html_comments_oneline = re.compile(r'<!--[\w\s].*?-->', re.I) html_inline_css = re.compile(r'<style.*?>.*?</style>', f_IMD) html_inline_js = re.compile(r'<script.*?>.*?</script>', f_IMD) any_tag = re.compile(r"<\w.*?>", f_IMD) excess_whitespace = re.compile(r' \s+|\s +', f_M) excess_whitespace1 = re.compile(r'\w\s+\w', f_M) excess_whitespace2 = re.compile(r'"\s+>', f_M) excess_whitespace3 = re.compile(r"'\s+>", f_M) excess_whitespace4 = re.compile('"\s\s+\w+="|\'\s\s+\w+=\'|"\s\s+\w+=|\'\s\s+\w+=', f_M) excess_whitespace6 = re.compile(r"\d\s+>", f_M) quotes_in_tag = re.compile('([a-zA-Z]+)="([a-zA-Z0-9-_\.]+)"') def _html_slimmer(html, xml=0): """ Optimize like XHTML but go one step further """ # 1. optimize inline CSS for styletag in html_inline_css.findall(html): html = html.replace(styletag, css_slimmer(styletag)) # 2. optimize inline Javascript for scripttag in html_inline_js.findall(html): html = html.replace(scripttag, js_slimmer(scripttag)) # 2. Remove excessive whitespace between tags html = re.sub(r'>\s+<','><', html) # 3. Remove oneline comments html = html_comments_oneline.sub('', html) # 4. In every tag, remove quotes on numerical attributes and all # excessive whitespace ew1 = excess_whitespace1 # shortcut ew6 = excess_whitespace6 # shortcut ew4 = excess_whitespace4 # shortcut for tag in uniqify(any_tag.findall(html)): # 4a. observe exceptions if tag.startswith('<!') or tag.find('</')>-1: continue original = tag # 4b. remove excess whitespace inside the tag tag= excess_whitespace2.sub('">', tag) tag= excess_whitespace3.sub("'>", tag) for each in ew1.findall(tag)+ew6.findall(tag): tag = tag.replace(each, excess_whitespace.sub(' ',each)) for each in ew4.findall(tag): tag = tag.replace(each, each[0]+' '+each[1:].lstrip()) # 4c. remove quotes if not xml and UNQUOTE_HTML_ATTRIBUTES: tag= quotes_in_tag.sub(r'\1=\2', tag) # has the tag been improved? if original != tag: html = html.replace(original, tag) return html.strip() def _xhtml_slimmer(xhtml): # currently not difference return _html_slimmer(xhtml, xml=1) excess_whitespace_js = re.compile('^\s+(\S)',re.MULTILINE) excess_whitespace_js2 = re.compile('(\S+);\s+(\S+)', re.MULTILINE) whitespaced_func_def = re.compile('(function)\s+(\S+\(.*?\))\s*{\s*(\S+)', f_IMD) whitespaced_func_def2 = re.compile('function\s*\(\)\s*{\s*(\S+)', f_IMD) js_comments_singlelines = re.compile('^//.*?$|\s+//.*?$', re.DOTALL|re.MULTILINE|re.I) js_comments_singlelines2 = re.compile('((^|;|\s)//.*?$)', re.DOTALL|re.MULTILINE|re.I) js_comment_end = re.compile('-->') js_comment_start = re.compile('(<!--(.*?))$\s(\w+)', re.MULTILINE) #js_comment_start2 = re.compile('(\<\!--(.*?)(\n+|[\r\n]+)\s*(\w+))', re.DOTALL|re.MULTILINE) whitespaced_controls = re.compile('(for|else if|if|catch|while)\s*\((.*?)\)\s*{\s*(\S+)', f_IMD) single_whitespaced_controls = re.compile('(try|else)\s*{\s*(\S+)', f_IMD) sloppy_conditionals = re.compile('\(\s*(\S+)\s*(==|!=)\s*(\S+)\)') sloppy_parameters = re.compile('\(([(\w+)\s,]+)\)') sloppy_ifs = re.compile('\s*(if|else if|else)\s*({|\()') sloppy_declarations = re.compile('var\s+(\w+)\s*=\s*(\d+|\w+|\"[\w+ ]\"|\[[\'\w \.,\"]+\])') sloppy_simple_declarations = re.compile('(\w+)\s*=\s*(\d+|\w+|\"[\w+ ]\")') sloppy_increments = re.compile('(\w+)\s*(\+=|-=)\s*(\d*|\"\w+\")') js_multiline_comments = re.compile(r'/\*.*?\*/', re.MULTILINE|re.DOTALL) closing_curly_brackets = re.compile(r'\s*}', re.MULTILINE) opening_curly_brackets = re.compile(r'{\s*', re.MULTILINE) def _js_slimmer(js, slim_functions=False): # 1. remove all whitespace starting every line js = excess_whitespace_js.sub(r'\1',js) # 2. Remove all /* multiline comments */ js = js_multiline_comments.sub('',js) # 3. // style comments def _reject_slashslash_comment(match): if match.group().find('-->')==-1: return '' else: return match.group() js = js_comments_singlelines.sub(_reject_slashslash_comment, js) _=""" for comment, start in js_comments_singlelines2.findall(js): # ...except those that contain --> replacewith = '' if start == ';': replacewith = ';' if not js_comment_end.findall(comment): js = js.replace(comment, replacewith) """ js = js_comment_start.sub(r'<!--\n\3', js) # 3. excessive whitespace after semicolons js = excess_whitespace_js2.sub(r'\1;\2', js) # 4. functions defined with lots of whitespace js = whitespaced_func_def.sub(r'\1 \2{\3', js) js = whitespaced_func_def2.sub(r'function(){\1', js) # 5. control statements with lots of whitespace js = whitespaced_controls.sub(r'\1(\2){\3', js) # 6. control statements without params with lots of whitespace js = single_whitespaced_controls.sub(r'\1{\2', js) # 7. convert '(page == "foo")' to '(page=="foo")' js = sloppy_conditionals.sub(r'(\1\2\3)', js) # 8. convert '} else if {' to '}else if{' js = sloppy_ifs.sub(r'\1\2', js) # 9. convert 'var x = foo' to 'var x=foo' js = sloppy_declarations.sub(r'var \1=\2',js) js = sloppy_simple_declarations.sub(r'\1=\2', js) # 10. whitespace around closing } curly brackets js = opening_curly_brackets.sub('{', js) js = closing_curly_brackets.sub('}', js) # 11. Neater parameter lists #js = sloppy_parameters.sub(lambda m:m.group().replace(' ',''), js) def param_list_fixer(m): whole = m.group() params = m.groups()[0] return whole.replace(params, ','.join([x.strip() for x in params.split(',')])) js = sloppy_parameters.sub(param_list_fixer, js) # 12. sloppy increments js = sloppy_increments.sub(r'\1\2\3', js) if slim_functions and js_function_slimmer: js = js_function_slimmer(js) return js.strip() ## ----- Some fancier names ## def css_slimmer(css, hardcore=False): return _css_slimmer(css) def xhtml_slimmer(xhtml, hardcore=False): return _xhtml_slimmer(xhtml) def html_slimmer(html, hardcore=False): return _html_slimmer(html) def js_slimmer(js, hardcore=False): return _js_slimmer(js, slim_functions=bool(hardcore)) ## ----- Methods related to simplifying HEX colour codes def uniqify(all): """ borrowed from Tim Peters' algorithm on ASPN Cookbook """ # REMEMBER! This will shuffle the order of the list u = {} for each in all: u[each]=1 return u.keys() def simplifyHexColours(text): """ Replace all colour declarations where pairs repeat. I.e. #FFFFFF => #FFF; #CCEEFF => #CEF and #EFEFEF, #EFCDI9 avoided """ colour_replacements = {} all_hex_encodings = hex_colour.findall(text) for e in uniqify(all_hex_encodings): if e[1]==e[2] and e[3]==e[4] and e[5]==e[6]: colour_replacements[e] = '#'+e[1]+e[3]+e[5] for k, v in colour_replacements.items(): text = text.replace(k, v) return text def __grr(): print "Usage: python slimmer.py /path/to/input.html [xhtml|html|css|js] /path/to/output.html" def _pingable(url): try: urllib2.urlopen(url) return 1 except: return 0 def _is_openable_url(path_or_url): # looks like a URL? if path_or_url.lower().startswith('http'): return _pingable(path_or_url) else: return 0 def __guess_syntax(filepath): lines = [] if os.path.isfile(filepath) or _is_openable_url(filepath): if filepath.lower().endswith('.css'): return 'css' elif filepath.lower().endswith('.js'): return 'js' if os.path.isfile(filepath): f=open(filepath) else: f=urllib2.urlopen(filepath) line = f.readline() c = 0 while len(lines) < 50 and line is not None: if line.strip(): lines.append(line) line = f.readline() c += 1 if c>100: break # paranoid safety f.close() lines_list = lines lines = '\n'.join([x for x in lines_list if x.find('!DOCTYPE')>-1]) if lines.find('HTML 4.0')>-1: return 'html' elif lines.find('XHTML 1.0')>-1: return 'xhtml' elif lines.find('<html>') > -1: return 'html' else: lines = '\n'.join(lines_list) if lines.lower().find('<html') > -1: return 'html' if filepath.lower().endswith('.html') or \ filepath.lower().endswith('.htm'): return 'html' return None usage="""slimmer.py Compress web files on the command line Peter Bengtsson, <mail@peterbe.com>, Nov 2004 USAGE: python slimmer.py [OPTIONS] /path/to/input.html [xhtml|html|css|js] Options: -t, --test Perform a speed and compression test --output Save result to file --version Prints version and exits --hardcore Tries really hard but potentially slower -h, --help Prints this message If you don't specify the content type after the input filename, the program will try to guess it by opening the file and looking at the file extension. Examples: $ python slimmer.py index.html XHTML --output=index.optimized.html $ python slimmer.py --test screen.css """ def __showversion(): print __version__ def __usage(): print usage class Usage(Exception): def __init__(self, msg): self.msg = msg def main(argv=None): if argv is None: argv = sys.argv try: try: opts, args = getopt.getopt(argv[1:], "ho:vt", ["help", "output=", "version", "test", "hardcore"]) except getopt.error, msg: raise Usage(msg) # more code, unchanged except Usage, err: print >>sys.stderr, err.msg print >>sys.stderr, "for help use --help" return 2 outputfile = None speedtest = 0 hardcore = False for o, a in opts: if o == "--version": __showversion() return 2 elif o in ('-h', '--help'): __usage() return 3 elif o in ('-o', '--output'): outputfile = a elif o in ("-t", "--test"): speedtest = 1 elif o == '--hardcore': hardcore = True if not args: __usage() return 4 syntax = None inputfile = None otherargs = [] for arg in args: if arg in ('-t', '--test'): speedtest = 1 elif arg.startswith('--output='): outputfile = arg[9:] elif acceptableSyntax(arg): syntax = acceptableSyntax(arg) elif os.path.isfile(arg) or _is_openable_url(arg): inputfile = arg else: otherargs.append(arg) if inputfile and syntax is None: syntax = __guess_syntax(inputfile) if inputfile is None: print >>sys.stderr, "No input file" print >>sys.stderr, "for help use --help" return 2 if not acceptableSyntax(syntax): print >>sys.stderr, "Unrecognized syntax" print >>sys.stderr, "for help use --help" return 2 if otherargs: print >>sys.stderr, "Unrecognized arguments %r"%otherargs print >>sys.stderr, "for help use --help" return 2 run(inputfile, syntax, speedtest, outputfile, hardcore=hardcore) return 0 from time import time def _gzipText(content): import cStringIO,gzip zbuf = cStringIO.StringIO() zfile = gzip.GzipFile(None, 'wb', 9, zbuf) zfile.write(content) zfile.close() return zbuf.getvalue() def run(inputfile, syntax, speedtest, outputfile, hardcore=False): if os.path.isfile(inputfile): contents = open(inputfile).read() else: contents = urllib2.urlopen(inputfile).read() t0=time() slimmed = slimmer(contents, syntax, hardcore=hardcore) t=time()-t0 if speedtest: before = len(contents) after = len(slimmed) after_zlibbed = len(slimmed.encode('zlib')) after_gzip = len(_gzipText(slimmed)) size_before = before if size_before > 100000: size_before = "%s (%sK)"%(size_before, size_before/1024) size_after = after if size_after > 100000: size_after = "%s (%sK)"%(size_after, size_after/1024) size_difference = before-after if size_difference > 10000: size_difference = "%s (%sK)"%(size_difference, size_difference/1024) print "Took %s seconds"%round(t, 3) print "Bytes before: %s"%size_before print "Bytes after: %s"%size_after print "Bytes after zlib: %s"%after_zlibbed print "Bytes after gzip: %s"%after_gzip print "Bytes saved: %s "%size_difference, print "(%s%% of original size)"%(100*round(after/float(before), 2)) elif outputfile: open(outputfile, 'w').write(slimmed) else: print >>sys.stdout, slimmed if __name__=='__main__': sys.exit(main()) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/tests/�����������������������������������������������������������������������0000755�0001750�0001750�00000000000�11275116110�015706� 5����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/tests/testSlimmer.py���������������������������������������������������������0000644�0001750�0001750�00000023637�11275115737�020621� 0����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������import os from time import time import unittest import codecs import sys sys.path.insert(0,'../') import slimmer VERBOSE = False from codechunks import * class SlimmerTestCase(unittest.TestCase): def _assert(self, str1, str2, name=''): """ special kind of assertEqual that strips """ if not str1.strip() == str2.strip(): print '\n'+"-"*70 print "DIFFERENCES %s"%name print "----Result|"+"-"*50 #print repr(str1.strip()) print str1.strip() print "----Expect|"+"-"*50 #print repr(str2.strip()) print str2.strip() print "-"*70 x = str1.strip() y = str2.strip() print x arrow = '' for i, e in enumerate(list(x)): if e==y[i]: arrow += "-" else: arrow += "^" break print arrow self.assertEqual(str1.strip(), str2.strip()) #assert str1.strip() == str2.strip() #return self.assertEqual(str1.strip(), str2.strip()) def timer(self, name, timeittook, size1, size2): record = {'name':name, 'time':timeittook, 'size1':size1, 'size2':size2} records = self.timed_records records.append(record) self.time_records = records def setUp(self): self.timed_records=[] def tearDown(self): for record in self.timed_records: if VERBOSE: print "-- %s --:"%record['name'] print "%s seconds"%round(record['time'], 6) print "Was: %s\tNow: %s"%(record['size1'], record['size2']) percent = round(100*record['size2']/float(record['size1']), 5) percent = "%s%%"%percent difference = record['size1'] - record['size2'] print "Difference: %s (%s)"%(difference, percent) print def atest(self, str1, str2, name, func, printresult=VERBOSE, *args, **kw): """ standard type of test """ before = str1 expect = str2 t0=time() args = [before]+list(args) result = apply(func, args, kw) if printresult: print result T = time()-t0 self.timer(name,time()-t0, len(before), len(result)) self._assert(result, expect, name) #--- Start the madness! ---------------------------------------------- def testGuessSyntax(self): for var, value in globals().items(): syntax = None if var.find('CSS')> -1: syntax = slimmer.guessSyntax(value) self.assertEqual(syntax, 'css') elif var.find('JS')> -1: syntax = slimmer.guessSyntax(value) self.assertEqual(syntax, 'js') elif var.find('HTML')> -1: syntax = slimmer.guessSyntax(value) self.assertTrue(syntax in ('html','xhtml')) else: continue def testGuessHTMLorXHTML(self): code = """<ul> <li>One</li> <li>Two</li> </ul>""" self.assertEqual(slimmer.guessSyntax(code), 'html') code = """ <a href="foo.html"><img src="foo.jpg" /></a> """ self.assertEqual(slimmer.guessSyntax(code), 'xhtml') def testCSS1(self): before = CSS_1 expect = expect_CSS_1 self.atest(before, expect, "CSS1", slimmer.css_slimmer) def testCSS2(self): before = CSS_2 expect = expect_CSS_2 self.atest(before, expect, "CSS2", slimmer.css_slimmer) def testCSS3(self): before = CSS_3 expect = expect_CSS_3 self.atest(before, expect, "CSS3", slimmer.css_slimmer) def testCSS3b(self): before = CSS_3b expect = expect_CSS_3b self.atest(before, expect, "CSS3b", slimmer.css_slimmer) def testCSS3c(self): before = CSS_3c expect = expect_CSS_3c self.atest(before, expect, "CSS3c", slimmer.css_slimmer) def testCSS4(self): before = CSS_4 expect = expect_CSS_4 self.atest(before, expect, "CSS4", slimmer.css_slimmer) def testCSS5(self): before = CSS_5 expect = expect_CSS_5 self.atest(before, expect, "CSS5", slimmer.css_slimmer) def testCSS6(self): before = CSS_6 expect = expect_CSS_6 self.atest(before, expect, "CSS6", slimmer.css_slimmer) def testCSS7(self): before = CSS_7 expect = expect_CSS_7 self.atest(before, expect, "CSS6", slimmer.css_slimmer) def testHTML1(self): before = HTML_1 expect = expect_HTML_1 self.atest(before, expect, "HTML1", slimmer.html_slimmer) def testHTML2(self): before = HTML_2 expect = expect_HTML_2 self.atest(before, expect, "HTML2", slimmer.html_slimmer) def testHTML3(self): before = HTML_3 expect = expect_HTML_3 self.atest(before, expect, "HTML3", slimmer.html_slimmer) def testHTML4(self): before = HTML_4 expect = expect_HTML_4 self.atest(before, expect, "HTML4", slimmer.html_slimmer) def testHTML5(self): before = HTML_5 expect = expect_HTML_5 self.atest(before, expect, "HTML5", slimmer.html_slimmer) def testHTML6(self): before = HTML_6 expect = expect_HTML_6 self.atest(before, expect, "HTML6", slimmer.html_slimmer) def testHTML7(self): before = HTML_7 expect = expect_HTML_7 self.atest(before, expect, "HTML7", slimmer.html_slimmer) def testHTML8(self): before = HTML_8 expect = expect_HTML_8 self.atest(before, expect, "HTML8", slimmer.html_slimmer) def testHTML9(self): """ UTF-8 characters in the HTML """ before = HTML_9 expect = expect_HTML_9 self.atest(before, expect, "HTML9", slimmer.html_slimmer) def testJS1(self): before = JS_1 expect = expect_JS_1 self.atest(before, expect, "JS1", slimmer.js_slimmer) def testJS2(self): before = JS_2 expect = expect_JS_2 self.atest(before, expect, "JS2", slimmer.js_slimmer) def testJS3(self): before = JS_3 expect = expect_JS_3 self.atest(before, expect, "JS3", slimmer.js_slimmer) def testJS4(self): before = JS_4 expect = expect_JS_4 self.atest(before, expect, "JS4", slimmer.js_slimmer) def testJS5(self): before = JS_5 expect = expect_JS_5 self.atest(before, expect, "JS5", slimmer.js_slimmer) def testJS6(self): before = JS_6 expect = expect_JS_6 self.atest(before, expect, "JS6", slimmer.js_slimmer) def testJS8(self): before = JS_8 expect = expect_JS_8 self.atest(before, expect, "JS8", slimmer.js_slimmer) def testJS9(self): before = JS_9 expect = expect_JS_9 self.atest(before, expect, "JS9", slimmer.js_slimmer) def testJS10(self): before = JS_10 expect = expect_JS_10 self.atest(before, expect, "JS10", slimmer.js_slimmer) def testJS11a(self): before = JS_11 expect = expect_JS_11 self.atest(before, expect, "JS11", slimmer.js_slimmer) def testJS11b(self): before = JS_11 expect = expect_JS_11_hardcore self.atest(before, expect, "JS11", slimmer.js_slimmer, hardcore=True) def testJS12a(self): before = JS_12 expect = expect_JS_12 self.atest(before, expect, "JS12", slimmer.js_slimmer) def testJS12b(self): before = JS_12 expect = expect_JS_12_hardcore self.atest(before, expect, "JS12", slimmer.js_slimmer, hardcore=True) def testJS13(self): before = JS_13 expect = expect_JS_13 self.atest(before, expect, "JS13", slimmer.js_slimmer) def testJS14a(self): before = JS_14 expect = expect_JS_14 self.atest(before, expect, "JS14a", slimmer.js_slimmer) def testJS14b(self): before = JS_14 expect = expect_JS_14_hardcore self.atest(before, expect, "JS14b", slimmer.js_slimmer, hardcore=True) def testJS15(self): before = JS_15 expect = expect_JS_15 self.atest(before, expect, "JS15", slimmer.js_slimmer) def testJS16(self): before = JS_16 expect = expect_JS_16 self.atest(before, expect, "JS16", slimmer.js_slimmer) def testUnicodeHTML1(self): here = os.path.dirname(__file__) before = codecs.open(os.path.join(here, 'euc-jp.html'), 'r','euc-jp').read() assert isinstance(before, unicode) after = slimmer.html_slimmer(before) assert isinstance(after, unicode) def testUnicodeHTML2(self): here = os.path.dirname(__file__) before = codecs.open(os.path.join(here, 'utf-8.html'), 'r','utf-8').read() assert isinstance(before, unicode) after = slimmer.html_slimmer(before) assert isinstance(after, unicode) expect = u'<html><p>\u0e2a\u0e27\u0e31\u0e2a\u0e14\u0e35\u0e04\u0e23\u0e31\u0e1a</p></html>' assert after == expect def suite(): return unittest.makeSuite(SlimmerTestCase) if __name__ == '__main__': if '-v' in sys.argv[1:] or '--verbose' in sys.argv[1:]: VERBOSE = True unittest.main() �������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/tests/__init__.py������������������������������������������������������������0000644�0001750�0001750�00000000055�11114011722�020012� 0����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Test some things in CheckoutableTemplates �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/tests/codechunks.py����������������������������������������������������������0000644�0001750�0001750�00000041546�11114022167�020420� 0����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#-*- coding: utf-8 -* CSS_1 = ''' /* Comment 1 */ div#main { font-family: Verdana, "Courier New" ; } h2 { /* Comment 2 */ font-size: 10px; } ''' expect_CSS_1 = ''' div#main{font-family:Verdana,"Courier New"}h2{font-size:10px} ''' #---------------------------------------------------------------------------- CSS_2 = ''' <style type="text/css"> div#main { font-family: Verdana, "Courier New" ; } h2 { font-size: 10px; } </style> ''' expect_CSS_2 = ''' <style type="text/css"> div#main{font-family:Verdana,"Courier New"}h2{font-size:10px}</style> ''' #---------------------------------------------------------------------------- CSS_3 = r''' #centercontent { border:1px solid #000000; voice-family: "\"}\""; voice-family: inherit; margin-left: 201px; } ''' expect_CSS_3 = r''' #centercontent{border:1px solid #000;voice-family: "\"}\"";voice-family:inherit;margin-left:201px} ''' #---------------------------------------------------------------------------- CSS_3b = unicode(CSS_3) expect_CSS_3b = unicode(expect_CSS_3) #---------------------------------------------------------------------------- CSS_3c = u''' body { color:#000000; color:#ccFF99; \xa3 } ''' expect_CSS_3c = u''' body{color:#000;color:#cF9;\xa3}''' #---------------------------------------------------------------------------- CSS_4 = r''' p { color:#123456; } select { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 11px; color: #000000; /* background-color: #FFFFFF; */ } #myDiv { float: left; background: transparent; } ''' expect_CSS_4 = r''' p{color:#123456}select{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;color:#000}#myDiv{float:left;background:transparent} ''' #---------------------------------------------------------------------------- CSS_5 = r''' /* remove this comment */ #isnotMacIE5 { display: none; } #isMacIE5 { display: block; background-color: #060; color: #fff; } /* commented backslash hack v2 \*/ #isnotMacIE5 { display: block; background-color: #060; color: #fff; } #isMacIE5 { display: none; } /* keep this comment */ #ismozilla { state: cool; } /* safely remove this one too */ ''' expect_CSS_5 = r''' #isnotMacIE5{display:none}#isMacIE5{display:block;background-color:#060;color:#fff}/* commented backslash hack v2 \*/ #isnotMacIE5{display:block;background-color:#060;color:#fff}#isMacIE5{display:none}/* keep this comment */ #ismozilla{state:cool} ''' #---------------------------------------------------------------------------- CSS_6 = r''' div a {display:block;} ''' expect_CSS_6 = r''' div a{display:block} ''' #---------------------------------------------------------------------------- CSS_7 = r''' /* Holly hack to cure peek-a-boo IE 6 bug*/ /* Hides from IE5-mac \*/ * html #region-content {height: 1%;} /* End hide from IE5-mac */ ''' expect_CSS_7 = r''' /* Hides from IE5-mac \*/ * html #region-content{height:1%}/* End hide from IE5-mac */ ''' #---------------------------------------------------------------------------- HTML_1=''' <img src="a.gif" width="100" width="100" height='100' border=0> <STYLE type="text/css"> div#main { font-family:Verdana, "Courier New" ; } </style> <pre> Here width="100" </pre> ''' expect_HTML_1=''' <img src="a.gif" width="100" width="100" height='100' border=0><STYLE type="text/css"> div#main{font-family:Verdana,"Courier New"}</style><pre> Here width="100" </pre> ''' #---------------------------------------------------------------------------- HTML_2=''' <a href="x" width="100%" border='0'>Pointless extra space</a> <!-- one line comment --> <!-- two line comment --> <script language="Javascript"> <!-- hide this function foo() { alert("Hell"); } //--> </script> ''' expect_HTML_2=''' <a href="x" width="100%" border='0'>Pointless extra space</a><!-- two line comment --><script language="Javascript"><!-- function foo(){alert("Hell");} //--></script> ''' #---------------------------------------------------------------------------- HTML_3=''' <input value=" OK " > <img alt=' hej ' title=" Bajs " width=32 > <a href="x" width="100%" border=0>Pointless extra space</a> <img src='blank.gif' border='0' height='32' alt='' width='32'> ''' expect_HTML_3=''' <input value=" OK "><img alt=' hej ' title=" Bajs " width=32 ><a href="x" width="100%" border=0>Pointless extra space</a><img src='blank.gif' border='0' height='32' alt='' width='32'> ''' #---------------------------------------------------------------------------- HTML_4='''<script> if (isMozi) { slides = slideml.doc.getElementsByTagNameNS("http://www.oscom.org/2003/SlideML/1.0/","slide"); } else { slides = slideml.doc.getElementsByTagName("s:slide"); } </script>''' expect_HTML_4 = '''<script>if(isMozi){slides=slideml.doc.getElementsByTagNameNS("http://www.oscom.org/2003/SlideML/1.0/","slide");}else{slides=slideml.doc.getElementsByTagName("s:slide");} </script>''' #---------------------------------------------------------------------------- HTML_5='''<img src="/p_/sp" width="2" height="1" alt="" />''' expect_HTML_5='''<img src="/p_/sp" width="2" height="1" alt="" />''' #---------------------------------------------------------------------------- HTML_6=''' <style type="text/css"><!-- div.commentinline { font-family:Arial, Verdana, sans-serif; border-top:1px solid #cccccc; padding:3px 4px 4px 4px; margin-top:10px; margin-bottom:10px; margin-left:15px; } //--></style> ''' expect_HTML_6=''' <style type="text/css"><!-- div.commentinline{font-family:Arial,Verdana,sans-serif;border-top:1px solid #ccc;padding:3px 4px 4px 4px;margin-top:10px;margin-bottom:10px;margin-left:15px} //--></style>''' #---------------------------------------------------------------------------- HTML_7=''' <html> <!--#include virtual="/include/myinclude.asp"--> <body> </body> </html> ''' expect_HTML_7=''' <html><!--#include virtual="/include/myinclude.asp"--><body></body></html> ''' #---------------------------------------------------------------------------- HTML_8=u''' <html> <style> * { color:#000000; background-color:#ffcc99 ; } </style> <body> <div style="color:#CCCCCC; background-color: #ee99cc">Pay with \xa3</div> </body> </html> ''' expect_HTML_8=u''' <html><style> *{color:#000;background-color:#fc9}</style><body><div style="color:#CCCCCC; background-color: #ee99cc">Pay with \xa3</div></body></html> ''' #---------------------------------------------------------------------------- HTML_9=u''' <html> <style> * { color:#000000; background-color:#ffcc99 ; } </style> <body> <div style="color:#CCCCCC; background-color: #ee99cc">Pay with \xa3</div> </body> </html> ''' expect_HTML_9=u''' <html><style> *{color:#000;background-color:#fc9}</style><body><div style="color:#CCCCCC; background-color: #ee99cc">Pay with \xa3</div></body></html> ''' #---------------------------------------------------------------------------- JS_1=''' init = function() { foo(); bar(); } window.onload = init; ''' expect_JS_1=''' init=function(){foo();bar();} window.onload=init; ''' #---------------------------------------------------------------------------- JS_2=''' function econvert(s) { s=s.replace(/%7E/g,'~'); s=s.replace(/%28/g,'('); s=s.replace(/%29/g,')'); s=s.replace(/%20/g,' '); s=s.replace(/_dot_| dot |_\._|\(\.\)/gi, '.'); s=s.replace(/_at_|~at~/gi, '@'); return s; } function AEHit() { var ss = document.getElementsByTagName("span"); for (i=0; i< ss.length; i++) if (ss[i].className=="aeh") ss[i].innerHTML = econvert(ss[i].innerHTML); } ''' expect_JS_2=''' function econvert(s){s=s.replace(/%7E/g,'~');s=s.replace(/%28/g,'('); s=s.replace(/%29/g,')');s=s.replace(/%20/g,' ');s=s.replace(/_dot_| dot |_\._|\(\.\)/gi, '.');s=s.replace(/_at_|~at~/gi, '@');return s;} function AEHit(){var ss=document.getElementsByTagName("span");for (i=0;i< ss.length;i++)if(ss[i].className=="aeh") ss[i].innerHTML=econvert(ss[i].innerHTML);} ''' #---------------------------------------------------------------------------- JS_3=''' var x = " "; x +="nothing"; x+= "something"; x+="anything"; y = 10; y +=1; y+= 1; y+=1; y +=15; y+= 15; y+=15; ''' expect_JS_3=''' var x=" ";x+="nothing";x+="something";x+="anything"; y=10;y+=1;y+=1;y+=1; y+=15;y+=15;y+=15; ''' #---------------------------------------------------------------------------- JS_4 =''' this.onLoad = true; this.onLoaded = false; var x = true; ''' expect_JS_4 =''' this.onLoad=true;this.onLoaded=false;var x=true; ''' #---------------------------------------------------------------------------- JS_5 =''' if (document.getElementById("someting")) { cool(); } else if (document.getElementById("elsething")) { wicked(); } else { poor(); } ''' expect_JS_5 =''' if(document.getElementById("someting")){cool();}else if(document.getElementById("elsething")){wicked();}else{poor();} ''' #---------------------------------------------------------------------------- # function foo() { alert( "foo" ); } JS_6 =''' bar = function () { alert( "bar" ); } bar2 = function() { alert( "bar2" ); } ''' # function foo(){alert( "foo" );} expect_JS_6 =''' bar=function(){alert( "bar" );} bar2=function(){alert( "bar2" );} ''' #---------------------------------------------------------------------------- # testing local variables inside functions JS_7 =''' function foobar(x,y) { var element1 = document.getElementById('something'); alert(element1); } ''' # function foo(){alert( "foo" );} expect_JS_7 =''' function foobar(x,y) { var e = document.getElementById('something'); alert(e); } ''' #---------------------------------------------------------------------------- # comments within the code JS_8 =''' function foobar(x,y) { var element1 = document.getElementById('something'); // alert(element1); alert(element1); // this can be removed } // end of function; ''' expect_JS_8 =''' function foobar(x,y){var element1=document.getElementById('something');alert(element1);} ''' #---------------------------------------------------------------------------- # JS_9 =''' function nodeContained(innernode, outernode){ // check if innernode is contained in outernode var node = innernode.parentNode; while (node != document) { if (node == outernode) { return true; } node=node.parentNode; } return false; }; ''' expect_JS_9 =''' function nodeContained(innernode,outernode){var node=innernode.parentNode;while(node!=document){if(node==outernode) {return true;} node=node.parentNode;} return false;}; ''' #---------------------------------------------------------------------------- # JS_10 =''' // Insert P element if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) { // Insert P element instead of BR if (tinyMCE.selectedInstance._insertPara(e)) { // Cancel event tinyMCE.execCommand("mceAddUndoLevel"); tinyMCE.cancelEvent(e); return false; } } ''' expect_JS_10 =''' if(tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey){if(tinyMCE.selectedInstance._insertPara(e)) {tinyMCE.execCommand("mceAddUndoLevel");tinyMCE.cancelEvent(e); return false;}} ''' JS_11 = ''' ajax = Class.create(); ajax.prototype = { initialize: function(url, options){ this.transport = this.getTransport(); this.postBody = options.postBody || ''; this.method = options.method || 'post'; this.onComplete = options.onComplete || null; this.update = $(options.update) || null; this.request(url); }, request: function(url){ this.transport.open(this.method, url, true); this.transport.onreadystatechange = this.onStateChange.bind(this); if (this.method == 'post') { this.transport.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); if (this.transport.overrideMimeType) this.transport.setRequestHeader('Connection', 'close'); } this.transport.send(this.postBody); }, onStateChange: function(){ if (this.transport.readyState == 4 && this.transport.status == 200) { if (this.onComplete) setTimeout(function(){this.onComplete(this.transport);}.bind(this), 10); if (this.update) setTimeout(function(){this.update.innerHTML = this.transport.responseText;}.bind(this), 10); this.transport.onreadystatechange = function(){}; } }, getTransport: function() { if (window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP'); else if (window.XMLHttpRequest) return new XMLHttpRequest(); else return false; } }; ''' expect_JS_11 =''' ajax=Class.create();ajax.prototype = {initialize: function(url,options){this.transport=this.getTransport();this.postBody=options.postBody || '';this.method=options.method || 'post';this.onComplete=options.onComplete || null;this.update = $(options.update) || null;this.request(url);}, request: function(url){this.transport.open(this.method, url, true);this.transport.onreadystatechange=this.onStateChange.bind(this);if(this.method=='post'){this.transport.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');if(this.transport.overrideMimeType) this.transport.setRequestHeader('Connection', 'close');} this.transport.send(this.postBody);}, onStateChange: function(){if(this.transport.readyState == 4 && this.transport.status == 200) {if(this.onComplete) setTimeout(function(){this.onComplete(this.transport);}.bind(this),10);if(this.update) setTimeout(function(){this.update.innerHTML=this.transport.responseText;}.bind(this),10);this.transport.onreadystatechange=function(){};}}, getTransport: function(){if(window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP');else if(window.XMLHttpRequest) return new XMLHttpRequest();else return false;}}; ''' expect_JS_11_hardcore =''' ajax=Class.create();ajax.prototype = {initialize: function(_0,_1){this.transport=this.getTransport();this.postBody=_1.postBody || '';this.method=_1.method || 'post';this.onComplete=_1.onComplete || null;this.update = $(_1.update) || null;this.request(_0);}, request: function(_0){this.transport.open(this.method, _0, true);this.transport.onreadystatechange=this.onStateChange.bind(this);if(this.method=='post'){this.transport.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');if(this.transport.overrideMimeType) this.transport.setRequestHeader('Connection', 'close');} this.transport.send(this.postBody);}, onStateChange: function(){if(this.transport.readyState == 4 && this.transport.status == 200) {if(this.onComplete) setTimeout(function(){this.onComplete(this.transport);}.bind(this),10);if(this.update) setTimeout(function(){this.update.innerHTML=this.transport.responseText;}.bind(this),10);this.transport.onreadystatechange=function(){};}}, getTransport: function(){if(window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP');else if(window.XMLHttpRequest) return new XMLHttpRequest();else return false;}}; ''' #---------------------------------------------------------------------------- JS_12=''' function foo(documentnode, nodevalue) { return documentnode + nodevalue; } ''' expect_JS_12=''' function foo(documentnode,nodevalue){return documentnode + nodevalue;} ''' expect_JS_12_hardcore=''' function foo(_0,_1){return _0 + _1;} ''' #---------------------------------------------------------------------------- JS_13 = ''' addEvent(window, 'load', function(){ var editlinks = getElementsByClass("edit", document, "img"); for (var e in editlinks) { foo(); } }); ''' expect_JS_13 = ''' addEvent(window, 'load', function(){var editlinks=getElementsByClass("edit", document, "img");for(var e in editlinks){foo();}}); ''' #---------------------------------------------------------------------------- JS_14 = ''' function (variable1, variable2) { if (variable1 == variable2) { return true; } else { return false; } }''' expect_JS_14 = ''' function (variable1,variable2) {if(variable1==variable2){return true;}else{return false;}} ''' expect_JS_14_hardcore = ''' function (_0,_1) {if(_0==_1){return true;}else{return false;}} ''' #---------------------------------------------------------------------------- JS_15 = ''' var x =1 if (x==1) { x=2; }''' expect_JS_15 = ''' var x=1if(x==1){x=2;} ''' #---------------------------------------------------------------------------- JS_16 = ''' var uk_counties = ['a', 'b', 'c']; var uk__9123 = ['a', 'b', 'c']; var uk = ['a', 'b', 'c']; var uk_counties = ["a", "b", "c"]; var uk__9123 = ["a", "b", "c"]; var uk = ["a", "b", "c"]; ''' expect_JS_16 = ''' var uk_counties=['a', 'b', 'c'];var uk__9123=['a', 'b', 'c'];var uk=['a', 'b', 'c'];var uk_counties=["a", "b", "c"];var uk__9123=["a", "b", "c"];var uk=["a", "b", "c"]; ''' ����������������������������������������������������������������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/slimit.py��������������������������������������������������������������������0000755�0001750�0001750�00000003430�11114011722�016415� 0����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python """ A command line program wrapper to slimmer """ from slimmer import * from slimmer import run import CommandLineApp class slimit(CommandLineApp.CommandLineApp): """ whitespace trip HTML, XHTML, Javascript and CSS """ EXAMPLES_DESCRIPTION = """ To slim a html file: $ slimit /home/peter/big.html xhtml To slim a Javascript file: $ slimit library.js js Most of the time you don't need specify the format since it's guessed: $ slimit screen.css To save to a particular file other than stdout: $ slimit --output=library.slimmed.js library.js """ def optionHandler_version(self): """Prints version and exits""" print __version__ speedtest = 0 def optionHandler_test(self): """Perform a speed and compression test""" self.speedtest = 1 optionHandler_t = optionHandler_test outputfile = None def optionHandler_output(self, path): """ Save result to file """ self.outputfile = path hardcore = False def optionHandler_hardcore(self): """Tries really hard but potentially slower. Default is not to do it hardcore.""" self.hardcore = True def showVerboseHelp(self): CommandLineApp.CommandLineApp.showVerboseHelp(self) def main(self, filename, syntax=None): """ Run the slimmer """ if syntax is None: print "guess for", repr(filename), syntax = guessSyntax(filename) print repr(syntax) print syntax run(filename, syntax, self.speedtest, self.outputfile, hardcore=self.hardcore) if __name__ == '__main__': slimit().run() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������slimmer-0.1.30/slimmer/js_function_slimmer.py�������������������������������������������������������0000644�0001750�0001750�00000011145�11114011722�021164� 0����������������������������������������������������������������������������������������������������ustar �peterbe�������������������������peterbe����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������""" js_function_slimmer.py Peter Bengtsson, mail@peterbe.com, 2004-2006 >>> from slimmer.js_function_slimmer import slim >>> print slim('''// comment ... function foo(parameter1, parameter2) { ... if (parameter1 > parameter2) { ... parameter2 = parameter1; ... } ... } ... // post comment''') // comment function foo(_0,_1) { if (_0 > _1) { _1 = _0; } } // post comment >>> It digs out the functions and make them slimmer. Changes:: 0.0.2 May 2006 Added slim_func_names() 0.0.1 Feb 2006 First draft """ import re function_start_regex = re.compile('(function[ \w+\s*]\(([^\)]*)\)\s*{)') function_start_regex = re.compile('(function(\s+\w+|)\s*\(([^\)]*)\)\s*{)') function_name_regex = re.compile('(function (\w+)\()') def _findFunctions(whole): functions = [] for res in function_start_regex.findall(whole): function_start, function_name, params = res params_split = [x.strip() for x in params.split(',')] stack = 1 code = function_start core_code = '' start = whole.find(function_start) + len(code) while stack > 0: #start += 1 next_char = whole[start] core_code += next_char if next_char == '{': stack += 1 elif next_char == '}': stack -= 1 start += 1 yield (params, params_split, core_code[:-1], function_start) def slim_params(code): new_functions = [] old_functions = {} new_code = code for params, params_split, core, function_start in _findFunctions(code): params_split_use = [x for x in params_split if len(x)>1] _param_regex = '|'.join([r'\b%s\b' % x for x in params_split_use]) param_regex = re.compile(_param_regex) new_params = {} for i in range(len(params_split_use)): new_params[params_split[i]] = '_%s' % i def replacer(match): return new_params.get(match.group()) new_core = param_regex.sub(replacer, core) _params = [] for p in params_split: _params.append(new_params.get(p,p)) new_function = function_start.replace(params, ','.join(_params))+\ new_core + '}' old_function = function_start+core+'}' old_functions[old_function] = new_function # killer regex regex = '|'.join([re.escape(x) for x in old_functions.keys()]) def replacer(match): return old_functions.get(match.group()) return re.sub(regex, replacer, new_code) class NamesGenerator: def __init__(self): self.i = 0 self.pool = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ') def next(self): try: e = self.pool[self.i] self.i = self.i + 1 except IndexError: if not hasattr(self, 'j'): self.j = 0 self.pool.extend([x.lower() for x in self.pool]) try: e = self.pool[self.i % len(self.pool)] +\ self.pool[self.j] self.j = self.j + 1 except IndexError: self.i += 1 self.j = 0 return self.next() return '_%s' % e def slim_func_names(js): relabel_functions = [] functions = function_name_regex.findall(js) new_names_generator = NamesGenerator() for whole_func, func_name in functions: count = js.count(func_name) if len(func_name) > 2 and count > 1: #print func_name, count, #len(re.findall(r'\b%s\b'% re.escape(func_name), js)) new_name = new_names_generator.next() if re.findall(r'\b%s\b' % re.escape(new_name), js): #print "new_name:%r\n\n%s" % (new_name, js) continue js = re.sub(r'\b%s\b'% re.escape(func_name), new_name, js) relabel_functions.append((func_name, new_name)) add_codes=['var %s=%s'%(x,y) for (x,y) in relabel_functions] add_code = ';'.join(add_codes) return js + add_code def slim(code): return slim_func_names(slim_params(code)) def test(inputbuffer): from time import time t0 = time() js1 = inputbuffer.read() res = slim(js1) t1 = time() print t1-t0 return res if __name__=='__main__': import sys argv = sys.argv[1:] if argv: print test(open(argv[0])) else: test(sys.stdin) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������