crush 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -3
- data/LICENSE +20 -0
- data/README.md +42 -0
- data/Rakefile +5 -0
- data/crush.gemspec +9 -0
- data/lib/crush.rb +77 -0
- data/lib/crush/closure.rb +21 -0
- data/lib/crush/cssmin.rb +15 -0
- data/lib/crush/engine.rb +89 -0
- data/lib/crush/jsmin.rb +15 -0
- data/lib/crush/packr.rb +15 -0
- data/lib/crush/rainpress.rb +15 -0
- data/lib/crush/uglifier.rb +19 -0
- data/lib/crush/version.rb +1 -1
- data/lib/crush/yui.rb +39 -0
- data/spec/crush/closure_spec.rb +22 -0
- data/spec/crush/cssmin_spec.rb +13 -0
- data/spec/crush/engine_spec.rb +104 -0
- data/spec/crush/jsmin_spec.rb +13 -0
- data/spec/crush/packr_spec.rb +18 -0
- data/spec/crush/rainpress_spec.rb +18 -0
- data/spec/crush/uglifier_spec.rb +22 -0
- data/spec/crush/yui_spec.rb +42 -0
- data/spec/crush_spec.rb +101 -0
- data/spec/spec_helper.rb +7 -0
- metadata +123 -18
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Peter Browne
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Crush
|
2
|
+
=====
|
3
|
+
|
4
|
+
Crush is a generic interface, like Tilt, for the various compression engines in Ruby.
|
5
|
+
It is useful for asset libraries that support multiple javascript and stylesheet compression engines.
|
6
|
+
|
7
|
+
Basic Usage
|
8
|
+
-----------
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require "uglifier"
|
12
|
+
require "crush"
|
13
|
+
Crush.new("application.js").compress
|
14
|
+
```
|
15
|
+
|
16
|
+
This would automatically compress the data found in the `application.js` file using Uglifier.
|
17
|
+
Crush favors engines whose libraries have already been loaded.
|
18
|
+
|
19
|
+
If you have multiple compression libraries loaded, and you want to control which one to use,
|
20
|
+
you can initialize the engine directly.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require "uglifier"
|
24
|
+
require "jsmin"
|
25
|
+
require "crush"
|
26
|
+
Crush::Uglifier.new("application.js").compress
|
27
|
+
```
|
28
|
+
|
29
|
+
Or you could use `Crush.prefer` to tell Crush which engine you'd like to use.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require "uglifier"
|
33
|
+
require "jsmin"
|
34
|
+
require "crush"
|
35
|
+
Crush.prefer(Crush::Uglifier)
|
36
|
+
Crush.new("application.js").compress
|
37
|
+
```
|
38
|
+
|
39
|
+
Copyright
|
40
|
+
---------
|
41
|
+
|
42
|
+
Copyright (c) 2011 [Peter Browne](http://petebrowne.com). See LICENSE for details.
|
data/Rakefile
CHANGED
data/crush.gemspec
CHANGED
@@ -12,6 +12,15 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = "Crush is a generic interface, like Tilt, for the various compression engines in Ruby."
|
13
13
|
|
14
14
|
s.rubyforge_project = "crush"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec", "~> 2.6.0"
|
17
|
+
s.add_development_dependency "jsmin"
|
18
|
+
s.add_development_dependency "packr"
|
19
|
+
s.add_development_dependency "uglifier"
|
20
|
+
s.add_development_dependency "closure-compiler"
|
21
|
+
s.add_development_dependency "yui-compressor"
|
22
|
+
s.add_development_dependency "cssmin"
|
23
|
+
s.add_development_dependency "rainpress"
|
15
24
|
|
16
25
|
s.files = `git ls-files`.split("\n")
|
17
26
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/crush.rb
CHANGED
@@ -1,2 +1,79 @@
|
|
1
1
|
module Crush
|
2
|
+
autoload :Closure, "crush/closure"
|
3
|
+
autoload :CSSMin, "crush/cssmin"
|
4
|
+
autoload :Engine, "crush/engine"
|
5
|
+
autoload :JSMin, "crush/jsmin"
|
6
|
+
autoload :Packr, "crush/packr"
|
7
|
+
autoload :Rainpress, "crush/rainpress"
|
8
|
+
autoload :Uglifier, "crush/uglifier"
|
9
|
+
autoload :YUI, "crush/yui"
|
10
|
+
|
11
|
+
class EngineNotFound < StandardError; end
|
12
|
+
|
13
|
+
# Hash of registered compression engines.
|
14
|
+
def self.mappings
|
15
|
+
@mappings ||= Hash.new { |h, k| h[k] = [] }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Ensures the extension doesn't include the "."
|
19
|
+
def self.normalize(ext)
|
20
|
+
ext.to_s.downcase.sub /^\./, ""
|
21
|
+
end
|
22
|
+
|
23
|
+
# Registers a compression engine for the given file extension(s).
|
24
|
+
def self.register(engine, *extensions)
|
25
|
+
extensions.each do |ext|
|
26
|
+
ext = normalize(ext)
|
27
|
+
mappings[ext].unshift(engine).uniq!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns true when an engine exists for the given file extension.
|
32
|
+
def self.registered?(ext)
|
33
|
+
ext = normalize(ext)
|
34
|
+
mappings.key?(ext) && !mappings[ext].empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Make the given compression engine preferred. Which means,
|
38
|
+
# it will reordered the beginning of its mapping.
|
39
|
+
def self.prefer(engine)
|
40
|
+
mappings.each do |ext, engines|
|
41
|
+
if engines.include?(engine)
|
42
|
+
engines.delete(engine)
|
43
|
+
engines.unshift(engine)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Look for a compression engine for the given filename or file
|
49
|
+
# extension. Return nil when no engine is found.
|
50
|
+
def self.[](path)
|
51
|
+
pattern = File.basename(path.to_s).downcase
|
52
|
+
until pattern.empty? || registered?(pattern)
|
53
|
+
pattern.sub! /^[^.]*\.?/, ""
|
54
|
+
end
|
55
|
+
|
56
|
+
pattern = normalize(pattern)
|
57
|
+
mappings[pattern].detect(&:engine_initialized?) || mappings[pattern].first
|
58
|
+
end
|
59
|
+
|
60
|
+
# Create a new compression engine for the given file using the file's extension
|
61
|
+
# to determine the the engine mapping.
|
62
|
+
def self.new(path, options = {}, &block)
|
63
|
+
if engine = self[path]
|
64
|
+
engine.new path, options, &block
|
65
|
+
else
|
66
|
+
raise EngineNotFound.new("No compression engine registered for '#{path}'")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
register Crush::JSMin, "js", "min.js"
|
71
|
+
register Crush::Packr, "js", "pack.js"
|
72
|
+
register Crush::YUI::JavaScriptCompressor, "js", "yui.js"
|
73
|
+
register Crush::Closure::Compiler, "js", "closure.js"
|
74
|
+
register Crush::Uglifier, "js", "ugly.js"
|
75
|
+
|
76
|
+
register Crush::CSSMin, "css", "min.css"
|
77
|
+
register Crush::Rainpress, "css", "rain.css"
|
78
|
+
register Crush::YUI::CssCompressor, "css", "yui.css"
|
2
79
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Crush
|
2
|
+
module Closure
|
3
|
+
class Compiler < Crush::Engine
|
4
|
+
def self.engine_initialized?
|
5
|
+
!!(defined? ::Closure) && !!(defined? ::Closure::Compiler)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize_engine
|
9
|
+
require_template_library "closure-compiler"
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
@engine = ::Closure::Compiler.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate
|
17
|
+
@engine.compile(data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/crush/cssmin.rb
ADDED
data/lib/crush/engine.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module Crush
|
2
|
+
class Engine
|
3
|
+
# The name of the file to be compressed
|
4
|
+
attr_reader :file
|
5
|
+
|
6
|
+
# A Hash of compression engine specific options. This is passed directly
|
7
|
+
# to the underlying engine and is not used by the generic interface.
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
# The data to cmopress; loaded from a file or given directly.
|
11
|
+
attr_reader :data
|
12
|
+
|
13
|
+
# Used to determine if this class's initialize_engine method has
|
14
|
+
# been called yet.
|
15
|
+
@engine_initialized = false
|
16
|
+
class << self
|
17
|
+
attr_accessor :engine_initialized
|
18
|
+
alias :engine_initialized? :engine_initialized
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create a new engine with the file and options specified. By
|
22
|
+
# default, the data to compress is read from the file. When a block is given,
|
23
|
+
# it should read data and return as a String.
|
24
|
+
#
|
25
|
+
# All arguments are optional.
|
26
|
+
def initialize(file = nil, options = nil)
|
27
|
+
if file.respond_to?(:to_hash)
|
28
|
+
@options = file.to_hash
|
29
|
+
else
|
30
|
+
@file = file
|
31
|
+
@options = options || {}
|
32
|
+
end
|
33
|
+
|
34
|
+
unless self.class.engine_initialized?
|
35
|
+
initialize_engine
|
36
|
+
self.class.engine_initialized = true
|
37
|
+
end
|
38
|
+
|
39
|
+
@data = if block_given?
|
40
|
+
yield
|
41
|
+
elsif @file
|
42
|
+
File.respond_to?(:binread) ? File.binread(@file) : File.read(@file)
|
43
|
+
end
|
44
|
+
|
45
|
+
prepare
|
46
|
+
end
|
47
|
+
|
48
|
+
# Compresses the data. Data can be read through the file or the block
|
49
|
+
# given at initialization, or through passing it here directly.
|
50
|
+
def render(data = nil)
|
51
|
+
@data = data unless data.nil?
|
52
|
+
evaluate
|
53
|
+
end
|
54
|
+
alias :compress :render
|
55
|
+
alias :compile :render
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
# Called once and only once for each template subclass the first time
|
60
|
+
# the engine class is initialized. This should be used to require the
|
61
|
+
# underlying engine library and perform any initial setup.
|
62
|
+
def initialize_engine
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Do whatever preparation is necessary to setup the underlying compression
|
67
|
+
# engine. Called immediately after template data is loaded. Instance
|
68
|
+
# variables set in this method are available when #compress is called.
|
69
|
+
def prepare
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# Called when it's time to compress. Return the compressed data
|
74
|
+
# from this method.
|
75
|
+
def evaluate
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
# Like Kernel::require but issues a warning urging a manual require when
|
80
|
+
# running under a threaded environment.
|
81
|
+
def require_template_library(name)
|
82
|
+
if Thread.list.size > 1
|
83
|
+
warn "WARN: crush autoloading '#{name}' in a non thread-safe way; " +
|
84
|
+
"explicit require '#{name}' suggested."
|
85
|
+
end
|
86
|
+
require name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/crush/jsmin.rb
ADDED
data/lib/crush/packr.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Crush
|
2
|
+
class Rainpress < Engine
|
3
|
+
def self.engine_initialized?
|
4
|
+
!!(defined? ::Rainpress)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize_engine
|
8
|
+
require_template_library "rainpress"
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate
|
12
|
+
::Rainpress.compress(data, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Crush
|
2
|
+
class Uglifier < Engine
|
3
|
+
def self.engine_initialized?
|
4
|
+
!!(defined? ::Uglifier)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize_engine
|
8
|
+
require_template_library "uglifier"
|
9
|
+
end
|
10
|
+
|
11
|
+
def prepare
|
12
|
+
@engine = ::Uglifier.new(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate
|
16
|
+
@engine.compile(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/crush/version.rb
CHANGED
data/lib/crush/yui.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Crush
|
2
|
+
module YUI
|
3
|
+
class JavaScriptCompressor < Crush::Engine
|
4
|
+
def self.engine_initialized?
|
5
|
+
!!(defined? ::YUI) && !!(defined? ::YUI::JavaScriptCompressor)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize_engine
|
9
|
+
require_template_library "yui/compressor"
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare
|
13
|
+
@engine = ::YUI::JavaScriptCompressor.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate
|
17
|
+
@engine.compress(data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class CssCompressor < Crush::Engine
|
22
|
+
def self.engine_initialized?
|
23
|
+
!!(defined? ::YUI) && !!(defined? ::YUI::CssCompressor)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize_engine
|
27
|
+
require_template_library "yui/compressor"
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare
|
31
|
+
@engine = ::YUI::CssCompressor.new(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def evaluate
|
35
|
+
@engine.compress(data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "closure-compiler"
|
3
|
+
|
4
|
+
describe Crush::Closure::Compiler do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["js"].should include(Crush::Closure::Compiler)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using Closure::Compiler" do
|
10
|
+
compressor = mock(:compressor)
|
11
|
+
::Closure::Compiler.should_receive(:new).with({}).and_return(compressor)
|
12
|
+
compressor.should_receive(:compile).with("hello").and_return("world")
|
13
|
+
Crush::Closure::Compiler.new.compress("hello").should == "world"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sends options to Closure::Compiler" do
|
17
|
+
compressor = mock(:compressor)
|
18
|
+
::Closure::Compiler.should_receive(:new).with(:foo => "bar").and_return(compressor)
|
19
|
+
compressor.should_receive(:compile).with("hello").and_return("world")
|
20
|
+
Crush::Closure::Compiler.new(:foo => "bar").compress("hello")
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "cssmin"
|
3
|
+
|
4
|
+
describe Crush::CSSMin do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["css"].should include(Crush::CSSMin)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using CSSMin" do
|
10
|
+
::CSSMin.should_receive(:minify).with("hello").and_return("world")
|
11
|
+
Crush::CSSMin.new.compress("hello").should == "world"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Crush::Engine do
|
4
|
+
class MockEngine < Crush::Engine
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "#file" do
|
8
|
+
it "returns the file the engine was initialized with" do
|
9
|
+
engine = MockEngine.new("application.js") {}
|
10
|
+
engine.file.should == "application.js"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#options" do
|
15
|
+
it "returns the options passed to the engine" do
|
16
|
+
engine = MockEngine.new(nil, :foo => "bar") {}
|
17
|
+
engine.options[:foo].should == "bar"
|
18
|
+
engine = MockEngine.new(:bar => "foo") {}
|
19
|
+
engine.options[:bar].should == "foo"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#data" do
|
24
|
+
it "returns the data from the file" do
|
25
|
+
File.stub(:binread => "Hello", :read => "Hello")
|
26
|
+
engine = MockEngine.new("application.js")
|
27
|
+
engine.data.should == "Hello"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the data from the given block" do
|
31
|
+
engine = MockEngine.new("application.js") { "Hello" }
|
32
|
+
engine.data.should == "Hello"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class InitializingMockEngine < Crush::Engine
|
37
|
+
class << self
|
38
|
+
attr_accessor :initialized_count
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_engine
|
42
|
+
self.class.initialized_count += 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#initialize_engine" do
|
47
|
+
it "is called one time to require the library" do
|
48
|
+
InitializingMockEngine.initialized_count = 0
|
49
|
+
InitializingMockEngine.new
|
50
|
+
InitializingMockEngine.initialized_count.should == 1
|
51
|
+
InitializingMockEngine.new
|
52
|
+
InitializingMockEngine.initialized_count.should == 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class InitializedMockEngine < Crush::Engine
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ".engine_initialized?" do
|
60
|
+
it "returns false before the engine has been initialized" do
|
61
|
+
InitializedMockEngine.engine_initialized?.should be_false
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns true once the engine has been initialized" do
|
65
|
+
InitializedMockEngine.new
|
66
|
+
InitializedMockEngine.engine_initialized?.should be_true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class PreparingMockEngine < Crush::Engine
|
71
|
+
class << self
|
72
|
+
attr_accessor :prepared_count
|
73
|
+
end
|
74
|
+
|
75
|
+
def prepare
|
76
|
+
self.class.prepared_count += 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#prepare" do
|
81
|
+
it "is called each time an engine is created" do
|
82
|
+
PreparingMockEngine.prepared_count = 0
|
83
|
+
PreparingMockEngine.new
|
84
|
+
PreparingMockEngine.prepared_count.should == 1
|
85
|
+
PreparingMockEngine.new
|
86
|
+
PreparingMockEngine.prepared_count.should == 2
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class SimpleMockEngine < Crush::Engine
|
91
|
+
def evaluate
|
92
|
+
@data.strip
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#compress" do
|
97
|
+
it "compresses the data using the engine" do
|
98
|
+
File.stub(:binread => " hello ", :read => " hello ")
|
99
|
+
SimpleMockEngine.new("file.txt").compile.should == "hello"
|
100
|
+
SimpleMockEngine.new { " hello " }.render.should == "hello"
|
101
|
+
SimpleMockEngine.new.compress(" hello ").should == "hello"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "jsmin"
|
3
|
+
|
4
|
+
describe Crush::JSMin do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["js"].should include(Crush::JSMin)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using JSMin" do
|
10
|
+
::JSMin.should_receive(:minify).with("hello").and_return("world")
|
11
|
+
Crush::JSMin.new.compress("hello").should == "world"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "packr"
|
3
|
+
|
4
|
+
describe Crush::Packr do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["js"].should include(Crush::Packr)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using Packr" do
|
10
|
+
::Packr.should_receive(:pack).with("hello", {}).and_return("world")
|
11
|
+
Crush::Packr.new.compress("hello").should == "world"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "sends options to Packr" do
|
15
|
+
::Packr.should_receive(:pack).with("hello", :foo => "bar")
|
16
|
+
Crush::Packr.new(:foo => "bar").compress("hello")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rainpress"
|
3
|
+
|
4
|
+
describe Crush::Rainpress do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["css"].should include(Crush::Rainpress)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using Rainpress" do
|
10
|
+
::Rainpress.should_receive(:compress).with("hello", {}).and_return("world")
|
11
|
+
Crush::Rainpress.new.compress("hello").should == "world"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "sends options to Rainpress" do
|
15
|
+
::Rainpress.should_receive(:compress).with("hello", :foo => "bar")
|
16
|
+
Crush::Rainpress.new(:foo => "bar").compress("hello")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "uglifier"
|
3
|
+
|
4
|
+
describe Crush::Uglifier do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["js"].should include(Crush::Uglifier)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using Uglifier" do
|
10
|
+
compressor = mock(:compressor)
|
11
|
+
::Uglifier.should_receive(:new).with({}).and_return(compressor)
|
12
|
+
compressor.should_receive(:compile).with("hello").and_return("world")
|
13
|
+
Crush::Uglifier.new.compress("hello").should == "world"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sends options to Uglifier" do
|
17
|
+
compressor = mock(:compressor)
|
18
|
+
::Uglifier.should_receive(:new).with(:foo => "bar").and_return(compressor)
|
19
|
+
compressor.should_receive(:compile).with("hello").and_return("world")
|
20
|
+
Crush::Uglifier.new(:foo => "bar").compress("hello")
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "yui/compressor"
|
3
|
+
|
4
|
+
describe Crush::YUI::JavaScriptCompressor do
|
5
|
+
it "is registered for '.js' files" do
|
6
|
+
Crush.mappings["js"].should include(Crush::YUI::JavaScriptCompressor)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "minifies using YUI::JavaScriptCompressor" do
|
10
|
+
compressor = mock(:compressor)
|
11
|
+
::YUI::JavaScriptCompressor.should_receive(:new).with({}).and_return(compressor)
|
12
|
+
compressor.should_receive(:compress).with("hello").and_return("world")
|
13
|
+
Crush::YUI::JavaScriptCompressor.new.compress("hello").should == "world"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sends options to YUI::JavaScriptCompressor" do
|
17
|
+
compressor = mock(:compressor)
|
18
|
+
::YUI::JavaScriptCompressor.should_receive(:new).with(:foo => "bar").and_return(compressor)
|
19
|
+
compressor.should_receive(:compress).with("hello").and_return("world")
|
20
|
+
Crush::YUI::JavaScriptCompressor.new(:foo => "bar").compress("hello")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Crush::YUI::CssCompressor do
|
25
|
+
it "is registered for '.js' files" do
|
26
|
+
Crush.mappings["css"].should include(Crush::YUI::CssCompressor)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "minifies using YUI::CssCompressor" do
|
30
|
+
compressor = mock(:compressor)
|
31
|
+
::YUI::CssCompressor.should_receive(:new).with({}).and_return(compressor)
|
32
|
+
compressor.should_receive(:compress).with("hello").and_return("world")
|
33
|
+
Crush::YUI::CssCompressor.new.compress("hello").should == "world"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sends options to YUI::CssCompressor" do
|
37
|
+
compressor = mock(:compressor)
|
38
|
+
::YUI::CssCompressor.should_receive(:new).with(:foo => "bar").and_return(compressor)
|
39
|
+
compressor.should_receive(:compress).with("hello").and_return("world")
|
40
|
+
Crush::YUI::CssCompressor.new(:foo => "bar").compress("hello")
|
41
|
+
end
|
42
|
+
end
|
data/spec/crush_spec.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Crush do
|
4
|
+
class MockCompressor
|
5
|
+
def self.engine_initialized?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :args, :block
|
10
|
+
def initialize(*args, &block)
|
11
|
+
@args = args
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class MockCompressor2 < MockCompressor
|
17
|
+
def self.engine_initialized?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
before(:all) do
|
23
|
+
Crush.register(MockCompressor, "mock", ".mck", "file.txt")
|
24
|
+
Crush.register(MockCompressor, "mult")
|
25
|
+
Crush.register(MockCompressor2, "mult")
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".mappings" do
|
29
|
+
it "always returns an array" do
|
30
|
+
Crush.mappings["none"].should == []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe ".register" do
|
35
|
+
it "stores engines" do
|
36
|
+
Crush.mappings["mock"].should include(MockCompressor)
|
37
|
+
Crush.mappings["mck"].should include(MockCompressor)
|
38
|
+
Crush.mappings["file.txt"].should include(MockCompressor)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "prefers the latest registered engines" do
|
42
|
+
Crush.mappings["mult"].first.should == MockCompressor2
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe ".registered?" do
|
47
|
+
it "returns false if the extension is not registered" do
|
48
|
+
Crush.registered?("none").should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns true if the given extension is registered" do
|
52
|
+
Crush.registered?("mock").should be_true
|
53
|
+
Crush.registered?(".mock").should be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".[]" do
|
58
|
+
it "returns nil when no engines are found" do
|
59
|
+
Crush["none"].should be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns engines matching exact extension names" do
|
63
|
+
Crush["mock"].should == MockCompressor
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns engines matching exact file extensions" do
|
67
|
+
Crush[".MOCK"].should == MockCompressor
|
68
|
+
end
|
69
|
+
|
70
|
+
it "returns engines matching multiple file extensions" do
|
71
|
+
Crush["application.js.Mock"].should == MockCompressor
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns engines matching filenames" do
|
75
|
+
Crush["some/path/file.txt"].should == MockCompressor
|
76
|
+
end
|
77
|
+
|
78
|
+
it "returns engines that are already initialized" do
|
79
|
+
Crush["mult"].should == MockCompressor
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe ".prefer" do
|
84
|
+
it "reorders the engine mappings so the given engine is returned" do
|
85
|
+
Crush.prefer(MockCompressor)
|
86
|
+
Crush["mult"].should == MockCompressor
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe ".new" do
|
91
|
+
it "creates a new engine if found" do
|
92
|
+
compressor = Crush.new("application.mock", :key => "value") { "Hello World" }
|
93
|
+
compressor.args.should =~ [ "application.mock", { :key => "value" } ]
|
94
|
+
compressor.block.call.should == "Hello World"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "raises an error if no engine is found" do
|
98
|
+
expect { Crush.new("file.php") }.to raise_error(Crush::EngineNotFound)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crush
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 29
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
5
|
+
version: 0.1.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Pete
|
@@ -16,9 +11,96 @@ autorequire:
|
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
13
|
|
19
|
-
date: 2011-05
|
20
|
-
dependencies:
|
21
|
-
|
14
|
+
date: 2011-06-05 00:00:00 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.6.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jsmin
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: packr
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: uglifier
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: closure-compiler
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: yui-compressor
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: cssmin
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: rainpress
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id008
|
22
104
|
description: Crush is a generic interface, like Tilt, for the various compression engines in Ruby.
|
23
105
|
email: me@petebrowne.com
|
24
106
|
executables: []
|
@@ -30,10 +112,30 @@ extra_rdoc_files: []
|
|
30
112
|
files:
|
31
113
|
- .gitignore
|
32
114
|
- Gemfile
|
115
|
+
- LICENSE
|
116
|
+
- README.md
|
33
117
|
- Rakefile
|
34
118
|
- crush.gemspec
|
35
119
|
- lib/crush.rb
|
120
|
+
- lib/crush/closure.rb
|
121
|
+
- lib/crush/cssmin.rb
|
122
|
+
- lib/crush/engine.rb
|
123
|
+
- lib/crush/jsmin.rb
|
124
|
+
- lib/crush/packr.rb
|
125
|
+
- lib/crush/rainpress.rb
|
126
|
+
- lib/crush/uglifier.rb
|
36
127
|
- lib/crush/version.rb
|
128
|
+
- lib/crush/yui.rb
|
129
|
+
- spec/crush/closure_spec.rb
|
130
|
+
- spec/crush/cssmin_spec.rb
|
131
|
+
- spec/crush/engine_spec.rb
|
132
|
+
- spec/crush/jsmin_spec.rb
|
133
|
+
- spec/crush/packr_spec.rb
|
134
|
+
- spec/crush/rainpress_spec.rb
|
135
|
+
- spec/crush/uglifier_spec.rb
|
136
|
+
- spec/crush/yui_spec.rb
|
137
|
+
- spec/crush_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
37
139
|
homepage: http://github.com/petebrowne/crush
|
38
140
|
licenses: []
|
39
141
|
|
@@ -47,25 +149,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
47
149
|
requirements:
|
48
150
|
- - ">="
|
49
151
|
- !ruby/object:Gem::Version
|
50
|
-
hash: 3
|
51
|
-
segments:
|
52
|
-
- 0
|
53
152
|
version: "0"
|
54
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
154
|
none: false
|
56
155
|
requirements:
|
57
156
|
- - ">="
|
58
157
|
- !ruby/object:Gem::Version
|
59
|
-
hash: 3
|
60
|
-
segments:
|
61
|
-
- 0
|
62
158
|
version: "0"
|
63
159
|
requirements: []
|
64
160
|
|
65
161
|
rubyforge_project: crush
|
66
|
-
rubygems_version: 1.7.
|
162
|
+
rubygems_version: 1.7.2
|
67
163
|
signing_key:
|
68
164
|
specification_version: 3
|
69
165
|
summary: A generic interface to multiple Ruby compression engines.
|
70
|
-
test_files:
|
71
|
-
|
166
|
+
test_files:
|
167
|
+
- spec/crush/closure_spec.rb
|
168
|
+
- spec/crush/cssmin_spec.rb
|
169
|
+
- spec/crush/engine_spec.rb
|
170
|
+
- spec/crush/jsmin_spec.rb
|
171
|
+
- spec/crush/packr_spec.rb
|
172
|
+
- spec/crush/rainpress_spec.rb
|
173
|
+
- spec/crush/uglifier_spec.rb
|
174
|
+
- spec/crush/yui_spec.rb
|
175
|
+
- spec/crush_spec.rb
|
176
|
+
- spec/spec_helper.rb
|