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