sinatra-assetpack 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md CHANGED
@@ -1,3 +1,17 @@
1
+ v0.0.10 - Sep 18, 2011
2
+ ----------------------
3
+
4
+ ### Added:
5
+ * Support for 'prebuild' to build on startup.
6
+ * Add UglifyJS support via `js_compression :uglify`. (#18)
7
+ * Ignore '.*' and '_*' files. (#17)
8
+ * Allow specifying of files to be ignored. (#17)
9
+
10
+ ### Changed:
11
+ * Built files from 'rake assetpack:build' now match the mtimes of their
12
+ sources. (#12)
13
+ * Refactor Compressor into separate engine classes.
14
+
1
15
  v0.0.9 - Sep 18, 2011
2
16
  ---------------------
3
17
 
@@ -6,8 +20,8 @@ v0.0.9 - Sep 18, 2011
6
20
  * Fix the Rake task when the main App class is in a module. (#11)
7
21
 
8
22
  ### Changed:
9
- * Use Sinatra's `template_cache`. This makes AssetPack honor Sinatra's
10
- `reload_templates` setting. (#15)
23
+ * Use Sinatra's `template_cache`. This makes AssetPack honor Sinatra's
24
+ `reload_templates` setting. (#15)
11
25
 
12
26
  ### Added:
13
27
  * Added .htc (IE behavior files) to the list of file formats to be served.
@@ -17,16 +31,16 @@ v0.0.8 - Sep 06, 2011
17
31
  ---------------------
18
32
 
19
33
  ### Fixed:
20
- * Fixed the CSS preprocessing bug that gives invalid 'url()' properties to
21
- non-existing images. Closes #1.
34
+ * Fixed the CSS preprocessing bug that gives invalid 'url()' properties to
35
+ non-existing images. (#1)
22
36
 
23
37
  ### Added:
24
- * Allow adding CSS/JS files that don't exist. Closes #8.
25
- * Support any Tilt-compatible CSS or JS engine. Related to #5.
38
+ * Allow adding CSS/JS files that don't exist. (#8)
39
+ * Support any Tilt-compatible CSS or JS engine. (#5)
26
40
 
27
41
  ### Changed:
28
- * Default to '/assets/x.js' then using assets.css without a path. Inspiration
29
- from Jammit.
42
+ * Default to '/assets/x.js' then using assets.css without a path. Inspiration
43
+ from Jammit.
30
44
  * Ask browsers to cache assets for 1 month.
31
45
 
32
46
  ### Misc:
data/README.md CHANGED
@@ -136,7 +136,7 @@ compressors in the `assets` block:
136
136
 
137
137
  ``` ruby
138
138
  assets {
139
- js_compression :jsmin # :jsmin | :yui | :closure
139
+ js_compression :jsmin # :jsmin | :yui | :closure | :uglify
140
140
  css_compression :simple # :simple | :sass | :yui | :sqwish
141
141
  }
142
142
  ```
@@ -155,10 +155,19 @@ assets {
155
155
  }
156
156
  ```
157
157
 
158
+ __Note:__ This depends on the `yui-compressor` gem. You will need to install it.
159
+ (`gem install yui-compressor`) If you use Bundler, you will need to add it to
160
+ your Gemfile as well.
161
+
162
+ ``` ruby
163
+ # Gemfile
164
+ gem 'yui-compressor', :require => 'yui/compressor'
165
+ ```
166
+
158
167
  ### SASS compression
159
168
 
160
169
  For SASS compression, you need the Sass gem (`gem install sass`). This treats
161
- the CSS files as Scss files and uses Sass's `output: :compressed`.
170
+ the CSS files as Scss files and uses Sass's `:output => :compressed`.
162
171
 
163
172
  ``` ruby
164
173
  assets {
@@ -166,6 +175,15 @@ assets {
166
175
  }
167
176
  ```
168
177
 
178
+ __Note:__ This depends on the `sass` gem. You will need to install it (`gem
179
+ install sass`). If you use Bundler, you will need to add it to your Gemfile as
180
+ well.
181
+
182
+ ``` ruby
183
+ # Gemfile
184
+ gem 'sass'
185
+ ```
186
+
169
187
  ### Sqwish CSS compression
170
188
 
171
189
  [Sqwish](http://github.com/ded/sqwish) is a NodeJS-based CSS compressor. To use
@@ -196,6 +214,35 @@ assets {
196
214
  }
197
215
  ```
198
216
 
217
+ ### UglifyJS compression
218
+
219
+ This uses the [UglifyJS](https://github.com/mishoo/UglifyJS) compressor to
220
+ compress your JavaScript. You will need to install the
221
+ [uglifier](http://rubygems.org/gems/uglifier) gem.
222
+
223
+ For options, refer to the [Uglifier
224
+ documentation](https://github.com/lautis/uglifier).
225
+
226
+ ``` ruby
227
+ assets {
228
+ js_compression :uglify
229
+ js_compression :uglify, [options]
230
+ }
231
+ ```
232
+
233
+ __Note:__ This depends on the `uglifier` gem. In your Gemfile, you will need to
234
+ add it. For Heroku support, you will need to add the `therubyracer-heroku` gem
235
+ as well.
236
+
237
+ ``` ruby
238
+ # Gemfile
239
+ gem 'uglifier'
240
+
241
+ # If you're on Heroku:
242
+ gem "therubyracer-heroku", "0.8.1.pre3", :require => false
243
+ ```
244
+
245
+
199
246
  Images
200
247
  ------
201
248
 
@@ -378,8 +425,8 @@ from `./app/javascripts/vendor/jquery*.js`.
378
425
 
379
426
  ``` ruby
380
427
  class App < Sinatra::Base
381
- serve '/js', from: '/app/javascripts'
382
428
  assets {
429
+ serve '/js', from: '/app/javascripts'
383
430
  js :application, [
384
431
  '/js/vendor/jquery.*.js',
385
432
  '/js/vendor/jquery.js'
@@ -390,6 +437,96 @@ end
390
437
  # In views: <%= js :application %>
391
438
  ```
392
439
 
440
+ ### assets.ignore
441
+ Excludes any URL paths that match the given spec.
442
+
443
+ These files will not show up in packages, and they will not be accessible.
444
+
445
+ By default, `.*` and `_*` are ignored. The former protects folders such as
446
+ `.svn` from being accessed, and the latter protects Sass partial files from
447
+ being accessed directly.
448
+
449
+ Note that this matches against URL paths, not local file paths. This means
450
+ something like `*.scss` will not work, as all stylesheet files will be compiled
451
+ to `.css`.
452
+
453
+ ``` ruby
454
+ # Usage:
455
+ assets {
456
+ ignore FILESPEC
457
+ }
458
+ ```
459
+
460
+ #### Example
461
+ Here's an example.
462
+
463
+ ``` ruby
464
+ class App < Sinatra::Base
465
+ assets {
466
+ # Ignores all files matching *.private.js in any folder.
467
+ ignore '*.private.js'
468
+
469
+ # Ignores all files in `/app/js/foo/**/*`
470
+ ignore '/js/foo'
471
+ }
472
+ end
473
+ ```
474
+
475
+ #### Advanced usage
476
+ By default, `.*` and `_*` are ignored. To disable this behavior, you can use
477
+ `clear_ignores!` before your `ignore` lines.
478
+
479
+ ``` ruby
480
+ assets {
481
+ clear_ignores!
482
+ ignore '*.private.js'
483
+ }
484
+ ```
485
+
486
+ To check if a certain file is ignored, use `assets.ignore?`
487
+
488
+ ``` ruby
489
+ assets.ignored?("/css/_chrome.css") #=> true
490
+ ```
491
+
492
+
493
+ ### assets.prebuild
494
+ Caches the built packages on application startup.
495
+
496
+ If this is not used, the packages will be minified when they are first
497
+ requested. This only has an effect in the production environment (or when
498
+ Sinatra's `reload_templates` is otherwise set to false).
499
+
500
+ ``` ruby
501
+ # Usage:
502
+ prebuild {true|false}
503
+ ```
504
+
505
+ #### Example
506
+ In this example, the package for `:application` will be built when the
507
+ application is started in the production environment.
508
+
509
+ ``` ruby
510
+ class App < Sinatra::Base
511
+ assets {
512
+ js_compression :closure
513
+
514
+ js :application, [
515
+ '/js/vendor/jquery.*.js',
516
+ '/js/vendor/jquery.js'
517
+ ]
518
+ prebuild true
519
+ }
520
+ end
521
+
522
+ # $ RACK_ENV=production ruby app.rb
523
+ # ** Building /assets/application.js...
524
+ # == Sinatra/1.2.6 has taken the stage on 4567 for production
525
+ # >> Thin web server (v1.2.11 codename Bat-Shit Crazy)
526
+ # >> Maximum connections set to 1024
527
+ # >> Listening on 0.0.0.0:4567, CTRL+C to stop
528
+ ```
529
+
393
530
  API reference: helpers
394
531
  ----------------------
395
532
 
@@ -500,19 +637,6 @@ class Main
500
637
  end
501
638
  ```
502
639
 
503
- To do
504
- -----
505
-
506
- AssetPack will eventually have:
507
-
508
- * Nested packages
509
- * Ignored files (to ignore included sass files and such)
510
- * `rake assetpack:build` should be able to output to another folder
511
- * Cache folder support (best if your app has many workers)
512
- * Refactor *Compressor* module
513
- * CDN (Cloudfront, S3) support
514
- * Better support for Compass sprites
515
-
516
640
  Acknowledgements
517
641
  ----------------
518
642
 
@@ -1,3 +1,4 @@
1
1
  ("App.js goes here.");
2
+ console.log("Hello");
2
3
 
3
4
 
@@ -1,4 +1,4 @@
1
- $:.unshift File.expand_path('../../lib', __FILE__)
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
2
 
3
3
  require 'sinatra/base'
4
4
  require 'sinatra/assetpack'
@@ -8,6 +8,9 @@ class App < Sinatra::Base
8
8
  register Sinatra::AssetPack
9
9
 
10
10
  assets do
11
+ #js_compression :closure
12
+ js_compression :uglify
13
+
11
14
  js :main, '/js/main.js', [
12
15
  '/js/vendor/*.js',
13
16
  '/js/app.js'
@@ -22,6 +25,8 @@ class App < Sinatra::Base
22
25
  css :more, '/css/more.css', [
23
26
  '/css/more/*.css'
24
27
  ]
28
+
29
+ prebuild true
25
30
  end
26
31
 
27
32
  get '/' do
@@ -1,4 +1,4 @@
1
- $:.unshift File.expand_path('../../lib', __FILE__)
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
2
 
3
3
  require 'sinatra/base'
4
4
  require 'sinatra/assetpack'
@@ -13,6 +13,11 @@ module Sinatra
13
13
  def assets_initialize!
14
14
  add_compressed_routes!
15
15
  add_individual_routes!
16
+
17
+ # Cache the built files.
18
+ if assets.prebuild && !reload_templates
19
+ assets.cache! { |file| $stderr.write "** Building #{file}...\n" }
20
+ end
16
21
  end
17
22
 
18
23
  # Add routes for the compressed versions
@@ -40,6 +45,8 @@ module Sinatra
40
45
  pass unless AssetPack.supported_formats.include?(fmt)
41
46
  fn = asset_path_for(file, from) or pass
42
47
 
48
+ pass if settings.assets.ignored?("#{path}/#{file}")
49
+
43
50
  # Send headers
44
51
  content_type fmt.to_sym
45
52
  last_modified File.mtime(fn).to_i
@@ -8,102 +8,47 @@ module Sinatra
8
8
  # compress File.read('x.js'), :js, :jsmin
9
9
  #
10
10
  def compress(str, type, engine=nil, options={})
11
- engine ||= 'jsmin' if type == :js
12
- engine ||= 'simple' if type == :css
11
+ # Use defaults if no engine is given.
12
+ return fallback(str, type, options) if engine.nil?
13
13
 
14
- key = :"#{type}/#{engine}"
15
- meth = compressors[key]
16
- return str unless meth
14
+ # Ensure that the engine exists.
15
+ klass = compressors[[type, engine]]
16
+ raise Error, "Engine #{engine} (#{type}) doesn't exist." unless klass
17
17
 
18
- meth[str, options]
19
- end
20
-
21
- def compressors
22
- @compressors ||= {
23
- :'js/jsmin' => method(:jsmin),
24
- :'js/yui' => method(:yui_js),
25
- :'js/closure' => method(:closure_js),
26
- :'css/sass' => method(:sass),
27
- :'css/yui' => method(:yui_css),
28
- :'css/simple' => method(:simple_css),
29
- :'css/sqwish' => method(:sqwish_css)
30
- }
31
- end
32
-
33
- # =====================================================================
34
- # Compressors
35
-
36
- def jsmin(str, options={})
37
- require 'jsmin'
38
- JSMin.minify str
39
- end
40
-
41
- def sass(str, options={})
42
- Tilt.new("scss", {:style => :compressed}) { str }.render
43
- rescue LoadError
44
- simple_css str
45
- end
18
+ # Ensure that the engine can support that type.
19
+ engine = klass.new
20
+ raise Error, "#{klass} does not support #{type.upcase} compression." unless engine.respond_to?(type)
46
21
 
47
- def yui_css(str, options={})
48
- require 'yui/compressor'
49
- YUI::CssCompressor.new.compress(str)
50
- rescue Errno::ENOENT
51
- sass str
22
+ # Build it using the engine, and fallback to defaults if it fails.
23
+ output = engine.send type, str, options
24
+ output ||= fallback(str, type, options) unless options[:no_fallback]
25
+ output
52
26
  end
53
27
 
54
- def yui_js(str, options={})
55
- require 'yui/compressor'
56
- YUI::JavaScriptCompressor.new(options).compress(str)
57
- rescue LoadError
58
- jsmin str
28
+ # Compresses a given string using the default engines.
29
+ def fallback(str, type, options)
30
+ if type == :js
31
+ compress str, :js, :jsmin, :no_fallback => true
32
+ elsif type == :css
33
+ compress str, :css, :simple, :no_fallback => true
34
+ end
59
35
  end
60
36
 
61
- def simple_css(str, options={})
62
- str.gsub! /[ \r\n\t]+/m, ' '
63
- str.gsub! %r{ *([;\{\},:]) *}, '\1'
64
- end
65
-
66
- def sqwish_css(str, options={})
67
- cmd = "#{sqwish_bin} %f "
68
- cmd += "--strict" if options[:strict]
69
-
70
- _, input = sys :css, str, cmd
71
- output = input.gsub(/\.css/, '.min.css')
72
-
73
- File.read(output)
74
- rescue => e
75
- simple_css str
76
- end
77
-
78
- def sqwish_bin
79
- ENV['SQWISH_PATH'] || "sqwish"
80
- end
81
-
82
- def closure_js(str, options={})
83
- require 'net/http'
84
- require 'uri'
85
-
86
- response = Net::HTTP.post_form(URI.parse('http://closure-compiler.appspot.com/compile'), {
87
- 'js_code' => str,
88
- 'compilation_level' => options[:level] || "ADVANCED_OPTIMIZATIONS",
89
- 'output_format' => 'text',
90
- 'output_info' => 'compiled_code'
91
- })
92
-
93
- response.body
37
+ def compressors
38
+ @compressors ||= Hash.new
94
39
  end
95
40
 
96
- # For others
97
- def sys(type, str, cmd)
98
- t = Tempfile.new ['', ".#{type}"]
99
- t.write(str)
100
- t.close
101
-
102
- output = `#{cmd.gsub('%f', t.path)}`
103
- FileUtils.rm t
104
-
105
- [output, t.path]
41
+ def register(type, engine, meth)
42
+ compressors[[type, engine]] = meth
106
43
  end
107
44
  end
45
+
46
+ require "#{AssetPack::PREFIX}/assetpack/engines/simple"
47
+ require "#{AssetPack::PREFIX}/assetpack/engines/jsmin"
48
+ require "#{AssetPack::PREFIX}/assetpack/engines/yui"
49
+ require "#{AssetPack::PREFIX}/assetpack/engines/sass"
50
+ require "#{AssetPack::PREFIX}/assetpack/engines/sqwish"
51
+ require "#{AssetPack::PREFIX}/assetpack/engines/closure"
52
+ require "#{AssetPack::PREFIX}/assetpack/engines/uglify"
108
53
  end
109
54
  end
@@ -0,0 +1,20 @@
1
+ module Sinatra
2
+ module AssetPack
3
+ # The base class for all CSS/JS compression engines.
4
+ class Engine
5
+ # Helper for system files.
6
+ # Usage: sys('css', string, "sqwish %f")
7
+ # Returns stdout.
8
+ def sys(type, str, cmd)
9
+ t = Tempfile.new ['', ".#{type}"]
10
+ t.write(str)
11
+ t.close
12
+
13
+ output = `#{cmd.gsub('%f', t.path)}`
14
+ FileUtils.rm t
15
+
16
+ [output, t.path]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Sinatra::AssetPack
2
+ class ClosureEngine < Engine
3
+ def js(str, options={})
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ response = Net::HTTP.post_form(URI.parse('http://closure-compiler.appspot.com/compile'), {
8
+ 'js_code' => str,
9
+ 'compilation_level' => options[:level] || "ADVANCED_OPTIMIZATIONS",
10
+ 'output_format' => 'text',
11
+ 'output_info' => 'compiled_code'
12
+ })
13
+
14
+ response.body
15
+ end
16
+ end
17
+
18
+ Compressor.register :js, :closure, ClosureEngine
19
+ end
@@ -0,0 +1,10 @@
1
+ module Sinatra::AssetPack
2
+ class JsminEngine < Engine
3
+ def js(str, options={})
4
+ require 'jsmin'
5
+ JSMin.minify str
6
+ end
7
+ end
8
+
9
+ Compressor.register :js, :jsmin, JsminEngine
10
+ end
@@ -0,0 +1,11 @@
1
+ module Sinatra::AssetPack
2
+ class SassEngine < Engine
3
+ def css(str, options={})
4
+ Tilt.new("scss", {:style => :compressed}) { str }.render
5
+ rescue LoadError
6
+ nil
7
+ end
8
+ end
9
+
10
+ Compressor.register :css, :sass, SassEngine
11
+ end
@@ -0,0 +1,11 @@
1
+ module Sinatra::AssetPack
2
+ class SimpleEngine < Engine
3
+ def css(str, options={})
4
+ str.gsub! /[ \r\n\t]+/m, ' '
5
+ str.gsub! %r{ *([;\{\},:]) *}, '\1'
6
+ str
7
+ end
8
+ end
9
+
10
+ Compressor.register :css, :simple, SimpleEngine
11
+ end
@@ -0,0 +1,21 @@
1
+ module Sinatra::AssetPack
2
+ class SqwishEngine < Engine
3
+ def css(str, options={})
4
+ cmd = "#{sqwish_bin} %f "
5
+ cmd += "--strict" if options[:strict]
6
+
7
+ _, input = sys :css, str, cmd
8
+ output = input.gsub(/\.css/, '.min.css')
9
+
10
+ File.read(output)
11
+ rescue => e
12
+ nil
13
+ end
14
+
15
+ def sqwish_bin
16
+ ENV['SQWISH_PATH'] || "sqwish"
17
+ end
18
+ end
19
+
20
+ Compressor.register :css, :sqwish, SqwishEngine
21
+ end
@@ -0,0 +1,12 @@
1
+ module Sinatra::AssetPack
2
+ class UglifyEngine < Engine
3
+ def js(str, options={})
4
+ require 'uglifier'
5
+ Uglifier.compile str, options
6
+ rescue => e
7
+ nil
8
+ end
9
+ end
10
+
11
+ Compressor.register :js, :uglify, UglifyEngine
12
+ end
@@ -0,0 +1,22 @@
1
+ module Sinatra::AssetPack
2
+ class YuiEngine < Engine
3
+ def initialize
4
+ require 'yui/compressor'
5
+ end
6
+
7
+ def js(str, options={})
8
+ YUI::JavaScriptCompressor.new(options).compress(str)
9
+ rescue LoadError
10
+ nil
11
+ end
12
+
13
+ def css(str, options={})
14
+ YUI::CssCompressor.new.compress(str)
15
+ rescue Errno::ENOENT
16
+ nil
17
+ end
18
+ end
19
+
20
+ Compressor.register :js, :yui, YuiEngine
21
+ Compressor.register :css, :yui, YuiEngine
22
+ end
@@ -38,20 +38,6 @@ module Sinatra
38
38
  new arr.each_slice(2).map { |(k, v)| Hash[k, v] }
39
39
  end
40
40
 
41
- # Works like Hash#each.
42
- #
43
- # By extension, methods that rely on #each (like #inject) will work
44
- # as intended.
45
- #
46
- def each(&block)
47
- super { |hash| yield hash.to_a.flatten }
48
- end
49
-
50
- # Works like Hash#map.
51
- def map(&block)
52
- super { |hash| yield hash.to_a.flatten }
53
- end
54
-
55
41
  # Works like Hash#values.
56
42
  def values
57
43
  inject([]) { |a, (k, v)| a << v; a }
@@ -65,6 +51,16 @@ module Sinatra
65
51
  def keys
66
52
  inject([]) { |a, (k, v)| a << k; a }
67
53
  end
54
+
55
+ [:each, :map, :map!, :reject, :reject!, :select, :select!].each do |meth|
56
+ send(:define_method, meth) { |*a, &block|
57
+ if block.respond_to?(:call)
58
+ super(*a) { |hash| block.call *hash.to_a }
59
+ else
60
+ super(*a)
61
+ end
62
+ }
63
+ end
68
64
  end
69
65
  end
70
66
  end
@@ -49,6 +49,8 @@ module Sinatra
49
49
  @js_compression_options = Hash.new
50
50
  @css_compression_options = Hash.new
51
51
 
52
+ @ignored = Array.new
53
+
52
54
  reset!
53
55
 
54
56
  # Defaults!
@@ -56,6 +58,9 @@ module Sinatra
56
58
  serve '/js', :from => 'app/js'
57
59
  serve '/images', :from => 'app/images'
58
60
 
61
+ ignore '.*'
62
+ ignore '_*'
63
+
59
64
  blk.arity <= 0 ? instance_eval(&blk) : yield(self) if block_given?
60
65
  end
61
66
 
@@ -75,6 +80,27 @@ module Sinatra
75
80
  @packages = Hash.new
76
81
  end
77
82
 
83
+ # Ignores a given path spec.
84
+ def ignore(spec)
85
+ if spec[0] == '/'
86
+ @ignored << "#{spec}"
87
+ @ignored << "#{spec}/**"
88
+ else
89
+ @ignored << "**/#{spec}"
90
+ @ignored << "**/#{spec}/**"
91
+ end
92
+ end
93
+
94
+ # Makes nothing ignored. Use this if you don't want to ignore dotfiles and underscore files.
95
+ def clear_ignores!
96
+ @ignored = Array.new
97
+ end
98
+
99
+ # Checks if a given path is ignored.
100
+ def ignored?(fn)
101
+ @ignored.any? { |spec| File.fnmatch spec, fn }
102
+ end
103
+
78
104
  # Adds some JS packages.
79
105
  #
80
106
  # js :foo, [ '/js/vendor/jquery.*.js', ... ]
@@ -122,6 +148,8 @@ module Sinatra
122
148
  attrib :js_compression_options # Hash
123
149
  attrib :css_compression_options # Hash
124
150
 
151
+ attrib :prebuild # Bool
152
+
125
153
  def js_compression(name=nil, options=nil)
126
154
  @js_compression = name unless name.nil?
127
155
  @js_compression_options = options if options.is_a?(Hash)
@@ -142,18 +170,40 @@ module Sinatra
142
170
  def build!(&blk)
143
171
  session = Rack::Test::Session.new app
144
172
 
173
+ get = lambda { |path|
174
+ response = session.get(path)
175
+ out = response.body
176
+ mtime = Time.parse(response.headers['Last-Modified']) if response.headers['Last-Modified']
177
+
178
+ [ out, mtime ]
179
+ }
180
+
145
181
  packages.each { |_, pack|
146
- out = session.get(pack.path).body
182
+ out, mtime = get[pack.path]
147
183
 
148
- write pack.path, out, &blk
149
- write pack.production_path, out, &blk
184
+ write pack.path, out, mtime, &blk
185
+ write pack.production_path, out, mtime, &blk
150
186
  }
151
187
 
152
188
  files.each { |path, local|
153
- out = session.get(path).body
154
- write path, out, &blk
155
- write BusterHelpers.add_cache_buster(path, local), out, &blk
189
+ out, mtime = get[path]
190
+
191
+ write path, out, mtime, &blk
192
+ write BusterHelpers.add_cache_buster(path, local), out, mtime, &blk
193
+ }
194
+ end
195
+
196
+ # Caches the packages.
197
+ def cache!(&blk)
198
+ return false if app.reload_templates
199
+
200
+ session = Rack::Test::Session.new app
201
+ packages.each { |_, pack|
202
+ yield pack.path if block_given?
203
+ session.get(pack.path)
156
204
  }
205
+
206
+ true
157
207
  end
158
208
 
159
209
  def served?(path)
@@ -189,7 +239,7 @@ module Sinatra
189
239
  end
190
240
 
191
241
  # Writes `public/#{path}` based on contents of `output`.
192
- def write(path, output)
242
+ def write(path, output, mtime=nil)
193
243
  require 'fileutils'
194
244
 
195
245
  path = File.join(@output_path, path)
@@ -197,6 +247,10 @@ module Sinatra
197
247
 
198
248
  FileUtils.mkdir_p File.dirname(path)
199
249
  File.open(path, 'w') { |f| f.write output }
250
+
251
+ if mtime
252
+ File.utime mtime, mtime, path
253
+ end
200
254
  end
201
255
 
202
256
  # Returns the files as a hash.
@@ -37,7 +37,9 @@ module Sinatra
37
37
 
38
38
  # Returns a list of URIs
39
39
  def paths_and_files
40
- @assets.glob @filespecs, :preserve => true
40
+ list = @assets.glob(@filespecs, :preserve => true)
41
+ list.reject! { |path, file| @assets.ignored?(path) }
42
+ list
41
43
  end
42
44
 
43
45
  def files
@@ -1,7 +1,7 @@
1
1
  module Sinatra
2
2
  module AssetPack
3
3
  def self.version
4
- "0.0.9"
4
+ "0.0.10"
5
5
  end
6
6
  end
7
7
  end
@@ -46,6 +46,7 @@ module Sinatra
46
46
  autoload :Helpers, "#{PREFIX}/assetpack/helpers"
47
47
  autoload :HtmlHelpers, "#{PREFIX}/assetpack/html_helpers"
48
48
  autoload :BusterHelpers, "#{PREFIX}/assetpack/buster_helpers"
49
+ autoload :Engine, "#{PREFIX}/assetpack/engine"
49
50
  autoload :Package, "#{PREFIX}/assetpack/package"
50
51
  autoload :Compressor, "#{PREFIX}/assetpack/compressor"
51
52
  autoload :Image, "#{PREFIX}/assetpack/image"
@@ -22,4 +22,5 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "contest"
23
23
  s.add_development_dependency "mocha"
24
24
  s.add_development_dependency "stylus"
25
+ s.add_development_dependency "uglifier"
25
26
  end
@@ -0,0 +1 @@
1
+ alert("HELLO I SHOULD BE IGNORED. BUMBLEBEE.");
@@ -0,0 +1,7 @@
1
+ (function() {
2
+ var kitsch = 1;
3
+ var noodle = 2;
4
+ var banana = 3;
5
+ console.log(noodle, banana);
6
+ })();
7
+
data/test/arity_test.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class ArityTest < UnitTest
4
- class App < Sinatra::Base
5
- set :root, File.expand_path('../app', __FILE__)
4
+ class App < UnitTest::App
6
5
  register Sinatra::AssetPack
7
6
 
8
7
  assets do |a|
data/test/build_test.rb CHANGED
@@ -11,11 +11,21 @@ class BuildTest < UnitTest
11
11
  app.assets.build!
12
12
 
13
13
  assert File.file? File.join(app.root, 'public/js/app.js')
14
+ assert File.mtime(File.join(app.root, 'public/js/app.js')).to_i == app.assets.packages['app.js'].mtime.to_i
15
+
14
16
  assert Dir[File.join(app.root, 'public/js/app.*.js')].first
15
17
 
16
18
  assert File.read(File.join(app.root, 'public/js/app.js')).include?('function(){alert("Hello");')
17
19
 
18
20
  assert Dir["#{app.root}/public/images/background.*.jpg"].first
19
21
  assert Dir["#{app.root}/public/images/email.*.png"].first
22
+
23
+ assert \
24
+ File.mtime(Dir["#{app.root}/public/images/background.*.jpg"].first).to_i ==
25
+ File.mtime(Dir["#{app.root}/public/images/background.jpg"].first).to_i
26
+
27
+ assert \
28
+ File.mtime(Dir["#{app.root}/public/images/background.*.jpg"].first).to_i ==
29
+ File.mtime(Dir["#{app.root}/app/images/background.jpg"].first).to_i
20
30
  end
21
31
  end
data/test/cache_test.rb CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../test_helper', __FILE__)
3
3
  class CacheTest < UnitTest
4
4
  test "Compressed js caching" do
5
5
  app.set :reload_templates, false
6
- JSMin.expects(:minify).times(1)
6
+ JSMin.expects(:minify).times(1).returns ""
7
7
  3.times { get '/js/app.js' }
8
8
  end
9
9
  end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class IgnoreTest < UnitTest
4
+ class App < UnitTest::App
5
+ register Sinatra::AssetPack
6
+
7
+ assets do
8
+ js :main, '/main.js', %w[/js/*.js]
9
+ end
10
+ end
11
+
12
+ def app
13
+ App
14
+ end
15
+
16
+ test "ignore as individual file" do
17
+ get '/js/_ignoreme.js'
18
+ assert last_response.status == 404
19
+ end
20
+
21
+ test "ignore in package" do
22
+ get '/main.js'
23
+ assert body.size > 0
24
+ assert !body.include?("BUMBLEBEE")
25
+ end
26
+
27
+ test "package files" do
28
+ assert !app.assets.packages['main.js'].files.any? { |s| s.include? '_ignoreme.js' }
29
+ end
30
+ end
data/test/sqwish_test.rb CHANGED
@@ -20,9 +20,8 @@ class SqwishTest < UnitTest
20
20
 
21
21
  if sqwish?
22
22
  test "build" do
23
- Sinatra::AssetPack::Compressor.expects(:`).with() { |cmd|
24
- cmd.match /^sqwish .*? --strict$/
25
- }
23
+ Sinatra::AssetPack::Compressor
24
+ Sinatra::AssetPack::SqwishEngine.any_instance.expects(:css)
26
25
 
27
26
  get '/css/sq.css'
28
27
  end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class UglifyTest < UnitTest
4
+ class App < UnitTest::App
5
+ register Sinatra::AssetPack
6
+
7
+ assets do
8
+ js_compression :uglify, :mangle => true
9
+ js :main, '/main.js', [
10
+ '/js/ugly.js'
11
+ ]
12
+ end
13
+ end
14
+
15
+ def app
16
+ App
17
+ end
18
+
19
+ test "build" do
20
+ get '/main.js'
21
+ assert !body.include?("noodle")
22
+ end
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-assetpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-09-17 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: tilt
16
- requirement: &2156684180 !ruby/object:Gem::Requirement
16
+ requirement: &2153561760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.3.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2156684180
24
+ version_requirements: *2153561760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sinatra
27
- requirement: &2156683760 !ruby/object:Gem::Requirement
27
+ requirement: &2153561340 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2156683760
35
+ version_requirements: *2153561340
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jsmin
38
- requirement: &2156683300 !ruby/object:Gem::Requirement
38
+ requirement: &2153560880 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2156683300
46
+ version_requirements: *2153560880
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rack-test
49
- requirement: &2156682880 !ruby/object:Gem::Requirement
49
+ requirement: &2153560460 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2156682880
57
+ version_requirements: *2153560460
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yui-compressor
60
- requirement: &2156682460 !ruby/object:Gem::Requirement
60
+ requirement: &2153560040 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2156682460
68
+ version_requirements: *2153560040
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sass
71
- requirement: &2156682040 !ruby/object:Gem::Requirement
71
+ requirement: &2153559620 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2156682040
79
+ version_requirements: *2153559620
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: haml
82
- requirement: &2156681620 !ruby/object:Gem::Requirement
82
+ requirement: &2153559200 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2156681620
90
+ version_requirements: *2153559200
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: coffee-script
93
- requirement: &2156681200 !ruby/object:Gem::Requirement
93
+ requirement: &2153558780 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *2156681200
101
+ version_requirements: *2153558780
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: contest
104
- requirement: &2156680780 !ruby/object:Gem::Requirement
104
+ requirement: &2153558360 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *2156680780
112
+ version_requirements: *2153558360
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: mocha
115
- requirement: &2156680360 !ruby/object:Gem::Requirement
115
+ requirement: &2153557940 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *2156680360
123
+ version_requirements: *2153557940
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: stylus
126
- requirement: &2156679940 !ruby/object:Gem::Requirement
126
+ requirement: &2153557520 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,7 +131,18 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *2156679940
134
+ version_requirements: *2153557520
135
+ - !ruby/object:Gem::Dependency
136
+ name: uglifier
137
+ requirement: &2153557100 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: *2153557100
135
146
  description: Package your assets for Sinatra.
136
147
  email:
137
148
  - rico@sinefunc.com
@@ -176,6 +187,14 @@ files:
176
187
  - lib/sinatra/assetpack/compressor.rb
177
188
  - lib/sinatra/assetpack/configurator.rb
178
189
  - lib/sinatra/assetpack/css.rb
190
+ - lib/sinatra/assetpack/engine.rb
191
+ - lib/sinatra/assetpack/engines/closure.rb
192
+ - lib/sinatra/assetpack/engines/jsmin.rb
193
+ - lib/sinatra/assetpack/engines/sass.rb
194
+ - lib/sinatra/assetpack/engines/simple.rb
195
+ - lib/sinatra/assetpack/engines/sqwish.rb
196
+ - lib/sinatra/assetpack/engines/uglify.rb
197
+ - lib/sinatra/assetpack/engines/yui.rb
179
198
  - lib/sinatra/assetpack/hasharray.rb
180
199
  - lib/sinatra/assetpack/helpers.rb
181
200
  - lib/sinatra/assetpack/html_helpers.rb
@@ -197,8 +216,10 @@ files:
197
216
  - test/app/app/css_stylus/stylus.styl
198
217
  - test/app/app/images/background.jpg
199
218
  - test/app/app/images/email.png
219
+ - test/app/app/js/_ignoreme.js
200
220
  - test/app/app/js/hello.js
201
221
  - test/app/app/js/hi.coffee
222
+ - test/app/app/js/ugly.js
202
223
  - test/app/app/js_glob/a/b/c1/hello.js
203
224
  - test/app/app/js_glob/a/b/c2/hi.js
204
225
  - test/app/app/js_glob/a/b/c2/hola.js
@@ -209,6 +230,7 @@ files:
209
230
  - test/compressed_test.rb
210
231
  - test/glob_test.rb
211
232
  - test/helpers_test.rb
233
+ - test/ignore_test.rb
212
234
  - test/img_test.rb
213
235
  - test/local_file_test.rb
214
236
  - test/mime_type_test.rb
@@ -223,6 +245,7 @@ files:
223
245
  - test/template_cache_test.rb
224
246
  - test/test_helper.rb
225
247
  - test/tilt_test.rb
248
+ - test/uglifier_test.rb
226
249
  - test/unit_test.rb
227
250
  - test/yui_test.rb
228
251
  homepage: http://github.com/rstacruz/sinatra-assetpack