From 6cdfb77083aaedf56af88deec589b5a78053c205 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 30 Jun 2008 19:46:23 +0000 Subject: [PATCH] Added Minify_Lines to test suite, full docs on added methods in Minify & Minify_Lines. --- lib/Minify.php | 9 +- lib/Minify/Lines.php | 35 ++- web/test/_test_files/minify/lines_output.js | 245 ++++++++++++++++++++ web/test/test_Lines.php | 43 ++-- web/test/test_all.php | 1 + 5 files changed, 298 insertions(+), 35 deletions(-) create mode 100644 web/test/_test_files/minify/lines_output.js diff --git a/lib/Minify.php b/lib/Minify.php index 8128668..9c56bff 100644 --- a/lib/Minify.php +++ b/lib/Minify.php @@ -98,6 +98,10 @@ class Minify { * E.g. ($_SERVER['REQUEST_TIME'] + 86400 * 365) for 1yr * Note this has nothing to do with server-side caching. * + * 'debug' : set to true to minify all sources with the 'Lines' controller, which + * eases the debugging of combined files. This also prevents 304 responses. + * @see Minify_Lines::minify() + * * 'minifiers' : to override Minify's default choice of minifier function for * a particular content-type, specify your callback under the key of the * content-type: @@ -305,13 +309,16 @@ class Minify { * Set up sources to use Minify_Lines * * @param array $sources Minify_Source instances + * + * @return null */ protected static function _setupDebug($sources) { foreach ($sources as $source) { $source->minifier = array('Minify_Lines', 'minify'); + $id = $source->getId(); $source->minifyOptions = array( - 'id' => $source->getId() + 'id' => (is_file($id) ? basename($id) : $id) ); } } diff --git a/lib/Minify/Lines.php b/lib/Minify/Lines.php index 37301a3..e9b76fa 100644 --- a/lib/Minify/Lines.php +++ b/lib/Minify/Lines.php @@ -14,12 +14,16 @@ class Minify_Lines { /** * Add line numbers in C-style comments + * + * This uses a very basic parser easily fooled by comment tokens inside + * strings or regexes, but, otherwise, generally clean code will not be + * mangled. * * @param string $content * * @param array $options available options: * - * 'id': (optional) short string to identify file. E.g. "jqp" for plugins.jquery.js + * 'id': (optional) string to identify file. E.g. file name/path * * @return string */ @@ -37,11 +41,10 @@ class Minify_Lines { $padTo = strlen($numLines); $inComment = false; $i = 0; + $newLines = array(); while (null !== ($line = array_shift($lines))) { if (('' !== $id) && (0 == $i % 50)) { - $newLines[] = ''; - $newLines[] = "/* {$id} */"; - $newLines[] = ''; + array_push($newLines, '', "/* {$id} */", ''); } ++$i; $newLines[] = self::_addNote($line, $i, $inComment, $padTo); @@ -71,6 +74,16 @@ class Minify_Lines { : "\n"; } + /** + * Is the parser within a C-style comment at the end of this line? + * + * @param string $line current line of code + * + * @param bool $inComment was the parser in a comment at the + * beginning of the line? + * + * @return bool + */ private static function _eolInComment($line, $inComment) { while (strlen($line)) { @@ -88,6 +101,20 @@ class Minify_Lines { return $inComment; } + /** + * Prepend a comment (or note) to the given line + * + * @param string $line current line of code + * + * @param string $note content of note/comment + * + * @param bool $inComment was the parser in a comment at the + * beginning of the line? + * + * @param int $padTo minimum width of comment + * + * @return string + */ private static function _addNote($line, $note, $inComment, $padTo) { return $inComment diff --git a/web/test/_test_files/minify/lines_output.js b/web/test/_test_files/minify/lines_output.js new file mode 100644 index 0000000..dd06908 --- /dev/null +++ b/web/test/_test_files/minify/lines_output.js @@ -0,0 +1,245 @@ + +/* email.js */ + +/* 1 */ // http://mrclay.org/ +/* 2 */ (function(){ +/* 3 */ var +/* 4 */ reMailto = /^mailto:my_name_is_(\S+)_and_the_domain_is_(\S+)$/, +/* 5 */ reRemoveTitleIf = /^my name is/, +/* 6 */ oo = window.onload, +/* 7 */ fixHrefs = function() { +/* 8 */ var i = 0, l, m; +/* 9 */ while (l = document.links[i++]) { +/* 10 */ // require phrase in href property +/* 11 */ if (m = l.href.match(reMailto)) { +/* 12 */ l.href = 'mailto:' + m[1] + '@' + m[2]; +/* 13 */ if (reRemoveTitleIf.test(l.title)) { +/* 14 */ l.title = ''; +/* 15 */ } +/* 16 */ } +/* 17 */ } +/* 18 */ }; +/* 19 */ // end var +/* 20 */ window.onload = function() { +/* 21 */ oo && oo(); +/* 22 */ fixHrefs(); +/* 23 */ }; +/* 24 */ })(); +; +/* QueryString.js */ + +/* 1 */ var MrClay = window.MrClay || {}; +/* 2 */ +/* 3 */ /** +/* 4 *| * Simplified access to/manipulation of the query string +/* 5 *| * +/* 6 *| * Based on: http://adamv.com/dev/javascript/files/querystring.js +/* 7 *| * Design pattern: http://www.litotes.demon.co.uk/js_info/private_static.html#wConst +/* 8 *| */ +/* 9 */ MrClay.QueryString = function(){ +/* 10 */ /** +/* 11 *| * @static +/* 12 *| * @private +/* 13 *| */ +/* 14 */ var parse = function(str) { +/* 15 */ var assignments = str.split('&') +/* 16 */ ,obj = {} +/* 17 */ ,propValue; +/* 18 */ for (var i = 0, l = assignments.length; i < l; ++i) { +/* 19 */ propValue = assignments[i].split('='); +/* 20 */ if (propValue.length > 2 +/* 21 */ || -1 != propValue[0].indexOf('+') +/* 22 */ || propValue[0] == '' +/* 23 */ ) { +/* 24 */ continue; +/* 25 */ } +/* 26 */ if (propValue.length == 1) { +/* 27 */ propValue[1] = propValue[0]; +/* 28 */ } +/* 29 */ obj[unescape(propValue[0])] = unescape(propValue[1].replace(/\+/g, ' ')); +/* 30 */ } +/* 31 */ return obj; +/* 32 */ }; +/* 33 */ +/* 34 */ /** +/* 35 *| * Constructor (MrClay.QueryString becomes this) +/* 36 *| * +/* 37 *| * @param mixed A window object, a query string, or empty (default current window) +/* 38 *| */ +/* 39 */ function construct_(spec) { +/* 40 */ spec = spec || window; +/* 41 */ if (typeof spec == 'object') { +/* 42 */ // get querystring from window +/* 43 */ this.window = spec; +/* 44 */ spec = spec.location.search.substr(1); +/* 45 */ } else { +/* 46 */ this.window = window; +/* 47 */ } +/* 48 */ this.vars = parse(spec); +/* 49 */ } +/* 50 */ + +/* QueryString.js */ + +/* 51 */ /** +/* 52 *| * Reload the window +/* 53 *| * +/* 54 *| * @static +/* 55 *| * @public +/* 56 *| * @param object vars Specify querystring vars only if you wish to replace them +/* 57 *| * @param object window_ window to be reloaded (current window by default) +/* 58 *| */ +/* 59 */ construct_.reload = function(vars, window_) { +/* 60 */ window_ = window_ || window; +/* 61 */ vars = vars || (new MrClay.QueryString(window_)).vars; +/* 62 */ var l = window_.location +/* 63 */ ,currUrl = l.href +/* 64 */ ,s = MrClay.QueryString.toString(vars) +/* 65 */ ,newUrl = l.protocol + '//' + l.hostname + l.pathname +/* 66 */ + (s ? '?' + s : '') + l.hash; +/* 67 */ if (currUrl == newUrl) { +/* 68 */ l.reload(); +/* 69 */ } else { +/* 70 */ l.assign(newUrl); +/* 71 */ } +/* 72 */ }; +/* 73 */ +/* 74 */ /** +/* 75 *| * Get the value of a querystring var +/* 76 *| * +/* 77 *| * @static +/* 78 *| * @public +/* 79 *| * @param string key +/* 80 *| * @param mixed default_ value to return if key not found +/* 81 *| * @param object window_ window to check (current window by default) +/* 82 *| * @return mixed +/* 83 *| */ +/* 84 */ construct_.get = function(key, default_, window_) { +/* 85 */ window_ = window_ || window; +/* 86 */ return (new MrClay.QueryString(window_)).get(key, default_); +/* 87 */ }; +/* 88 */ +/* 89 */ /** +/* 90 *| * Reload the page setting one or multiple querystring vars +/* 91 *| * +/* 92 *| * @static +/* 93 *| * @public +/* 94 *| * @param mixed key object of query vars/values, or a string key for a single +/* 95 *| * assignment +/* 96 *| * @param mixed null for multiple settings, the value to assign for single +/* 97 *| * @param object window_ window to reload (current window by default) +/* 98 *| */ +/* 99 */ construct_.set = function(key, value, window_) { +/* 100 */ window_ = window_ || window; + +/* QueryString.js */ + +/* 101 */ (new MrClay.QueryString(window_)).set(key, value).reload(); +/* 102 */ }; +/* 103 */ +/* 104 */ /** +/* 105 *| * Convert an object of query vars/values to a querystring +/* 106 *| * +/* 107 *| * @static +/* 108 *| * @public +/* 109 *| * @param object query vars/values +/* 110 *| * @return string +/* 111 *| */ +/* 112 */ construct_.toString = function(vars) { +/* 113 */ var pieces = []; +/* 114 */ for (var prop in vars) { +/* 115 */ pieces.push(escape(prop) + '=' + escape(vars[prop])); +/* 116 */ } +/* 117 */ return pieces.join('&'); +/* 118 */ }; +/* 119 */ +/* 120 */ /** +/* 121 *| * @public +/* 122 *| */ +/* 123 */ construct_.prototype.reload = function() { +/* 124 */ MrClay.QueryString.reload(this.vars, this.window); +/* 125 */ return this; +/* 126 */ }; +/* 127 */ +/* 128 */ /** +/* 129 *| * @public +/* 130 *| */ +/* 131 */ construct_.prototype.get = function(key, default_) { +/* 132 */ if (typeof default_ == 'undefined') { +/* 133 */ default_ = null; +/* 134 */ } +/* 135 */ return (this.vars[key] == null) +/* 136 */ ? default_ +/* 137 */ : this.vars[key]; +/* 138 */ }; +/* 139 */ +/* 140 */ /** +/* 141 *| * @public +/* 142 *| */ +/* 143 */ construct_.prototype.set = function(key, value) { +/* 144 */ var obj = {}; +/* 145 */ if (typeof key == 'string') { +/* 146 */ obj[key] = value; +/* 147 */ } else { +/* 148 */ obj = key; +/* 149 */ } +/* 150 */ for (var prop in obj) { + +/* QueryString.js */ + +/* 151 */ if (obj[prop] == null) { +/* 152 */ delete this.vars[prop]; +/* 153 */ } else { +/* 154 */ this.vars[prop] = obj[prop]; +/* 155 */ } +/* 156 */ } +/* 157 */ return this; +/* 158 */ }; +/* 159 */ +/* 160 */ /** +/* 161 *| * @public +/* 162 *| */ +/* 163 */ construct_.prototype.toString = function() { +/* 164 */ return QueryString.toString(this.vars); +/* 165 */ }; +/* 166 */ +/* 167 */ return construct_; +/* 168 */ }(); // define and execute +; +/* before.js */ + +/* 1 */ /*! is.js +/* 2 *| +/* 3 *| (c) 2001 Douglas Crockford +/* 4 *| 2001 June 3 +/* 5 *| */ +/* 6 */ +/* 7 */ // is +/* 8 */ +/* 9 */ // The -is- object is used to identify the browser. Every browser edition +/* 10 */ // identifies itself, but there is no standard way of doing it, and some of +/* 11 */ // the identification is deceptive. This is because the authors of web +/* 12 */ // browsers are liars. For example, Microsoft's IE browsers claim to be +/* 13 */ // Mozilla 4. Netscape 6 claims to be version 5. +/* 14 */ +/* 15 */ var is = { +/* 16 */ ie: navigator.appName == 'Microsoft Internet Explorer', +/* 17 */ java: navigator.javaEnabled(), +/* 18 */ ns: navigator.appName == 'Netscape', +/* 19 */ ua: navigator.userAgent.toLowerCase(), +/* 20 */ version: parseFloat(navigator.appVersion.substr(21)) || +/* 21 */ parseFloat(navigator.appVersion), +/* 22 */ win: navigator.platform == 'Win32' +/* 23 */ } +/* 24 */ /*!* +/* 25 *| * preserve this comment, too +/* 26 *| */ +/* 27 */ is.mac = is.ua.indexOf('mac') >= 0; +/* 28 */ if (is.ua.indexOf('opera') >= 0) { +/* 29 */ is.ie = is.ns = false; +/* 30 */ is.opera = true; +/* 31 */ } +/* 32 */ if (is.ua.indexOf('gecko') >= 0) { +/* 33 */ is.ie = is.ns = false; +/* 34 */ is.gecko = true; +/* 35 */ } diff --git a/web/test/test_Lines.php b/web/test/test_Lines.php index d48fb40..0e7fd27 100644 --- a/web/test/test_Lines.php +++ b/web/test/test_Lines.php @@ -1,14 +1,18 @@ true + ,'quiet' => true + ,'encodeOutput' => false ,'files' => array( "{$thisDir}/_test_files/minify/email.js" ,"{$thisDir}/_test_files/minify/QueryString.js" @@ -16,35 +20,14 @@ function test_Lines() ) )); - /* - // build test file list - $d = dir($cssPath); - while (false !== ($entry = $d->read())) { - if (preg_match('/^([\w\\-]+)\.css$/', $entry, $m)) { - $list[] = $m[1]; + $passed = assertTrue($exp === $ret['content'], 'Minify_Lines'); + + if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) { + echo "\n---Output: " .strlen($ret['content']). " bytes\n\n{$ret['content']}\n\n"; + if (!$passed) { + echo "---Expected: " .strlen($exp). " bytes\n\n{$exp}\n\n\n"; } } - $d->close(); - - foreach ($list as $item) { - - $options = ($item === 'paths') - ? array('prependRelativePath' => '../') - : array(); - - $src = file_get_contents($cssPath . "/{$item}.css"); - $minExpected = file_get_contents($cssPath . "/{$item}.min.css"); - $minOutput = Minify_CSS::minify($src, $options); - $passed = assertTrue($minExpected === $minOutput, 'Minify_CSS : ' . $item); - - if (__FILE__ === realpath($_SERVER['SCRIPT_FILENAME'])) { - echo "\n---Output: " .strlen($minOutput). " bytes\n\n{$minOutput}\n\n"; - if (!$passed) { - echo "---Expected: " .strlen($minExpected). " bytes\n\n{$minExpected}\n\n"; - echo "---Source: " .strlen($src). " bytes\n\n{$src}\n\n\n"; - } - } - } */ } -test_Lines(); +test_Lines(); \ No newline at end of file diff --git a/web/test/test_all.php b/web/test/test_all.php index 5dff42b..c1efd27 100644 --- a/web/test/test_all.php +++ b/web/test/test_all.php @@ -3,6 +3,7 @@ require 'test_Minify.php'; require 'test_Javascript.php'; require 'test_CSS.php'; +require 'test_Lines.php'; require 'test_HTML.php'; require 'test_Minify_Build.php'; require 'test_HTTP_Encoder.php';