crush 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/README.md +75 -39
- data/crush.gemspec +7 -4
- data/lib/crush.rb +43 -97
- data/lib/crush/all.rb +3 -0
- data/lib/crush/closure.rb +11 -6
- data/lib/crush/css.rb +3 -0
- data/lib/crush/cssmin.rb +13 -5
- data/lib/crush/engine.rb +49 -85
- data/lib/crush/js.rb +3 -0
- data/lib/crush/jsmin.rb +13 -5
- data/lib/crush/packr.rb +14 -2
- data/lib/crush/rainpress.rb +14 -2
- data/lib/crush/uglifier.rb +11 -2
- data/lib/crush/version.rb +1 -1
- data/lib/crush/yui.rb +20 -12
- data/spec/crush/closure_spec.rb +11 -8
- data/spec/crush/cssmin_spec.rb +7 -6
- data/spec/crush/engine_spec.rb +40 -84
- data/spec/crush/jsmin_spec.rb +7 -6
- data/spec/crush/packr_spec.rb +7 -11
- data/spec/crush/rainpress_spec.rb +9 -8
- data/spec/crush/uglifier_spec.rb +11 -8
- data/spec/crush/yui_spec.rb +22 -15
- data/spec/crush_spec.rb +36 -132
- data/spec/spec_helper.rb +3 -6
- metadata +44 -56
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,80 +1,116 @@
|
|
1
1
|
Crush
|
2
2
|
=====
|
3
3
|
|
4
|
-
Crush is a
|
5
|
-
|
4
|
+
Crush is a set of Tilt templates for the various JavaScript and CSS compression libraries in Ruby.
|
5
|
+
|
6
|
+
See here for more information about Tilt templates: [http://github.com/rtomayko/tilt](https://github.com/rtomayko/tilt)
|
7
|
+
|
8
|
+
Well, they're not really templates. They're more like engines or processors. But, anyway, they fit
|
9
|
+
in very well with Tilt, because each one likes to do things a little differently. Tilt + Crush cures
|
10
|
+
the headache by providing a generic API to use any of the engines you need.
|
6
11
|
|
7
12
|
Basic Usage
|
8
13
|
-----------
|
9
14
|
|
15
|
+
Step 1, Install:
|
16
|
+
|
17
|
+
```
|
18
|
+
gem install crush
|
19
|
+
```
|
20
|
+
|
21
|
+
Step 2, Compress:
|
22
|
+
|
10
23
|
```ruby
|
11
|
-
require "uglifier"
|
12
24
|
require "crush"
|
13
|
-
Crush.
|
25
|
+
Crush.register
|
26
|
+
Tilt.new("application.js").render
|
27
|
+
# => compressed JavaScript...
|
14
28
|
```
|
15
29
|
|
16
|
-
|
17
|
-
|
30
|
+
Tilt Mappings
|
31
|
+
-------------
|
18
32
|
|
19
|
-
If you
|
20
|
-
|
33
|
+
If you look closely at the above example, you had to call `Crush.register` before you could
|
34
|
+
use any of the engines. That's because, by default, Crush does not automatically register
|
35
|
+
its templates with Tilt. But, fear not, it's insanely easy to register them.
|
21
36
|
|
22
37
|
```ruby
|
23
|
-
require "uglifier"
|
24
|
-
require "jsmin"
|
25
38
|
require "crush"
|
26
|
-
Crush
|
39
|
+
Crush.register
|
40
|
+
# or you can use this shortcut to do the same thing:
|
41
|
+
require "crush/all"
|
27
42
|
```
|
28
43
|
|
29
|
-
|
44
|
+
If you only want to use the JavaScript templates:
|
30
45
|
|
31
46
|
```ruby
|
32
|
-
require "uglifier"
|
33
|
-
require "jsmin"
|
34
47
|
require "crush"
|
35
|
-
Crush.
|
36
|
-
|
48
|
+
Crush.register_js
|
49
|
+
# or just:
|
50
|
+
require "crush/js"
|
37
51
|
```
|
38
52
|
|
39
|
-
|
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):
|
53
|
+
CSS engines only:
|
44
54
|
|
45
55
|
```ruby
|
46
|
-
|
56
|
+
require "crush"
|
57
|
+
Crush.register_css
|
58
|
+
# or, because I love shortcuts so much:
|
59
|
+
require "crush/css"
|
47
60
|
```
|
48
61
|
|
49
|
-
|
62
|
+
And finally, it's not hard to register only the ones you need, manually:
|
50
63
|
|
51
64
|
```ruby
|
52
|
-
|
65
|
+
require "crush"
|
66
|
+
Tilt.register Crush::Uglifier, "js"
|
67
|
+
Tilt.register Crush::Rainpress, "css"
|
53
68
|
```
|
54
69
|
|
55
|
-
|
70
|
+
Generic API
|
71
|
+
-----------
|
72
|
+
|
73
|
+
The included templates are actually subclasses of `Crush::Engine`, which adds a few
|
74
|
+
methods somewhat common to compression libraries.
|
75
|
+
|
76
|
+
`Crush::Engine.compress` takes the given string and immediately compresses it. It is also
|
77
|
+
aliased as `compile`.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
Crush::CSSMin.compress "body { color: red; }"
|
81
|
+
# => "body{color:red;}"
|
82
|
+
|
83
|
+
# Using Tilt's interface:
|
84
|
+
Tilt[:css].compress "body { color: red; }"
|
85
|
+
# => "body{color:red;}"
|
86
|
+
```
|
56
87
|
|
57
|
-
|
88
|
+
`Crush::Engine`s do not require data from a file or block like `Tilt::Template`s. They can
|
89
|
+
be initialized and given data through the `Crush::Engine#compress` instance method, which
|
90
|
+
is also aliased as `compile`.
|
58
91
|
|
59
92
|
```ruby
|
60
|
-
Crush.new
|
93
|
+
engine = Crush::CSSMin.new
|
94
|
+
# Does not through an ArgumentError like a Tilt::Template
|
95
|
+
engine.compress "body { color: red; }"
|
96
|
+
# => "body{color:red;}"
|
61
97
|
```
|
62
98
|
|
63
|
-
Engines
|
64
|
-
|
99
|
+
Included Engines
|
100
|
+
----------------
|
65
101
|
|
66
102
|
Support fo these compression engines are included:
|
67
103
|
|
68
|
-
ENGINES
|
69
|
-
--------------------------
|
70
|
-
JSMin .js
|
71
|
-
Packr .js
|
72
|
-
YUI::JavaScriptCompressor .js
|
73
|
-
Closure::Compiler .js
|
74
|
-
Uglifier .js
|
75
|
-
CSSMin .css
|
76
|
-
Rainpress .css
|
77
|
-
YUI::CssCompressor .css
|
104
|
+
ENGINES EXTENSIONS REQUIRED LIBRARIES
|
105
|
+
-------------------------- ----------- -----------------------
|
106
|
+
JSMin .js jsmin
|
107
|
+
Packr .js packr
|
108
|
+
YUI::JavaScriptCompressor .js yui/compressor
|
109
|
+
Closure::Compiler .js closure-compiler
|
110
|
+
Uglifier .js uglifier
|
111
|
+
CSSMin .css cssmin
|
112
|
+
Rainpress .css rainpress
|
113
|
+
YUI::CssCompressor .css yui/compressor
|
78
114
|
|
79
115
|
Copyright
|
80
116
|
---------
|
data/crush.gemspec
CHANGED
@@ -5,15 +5,18 @@ require "crush/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "crush"
|
7
7
|
s.version = Crush::VERSION
|
8
|
-
s.authors =
|
8
|
+
s.authors = [ "Pete Browne" ]
|
9
9
|
s.email = "me@petebrowne.com"
|
10
10
|
s.homepage = "http://github.com/petebrowne/crush"
|
11
|
-
s.summary = "
|
12
|
-
s.description = "Crush is a
|
11
|
+
s.summary = "Tilt templates for various JavaScript and CSS compression libraries."
|
12
|
+
s.description = "Crush is a set of Tilt templates for the various JavaScript and CSS compression libraries in Ruby."
|
13
13
|
|
14
14
|
s.rubyforge_project = "crush"
|
15
|
+
|
16
|
+
s.add_dependency "tilt", "~> 1.3"
|
15
17
|
|
16
|
-
s.add_development_dependency "rspec", "~> 2.6
|
18
|
+
s.add_development_dependency "rspec", "~> 2.6"
|
19
|
+
s.add_development_dependency "rake"
|
17
20
|
s.add_development_dependency "jsmin"
|
18
21
|
s.add_development_dependency "packr"
|
19
22
|
s.add_development_dependency "uglifier"
|
data/lib/crush.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
+
require "tilt"
|
2
|
+
require "crush/version"
|
3
|
+
|
1
4
|
module Crush
|
5
|
+
extend self
|
6
|
+
|
2
7
|
autoload :Closure, "crush/closure"
|
3
8
|
autoload :CSSMin, "crush/cssmin"
|
4
9
|
autoload :Engine, "crush/engine"
|
@@ -8,101 +13,42 @@ module Crush
|
|
8
13
|
autoload :Uglifier, "crush/uglifier"
|
9
14
|
autoload :YUI, "crush/yui"
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
register(engine, *extensions)
|
51
|
-
extensions.each do |ext|
|
52
|
-
ext = normalize(ext)
|
53
|
-
@preferred_engines[ext] = engine
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
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
|
-
|
84
|
-
# Look for a compression engine for the given filename or file
|
85
|
-
# extension. Return nil when no engine is found.
|
86
|
-
def self.find_by_path(path)
|
87
|
-
pattern = File.basename(path.to_s).downcase
|
88
|
-
until pattern.empty? || registered?(pattern)
|
89
|
-
pattern.sub! /^[^.]*\.?/, ""
|
90
|
-
end
|
91
|
-
pattern = normalize(pattern)
|
92
|
-
|
93
|
-
preferred_engine = @preferred_engines[pattern]
|
94
|
-
return preferred_engine unless preferred_engine.nil?
|
95
|
-
|
96
|
-
mappings[pattern].detect(&:engine_initialized?) || mappings[pattern].first
|
97
|
-
end
|
98
|
-
|
99
|
-
register Crush::JSMin, "js", "min.js"
|
100
|
-
register Crush::Packr, "js", "pack.js"
|
101
|
-
register Crush::YUI::JavaScriptCompressor, "js", "yui.js"
|
102
|
-
register Crush::Closure::Compiler, "js", "closure.js"
|
103
|
-
register Crush::Uglifier, "js", "ugly.js"
|
104
|
-
|
105
|
-
register Crush::CSSMin, "css", "min.css"
|
106
|
-
register Crush::Rainpress, "css", "rain.css"
|
107
|
-
register Crush::YUI::CssCompressor, "css", "yui.css"
|
16
|
+
# Registers all of the JavaScripts engines
|
17
|
+
# with Tilt in the following order of importance:
|
18
|
+
#
|
19
|
+
# 1. Crush::Uglifer
|
20
|
+
# 2. Crush::Closure::Compiler
|
21
|
+
# 3. Crush::YUI::JavaScriptCompressor
|
22
|
+
# 4. Crush::Packr
|
23
|
+
# 5. Crush::JSMin
|
24
|
+
def register_js
|
25
|
+
Tilt.register JSMin, "js"
|
26
|
+
Tilt.register Packr, "js"
|
27
|
+
Tilt.register YUI::JavaScriptCompressor, "js"
|
28
|
+
Tilt.register Closure::Compiler, "js"
|
29
|
+
Tilt.register Uglifier, "js"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Registers all of the CSS engines
|
33
|
+
# with Tilt in the following order of importance:
|
34
|
+
#
|
35
|
+
# 3. Crush::CSSMin
|
36
|
+
# 4. Crush::Rainpress
|
37
|
+
# 5. Crush::YUI::CssCompressor
|
38
|
+
def register_css
|
39
|
+
Tilt.register CSSMin, "css"
|
40
|
+
Tilt.register Rainpress, "css"
|
41
|
+
Tilt.register YUI::CssCompressor, "css"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Registers all of the included engines
|
45
|
+
# with Tilt.
|
46
|
+
#
|
47
|
+
# (see #register_js)
|
48
|
+
# (see #register_css)
|
49
|
+
def register
|
50
|
+
register_js
|
51
|
+
register_css
|
52
|
+
end
|
53
|
+
alias :register_all :register
|
108
54
|
end
|
data/lib/crush/all.rb
ADDED
data/lib/crush/closure.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
require "crush/engine"
|
2
|
+
|
1
3
|
module Crush
|
2
4
|
module Closure
|
5
|
+
# Engine implementation of Google's Closure Compiler,
|
6
|
+
# using the closure-compiler gem. See:
|
7
|
+
#
|
8
|
+
# https://rubygems.org/gems/closure-compiler
|
3
9
|
class Compiler < Crush::Engine
|
4
|
-
|
5
|
-
"closure"
|
6
|
-
end
|
10
|
+
self.default_mime_type = "application/javascript"
|
7
11
|
|
8
12
|
def self.engine_initialized?
|
9
|
-
!!(defined? ::Closure
|
13
|
+
!!(defined? ::Closure && defined? ::Closure::Compiler)
|
10
14
|
end
|
11
15
|
|
12
16
|
def initialize_engine
|
@@ -15,10 +19,11 @@ module Crush
|
|
15
19
|
|
16
20
|
def prepare
|
17
21
|
@engine = ::Closure::Compiler.new(options)
|
22
|
+
@output = nil
|
18
23
|
end
|
19
24
|
|
20
|
-
def evaluate
|
21
|
-
@engine.compile(data)
|
25
|
+
def evaluate(scope, locals, &block)
|
26
|
+
@output ||= @engine.compile(data)
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
data/lib/crush/css.rb
ADDED
data/lib/crush/cssmin.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
require "crush/engine"
|
2
|
+
|
1
3
|
module Crush
|
4
|
+
# Engine implementation of the CSS minification
|
5
|
+
# library, CSSMin. See:
|
6
|
+
#
|
7
|
+
# https://rubygems.org/gems/cssmin
|
2
8
|
class CSSMin < Engine
|
3
|
-
|
4
|
-
"cssmin"
|
5
|
-
end
|
9
|
+
self.default_mime_type = "text/css"
|
6
10
|
|
7
11
|
def self.engine_initialized?
|
8
12
|
!!(defined? ::CSSMin)
|
@@ -12,8 +16,12 @@ module Crush
|
|
12
16
|
require_template_library "cssmin"
|
13
17
|
end
|
14
18
|
|
15
|
-
def
|
16
|
-
|
19
|
+
def prepare
|
20
|
+
@output = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def evaluate(scope, locals, &block)
|
24
|
+
@output ||= ::CSSMin.minify(data)
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
data/lib/crush/engine.rb
CHANGED
@@ -1,100 +1,64 @@
|
|
1
|
+
require "tilt/template"
|
2
|
+
|
1
3
|
module Crush
|
2
|
-
class
|
3
|
-
|
4
|
-
|
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
|
4
|
+
# Crush::Engine is an abstract class like Tilt::Template,
|
5
|
+
# which adds methods common to compression library APIs.
|
6
|
+
class Engine < Tilt::Template
|
16
7
|
class << self
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
engine_name.downcase!
|
28
|
-
engine_name
|
8
|
+
# Convenience method of initializing an
|
9
|
+
# engine and immediately compressing the given
|
10
|
+
# data.
|
11
|
+
#
|
12
|
+
# @param [String] data The data to compress.
|
13
|
+
# @param [Hash] options Options to pass to the
|
14
|
+
# underlying compressor.
|
15
|
+
# @return [String] the compressed data.
|
16
|
+
def compress(data, options = {})
|
17
|
+
self.new(options).compress(data)
|
29
18
|
end
|
19
|
+
alias :compile :compress
|
30
20
|
end
|
31
21
|
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
22
|
+
# Override Tilt::Template#initialize so that it
|
23
|
+
# does not require a file or block. This is done
|
24
|
+
# so that Crush::Engines can follow the usual
|
25
|
+
# compressor API convention of having an instance
|
26
|
+
# method, #compress, which accepts the data to
|
27
|
+
# compress as an argument.
|
35
28
|
#
|
36
|
-
#
|
37
|
-
def initialize(file = nil,
|
38
|
-
|
39
|
-
|
40
|
-
else
|
41
|
-
@file = file
|
42
|
-
@options = options || {}
|
43
|
-
end
|
44
|
-
|
45
|
-
unless self.class.engine_initialized?
|
46
|
-
initialize_engine
|
47
|
-
self.class.engine_initialized = true
|
29
|
+
# (see Tilt::Template#initialize)
|
30
|
+
def initialize(file = nil, *args, &block)
|
31
|
+
unless block_given? or args[0].respond_to?(:to_str)
|
32
|
+
block = Proc.new {}
|
48
33
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
34
|
+
super file, *args, &block
|
35
|
+
end
|
36
|
+
|
37
|
+
# Compresses the given data.
|
38
|
+
#
|
39
|
+
# @param [String] data The data to compress.
|
40
|
+
# @return [String] the compressed data.
|
41
|
+
def compress(data = nil)
|
42
|
+
@data = data.to_s unless data.nil?
|
43
|
+
render
|
57
44
|
end
|
45
|
+
alias :compile :compress
|
58
46
|
|
59
|
-
#
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
47
|
+
# Override Tilt::Template#render to check for
|
48
|
+
# data and raise an error if there isn't any.
|
49
|
+
#
|
50
|
+
# (see Tilt::Template#render)
|
51
|
+
def render(*args)
|
52
|
+
raise ArgumentError, "data must be set before rendering" if @data.nil?
|
53
|
+
super
|
64
54
|
end
|
65
|
-
alias :compress :render
|
66
|
-
alias :compile :render
|
67
55
|
|
68
56
|
protected
|
69
57
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
# Do whatever preparation is necessary to setup the underlying compression
|
78
|
-
# engine. Called immediately after template data is loaded. Instance
|
79
|
-
# variables set in this method are available when #compress is called.
|
80
|
-
def prepare
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
# Called when it's time to compress. Return the compressed data
|
85
|
-
# from this method.
|
86
|
-
def evaluate
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
# Like Kernel::require but issues a warning urging a manual require when
|
91
|
-
# running under a threaded environment.
|
92
|
-
def require_template_library(name)
|
93
|
-
if Thread.list.size > 1
|
94
|
-
warn "WARN: crush autoloading '#{name}' in a non thread-safe way; " +
|
95
|
-
"explicit require '#{name}' suggested."
|
96
|
-
end
|
97
|
-
require name
|
98
|
-
end
|
58
|
+
# Crush::Engines are usually very, very simple.
|
59
|
+
# There's no need for them to be required to
|
60
|
+
# implement #prepare.
|
61
|
+
def prepare
|
62
|
+
end
|
99
63
|
end
|
100
64
|
end
|