crush 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -32,10 +32,50 @@ Or you could use `Crush.prefer` to tell Crush which engine you'd like to use.
32
32
  require "uglifier"
33
33
  require "jsmin"
34
34
  require "crush"
35
- Crush.prefer(Crush::Uglifier)
35
+ Crush.prefer(Crush::Uglifier) # or Crush.prefer(:uglifier)
36
36
  Crush.new("application.js").compress
37
37
  ```
38
38
 
39
+ API
40
+ ---
41
+
42
+ There a few different ways to compress some data. The API, for the most part, follows the Tilt
43
+ API. So this is the standard way of compressing (reading the data from the file):
44
+
45
+ ```ruby
46
+ Crush.new("file.js", :mangle => true).compress
47
+ ```
48
+
49
+ You can also pass the data using a block, like Tilt.
50
+
51
+ ```ruby
52
+ Crush.new(:uglifier, :mangle => true) { "some data to compress" }.compress
53
+ ```
54
+
55
+ _Note how I declared which engine to use by its name (as a Symbol)._
56
+
57
+ I've also included a way to pass data that is more consistent with the other compression engines:
58
+
59
+ ```ruby
60
+ Crush.new(:uglifier, :mangle => true).compress("some data to compress")
61
+ ```
62
+
63
+ Engines
64
+ -------
65
+
66
+ Support fo these compression engines are included:
67
+
68
+ ENGINES FILE EXTENSIONS NAME REQUIRED LIBRARIES
69
+ -------------------------- ------------------ ---------- ------------------
70
+ JSMin .js, .min.js jsmin jsmin
71
+ Packr .js, .pack.js packr packr
72
+ YUI::JavaScriptCompressor .js, .yui.js yui_js yui/compressor
73
+ Closure::Compiler .js, .closure.js closure closure-compiler
74
+ Uglifier .js, .ugly.js uglifier uglifier
75
+ CSSMin .css, .min.css cssmin cssmin
76
+ Rainpress .css, .rain.css rainpress rainpress
77
+ YUI::CssCompressor .css, .yui.css yui_css yui/compressor
78
+
39
79
  Copyright
40
80
  ---------
41
81
 
@@ -10,9 +10,12 @@ module Crush
10
10
 
11
11
  class EngineNotFound < StandardError; end
12
12
 
13
+ @preferred_engines = {}
14
+ @engine_mappings = Hash.new { |h, k| h[k] = [] }
15
+
13
16
  # Hash of registered compression engines.
14
17
  def self.mappings
15
- @mappings ||= Hash.new { |h, k| h[k] = [] }
18
+ @engine_mappings
16
19
  end
17
20
 
18
21
  # Ensures the extension doesn't include the "."
@@ -36,37 +39,63 @@ module Crush
36
39
 
37
40
  # Make the given compression engine preferred. Which means,
38
41
  # 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)
42
+ def self.prefer(engine_or_name, *extensions)
43
+ engine = find_by_name(engine_or_name) unless engine_or_name.is_a?(Class)
44
+
45
+ if extensions.empty?
46
+ mappings.each do |ext, engines|
47
+ @preferred_engines[ext] = engine if engines.include?(engine)
48
+ end
49
+ else
50
+ register(engine, *extensions)
51
+ extensions.each do |ext|
52
+ ext = normalize(ext)
53
+ @preferred_engines[ext] = engine
44
54
  end
45
55
  end
46
56
  end
47
57
 
58
+ # Looks for a compression engine. When given a Symbol, it will look for an engine
59
+ # by name. When given a String, it will look for a compression engine by filename
60
+ # or file extension.
61
+ def self.[](path_or_name)
62
+ path_or_name.is_a?(Symbol) ? find_by_name(path_or_name) : find_by_path(path_or_name)
63
+ end
64
+
65
+ # Create a new compression engine. The first argument is used to determine
66
+ # which engine to use. This can be either an engine name (as a Symbol) or a path
67
+ # to a file (as a String). If a path is given, the engine is initialized with
68
+ # a reference to that path.
69
+ def self.new(path_or_name, options = {}, &block)
70
+ if engine = self[path_or_name]
71
+ path = path_or_name.is_a?(Symbol) ? nil : path_or_name
72
+ engine.new(path, options, &block)
73
+ else
74
+ raise EngineNotFound.new("No compression engine registered for '#{path}'")
75
+ end
76
+ end
77
+
78
+ # Look for a compression engine with the given engine name.
79
+ # Return nil when no engine is found.
80
+ def self.find_by_name(engine_name)
81
+ mappings.values.flatten.detect { |engine| engine.engine_name == engine_name.to_s }
82
+ end
83
+
48
84
  # Look for a compression engine for the given filename or file
49
85
  # extension. Return nil when no engine is found.
50
- def self.[](path)
86
+ def self.find_by_path(path)
51
87
  pattern = File.basename(path.to_s).downcase
52
88
  until pattern.empty? || registered?(pattern)
53
89
  pattern.sub! /^[^.]*\.?/, ""
54
90
  end
55
-
56
91
  pattern = normalize(pattern)
92
+
93
+ preferred_engine = @preferred_engines[pattern]
94
+ return preferred_engine unless preferred_engine.nil?
95
+
57
96
  mappings[pattern].detect(&:engine_initialized?) || mappings[pattern].first
58
97
  end
59
98
 
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
99
  register Crush::JSMin, "js", "min.js"
71
100
  register Crush::Packr, "js", "pack.js"
72
101
  register Crush::YUI::JavaScriptCompressor, "js", "yui.js"
@@ -1,6 +1,10 @@
1
1
  module Crush
2
2
  module Closure
3
3
  class Compiler < Crush::Engine
4
+ def self.engine_name
5
+ "closure"
6
+ end
7
+
4
8
  def self.engine_initialized?
5
9
  !!(defined? ::Closure) && !!(defined? ::Closure::Compiler)
6
10
  end
@@ -1,5 +1,9 @@
1
1
  module Crush
2
2
  class CSSMin < Engine
3
+ def self.engine_name
4
+ "cssmin"
5
+ end
6
+
3
7
  def self.engine_initialized?
4
8
  !!(defined? ::CSSMin)
5
9
  end
@@ -16,6 +16,17 @@ module Crush
16
16
  class << self
17
17
  attr_accessor :engine_initialized
18
18
  alias :engine_initialized? :engine_initialized
19
+
20
+ # Returns a lowercase, underscored name for the engine.
21
+ def engine_name
22
+ engine_name = name.to_s.dup
23
+ engine_name.sub! /^.*::/ , ""
24
+ engine_name.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
25
+ engine_name.gsub! /([a-z\d])([A-Z])/, '\1_\2'
26
+ engine_name.tr! "-", "_"
27
+ engine_name.downcase!
28
+ engine_name
29
+ end
19
30
  end
20
31
 
21
32
  # Create a new engine with the file and options specified. By
@@ -1,5 +1,9 @@
1
1
  module Crush
2
2
  class JSMin < Engine
3
+ def self.engine_name
4
+ "jsmin"
5
+ end
6
+
3
7
  def self.engine_initialized?
4
8
  !!(defined? ::JSMin)
5
9
  end
@@ -1,3 +1,3 @@
1
1
  module Crush
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,6 +1,10 @@
1
1
  module Crush
2
2
  module YUI
3
3
  class JavaScriptCompressor < Crush::Engine
4
+ def self.engine_name
5
+ "yui_js"
6
+ end
7
+
4
8
  def self.engine_initialized?
5
9
  !!(defined? ::YUI) && !!(defined? ::YUI::JavaScriptCompressor)
6
10
  end
@@ -19,6 +23,10 @@ module Crush
19
23
  end
20
24
 
21
25
  class CssCompressor < Crush::Engine
26
+ def self.engine_name
27
+ "yui_css"
28
+ end
29
+
22
30
  def self.engine_initialized?
23
31
  !!(defined? ::YUI) && !!(defined? ::YUI::CssCompressor)
24
32
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "closure-compiler"
3
3
 
4
4
  describe Crush::Closure::Compiler do
5
+ specify { Crush::Closure::Compiler.engine_name.should == "closure" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["js"].should include(Crush::Closure::Compiler)
7
9
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "cssmin"
3
3
 
4
4
  describe Crush::CSSMin do
5
+ specify { Crush::CSSMin.engine_name.should == "cssmin" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["css"].should include(Crush::CSSMin)
7
9
  end
@@ -4,6 +4,12 @@ describe Crush::Engine do
4
4
  class MockEngine < Crush::Engine
5
5
  end
6
6
 
7
+ describe ".engine_name" do
8
+ it "returns an undescored version of the class name" do
9
+ MockEngine.engine_name.should == "mock_engine"
10
+ end
11
+ end
12
+
7
13
  describe "#file" do
8
14
  it "returns the file the engine was initialized with" do
9
15
  engine = MockEngine.new("application.js") {}
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "jsmin"
3
3
 
4
4
  describe Crush::JSMin do
5
+ specify { Crush::JSMin.engine_name.should == "jsmin" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["js"].should include(Crush::JSMin)
7
9
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "packr"
3
3
 
4
4
  describe Crush::Packr do
5
+ specify { Crush::Packr.engine_name.should == "packr" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["js"].should include(Crush::Packr)
7
9
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "rainpress"
3
3
 
4
4
  describe Crush::Rainpress do
5
+ specify { Crush::Rainpress.engine_name.should == "rainpress" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["css"].should include(Crush::Rainpress)
7
9
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "uglifier"
3
3
 
4
4
  describe Crush::Uglifier do
5
+ specify { Crush::Uglifier.engine_name.should == "uglifier" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["js"].should include(Crush::Uglifier)
7
9
  end
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
  require "yui/compressor"
3
3
 
4
4
  describe Crush::YUI::JavaScriptCompressor do
5
+ specify { Crush::YUI::JavaScriptCompressor.engine_name.should == "yui_js" }
6
+
5
7
  it "is registered for '.js' files" do
6
8
  Crush.mappings["js"].should include(Crush::YUI::JavaScriptCompressor)
7
9
  end
@@ -22,6 +24,8 @@ describe Crush::YUI::JavaScriptCompressor do
22
24
  end
23
25
 
24
26
  describe Crush::YUI::CssCompressor do
27
+ specify { Crush::YUI::CssCompressor.engine_name.should == "yui_css" }
28
+
25
29
  it "is registered for '.js' files" do
26
30
  Crush.mappings["css"].should include(Crush::YUI::CssCompressor)
27
31
  end
@@ -2,6 +2,10 @@ require "spec_helper"
2
2
 
3
3
  describe Crush do
4
4
  class MockCompressor
5
+ def self.engine_name
6
+ "mock"
7
+ end
8
+
5
9
  def self.engine_initialized?
6
10
  true
7
11
  end
@@ -14,6 +18,10 @@ describe Crush do
14
18
  end
15
19
 
16
20
  class MockCompressor2 < MockCompressor
21
+ def self.engine_name
22
+ "mock2"
23
+ end
24
+
17
25
  def self.engine_initialized?
18
26
  false
19
27
  end
@@ -21,8 +29,8 @@ describe Crush do
21
29
 
22
30
  before(:all) do
23
31
  Crush.register(MockCompressor, "mock", ".mck", "file.txt")
24
- Crush.register(MockCompressor, "mult")
25
- Crush.register(MockCompressor2, "mult")
32
+ Crush.register(MockCompressor, "mult", "mlt")
33
+ Crush.register(MockCompressor2, "mult", "mlt")
26
34
  end
27
35
 
28
36
  describe ".mappings" do
@@ -55,36 +63,34 @@ describe Crush do
55
63
  end
56
64
 
57
65
  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
66
+ it "returns engines found by path when given strings" do
63
67
  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
68
+ Crush["application.js.mock"].should == MockCompressor
75
69
  Crush["some/path/file.txt"].should == MockCompressor
76
70
  end
77
71
 
78
- it "returns engines that are already initialized" do
79
- Crush["mult"].should == MockCompressor
72
+ it "returns engines found by name when given symbols" do
73
+ Crush[:mock].should == MockCompressor
74
+ Crush[:mock2].should == MockCompressor2
80
75
  end
81
76
  end
82
77
 
83
78
  describe ".prefer" do
84
- it "reorders the engine mappings so the given engine is returned" do
79
+ it "reorders the engine engines so the given engine is returned" do
85
80
  Crush.prefer(MockCompressor)
86
81
  Crush["mult"].should == MockCompressor
87
82
  end
83
+
84
+ it "accepts symbol names of the various engines" do
85
+ Crush.prefer(:mock2)
86
+ Crush["mult"].should == MockCompressor2
87
+ end
88
+
89
+ it "limits the preference to the given extensions" do
90
+ Crush.prefer(:mock, "mlt")
91
+ Crush["mult"].should == MockCompressor2
92
+ Crush["mlt"].should == MockCompressor
93
+ end
88
94
  end
89
95
 
90
96
  describe ".new" do
@@ -98,4 +104,42 @@ describe Crush do
98
104
  expect { Crush.new("file.php") }.to raise_error(Crush::EngineNotFound)
99
105
  end
100
106
  end
107
+
108
+ describe ".find_by_name" do
109
+ it "returns nil if the engine could not be found" do
110
+ Crush.find_by_name("none").should be_nil
111
+ end
112
+
113
+ it "returns the registered engine with the given name" do
114
+ Crush.find_by_name("mock").should == MockCompressor
115
+ Crush.find_by_name("mock2").should == MockCompressor2
116
+ end
117
+ end
118
+
119
+ describe ".find_by_path" do
120
+ it "returns nil when no engines are found" do
121
+ Crush.find_by_path("none").should be_nil
122
+ end
123
+
124
+ it "returns engines matching exact extension names" do
125
+ Crush.find_by_path("mock").should == MockCompressor
126
+ end
127
+
128
+ it "returns engines matching exact file extensions" do
129
+ Crush.find_by_path(".MOCK").should == MockCompressor
130
+ end
131
+
132
+ it "returns engines matching multiple file extensions" do
133
+ Crush.find_by_path("application.js.Mock").should == MockCompressor
134
+ end
135
+
136
+ it "returns engines matching filenames" do
137
+ Crush.find_by_path("some/path/file.txt").should == MockCompressor
138
+ end
139
+
140
+ it "returns engines that are already initialized" do
141
+ Crush.instance_variable_get("@preferred_engines").delete("mult")
142
+ Crush.find_by_path("mult").should == MockCompressor
143
+ end
144
+ end
101
145
  end
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crush
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 23
4
5
  prerelease:
5
- version: 0.1.0
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
6
11
  platform: ruby
7
12
  authors:
8
13
  - Pete
@@ -11,7 +16,7 @@ autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2011-06-05 00:00:00 Z
19
+ date: 2011-06-06 00:00:00 Z
15
20
  dependencies:
16
21
  - !ruby/object:Gem::Dependency
17
22
  name: rspec
@@ -21,6 +26,11 @@ dependencies:
21
26
  requirements:
22
27
  - - ~>
23
28
  - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 2
32
+ - 6
33
+ - 0
24
34
  version: 2.6.0
25
35
  type: :development
26
36
  version_requirements: *id001
@@ -32,6 +42,9 @@ dependencies:
32
42
  requirements:
33
43
  - - ">="
34
44
  - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
35
48
  version: "0"
36
49
  type: :development
37
50
  version_requirements: *id002
@@ -43,6 +56,9 @@ dependencies:
43
56
  requirements:
44
57
  - - ">="
45
58
  - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
46
62
  version: "0"
47
63
  type: :development
48
64
  version_requirements: *id003
@@ -54,6 +70,9 @@ dependencies:
54
70
  requirements:
55
71
  - - ">="
56
72
  - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
57
76
  version: "0"
58
77
  type: :development
59
78
  version_requirements: *id004
@@ -65,6 +84,9 @@ dependencies:
65
84
  requirements:
66
85
  - - ">="
67
86
  - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
68
90
  version: "0"
69
91
  type: :development
70
92
  version_requirements: *id005
@@ -76,6 +98,9 @@ dependencies:
76
98
  requirements:
77
99
  - - ">="
78
100
  - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
79
104
  version: "0"
80
105
  type: :development
81
106
  version_requirements: *id006
@@ -87,6 +112,9 @@ dependencies:
87
112
  requirements:
88
113
  - - ">="
89
114
  - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
90
118
  version: "0"
91
119
  type: :development
92
120
  version_requirements: *id007
@@ -98,6 +126,9 @@ dependencies:
98
126
  requirements:
99
127
  - - ">="
100
128
  - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
101
132
  version: "0"
102
133
  type: :development
103
134
  version_requirements: *id008
@@ -149,17 +180,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
180
  requirements:
150
181
  - - ">="
151
182
  - !ruby/object:Gem::Version
183
+ hash: 3
184
+ segments:
185
+ - 0
152
186
  version: "0"
153
187
  required_rubygems_version: !ruby/object:Gem::Requirement
154
188
  none: false
155
189
  requirements:
156
190
  - - ">="
157
191
  - !ruby/object:Gem::Version
192
+ hash: 3
193
+ segments:
194
+ - 0
158
195
  version: "0"
159
196
  requirements: []
160
197
 
161
198
  rubyforge_project: crush
162
- rubygems_version: 1.7.2
199
+ rubygems_version: 1.7.1
163
200
  signing_key:
164
201
  specification_version: 3
165
202
  summary: A generic interface to multiple Ruby compression engines.