assiette 0.2.0 → 0.3.0
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 +116 -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 +10 -111
- data/lib/assiette/version.rb +1 -1
- data/lib/assiette.rb +2 -0
- data/lib/generators/assiette/install/templates/initializer.rb.tt +19 -11
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66f3dd34f305d6fbfa1ab42498d834bb2820d83ee2d5a1b84cec5cc54f686873
|
|
4
|
+
data.tar.gz: 4e824983daf15b8dad3eb6c4a9e9570b3fc9a2722575d21c31c8abd31e7fa70a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a123ca3f4632f04c15b4deba0e71f8bcce05123ea380a1a7c5877aab92d1994b10fb5a79168f86d795edebcdbad2a2056659c9729a42fa8608e0e5a49e10a7bf
|
|
7
|
+
data.tar.gz: 93273d9b24ee88b29d4fb7221e518a871e9931285c76c8bbc8c32af329d62a1a171e856068beb3fd0c337c8bf22bf6bc19ead2aac7ebb6a652d5c6671651d2bb
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
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
|
+
module Assiette
|
|
11
|
+
class AssetHandler
|
|
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
|
+
def initialize(root:, additional_directory_mappings: {})
|
|
24
|
+
@mappings = build_mappings(root, additional_directory_mappings)
|
|
25
|
+
@integrity_cache = {}
|
|
26
|
+
@integrity_mutex = Mutex.new
|
|
27
|
+
@modules_cache = nil
|
|
28
|
+
@modules_mutex = Mutex.new
|
|
29
|
+
@modules_version = nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resolve_file(path)
|
|
33
|
+
clean = path.sub(%r{\A/}, "")
|
|
34
|
+
@mappings.each do |prefix, root|
|
|
35
|
+
if prefix.empty?
|
|
36
|
+
relative = clean
|
|
37
|
+
elsif clean.start_with?(prefix + "/")
|
|
38
|
+
relative = clean[(prefix.length + 1)..]
|
|
39
|
+
elsif clean == prefix
|
|
40
|
+
next
|
|
41
|
+
else
|
|
42
|
+
next
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
abs = root.join(relative).cleanpath
|
|
46
|
+
next unless abs.to_s.start_with?(root.to_s + "/")
|
|
47
|
+
return abs if abs.exist? && abs.file?
|
|
48
|
+
end
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def absolute_asset_url_path(path, script_name = "")
|
|
53
|
+
clean = path.sub(%r{\A/}, "")
|
|
54
|
+
return nil unless resolve_file(clean)
|
|
55
|
+
"#{script_name}/#{clean}?v=#{Assiette.version_tag}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def asset_integrity(path)
|
|
59
|
+
version_tag = Assiette.version_tag
|
|
60
|
+
@integrity_mutex.synchronize do
|
|
61
|
+
if @integrity_version != version_tag
|
|
62
|
+
@integrity_cache = {}
|
|
63
|
+
@integrity_version = version_tag
|
|
64
|
+
end
|
|
65
|
+
return @integrity_cache[path] if @integrity_cache.key?(path)
|
|
66
|
+
|
|
67
|
+
clean = path.sub(%r{\A/}, "")
|
|
68
|
+
@integrity_cache[path] = compute_integrity(clean, version_tag)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def js_modules
|
|
73
|
+
version_tag = Assiette.version_tag
|
|
74
|
+
@modules_mutex.synchronize do
|
|
75
|
+
return @modules_cache if @modules_version == version_tag
|
|
76
|
+
|
|
77
|
+
@modules_cache = @mappings.flat_map { |prefix, root|
|
|
78
|
+
Dir[File.join(root, "**/*.{js,mjs}")].filter_map { |abs|
|
|
79
|
+
next unless File.foreach(abs).any? { |line| line.match?(/\A\s*(import|export)\s/) }
|
|
80
|
+
relative = Pathname.new(abs).relative_path_from(root).to_s
|
|
81
|
+
mod_path = "/#{"#{prefix}/" unless prefix.empty?}#{relative}".squeeze("/")
|
|
82
|
+
{path: mod_path, integrity: asset_integrity(mod_path)}
|
|
83
|
+
}
|
|
84
|
+
}.uniq { |m| m[:path] }.sort_by { |m| m[:path] }
|
|
85
|
+
|
|
86
|
+
@modules_version = version_tag
|
|
87
|
+
@modules_cache
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def build_mappings(root, additional_directory_mappings)
|
|
94
|
+
mappings = [["", Pathname.new(root).expand_path]]
|
|
95
|
+
additional_directory_mappings.each do |prefix, path|
|
|
96
|
+
clean_prefix = prefix.to_s.sub(%r{\A/}, "").chomp("/")
|
|
97
|
+
mappings << [clean_prefix, Pathname.new(path).expand_path]
|
|
98
|
+
end
|
|
99
|
+
mappings
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def compute_integrity(clean, version_tag)
|
|
103
|
+
file_path = resolve_file(clean)
|
|
104
|
+
return nil unless file_path
|
|
105
|
+
|
|
106
|
+
raw = File.read(file_path)
|
|
107
|
+
ext = File.extname(clean)
|
|
108
|
+
served = case ext
|
|
109
|
+
when ".js", ".mjs" then Rewriter.rewrite_js_imports(raw, version_tag)
|
|
110
|
+
when ".css" then Rewriter.rewrite_css_urls(raw, version_tag)
|
|
111
|
+
else raw
|
|
112
|
+
end
|
|
113
|
+
"sha256-#{Base64.strict_encode64(Digest::SHA256.digest(served))}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
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,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require "digest/sha2"
|
|
5
|
-
require "base64"
|
|
6
|
-
require "pathname"
|
|
7
|
-
require_relative "rewriter"
|
|
8
|
-
require_relative "version_tag"
|
|
3
|
+
require_relative "asset_handler"
|
|
9
4
|
|
|
10
5
|
module Assiette
|
|
11
6
|
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
7
|
CACHE_CONTROL = "public, max-age=432000, must-revalidate"
|
|
24
8
|
|
|
25
|
-
|
|
9
|
+
# Accepts either a pre-built handler or keyword args:
|
|
10
|
+
# Server.new(app, handler)
|
|
11
|
+
# Server.new(app, root: "...", additional_directory_mappings: {})
|
|
12
|
+
def initialize(app, handler = nil, root: nil, additional_directory_mappings: {})
|
|
26
13
|
@app = app
|
|
27
|
-
@
|
|
28
|
-
@integrity_cache = {}
|
|
29
|
-
@integrity_mutex = Mutex.new
|
|
30
|
-
@modules_cache = nil
|
|
31
|
-
@modules_mutex = Mutex.new
|
|
32
|
-
@modules_version = nil
|
|
14
|
+
@handler = handler || AssetHandler.new(root: root, additional_directory_mappings: additional_directory_mappings)
|
|
33
15
|
end
|
|
34
16
|
|
|
35
17
|
def call(env)
|
|
36
18
|
stack = (env["assiette.stack"] ||= [])
|
|
37
|
-
stack << {
|
|
19
|
+
stack << {handler: @handler, script_name: env["SCRIPT_NAME"].to_s}
|
|
38
20
|
|
|
39
21
|
result = serve(env)
|
|
40
22
|
return result if result
|
|
@@ -42,57 +24,8 @@ module Assiette
|
|
|
42
24
|
@app.call(env)
|
|
43
25
|
end
|
|
44
26
|
|
|
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
27
|
private
|
|
86
28
|
|
|
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
29
|
def serve(env)
|
|
97
30
|
return unless env["REQUEST_METHOD"] == "GET" || env["REQUEST_METHOD"] == "HEAD"
|
|
98
31
|
|
|
@@ -100,10 +33,10 @@ module Assiette
|
|
|
100
33
|
path_info = path_info.sub(%r{\A/}, "")
|
|
101
34
|
|
|
102
35
|
extension = File.extname(path_info)
|
|
103
|
-
content_type = CONTENT_TYPES[extension]
|
|
36
|
+
content_type = AssetHandler::CONTENT_TYPES[extension]
|
|
104
37
|
return unless content_type
|
|
105
38
|
|
|
106
|
-
file_path = resolve_file(path_info)
|
|
39
|
+
file_path = @handler.resolve_file(path_info)
|
|
107
40
|
return unless file_path
|
|
108
41
|
|
|
109
42
|
raw_bytes = File.binread(file_path)
|
|
@@ -117,7 +50,7 @@ module Assiette
|
|
|
117
50
|
query = Rack::Utils.parse_query(env["QUERY_STRING"])
|
|
118
51
|
tag = query["v"].to_s.empty? ? Assiette.version_tag : query["v"]
|
|
119
52
|
|
|
120
|
-
body = if JS_EXTENSIONS.include?(extension)
|
|
53
|
+
body = if AssetHandler::JS_EXTENSIONS.include?(extension)
|
|
121
54
|
Rewriter.rewrite_js_imports(raw_bytes, tag)
|
|
122
55
|
elsif extension == ".css"
|
|
123
56
|
Rewriter.rewrite_css_urls(raw_bytes, tag)
|
|
@@ -134,39 +67,5 @@ module Assiette
|
|
|
134
67
|
|
|
135
68
|
[200, headers, [body]]
|
|
136
69
|
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
70
|
end
|
|
172
71
|
end
|
data/lib/assiette/version.rb
CHANGED
data/lib/assiette.rb
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
require_relative "assiette/version"
|
|
4
4
|
require_relative "assiette/version_tag"
|
|
5
5
|
require_relative "assiette/rewriter"
|
|
6
|
+
require_relative "assiette/asset_handler"
|
|
6
7
|
require_relative "assiette/server"
|
|
7
8
|
require_relative "assiette/helpers"
|
|
9
|
+
require_relative "assiette/rails_asset_url_helper"
|
|
8
10
|
require_relative "assiette/railtie" if defined?(Rails::Railtie)
|
|
9
11
|
|
|
10
12
|
module Assiette
|
|
@@ -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,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: assiette
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julik Tarkhanov
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-25 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: actionpack
|
|
@@ -34,7 +35,9 @@ files:
|
|
|
34
35
|
- LICENSE.txt
|
|
35
36
|
- Rakefile
|
|
36
37
|
- lib/assiette.rb
|
|
38
|
+
- lib/assiette/asset_handler.rb
|
|
37
39
|
- lib/assiette/helpers.rb
|
|
40
|
+
- lib/assiette/rails_asset_url_helper.rb
|
|
38
41
|
- lib/assiette/railtie.rb
|
|
39
42
|
- lib/assiette/rewriter.rb
|
|
40
43
|
- lib/assiette/server.rb
|
|
@@ -50,6 +53,7 @@ metadata:
|
|
|
50
53
|
homepage_uri: https://github.com/julik/assiette
|
|
51
54
|
source_code_uri: https://github.com/julik/assiette
|
|
52
55
|
changelog_uri: https://github.com/julik/assiette/blob/main/CHANGELOG.md
|
|
56
|
+
post_install_message:
|
|
53
57
|
rdoc_options: []
|
|
54
58
|
require_paths:
|
|
55
59
|
- lib
|
|
@@ -64,7 +68,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
64
68
|
- !ruby/object:Gem::Version
|
|
65
69
|
version: '0'
|
|
66
70
|
requirements: []
|
|
67
|
-
rubygems_version: 3.
|
|
71
|
+
rubygems_version: 3.4.10
|
|
72
|
+
signing_key:
|
|
68
73
|
specification_version: 4
|
|
69
74
|
summary: Zero-build asset serving for Rails engines
|
|
70
75
|
test_files: []
|