sundawg-sinatra-assetpack-fork 0.0.12.pre1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +1 -1
  2. data/.travis.yml +17 -0
  3. data/CONTRIBUTING.md +27 -0
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +72 -0
  6. data/HISTORY.md +60 -1
  7. data/README.md +54 -11
  8. data/examples/basic/app.rb +12 -1
  9. data/lib/sinatra/assetpack.rb +1 -1
  10. data/lib/sinatra/assetpack/class_methods.rb +8 -6
  11. data/lib/sinatra/assetpack/compressor.rb +1 -0
  12. data/lib/sinatra/assetpack/css.rb +1 -1
  13. data/lib/sinatra/assetpack/engines/less.rb +11 -0
  14. data/lib/sinatra/assetpack/helpers.rb +13 -3
  15. data/lib/sinatra/assetpack/html_helpers.rb +12 -0
  16. data/lib/sinatra/assetpack/image.rb +2 -2
  17. data/lib/sinatra/assetpack/options.rb +24 -9
  18. data/lib/sinatra/assetpack/package.rb +15 -8
  19. data/lib/sinatra/assetpack/version.rb +1 -1
  20. data/sinatra-assetpack.gemspec +5 -0
  21. data/test/app/app.rb +8 -1
  22. data/test/app/app/fonts/cantarell-regular-webfont.eot +0 -0
  23. data/test/app/app/fonts/cantarell-regular-webfont.svg +18 -0
  24. data/test/app/app/fonts/cantarell-regular-webfont.ttf +0 -0
  25. data/test/app/app/fonts/cantarell-regular-webfont.woff +0 -0
  26. data/test/app/app/js/jquery-1.8.0.min.js +1 -0
  27. data/test/app/app/packages/a_package/package.css +1 -0
  28. data/test/app/app/packages/a_package/package.js +1 -0
  29. data/test/app/app/packages/a_package/package.png +0 -0
  30. data/test/app/config.ru +2 -0
  31. data/test/arity_test.rb +8 -2
  32. data/test/cache_test.rb +17 -1
  33. data/test/glob_test.rb +3 -0
  34. data/test/ignore_test.rb +2 -2
  35. data/test/img_test.rb +2 -2
  36. data/test/local_file_test.rb +6 -0
  37. data/test/mime_type_test.rb +20 -0
  38. data/test/redundant_test.rb +1 -0
  39. data/test/sqwish_test.rb +4 -3
  40. data/test/test_helper.rb +6 -1
  41. data/test/tilt_test.rb +1 -0
  42. data/test/unit_test.rb +42 -5
  43. metadata +207 -189
  44. data/lib/sinatra/assetpack/hasharray.rb +0 -66
@@ -12,6 +12,18 @@ module Sinatra
12
12
  def kv(hash)
13
13
  hash.map { |k, v| " #{e k}='#{e v}'" }.join('')
14
14
  end
15
+
16
+ def get_file_uri(file, assets)
17
+ raise RuntimeError, "You must pass in an asset for a URI to be created for it." if file.nil?
18
+
19
+ local = assets.local_file_for file
20
+
21
+ if assets.asset_hosts.nil?
22
+ BusterHelpers.add_cache_buster(file, local)
23
+ else
24
+ assets.asset_hosts[Digest::MD5.hexdigest(file).to_i(16) % assets.asset_hosts.length]+BusterHelpers.add_cache_buster(file, local)
25
+ end
26
+ end
15
27
  end
16
28
  end
17
29
  end
@@ -30,8 +30,8 @@ module Sinatra
30
30
  def dimensions
31
31
  return @dimensions unless @dimensions.nil?
32
32
 
33
- _, _, dim = `identify "#{@file}"`.split(' ')
34
- w, h = dim.split('x')
33
+ dim = /(\d+) x (\d+)/.match(`file "#{@file}"`)
34
+ w, h = dim[1,2]
35
35
 
36
36
  if w.to_i != 0 && h.to_i != 0
37
37
  @dimensions = [w.to_i, h.to_i]
@@ -153,12 +153,21 @@ module Sinatra
153
153
  attrib :js_compression # Symbol, compression method for JS
154
154
  attrib :css_compression # Symbol, compression method for CSS
155
155
  attrib :output_path # '/public'
156
+ attrib :asset_hosts # [ 'http://cdn0.example.org', 'http://cdn1.example.org' ]
156
157
 
157
158
  attrib :js_compression_options # Hash
158
159
  attrib :css_compression_options # Hash
159
160
 
160
161
  attrib :prebuild # Bool
161
162
 
163
+ def expires(*args)
164
+ if args.empty?
165
+ @expires
166
+ else
167
+ @expires = args
168
+ end
169
+ end
170
+
162
171
  def js_compression(name=nil, options=nil)
163
172
  @js_compression = name unless name.nil?
164
173
  @js_compression_options = options if options.is_a?(Hash)
@@ -238,16 +247,22 @@ module Sinatra
238
247
  # Returns nil if a file is not found.
239
248
  # TODO: consolidate with local_file_for
240
249
  def dyn_local_file_for(requested_file, from)
241
- # Remove extension
242
250
  file = requested_file
243
- extension = ''
244
-
245
- file.sub(/^(.*)(\.[^\.]+)$/) { file, extension = $1, $2 }
251
+ extension = File.extname(requested_file)
252
+ # Remove extension
253
+ file.gsub!(/#{extension}$/, "")
254
+ # Remove cache-buster (/js/app.28389 => /js/app)
255
+ file.gsub!(/\.[0-9]+$/, "")
256
+ matches = Dir[File.join(app.root, from, "#{file}.*")]
246
257
 
247
- # Remove cache-buster (/js/app.28389.js => /js/app)
248
- file = $1 if file =~ /^(.*)\.[0-9]+$/
258
+ # Fix for filenames with dots (can't do this with glob)
259
+ matches.select! { |f| f =~ /#{file}\.[^.]+$/ }
249
260
 
250
- Dir[File.join(app.root, from, "#{file}#{extension}")].first
261
+ # Sort static file match, weighting exact file extension matches
262
+ matches.sort! do |f, _|
263
+ (File.basename(f) == "#{file}#{extension}" || File.extname(f) == extension) ? -1 : 1
264
+ end
265
+ matches.first
251
266
  end
252
267
 
253
268
  # Writes `public/#{path}` based on contents of `output`.
@@ -258,7 +273,7 @@ module Sinatra
258
273
  yield path if block_given?
259
274
 
260
275
  FileUtils.mkdir_p File.dirname(path)
261
- File.open(path, 'w') { |f| f.write output }
276
+ File.open(path, 'wb') { |f| f.write output }
262
277
 
263
278
  if mtime
264
279
  File.utime mtime, mtime, path
@@ -305,7 +320,7 @@ module Sinatra
305
320
  paths = paths.uniq
306
321
  tuples = paths.map { |key| [key, files[key]] }
307
322
 
308
- HashArray[*tuples.flatten]
323
+ Hash[*tuples.flatten]
309
324
  end
310
325
 
311
326
  private
@@ -96,9 +96,12 @@ module Sinatra
96
96
  session = Rack::Test::Session.new(@assets.app)
97
97
  paths.map { |path|
98
98
  result = session.get(path)
99
- response_encoding = result.content_type.split(/;\s*charset\s*=\s*/).last.upcase rescue 'ASCII-8BIT'
100
- # p [:combined, path, result.body.encoding.name, response_encoding]
101
- result.body.force_encoding(response_encoding).encode(Encoding.default_external || 'ASCII-8BIT') if result.status == 200
99
+ if result.body.respond_to?(:force_encoding)
100
+ response_encoding = result.content_type.split(/;\s*charset\s*=\s*/).last.upcase rescue 'ASCII-8BIT'
101
+ result.body.force_encoding(response_encoding).encode(Encoding.default_external || 'ASCII-8BIT') if result.status == 200
102
+ else
103
+ result.body if result.status == 200
104
+ end
102
105
  }.join("\n")
103
106
  end
104
107
 
@@ -107,18 +110,22 @@ module Sinatra
107
110
 
108
111
  private
109
112
  def link_tag(file, options={})
110
- # allow for building of assets from an application context and CDN host
111
113
  context = options[:context]
112
114
  host = options[:host]
113
- file = "#{context}#{file}" unless context.nil? || context.empty?
114
- file = "#{host}#{file}" unless host.nil? || host.empty?
115
+
116
+ file_path = HtmlHelpers.get_file_uri(file, @assets)
117
+
118
+ file_path = "#{context}#{file_path}" unless context.nil? || context.empty?
119
+ file_path = "#{host}#{file_path}" unless host.nil? || host.empty?
120
+
115
121
  options_copy = options.clone
116
122
  options_copy.delete(:context)
117
123
  options_copy.delete(:host)
124
+
118
125
  if js?
119
- "<script src='#{e file}'#{kv options_copy}></script>"
126
+ "<script src='#{file_path}'#{kv options_copy}></script>"
120
127
  elsif css?
121
- "<link rel='stylesheet' href='#{e file}'#{kv options_copy} />"
128
+ "<link rel='stylesheet' href='#{file_path}'#{kv options_copy} />"
122
129
  end
123
130
  end
124
131
  end
@@ -1,7 +1,7 @@
1
1
  module Sinatra
2
2
  module AssetPack
3
3
  def self.version
4
- "0.0.12.pre1"
4
+ "0.1.6"
5
5
  end
6
6
  end
7
7
  end
@@ -15,6 +15,9 @@ Gem::Specification.new do |s|
15
15
  s.add_dependency "sinatra"
16
16
  s.add_dependency "jsmin"
17
17
  s.add_dependency "rack-test"
18
+ if RUBY_VERSION < "1.9"
19
+ s.add_runtime_dependency "backports"
20
+ end
18
21
  s.add_development_dependency "yui-compressor"
19
22
  s.add_development_dependency "sass"
20
23
  s.add_development_dependency "haml"
@@ -23,4 +26,6 @@ Gem::Specification.new do |s|
23
26
  s.add_development_dependency "mocha"
24
27
  s.add_development_dependency "stylus"
25
28
  s.add_development_dependency "uglifier"
29
+ s.add_development_dependency "rake"
30
+ s.add_development_dependency "less"
26
31
  end
data/test/app/app.rb CHANGED
@@ -14,9 +14,15 @@ class Main < Sinatra::Base
14
14
  disable :show_exceptions
15
15
 
16
16
  assets {
17
- #serve '/js', :from => 'app/js'
17
+ serve '/js', :from => 'app/js'
18
18
  serve '/css', :from => 'app/css'
19
19
  serve '/images', :from => 'app/images'
20
+ serve '/fonts', :from => 'app/fonts'
21
+ serve '/packages', :from => 'app/packages'
22
+
23
+ js :a_package, '/packages/a_package.js', [
24
+ '/packages/a_package/package.js',
25
+ ]
20
26
 
21
27
  js :skitch, '/skitch.js', [
22
28
  '/js/hi.js',
@@ -52,6 +58,7 @@ class Main < Sinatra::Base
52
58
  '/css/scre*.css',
53
59
  '/css/screen.css'
54
60
  ]
61
+
55
62
  }
56
63
 
57
64
  get '/index.html' do
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata></metadata>
5
+ <defs>
6
+ <font id="cantarellregular" horiz-adv-x="748" >
7
+ <font-face units-per-em="2048" ascent="1513" descent="-535" />
8
+ <missing-glyph horiz-adv-x="559" />
9
+ <glyph horiz-adv-x="2048" />
10
+ <glyph horiz-adv-x="2048" />
11
+ <glyph unicode="&#xd;" horiz-adv-x="682" />
12
+ <glyph unicode=" " horiz-adv-x="559" />
13
+ <glyph unicode="&#x09;" horiz-adv-x="559" />
14
+ <glyph unicode="&#xa0;" horiz-adv-x="559" />
15
+ <glyph unicode="A" horiz-adv-x="1382" d="M129 0l506 1421h192l506 -1421h-172l-143 414h-588l-143 -414h-158zM481 561h484l-240 694z" />
16
+ <glyph unicode="&#xe000;" horiz-adv-x="985" d="M0 0v985h985v-985h-985z" />
17
+ </font>
18
+ </defs></svg>
@@ -0,0 +1 @@
1
+ $(function() { alert("Hello"); });
@@ -0,0 +1 @@
1
+ .hi { color: red; }
@@ -0,0 +1 @@
1
+ $(function() { alert("Hello"); });
@@ -0,0 +1,2 @@
1
+ require './app'
2
+ run Main
data/test/arity_test.rb CHANGED
@@ -17,8 +17,14 @@ class ArityTest < UnitTest
17
17
 
18
18
  test "arity in #assets" do
19
19
  paths = App.assets.packages['a.css'].paths
20
- assert_equal paths,
21
- [ "/css/screen.css", "/css/sqwishable.css", "/css/style.css", "/css/stylus.css", "/css/js2c.css" ]
20
+ expect = [ "/css/screen.css", "/css/sqwishable.css", "/css/style.css", "/css/stylus.css", "/css/js2c.css" ]
21
+ if RUBY_VERSION < "1.9"
22
+ # In 1.8.7 glob returns inconsitent files order so just check array are equivalents
23
+ assert_equal expect.size, paths.size
24
+ assert_equal 0, paths.reject{ |p| expect.include?(p) }.size
25
+ else
26
+ assert_equal expect, paths
27
+ end
22
28
 
23
29
  assert App.assets.js_compression == :closure
24
30
  assert App.assets.css_compression == :yui
data/test/cache_test.rb CHANGED
@@ -1,8 +1,24 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class CacheTest < UnitTest
4
+ class App < UnitTest::App
5
+ register Sinatra::AssetPack
6
+
7
+ set :reload_templates, false
8
+ assets {
9
+ js :app, '/js/app.js', [
10
+ '/js/vendor/**/*.js',
11
+ '/js/assets/**/*.js',
12
+ '/js/hi.js',
13
+ '/js/hell*.js'
14
+ ]
15
+ js_compression :jsmin
16
+ }
17
+ end
18
+
19
+ def app() App; end
20
+
4
21
  test "Compressed js caching" do
5
- app.set :reload_templates, false
6
22
  JSMin.expects(:minify).times(1).returns ""
7
23
  3.times { get '/js/app.js' }
8
24
  end
data/test/glob_test.rb CHANGED
@@ -21,6 +21,7 @@ class GlobTest < UnitTest
21
21
  end
22
22
 
23
23
  should "match double-star globs recursively" do
24
+ app.stubs(:development?).returns(true)
24
25
  get '/a'
25
26
  assert body.include?("a/b/c1/hello.")
26
27
  assert body.include?("a/b/c2/hi.")
@@ -28,12 +29,14 @@ class GlobTest < UnitTest
28
29
  end
29
30
 
30
31
  should "match single-star globs in filenames" do
32
+ app.stubs(:development?).returns(true)
31
33
  get '/b'
32
34
  assert body.include?("a/b/c2/hi.")
33
35
  assert body.include?("a/b/c2/hola.")
34
36
  end
35
37
 
36
38
  should "match single-star globs in paths" do
39
+ app.stubs(:development?).returns(true)
37
40
  get '/c'
38
41
  assert body.include?("a/b/c1/hello.")
39
42
  assert body.include?("a/b/c2/hi.")
data/test/ignore_test.rb CHANGED
@@ -20,8 +20,8 @@ class IgnoreTest < UnitTest
20
20
 
21
21
  test "ignore in package" do
22
22
  get '/main.js'
23
- assert body.size > 0
24
- assert !body.include?("BUMBLEBEE")
23
+ assert last_response.body.size > 0
24
+ assert !last_response.body.include?("BUMBLEBEE")
25
25
  end
26
26
 
27
27
  test "package files" do
data/test/img_test.rb CHANGED
@@ -13,14 +13,14 @@ class ImgTest < UnitTest
13
13
  assert_equal last_response.headers['Content-Length'], File.size(r("/app/images/email.png")).to_s
14
14
  end
15
15
 
16
- test "Image[]" do
16
+ test "compare" do
17
17
  i = Image['/app/images/email.png']
18
18
  j = Image['/app/images/email.png']
19
19
 
20
20
  assert j === i
21
21
  end
22
22
 
23
- test "Image[]" do
23
+ test "dimensions" do
24
24
  i = Image['/app/images/email.png']
25
25
  j = Image['/app/images/email.png']
26
26
 
@@ -6,6 +6,7 @@ class LocalFileTest < UnitTest
6
6
 
7
7
  assets {
8
8
  css :application, [ '/css/*.css' ]
9
+ serve '/fonts', :from => 'app/fonts'
9
10
  }
10
11
  end
11
12
 
@@ -14,6 +15,11 @@ class LocalFileTest < UnitTest
14
15
  assert_equal r('app/images/background.jpg'), fn
15
16
  end
16
17
 
18
+ test "local file for (in existing files, custom serve path)" do
19
+ fn = App.assets.local_file_for '/fonts/cantarell-regular-webfont.ttf'
20
+ assert_equal r('app/fonts/cantarell-regular-webfont.ttf'), fn
21
+ end
22
+
17
23
  test "local file for (in nonexisting files)" do
18
24
  fn = App.assets.local_file_for '/images/404.jpg'
19
25
  assert fn.nil?
@@ -30,4 +30,24 @@ class AppTest < UnitTest
30
30
  get '/skitch.js'
31
31
  assert last_response.content_type =~ %r[^.*?/javascript]
32
32
  end
33
+
34
+ test 'eot' do
35
+ get '/fonts/cantarell-regular-webfont.eot'
36
+ assert last_response.content_type =~ %r[^application/vnd.ms-fontobject]
37
+ end
38
+
39
+ test 'svg' do
40
+ get '/fonts/cantarell-regular-webfont.svg'
41
+ assert last_response.content_type =~ %r[^image/svg\+xml]
42
+ end
43
+
44
+ test 'ttf' do
45
+ get '/fonts/cantarell-regular-webfont.ttf'
46
+ assert last_response.content_type =~ %r[^application/octet-stream]
47
+ end
48
+
49
+ test 'woff' do
50
+ get '/fonts/cantarell-regular-webfont.woff'
51
+ assert last_response.content_type =~ %r[^application/font-woff]
52
+ end
33
53
  end
@@ -5,6 +5,7 @@ class RedundantTest < UnitTest
5
5
  Main.get("/helpers/css/redundant") { css :redundant }
6
6
 
7
7
  test "redundant" do
8
+ app.stubs(:development?).returns(true)
8
9
  get '/helpers/css/redundant'
9
10
  assert body.scan(/screen/).count == 1
10
11
  end
data/test/sqwish_test.rb CHANGED
@@ -2,6 +2,7 @@ require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class SqwishTest < UnitTest
4
4
  setup do
5
+ app.set :reload_templates, true
5
6
  app.assets.css_compression :sqwish, :strict => true
6
7
  end
7
8
 
@@ -20,10 +21,10 @@ class SqwishTest < UnitTest
20
21
 
21
22
  if sqwish?
22
23
  test "build" do
23
- Sinatra::AssetPack::Compressor
24
- Sinatra::AssetPack::SqwishEngine.any_instance.expects(:css)
25
-
24
+ swqished_css = '#bg{background:green;color:red}'
25
+ Sinatra::AssetPack::SqwishEngine.any_instance.expects(:css).returns swqished_css
26
26
  get '/css/sq.css'
27
+ assert body == swqished_css
27
28
  end
28
29
  else
29
30
  puts "(No Sqwish found; skipping sqwish tests)"
data/test/test_helper.rb CHANGED
@@ -1,10 +1,15 @@
1
1
  require 'contest'
2
2
  require 'jsmin'
3
3
  require 'tilt'
4
+ require 'haml'
5
+ require 'sass'
4
6
  require 'stylus'
7
+ require 'stylus/tilt'
5
8
  require 'rack/test'
6
9
  require 'yaml'
7
- require 'mocha'
10
+ require 'mocha/setup'
11
+
12
+ ENV['RACK_ENV'] = 'test'
8
13
 
9
14
  require File.expand_path('../app/app.rb', __FILE__)
10
15
 
data/test/tilt_test.rb CHANGED
@@ -5,6 +5,7 @@ class OptionsTest < UnitTest
5
5
  @formats = Sinatra::AssetPack.tilt_formats
6
6
  assert @formats['sass'] == 'css'
7
7
  assert @formats['scss'] == 'css'
8
+ assert @formats['less'] == 'css'
8
9
  assert @formats['coffee'] == 'js'
9
10
  end
10
11
  end