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