sprockets 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +72 -0
  3. data/README.md +665 -0
  4. data/bin/sprockets +93 -0
  5. data/lib/rake/sprocketstask.rb +153 -0
  6. data/lib/sprockets.rb +229 -0
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +202 -0
  9. data/lib/sprockets/autoload.rb +16 -0
  10. data/lib/sprockets/autoload/babel.rb +8 -0
  11. data/lib/sprockets/autoload/closure.rb +8 -0
  12. data/lib/sprockets/autoload/coffee_script.rb +8 -0
  13. data/lib/sprockets/autoload/eco.rb +8 -0
  14. data/lib/sprockets/autoload/ejs.rb +8 -0
  15. data/lib/sprockets/autoload/jsminc.rb +8 -0
  16. data/lib/sprockets/autoload/sass.rb +8 -0
  17. data/lib/sprockets/autoload/sassc.rb +8 -0
  18. data/lib/sprockets/autoload/uglifier.rb +8 -0
  19. data/lib/sprockets/autoload/yui.rb +8 -0
  20. data/lib/sprockets/autoload/zopfli.rb +7 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +147 -0
  23. data/lib/sprockets/bower.rb +61 -0
  24. data/lib/sprockets/bundle.rb +105 -0
  25. data/lib/sprockets/cache.rb +271 -0
  26. data/lib/sprockets/cache/file_store.rb +208 -0
  27. data/lib/sprockets/cache/memory_store.rb +75 -0
  28. data/lib/sprockets/cache/null_store.rb +54 -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 +304 -0
  35. data/lib/sprockets/dependencies.rb +74 -0
  36. data/lib/sprockets/digest_utils.rb +200 -0
  37. data/lib/sprockets/directive_processor.rb +414 -0
  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 +262 -0
  41. data/lib/sprockets/environment.rb +46 -0
  42. data/lib/sprockets/erb_processor.rb +37 -0
  43. data/lib/sprockets/errors.rb +12 -0
  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 +50 -0
  53. data/lib/sprockets/loader.rb +345 -0
  54. data/lib/sprockets/manifest.rb +338 -0
  55. data/lib/sprockets/manifest_utils.rb +48 -0
  56. data/lib/sprockets/mime.rb +96 -0
  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 +82 -0
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +228 -0
  64. data/lib/sprockets/processor_utils.rb +169 -0
  65. data/lib/sprockets/resolve.rb +295 -0
  66. data/lib/sprockets/sass_cache_store.rb +30 -0
  67. data/lib/sprockets/sass_compressor.rb +63 -0
  68. data/lib/sprockets/sass_functions.rb +3 -0
  69. data/lib/sprockets/sass_importer.rb +3 -0
  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 +295 -0
  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 +191 -0
  81. data/lib/sprockets/utils.rb +202 -0
  82. data/lib/sprockets/utils/gzip.rb +99 -0
  83. data/lib/sprockets/version.rb +4 -0
  84. data/lib/sprockets/yui_compressor.rb +56 -0
  85. metadata +444 -0
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+ require 'sprockets/asset'
3
+ require 'sprockets/bower'
4
+ require 'sprockets/cache'
5
+ require 'sprockets/configuration'
6
+ require 'sprockets/digest_utils'
7
+ require 'sprockets/errors'
8
+ require 'sprockets/loader'
9
+ require 'sprockets/npm'
10
+ require 'sprockets/path_dependency_utils'
11
+ require 'sprockets/path_digest_utils'
12
+ require 'sprockets/path_utils'
13
+ require 'sprockets/resolve'
14
+ require 'sprockets/server'
15
+ require 'sprockets/source_map_utils'
16
+ require 'sprockets/uri_tar'
17
+
18
+ module Sprockets
19
+
20
+ class DoubleLinkError < Sprockets::Error
21
+ def initialize(parent_filename:, logical_path:, last_filename:, filename:)
22
+ super <<~MSG
23
+ Multiple files with the same output path cannot be linked (#{logical_path.inspect})
24
+ In #{parent_filename.inspect} these files were linked:
25
+ - #{last_filename}
26
+ - #{filename}
27
+ MSG
28
+ end
29
+ end
30
+
31
+ # `Base` class for `Environment` and `CachedEnvironment`.
32
+ class Base
33
+ include PathUtils, PathDependencyUtils, PathDigestUtils, DigestUtils, SourceMapUtils
34
+ include Configuration
35
+ include Server
36
+ include Resolve, Loader
37
+ include Bower
38
+ include Npm
39
+
40
+ # Get persistent cache store
41
+ attr_reader :cache
42
+
43
+ # Set persistent cache store
44
+ #
45
+ # The cache store must implement a pair of getters and
46
+ # setters. Either `get(key)`/`set(key, value)`,
47
+ # `[key]`/`[key]=value`, `read(key)`/`write(key, value)`.
48
+ def cache=(cache)
49
+ @cache = Cache.new(cache, logger)
50
+ end
51
+
52
+ # Return an `CachedEnvironment`. Must be implemented by the subclass.
53
+ def cached
54
+ raise NotImplementedError
55
+ end
56
+ alias_method :index, :cached
57
+
58
+ # Internal: Compute digest for path.
59
+ #
60
+ # path - String filename or directory path.
61
+ #
62
+ # Returns a String digest or nil.
63
+ def file_digest(path)
64
+ if stat = self.stat(path)
65
+ # Caveat: Digests are cached by the path's current mtime. Its possible
66
+ # for a files contents to have changed and its mtime to have been
67
+ # negligently reset thus appearing as if the file hasn't changed on
68
+ # disk. Also, the mtime is only read to the nearest second. It's
69
+ # also possible the file was updated more than once in a given second.
70
+ key = UnloadedAsset.new(path, self).file_digest_key(stat.mtime.to_i)
71
+ cache.fetch(key) do
72
+ self.stat_digest(path, stat)
73
+ end
74
+ end
75
+ end
76
+
77
+ # Find asset by logical path or expanded path.
78
+ def find_asset(*args, **options)
79
+ uri, _ = resolve(*args, **options)
80
+ if uri
81
+ load(uri)
82
+ end
83
+ end
84
+
85
+ def find_all_linked_assets(*args)
86
+ return to_enum(__method__, *args) unless block_given?
87
+
88
+ parent_asset = asset = find_asset(*args)
89
+ return unless asset
90
+
91
+ yield asset
92
+ stack = asset.links.to_a
93
+ linked_paths = {}
94
+
95
+ while uri = stack.shift
96
+ yield asset = load(uri)
97
+
98
+ last_filename = linked_paths[asset.logical_path]
99
+ if last_filename && last_filename != asset.filename
100
+ raise DoubleLinkError.new(
101
+ parent_filename: parent_asset.filename,
102
+ last_filename: last_filename,
103
+ logical_path: asset.logical_path,
104
+ filename: asset.filename
105
+ )
106
+ end
107
+ linked_paths[asset.logical_path] = asset.filename
108
+ stack = asset.links.to_a + stack
109
+ end
110
+
111
+ nil
112
+ end
113
+
114
+ # Preferred `find_asset` shorthand.
115
+ #
116
+ # environment['application.js']
117
+ #
118
+ def [](*args, **options)
119
+ find_asset(*args, **options)
120
+ end
121
+
122
+ # Find asset by logical path or expanded path.
123
+ #
124
+ # If the asset is not found an error will be raised.
125
+ def find_asset!(*args)
126
+ uri, _ = resolve!(*args)
127
+ if uri
128
+ load(uri)
129
+ end
130
+ end
131
+
132
+ # Pretty inspect
133
+ def inspect
134
+ "#<#{self.class}:0x#{object_id.to_s(16)} " +
135
+ "root=#{root.to_s.inspect}, " +
136
+ "paths=#{paths.inspect}>"
137
+ end
138
+
139
+ def compress_from_root(uri)
140
+ URITar.new(uri, self).compress
141
+ end
142
+
143
+ def expand_from_root(uri)
144
+ URITar.new(uri, self).expand
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+
4
+ module Sprockets
5
+ module Bower
6
+ # Internal: All supported bower.json files.
7
+ #
8
+ # https://github.com/bower/json/blob/0.4.0/lib/json.js#L7
9
+ POSSIBLE_BOWER_JSONS = ['bower.json', 'component.json', '.bower.json']
10
+
11
+ # Internal: Override resolve_alternates to install bower.json behavior.
12
+ #
13
+ # load_path - String environment path
14
+ # logical_path - String path relative to base
15
+ #
16
+ # Returns candiate filenames.
17
+ def resolve_alternates(load_path, logical_path)
18
+ candidates, deps = super
19
+
20
+ # bower.json can only be nested one level deep
21
+ if !logical_path.index('/'.freeze)
22
+ dirname = File.join(load_path, logical_path)
23
+
24
+ if directory?(dirname)
25
+ filenames = POSSIBLE_BOWER_JSONS.map { |basename| File.join(dirname, basename) }
26
+ filename = filenames.detect { |fn| self.file?(fn) }
27
+
28
+ if filename
29
+ deps << build_file_digest_uri(filename)
30
+ read_bower_main(dirname, filename) do |path|
31
+ if file?(path)
32
+ candidates << path
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ return candidates, deps
40
+ end
41
+
42
+ # Internal: Read bower.json's main directive.
43
+ #
44
+ # dirname - String path to component directory.
45
+ # filename - String path to bower.json.
46
+ #
47
+ # Returns nothing.
48
+ def read_bower_main(dirname, filename)
49
+ bower = JSON.parse(File.read(filename), create_additions: false)
50
+
51
+ case bower['main']
52
+ when String
53
+ yield File.expand_path(bower['main'], dirname)
54
+ when Array
55
+ bower['main'].each do |name|
56
+ yield File.expand_path(name, dirname)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+ require 'sprockets/utils'
4
+ require 'sprockets/uri_utils'
5
+
6
+ module Sprockets
7
+ # Internal: Bundle processor takes a single file asset and prepends all the
8
+ # `:required` URIs to the contents.
9
+ #
10
+ # Uses pipeline metadata:
11
+ #
12
+ # :required - Ordered Set of asset URIs to prepend
13
+ # :stubbed - Set of asset URIs to substract from the required set.
14
+ #
15
+ # Also see DirectiveProcessor.
16
+ class Bundle
17
+ def self.call(input)
18
+ env = input[:environment]
19
+ type = input[:content_type]
20
+ input[:links] ||= Set.new
21
+ dependencies = Set.new(input[:metadata][:dependencies])
22
+
23
+ processed_uri, deps = env.resolve(input[:filename], accept: type, pipeline: :self)
24
+ dependencies.merge(deps)
25
+
26
+ # DirectiveProcessor (and any other transformers called here with pipeline=self)
27
+ primary_asset = env.load(processed_uri)
28
+ to_load = primary_asset.metadata.delete(:to_load) || Set.new
29
+ to_link = primary_asset.metadata.delete(:to_link) || Set.new
30
+
31
+ to_load.each do |uri|
32
+ loaded_asset = env.load(uri)
33
+ dependencies.merge(loaded_asset.metadata[:dependencies])
34
+ if to_link.include?(uri)
35
+ primary_metadata = primary_asset.metadata
36
+ input[:links] << loaded_asset.uri
37
+ primary_metadata[:links] << loaded_asset.uri
38
+ end
39
+ end
40
+
41
+ find_required = proc { |uri| env.load(uri).metadata[:required] }
42
+ required = Utils.dfs(processed_uri, &find_required)
43
+ stubbed = Utils.dfs(env.load(processed_uri).metadata[:stubbed], &find_required)
44
+ required.subtract(stubbed)
45
+ dedup(required)
46
+ assets = required.map { |uri| env.load(uri) }
47
+
48
+ (required + stubbed).each do |uri|
49
+ dependencies.merge(env.load(uri).metadata[:dependencies])
50
+ end
51
+
52
+ reducers = Hash[env.match_mime_type_keys(env.config[:bundle_reducers], type).flat_map(&:to_a)]
53
+ process_bundle_reducers(input, assets, reducers).merge(dependencies: dependencies, included: assets.map(&:uri))
54
+ end
55
+
56
+ # Internal: Removes uri from required if it's already included as an alias.
57
+ #
58
+ # required - Set of required uris
59
+ #
60
+ # Returns deduped set of uris
61
+ def self.dedup(required)
62
+ dupes = required.reduce([]) do |r, uri|
63
+ path, params = URIUtils.parse_asset_uri(uri)
64
+ if (params.delete(:index_alias))
65
+ r << URIUtils.build_asset_uri(path, params)
66
+ end
67
+ r
68
+ end
69
+ required.subtract(dupes)
70
+ end
71
+
72
+ # Internal: Run bundle reducers on set of Assets producing a reduced
73
+ # metadata Hash.
74
+ #
75
+ # filename - String bundle filename
76
+ # assets - Array of Assets
77
+ # reducers - Array of [initial, reducer_proc] pairs
78
+ #
79
+ # Returns reduced asset metadata Hash.
80
+ def self.process_bundle_reducers(input, assets, reducers)
81
+ initial = {}
82
+ reducers.each do |k, (v, _)|
83
+ if v.respond_to?(:call)
84
+ initial[k] = v.call(input)
85
+ elsif !v.nil?
86
+ initial[k] = v
87
+ end
88
+ end
89
+
90
+ assets.reduce(initial) do |h, asset|
91
+ reducers.each do |k, (_, block)|
92
+ value = k == :data ? asset.source : asset.metadata[k]
93
+ if h.key?(k)
94
+ if !value.nil?
95
+ h[k] = block.call(h[k], value)
96
+ end
97
+ else
98
+ h[k] = value
99
+ end
100
+ end
101
+ h
102
+ end
103
+ end
104
+ end
105
+ end
@@ -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 retreive 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