assiette 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/lib/assiette/asset_handler.rb +115 -0
- data/lib/assiette/helpers.rb +3 -3
- data/lib/assiette/rails_asset_url_helper.rb +21 -0
- data/lib/assiette/railtie.rb +6 -0
- data/lib/assiette/server.rb +9 -112
- data/lib/assiette/version.rb +1 -1
- data/lib/assiette.rb +7 -5
- data/lib/generators/assiette/install/templates/initializer.rb.tt +19 -11
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1267863146e1fa5c134f47f1cf797123609d8466690d3a39d9603fe9c35787ef
|
|
4
|
+
data.tar.gz: fcfbe591ac7de77fddb85bfe0d3b2cee0838ef30ac596aef612712b37294511a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d525c3fb1891574eac36d5b42ac82d5426b7a60e870a8001f4115edc15f32935e5559623a08ad849a6e580917788c25e16d39d64274deec47aa4291c3b399d8a
|
|
7
|
+
data.tar.gz: 3b35f41fec398a1ed00d3b18f2bec5167d14cd0af451d8cc838fa4f5957c21bf8d349e8fcc0a15d54ceeb788a9c78c0bb30e754baf44350c51961cf4e0836d53
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest/sha1"
|
|
4
|
+
require "digest/sha2"
|
|
5
|
+
require "base64"
|
|
6
|
+
require "pathname"
|
|
7
|
+
require_relative "version_tag"
|
|
8
|
+
|
|
9
|
+
module Assiette
|
|
10
|
+
class AssetHandler
|
|
11
|
+
CONTENT_TYPES = {
|
|
12
|
+
".js" => "application/javascript",
|
|
13
|
+
".mjs" => "application/javascript",
|
|
14
|
+
".css" => "text/css",
|
|
15
|
+
".svg" => "image/svg+xml",
|
|
16
|
+
".png" => "image/png",
|
|
17
|
+
".ico" => "image/x-icon"
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
JS_EXTENSIONS = %w[.js .mjs].to_set.freeze
|
|
21
|
+
|
|
22
|
+
def initialize(root:, additional_directory_mappings: {})
|
|
23
|
+
@mappings = build_mappings(root, additional_directory_mappings)
|
|
24
|
+
@integrity_cache = {}
|
|
25
|
+
@integrity_mutex = Mutex.new
|
|
26
|
+
@modules_cache = nil
|
|
27
|
+
@modules_mutex = Mutex.new
|
|
28
|
+
@modules_version = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def resolve_file(path)
|
|
32
|
+
clean = path.sub(%r{\A/}, "")
|
|
33
|
+
@mappings.each do |prefix, root|
|
|
34
|
+
if prefix.empty?
|
|
35
|
+
relative = clean
|
|
36
|
+
elsif clean.start_with?(prefix + "/")
|
|
37
|
+
relative = clean[(prefix.length + 1)..]
|
|
38
|
+
elsif clean == prefix
|
|
39
|
+
next
|
|
40
|
+
else
|
|
41
|
+
next
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
abs = root.join(relative).cleanpath
|
|
45
|
+
next unless abs.to_s.start_with?(root.to_s + "/")
|
|
46
|
+
return abs if abs.exist? && abs.file?
|
|
47
|
+
end
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def absolute_asset_url_path(path, script_name = "")
|
|
52
|
+
clean = path.sub(%r{\A/}, "")
|
|
53
|
+
return nil unless resolve_file(clean)
|
|
54
|
+
"#{script_name}/#{clean}?v=#{Assiette.version_tag}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def asset_integrity(path)
|
|
58
|
+
version_tag = Assiette.version_tag
|
|
59
|
+
@integrity_mutex.synchronize do
|
|
60
|
+
if @integrity_version != version_tag
|
|
61
|
+
@integrity_cache = {}
|
|
62
|
+
@integrity_version = version_tag
|
|
63
|
+
end
|
|
64
|
+
return @integrity_cache[path] if @integrity_cache.key?(path)
|
|
65
|
+
|
|
66
|
+
clean = path.sub(%r{\A/}, "")
|
|
67
|
+
@integrity_cache[path] = compute_integrity(clean, version_tag)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def js_modules
|
|
72
|
+
version_tag = Assiette.version_tag
|
|
73
|
+
@modules_mutex.synchronize do
|
|
74
|
+
return @modules_cache if @modules_version == version_tag
|
|
75
|
+
|
|
76
|
+
@modules_cache = @mappings.flat_map { |prefix, root|
|
|
77
|
+
Dir[File.join(root, "**/*.{js,mjs}")].filter_map { |abs|
|
|
78
|
+
next unless File.foreach(abs).any? { |line| line.match?(/\A\s*(import|export)\s/) }
|
|
79
|
+
relative = Pathname.new(abs).relative_path_from(root).to_s
|
|
80
|
+
mod_path = "/#{"#{prefix}/" unless prefix.empty?}#{relative}".squeeze("/")
|
|
81
|
+
{path: mod_path, integrity: asset_integrity(mod_path)}
|
|
82
|
+
}
|
|
83
|
+
}.uniq { |m| m[:path] }.sort_by { |m| m[:path] }
|
|
84
|
+
|
|
85
|
+
@modules_version = version_tag
|
|
86
|
+
@modules_cache
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def build_mappings(root, additional_directory_mappings)
|
|
93
|
+
mappings = [["", Pathname.new(root).expand_path]]
|
|
94
|
+
additional_directory_mappings.each do |prefix, path|
|
|
95
|
+
clean_prefix = prefix.to_s.sub(%r{\A/}, "").chomp("/")
|
|
96
|
+
mappings << [clean_prefix, Pathname.new(path).expand_path]
|
|
97
|
+
end
|
|
98
|
+
mappings
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def compute_integrity(clean, version_tag)
|
|
102
|
+
file_path = resolve_file(clean)
|
|
103
|
+
return nil unless file_path
|
|
104
|
+
|
|
105
|
+
raw = File.read(file_path)
|
|
106
|
+
ext = File.extname(clean)
|
|
107
|
+
served = case ext
|
|
108
|
+
when ".js", ".mjs" then Rewriter.rewrite_js_imports(raw, version_tag)
|
|
109
|
+
when ".css" then Rewriter.rewrite_css_urls(raw, version_tag)
|
|
110
|
+
else raw
|
|
111
|
+
end
|
|
112
|
+
"sha256-#{Base64.strict_encode64(Digest::SHA256.digest(served))}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
data/lib/assiette/helpers.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Assiette
|
|
|
7
7
|
def assiette_asset_path(path)
|
|
8
8
|
entry = request.env["assiette.stack"]&.last
|
|
9
9
|
raise "No Assiette::Server in middleware stack" unless entry
|
|
10
|
-
entry[:
|
|
10
|
+
entry[:handler].absolute_asset_url_path(path, entry[:script_name])
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Returns the SRI integrity hash for an asset, computed over the served
|
|
@@ -15,7 +15,7 @@ module Assiette
|
|
|
15
15
|
def assiette_asset_integrity(path)
|
|
16
16
|
entry = request.env["assiette.stack"]&.last
|
|
17
17
|
raise "No Assiette::Server in middleware stack" unless entry
|
|
18
|
-
entry[:
|
|
18
|
+
entry[:handler].asset_integrity(path)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# Generates a <link rel="stylesheet"> tag with SRI integrity.
|
|
@@ -30,7 +30,7 @@ module Assiette
|
|
|
30
30
|
def assiette_modulepreload_tags
|
|
31
31
|
entry = request.env["assiette.stack"]&.last
|
|
32
32
|
raise "No Assiette::Server in middleware stack" unless entry
|
|
33
|
-
modules = entry[:
|
|
33
|
+
modules = entry[:handler].js_modules
|
|
34
34
|
safe_join(modules.map { |mod|
|
|
35
35
|
tag.link(rel: "modulepreload", href: assiette_asset_path(mod[:path]),
|
|
36
36
|
integrity: mod[:integrity], crossorigin: "anonymous")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Assiette
|
|
4
|
+
# Include this module into ActionView::Base to make standard Rails asset
|
|
5
|
+
# helpers (image_tag, stylesheet_link_tag, etc.) resolve paths through
|
|
6
|
+
# an Assiette::AssetHandler assigned to Rails.application.assets.
|
|
7
|
+
#
|
|
8
|
+
# ActiveSupport.on_load(:action_view) do
|
|
9
|
+
# include Assiette::RailsAssetUrlHelper
|
|
10
|
+
# end
|
|
11
|
+
module RailsAssetUrlHelper
|
|
12
|
+
def compute_asset_path(source, options = {})
|
|
13
|
+
resolver = Rails.application.assets
|
|
14
|
+
if resolver.is_a?(Assiette::AssetHandler)
|
|
15
|
+
resolved = resolver.absolute_asset_url_path("/#{source}")
|
|
16
|
+
return resolved if resolved
|
|
17
|
+
end
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/assiette/railtie.rb
CHANGED
|
@@ -7,5 +7,11 @@ module Assiette
|
|
|
7
7
|
generators do
|
|
8
8
|
require_relative "../generators/assiette/install/install_generator"
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
initializer "assiette.rails_asset_url_helper" do
|
|
12
|
+
ActiveSupport.on_load(:action_view) do
|
|
13
|
+
include Assiette::RailsAssetUrlHelper
|
|
14
|
+
end
|
|
15
|
+
end
|
|
10
16
|
end
|
|
11
17
|
end
|
data/lib/assiette/server.rb
CHANGED
|
@@ -1,40 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "digest/sha1"
|
|
4
|
-
require "digest/sha2"
|
|
5
|
-
require "base64"
|
|
6
|
-
require "pathname"
|
|
7
|
-
require_relative "rewriter"
|
|
8
|
-
require_relative "version_tag"
|
|
9
|
-
|
|
10
3
|
module Assiette
|
|
11
4
|
class Server
|
|
12
|
-
CONTENT_TYPES = {
|
|
13
|
-
".js" => "application/javascript",
|
|
14
|
-
".mjs" => "application/javascript",
|
|
15
|
-
".css" => "text/css",
|
|
16
|
-
".svg" => "image/svg+xml",
|
|
17
|
-
".png" => "image/png",
|
|
18
|
-
".ico" => "image/x-icon"
|
|
19
|
-
}.freeze
|
|
20
|
-
|
|
21
|
-
JS_EXTENSIONS = %w[.js .mjs].to_set.freeze
|
|
22
|
-
|
|
23
5
|
CACHE_CONTROL = "public, max-age=432000, must-revalidate"
|
|
24
6
|
|
|
25
|
-
|
|
7
|
+
# Accepts either a pre-built handler or keyword args:
|
|
8
|
+
# Server.new(app, handler)
|
|
9
|
+
# Server.new(app, root: "...", additional_directory_mappings: {})
|
|
10
|
+
def initialize(app, handler = nil, root: nil, additional_directory_mappings: {})
|
|
26
11
|
@app = app
|
|
27
|
-
@
|
|
28
|
-
@integrity_cache = {}
|
|
29
|
-
@integrity_mutex = Mutex.new
|
|
30
|
-
@modules_cache = nil
|
|
31
|
-
@modules_mutex = Mutex.new
|
|
32
|
-
@modules_version = nil
|
|
12
|
+
@handler = handler || AssetHandler.new(root: root, additional_directory_mappings: additional_directory_mappings)
|
|
33
13
|
end
|
|
34
14
|
|
|
35
15
|
def call(env)
|
|
36
16
|
stack = (env["assiette.stack"] ||= [])
|
|
37
|
-
stack << {
|
|
17
|
+
stack << {handler: @handler, script_name: env["SCRIPT_NAME"].to_s}
|
|
38
18
|
|
|
39
19
|
result = serve(env)
|
|
40
20
|
return result if result
|
|
@@ -42,57 +22,8 @@ module Assiette
|
|
|
42
22
|
@app.call(env)
|
|
43
23
|
end
|
|
44
24
|
|
|
45
|
-
# Public API for helpers
|
|
46
|
-
def absolute_asset_url_path(path, script_name = "")
|
|
47
|
-
clean = path.sub(%r{\A/}, "")
|
|
48
|
-
return nil unless resolve_file(clean)
|
|
49
|
-
"#{script_name}/#{clean}?v=#{Assiette.version_tag}"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def asset_integrity(path)
|
|
53
|
-
version_tag = Assiette.version_tag
|
|
54
|
-
@integrity_mutex.synchronize do
|
|
55
|
-
if @integrity_version != version_tag
|
|
56
|
-
@integrity_cache = {}
|
|
57
|
-
@integrity_version = version_tag
|
|
58
|
-
end
|
|
59
|
-
return @integrity_cache[path] if @integrity_cache.key?(path)
|
|
60
|
-
|
|
61
|
-
clean = path.sub(%r{\A/}, "")
|
|
62
|
-
@integrity_cache[path] = compute_integrity(clean, version_tag)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def js_modules
|
|
67
|
-
version_tag = Assiette.version_tag
|
|
68
|
-
@modules_mutex.synchronize do
|
|
69
|
-
return @modules_cache if @modules_version == version_tag
|
|
70
|
-
|
|
71
|
-
@modules_cache = @mappings.flat_map { |prefix, root|
|
|
72
|
-
Dir[File.join(root, "**/*.{js,mjs}")].filter_map { |abs|
|
|
73
|
-
next unless File.foreach(abs).any? { |line| line.match?(/\A\s*(import|export)\s/) }
|
|
74
|
-
relative = Pathname.new(abs).relative_path_from(root).to_s
|
|
75
|
-
mod_path = "/#{"#{prefix}/" unless prefix.empty?}#{relative}".squeeze("/")
|
|
76
|
-
{path: mod_path, integrity: asset_integrity(mod_path)}
|
|
77
|
-
}
|
|
78
|
-
}.uniq { |m| m[:path] }.sort_by { |m| m[:path] }
|
|
79
|
-
|
|
80
|
-
@modules_version = version_tag
|
|
81
|
-
@modules_cache
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
25
|
private
|
|
86
26
|
|
|
87
|
-
def build_mappings(root, additional_directory_mappings)
|
|
88
|
-
mappings = [["", Pathname.new(root).expand_path]]
|
|
89
|
-
additional_directory_mappings.each do |prefix, path|
|
|
90
|
-
clean_prefix = prefix.to_s.sub(%r{\A/}, "").chomp("/")
|
|
91
|
-
mappings << [clean_prefix, Pathname.new(path).expand_path]
|
|
92
|
-
end
|
|
93
|
-
mappings
|
|
94
|
-
end
|
|
95
|
-
|
|
96
27
|
def serve(env)
|
|
97
28
|
return unless env["REQUEST_METHOD"] == "GET" || env["REQUEST_METHOD"] == "HEAD"
|
|
98
29
|
|
|
@@ -100,10 +31,10 @@ module Assiette
|
|
|
100
31
|
path_info = path_info.sub(%r{\A/}, "")
|
|
101
32
|
|
|
102
33
|
extension = File.extname(path_info)
|
|
103
|
-
content_type = CONTENT_TYPES[extension]
|
|
34
|
+
content_type = AssetHandler::CONTENT_TYPES[extension]
|
|
104
35
|
return unless content_type
|
|
105
36
|
|
|
106
|
-
file_path = resolve_file(path_info)
|
|
37
|
+
file_path = @handler.resolve_file(path_info)
|
|
107
38
|
return unless file_path
|
|
108
39
|
|
|
109
40
|
raw_bytes = File.binread(file_path)
|
|
@@ -117,7 +48,7 @@ module Assiette
|
|
|
117
48
|
query = Rack::Utils.parse_query(env["QUERY_STRING"])
|
|
118
49
|
tag = query["v"].to_s.empty? ? Assiette.version_tag : query["v"]
|
|
119
50
|
|
|
120
|
-
body = if JS_EXTENSIONS.include?(extension)
|
|
51
|
+
body = if AssetHandler::JS_EXTENSIONS.include?(extension)
|
|
121
52
|
Rewriter.rewrite_js_imports(raw_bytes, tag)
|
|
122
53
|
elsif extension == ".css"
|
|
123
54
|
Rewriter.rewrite_css_urls(raw_bytes, tag)
|
|
@@ -134,39 +65,5 @@ module Assiette
|
|
|
134
65
|
|
|
135
66
|
[200, headers, [body]]
|
|
136
67
|
end
|
|
137
|
-
|
|
138
|
-
def resolve_file(path)
|
|
139
|
-
clean = path.sub(%r{\A/}, "")
|
|
140
|
-
@mappings.each do |prefix, root|
|
|
141
|
-
if prefix.empty?
|
|
142
|
-
relative = clean
|
|
143
|
-
elsif clean.start_with?(prefix + "/")
|
|
144
|
-
relative = clean[(prefix.length + 1)..]
|
|
145
|
-
elsif clean == prefix
|
|
146
|
-
next
|
|
147
|
-
else
|
|
148
|
-
next
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
abs = root.join(relative).cleanpath
|
|
152
|
-
next unless abs.to_s.start_with?(root.to_s + "/")
|
|
153
|
-
return abs if abs.exist? && abs.file?
|
|
154
|
-
end
|
|
155
|
-
nil
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def compute_integrity(clean, version_tag)
|
|
159
|
-
file_path = resolve_file(clean)
|
|
160
|
-
return nil unless file_path
|
|
161
|
-
|
|
162
|
-
raw = File.read(file_path)
|
|
163
|
-
ext = File.extname(clean)
|
|
164
|
-
served = case ext
|
|
165
|
-
when ".js", ".mjs" then Rewriter.rewrite_js_imports(raw, version_tag)
|
|
166
|
-
when ".css" then Rewriter.rewrite_css_urls(raw, version_tag)
|
|
167
|
-
else raw
|
|
168
|
-
end
|
|
169
|
-
"sha256-#{Base64.strict_encode64(Digest::SHA256.digest(served))}"
|
|
170
|
-
end
|
|
171
68
|
end
|
|
172
69
|
end
|
data/lib/assiette/version.rb
CHANGED
data/lib/assiette.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "assiette/version"
|
|
4
|
-
require_relative "assiette/version_tag"
|
|
5
|
-
require_relative "assiette/rewriter"
|
|
6
|
-
require_relative "assiette/server"
|
|
7
|
-
require_relative "assiette/helpers"
|
|
8
|
-
require_relative "assiette/railtie" if defined?(Rails::Railtie)
|
|
9
4
|
|
|
10
5
|
module Assiette
|
|
6
|
+
autoload :Rewriter, File.expand_path("assiette/rewriter", __dir__)
|
|
7
|
+
autoload :AssetHandler, File.expand_path("assiette/asset_handler", __dir__)
|
|
8
|
+
autoload :Server, File.expand_path("assiette/server", __dir__)
|
|
9
|
+
autoload :Helpers, File.expand_path("assiette/helpers", __dir__)
|
|
10
|
+
autoload :RailsAssetUrlHelper, File.expand_path("assiette/rails_asset_url_helper", __dir__)
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
require_relative "assiette/railtie" if defined?(Rails::Railtie)
|
|
@@ -6,20 +6,28 @@
|
|
|
6
6
|
# This file runs during :load_config_initializers, which is before the
|
|
7
7
|
# middleware stack is frozen (:build_middleware_stack) in Rails 8.1+.
|
|
8
8
|
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
# Build a single handler that knows about app/assets and public/, and share
|
|
10
|
+
# it between the Rack middleware (which serves the files) and the Rails
|
|
11
|
+
# asset helpers (which generate URLs).
|
|
12
|
+
handler = Assiette::AssetHandler.new(
|
|
13
|
+
root: Rails.root.join("app/assets"),
|
|
14
|
+
additional_directory_mappings: {
|
|
15
|
+
"/" => Rails.root.join("public")
|
|
16
|
+
}
|
|
13
17
|
)
|
|
14
18
|
|
|
15
|
-
# Serve files
|
|
16
|
-
Rails.application.config.middleware.use
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
19
|
+
# Serve files through the shared handler.
|
|
20
|
+
Rails.application.config.middleware.use Assiette::Server, handler
|
|
21
|
+
|
|
22
|
+
# Make the standard Rails asset helpers (asset_path, image_tag,
|
|
23
|
+
# stylesheet_link_tag, javascript_include_tag, ...) resolve paths through
|
|
24
|
+
# Assiette and pick up its ?v= cache-busting tag. Unknown assets fall back
|
|
25
|
+
# to Rails' default behavior. Remove this line if you'd rather use only
|
|
26
|
+
# the assiette_* helpers below.
|
|
27
|
+
Rails.application.assets = handler
|
|
20
28
|
|
|
21
|
-
#
|
|
22
|
-
# assiette_modulepreload_tags
|
|
29
|
+
# Also expose assiette_asset_path, assiette_stylesheet_tag, and
|
|
30
|
+
# assiette_modulepreload_tags for templates that want them directly.
|
|
23
31
|
ActiveSupport.on_load(:action_controller_base) do
|
|
24
32
|
helper Assiette::Helpers
|
|
25
33
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: assiette
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julik Tarkhanov
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-05-
|
|
10
|
+
date: 2026-05-26 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: actionpack
|
|
@@ -34,7 +34,9 @@ files:
|
|
|
34
34
|
- LICENSE.txt
|
|
35
35
|
- Rakefile
|
|
36
36
|
- lib/assiette.rb
|
|
37
|
+
- lib/assiette/asset_handler.rb
|
|
37
38
|
- lib/assiette/helpers.rb
|
|
39
|
+
- lib/assiette/rails_asset_url_helper.rb
|
|
38
40
|
- lib/assiette/railtie.rb
|
|
39
41
|
- lib/assiette/rewriter.rb
|
|
40
42
|
- lib/assiette/server.rb
|