sinatra-minify 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,5 @@
1
1
  .DS_Store
2
2
  *~
3
+ *.min.js
4
+ *.min.css
5
+ pkg
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.1@sinatra-minify
data/README.md CHANGED
@@ -1,10 +1,15 @@
1
- Usage
2
- -----
1
+ sinatra-minify
2
+ ==============
3
3
 
4
- Add these to your `init.rb`;
4
+ Quick-start guide
5
+ -----------------
6
+
7
+ First, install the `sinatra-minify` gem.
8
+
9
+ Add these to your app's main file:
5
10
 
6
11
  require 'sinatra/minify'
7
- class Main
12
+ class Main < Sinatra::Base
8
13
  register Sinatra::Minify
9
14
  end
10
15
 
@@ -12,4 +17,102 @@ Add this to your `Rakefile`:
12
17
 
13
18
  load 'vendor/sinatra-minify/lib/tasks.rake'
14
19
 
15
- Type `rake minify:build` to build the compressed JS/CSS files.
20
+ Now add your JS/CSS packages in `config/assets.yml` (relative to your app's root path).
21
+ The files are are assumed to be in `public/js` and `public/css` by default.
22
+
23
+ js:
24
+ base:
25
+ - jquery-1.4.2.js
26
+ - underscore-0.6.0.js
27
+ - app/*.js # Wildcards are allowed! ;)
28
+ css:
29
+ base:
30
+ - common.css
31
+ - app.*.css
32
+ homepage:
33
+ - home.*.css
34
+
35
+ Now add the helpers to your templates:
36
+
37
+ ...
38
+ <%= css_assets 'base' %>
39
+ <%= css_assets 'homepage' %>
40
+ </head>
41
+ <body>
42
+ ...
43
+ <%= js_assets 'base' %>
44
+ </body>
45
+ </html>
46
+ <!-- The 'base' and 'homepage' above are the names of the
47
+ packages as defined in your config/assets.yml. -->
48
+
49
+ This will include the scripts and stylesheets as individual `<script>` and `<link>` tags.
50
+ To include the minified files instead, switch to the production environment and build
51
+ the minified files by typing `rake minify:build`.
52
+
53
+ Usage tips
54
+ ==========
55
+
56
+ Building minified files
57
+ -----------------------
58
+
59
+ Minified files are built by typing:
60
+
61
+ rake minify:build
62
+
63
+ This creates files called `<package_name>.min.js` (and `.css`) in your `public/js` and
64
+ `public/css` folders.
65
+
66
+ NOTE: Building of minified files is NOT done automatically! You must call this explicitly.
67
+ Add it to your Capistrano deploy scripts or something.
68
+
69
+ Adding sinatra-minify as a dependency (Monk)
70
+ --------------------------------------------
71
+
72
+ If your using Monk (or otherwise using the `dependency` gem), simply add the
73
+ `sinatra-minify` GitHub repo to your dependencies file.
74
+
75
+ echo sinatra-minify git://github.com/sinefunc/sinatra-minify.git >> dependencies
76
+ dep vendor sinatra-minify
77
+
78
+ Changing JS/CSS paths
79
+ ---------------------
80
+
81
+ By default, sinatra-minify looks at `public/js` and `public/css` for your JS and CSS files,
82
+ respectively. You can change them with:
83
+
84
+ class Main < Sinatra::Base
85
+ register Sinatra::Minify
86
+
87
+ set :js_path, 'public/javascripts'
88
+ set :js_url, '/javascripts'
89
+
90
+ set :css_path, 'public/stylesheets'
91
+ set :css_url, '/stylesheets'
92
+
93
+ Forcing minification
94
+ --------------------
95
+
96
+ Minifying happens in the production environment only by default. You can force this behavior
97
+ by enabling the `force_minify` option in your app:
98
+
99
+ class Main < Sinatra::Base
100
+ register Sinatra::Minify
101
+
102
+ # Always minify
103
+ enable :force_minify
104
+
105
+ You can also define your own behavior for checking whether to minify or not.
106
+
107
+ class Main < Sinatra::Base
108
+ register Sinatra::Minify
109
+ def self.minify?
110
+ prodiction? or staging?
111
+ end
112
+
113
+ Ignore minified files in source control
114
+ ---------------------------------------
115
+
116
+ It'd be good practice to add `*.min.{css,js}` to your `.gitignore` file (or similar,
117
+ for those not using Git).
118
+
data/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
1
4
  begin
2
5
  require 'jeweler'
3
6
  Jeweler::Tasks.new do |s|
@@ -7,10 +10,43 @@ begin
7
10
  s.summary = "CSS/JS compressor for Sinatra"
8
11
  s.homepage = "http://www.github.com/sinefunc/sinatra-minify"
9
12
  s.description = "sinatra-minify is an extension for Sinatra to compress assets."
10
- s.add_dependency('jsmin', '>= 1.0.1')
13
+ s.add_development_dependency 'rack-test'
11
14
  end
12
15
  Jeweler::GemcutterTasks.new
13
16
  rescue LoadError
14
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
15
25
  end
16
26
 
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "sinatra-minify #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.1
@@ -1,14 +1,27 @@
1
1
  require 'sinatra/base'
2
- require File.join(File.dirname(__FILE__), 'minify/builder')
2
+
3
+ begin
4
+ require 'jsmin'
5
+ rescue LoadError
6
+ require File.join(File.dirname(__FILE__), '..', '..', 'vendor/jsmin-1.0.1/lib/jsmin')
7
+ end
3
8
 
4
9
  module Sinatra
5
10
  module Minify
11
+ autoload :Builder, 'sinatra/minify/builder'
12
+ autoload :Helpers, 'sinatra/minify/helpers'
13
+
6
14
  def self.registered( app )
7
15
  app.helpers Helpers
8
16
  app.set :js_url, '/js' # => http://site.com/js
9
17
  app.set :js_path, '/public/js' # => ~/myproject/public/js
10
18
  app.set :css_url, '/css'
11
19
  app.set :css_path, '/public/css'
20
+ app.disable :force_minify
21
+ end
22
+
23
+ def minify?
24
+ production? or force_minify
12
25
  end
13
26
  end
14
27
  register Minify
@@ -1,29 +1,40 @@
1
+ require 'yaml'
2
+
1
3
  module Sinatra
2
4
  module Minify
3
- module Helpers
4
- def js_assets( set )
5
- Builder.new(self.class).js_assets set
5
+ class Builder
6
+ # Returns the root path of the main Sinatra application.
7
+ # Mimins the root_path functionality of Monk.`
8
+ def root_path(*args)
9
+ File.join(File.dirname(settings.app_file), *args)
6
10
  end
7
- def css_assets( set )
8
- Builder.new(self.class).css_assets set
11
+
12
+ # Deletes all minified files.
13
+ def clean
14
+ [:js, :css].each do |type|
15
+ assets_config(type).keys.each do |set|
16
+ prefix = type == :js ? settings.js_path : settings.css_path
17
+ path = root_path File.join(prefix, "#{set}.min.#{type}")
18
+ File.unlink path if File.exists? path
19
+ end
20
+ end
9
21
  end
10
- end
11
22
 
12
- class Builder
23
+ # Rebuilds the minified .min.js and .min.css files.
13
24
  def build
14
25
  out = []
15
26
  [:js, :css].each do |type|
16
27
  assets_config(type).keys.each do |set|
17
28
  prefix = type == :js ? settings.js_path : settings.css_path
18
- path = root_path File.join(prefix, "#{set}.min." + type.to_s)
19
- File.open(path, 'w') << compress(type, set)
29
+ path = root_path(prefix, "#{set}.min.#{type}")
30
+ File.open(path, 'w') { |f| f.write compress(type, set) }
20
31
  out << path
21
32
  end
22
33
  end
23
34
  out
24
35
  end
25
36
 
26
- def initialize( app_class = ::Main )
37
+ def initialize(app_class = ::Main)
27
38
  @app_class = app_class
28
39
  end
29
40
 
@@ -34,13 +45,15 @@ module Sinatra
34
45
  # Returns the file sets for a given type as defined in the `assets.yml` config file.
35
46
  #
36
47
  # Params:
37
- # - `type` (Symbol/string) - Can be either `:javascripts` or `:stylesheets`
48
+ # - `type` (Symbol/string) - Can be either `:js` or `:css`
38
49
  #
39
50
  def assets_config(type)
40
- YAML::load(File.open(root_path "config/assets.yml")) [type.to_s]
51
+ YAML.load_file(root_path("config/assets.yml"))[type.to_s]
41
52
  end
42
53
 
43
54
  # Returns HTML code with `<script>` tags to include the scripts in a given `set`.
55
+ # In a production environment, this tries to include the minified version of the
56
+ # files. If it doesn't exist, it falls back to the original files.
44
57
  #
45
58
  # Params:
46
59
  # - `set` (String) - The set name, as defined in `config/assets.yml`.
@@ -50,22 +63,25 @@ module Sinatra
50
63
  # <%= js_assets 'base' %>
51
64
  #
52
65
  def js_assets( set )
53
- if settings.production?
54
- "<script src='#{settings.js_url}/#{set}.min.js' type='text/javascript'></script>\n"
66
+ min_file = root_path(settings.js_path, "#{set}.min.js")
67
+ min_path = "/#{settings.js_url}/#{set}.min.js".squeeze("/")
68
+ if settings.minify? and File.exists? min_file
69
+ mtime = File.mtime(min_file).to_i
70
+ "<script src='#{min_path}?#{mtime}' type='text/javascript'></script>\n"
55
71
  else
56
72
  js_assets_all set
57
73
  end
58
74
  end
59
75
 
60
- def js_assets_all( set )
61
- ret = ''
62
- assets(:js, set).each do |script|
63
- ret << "<script src=\"#{script[:url]}\" type=\"text/javascript\"></script>\n"
64
- end
65
- ret
76
+ def js_assets_all(set)
77
+ assets(:js, set).map { |script|
78
+ "<script src='#{script[:url]}' type='text/javascript'></script>"
79
+ }.join("\n")
66
80
  end
67
81
 
68
82
  # Returns HTML code with `<link>` tags to include the stylesheets in a given `set`.
83
+ # In a production environment, this tries to include the minified version of the
84
+ # files. If it doesn't exist, it falls back to the original files.
69
85
  #
70
86
  # Params:
71
87
  # - `set` (String) - The set name, as defined in `config/assets.yml`.
@@ -75,50 +91,52 @@ module Sinatra
75
91
  # <%= css_assets 'base' %>
76
92
  #
77
93
  def css_assets( set )
78
- if settings.production?
79
- "<link rel='stylesheet' href='#{settings.css_url}/#{set}.min.css' media='screen' />\n"
94
+ min_file = root_path settings.css_path, "#{set}.min.css"
95
+ min_path = "/#{settings.css_url}/#{set}.min.css".squeeze("/")
96
+ if settings.minify? and File.exists? min_file
97
+ mtime = File.mtime(file).to_i
98
+ "<link rel='stylesheet' href='#{min_path}?#{mtime}' media='screen' />\n"
80
99
  else
81
100
  css_assets_all set
82
101
  end
83
102
  end
84
103
 
85
104
  def css_assets_all(set)
86
- ret = ''
87
- (assets_config :css) [set].each do |filename|
88
- ret << "<link rel='stylesheet' href='#{settings.css_url}/#{filename}' media='screen' />\n"
89
- end
90
- ret
105
+ assets(:css, set).map { |sheet|
106
+ "<link rel='stylesheet' href='#{sheet[:url]}' media='screen' />"
107
+ }.join("\n")
91
108
  end
92
109
 
93
110
  # Returns the raw consolidated CSS/JS contents of a given type/set
94
- def combine( type, set )
95
- assets(type, set).map { |asset| File.open(asset[:path]).read }.join "\n"
111
+ def combine(type, set)
112
+ assets(type, set).map { |asset| File.open(asset[:path]).read }.join("\n").strip
96
113
  end
97
114
 
98
115
  # Returns compressed code
99
- def compress( type, set )
100
- code = combine type, set
116
+ def compress(type, set)
117
+ code = combine(type, set)
101
118
  if type == :js
102
119
  minify_js code
103
120
  elsif type == :css
104
121
  minify_css code
105
122
  else
106
- raise Exception.new
123
+ raise ArgumentError, "type should be one of :js or :css"
107
124
  end
108
125
  end
109
126
 
110
127
  def minify_css( src )
111
- src.gsub!(/\s+/, " ")
112
- src.gsub!(/\/\*(.*?)\*\//, "")
113
- src.gsub!(/\} /, "}\n")
114
- src.gsub!(/\n$/, "")
115
- src.gsub!(/ \{ /, " {")
116
- src.gsub!(/; \}/, "}")
117
- src
118
- end
119
-
120
- def minify_js( src )
121
- require 'jsmin'
128
+ src.gsub! /\s+/, " "
129
+ src.gsub! /\/\*(.*?)\*\//, ""
130
+ src.gsub! /\} /, "}\n"
131
+ src.gsub! /\n$/, ""
132
+ src.gsub! /[ \t]*\{[ \t]*/, "{"
133
+ src.gsub! /;[ \t]*\}/, "}"
134
+ src.gsub! /[ \t]*([,|{|}|>|:|;])[ \t]*/,"\\1" # Tersify
135
+ src.gsub! /[ \t]*\n[ \t]*/, "" # Hardcore mode (no NLs)
136
+ src.strip
137
+ end
138
+
139
+ def minify_js(src)
122
140
  JSMin.minify src
123
141
  end
124
142
 
@@ -132,13 +150,9 @@ module Sinatra
132
150
  # get_path :js
133
151
  # # Possible value: "/home/rsc/myproject/public/js"
134
152
  #
135
- def get_path( type )
136
- if type == :js
137
- path = settings.js_path
138
- else
139
- path = settings.css_path
140
- end
141
- root_path(path.split('/').inject([]) { |arr, item| arr << item unless item.empty?; arr })
153
+ def get_path(type)
154
+ path = (type == :js) ? settings.js_path : settings.css_path
155
+ root_path path.squeeze('/')
142
156
  end
143
157
 
144
158
  # Returns the URL for a given filename and a type.
@@ -149,18 +163,10 @@ module Sinatra
149
163
  # Example:
150
164
  # get_url :js, '/path/to/file.js'
151
165
  #
152
- def get_url( type, filename )
153
- if type == :js
154
- prefix = settings.js_url
155
- else
156
- prefix = settings.css_url
157
- end
158
- # Remove the js_path from it (/home/rsc/project/public/js/aa/lol.js => aa/lol.js)
159
- url = File.join(prefix, filename.split(get_path type).join(''))
160
-
161
- # Remove duplicate slashes
162
- url = url.split('/').inject([]) { |arr, item| arr << item unless item.empty?; arr }
163
- '/' + url.join('/')
166
+ def get_url(type, filename)
167
+ prefix = (type == :js) ? settings.js_url : settings.css_url
168
+ path = filename.gsub(/^#{Regexp.escape(get_path(type))}/, '')
169
+ File.join(prefix, path).squeeze('/')
164
170
  end
165
171
 
166
172
  # Returns a list of assets of a given type for a given set.
@@ -184,28 +190,34 @@ module Sinatra
184
190
  # See also:
185
191
  # - js_assets
186
192
  #
187
- def assets( type, set )
188
- # type is either js or css
189
- specs = (assets_config type) [set]
190
- path = get_path type
191
- ret = []
192
- done = []
193
+ def assets(type, set)
194
+ # type is either :js or :css
195
+ specs = assets_config(type)[set]
196
+ path = get_path(type)
197
+ done = []
193
198
  # `specs` will be a list of filespecs. Find all files that
194
199
  # match all specs.
195
- if specs.class == Array
196
- specs.each do |spec|
197
- Dir["#{path}/#{spec}"].each do |filename|
198
- unless done.include? filename
199
- ret << {
200
- :url => get_url(type, filename),
201
- :path => filename
202
- }
203
- done << filename
204
- end
200
+ [specs].flatten.inject([]) do |ret, spec|
201
+ filepath = "#{path}/#{spec}"
202
+ files = Dir[filepath]
203
+
204
+ # Add it anyway if it doesn't match anything
205
+ unless files.any? || done.include?(filepath) || filepath.include?('*')
206
+ ret << { :url => get_url(type, filepath), :path => filepath }
207
+ done << filepath
208
+ end
209
+
210
+ files.each do |filename|
211
+ unless done.include? filename
212
+ ret << {
213
+ :url => [get_url(type, filename), File.mtime(filename).to_i].join('?'),
214
+ :path => filename
215
+ }
216
+ done << filename
205
217
  end
206
218
  end
219
+ ret
207
220
  end
208
- ret
209
221
  end
210
222
  end
211
223
  end
@@ -0,0 +1,14 @@
1
+ module Sinatra
2
+ module Minify
3
+ module Helpers
4
+ def js_assets( set )
5
+ Builder.new(self.class).js_assets set
6
+ end
7
+
8
+ def css_assets( set )
9
+ Builder.new(self.class).css_assets set
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sinatra-minify}
8
- s.version = "0.0.1"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["sinefunc"]
12
- s.date = %q{2010-04-22}
12
+ s.date = %q{2010-04-23}
13
13
  s.description = %q{sinatra-minify is an extension for Sinatra to compress assets.}
14
14
  s.email = %q{info@sinefunc.com}
15
15
  s.extra_rdoc_files = [
@@ -17,31 +17,47 @@ Gem::Specification.new do |s|
17
17
  ]
18
18
  s.files = [
19
19
  ".gitignore",
20
+ ".rvmrc",
20
21
  "README.md",
21
22
  "Rakefile",
22
23
  "VERSION",
23
24
  "lib/sinatra/minify.rb",
24
25
  "lib/sinatra/minify/builder.rb",
26
+ "lib/sinatra/minify/helpers.rb",
25
27
  "lib/tasks.rake",
26
- "sinatra-minify.gemspec"
28
+ "sinatra-minify.gemspec",
29
+ "test/fixtures/exampleapp/app.rb",
30
+ "test/fixtures/exampleapp/config/assets.yml",
31
+ "test/fixtures/exampleapp/public/css/style-default.css",
32
+ "test/fixtures/exampleapp/public/js/script-1.js",
33
+ "test/fixtures/exampleapp/public/js/script-2.js",
34
+ "test/helper.rb",
35
+ "test/test_minify.rb",
36
+ "vendor/jsmin-1.0.1/HISTORY",
37
+ "vendor/jsmin-1.0.1/lib/jsmin.rb"
27
38
  ]
28
39
  s.homepage = %q{http://www.github.com/sinefunc/sinatra-minify}
29
40
  s.rdoc_options = ["--charset=UTF-8"]
30
41
  s.require_paths = ["lib"]
31
42
  s.rubygems_version = %q{1.3.6}
32
43
  s.summary = %q{CSS/JS compressor for Sinatra}
44
+ s.test_files = [
45
+ "test/fixtures/exampleapp/app.rb",
46
+ "test/helper.rb",
47
+ "test/test_minify.rb"
48
+ ]
33
49
 
34
50
  if s.respond_to? :specification_version then
35
51
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
36
52
  s.specification_version = 3
37
53
 
38
54
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
39
- s.add_runtime_dependency(%q<jsmin>, [">= 1.0.1"])
55
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
40
56
  else
41
- s.add_dependency(%q<jsmin>, [">= 1.0.1"])
57
+ s.add_dependency(%q<rack-test>, [">= 0"])
42
58
  end
43
59
  else
44
- s.add_dependency(%q<jsmin>, [">= 1.0.1"])
60
+ s.add_dependency(%q<rack-test>, [">= 0"])
45
61
  end
46
62
  end
47
63
 
@@ -0,0 +1,30 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'sinatra/base'
6
+ require 'sinatra/minify'
7
+
8
+ # ROOT_DIR = File.dirname(__FILE__)
9
+
10
+ class App < Sinatra::Base
11
+ set :app_file, __FILE__
12
+
13
+ register Sinatra::Minify
14
+
15
+ get '/' do
16
+ "Hello"
17
+ end
18
+
19
+ get "/foo" do
20
+ output = ""
21
+ output << js_assets('base')
22
+ end
23
+
24
+ # Doesn't stop Sinatra::Application from running by default
25
+ def self.run?
26
+ false
27
+ end
28
+ end
29
+
30
+ App.run! if $0 == __FILE__
@@ -0,0 +1,6 @@
1
+ js:
2
+ base:
3
+ script-*.js
4
+ css:
5
+ base:
6
+ style-*.css
@@ -0,0 +1,86 @@
1
+ /* Reset */
2
+ div, dl, dt, dd, ul, ol, li, form,
3
+ fieldset, input, th, td { margin: 0; padding: 0; }
4
+ pre, p, blockquote, h1, h2, h3, h4, h5,
5
+ h6 { margin: 1em 0 1em 0; }
6
+ blockquote { border-left: solid 2px #ccc; padding: 0 1em; margin-left: 0.2em; color: #888; }
7
+ h1 { font-size: 1.4em; }
8
+ h2 { font-size: 1.3em; }
9
+ h3 { font-size: 1.2em; }
10
+ h4 { font-size: 1.1em; }
11
+ h5 { font-size: 0.9em; }
12
+ h6 { font-size: 0.9em; }
13
+ ol, ul { margin-left: 2em; }
14
+
15
+ /* Body & wrapper */
16
+ html, body { margin: 0; padding: 0; }
17
+ body, td, input, textarea { font-family: arial, helvetica, sans-serif; font-size: 1em; }
18
+ body { font-size: 0.85em; line-height: 1.6em; background: #6ba241; color: #333; }
19
+ #all { margin: 0 auto; width: auto; position: relative; }
20
+
21
+ /* Links */
22
+ a { color: #393; text-decoration: none; font-weight: bold; padding: 1px; }
23
+ a:visited { color: #393; }
24
+ a:hover { color: #393; text-decoration: underline; }
25
+ a img { border: 0; }
26
+
27
+ /* Common layout */
28
+ #what-we-do, #who-we-are, #content { overflow: hidden; }
29
+ #header>.c, #what-we-do>.c,
30
+ #who-we-are>.c, #footer>.c { width: 940px; margin: 0 auto; overflow: hidden; }
31
+
32
+ /* Common styling */
33
+ #header { background: #f8fbf4 url(bg-header.png) center bottom repeat-x; padding: 10px 0 130px 0; }
34
+ #what-we-do { background: #f0f6e9; padding: 30px 0 0 0; }
35
+ #who-we-are { background: #6ba241 url(bg-stripe.png) center top repeat-x; padding: 90px 0 30px 0; color: #d3e3c6; text-shadow: 1px 1px #5c843d; }
36
+ #footer { background: #444; padding: 50px 0 50px 0; color: #bbb; }
37
+
38
+ /* Header */
39
+ #header { overflow: hidden; }
40
+ #header #logo { float: left; margin-right: 75px; margin-left: 75px; }
41
+ #header h1 { background: url(text.png) 0 0 no-repeat; width: 511px; height: 95px; text-indent: -9999px; margin: 0; padding: 0; display: block; float: left; }
42
+ #contact-header { border-bottom: solid 1px #ccc; margin-bottom: 90px; padding: 0 0 4px 0; text-align: right; color: #aaa;
43
+ font-size: 0.9em; }
44
+ #contact-header em { margin: 0 12px 0 10px; color: #ccc; }
45
+ #contact-header a { color: #888; text-decoration: underline; }
46
+ #contact-header a:hover { color: #6b6; }
47
+
48
+ /* Content */
49
+ #content h2 { float: left; width: 240px; }
50
+ #content ul, #content li { margin: 0; padding: 0; display: block; }
51
+ #what-we-do>.c ul { float: left; width: 700px; overflow: hidden; }
52
+
53
+ /* What we do */
54
+ #what-we-do li { float: left; width: 340px; }
55
+ #what-we-do li.left { margin-right: 20px; }
56
+
57
+ #what-we-do li h3 { font-size: 1.4em; }
58
+ #what-we-do li h4 { font-family: georgia, times, serif; font-style: italic; color: #777; font-weight: normal;
59
+ font-size: 1.2em; line-height: 1.4em; margin: 0.8em 0 0 0; }
60
+ #what-we-do li p { margin: 3px 0 2em 0; }
61
+ #what-we-do #do-build,
62
+ #what-we-do #do-scale { padding-bottom: 1.5em; }
63
+
64
+ /* What we do: h2 */
65
+ #what-we-do h2 { background: url(text.png) 0 -400px no-repeat; height: 18px; text-indent: -9999px; margin: 0; padding: 0;
66
+ display: block; }
67
+
68
+ /* What we do: h3 */
69
+ #what-we-do h3 { background: url(text.png) 0 0 no-repeat; height: 21px; text-indent: -9999px; margin: 0; padding: 0;
70
+ display: block; }
71
+ #do-build h3 { background-position: 0 -200px; }
72
+ #do-scale h3 { background-position: 0 -250px; }
73
+ #do-craft h3 { background-position: 0 -300px; }
74
+ #do-train h3 { background-position: 0 -350px; }
75
+
76
+ /* Who we are */
77
+ #who-we-are>.c div { float: left; width: 560px; overflow: hidden; }
78
+ #who-we-are h3 { font-size: 1.4em; line-height: 1.5em; color: white; background: url(text.png) 0 -550px no-repeat;
79
+ width: 521px; height: 73px; text-indent: -9999px; margin: 0; padding: 0; display: block; padding-bottom: 7px; }
80
+ #who-we-are h2 { background: url(text.png) 0 -450px no-repeat; height: 18px; text-indent: -9999px; margin: 0; padding: 0;
81
+ display: block; }
82
+
83
+ /* Footer */
84
+ #footer { text-align: center; }
85
+ #footer a { font-size: 1.3em; color: white; font-weight: normal; }
86
+ #footer span { display: block; font-size: 1.2em; color: #888; margin-bottom: 3px; font-family: georgia; font-style: italic; }
@@ -0,0 +1 @@
1
+ aoeu = 234 /* Test */;
@@ -0,0 +1 @@
1
+ aoeu = 234 /* Test */;
data/test/helper.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ #require 'shoulda'
4
+ require 'contest'
5
+ require 'rack/test'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+
10
+ require 'fixtures/exampleapp/app'
11
+
12
+ class Test::Unit::TestCase
13
+ include Rack::Test::Methods
14
+ end
@@ -0,0 +1,52 @@
1
+ require 'helper'
2
+
3
+ class TestMinify < Test::Unit::TestCase
4
+ def app
5
+ App
6
+ end
7
+
8
+ def output
9
+ last_response.body
10
+ end
11
+
12
+ def builder
13
+ Sinatra::Minify::Builder.new app
14
+ end
15
+
16
+ should "rock pants off" do
17
+ get '/'
18
+ assert_match "Hello", output
19
+ end
20
+
21
+ should "Include all scripts" do
22
+ get '/foo'
23
+ assert_match /\/js\/script-1.js\?/, output
24
+ assert_match /\/js\/script-2.js\?/, output
25
+ end
26
+
27
+ describe "In a production environment" do
28
+ def setup
29
+ app.enable :force_minify
30
+ end
31
+
32
+ def teardown
33
+ app.disable :force_minify
34
+ end
35
+
36
+ should "Include the minified script" do
37
+ get '/foo'
38
+ assert_match /\/js\/base.min.js\?/, output
39
+ end
40
+ end
41
+
42
+ describe "Building files" do
43
+ def setup
44
+ builder.clean
45
+ builder.build
46
+ end
47
+
48
+ should "Build properly" do
49
+ assert true
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,9 @@
1
+ JSMin History
2
+ ================================================================================
3
+
4
+ Version 1.0.1 (2008-11-10)
5
+ * Ruby 1.9 compatibility.
6
+ * Minor performance improvements.
7
+
8
+ Version 1.0.0 (2008-03-22)
9
+ * First release.
@@ -0,0 +1,249 @@
1
+ #--
2
+ # jsmin.rb - Ruby implementation of Douglas Crockford's JSMin.
3
+ #
4
+ # This is a port of jsmin.c, and is distributed under the same terms, which are
5
+ # as follows:
6
+ #
7
+ # Copyright (c) 2002 Douglas Crockford (www.crockford.com)
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ # of this software and associated documentation files (the "Software"), to deal
11
+ # in the Software without restriction, including without limitation the rights
12
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # copies of the Software, and to permit persons to whom the Software is
14
+ # furnished to do so, subject to the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included in all
17
+ # copies or substantial portions of the Software.
18
+ #
19
+ # The Software shall be used for Good, not Evil.
20
+ #
21
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ # SOFTWARE.
28
+ #++
29
+
30
+ require 'strscan'
31
+
32
+ # = JSMin
33
+ #
34
+ # Ruby implementation of Douglas Crockford's JavaScript minifier, JSMin.
35
+ #
36
+ # Author:: Ryan Grove (mailto:ryan@wonko.com)
37
+ # Version:: 1.0.1 (2008-11-10)
38
+ # Copyright:: Copyright (c) 2008 Ryan Grove. All rights reserved.
39
+ # Website:: http://github.com/rgrove/jsmin/
40
+ #
41
+ # == Example
42
+ #
43
+ # require 'rubygems'
44
+ # require 'jsmin'
45
+ #
46
+ # File.open('example.js', 'r') {|file| puts JSMin.minify(file) }
47
+ #
48
+ module JSMin
49
+ CHR_APOS = "'".freeze
50
+ CHR_ASTERISK = '*'.freeze
51
+ CHR_BACKSLASH = '\\'.freeze
52
+ CHR_CR = "\r".freeze
53
+ CHR_FRONTSLASH = '/'.freeze
54
+ CHR_LF = "\n".freeze
55
+ CHR_QUOTE = '"'.freeze
56
+ CHR_SPACE = ' '.freeze
57
+
58
+ if RUBY_VERSION >= '1.9'
59
+ ORD_LF = "\n".freeze
60
+ ORD_SPACE = ' '.freeze
61
+ ORD_TILDE = '~'.freeze
62
+ else
63
+ ORD_LF = "\n"[0].freeze
64
+ ORD_SPACE = ' '[0].freeze
65
+ ORD_TILDE = '~'[0].freeze
66
+ end
67
+
68
+ class << self
69
+
70
+ # Reads JavaScript from +input+ (which can be a String or an IO object) and
71
+ # returns a String containing minified JS.
72
+ def minify(input)
73
+ @js = StringScanner.new(input.is_a?(IO) ? input.read : input.to_s)
74
+
75
+ @a = "\n"
76
+ @b = nil
77
+ @lookahead = nil
78
+ @output = ''
79
+
80
+ action_get
81
+
82
+ while !@a.nil? do
83
+ case @a
84
+ when CHR_SPACE
85
+ if alphanum?(@b)
86
+ action_output
87
+ else
88
+ action_copy
89
+ end
90
+
91
+ when CHR_LF
92
+ if @b == CHR_SPACE
93
+ action_get
94
+ elsif @b =~ /[{\[\(+-]/
95
+ action_output
96
+ else
97
+ if alphanum?(@b)
98
+ action_output
99
+ else
100
+ action_copy
101
+ end
102
+ end
103
+
104
+ else
105
+ if @b == CHR_SPACE
106
+ if alphanum?(@a)
107
+ action_output
108
+ else
109
+ action_get
110
+ end
111
+ elsif @b == CHR_LF
112
+ if @a =~ /[}\]\)\\"+-]/
113
+ action_output
114
+ else
115
+ if alphanum?(@a)
116
+ action_output
117
+ else
118
+ action_get
119
+ end
120
+ end
121
+ else
122
+ action_output
123
+ end
124
+ end
125
+ end
126
+
127
+ @output
128
+ end
129
+
130
+ private
131
+
132
+ # Corresponds to action(1) in jsmin.c.
133
+ def action_output
134
+ @output << @a
135
+ action_copy
136
+ end
137
+
138
+ # Corresponds to action(2) in jsmin.c.
139
+ def action_copy
140
+ @a = @b
141
+
142
+ if @a == CHR_APOS || @a == CHR_QUOTE
143
+ loop do
144
+ @output << @a
145
+ @a = get
146
+
147
+ break if @a == @b
148
+
149
+ if @a[0] <= ORD_LF
150
+ raise "JSMin parse error: unterminated string literal: #{@a}"
151
+ end
152
+
153
+ if @a == CHR_BACKSLASH
154
+ @output << @a
155
+ @a = get
156
+
157
+ if @a[0] <= ORD_LF
158
+ raise "JSMin parse error: unterminated string literal: #{@a}"
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ action_get
165
+ end
166
+
167
+ # Corresponds to action(3) in jsmin.c.
168
+ def action_get
169
+ @b = nextchar
170
+
171
+ if @b == CHR_FRONTSLASH && (@a == CHR_LF || @a =~ /[\(,=:\[!&|?{};]/)
172
+ @output << @a
173
+ @output << @b
174
+
175
+ loop do
176
+ @a = get
177
+
178
+ if @a == CHR_FRONTSLASH
179
+ break
180
+ elsif @a == CHR_BACKSLASH
181
+ @output << @a
182
+ @a = get
183
+ elsif @a[0] <= ORD_LF
184
+ raise "JSMin parse error: unterminated regular expression " +
185
+ "literal: #{@a}"
186
+ end
187
+
188
+ @output << @a
189
+ end
190
+
191
+ @b = nextchar
192
+ end
193
+ end
194
+
195
+ # Returns true if +c+ is a letter, digit, underscore, dollar sign,
196
+ # backslash, or non-ASCII character.
197
+ def alphanum?(c)
198
+ c.is_a?(String) && !c.empty? && (c[0] > ORD_TILDE || c =~ /[0-9a-z_$\\]/i)
199
+ end
200
+
201
+ # Returns the next character from the input. If the character is a control
202
+ # character, it will be translated to a space or linefeed.
203
+ def get
204
+ c = @lookahead.nil? ? @js.getch : @lookahead
205
+ @lookahead = nil
206
+
207
+ return c if c.nil? || c == CHR_LF || c[0] >= ORD_SPACE
208
+ return "\n" if c == CHR_CR
209
+ return ' '
210
+ end
211
+
212
+ # Gets the next character, excluding comments.
213
+ def nextchar
214
+ c = get
215
+ return c unless c == CHR_FRONTSLASH
216
+
217
+ case peek
218
+ when CHR_FRONTSLASH
219
+ loop do
220
+ c = get
221
+ return c if c[0] <= ORD_LF
222
+ end
223
+
224
+ when CHR_ASTERISK
225
+ get
226
+ loop do
227
+ case get
228
+ when CHR_ASTERISK
229
+ if peek == CHR_FRONTSLASH
230
+ get
231
+ return ' '
232
+ end
233
+
234
+ when nil
235
+ raise 'JSMin parse error: unterminated comment'
236
+ end
237
+ end
238
+
239
+ else
240
+ return c
241
+ end
242
+ end
243
+
244
+ # Gets the next character without getting it.
245
+ def peek
246
+ @lookahead = get
247
+ end
248
+ end
249
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
7
  - 1
9
- version: 0.0.1
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - sinefunc
@@ -14,22 +14,20 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-22 00:00:00 +08:00
17
+ date: 2010-04-23 00:00:00 +08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: jsmin
21
+ name: rack-test
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
- - 1
29
28
  - 0
30
- - 1
31
- version: 1.0.1
32
- type: :runtime
29
+ version: "0"
30
+ type: :development
33
31
  version_requirements: *id001
34
32
  description: sinatra-minify is an extension for Sinatra to compress assets.
35
33
  email: info@sinefunc.com
@@ -41,13 +39,24 @@ extra_rdoc_files:
41
39
  - README.md
42
40
  files:
43
41
  - .gitignore
42
+ - .rvmrc
44
43
  - README.md
45
44
  - Rakefile
46
45
  - VERSION
47
46
  - lib/sinatra/minify.rb
48
47
  - lib/sinatra/minify/builder.rb
48
+ - lib/sinatra/minify/helpers.rb
49
49
  - lib/tasks.rake
50
50
  - sinatra-minify.gemspec
51
+ - test/fixtures/exampleapp/app.rb
52
+ - test/fixtures/exampleapp/config/assets.yml
53
+ - test/fixtures/exampleapp/public/css/style-default.css
54
+ - test/fixtures/exampleapp/public/js/script-1.js
55
+ - test/fixtures/exampleapp/public/js/script-2.js
56
+ - test/helper.rb
57
+ - test/test_minify.rb
58
+ - vendor/jsmin-1.0.1/HISTORY
59
+ - vendor/jsmin-1.0.1/lib/jsmin.rb
51
60
  has_rdoc: true
52
61
  homepage: http://www.github.com/sinefunc/sinatra-minify
53
62
  licenses: []
@@ -78,5 +87,7 @@ rubygems_version: 1.3.6
78
87
  signing_key:
79
88
  specification_version: 3
80
89
  summary: CSS/JS compressor for Sinatra
81
- test_files: []
82
-
90
+ test_files:
91
+ - test/fixtures/exampleapp/app.rb
92
+ - test/helper.rb
93
+ - test/test_minify.rb