sinatra-minify 0.0.1 → 0.1.1

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/.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