dassets 0.14.5 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,15 @@
1
- require 'dassets/engine'
1
+ # frozen_string_literal: true
2
+
3
+ require "dassets/engine"
2
4
 
3
5
  module Dassets; end
4
6
  class Dassets::Source
5
-
6
7
  attr_reader :path, :engines, :response_headers
7
8
 
8
9
  def initialize(path)
9
10
  @path = path.to_s
10
11
  @filter = proc{ |paths| paths }
11
- @engines = Hash.new{ |h,k| Dassets::NullEngine.new }
12
+ @engines = Hash.new{ |hash, key| hash[key] = [] }
12
13
  @response_headers = Hash.new
13
14
  end
14
15
 
@@ -16,10 +17,10 @@ class Dassets::Source
16
17
  block.nil? ? @filter : @filter = block
17
18
  end
18
19
 
19
- def engine(input_ext, engine_class, registered_opts=nil)
20
- default_opts = { 'source_path' => @path }
20
+ def engine(input_ext, engine_class, registered_opts = nil)
21
+ default_opts = { "source_path" => @path }
21
22
  engine_opts = default_opts.merge(registered_opts || {})
22
- @engines[input_ext.to_s] = engine_class.new(engine_opts)
23
+ @engines[input_ext.to_s] << engine_class.new(engine_opts)
23
24
  end
24
25
 
25
26
  def files
@@ -28,12 +29,16 @@ class Dassets::Source
28
29
 
29
30
  private
30
31
 
32
+ # Use "**{,/*/**}/*" to glob following symlinks and returning immediate-child
33
+ # matches. See https://stackoverflow.com/a/2724048.
31
34
  def glob_files
32
- Dir.glob(File.join(@path, "**/*")).reject!{ |p| !File.file?(p) }
35
+ Dir
36
+ .glob(File.join(@path, "**{,/*/**}/*"))
37
+ .uniq
38
+ .reject{ |path| !File.file?(path) }
33
39
  end
34
40
 
35
41
  def apply_filter(files)
36
42
  @filter.call(files)
37
43
  end
38
-
39
44
  end
@@ -1,114 +1,132 @@
1
- require 'fileutils'
2
- require 'dassets'
3
- require 'dassets/asset_file'
4
- require 'dassets/source_proxy'
1
+ # frozen_string_literal: true
5
2
 
6
- module Dassets
3
+ require "fileutils"
4
+ require "dassets"
5
+ require "dassets/asset_file"
6
+ require "dassets/source_proxy"
7
7
 
8
- class SourceFile
9
-
10
- def self.find_by_digest_path(path, options = nil)
11
- Dassets.source_files[path] || NullSourceFile.new(path, options)
12
- end
8
+ module Dassets; end
9
+ class Dassets::SourceFile
10
+ def self.find_by_digest_path(path, **options)
11
+ Dassets.source_files[path] || Dassets::NullSourceFile.new(path, **options)
12
+ end
13
13
 
14
- attr_reader :file_path
14
+ attr_reader :file_path
15
15
 
16
- def initialize(file_path)
17
- @file_path = file_path.to_s
18
- @ext_list = File.basename(@file_path).split('.').reverse
19
- end
16
+ def initialize(file_path)
17
+ @file_path = file_path.to_s
18
+ @ext_list = File.basename(@file_path).split(".").reverse
19
+ end
20
20
 
21
- # get the last matching one (in the case two sources with the same path are
22
- # configured) since we select the last matching source file (from the last
23
- # configured source) in `find_by_digest_path` above.
24
- def source
25
- @source ||= Dassets.config.sources.select do |source|
21
+ # Get the last matching one (in the case two sources with the same path are
22
+ # configured) since we select the last matching source file (from the last
23
+ # configured source) in `find_by_digest_path` above.
24
+ def source
25
+ @source ||=
26
+ Dassets.config.sources.select { |source|
26
27
  @file_path =~ /^#{slash_path(source.path)}/
27
- end.last
28
- end
28
+ }.last
29
+ end
29
30
 
30
- def asset_file
31
- @asset_file ||= Dassets::AssetFile.new(self.digest_path)
32
- end
31
+ def asset_file
32
+ @asset_file ||= Dassets::AssetFile.new(self.digest_path)
33
+ end
33
34
 
34
- def digest_path
35
- @digest_path ||= begin
36
- digest_basename = @ext_list.inject([]) do |digest_ext_list, ext|
37
- digest_ext_list << self.source.engines[ext].ext(ext)
38
- end.reject(&:empty?).reverse.join('.')
35
+ def digest_path
36
+ @digest_path ||=
37
+ begin
38
+ digest_basename =
39
+ @ext_list
40
+ .reduce([]) { |digest_ext_list, ext|
41
+ digest_ext_list <<
42
+ self.source.engines[ext].reduce(ext) { |ext_acc, engine|
43
+ engine.ext(ext_acc)
44
+ }
45
+ }
46
+ .reject(&:empty?)
47
+ .reverse
48
+ .join(".")
39
49
 
40
50
  File.join([digest_dirname(@file_path), digest_basename].reject(&:empty?))
41
51
  end
42
- end
52
+ end
43
53
 
44
- def compiled
45
- @ext_list.inject(read_file(@file_path)) do |content, ext|
46
- self.source.engines[ext].compile(content)
47
- end
48
- end
54
+ def compiled
55
+ @ext_list.reduce(read_file(@file_path)) { |file_acc, ext|
56
+ self.source.engines[ext].reduce(file_acc) { |ext_acc, engine|
57
+ engine.compile(ext_acc)
58
+ }
59
+ }
60
+ end
49
61
 
50
- def exists?
51
- File.file?(@file_path)
52
- end
62
+ def exists?
63
+ File.file?(@file_path)
64
+ end
53
65
 
54
- def mtime
55
- File.mtime(@file_path)
56
- end
66
+ def mtime
67
+ File.mtime(@file_path)
68
+ end
57
69
 
58
- def response_headers
59
- self.source.nil? ? Hash.new : self.source.response_headers
60
- end
70
+ def response_headers
71
+ self.source.nil? ? Hash.new : self.source.response_headers
72
+ end
61
73
 
62
- def ==(other_source_file)
74
+ def ==(other_source_file)
75
+ if other_source_file.is_a?(self.class)
63
76
  self.file_path == other_source_file.file_path
77
+ else
78
+ super
64
79
  end
80
+ end
65
81
 
66
- private
67
-
68
- # remove the source path from the dirname (if it exists)
69
- def digest_dirname(file_path)
70
- slash_path(File.dirname(file_path)).sub(slash_path(self.source.path), '')
71
- end
72
-
73
- def slash_path(path)
74
- File.join(path, '')
75
- end
76
-
77
- def read_file(path)
78
- File.send(File.respond_to?(:binread) ? :binread : :read, path.to_s)
79
- end
82
+ private
80
83
 
84
+ # remove the source path from the dirname (if it exists)
85
+ def digest_dirname(file_path)
86
+ slash_path(File.dirname(file_path)).sub(slash_path(self.source.path), "")
81
87
  end
82
88
 
83
- # A null source file is used to represent source that either doesn't exist
84
- # or source that is a proxy (ie a combination)
89
+ def slash_path(path)
90
+ File.join(path, "")
91
+ end
85
92
 
86
- class NullSourceFile < SourceFile
93
+ def read_file(path)
94
+ File.send(File.respond_to?(:binread) ? :binread : :read, path.to_s)
95
+ end
96
+ end
87
97
 
88
- def initialize(digest_path, options = nil)
89
- @file_path, @ext_list = '', []
90
- @digest_path = digest_path
91
- @source_proxy = if Dassets.config.combination?(@digest_path)
92
- SourceProxy.new(@digest_path, options)
98
+ # A null source file is used to represent source that either doesn't exist
99
+ # or source that is a proxy (ie a combination)
100
+ class Dassets::NullSourceFile < Dassets::SourceFile
101
+ def initialize(digest_path, **options)
102
+ @file_path = ""
103
+ @ext_list = []
104
+ @digest_path = digest_path
105
+ @source_proxy =
106
+ if Dassets.config.combination?(@digest_path)
107
+ Dassets::SourceProxy.new(@digest_path, **options)
93
108
  else
94
- NullSourceProxy.new
109
+ Dassets::NullSourceProxy.new
95
110
  end
96
- end
97
-
98
- def compiled; @source_proxy.content; end
99
- def exists?; @source_proxy.exists?; end
100
- def mtime; @source_proxy.mtime; end
111
+ end
101
112
 
102
- def ==(other_source_file)
103
- self.file_path == other_source_file.file_path
104
- end
113
+ def compiled
114
+ @source_proxy.content
115
+ end
105
116
 
106
- class NullSourceProxy
107
- def content; nil; end
108
- def exists?; false; end
109
- def mtime; nil; end
110
- end
117
+ def exists?
118
+ @source_proxy.exists?
119
+ end
111
120
 
121
+ def mtime
122
+ @source_proxy.mtime
112
123
  end
113
124
 
125
+ def ==(other_source_file)
126
+ if other_source_file.is_a?(self.class)
127
+ self.file_path == other_source_file.file_path
128
+ else
129
+ super
130
+ end
131
+ end
114
132
  end
@@ -1,22 +1,25 @@
1
- require 'digest/md5'
2
- require 'dassets/cache'
3
- require 'dassets/source_file'
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+ require "dassets/cache"
5
+ require "dassets/source_file"
4
6
 
5
7
  module Dassets; end
6
- class Dassets::SourceProxy
7
8
 
9
+ class Dassets::SourceProxy
8
10
  attr_reader :digest_path, :content_cache, :fingerprint_cache
9
11
  attr_reader :source_files
10
12
 
11
- def initialize(digest_path, options = nil)
12
- options ||= {}
13
+ def initialize(digest_path, **options)
13
14
  @digest_path = digest_path
14
- @content_cache = options[:content_cache] || Dassets::Cache::NoCache.new
15
- @fingerprint_cache = options[:fingerprint_cache] || Dassets::Cache::NoCache.new
16
- @source_files = get_source_files(@digest_path, {
17
- :content_cache => @content_cache,
18
- :fingerprint_cache => @fingerprint_cache
19
- })
15
+ @content_cache = options[:content_cache] || Dassets::NoCache.new
16
+ @fingerprint_cache = options[:fingerprint_cache] || Dassets::NoCache.new
17
+ @source_files =
18
+ get_source_files(
19
+ @digest_path,
20
+ content_cache: @content_cache,
21
+ fingerprint_cache: @fingerprint_cache,
22
+ )
20
23
  end
21
24
 
22
25
  def key
@@ -53,10 +56,23 @@ class Dassets::SourceProxy
53
56
  Digest::MD5.new.hexdigest(source_content)
54
57
  end
55
58
 
56
- def get_source_files(digest_path, options)
57
- Dassets.config.combinations[digest_path.to_s].map do |source_digest_path|
58
- Dassets::SourceFile.find_by_digest_path(source_digest_path, options)
59
- end
59
+ def get_source_files(digest_path, **options)
60
+ Dassets.config.combinations[digest_path.to_s].map { |source_digest_path|
61
+ Dassets::SourceFile.find_by_digest_path(source_digest_path, **options)
62
+ }
63
+ end
64
+ end
65
+
66
+ class Dassets::NullSourceProxy
67
+ def content
68
+ nil
69
+ end
70
+
71
+ def exists?
72
+ false
60
73
  end
61
74
 
75
+ def mtime
76
+ nil
77
+ end
62
78
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dassets
2
- VERSION = "0.14.5"
4
+ VERSION = "0.15.0"
3
5
  end
@@ -5,39 +5,33 @@
5
5
  $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
6
6
 
7
7
  # require pry for debugging (`binding.pry`)
8
- require 'pry'
8
+ require "pry"
9
9
 
10
- require 'test/support/factory'
10
+ require "test/support/factory"
11
11
 
12
- # 1.8.7 backfills
12
+ require "pathname"
13
+ TEST_SUPPORT_PATH = Pathname.new(File.expand_path("../support", __FILE__))
13
14
 
14
- # Array#sample
15
- if !(a = Array.new).respond_to?(:sample) && a.respond_to?(:choice)
16
- class Array
17
- alias_method :sample, :choice
18
- end
19
- end
15
+ ENV["DASSETS_TEST_MODE"] = "yes"
20
16
 
21
- require 'pathname'
22
- TEST_SUPPORT_PATH = Pathname.new(File.expand_path('../support', __FILE__))
17
+ require "dassets"
23
18
 
24
- ENV['DASSETS_TEST_MODE'] = 'yes'
25
-
26
- require 'dassets'
19
+ @dumb_engine =
20
+ Class.new(Dassets::Engine) do
21
+ def ext(in_ext); ""; end
22
+ def compile(input); "#{input}\nDUMB"; end
23
+ end
27
24
 
28
- @dumb_engine = Class.new(Dassets::Engine) do
29
- def ext(in_ext); ''; end
30
- def compile(input); "#{input}\nDUMB"; end
31
- end
32
- @useless_engine = Class.new(Dassets::Engine) do
33
- def ext(in_ext); 'no-use'; end
34
- def compile(input); "#{input}\nUSELESS"; end
35
- end
25
+ @useless_engine =
26
+ Class.new(Dassets::Engine) do
27
+ def ext(in_ext); "no-use"; end
28
+ def compile(input); "#{input}\nUSELESS"; end
29
+ end
36
30
 
37
31
  Dassets.configure do |c|
38
32
  c.source TEST_SUPPORT_PATH.join("app/assets") do |s|
39
- s.engine 'dumb', @dumb_engine
40
- s.engine 'useless', @useless_engine
33
+ s.engine "dumb", @dumb_engine
34
+ s.engine "useless", @useless_engine
41
35
  s.response_headers[Factory.string] = Factory.string
42
36
  end
43
37
  end
@@ -1,10 +1,8 @@
1
- require 'sinatra/base'
1
+ require "sinatra/base"
2
2
 
3
3
  class SinatraApp < Sinatra::Base
4
-
5
4
  configure do
6
- set :root, File.expand_path('..', __FILE__)
7
- set :public_dir, File.expand_path('./app_public', __FILE__)
5
+ set :root, File.expand_path("..", __FILE__)
6
+ set :public_dir, File.expand_path("./app_public", __FILE__)
8
7
  end
9
-
10
8
  end
@@ -1,4 +1,4 @@
1
- require 'assert/factory'
1
+ require "assert/factory"
2
2
 
3
3
  module Factory
4
4
  extend Assert::Factory
@@ -6,5 +6,4 @@ module Factory
6
6
  def self.base_url
7
7
  Factory.boolean ? Factory.url : nil
8
8
  end
9
-
10
9
  end
@@ -0,0 +1 @@
1
+ ../linked_source_files/
@@ -0,0 +1 @@
1
+ ../linked_source_files/linked_file.txt
@@ -1,13 +1,12 @@
1
- require 'assert'
2
- require 'dassets'
1
+ require "assert"
2
+ require "dassets"
3
3
 
4
- require 'assert-rack-test'
5
- require 'fileutils'
6
- require 'dassets/server'
7
- require 'test/support/app'
4
+ require "assert-rack-test"
5
+ require "fileutils"
6
+ require "dassets/server"
7
+ require "test/support/app"
8
8
 
9
9
  module Dassets
10
-
11
10
  class RackTests < Assert::Context
12
11
  include Assert::Rack::Test
13
12
 
@@ -19,121 +18,118 @@ module Dassets
19
18
  def app
20
19
  @app ||= SinatraApp
21
20
  end
22
-
23
21
  end
24
22
 
25
23
  class SuccessTests < RackTests
26
24
  desc "requesting an existing asset file"
27
25
 
28
26
  should "return a successful response" do
29
- resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt'
30
- assert_equal 200, resp.status
31
- assert_equal Dassets['file1.txt'].content, resp.body
27
+ resp = get "/file1-daa05c683a4913b268653f7a7e36a5b4.txt"
28
+
29
+ assert_that(resp.status).equals(200)
30
+ assert_that(resp.body).equals(Dassets["file1.txt"].content)
32
31
  end
33
32
 
34
33
  should "return a successful response with no body on HEAD requests" do
35
- resp = head '/file2-9bbe1047cffbb590f59e0e5aeff46ae4.txt'
36
- assert_equal 200, resp.status
37
- assert_equal Dassets['file2.txt'].size.to_s, resp.headers['Content-Length']
38
- assert_empty resp.body
34
+ resp = head "/file2-9bbe1047cffbb590f59e0e5aeff46ae4.txt"
35
+
36
+ assert_that(resp.status).equals(200)
37
+ assert_that(resp.headers["Content-Length"])
38
+ .equals(Dassets["file2.txt"].size.to_s)
39
+ assert_that(resp.body).is_empty
39
40
  end
40
41
 
41
42
  should "return a partial content response on valid partial content requests" do
42
- content = Dassets['file1.txt'].content
43
+ content = Dassets["file1.txt"].content
43
44
  size = Factory.integer(content.length)
44
-
45
45
  # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
46
- env = { 'HTTP_RANGE' => "bytes=0-#{size}" }
46
+ env = { "HTTP_RANGE" => "bytes=0-#{size}" }
47
+ resp = get "/file1-daa05c683a4913b268653f7a7e36a5b4.txt", {}, env
47
48
 
48
- resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, env
49
- assert_equal 206, resp.status
50
- assert_equal content[0..size], resp.body
49
+ assert_that(resp.status).equals(206)
50
+ assert_that(resp.body).equals(content[0..size])
51
51
  end
52
52
 
53
53
  should "return a full response on no-range partial content requests" do
54
54
  # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
55
- env = { 'HTTP_RANGE' => 'bytes=' }
55
+ env = { "HTTP_RANGE" => "bytes=" }
56
+ resp = get "/file1-daa05c683a4913b268653f7a7e36a5b4.txt", {}, env
56
57
 
57
- resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, env
58
- assert_equal 200, resp.status
59
- assert_equal Dassets['file1.txt'].content, resp.body
58
+ assert_that(resp.status).equals(200)
59
+ assert_that(resp.body).equals(Dassets["file1.txt"].content)
60
60
  end
61
61
 
62
62
  should "return a full response on multiple-range partial content requests" do
63
63
  # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
64
- env = { 'HTTP_RANGE' => 'bytes=0-1,2-3' }
64
+ env = { "HTTP_RANGE" => "bytes=0-1,2-3" }
65
+ resp = get "/file1-daa05c683a4913b268653f7a7e36a5b4.txt", {}, env
65
66
 
66
- resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, env
67
- assert_equal 200, resp.status
68
- assert_equal Dassets['file1.txt'].content, resp.body
67
+ assert_that(resp.status).equals(200)
68
+ assert_that(resp.body).equals(Dassets["file1.txt"].content)
69
69
  end
70
70
 
71
71
  should "return a full response on invalid-range partial content requests" do
72
72
  # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
73
- env = { 'HTTP_RANGE' => ['bytes=3-2', 'bytes=abc'].sample }
73
+ env = { "HTTP_RANGE" => ["bytes=3-2", "bytes=abc"].sample }
74
+ resp = get "/file1-daa05c683a4913b268653f7a7e36a5b4.txt", {}, env
74
75
 
75
- resp = get '/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, env
76
- assert_equal 200, resp.status
77
- assert_equal Dassets['file1.txt'].content, resp.body
76
+ assert_that(resp.status).equals(200)
77
+ assert_that(resp.body).equals(Dassets["file1.txt"].content)
78
78
  end
79
-
80
79
  end
81
80
 
82
81
  class DigestTests < SuccessTests
83
82
  setup do
84
83
  base_url = Factory.base_url
85
84
  Assert.stub(Dassets.config, :base_url){ base_url }
86
- Dassets.config.file_store TEST_SUPPORT_PATH.join('public').to_s
87
- @url = Dassets['file1.txt'].url
85
+ Dassets.config.file_store TEST_SUPPORT_PATH.join("public").to_s
86
+ @url = Dassets["file1.txt"].url
88
87
  @url_file = Dassets.config.file_store.store_path(@url)
89
88
  end
89
+
90
90
  teardown do
91
91
  FileUtils.rm(@url_file)
92
- Dassets.config.file_store FileStore::NullStore.new
92
+ Dassets.config.file_store Dassets::NullFileStore.new
93
93
  end
94
94
 
95
95
  should "digest the asset" do
96
- assert_not_file_exists @url_file
96
+ assert_that(@url_file).is_not_a_file
97
97
 
98
98
  resp = get @url
99
- assert_equal 200, resp.status
100
- assert_file_exists @url_file
99
+ assert_that(resp.status).equals(200)
100
+ assert_that(@url_file).is_a_file
101
101
  end
102
-
103
102
  end
104
103
 
105
104
  class NotModifiedTests < RackTests
106
105
  desc "requesting an existing asset file that has not been modified"
107
- setup do
108
- @resp = get('/file1-daa05c683a4913b268653f7a7e36a5b4.txt', {}, {
109
- 'HTTP_IF_MODIFIED_SINCE' => Dassets['file1.txt'].mtime.to_s
110
- })
111
- end
112
106
 
113
107
  should "return a successful response" do
114
- assert_equal 304, @resp.status
115
- assert_empty @resp.body
116
- end
108
+ resp =
109
+ get("/file1-daa05c683a4913b268653f7a7e36a5b4.txt", {}, {
110
+ "HTTP_IF_MODIFIED_SINCE" => Dassets["file1.txt"].mtime.to_s
111
+ })
117
112
 
113
+ assert_that(resp.status).equals(304)
114
+ assert_that(resp.body).is_empty
115
+ end
118
116
  end
119
117
 
120
118
  class NotFoundTests < RackTests
121
119
  desc "requesting an non-existing asset file"
122
120
 
123
121
  should "return a not found response" do
124
- resp = get '/file1-daa05c683a4913b268.txt'
125
- assert_equal 404, resp.status
122
+ resp = get "/file1-daa05c683a4913b268.txt"
123
+ assert_that(resp.status).equals(404)
126
124
 
127
- get '/file1-.txt'
128
- assert_equal 404, resp.status
125
+ resp = get "/file1-.txt"
126
+ assert_that(resp.status).equals(404)
129
127
 
130
- get '/file1.txt'
131
- assert_equal 404, resp.status
128
+ resp = get "/file1.txt"
129
+ assert_that(resp.status).equals(404)
132
130
 
133
- get '/something-not-found'
134
- assert_equal 404, resp.status
131
+ resp = get "/something-not-found"
132
+ assert_that(resp.status).equals(404)
135
133
  end
136
-
137
134
  end
138
-
139
135
  end