dasch-smurf 1.0.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/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,59 @@
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
+ ## Testing and Other Stuff
44
+
45
+ If you want to test Smurf and you don't want to test with the latest version of Rails as of this writing (2.2.2), then do something like the following:
46
+
47
+ rake RAILS_GEM_VERSION=2.1.2
48
+
49
+ This is the mechanism I used for testing that Smurf works for all versions:
50
+
51
+ rake && rake RAILS_GEM_VERSION=2.1.2
52
+
53
+ ## Contact
54
+
55
+ Justin Knowlden <gus@gusg.us>
56
+
57
+ ## License
58
+
59
+ See MIT-LICENSE
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
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
data/config/boot.rb ADDED
@@ -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,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ dbfile: ":memory:" # db/test.db
@@ -0,0 +1,74 @@
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.2.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
+ # Settings in config/environments/* take precedence over those specified here.
17
+ # Application configuration should go into files in config/initializers
18
+ # -- all .rb files in that directory are automatically loaded.
19
+ # See Rails::Configuration for more options.
20
+
21
+ # Skip frameworks you're not going to use. To use Rails without a database
22
+ # you must remove the Active Record framework.
23
+ # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
24
+
25
+ # Specify gems that this application depends on.
26
+ # They can then be installed with "rake gems:install" on new installations.
27
+ # config.gem "bj"
28
+ # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
29
+ # config.gem "aws-s3", :lib => "aws/s3"
30
+ config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails',
31
+ :source => 'http://gems.github.com'
32
+ config.gem 'sqlite3-ruby', :lib => 'sqlite3'
33
+
34
+ # Only load the plugins named here, in the order given. By default, all plugins
35
+ # in vendor/plugins are loaded in alphabetical order.
36
+ # :all can be used as a placeholder for all plugins not explicitly named
37
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
38
+
39
+ # Add additional load paths for your own custom dirs
40
+ # config.load_paths += %W( #{RAILS_ROOT}/extras )
41
+
42
+ # Force all environments to use the same logger level
43
+ # (by default production uses :info, the others :debug)
44
+ # config.log_level = :debug
45
+
46
+ # Make Time.zone default to the specified zone, and make Active Record store time values
47
+ # in the database in UTC, and return them converted to the specified local zone.
48
+ # Run "rake -D time" for a list of tasks for finding time zone names. Comment line to use default local time.
49
+ # config.time_zone = ENV['TZ'] = 'UTC'
50
+
51
+ # Your secret key for verifying cookie session data integrity.
52
+ # If you change this key, all old sessions will become invalid!
53
+ # Make sure the secret is at least 30 characters and all random,
54
+ # no regular words or you'll be exposed to dictionary attacks.
55
+ # config.action_controller.session = {
56
+ # :session_key => '_load_model_session',
57
+ # :secret => '731d6426b38a848657211af3650ea99dc064a830ec15fd20565d71ba62498382132872b2d9b549eeb5a016025c119eb821d8e66794cd380888120aa0b857386d'
58
+ # }
59
+
60
+ # Use the database for sessions instead of the cookie-based default,
61
+ # which shouldn't be used to store highly confidential information
62
+ # (create the session table with "rake db:sessions:create")
63
+ # config.action_controller.session_store = :active_record_store
64
+
65
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
66
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
67
+ # like if you have constraints or database-specific column types
68
+ # config.active_record.schema_format = :sql
69
+
70
+ # Activate observers that should always be running
71
+ # config.active_record.observers = :cacher, :garbage_collector
72
+ end
73
+
74
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'init'))
@@ -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
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect ':controller/service.wsdl', :action => 'wsdl'
3
+ map.connect ':controller/:action/:id.:format'
4
+ map.connect ':controller/:action/:id'
5
+ 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,219 @@
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 == '\\' || c[0] > 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
+ @output.write @theA
134
+ @theA = get
135
+ end
136
+ end
137
+ end
138
+ end
139
+ if(a==1 || a==2 || a==3)
140
+ @theB = mynext
141
+ if (@theB == "/" && (@theA == "(" || @theA == "," || @theA == "=" ||
142
+ @theA == ":" || @theA == "[" || @theA == "!" ||
143
+ @theA == "&" || @theA == "|" || @theA == "?" ||
144
+ @theA == "{" || @theA == "}" || @theA == ";" ||
145
+ @theA == "\n"))
146
+ @output.write @theA
147
+ @output.write @theB
148
+ while (true)
149
+ @theA = get
150
+ if (@theA == "/")
151
+ break
152
+ elsif (@theA == "\\")
153
+ @output.write @theA
154
+ @theA = get
155
+ elsif (@theA <= "\n")
156
+ raise "Unterminated RegExp Literal"
157
+ end
158
+ @output.write @theA
159
+ end
160
+ @theB = mynext
161
+ end
162
+ end
163
+ end
164
+
165
+ # jsmin -- Copy the input to the output, deleting the characters which are
166
+ # insignificant to JavaScript. Comments will be removed. Tabs will be
167
+ # replaced with spaces. Carriage returns will be replaced with linefeeds.
168
+ # Most spaces and linefeeds will be removed.
169
+ def jsmin
170
+ @theA = "\n"
171
+ action(3)
172
+ while (@theA != EOF)
173
+ case @theA
174
+ when " "
175
+ if (isAlphanum(@theB))
176
+ action(1)
177
+ else
178
+ action(2)
179
+ end
180
+ when "\n"
181
+ case (@theB)
182
+ when "{","[","(","+","-"
183
+ action(1)
184
+ when " "
185
+ action(3)
186
+ else
187
+ if (isAlphanum(@theB))
188
+ action(1)
189
+ else
190
+ action(2)
191
+ end
192
+ end
193
+ else
194
+ case (@theB)
195
+ when " "
196
+ if (isAlphanum(@theA))
197
+ action(1)
198
+ else
199
+ action(3)
200
+ end
201
+ when "\n"
202
+ case (@theA)
203
+ when "}","]",")","+","-","\"","\\", "'", '"'
204
+ action(1)
205
+ else
206
+ if (isAlphanum(@theA))
207
+ action(1)
208
+ else
209
+ action(3)
210
+ end
211
+ end
212
+ else
213
+ action(1)
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end # Javascript
219
+ 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
@@ -0,0 +1,2 @@
1
+
2
+ function foo(){puts"Hello, world"}
@@ -0,0 +1,3 @@
1
+ function foo() {
2
+ puts "Hello, world"
3
+ }
@@ -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/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'smurf'
data/smurf.gemspec ADDED
@@ -0,0 +1,35 @@
1
+
2
+ Gem::Specification.new do |s|
3
+ s.name = "smurf"
4
+ s.summary = "Rails plugin to automatically minify JS and CSS when their bundles get cached"
5
+ s.version = "1.0.0"
6
+ s.authors = ["Justin Knowlden"]
7
+ s.homepage = "http://github.com/thumblemonks/smurf"
8
+ s.files = ["config/boot.rb",
9
+ "config/routes.rb",
10
+ "config/environments/test.rb",
11
+ "config/database.yml",
12
+ "config/environment.rb",
13
+ "init.rb",
14
+ "install.rb",
15
+ "uninstall.rb",
16
+ "rails/init.rb",
17
+ "Rakefile",
18
+ "README.markdown",
19
+ "smurf.gemspec",
20
+ "lib/smurf/stylesheet.rb",
21
+ "lib/smurf/javascript.rb",
22
+ "lib/smurf.rb",
23
+ "MIT-LICENSE"]
24
+ s.test_files = ["app/controllers/application.rb",
25
+ "public/stylesheets/bar.css",
26
+ "public/stylesheets/cache",
27
+ "public/stylesheets/cache/expected.css",
28
+ "public/stylesheets/foo.css",
29
+ "public/javascripts",
30
+ "public/javascripts/cache",
31
+ "public/javascripts/cache/expected.js",
32
+ "public/javascripts/testing.js",
33
+ "test/smurf_test.rb",
34
+ "test/test_helper.rb"]
35
+ end
@@ -0,0 +1,64 @@
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
+ context "when caching on for javascript" do
8
+ setup do
9
+ ActionController::Base.stubs(:perform_caching).returns(true)
10
+ javascript_include_tag('testing.js', :cache => 'cache/actual')
11
+ end
12
+
13
+ should_have_same_contents('javascripts/cache/expected.js',
14
+ 'javascripts/cache/actual.js')
15
+ end # when caching on for javascript
16
+
17
+ # Stylesheet
18
+
19
+ context "when caching on for stylesheets" do
20
+ setup do
21
+ ActionController::Base.stubs(:perform_caching).returns(true)
22
+ stylesheet_link_tag('foo', 'bar', :cache => 'cache/actual')
23
+ end
24
+
25
+ should_have_same_contents('stylesheets/cache/expected.css',
26
+ 'stylesheets/cache/actual.css')
27
+ end # when caching on for stylesheets
28
+
29
+ context "minifying a non-existent pattern in a stylesheet" do
30
+ setup {@himom = "hi{mom:super-awesome}"}
31
+
32
+ # Thanks to someone named Niko for finding this
33
+ should "succeed for removing comments" do
34
+ actual = "hi { mom: super-awesome; } "
35
+ assert_equal @himom, Smurf::Stylesheet.new(actual).minified
36
+ end
37
+
38
+ should "succeed when no spaces to compress" do
39
+ actual = @himom
40
+ assert_equal @himom, Smurf::Stylesheet.new(actual).minified
41
+ end
42
+
43
+ should "succeed when no outside or inside blocks" do
44
+ # nothing outside, means nothing inside. they are complementary
45
+ actual = "how-did: this-happen; typo: maybe;}"
46
+ expected = "how-did: this-happen; typo: maybe}"
47
+ assert_equal expected, Smurf::Stylesheet.new(actual).minified
48
+ end
49
+
50
+ should "succeed when no last semi-colon in block" do
51
+ actual = "hi { mom: super-awesome } "
52
+ assert_equal @himom, Smurf::Stylesheet.new(actual).minified
53
+ end
54
+
55
+ should "succeed across all parsers when no content provided" do
56
+ actual = ""
57
+ assert_equal "", Smurf::Stylesheet.new(actual).minified
58
+ end
59
+
60
+ should "succeed if nil provided" do
61
+ assert_nil Smurf::Stylesheet.new(nil).minified
62
+ end
63
+ end # minifying a non-existent pattern
64
+ end
@@ -0,0 +1,31 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
3
+ # load(File.dirname(__FILE__) + "/../db/schema.rb")
4
+
5
+ require 'test_help'
6
+ require 'ruby-debug'
7
+
8
+ class Test::Unit::TestCase
9
+
10
+ def teardown
11
+ artifacts = Dir.glob(File.join(asset_path, '**', 'cache', 'actual.*'))
12
+ FileUtils.rm(artifacts)
13
+ end
14
+
15
+ def self.should_have_same_contents(expected_path, actual_path)
16
+ should "have the same file contents as #{expected_path}" do
17
+ expected = read_asset_file(expected_path)
18
+ actual = read_asset_file(actual_path)
19
+ assert_equal expected, actual
20
+ end
21
+ end
22
+
23
+ private
24
+ def asset_path
25
+ File.join(File.dirname(__FILE__), '..', 'public')
26
+ end
27
+
28
+ def read_asset_file(relative_path)
29
+ File.read(File.join(asset_path, relative_path))
30
+ end
31
+ end
data/uninstall.rb ADDED
File without changes
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dasch-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-04-08 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email:
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - config/boot.rb
26
+ - config/routes.rb
27
+ - config/environments/test.rb
28
+ - config/database.yml
29
+ - config/environment.rb
30
+ - init.rb
31
+ - install.rb
32
+ - uninstall.rb
33
+ - rails/init.rb
34
+ - Rakefile
35
+ - README.markdown
36
+ - smurf.gemspec
37
+ - lib/smurf/stylesheet.rb
38
+ - lib/smurf/javascript.rb
39
+ - lib/smurf.rb
40
+ - MIT-LICENSE
41
+ has_rdoc: false
42
+ homepage: http://github.com/thumblemonks/smurf
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.2.0
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: Rails plugin to automatically minify JS and CSS when their bundles get cached
67
+ test_files:
68
+ - app/controllers/application.rb
69
+ - public/stylesheets/bar.css
70
+ - public/stylesheets/cache
71
+ - public/stylesheets/cache/expected.css
72
+ - public/stylesheets/foo.css
73
+ - public/javascripts
74
+ - public/javascripts/cache
75
+ - public/javascripts/cache/expected.js
76
+ - public/javascripts/testing.js
77
+ - test/smurf_test.rb
78
+ - test/test_helper.rb