reduce 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ spec/files/*.min
data/README.markdown ADDED
@@ -0,0 +1,32 @@
1
+ Lossless reduction for js, css, jpg, png, gif
2
+
3
+ Install
4
+ =======
5
+ install ruby + rubygems
6
+ sudo gem install reduce
7
+
8
+ Usage
9
+ =====
10
+ reduce -o public/image.gif
11
+ reduce public/javascripts/application.js > public/javascripts/application.min.js
12
+
13
+ Options
14
+ =======
15
+ -o, --overwrite overwrite file
16
+ -v, --version Show Version
17
+ -h, --help Show this.
18
+
19
+ Ruby
20
+ ====
21
+ reduced_data = Reduce.reduce('files/bla.js')
22
+
23
+ How does it work?
24
+ =================
25
+ - uses web-based lossless image reduction service [Smush.it](http://smush.it) / [PunyPng](http://www.gracepointafterfive.com/punypng) through [smusher](http://github.com/grosser/smusher)
26
+ - uses YUI compressor to minify css/js
27
+
28
+ Author
29
+ ======
30
+ Michael Grosser
31
+ grosser.michael@gmail.com
32
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ task :default => :spec
2
+ require 'spec/rake/spectask'
3
+ Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color']}
4
+
5
+ begin
6
+ require 'jeweler'
7
+ project_name = 'reduce'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "reduce"
10
+ gem.summary = "Reduce your assets: minify javascript + stylesheets, optimize images lossless"
11
+ gem.email = "grosser.michael@gmail.com"
12
+ gem.homepage = "http://github.com/grosser/#{project_name}"
13
+ gem.authors = ["Michael Grosser"]
14
+ gem.add_dependency ['smusher']
15
+ end
16
+
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/bin/reduce ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+ require 'reduce'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = <<BANNER
9
+ Lossless optimize js, css, jpg, png, gif
10
+
11
+ Usage:
12
+ reduce -o public/image.gif
13
+ reduce public/javascripts/application.js > public/javascripts/application.min.js
14
+
15
+ Options are:
16
+ BANNER
17
+ opts.on("-o", "--overwrite", "overwrite file") { options[:overwrite]=true }
18
+ opts.on('-v', '--version', 'Show Version'){ puts Reduce::VERSION; exit}
19
+ opts.on("-h", "--help", "Show this.") { puts opts; exit }
20
+ end.parse!
21
+
22
+ file = ARGV.first
23
+ if file.to_s.empty? or not File.exist?(file)
24
+ puts "Usage instructions: reduce --help"
25
+ exit
26
+ else
27
+ data = Reduce.reduce(file)
28
+ if options[:overwrite]
29
+ File.open(file, 'w'){|f| f.print data}
30
+ else
31
+ print data
32
+ end
33
+ end
data/lib/reduce.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'smusher'
2
+ raise "please install a newer version of smusher" if Smusher::VERSION < '0.4.0'
3
+
4
+ module Reduce
5
+ extend self
6
+
7
+ VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
8
+
9
+ def reduce(file)
10
+ extension = File.extname(file).downcase.sub('.','')
11
+ case extension
12
+ when 'js','css'
13
+ compressor = File.join(File.dirname(__FILE__),'..','vendor','yuicompressor*.jar')
14
+ `java -jar #{compressor} --type #{extension} #{file}`
15
+ when 'jpg', 'jpeg', 'png', 'gif'
16
+ reduce_image file
17
+ else
18
+ raise "reduce does not know how to handle a .#{extension} file (#{file})"
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def reduce_image(input)
25
+ output = input+'.temp'
26
+ FileUtils.cp(input, output)
27
+
28
+ service = (input.downcase =~ /\.gif$/ ? 'PunyPng' : 'SmushIt')
29
+ Smusher.optimize_image(output, :quiet=>true, :service => service)
30
+
31
+ data = File.read(output)
32
+ FileUtils.rm(output)
33
+ data
34
+ end
35
+ end
data/reduce.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{reduce}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2009-11-22}
13
+ s.default_executable = %q{reduce}
14
+ s.email = %q{grosser.michael@gmail.com}
15
+ s.executables = ["reduce"]
16
+ s.extra_rdoc_files = [
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "bin/reduce",
25
+ "lib/reduce.rb",
26
+ "reduce.gemspec",
27
+ "spec/files/facebox.css",
28
+ "spec/files/facebox.js",
29
+ "spec/files/paintcan.png",
30
+ "spec/files/test.gif",
31
+ "spec/reduce_spec.rb",
32
+ "spec/spec_helper.rb",
33
+ "vendor/README",
34
+ "vendor/yuicompressor-2.4.2.jar"
35
+ ]
36
+ s.homepage = %q{http://github.com/grosser/reduce}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{Reduce your assets: minify javascript + stylesheets, optimize images lossless}
41
+ s.test_files = [
42
+ "spec/spec_helper.rb",
43
+ "spec/reduce_spec.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<smusher>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<smusher>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<smusher>, [">= 0"])
57
+ end
58
+ end
59
+
@@ -0,0 +1,99 @@
1
+ #facebox .b {
2
+ background:url(/images/facebox/b.png);
3
+ }
4
+
5
+ #facebox .tl {
6
+ background:url(/images/facebox/tl.png);
7
+ }
8
+
9
+ #facebox .tr {
10
+ background:url(/images/facebox/tr.png);
11
+ }
12
+
13
+ #facebox .bl {
14
+ background:url(/images/facebox/bl.png);
15
+ }
16
+
17
+ #facebox .br {
18
+ background:url(/images/facebox/br.png);
19
+ }
20
+
21
+ #facebox {
22
+ position: absolute;
23
+ top: 0;
24
+ left: 0;
25
+ z-index: 100;
26
+ text-align: left;
27
+ }
28
+
29
+ #facebox .popup {
30
+ position: relative;
31
+ }
32
+
33
+ #facebox table {
34
+ border-collapse: collapse;
35
+ }
36
+
37
+ #facebox td {
38
+ border-bottom: 0;
39
+ padding: 0;
40
+ }
41
+
42
+ #facebox .body {
43
+ padding: 10px;
44
+ background: #fff;
45
+ width: 370px;
46
+ }
47
+
48
+ #facebox .loading {
49
+ text-align: center;
50
+ }
51
+
52
+ #facebox .image {
53
+ text-align: center;
54
+ }
55
+
56
+ #facebox img {
57
+ border: 0;
58
+ margin: 0;
59
+ }
60
+
61
+ #facebox .footer {
62
+ border-top: 1px solid #DDDDDD;
63
+ padding-top: 5px;
64
+ margin-top: 10px;
65
+ text-align: right;
66
+ }
67
+
68
+ #facebox .footer img {
69
+ vertical-align: middle;
70
+ }
71
+
72
+ #facebox .tl, #facebox .tr, #facebox .bl, #facebox .br {
73
+ height: 10px;
74
+ width: 10px;
75
+ overflow: hidden;
76
+ padding: 0;
77
+ }
78
+
79
+ #facebox_overlay {
80
+ position: fixed;
81
+ top: 0px;
82
+ left: 0px;
83
+ height:100%;
84
+ width:100%;
85
+ }
86
+
87
+ .facebox_hide {
88
+ z-index:-100;
89
+ }
90
+
91
+ .facebox_overlayBG {
92
+ background-color: #000;
93
+ z-index: 99;
94
+ }
95
+
96
+ * html #facebox_overlay { /* ie6 hack */
97
+ position: absolute;
98
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
99
+ }
@@ -0,0 +1,336 @@
1
+ /*
2
+ * Facebox (for jQuery)
3
+ * version: 1.2 (05/05/2008)
4
+ * @requires jQuery v1.2 or later
5
+ *
6
+ * Examples at http://famspam.com/facebox/
7
+ *
8
+ * Licensed under the MIT:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
12
+ *
13
+ * Usage:
14
+ *
15
+ * jQuery(document).ready(function() {
16
+ * jQuery('a[rel*=facebox]').facebox()
17
+ * })
18
+ *
19
+ * <a href="#terms" rel="facebox">Terms</a>
20
+ * Loads the #terms div in the box
21
+ *
22
+ * <a href="terms.html" rel="facebox">Terms</a>
23
+ * Loads the terms.html page in the box
24
+ *
25
+ * <a href="terms.png" rel="facebox">Terms</a>
26
+ * Loads the terms.png image in the box
27
+ *
28
+ *
29
+ * You can also use it programmatically:
30
+ *
31
+ * jQuery.facebox('some html')
32
+ * jQuery.facebox('some html', 'my-groovy-style')
33
+ *
34
+ * The above will open a facebox with "some html" as the content.
35
+ *
36
+ * jQuery.facebox(function($) {
37
+ * $.get('blah.html', function(data) { $.facebox(data) })
38
+ * })
39
+ *
40
+ * The above will show a loading screen before the passed function is called,
41
+ * allowing for a better ajaxy experience.
42
+ *
43
+ * The facebox function can also display an ajax page, an image, or the contents of a div:
44
+ *
45
+ * jQuery.facebox({ ajax: 'remote.html' })
46
+ * jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
47
+ * jQuery.facebox({ image: 'stairs.jpg' })
48
+ * jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
49
+ * jQuery.facebox({ div: '#box' })
50
+ * jQuery.facebox({ div: '#box' }, 'my-groovy-style')
51
+ *
52
+ * Want to close the facebox? Trigger the 'close.facebox' document event:
53
+ *
54
+ * jQuery(document).trigger('close.facebox')
55
+ *
56
+ * Facebox also has a bunch of other hooks:
57
+ *
58
+ * loading.facebox
59
+ * beforeReveal.facebox
60
+ * reveal.facebox (aliased as 'afterReveal.facebox')
61
+ * init.facebox
62
+ *
63
+ * Simply bind a function to any of these hooks:
64
+ *
65
+ * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
66
+ *
67
+ */
68
+ (function($) {
69
+ $.facebox = function(data, klass) {
70
+ $.facebox.loading()
71
+
72
+ if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
73
+ else if (data.image) fillFaceboxFromImage(data.image, klass)
74
+ else if (data.div) fillFaceboxFromHref(data.div, klass)
75
+ else if ($.isFunction(data)) data.call($)
76
+ else $.facebox.reveal(data, klass)
77
+ }
78
+
79
+ /*
80
+ * Public, $.facebox methods
81
+ */
82
+
83
+ $.extend($.facebox, {
84
+ //possible option: noAutoload --- will build facebox only when it is needed
85
+ settings: {
86
+ opacity : 0,
87
+ overlay : true,
88
+ imagePath : '/images/facebox/',
89
+ loadingImage : 'loading.gif',
90
+ closeImage : 'closelabel.gif',
91
+ imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ]
92
+ },
93
+
94
+ html : function(){
95
+ return '\
96
+ <div id="facebox" style="display:none;"> \
97
+ <div class="popup"> \
98
+ <table> \
99
+ <tbody> \
100
+ <tr> \
101
+ <td class="tl"/><td class="b"/><td class="tr"/> \
102
+ </tr> \
103
+ <tr> \
104
+ <td class="b"/> \
105
+ <td class="body"> \
106
+ <div class="content"> \
107
+ </div> \
108
+ <div class="footer"> \
109
+ <a href="#" class="close"> \
110
+ <img src="'+$.facebox.settings.imagePath+$.facebox.settings.closeImage+'" title="close" class="close_image" /> \
111
+ </a> \
112
+ </div> \
113
+ </td> \
114
+ <td class="b"/> \
115
+ </tr> \
116
+ <tr> \
117
+ <td class="bl"/><td class="b"/><td class="br"/> \
118
+ </tr> \
119
+ </tbody> \
120
+ </table> \
121
+ </div> \
122
+ </div>'
123
+ },
124
+
125
+ loading: function() {
126
+ init()
127
+ var $f = $('#facebox')
128
+ if ($f.find('.loading').length == 1) return true
129
+ showOverlay()
130
+
131
+ $f.find('.content').empty()
132
+ $f.find('.body').children().hide().end().
133
+ append('<div class="loading"><img src="'+$.facebox.settings.imagePath+$.facebox.settings.loadingImage+'"/></div>')
134
+
135
+ $f.css({
136
+ top: getPageScroll()[1] + (getPageHeight() / 10),
137
+ left: $(window).width() / 2 - 205
138
+ }).show()
139
+
140
+ $(document).bind('keydown.facebox', function(e) {
141
+ if (e.keyCode == 27) $.facebox.close()
142
+ return true
143
+ })
144
+ $(document).trigger('loading.facebox')
145
+ },
146
+
147
+ reveal: function(data, klass) {
148
+ $(document).trigger('beforeReveal.facebox')
149
+ var $f = $('#facebox')
150
+ if (klass) $('#facebox .content').addClass(klass)
151
+ $f.find('.content').append(data)
152
+ $f.find('.loading').remove()
153
+ $f.find('.body').children().fadeIn('normal')
154
+ $f.css('left', $(window).width() / 2 - ($('#facebox table').width() / 2))
155
+ $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
156
+ },
157
+
158
+ close: function() {
159
+ $(document).trigger('close.facebox')
160
+ return false
161
+ }
162
+ })
163
+
164
+ /*
165
+ * Public, $.fn methods
166
+ */
167
+
168
+ $.fn.facebox = function(settings) {
169
+ merge_settings(settings)
170
+ if(!settings.noAutoload)init()
171
+
172
+ return this.bind('click.facebox',function(){
173
+ $.facebox.loading()
174
+
175
+ // support for rel="facebox.inline_popup" syntax, to add a class
176
+ // also supports deprecated "facebox[.inline_popup]" syntax
177
+ var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
178
+ if (klass) klass = klass[1]
179
+
180
+ fillFaceboxFromHref(this.href, klass)
181
+ return false
182
+ })
183
+ }
184
+
185
+ /*
186
+ * Private methods
187
+ */
188
+
189
+ function merge_settings(settings){
190
+ $.extend($.facebox.settings, settings)
191
+ }
192
+
193
+ // called one time to setup facebox on this page
194
+ function init() {
195
+ if ($.facebox.settings.inited) return
196
+ else $.facebox.settings.inited = true
197
+
198
+ $(document).trigger('init.facebox')
199
+ makeCompatible()
200
+
201
+ var imageTypes = $.facebox.settings.imageTypes.join('|')
202
+ $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')$', 'i')
203
+
204
+ $('body').append($.facebox.html())
205
+ if(! $.facebox.settings.noAutoload)preloadImages()
206
+ $('#facebox .close').click($.facebox.close)
207
+ }
208
+
209
+ function preloadImages(){
210
+ var preload = [ new Image(), new Image() ]
211
+ var path = $.facebox.settings.imagePath
212
+ preload[0].src = path + $.facebox.settings.closeImage
213
+ preload[1].src = path + $.facebox.settings.loadingImage
214
+
215
+ $('#facebox').find('.b:first, .bl, .br, .tl, .tr').each(function() {
216
+ preload.push(new Image())
217
+ preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
218
+ })
219
+ }
220
+
221
+ // getPageScroll() by quirksmode.com
222
+ function getPageScroll() {
223
+ var xScroll, yScroll;
224
+ if (self.pageYOffset) {
225
+ yScroll = self.pageYOffset;
226
+ xScroll = self.pageXOffset;
227
+ } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
228
+ yScroll = document.documentElement.scrollTop;
229
+ xScroll = document.documentElement.scrollLeft;
230
+ } else if (document.body) {// all other Explorers
231
+ yScroll = document.body.scrollTop;
232
+ xScroll = document.body.scrollLeft;
233
+ }
234
+ return new Array(xScroll,yScroll)
235
+ }
236
+
237
+ // Adapted from getPageSize() by quirksmode.com
238
+ function getPageHeight() {
239
+ var windowHeight
240
+ if (self.innerHeight) { // all except Explorer
241
+ windowHeight = self.innerHeight;
242
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
243
+ windowHeight = document.documentElement.clientHeight;
244
+ } else if (document.body) { // other Explorers
245
+ windowHeight = document.body.clientHeight;
246
+ }
247
+ return windowHeight
248
+ }
249
+
250
+ // Backwards compatibility
251
+ function makeCompatible() {
252
+ var $s = $.facebox.settings
253
+
254
+ $s.loadingImage = $s.loading_image || $s.loadingImage
255
+ $s.closeImage = $s.close_image || $s.closeImage
256
+ $s.imageTypes = $s.image_types || $s.imageTypes
257
+ $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
258
+ }
259
+
260
+ // Figures out what you want to display and displays it
261
+ // formats are:
262
+ // div: #id
263
+ // image: blah.extension
264
+ // ajax: anything else
265
+ function fillFaceboxFromHref(href, klass) {
266
+ // div
267
+ if (href.match(/#/)) {
268
+ var url = window.location.href.split('#')[0]
269
+ var target = href.replace(url,'')
270
+ $.facebox.reveal($(target).show().replaceWith("<div id='facebox_moved'></div>"), klass)
271
+
272
+ // image
273
+ } else if (href.match($.facebox.settings.imageTypesRegexp)) {
274
+ fillFaceboxFromImage(href, klass)
275
+ // ajax
276
+ } else {
277
+ fillFaceboxFromAjax(href, klass)
278
+ }
279
+ }
280
+
281
+ function fillFaceboxFromImage(href, klass) {
282
+ var image = new Image()
283
+ image.onload = function() {
284
+ $.facebox.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
285
+ }
286
+ image.src = href
287
+ }
288
+
289
+ function fillFaceboxFromAjax(href, klass) {
290
+ $.get(href, function(data) { $.facebox.reveal(data, klass) })
291
+ }
292
+
293
+ function skipOverlay() {
294
+ return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null
295
+ }
296
+
297
+ function showOverlay() {
298
+ if (skipOverlay()) return
299
+
300
+ if ($('#facebox_overlay').length == 0)
301
+ $("body").append('<div id="facebox_overlay" class="facebox_hide"></div>')
302
+
303
+ $('#facebox_overlay').hide().addClass("facebox_overlayBG")
304
+ .css('opacity', $.facebox.settings.opacity)
305
+ .click(function() { $(document).trigger('close.facebox') })
306
+ .fadeIn(200)
307
+ return false
308
+ }
309
+
310
+ function hideOverlay() {
311
+ if (skipOverlay()) return
312
+
313
+ $('#facebox_overlay').fadeOut(200, function(){
314
+ $("#facebox_overlay").removeClass("facebox_overlayBG").
315
+ addClass("facebox_hide").
316
+ remove()
317
+ })
318
+
319
+ return false
320
+ }
321
+
322
+ /*
323
+ * Bindings
324
+ */
325
+
326
+ $(document).bind('close.facebox', function() {
327
+ $(document).unbind('keydown.facebox')
328
+ $('#facebox').fadeOut(function() {
329
+ if ($('#facebox_moved').length == 0) $('#facebox .content').removeClass().addClass('content')
330
+ else $('#facebox_moved').replaceWith($('#facebox .content').children().hide())
331
+ hideOverlay()
332
+ $('#facebox .loading').remove()
333
+ })
334
+ })
335
+
336
+ })(jQuery);
Binary file
Binary file
@@ -0,0 +1,33 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+ files = File.join(File.dirname(__FILE__),'files')
3
+
4
+ def cleanup(files)
5
+ Dir[files+'/*.min.*', files+'/*.temp'].each{|f| FileUtils.rm(f)}
6
+ end
7
+
8
+ describe Reduce do
9
+ after(:all){ cleanup(files) }
10
+
11
+ cleanup(files)
12
+ Dir[files+'/*.*'].each do |file|
13
+ extension = File.extname(file)
14
+ it "reduces #{File.extname(file)} and returns the content" do
15
+ data = Reduce.reduce(file)
16
+ data.length.should < File.size(file)
17
+ end
18
+ end
19
+
20
+ it "uses PunyPng for gifs" do
21
+ Smusher.should_receive(:optimize_image).with(anything, hash_including(:service => 'PunyPng'))
22
+ Reduce.reduce(File.join(files, 'test.gif'))
23
+ end
24
+
25
+ it "uses SmushIt for other images" do
26
+ Smusher.should_receive(:optimize_image).with(anything, hash_including(:service => 'SmushIt'))
27
+ Reduce.reduce(File.join(files, 'paintcan.png'))
28
+ end
29
+
30
+ it "has a VERSION" do
31
+ Reduce::VERSION.should =~ /^\d+\.\d+\.\d+$/
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ # ---- requirements
2
+ require 'rubygems'
3
+
4
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
5
+ require 'reduce'
6
+
7
+ # ---- bugfix
8
+ #`exit?': undefined method `run?' for Test::Unit:Module (NoMethodError)
9
+ #can be solved with require test/unit but this will result in extra test-output
10
+ module Test
11
+ module Unit
12
+ def self.run?
13
+ true
14
+ end
15
+ end
16
+ end
17
+
18
+ # ---- Helpers
19
+ def pending_it(text,&block)
20
+ it text do
21
+ pending(&block)
22
+ end
23
+ end
data/vendor/README ADDED
@@ -0,0 +1,135 @@
1
+ ==============================================================================
2
+ YUI Compressor
3
+ ==============================================================================
4
+
5
+ NAME
6
+
7
+ YUI Compressor - The Yahoo! JavaScript and CSS Compressor
8
+
9
+ SYNOPSIS
10
+
11
+ Usage: java -jar yuicompressor-x.y.z.jar [options] [input file]
12
+
13
+ Global Options
14
+ -h, --help Displays this information
15
+ --type <js|css> Specifies the type of the input file
16
+ --charset <charset> Read the input file using <charset>
17
+ --line-break <column> Insert a line break after the specified column number
18
+ -v, --verbose Display informational messages and warnings
19
+ -o <file> Place the output into <file>. Defaults to stdout.
20
+
21
+ JavaScript Options
22
+ --nomunge Minify only, do not obfuscate
23
+ --preserve-semi Preserve all semicolons
24
+ --disable-optimizations Disable all micro optimizations
25
+
26
+ DESCRIPTION
27
+
28
+ The YUI Compressor is a JavaScript compressor which, in addition to removing
29
+ comments and white-spaces, obfuscates local variables using the smallest
30
+ possible variable name. This obfuscation is safe, even when using constructs
31
+ such as 'eval' or 'with' (although the compression is not optimal is those
32
+ cases) Compared to jsmin, the average savings is around 20%.
33
+
34
+ The YUI Compressor is also able to safely compress CSS files. The decision
35
+ on which compressor is being used is made on the file extension (js or css)
36
+
37
+ GLOBAL OPTIONS
38
+
39
+ -h, --help
40
+ Prints help on how to use the YUI Compressor
41
+
42
+ --line-break
43
+ Some source control tools don't like files containing lines longer than,
44
+ say 8000 characters. The linebreak option is used in that case to split
45
+ long lines after a specific column. It can also be used to make the code
46
+ more readable, easier to debug (especially with the MS Script Debugger)
47
+ Specify 0 to get a line break after each semi-colon in JavaScript, and
48
+ after each rule in CSS.
49
+
50
+ --type js|css
51
+ The type of compressor (JavaScript or CSS) is chosen based on the
52
+ extension of the input file name (.js or .css) This option is required
53
+ if no input file has been specified. Otherwise, this option is only
54
+ required if the input file extension is neither 'js' nor 'css'.
55
+
56
+ --charset character-set
57
+ If a supported character set is specified, the YUI Compressor will use it
58
+ to read the input file. Otherwise, it will assume that the platform's
59
+ default character set is being used. The output file is encoded using
60
+ the same character set.
61
+
62
+ -o outfile
63
+ Place output in file outfile. If not specified, the YUI Compressor will
64
+ default to the standard output, which you can redirect to a file.
65
+
66
+ -v, --verbose
67
+ Display informational messages and warnings.
68
+
69
+ JAVASCRIPT ONLY OPTIONS
70
+
71
+ --nomunge
72
+ Minify only. Do not obfuscate local symbols.
73
+
74
+ --preserve-semi
75
+ Preserve unnecessary semicolons (such as right before a '}') This option
76
+ is useful when compressed code has to be run through JSLint (which is the
77
+ case of YUI for example)
78
+
79
+ --disable-optimizations
80
+ Disable all the built-in micro optimizations.
81
+
82
+ NOTES
83
+
84
+ + If no input file is specified, it defaults to stdin.
85
+
86
+ + The YUI Compressor requires Java version >= 1.4.
87
+
88
+ + It is possible to prevent a local variable, nested function or function
89
+ argument from being obfuscated by using "hints". A hint is a string that
90
+ is located at the very beginning of a function body like so:
91
+
92
+ function fn (arg1, arg2, arg3) {
93
+ "arg2:nomunge, localVar:nomunge, nestedFn:nomunge";
94
+
95
+ ...
96
+ var localVar;
97
+ ...
98
+
99
+ function nestedFn () {
100
+ ....
101
+ }
102
+
103
+ ...
104
+ }
105
+
106
+ The hint itself disappears from the compressed file.
107
+
108
+ + C-style comments starting with /*! are preserved. This is useful with
109
+ comments containing copyright/license information. For example:
110
+
111
+ /*!
112
+ * TERMS OF USE - EASING EQUATIONS
113
+ * Open source under the BSD License.
114
+ * Copyright 2001 Robert Penner All rights reserved.
115
+ */
116
+
117
+ becomes:
118
+
119
+ /*
120
+ * TERMS OF USE - EASING EQUATIONS
121
+ * Open source under the BSD License.
122
+ * Copyright 2001 Robert Penner All rights reserved.
123
+ */
124
+
125
+ AUTHOR
126
+
127
+ The YUI Compressor was written and is maintained by:
128
+ Julien Lecomte <jlecomte@yahoo-inc.com>
129
+ The CSS portion is a port of Isaac Schlueter's cssmin utility.
130
+
131
+ COPYRIGHT
132
+
133
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
134
+ Code licensed under the BSD License:
135
+ http://developer.yahoo.net/yui/license.txt
Binary file
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reduce
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-22 00:00:00 +01:00
13
+ default_executable: reduce
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: smusher
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: grosser.michael@gmail.com
27
+ executables:
28
+ - reduce
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.markdown
33
+ files:
34
+ - .gitignore
35
+ - README.markdown
36
+ - Rakefile
37
+ - VERSION
38
+ - bin/reduce
39
+ - lib/reduce.rb
40
+ - reduce.gemspec
41
+ - spec/files/facebox.css
42
+ - spec/files/facebox.js
43
+ - spec/files/paintcan.png
44
+ - spec/files/test.gif
45
+ - spec/reduce_spec.rb
46
+ - spec/spec_helper.rb
47
+ - vendor/README
48
+ - vendor/yuicompressor-2.4.2.jar
49
+ has_rdoc: true
50
+ homepage: http://github.com/grosser/reduce
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: "Reduce your assets: minify javascript + stylesheets, optimize images lossless"
77
+ test_files:
78
+ - spec/spec_helper.rb
79
+ - spec/reduce_spec.rb