smurf 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +24 -0
- data/README.markdown +67 -0
- data/Rakefile +22 -0
- data/init.rb +1 -0
- data/install.rb +0 -0
- data/lib/smurf.rb +38 -0
- data/lib/smurf/javascript.rb +225 -0
- data/lib/smurf/stylesheet.rb +34 -0
- data/rails/init.rb +1 -0
- data/smurf.gemspec +42 -0
- data/test/rails/app/controllers/application.rb +2 -0
- data/test/rails/config/boot.rb +109 -0
- data/test/rails/config/database.yml +3 -0
- data/test/rails/config/environment.rb +24 -0
- data/test/rails/config/environments/test.rb +19 -0
- data/test/rails/config/routes.rb +5 -0
- data/test/rails/public/javascripts/cache/expected.js +2 -0
- data/test/rails/public/javascripts/testing.js +3 -0
- data/test/rails/public/stylesheets/bar.css +44 -0
- data/test/rails/public/stylesheets/cache/expected.css +1 -0
- data/test/rails/public/stylesheets/foo.css +48 -0
- data/test/smurf_test.rb +82 -0
- data/test/test_helper.rb +32 -0
- data/uninstall.rb +0 -0
- metadata +79 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
MIT License
|
2
|
+
--------------------------------------------------------------------------------
|
3
|
+
Copyright (c) 2008 Justin Knowlden
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person
|
6
|
+
obtaining a copy of this software and associated documentation
|
7
|
+
files (the "Software"), to deal in the Software without
|
8
|
+
restriction, including without limitation the rights to use,
|
9
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the
|
11
|
+
Software is furnished to do so, subject to the following
|
12
|
+
conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
19
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
21
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
22
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
23
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
24
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Smurf
|
2
|
+
|
3
|
+
Smurf is a Rails plugin that does Javascript and CSS minification the way you would expect. See, with Rails `2.x` we got this cool new `:cache` option on `javascript_include_tag` and `stylesheet_link_tag`, but no option for minifying the cached file(s).
|
4
|
+
|
5
|
+
Smurf ends that. Smurf - if installed and when caching is enabled for the environment - will nab the concatenated file content from Rails just before it saves it and minifies the content using either JSmin or a custom CSS compressor.
|
6
|
+
|
7
|
+
Some cool things about Smurf, which also allude to the reasons I wrote it:
|
8
|
+
|
9
|
+
* Smurf will only run when Rails needs to cache new files
|
10
|
+
* It will never run on its own
|
11
|
+
* It requires absolutely no configuration
|
12
|
+
* Other than installing it, you don't need to do anything
|
13
|
+
* It just gets out of your way
|
14
|
+
|
15
|
+
Smurf will work with any version of Rails `2.x`; including Rails `2.2.2`.
|
16
|
+
|
17
|
+
### JSmin
|
18
|
+
|
19
|
+
It's really an adaptation of Uladzislau Latynski's [jsmin.rb](http://javascript.crockford.com/jsmin.rb) port of Douglas Crockford's [jsmin.c](http://javascript.crockford.com/jsmin.c) library.
|
20
|
+
|
21
|
+
### Smurf CSS Compressor
|
22
|
+
|
23
|
+
The following are the rules I applied, gathered from various perusals around the Internet*s*
|
24
|
+
|
25
|
+
1. Replace consecutive whitespace characters with a single space
|
26
|
+
2. Remove whitespace around opening brackets
|
27
|
+
3. Remove whitespace in front of closing brackets
|
28
|
+
4. Remove the semi-colon just before the closing bracket
|
29
|
+
5. Remove comments between `/* ... */` - this could be a problem (esp. for CSS hacks)
|
30
|
+
6. Remove spaces around `;`, `:`, and `,` characters
|
31
|
+
7. Ensure whitespace between closing brackets and periods
|
32
|
+
|
33
|
+
## Installation
|
34
|
+
|
35
|
+
./script/plugin install git://github.com/thumblemonks/smurf.git
|
36
|
+
|
37
|
+
Then, wherever you define `javascript_include_tag` or `stylesheet_link_tag`, make sure to add the standard `:cache => true` or `:cache => 'some_bundle'` options.
|
38
|
+
|
39
|
+
Also make sure to at least have this setting in your production.rb:
|
40
|
+
|
41
|
+
config.action_controller.perform_caching = true
|
42
|
+
|
43
|
+
### Small suggestion
|
44
|
+
|
45
|
+
[bcarpenter](http://github.com/bcarpenter) reminded all of us that Rails will generate real files if you set `config.action_controller.perform_caching` to `true`. If you happen to do this while developing your fantastic Rails app you may also accidentally commit them to your development repository. This is not what you want as it can send you and your awesome developer friends down the wrong rabbit hole ... and then when you figure out the problem you may be understandably and misguidedly pissed at Smurf :)
|
46
|
+
|
47
|
+
[bcarpenter](http://github.com/bcarpenter) didn't seem too mad since he reached out to me (whew!) and suggested I add a little comment about making sure to ignore the generated cache files/directories in your SCM of choice. If you happen to be using git, be sure to do something to the effect of the following in your `.gitignore` file:
|
48
|
+
|
49
|
+
public/*/cache/*
|
50
|
+
|
51
|
+
## Testing
|
52
|
+
|
53
|
+
If you want to test Smurf and you don't want to test with the latest version of Rails, then do something like the following (using 2.2.2 as an example):
|
54
|
+
|
55
|
+
rake RAILS_GEM_VERSION=2.2.2
|
56
|
+
|
57
|
+
This is the mechanism I used for testing that Smurf works for all versions:
|
58
|
+
|
59
|
+
rake && rake RAILS_GEM_VERSION=2.2.2
|
60
|
+
|
61
|
+
## Meta
|
62
|
+
|
63
|
+
Author: Justin Knowlden <gus@thumblemonks.com>
|
64
|
+
|
65
|
+
Contributions from: Lance Ivy, Scott White, Daniel Schierbeck
|
66
|
+
|
67
|
+
See MIT-LICENSE for licensing information
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the load_model plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the smurf plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Smurf'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'smurf'
|
data/install.rb
ADDED
File without changes
|
data/lib/smurf.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'smurf/javascript'
|
2
|
+
require 'smurf/stylesheet'
|
3
|
+
|
4
|
+
if Rails.version =~ /^2\.2\./
|
5
|
+
# Support for Rails >= 2.2.x
|
6
|
+
module Smurf
|
7
|
+
|
8
|
+
module JavaScriptSources
|
9
|
+
private
|
10
|
+
def joined_contents; Smurf::Javascript.new(super).minified; end
|
11
|
+
end # JavaScriptSources
|
12
|
+
|
13
|
+
module StylesheetSources
|
14
|
+
private
|
15
|
+
def joined_contents; Smurf::Stylesheet.new(super).minified; end
|
16
|
+
end # StylesheetSources
|
17
|
+
|
18
|
+
end # ActionView::Helpers::AssetTagHelper::AssetTag
|
19
|
+
ActionView::Helpers::AssetTagHelper::JavaScriptSources.send(
|
20
|
+
:include, Smurf::JavaScriptSources)
|
21
|
+
ActionView::Helpers::AssetTagHelper::StylesheetSources.send(
|
22
|
+
:include, Smurf::StylesheetSources)
|
23
|
+
else
|
24
|
+
# Support for Rails <= 2.1.x
|
25
|
+
module ActionView::Helpers::AssetTagHelper
|
26
|
+
private
|
27
|
+
def join_asset_file_contents_with_minification(files)
|
28
|
+
content = join_asset_file_contents_without_minification(files)
|
29
|
+
if !files.grep(%r[/javascripts]).empty?
|
30
|
+
content = Smurf::Javascript.new(content).minified
|
31
|
+
elsif !files.grep(%r[/stylesheets]).empty?
|
32
|
+
content = Smurf::Stylesheet.new(content).minified
|
33
|
+
end
|
34
|
+
content
|
35
|
+
end
|
36
|
+
alias_method_chain :join_asset_file_contents, :minification
|
37
|
+
end # ActionView::Helpers::AssetTagHelper
|
38
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
# Author: Justin Knowlden
|
2
|
+
# Adaption of jsmin.rb published by Uladzislau Latynski
|
3
|
+
#
|
4
|
+
# -------------------
|
5
|
+
# jsmin.rb 2007-07-20
|
6
|
+
# Author: Uladzislau Latynski
|
7
|
+
# This work is a translation from C to Ruby of jsmin.c published by
|
8
|
+
# Douglas Crockford. Permission is hereby granted to use the Ruby
|
9
|
+
# version under the same conditions as the jsmin.c on which it is
|
10
|
+
# based.
|
11
|
+
#
|
12
|
+
# /* jsmin.c
|
13
|
+
# 2003-04-21
|
14
|
+
#
|
15
|
+
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
16
|
+
#
|
17
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
18
|
+
# this software and associated documentation files (the "Software"), to deal in
|
19
|
+
# the Software without restriction, including without limitation the rights to
|
20
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
21
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
22
|
+
# so, subject to the following conditions:
|
23
|
+
#
|
24
|
+
# The above copyright notice and this permission notice shall be included in all
|
25
|
+
# copies or substantial portions of the Software.
|
26
|
+
#
|
27
|
+
# The Software shall be used for Good, not Evil.
|
28
|
+
#
|
29
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
30
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
31
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
32
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
33
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
34
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
35
|
+
# SOFTWARE.
|
36
|
+
|
37
|
+
require 'stringio'
|
38
|
+
|
39
|
+
module Smurf
|
40
|
+
class Javascript
|
41
|
+
EOF = -1
|
42
|
+
|
43
|
+
@theA = ""
|
44
|
+
@theB = ""
|
45
|
+
|
46
|
+
def initialize(content)
|
47
|
+
@input = StringIO.new(content)
|
48
|
+
@output = StringIO.new
|
49
|
+
jsmin
|
50
|
+
end
|
51
|
+
|
52
|
+
def minified
|
53
|
+
@output.rewind
|
54
|
+
@output.read
|
55
|
+
end
|
56
|
+
|
57
|
+
# isAlphanum -- return true if the character is a letter, digit,
|
58
|
+
# underscore, # dollar sign, or non-ASCII character
|
59
|
+
def isAlphanum(c)
|
60
|
+
return false if !c || c == EOF
|
61
|
+
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
62
|
+
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
63
|
+
c == '\\' || Array(c[0].bytes).first > 126)
|
64
|
+
end
|
65
|
+
|
66
|
+
# get -- return the next character from stdin. Watch out for lookahead. If
|
67
|
+
# the character is a control character, translate it to a space or linefeed.
|
68
|
+
def get()
|
69
|
+
c = @input.getc
|
70
|
+
return EOF if(!c)
|
71
|
+
c = c.chr
|
72
|
+
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
|
73
|
+
return "\n" if (c == "\r")
|
74
|
+
return " "
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get the next character without getting it.
|
78
|
+
def peek()
|
79
|
+
lookaheadChar = @input.getc
|
80
|
+
@input.ungetc(lookaheadChar)
|
81
|
+
return lookaheadChar.chr
|
82
|
+
end
|
83
|
+
|
84
|
+
# mynext -- get the next character, excluding comments.
|
85
|
+
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
86
|
+
def mynext()
|
87
|
+
c = get
|
88
|
+
if (c == "/")
|
89
|
+
if(peek == "/")
|
90
|
+
while(true)
|
91
|
+
c = get
|
92
|
+
if (c <= "\n")
|
93
|
+
return c
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
if(peek == "*")
|
98
|
+
get
|
99
|
+
while(true)
|
100
|
+
case get
|
101
|
+
when "*"
|
102
|
+
if (peek == "/")
|
103
|
+
get
|
104
|
+
return " "
|
105
|
+
end
|
106
|
+
when EOF
|
107
|
+
raise "Unterminated comment"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return c
|
113
|
+
end
|
114
|
+
|
115
|
+
# action -- do something! What you do is determined by the argument: 1
|
116
|
+
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
117
|
+
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
118
|
+
# single character. Wow! action recognizes a regular expression if it is
|
119
|
+
# preceded by ( or , or =.
|
120
|
+
def action(a)
|
121
|
+
if(a==1)
|
122
|
+
@output.write @theA
|
123
|
+
end
|
124
|
+
if(a==1 || a==2)
|
125
|
+
@theA = @theB
|
126
|
+
if (@theA == "\'" || @theA == "\"")
|
127
|
+
while (true)
|
128
|
+
@output.write @theA
|
129
|
+
@theA = get
|
130
|
+
break if (@theA == @theB)
|
131
|
+
raise "Unterminated string literal" if (@theA <= "\n")
|
132
|
+
if (@theA == "\\")
|
133
|
+
# allow multi-line strings if each line is terminated by \\n (or \\r\n)
|
134
|
+
if ["\r", "\n"].include? peek
|
135
|
+
get # throw away the line ending
|
136
|
+
get if ["\r", "\n"].include? peek
|
137
|
+
else
|
138
|
+
@output.write @theA
|
139
|
+
end
|
140
|
+
@theA = get
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
if(a==1 || a==2 || a==3)
|
146
|
+
@theB = mynext
|
147
|
+
if (@theB == "/" && (@theA == "(" || @theA == "," || @theA == "=" ||
|
148
|
+
@theA == ":" || @theA == "[" || @theA == "!" ||
|
149
|
+
@theA == "&" || @theA == "|" || @theA == "?" ||
|
150
|
+
@theA == "{" || @theA == "}" || @theA == ";" ||
|
151
|
+
@theA == "\n"))
|
152
|
+
@output.write @theA
|
153
|
+
@output.write @theB
|
154
|
+
while (true)
|
155
|
+
@theA = get
|
156
|
+
if (@theA == "/")
|
157
|
+
break
|
158
|
+
elsif (@theA == "\\")
|
159
|
+
@output.write @theA
|
160
|
+
@theA = get
|
161
|
+
elsif (@theA <= "\n")
|
162
|
+
raise "Unterminated RegExp Literal"
|
163
|
+
end
|
164
|
+
@output.write @theA
|
165
|
+
end
|
166
|
+
@theB = mynext
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# jsmin -- Copy the input to the output, deleting the characters which are
|
172
|
+
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
173
|
+
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
174
|
+
# Most spaces and linefeeds will be removed.
|
175
|
+
def jsmin
|
176
|
+
@theA = "\n"
|
177
|
+
action(3)
|
178
|
+
while (@theA != EOF)
|
179
|
+
case @theA
|
180
|
+
when " "
|
181
|
+
if (isAlphanum(@theB))
|
182
|
+
action(1)
|
183
|
+
else
|
184
|
+
action(2)
|
185
|
+
end
|
186
|
+
when "\n"
|
187
|
+
case (@theB)
|
188
|
+
when "{","[","(","+","-"
|
189
|
+
action(1)
|
190
|
+
when " "
|
191
|
+
action(3)
|
192
|
+
else
|
193
|
+
if (isAlphanum(@theB))
|
194
|
+
action(1)
|
195
|
+
else
|
196
|
+
action(2)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
else
|
200
|
+
case (@theB)
|
201
|
+
when " "
|
202
|
+
if (isAlphanum(@theA))
|
203
|
+
action(1)
|
204
|
+
else
|
205
|
+
action(3)
|
206
|
+
end
|
207
|
+
when "\n"
|
208
|
+
case (@theA)
|
209
|
+
when "}","]",")","+","-","\"","\\", "'", '"'
|
210
|
+
action(1)
|
211
|
+
else
|
212
|
+
if (isAlphanum(@theA))
|
213
|
+
action(1)
|
214
|
+
else
|
215
|
+
action(3)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
else
|
219
|
+
action(1)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end # Javascript
|
225
|
+
end # Smurf
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Smurf
|
2
|
+
class Stylesheet
|
3
|
+
def initialize(content)
|
4
|
+
@content = content.nil? ? nil : minify(content)
|
5
|
+
end
|
6
|
+
|
7
|
+
def minified; @content; end
|
8
|
+
|
9
|
+
# TODO: deal with string values better (urls, content blocks, etc.)
|
10
|
+
def minify(content)
|
11
|
+
class << content; include Minifier; end
|
12
|
+
content.compress_whitespace.remove_comments.remove_spaces_outside_block.
|
13
|
+
remove_spaces_inside_block.trim_last_semicolon.strip
|
14
|
+
end
|
15
|
+
|
16
|
+
module Minifier
|
17
|
+
# .*? is a non-greedy match on anything
|
18
|
+
def compress_whitespace; compress!(/\s+/, ' '); end
|
19
|
+
def remove_comments; compress!(/\/\*.*?\*\/\s?/, ''); end
|
20
|
+
def remove_spaces_outside_block
|
21
|
+
compress!(/(\A|\})(.*?)\{/) { |m| m.gsub(/\s?([}{,])\s?/, '\1') }
|
22
|
+
end
|
23
|
+
def remove_spaces_inside_block
|
24
|
+
compress!(/\{(.*?)(?=\})/) do |m|
|
25
|
+
# remove spaces in the labels/attributes
|
26
|
+
m.gsub(/(?:\A|\s*;)(.*?)(?::\s*|\z)/) { |n| n.gsub(/\s/, '') }.strip
|
27
|
+
end
|
28
|
+
end
|
29
|
+
def trim_last_semicolon; compress!(/;(?=\})/, ''); end
|
30
|
+
private
|
31
|
+
def compress!(*args, &block) gsub!(*args, &block) || self; end
|
32
|
+
end
|
33
|
+
end # Stylesheet
|
34
|
+
end # Smurf
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'smurf'
|
data/smurf.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "smurf"
|
3
|
+
s.summary = "Rails plugin to automatically minify JS and CSS when their bundles get cached"
|
4
|
+
s.description = "Rails plugin to automatically minify JS and CSS when their bundles get cached. Send in those patches!"
|
5
|
+
s.version = "1.0.0"
|
6
|
+
s.authors = ["Justin Knowlden"]
|
7
|
+
s.email = %w[gus@thumblemonks.com]
|
8
|
+
s.homepage = "http://github.com/thumblemonks/smurf"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
|
11
|
+
s.post_install_message = %q{Choosy Gargamels choose Thumble Monks.}
|
12
|
+
|
13
|
+
s.files = %w[
|
14
|
+
MIT-LICENSE
|
15
|
+
README.markdown
|
16
|
+
Rakefile
|
17
|
+
init.rb
|
18
|
+
install.rb
|
19
|
+
lib/smurf.rb
|
20
|
+
lib/smurf/javascript.rb
|
21
|
+
lib/smurf/stylesheet.rb
|
22
|
+
rails/init.rb
|
23
|
+
smurf.gemspec
|
24
|
+
uninstall.rb
|
25
|
+
]
|
26
|
+
|
27
|
+
s.test_files = %w[
|
28
|
+
test/rails/app/controllers/application.rb
|
29
|
+
test/rails/config/boot.rb
|
30
|
+
test/rails/config/database.yml
|
31
|
+
test/rails/config/environment.rb
|
32
|
+
test/rails/config/environments/test.rb
|
33
|
+
test/rails/config/routes.rb
|
34
|
+
test/rails/public/javascripts/cache/expected.js
|
35
|
+
test/rails/public/javascripts/testing.js
|
36
|
+
test/rails/public/stylesheets/bar.css
|
37
|
+
test/rails/public/stylesheets/cache/expected.css
|
38
|
+
test/rails/public/stylesheets/foo.css
|
39
|
+
test/smurf_test.rb
|
40
|
+
test/test_helper.rb
|
41
|
+
]
|
42
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Don't change this file!
|
2
|
+
# Configure your app in config/environment.rb and config/environments/*.rb
|
3
|
+
|
4
|
+
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
5
|
+
|
6
|
+
module Rails
|
7
|
+
class << self
|
8
|
+
def boot!
|
9
|
+
unless booted?
|
10
|
+
preinitialize
|
11
|
+
pick_boot.run
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def booted?
|
16
|
+
defined? Rails::Initializer
|
17
|
+
end
|
18
|
+
|
19
|
+
def pick_boot
|
20
|
+
(vendor_rails? ? VendorBoot : GemBoot).new
|
21
|
+
end
|
22
|
+
|
23
|
+
def vendor_rails?
|
24
|
+
File.exist?("#{RAILS_ROOT}/vendor/rails")
|
25
|
+
end
|
26
|
+
|
27
|
+
def preinitialize
|
28
|
+
load(preinitializer_path) if File.exist?(preinitializer_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
def preinitializer_path
|
32
|
+
"#{RAILS_ROOT}/config/preinitializer.rb"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Boot
|
37
|
+
def run
|
38
|
+
load_initializer
|
39
|
+
Rails::Initializer.run(:set_load_path)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class VendorBoot < Boot
|
44
|
+
def load_initializer
|
45
|
+
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
|
46
|
+
Rails::Initializer.run(:install_gem_spec_stubs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class GemBoot < Boot
|
51
|
+
def load_initializer
|
52
|
+
self.class.load_rubygems
|
53
|
+
load_rails_gem
|
54
|
+
require 'initializer'
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_rails_gem
|
58
|
+
if version = self.class.gem_version
|
59
|
+
gem 'rails', version
|
60
|
+
else
|
61
|
+
gem 'rails'
|
62
|
+
end
|
63
|
+
rescue Gem::LoadError => load_error
|
64
|
+
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
def rubygems_version
|
70
|
+
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
|
71
|
+
end
|
72
|
+
|
73
|
+
def gem_version
|
74
|
+
if defined? RAILS_GEM_VERSION
|
75
|
+
RAILS_GEM_VERSION
|
76
|
+
elsif ENV.include?('RAILS_GEM_VERSION')
|
77
|
+
ENV['RAILS_GEM_VERSION']
|
78
|
+
else
|
79
|
+
parse_gem_version(read_environment_rb)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_rubygems
|
84
|
+
require 'rubygems'
|
85
|
+
min_version = '1.1.1'
|
86
|
+
unless rubygems_version >= min_version
|
87
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
|
91
|
+
rescue LoadError
|
92
|
+
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_gem_version(text)
|
97
|
+
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def read_environment_rb
|
102
|
+
File.read("#{RAILS_ROOT}/config/environment.rb")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# All that for this:
|
109
|
+
Rails.boot!
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file
|
2
|
+
|
3
|
+
# Uncomment below to force Rails into production mode when
|
4
|
+
# you don't control web/app server and can't set it the proper way
|
5
|
+
# ENV['RAILS_ENV'] ||= 'production'
|
6
|
+
|
7
|
+
# Specifies gem version of Rails to use when vendor/rails is not present
|
8
|
+
unless defined? RAILS_GEM_VERSION
|
9
|
+
RAILS_GEM_VERSION = (ENV['RAILS_GEM_VERSION'] || '2.3.2')
|
10
|
+
end
|
11
|
+
|
12
|
+
# Bootstrap the Rails environment, frameworks, and default configuration
|
13
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
14
|
+
|
15
|
+
Rails::Initializer.run do |config|
|
16
|
+
config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails',
|
17
|
+
:source => 'http://gems.github.com'
|
18
|
+
config.gem 'sqlite3-ruby', :lib => 'sqlite3'
|
19
|
+
|
20
|
+
config.action_controller.session = {
|
21
|
+
:session_key => '_smurf_session',
|
22
|
+
:secret => '731d6426b731d6426b731d6426b731d6426b731d6426b731d6426b731d6426b'
|
23
|
+
}
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
2
|
+
|
3
|
+
# The test environment is used exclusively to run your application's
|
4
|
+
# test suite. You never need to work with it otherwise. Remember that
|
5
|
+
# your test database is "scratch space" for the test suite and is wiped
|
6
|
+
# and recreated between test runs. Don't rely on the data there!
|
7
|
+
config.cache_classes = true
|
8
|
+
|
9
|
+
# Log error messages when you accidentally call methods on nil.
|
10
|
+
config.whiny_nils = true
|
11
|
+
|
12
|
+
# Show full error reports and disable caching
|
13
|
+
config.action_controller.consider_all_requests_local = true
|
14
|
+
config.action_controller.perform_caching = false
|
15
|
+
|
16
|
+
# Tell ActionMailer not to deliver emails to the real world.
|
17
|
+
# The :test delivery method accumulates sent emails in the
|
18
|
+
# ActionMailer::Base.deliveries array.
|
19
|
+
config.action_mailer.delivery_method = :test
|
@@ -0,0 +1,44 @@
|
|
1
|
+
abbr, acronym {
|
2
|
+
border: 0;
|
3
|
+
font-variant: normal;
|
4
|
+
}
|
5
|
+
|
6
|
+
sup {
|
7
|
+
vertical-align: text-top;
|
8
|
+
}
|
9
|
+
/*
|
10
|
+
hello, my name is sam
|
11
|
+
*/
|
12
|
+
sub {
|
13
|
+
vertical-align: text-bottom;
|
14
|
+
}
|
15
|
+
|
16
|
+
input, textarea, select{
|
17
|
+
font-family: inherit;
|
18
|
+
font-size: inherit;
|
19
|
+
font-weight: inherit;
|
20
|
+
}
|
21
|
+
|
22
|
+
input, textarea, select {
|
23
|
+
*font-size: 100%;
|
24
|
+
}
|
25
|
+
|
26
|
+
legend { color:#000; }
|
27
|
+
|
28
|
+
del, ins {
|
29
|
+
text-decoration:none;
|
30
|
+
}
|
31
|
+
|
32
|
+
smurf {
|
33
|
+
content: "pa pa";
|
34
|
+
}
|
35
|
+
|
36
|
+
.smurf :link li {
|
37
|
+
color:blue;
|
38
|
+
}
|
39
|
+
|
40
|
+
smurf #smurf , :smurf .smurf {
|
41
|
+
color : black;
|
42
|
+
}
|
43
|
+
|
44
|
+
smurfdom { papa: smurf }
|
@@ -0,0 +1 @@
|
|
1
|
+
html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{*font-size:100%}legend{color:#000}del,ins{text-decoration:none}smurf{content:"pa pa"}.smurf :link li{color:blue}smurf #smurf,:smurf .smurf{color:black}smurfdom{papa:smurf}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
|
3
|
+
Code licensed under the BSD License:
|
4
|
+
http://developer.yahoo.net/yui/license.txt
|
5
|
+
version: 2.6.0
|
6
|
+
*/
|
7
|
+
|
8
|
+
html {
|
9
|
+
color: #000;
|
10
|
+
background: #FFF;
|
11
|
+
}
|
12
|
+
|
13
|
+
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td {
|
14
|
+
margin: 0;
|
15
|
+
padding: 0;
|
16
|
+
}
|
17
|
+
|
18
|
+
table {
|
19
|
+
border-collapse: collapse;
|
20
|
+
border-spacing: 0;
|
21
|
+
}
|
22
|
+
|
23
|
+
fieldset, img {
|
24
|
+
border: 0;
|
25
|
+
}
|
26
|
+
|
27
|
+
address, caption, cite, code, dfn, em, strong, th, var {
|
28
|
+
font-style: normal;
|
29
|
+
font-weight: normal;
|
30
|
+
}
|
31
|
+
|
32
|
+
li {
|
33
|
+
list-style: none;
|
34
|
+
}
|
35
|
+
|
36
|
+
caption, th {
|
37
|
+
text-align: left;
|
38
|
+
}
|
39
|
+
|
40
|
+
h1, h2, h3, h4, h5, h6 {
|
41
|
+
font-size: 100%;
|
42
|
+
font-weight: normal;
|
43
|
+
}
|
44
|
+
|
45
|
+
q:before, q:after {
|
46
|
+
content: '';
|
47
|
+
}
|
48
|
+
|
data/test/smurf_test.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class SmurfTest < Test::Unit::TestCase
|
4
|
+
include ActionView::Helpers::TagHelper
|
5
|
+
include ActionView::Helpers::AssetTagHelper
|
6
|
+
|
7
|
+
# Javascript
|
8
|
+
|
9
|
+
context "when caching on for javascript" do
|
10
|
+
setup do
|
11
|
+
ActionController::Base.stubs(:perform_caching).returns(true)
|
12
|
+
javascript_include_tag('testing.js', :cache => 'cache/actual')
|
13
|
+
end
|
14
|
+
|
15
|
+
should_have_same_contents('javascripts/cache/expected.js',
|
16
|
+
'javascripts/cache/actual.js')
|
17
|
+
end # when caching on for javascript
|
18
|
+
|
19
|
+
context "minifying multi-line strings in javascript" do
|
20
|
+
setup do
|
21
|
+
input = StringIO.new()
|
22
|
+
input.puts("var foo='bar \\")
|
23
|
+
input.puts(" bar \\")
|
24
|
+
input.puts(" baz';")
|
25
|
+
input.rewind
|
26
|
+
@content = input.read
|
27
|
+
end
|
28
|
+
|
29
|
+
should "not affect the string" do
|
30
|
+
expected = "\n" + @content.gsub(/\\?\r?\n/, '')
|
31
|
+
assert_equal expected, Smurf::Javascript.new(@content).minified
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Stylesheet
|
36
|
+
|
37
|
+
context "when caching on for stylesheets" do
|
38
|
+
setup do
|
39
|
+
ActionController::Base.stubs(:perform_caching).returns(true)
|
40
|
+
stylesheet_link_tag('foo', 'bar', :cache => 'cache/actual')
|
41
|
+
end
|
42
|
+
|
43
|
+
should_have_same_contents('stylesheets/cache/expected.css',
|
44
|
+
'stylesheets/cache/actual.css')
|
45
|
+
end # when caching on for stylesheets
|
46
|
+
|
47
|
+
context "minifying a non-existent pattern in a stylesheet" do
|
48
|
+
setup {@himom = "hi{mom:super-awesome}"}
|
49
|
+
|
50
|
+
# Thanks to someone named Niko for finding this
|
51
|
+
should "succeed for removing comments" do
|
52
|
+
actual = "hi { mom: super-awesome; } "
|
53
|
+
assert_equal @himom, Smurf::Stylesheet.new(actual).minified
|
54
|
+
end
|
55
|
+
|
56
|
+
should "succeed when no spaces to compress" do
|
57
|
+
actual = @himom
|
58
|
+
assert_equal @himom, Smurf::Stylesheet.new(actual).minified
|
59
|
+
end
|
60
|
+
|
61
|
+
should "succeed when no outside or inside blocks" do
|
62
|
+
# nothing outside, means nothing inside. they are complementary
|
63
|
+
actual = "how-did: this-happen; typo: maybe;}"
|
64
|
+
expected = "how-did: this-happen; typo: maybe}"
|
65
|
+
assert_equal expected, Smurf::Stylesheet.new(actual).minified
|
66
|
+
end
|
67
|
+
|
68
|
+
should "succeed when no last semi-colon in block" do
|
69
|
+
actual = "hi { mom: super-awesome } "
|
70
|
+
assert_equal @himom, Smurf::Stylesheet.new(actual).minified
|
71
|
+
end
|
72
|
+
|
73
|
+
should "succeed across all parsers when no content provided" do
|
74
|
+
actual = ""
|
75
|
+
assert_equal "", Smurf::Stylesheet.new(actual).minified
|
76
|
+
end
|
77
|
+
|
78
|
+
should "succeed if nil provided" do
|
79
|
+
assert_nil Smurf::Stylesheet.new(nil).minified
|
80
|
+
end
|
81
|
+
end # minifying a non-existent pattern
|
82
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
ENV["RAILS_ROOT"] = File.expand_path(File.join(File.dirname(__FILE__), 'rails'))
|
3
|
+
require File.expand_path(File.join(ENV["RAILS_ROOT"], 'config', 'environment'))
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'init'))
|
5
|
+
|
6
|
+
require 'test_help'
|
7
|
+
require 'ruby-debug'
|
8
|
+
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
artifacts = Dir.glob(File.join(asset_path, '**', 'cache', 'actual.*'))
|
13
|
+
FileUtils.rm(artifacts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.should_have_same_contents(expected_path, actual_path)
|
17
|
+
should "have the same file contents as #{expected_path}" do
|
18
|
+
expected = read_asset_file(expected_path)
|
19
|
+
actual = read_asset_file(actual_path)
|
20
|
+
assert_equal expected, actual
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def asset_path
|
26
|
+
File.join(File.join(ENV["RAILS_ROOT"], 'public'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def read_asset_file(relative_path)
|
30
|
+
File.read(File.join(asset_path, relative_path))
|
31
|
+
end
|
32
|
+
end
|
data/uninstall.rb
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smurf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Knowlden
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-02 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Rails plugin to automatically minify JS and CSS when their bundles get cached. Send in those patches!
|
17
|
+
email:
|
18
|
+
- gus@thumblemonks.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.markdown
|
28
|
+
- Rakefile
|
29
|
+
- init.rb
|
30
|
+
- install.rb
|
31
|
+
- lib/smurf.rb
|
32
|
+
- lib/smurf/javascript.rb
|
33
|
+
- lib/smurf/stylesheet.rb
|
34
|
+
- rails/init.rb
|
35
|
+
- smurf.gemspec
|
36
|
+
- uninstall.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/thumblemonks/smurf
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message: Choosy Gargamels choose Thumble Monks.
|
42
|
+
rdoc_options:
|
43
|
+
- --inline-source
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Rails plugin to automatically minify JS and CSS when their bundles get cached
|
66
|
+
test_files:
|
67
|
+
- test/rails/app/controllers/application.rb
|
68
|
+
- test/rails/config/boot.rb
|
69
|
+
- test/rails/config/database.yml
|
70
|
+
- test/rails/config/environment.rb
|
71
|
+
- test/rails/config/environments/test.rb
|
72
|
+
- test/rails/config/routes.rb
|
73
|
+
- test/rails/public/javascripts/cache/expected.js
|
74
|
+
- test/rails/public/javascripts/testing.js
|
75
|
+
- test/rails/public/stylesheets/bar.css
|
76
|
+
- test/rails/public/stylesheets/cache/expected.css
|
77
|
+
- test/rails/public/stylesheets/foo.css
|
78
|
+
- test/smurf_test.rb
|
79
|
+
- test/test_helper.rb
|