sprockets 2.6.0 → 4.2.2

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.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +118 -0
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +541 -289
  5. data/bin/sprockets +20 -7
  6. data/lib/rake/sprocketstask.rb +34 -17
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +158 -210
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +8 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +8 -0
  12. data/lib/sprockets/autoload/eco.rb +8 -0
  13. data/lib/sprockets/autoload/ejs.rb +8 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +8 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +8 -0
  18. data/lib/sprockets/autoload/yui.rb +8 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +16 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +89 -378
  23. data/lib/sprockets/bower.rb +61 -0
  24. data/lib/sprockets/bundle.rb +105 -0
  25. data/lib/sprockets/cache/file_store.rb +190 -14
  26. data/lib/sprockets/cache/memory_store.rb +84 -0
  27. data/lib/sprockets/cache/null_store.rb +54 -0
  28. data/lib/sprockets/cache.rb +271 -0
  29. data/lib/sprockets/cached_environment.rb +64 -0
  30. data/lib/sprockets/closure_compressor.rb +48 -0
  31. data/lib/sprockets/coffee_script_processor.rb +39 -0
  32. data/lib/sprockets/compressing.rb +134 -0
  33. data/lib/sprockets/configuration.rb +79 -0
  34. data/lib/sprockets/context.rb +166 -150
  35. data/lib/sprockets/dependencies.rb +74 -0
  36. data/lib/sprockets/digest_utils.rb +197 -0
  37. data/lib/sprockets/directive_processor.rb +241 -215
  38. data/lib/sprockets/eco_processor.rb +33 -0
  39. data/lib/sprockets/ejs_processor.rb +32 -0
  40. data/lib/sprockets/encoding_utils.rb +261 -0
  41. data/lib/sprockets/environment.rb +23 -64
  42. data/lib/sprockets/erb_processor.rb +43 -0
  43. data/lib/sprockets/errors.rb +5 -13
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +16 -0
  50. data/lib/sprockets/http_utils.rb +135 -0
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +36 -19
  53. data/lib/sprockets/loader.rb +347 -0
  54. data/lib/sprockets/manifest.rb +228 -112
  55. data/lib/sprockets/manifest_utils.rb +48 -0
  56. data/lib/sprockets/mime.rb +78 -31
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +77 -0
  59. data/lib/sprockets/path_digest_utils.rb +48 -0
  60. data/lib/sprockets/path_utils.rb +367 -0
  61. data/lib/sprockets/paths.rb +43 -19
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +146 -164
  64. data/lib/sprockets/processor_utils.rb +170 -0
  65. data/lib/sprockets/resolve.rb +295 -0
  66. data/lib/sprockets/sass_cache_store.rb +20 -15
  67. data/lib/sprockets/sass_compressor.rb +55 -10
  68. data/lib/sprockets/sass_functions.rb +3 -70
  69. data/lib/sprockets/sass_importer.rb +3 -29
  70. data/lib/sprockets/sass_processor.rb +313 -0
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +159 -91
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +173 -0
  77. data/lib/sprockets/uglifier_compressor.rb +66 -0
  78. data/lib/sprockets/unloaded_asset.rb +139 -0
  79. data/lib/sprockets/uri_tar.rb +99 -0
  80. data/lib/sprockets/uri_utils.rb +194 -0
  81. data/lib/sprockets/utils/gzip.rb +99 -0
  82. data/lib/sprockets/utils.rb +193 -52
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +56 -0
  85. data/lib/sprockets.rb +217 -75
  86. metadata +272 -117
  87. data/lib/sprockets/asset_attributes.rb +0 -131
  88. data/lib/sprockets/bundled_asset.rb +0 -80
  89. data/lib/sprockets/caching.rb +0 -96
  90. data/lib/sprockets/charset_normalizer.rb +0 -41
  91. data/lib/sprockets/eco_template.rb +0 -38
  92. data/lib/sprockets/ejs_template.rb +0 -37
  93. data/lib/sprockets/engines.rb +0 -74
  94. data/lib/sprockets/index.rb +0 -99
  95. data/lib/sprockets/processed_asset.rb +0 -152
  96. data/lib/sprockets/processor.rb +0 -32
  97. data/lib/sprockets/safety_colons.rb +0 -28
  98. data/lib/sprockets/sass_template.rb +0 -60
  99. data/lib/sprockets/scss_template.rb +0 -13
  100. data/lib/sprockets/static_asset.rb +0 -58
@@ -0,0 +1,271 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'sprockets/digest_utils'
4
+
5
+ module Sprockets
6
+ # Public: Wrapper interface to backend cache stores. Ensures a consistent API
7
+ # even when the backend uses get/set or read/write.
8
+ #
9
+ # Public cache interface
10
+ #
11
+ # Always assign the backend store instance to Environment#cache=.
12
+ #
13
+ # environment.cache = Sprockets::Cache::MemoryStore.new(1000)
14
+ #
15
+ # Environment#cache will always return a wrapped Cache interface. See the
16
+ # methods marked public on this class.
17
+ #
18
+ #
19
+ # Backend cache interface
20
+ #
21
+ # The Backend cache store must implement two methods.
22
+ #
23
+ # get(key)
24
+ #
25
+ # key - An opaque String with a length less than 250 characters.
26
+ #
27
+ # Returns an JSON serializable object.
28
+ #
29
+ # set(key, value)
30
+ #
31
+ # Will only be called once per key. Setting a key "foo" with value "bar",
32
+ # then later key "foo" with value "baz" is an undefined behavior.
33
+ #
34
+ # key - An opaque String with a length less than 250 characters.
35
+ # value - A JSON serializable object.
36
+ #
37
+ # Returns argument value.
38
+ #
39
+ # clear(options)
40
+ #
41
+ # Clear the entire cache. Be careful with this method since it could
42
+ # affect other processes if shared cache is being used.
43
+ #
44
+ # The options hash is passed to the underlying cache implementation.
45
+ class Cache
46
+ # Builtin cache stores.
47
+ autoload :FileStore, 'sprockets/cache/file_store'
48
+ autoload :MemoryStore, 'sprockets/cache/memory_store'
49
+ autoload :NullStore, 'sprockets/cache/null_store'
50
+
51
+ # Internal: Cache key version for this class. Rarely should have to change
52
+ # unless the cache format radically changes. Will be bump on major version
53
+ # releases though.
54
+ VERSION = '4.0.0'
55
+
56
+ def self.default_logger
57
+ logger = Logger.new($stderr)
58
+ logger.level = Logger::FATAL
59
+ logger
60
+ end
61
+
62
+ # Internal: Wrap a backend cache store.
63
+ #
64
+ # Always assign a backend cache store instance to Environment#cache= and
65
+ # use Environment#cache to retrieve a wrapped interface.
66
+ #
67
+ # cache - A compatible backend cache store instance.
68
+ def initialize(cache = nil, logger = self.class.default_logger)
69
+ @cache_wrapper = get_cache_wrapper(cache)
70
+ @fetch_cache = Cache::MemoryStore.new(1024)
71
+ @logger = logger
72
+ end
73
+
74
+ # Public: Prefer API to retrieve and set values in the cache store.
75
+ #
76
+ # key - JSON serializable key
77
+ # block -
78
+ # Must return a consistent JSON serializable object for the given key.
79
+ #
80
+ # Examples
81
+ #
82
+ # cache.fetch("foo") { "bar" }
83
+ #
84
+ # Returns a JSON serializable object.
85
+ def fetch(key)
86
+ start = Time.now.to_f
87
+ expanded_key = expand_key(key)
88
+ value = @fetch_cache.get(expanded_key)
89
+ if value.nil?
90
+ value = @cache_wrapper.get(expanded_key)
91
+ if value.nil?
92
+ value = yield
93
+ @cache_wrapper.set(expanded_key, value)
94
+ @logger.debug do
95
+ ms = "(#{((Time.now.to_f - start) * 1000).to_i}ms)"
96
+ "Sprockets Cache miss #{peek_key(key)} #{ms}"
97
+ end
98
+ end
99
+ @fetch_cache.set(expanded_key, value)
100
+ end
101
+ value
102
+ end
103
+
104
+ # Public: Low level API to retrieve item directly from the backend cache
105
+ # store.
106
+ #
107
+ # This API may be used publicly, but may have undefined behavior
108
+ # depending on the backend store being used. Prefer the
109
+ # Cache#fetch API over using this.
110
+ #
111
+ # key - JSON serializable key
112
+ # local - Check local cache first (default: false)
113
+ #
114
+ # Returns a JSON serializable object or nil if there was a cache miss.
115
+ def get(key, local = false)
116
+ expanded_key = expand_key(key)
117
+
118
+ if local && value = @fetch_cache.get(expanded_key)
119
+ return value
120
+ end
121
+
122
+ value = @cache_wrapper.get(expanded_key)
123
+ @fetch_cache.set(expanded_key, value) if local
124
+
125
+ value
126
+ end
127
+
128
+ # Public: Low level API to set item directly to the backend cache store.
129
+ #
130
+ # This API may be used publicly, but may have undefined behavior
131
+ # depending on the backend store being used. Prefer the
132
+ # Cache#fetch API over using this.
133
+ #
134
+ # key - JSON serializable key
135
+ # value - A consistent JSON serializable object for the given key. Setting
136
+ # a different value for the given key has undefined behavior.
137
+ # local - Set on local cache (default: false)
138
+ #
139
+ # Returns the value argument.
140
+ def set(key, value, local = false)
141
+ expanded_key = expand_key(key)
142
+ @fetch_cache.set(expanded_key, value) if local
143
+ @cache_wrapper.set(expanded_key, value)
144
+ end
145
+
146
+ # Public: Pretty inspect
147
+ #
148
+ # Returns String.
149
+ def inspect
150
+ "#<#{self.class} local=#{@fetch_cache.inspect} store=#{@cache_wrapper.cache.inspect}>"
151
+ end
152
+
153
+ # Public: Clear cache
154
+ #
155
+ # Returns truthy on success, potentially raises exception on failure
156
+ def clear(options=nil)
157
+ @cache_wrapper.clear
158
+ @fetch_cache.clear
159
+ end
160
+
161
+ private
162
+ # Internal: Expand object cache key into a short String key.
163
+ #
164
+ # The String should be under 250 characters so its compatible with
165
+ # Memcache.
166
+ #
167
+ # key - JSON serializable key
168
+ #
169
+ # Returns a String with a length less than 250 characters.
170
+ def expand_key(key)
171
+ digest_key = DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key))
172
+ namespace = digest_key[0, 2]
173
+ "sprockets/v#{VERSION}/#{namespace}/#{digest_key}"
174
+ end
175
+
176
+ PEEK_SIZE = 100
177
+
178
+ # Internal: Show first 100 characters of cache key for logging purposes.
179
+ #
180
+ # Returns a String with a length less than 100 characters.
181
+ def peek_key(key)
182
+ case key
183
+ when Integer
184
+ key.to_s
185
+ when String
186
+ key[0, PEEK_SIZE].inspect
187
+ when Array
188
+ str = []
189
+ key.each { |k| str << peek_key(k) }
190
+ str.join(':')[0, PEEK_SIZE]
191
+ else
192
+ peek_key(DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key)))
193
+ end
194
+ end
195
+
196
+ def get_cache_wrapper(cache)
197
+ if cache.is_a?(Cache)
198
+ cache
199
+
200
+ # `Cache#get(key)` for Memcache
201
+ elsif cache.respond_to?(:get)
202
+ GetWrapper.new(cache)
203
+
204
+ # `Cache#[key]` so `Hash` can be used
205
+ elsif cache.respond_to?(:[])
206
+ HashWrapper.new(cache)
207
+
208
+ # `Cache#read(key)` for `ActiveSupport::Cache` support
209
+ elsif cache.respond_to?(:read)
210
+ ReadWriteWrapper.new(cache)
211
+
212
+ else
213
+ cache = Sprockets::Cache::NullStore.new
214
+ GetWrapper.new(cache)
215
+ end
216
+ end
217
+
218
+ class Wrapper < Struct.new(:cache)
219
+ end
220
+
221
+ class GetWrapper < Wrapper
222
+ def get(key)
223
+ cache.get(key)
224
+ end
225
+
226
+ def set(key, value)
227
+ cache.set(key, value)
228
+ end
229
+
230
+ def clear(options=nil)
231
+ # dalli has a #flush method so try it
232
+ if cache.respond_to?(:flush)
233
+ cache.flush(options)
234
+ else
235
+ cache.clear(options)
236
+ end
237
+ true
238
+ end
239
+ end
240
+
241
+ class HashWrapper < Wrapper
242
+ def get(key)
243
+ cache[key]
244
+ end
245
+
246
+ def set(key, value)
247
+ cache[key] = value
248
+ end
249
+
250
+ def clear(options=nil)
251
+ cache.clear
252
+ true
253
+ end
254
+ end
255
+
256
+ class ReadWriteWrapper < Wrapper
257
+ def get(key)
258
+ cache.read(key)
259
+ end
260
+
261
+ def set(key, value)
262
+ cache.write(key, value)
263
+ end
264
+
265
+ def clear(options=nil)
266
+ cache.clear(options)
267
+ true
268
+ end
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/base'
3
+
4
+ module Sprockets
5
+ # `CachedEnvironment` is a special cached version of `Environment`.
6
+ #
7
+ # The exception is that all of its file system methods are cached
8
+ # for the instances lifetime. This makes `CachedEnvironment` much faster. This
9
+ # behavior is ideal in production environments where the file system
10
+ # is immutable.
11
+ #
12
+ # `CachedEnvironment` should not be initialized directly. Instead use
13
+ # `Environment#cached`.
14
+ class CachedEnvironment < Base
15
+ def initialize(environment)
16
+ initialize_configuration(environment)
17
+
18
+ @cache = environment.cache
19
+ @stats = Concurrent::Map.new
20
+ @entries = Concurrent::Map.new
21
+ @uris = Concurrent::Map.new
22
+ @processor_cache_keys = Concurrent::Map.new
23
+ @resolved_dependencies = Concurrent::Map.new
24
+ end
25
+
26
+ # No-op return self as cached environment.
27
+ def cached
28
+ self
29
+ end
30
+ alias_method :index, :cached
31
+
32
+ # Internal: Cache Environment#entries
33
+ def entries(path)
34
+ @entries.fetch_or_store(path) { super(path) }
35
+ end
36
+
37
+ # Internal: Cache Environment#stat
38
+ def stat(path)
39
+ @stats.fetch_or_store(path) { super(path) }
40
+ end
41
+
42
+ # Internal: Cache Environment#load
43
+ def load(uri)
44
+ @uris.fetch_or_store(uri) { super(uri) }
45
+ end
46
+
47
+ # Internal: Cache Environment#processor_cache_key
48
+ def processor_cache_key(str)
49
+ @processor_cache_keys.fetch_or_store(str) { super(str) }
50
+ end
51
+
52
+ # Internal: Cache Environment#resolve_dependency
53
+ def resolve_dependency(str)
54
+ @resolved_dependencies.fetch_or_store(str) { super(str) }
55
+ end
56
+
57
+ private
58
+ # Cache is immutable, any methods that try to change the runtime config
59
+ # should bomb.
60
+ def config=(config)
61
+ raise RuntimeError, "can't modify immutable cached environment"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/autoload'
3
+ require 'sprockets/digest_utils'
4
+
5
+ module Sprockets
6
+ # Public: Closure Compiler minifier.
7
+ #
8
+ # To accept the default options
9
+ #
10
+ # environment.register_bundle_processor 'application/javascript',
11
+ # Sprockets::ClosureCompressor
12
+ #
13
+ # Or to pass options to the Closure::Compiler class.
14
+ #
15
+ # environment.register_bundle_processor 'application/javascript',
16
+ # Sprockets::ClosureCompressor.new({ ... })
17
+ #
18
+ class ClosureCompressor
19
+ VERSION = '1'
20
+
21
+ # Public: Return singleton instance with default options.
22
+ #
23
+ # Returns ClosureCompressor object.
24
+ def self.instance
25
+ @instance ||= new
26
+ end
27
+
28
+ def self.call(input)
29
+ instance.call(input)
30
+ end
31
+
32
+ def self.cache_key
33
+ instance.cache_key
34
+ end
35
+
36
+ attr_reader :cache_key
37
+
38
+ def initialize(options = {})
39
+ @options = options
40
+ @cache_key = "#{self.class.name}:#{Autoload::Closure::VERSION}:#{Autoload::Closure::COMPILER_VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
41
+ end
42
+
43
+ def call(input)
44
+ @compiler ||= Autoload::Closure::Compiler.new(@options)
45
+ @compiler.compile(input[:data])
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/autoload'
3
+ require 'sprockets/source_map_utils'
4
+
5
+ module Sprockets
6
+ # Processor engine class for the CoffeeScript compiler.
7
+ # Depends on the `coffee-script` and `coffee-script-source` gems.
8
+ #
9
+ # For more information see:
10
+ #
11
+ # https://github.com/rails/ruby-coffee-script
12
+ #
13
+ module CoffeeScriptProcessor
14
+ VERSION = '2'
15
+
16
+ def self.cache_key
17
+ @cache_key ||= "#{name}:#{Autoload::CoffeeScript::Source.version}:#{VERSION}".freeze
18
+ end
19
+
20
+ def self.call(input)
21
+ data = input[:data]
22
+
23
+ js, map = input[:cache].fetch([self.cache_key, data, input[:filename]]) do
24
+ result = Autoload::CoffeeScript.compile(
25
+ data,
26
+ sourceMap: "v3",
27
+ sourceFiles: [File.basename(input[:filename])],
28
+ generatedFile: input[:filename]
29
+ )
30
+ [result['js'], JSON.parse(result['v3SourceMap'])]
31
+ end
32
+
33
+ map = SourceMapUtils.format_source_map(map, input)
34
+ map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
35
+
36
+ { data: js, map: map }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/utils'
3
+
4
+ module Sprockets
5
+ # `Compressing` is an internal mixin whose public methods are exposed on
6
+ # the `Environment` and `CachedEnvironment` classes.
7
+ module Compressing
8
+ include Utils
9
+
10
+ def compressors
11
+ config[:compressors]
12
+ end
13
+
14
+ # Public: Register a new compressor `klass` at `sym` for `mime_type`.
15
+ #
16
+ # Registering a processor allows it to be looked up by `sym` later when
17
+ # assigning a JavaScript or CSS compressor.
18
+ #
19
+ # Compressors only operate on JavaScript and CSS. If you want to compress a
20
+ # different type of asset, use a processor instead.
21
+ #
22
+ # Examples
23
+ #
24
+ # register_compressor 'text/css', :my_sass, MySassCompressor
25
+ # css_compressor = :my_sass
26
+ #
27
+ # mime_type - String MIME Type (one of: 'test/css' or 'application/javascript').
28
+ # sym - Symbol registration address.
29
+ # klass - The compressor class.
30
+ #
31
+ # Returns nothing.
32
+ def register_compressor(mime_type, sym, klass)
33
+ self.config = hash_reassoc(config, :compressors, mime_type) do |compressors|
34
+ compressors[sym] = klass
35
+ compressors
36
+ end
37
+ end
38
+
39
+ # Return CSS compressor or nil if none is set
40
+ def css_compressor
41
+ if defined? @css_compressor
42
+ @css_compressor
43
+ end
44
+ end
45
+
46
+ # Assign a compressor to run on `text/css` assets.
47
+ #
48
+ # The compressor object must respond to `compress`.
49
+ def css_compressor=(compressor)
50
+ unregister_bundle_processor 'text/css', @css_compressor if defined? @css_compressor
51
+ @css_compressor = nil
52
+ return unless compressor
53
+
54
+ if compressor.is_a?(Symbol)
55
+ @css_compressor = klass = config[:compressors]['text/css'][compressor] || raise(Error, "unknown compressor: #{compressor}")
56
+ elsif compressor.respond_to?(:compress)
57
+ klass = proc { |input| compressor.compress(input[:data]) }
58
+ @css_compressor = :css_compressor
59
+ else
60
+ @css_compressor = klass = compressor
61
+ end
62
+
63
+ register_bundle_processor 'text/css', klass
64
+ end
65
+
66
+ # Return JS compressor or nil if none is set
67
+ def js_compressor
68
+ if defined? @js_compressor
69
+ @js_compressor
70
+ end
71
+ end
72
+
73
+ # Assign a compressor to run on `application/javascript` assets.
74
+ #
75
+ # The compressor object must respond to `compress`.
76
+ def js_compressor=(compressor)
77
+ unregister_bundle_processor 'application/javascript', @js_compressor if defined? @js_compressor
78
+ @js_compressor = nil
79
+ return unless compressor
80
+
81
+ if compressor.is_a?(Symbol)
82
+ @js_compressor = klass = config[:compressors]['application/javascript'][compressor] || raise(Error, "unknown compressor: #{compressor}")
83
+ elsif compressor.respond_to?(:compress)
84
+ klass = proc { |input| compressor.compress(input[:data]) }
85
+ @js_compressor = :js_compressor
86
+ else
87
+ @js_compressor = klass = compressor
88
+ end
89
+
90
+ register_bundle_processor 'application/javascript', klass
91
+ end
92
+
93
+ # Public: Checks if Gzip is enabled.
94
+ def gzip?
95
+ config[:gzip_enabled]
96
+ end
97
+
98
+ # Public: Checks if Gzip is disabled.
99
+ def skip_gzip?
100
+ !gzip?
101
+ end
102
+
103
+ # Public: Enable or disable the creation of Gzip files.
104
+ #
105
+ # To disable gzip generation set to a falsey value:
106
+ #
107
+ # environment.gzip = false
108
+ #
109
+ # To enable set to a truthy value. By default zlib wil
110
+ # be used to gzip assets. If you have the Zopfli gem
111
+ # installed you can specify the zopfli algorithm to be used
112
+ # instead:
113
+ #
114
+ # environment.gzip = :zopfli
115
+ #
116
+ def gzip=(gzip)
117
+ self.config = config.merge(gzip_enabled: gzip).freeze
118
+
119
+ case gzip
120
+ when false, nil
121
+ self.unregister_exporter Exporters::ZlibExporter
122
+ self.unregister_exporter Exporters::ZopfliExporter
123
+ when :zopfli
124
+ self.unregister_exporter Exporters::ZlibExporter
125
+ self.register_exporter '*/*', Exporters::ZopfliExporter
126
+ else
127
+ self.unregister_exporter Exporters::ZopfliExporter
128
+ self.register_exporter '*/*', Exporters::ZlibExporter
129
+ end
130
+
131
+ gzip
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/compressing'
3
+ require 'sprockets/dependencies'
4
+ require 'sprockets/mime'
5
+ require 'sprockets/paths'
6
+ require 'sprockets/processing'
7
+ require 'sprockets/exporting'
8
+ require 'sprockets/transformers'
9
+ require 'sprockets/utils'
10
+
11
+ module Sprockets
12
+ module Configuration
13
+ include Paths, Mime, Transformers, Processing, Exporting, Compressing, Dependencies, Utils
14
+
15
+ def initialize_configuration(parent)
16
+ @config = parent.config
17
+ @logger = parent.logger
18
+ @context_class = Class.new(parent.context_class)
19
+ end
20
+
21
+ attr_reader :config
22
+
23
+ def config=(config)
24
+ raise TypeError, "can't assign mutable config" unless config.frozen?
25
+ @config = config
26
+ end
27
+
28
+ # Get and set `Logger` instance.
29
+ attr_accessor :logger
30
+
31
+ # The `Environment#version` is a custom value used for manually
32
+ # expiring all asset caches.
33
+ #
34
+ # Sprockets is able to track most file and directory changes and
35
+ # will take care of expiring the cache for you. However, its
36
+ # impossible to know when any custom helpers change that you mix
37
+ # into the `Context`.
38
+ #
39
+ # It would be wise to increment this value anytime you make a
40
+ # configuration change to the `Environment` object.
41
+ def version
42
+ config[:version]
43
+ end
44
+
45
+ # Assign an environment version.
46
+ #
47
+ # environment.version = '2.0'
48
+ #
49
+ def version=(version)
50
+ self.config = hash_reassoc(config, :version) { version.dup }
51
+ end
52
+
53
+ # Public: Returns a `Digest` implementation class.
54
+ #
55
+ # Defaults to `Digest::SHA256`.
56
+ def digest_class
57
+ config[:digest_class]
58
+ end
59
+
60
+ # Deprecated: Assign a `Digest` implementation class. This maybe any Ruby
61
+ # `Digest::` implementation such as `Digest::SHA256` or
62
+ # `Digest::SHA512`.
63
+ #
64
+ # environment.digest_class = Digest::SHA512
65
+ #
66
+ def digest_class=(klass)
67
+ self.config = config.merge(digest_class: klass).freeze
68
+ end
69
+
70
+ # This class maybe mutated and mixed in with custom helpers.
71
+ #
72
+ # environment.context_class.instance_eval do
73
+ # include MyHelpers
74
+ # def asset_url; end
75
+ # end
76
+ #
77
+ attr_reader :context_class
78
+ end
79
+ end