crush 0.0.1 → 0.1.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/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
|