sprockets 2.12.5 → 3.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +296 -0
- data/LICENSE +2 -2
- data/README.md +235 -262
- data/bin/sprockets +1 -0
- data/lib/rake/sprocketstask.rb +5 -4
- data/lib/sprockets/asset.rb +143 -212
- data/lib/sprockets/autoload/closure.rb +7 -0
- data/lib/sprockets/autoload/coffee_script.rb +7 -0
- data/lib/sprockets/autoload/eco.rb +7 -0
- data/lib/sprockets/autoload/ejs.rb +7 -0
- data/lib/sprockets/autoload/sass.rb +7 -0
- data/lib/sprockets/autoload/uglifier.rb +7 -0
- data/lib/sprockets/autoload/yui.rb +7 -0
- data/lib/sprockets/autoload.rb +11 -0
- data/lib/sprockets/base.rb +56 -393
- data/lib/sprockets/bower.rb +58 -0
- data/lib/sprockets/bundle.rb +69 -0
- data/lib/sprockets/cache/file_store.rb +168 -14
- data/lib/sprockets/cache/memory_store.rb +66 -0
- data/lib/sprockets/cache/null_store.rb +46 -0
- data/lib/sprockets/cache.rb +236 -0
- data/lib/sprockets/cached_environment.rb +69 -0
- data/lib/sprockets/closure_compressor.rb +35 -10
- data/lib/sprockets/coffee_script_processor.rb +25 -0
- data/lib/sprockets/coffee_script_template.rb +17 -0
- data/lib/sprockets/compressing.rb +44 -23
- data/lib/sprockets/configuration.rb +83 -0
- data/lib/sprockets/context.rb +86 -144
- data/lib/sprockets/dependencies.rb +73 -0
- data/lib/sprockets/deprecation.rb +90 -0
- data/lib/sprockets/digest_utils.rb +180 -0
- data/lib/sprockets/directive_processor.rb +207 -211
- data/lib/sprockets/eco_processor.rb +32 -0
- data/lib/sprockets/eco_template.rb +9 -30
- data/lib/sprockets/ejs_processor.rb +31 -0
- data/lib/sprockets/ejs_template.rb +9 -29
- data/lib/sprockets/encoding_utils.rb +261 -0
- data/lib/sprockets/engines.rb +53 -35
- data/lib/sprockets/environment.rb +17 -64
- data/lib/sprockets/erb_processor.rb +30 -0
- data/lib/sprockets/erb_template.rb +11 -0
- data/lib/sprockets/errors.rb +4 -13
- data/lib/sprockets/file_reader.rb +15 -0
- data/lib/sprockets/http_utils.rb +117 -0
- data/lib/sprockets/jst_processor.rb +35 -15
- data/lib/sprockets/legacy.rb +330 -0
- data/lib/sprockets/legacy_proc_processor.rb +35 -0
- data/lib/sprockets/legacy_tilt_processor.rb +29 -0
- data/lib/sprockets/loader.rb +325 -0
- data/lib/sprockets/manifest.rb +202 -127
- data/lib/sprockets/manifest_utils.rb +45 -0
- data/lib/sprockets/mime.rb +112 -31
- data/lib/sprockets/path_dependency_utils.rb +85 -0
- data/lib/sprockets/path_digest_utils.rb +47 -0
- data/lib/sprockets/path_utils.rb +287 -0
- data/lib/sprockets/paths.rb +42 -19
- data/lib/sprockets/processing.rb +178 -126
- data/lib/sprockets/processor_utils.rb +180 -0
- data/lib/sprockets/resolve.rb +211 -0
- data/lib/sprockets/sass_cache_store.rb +22 -17
- data/lib/sprockets/sass_compressor.rb +39 -15
- data/lib/sprockets/sass_functions.rb +2 -70
- data/lib/sprockets/sass_importer.rb +2 -30
- data/lib/sprockets/sass_processor.rb +292 -0
- data/lib/sprockets/sass_template.rb +12 -59
- data/lib/sprockets/server.rb +129 -84
- data/lib/sprockets/transformers.rb +145 -0
- data/lib/sprockets/uglifier_compressor.rb +39 -12
- data/lib/sprockets/unloaded_asset.rb +137 -0
- data/lib/sprockets/uri_tar.rb +98 -0
- data/lib/sprockets/uri_utils.rb +188 -0
- data/lib/sprockets/utils/gzip.rb +67 -0
- data/lib/sprockets/utils.rb +210 -44
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +39 -11
- data/lib/sprockets.rb +142 -81
- metadata +96 -90
- data/lib/sprockets/asset_attributes.rb +0 -137
- data/lib/sprockets/bundled_asset.rb +0 -78
- data/lib/sprockets/caching.rb +0 -96
- data/lib/sprockets/charset_normalizer.rb +0 -41
- data/lib/sprockets/index.rb +0 -100
- data/lib/sprockets/processed_asset.rb +0 -152
- data/lib/sprockets/processor.rb +0 -32
- data/lib/sprockets/safety_colons.rb +0 -28
- data/lib/sprockets/scss_template.rb +0 -13
- data/lib/sprockets/static_asset.rb +0 -60
data/lib/sprockets/processing.rb
CHANGED
|
@@ -1,62 +1,40 @@
|
|
|
1
1
|
require 'sprockets/engines'
|
|
2
|
+
require 'sprockets/file_reader'
|
|
3
|
+
require 'sprockets/legacy_proc_processor'
|
|
4
|
+
require 'sprockets/legacy_tilt_processor'
|
|
2
5
|
require 'sprockets/mime'
|
|
3
|
-
require 'sprockets/
|
|
6
|
+
require 'sprockets/processor_utils'
|
|
7
|
+
require 'sprockets/uri_utils'
|
|
4
8
|
require 'sprockets/utils'
|
|
5
9
|
|
|
6
10
|
module Sprockets
|
|
7
11
|
# `Processing` is an internal mixin whose public methods are exposed on
|
|
8
|
-
# the `Environment` and `
|
|
12
|
+
# the `Environment` and `CachedEnvironment` classes.
|
|
9
13
|
module Processing
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
def format_extensions
|
|
16
|
-
@trail.extensions - @engines.keys
|
|
14
|
+
include ProcessorUtils, URIUtils, Utils
|
|
15
|
+
|
|
16
|
+
def pipelines
|
|
17
|
+
config[:pipelines]
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
def register_pipeline(name, proc = nil, &block)
|
|
21
|
+
proc ||= block
|
|
22
|
+
|
|
23
|
+
self.config = hash_reassoc(config, :pipelines) do |pipelines|
|
|
24
|
+
pipelines.merge(name.to_sym => proc)
|
|
25
|
+
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
# Returns an `Array` of `Processor` classes. If a `mime_type`
|
|
25
|
-
# argument is supplied, the processors registered under that
|
|
26
|
-
# extension will be returned.
|
|
27
|
-
#
|
|
28
28
|
# Preprocessors are ran before Postprocessors and Engine
|
|
29
29
|
# processors.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# recommended to subclass `Tilt::Template`.
|
|
33
|
-
def preprocessors(mime_type = nil)
|
|
34
|
-
if mime_type
|
|
35
|
-
@preprocessors[mime_type].dup
|
|
36
|
-
else
|
|
37
|
-
deep_copy_hash(@preprocessors)
|
|
38
|
-
end
|
|
30
|
+
def preprocessors
|
|
31
|
+
config[:preprocessors]
|
|
39
32
|
end
|
|
33
|
+
alias_method :processors, :preprocessors
|
|
40
34
|
|
|
41
|
-
# Returns an `Array` of `Processor` classes. If a `mime_type`
|
|
42
|
-
# argument is supplied, the processors registered under that
|
|
43
|
-
# extension will be returned.
|
|
44
|
-
#
|
|
45
35
|
# Postprocessors are ran after Preprocessors and Engine processors.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# recommended to subclass `Tilt::Template`.
|
|
49
|
-
def postprocessors(mime_type = nil)
|
|
50
|
-
if mime_type
|
|
51
|
-
@postprocessors[mime_type].dup
|
|
52
|
-
else
|
|
53
|
-
deep_copy_hash(@postprocessors)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Deprecated alias for `register_preprocessor`.
|
|
58
|
-
def register_processor(*args, &block)
|
|
59
|
-
register_preprocessor(*args, &block)
|
|
36
|
+
def postprocessors
|
|
37
|
+
config[:postprocessors]
|
|
60
38
|
end
|
|
61
39
|
|
|
62
40
|
# Registers a new Preprocessor `klass` for `mime_type`.
|
|
@@ -69,137 +47,211 @@ module Sprockets
|
|
|
69
47
|
# data.gsub(...)
|
|
70
48
|
# end
|
|
71
49
|
#
|
|
72
|
-
def register_preprocessor(
|
|
73
|
-
|
|
74
|
-
name = klass.to_s
|
|
75
|
-
klass = Class.new(Processor) do
|
|
76
|
-
@name = name
|
|
77
|
-
@processor = block
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
@preprocessors[mime_type].push(klass)
|
|
50
|
+
def register_preprocessor(*args, &block)
|
|
51
|
+
register_config_processor(:preprocessors, *args, &block)
|
|
82
52
|
end
|
|
53
|
+
alias_method :register_processor, :register_preprocessor
|
|
83
54
|
|
|
84
55
|
# Registers a new Postprocessor `klass` for `mime_type`.
|
|
85
56
|
#
|
|
86
|
-
# register_postprocessor '
|
|
57
|
+
# register_postprocessor 'application/javascript', Sprockets::DirectiveProcessor
|
|
87
58
|
#
|
|
88
59
|
# A block can be passed for to create a shorthand processor.
|
|
89
60
|
#
|
|
90
|
-
# register_postprocessor '
|
|
61
|
+
# register_postprocessor 'application/javascript', :my_processor do |context, data|
|
|
91
62
|
# data.gsub(...)
|
|
92
63
|
# end
|
|
93
64
|
#
|
|
94
|
-
def register_postprocessor(
|
|
95
|
-
|
|
96
|
-
name = klass.to_s
|
|
97
|
-
klass = Class.new(Processor) do
|
|
98
|
-
@name = name
|
|
99
|
-
@processor = block
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
@postprocessors[mime_type].push(klass)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# Deprecated alias for `unregister_preprocessor`.
|
|
107
|
-
def unregister_processor(*args)
|
|
108
|
-
unregister_preprocessor(*args)
|
|
65
|
+
def register_postprocessor(*args, &block)
|
|
66
|
+
register_config_processor(:postprocessors, *args, &block)
|
|
109
67
|
end
|
|
110
68
|
|
|
111
69
|
# Remove Preprocessor `klass` for `mime_type`.
|
|
112
70
|
#
|
|
113
71
|
# unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor
|
|
114
72
|
#
|
|
115
|
-
def unregister_preprocessor(
|
|
116
|
-
|
|
117
|
-
klass = @preprocessors[mime_type].detect { |cls|
|
|
118
|
-
cls.respond_to?(:name) &&
|
|
119
|
-
cls.name == "Sprockets::Processor (#{klass})"
|
|
120
|
-
}
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
@preprocessors[mime_type].delete(klass)
|
|
73
|
+
def unregister_preprocessor(*args)
|
|
74
|
+
unregister_config_processor(:preprocessors, *args)
|
|
124
75
|
end
|
|
76
|
+
alias_method :unregister_processor, :unregister_preprocessor
|
|
125
77
|
|
|
126
78
|
# Remove Postprocessor `klass` for `mime_type`.
|
|
127
79
|
#
|
|
128
80
|
# unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor
|
|
129
81
|
#
|
|
130
|
-
def unregister_postprocessor(
|
|
131
|
-
|
|
132
|
-
klass = @postprocessors[mime_type].detect { |cls|
|
|
133
|
-
cls.respond_to?(:name) &&
|
|
134
|
-
cls.name == "Sprockets::Processor (#{klass})"
|
|
135
|
-
}
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
@postprocessors[mime_type].delete(klass)
|
|
82
|
+
def unregister_postprocessor(*args)
|
|
83
|
+
unregister_config_processor(:postprocessors, *args)
|
|
139
84
|
end
|
|
140
85
|
|
|
141
|
-
# Returns an `Array` of `Processor` classes. If a `mime_type`
|
|
142
|
-
# argument is supplied, the processors registered under that
|
|
143
|
-
# extension will be returned.
|
|
144
|
-
#
|
|
145
86
|
# Bundle Processors are ran on concatenated assets rather than
|
|
146
87
|
# individual files.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
# recommended to subclass `Tilt::Template`.
|
|
150
|
-
def bundle_processors(mime_type = nil)
|
|
151
|
-
if mime_type
|
|
152
|
-
@bundle_processors[mime_type].dup
|
|
153
|
-
else
|
|
154
|
-
deep_copy_hash(@bundle_processors)
|
|
155
|
-
end
|
|
88
|
+
def bundle_processors
|
|
89
|
+
config[:bundle_processors]
|
|
156
90
|
end
|
|
157
91
|
|
|
158
92
|
# Registers a new Bundle Processor `klass` for `mime_type`.
|
|
159
93
|
#
|
|
160
|
-
# register_bundle_processor '
|
|
94
|
+
# register_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
|
|
161
95
|
#
|
|
162
96
|
# A block can be passed for to create a shorthand processor.
|
|
163
97
|
#
|
|
164
|
-
# register_bundle_processor '
|
|
98
|
+
# register_bundle_processor 'application/javascript', :my_processor do |context, data|
|
|
165
99
|
# data.gsub(...)
|
|
166
100
|
# end
|
|
167
101
|
#
|
|
168
|
-
def register_bundle_processor(
|
|
169
|
-
|
|
170
|
-
name = klass.to_s
|
|
171
|
-
klass = Class.new(Processor) do
|
|
172
|
-
@name = name
|
|
173
|
-
@processor = block
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
@bundle_processors[mime_type].push(klass)
|
|
102
|
+
def register_bundle_processor(*args, &block)
|
|
103
|
+
register_config_processor(:bundle_processors, *args, &block)
|
|
178
104
|
end
|
|
179
105
|
|
|
180
106
|
# Remove Bundle Processor `klass` for `mime_type`.
|
|
181
107
|
#
|
|
182
|
-
# unregister_bundle_processor '
|
|
108
|
+
# unregister_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
|
|
109
|
+
#
|
|
110
|
+
def unregister_bundle_processor(*args)
|
|
111
|
+
unregister_config_processor(:bundle_processors, *args)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Public: Register bundle metadata reducer function.
|
|
115
|
+
#
|
|
116
|
+
# Examples
|
|
183
117
|
#
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
118
|
+
# Sprockets.register_bundle_metadata_reducer 'application/javascript', :jshint_errors, [], :+
|
|
119
|
+
#
|
|
120
|
+
# Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, 0 { |total, count|
|
|
121
|
+
# total + count
|
|
122
|
+
# }
|
|
123
|
+
#
|
|
124
|
+
# mime_type - String MIME Type. Use '*/*' applies to all types.
|
|
125
|
+
# key - Symbol metadata key
|
|
126
|
+
# initial - Initial memo to pass to the reduce funciton (default: nil)
|
|
127
|
+
# block - Proc accepting the memo accumulator and current value
|
|
128
|
+
#
|
|
129
|
+
# Returns nothing.
|
|
130
|
+
def register_bundle_metadata_reducer(mime_type, key, *args, &block)
|
|
131
|
+
case args.size
|
|
132
|
+
when 0
|
|
133
|
+
reducer = block
|
|
134
|
+
when 1
|
|
135
|
+
if block_given?
|
|
136
|
+
initial = args[0]
|
|
137
|
+
reducer = block
|
|
138
|
+
else
|
|
139
|
+
initial = nil
|
|
140
|
+
reducer = args[0].to_proc
|
|
141
|
+
end
|
|
142
|
+
when 2
|
|
143
|
+
initial = args[0]
|
|
144
|
+
reducer = args[1].to_proc
|
|
145
|
+
else
|
|
146
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0..2)"
|
|
190
147
|
end
|
|
191
148
|
|
|
192
|
-
|
|
149
|
+
self.config = hash_reassoc(config, :bundle_reducers, mime_type) do |reducers|
|
|
150
|
+
reducers.merge(key => [initial, reducer])
|
|
151
|
+
end
|
|
193
152
|
end
|
|
194
153
|
|
|
154
|
+
protected
|
|
155
|
+
def resolve_processors_cache_key_uri(uri)
|
|
156
|
+
params = parse_uri_query_params(uri[11..-1])
|
|
157
|
+
params[:engine_extnames] = params[:engines] ? params[:engines].split(',') : []
|
|
158
|
+
processors = processors_for(params[:type], params[:file_type], params[:engine_extnames], params[:pipeline])
|
|
159
|
+
processors_cache_keys(processors)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def build_processors_uri(type, file_type, engine_extnames, pipeline)
|
|
163
|
+
engines = engine_extnames.join(',') if engine_extnames.any?
|
|
164
|
+
query = encode_uri_query_params(
|
|
165
|
+
type: type,
|
|
166
|
+
file_type: file_type,
|
|
167
|
+
engines: engines,
|
|
168
|
+
pipeline: pipeline
|
|
169
|
+
)
|
|
170
|
+
"processors:#{query}"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def processors_for(type, file_type, engine_extnames, pipeline)
|
|
174
|
+
pipeline ||= :default
|
|
175
|
+
config[:pipelines][pipeline.to_sym].call(self, type, file_type, engine_extnames)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def default_processors_for(type, file_type, engine_extnames)
|
|
179
|
+
bundled_processors = config[:bundle_processors][type]
|
|
180
|
+
if bundled_processors.any?
|
|
181
|
+
bundled_processors
|
|
182
|
+
else
|
|
183
|
+
self_processors_for(type, file_type, engine_extnames)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def self_processors_for(type, file_type, engine_extnames)
|
|
188
|
+
processors = []
|
|
189
|
+
|
|
190
|
+
processors.concat config[:postprocessors][type]
|
|
191
|
+
|
|
192
|
+
if type != file_type && processor = config[:transformers][file_type][type]
|
|
193
|
+
processors << processor
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
processors.concat engine_extnames.map { |ext| engines[ext] }
|
|
197
|
+
processors.concat config[:preprocessors][file_type]
|
|
198
|
+
|
|
199
|
+
if processors.any? || mime_type_charset_detecter(type)
|
|
200
|
+
processors << FileReader
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
processors
|
|
204
|
+
end
|
|
205
|
+
|
|
195
206
|
private
|
|
196
|
-
def
|
|
197
|
-
|
|
207
|
+
def register_config_processor(type, mime_type, klass, proc = nil, &block)
|
|
208
|
+
proc ||= block
|
|
209
|
+
processor = wrap_processor(klass, proc)
|
|
210
|
+
|
|
211
|
+
self.config = hash_reassoc(config, type, mime_type) do |processors|
|
|
212
|
+
processors.unshift(processor)
|
|
213
|
+
processors
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
compute_transformers!
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def unregister_config_processor(type, mime_type, klass)
|
|
220
|
+
if klass.is_a?(String) || klass.is_a?(Symbol)
|
|
221
|
+
klass = config[type][mime_type].detect do |cls|
|
|
222
|
+
cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})"
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
self.config = hash_reassoc(config, type, mime_type) do |processors|
|
|
227
|
+
processors.delete(klass)
|
|
228
|
+
processors
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
compute_transformers!
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def deprecate_legacy_processor_interface(interface)
|
|
235
|
+
msg = "You are using a deprecated processor interface #{ interface.inspect }.\n" +
|
|
236
|
+
"Please update your processor interface:\n" +
|
|
237
|
+
"https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors\n"
|
|
238
|
+
|
|
239
|
+
Deprecation.new([caller[3]]).warn msg
|
|
240
|
+
end
|
|
198
241
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
242
|
+
def wrap_processor(klass, proc)
|
|
243
|
+
if !proc
|
|
244
|
+
if klass.respond_to?(:call)
|
|
245
|
+
klass
|
|
246
|
+
else
|
|
247
|
+
deprecate_legacy_processor_interface(klass)
|
|
248
|
+
LegacyTiltProcessor.new(klass)
|
|
202
249
|
end
|
|
250
|
+
elsif proc.respond_to?(:arity) && proc.arity == 2
|
|
251
|
+
deprecate_legacy_processor_interface(proc)
|
|
252
|
+
LegacyProcProcessor.new(klass.to_s, proc)
|
|
253
|
+
else
|
|
254
|
+
proc
|
|
203
255
|
end
|
|
204
256
|
end
|
|
205
257
|
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Sprockets
|
|
4
|
+
# Functional utilities for dealing with Processor functions.
|
|
5
|
+
#
|
|
6
|
+
# A Processor is a general function that my modify or transform an asset as
|
|
7
|
+
# part of the pipeline. CoffeeScript to JavaScript conversion, Minification
|
|
8
|
+
# or Concatenation are all implemented as seperate Processor steps.
|
|
9
|
+
#
|
|
10
|
+
# Processors maybe any object that responds to call. So procs or a class that
|
|
11
|
+
# defines a self.call method.
|
|
12
|
+
#
|
|
13
|
+
# For ergonomics, processors may return a number of shorthand values.
|
|
14
|
+
# Unfortunately, this means that processors can not compose via ordinary
|
|
15
|
+
# function composition. The composition helpers here can help.
|
|
16
|
+
module ProcessorUtils
|
|
17
|
+
extend self
|
|
18
|
+
|
|
19
|
+
# Public: Compose processors in right to left order.
|
|
20
|
+
#
|
|
21
|
+
# processors - Array of processors callables
|
|
22
|
+
#
|
|
23
|
+
# Returns a composed Proc.
|
|
24
|
+
def compose_processors(*processors)
|
|
25
|
+
context = self
|
|
26
|
+
|
|
27
|
+
if processors.length == 1
|
|
28
|
+
obj = method(:call_processor).to_proc.curry[processors.first]
|
|
29
|
+
else
|
|
30
|
+
obj = method(:call_processors).to_proc.curry[processors]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
metaclass = (class << obj; self; end)
|
|
34
|
+
metaclass.send(:define_method, :cache_key) do
|
|
35
|
+
context.processors_cache_keys(processors)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
obj
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Public: Invoke list of processors in right to left order.
|
|
42
|
+
#
|
|
43
|
+
# The right to left order processing mirrors standard function composition.
|
|
44
|
+
# Think about:
|
|
45
|
+
#
|
|
46
|
+
# bundle.call(uglify.call(coffee.call(input)))
|
|
47
|
+
#
|
|
48
|
+
# processors - Array of processor callables
|
|
49
|
+
# input - Hash of input data to pass to each processor
|
|
50
|
+
#
|
|
51
|
+
# Returns a Hash with :data and other processor metadata key/values.
|
|
52
|
+
def call_processors(processors, input)
|
|
53
|
+
data = input[:data] || ""
|
|
54
|
+
metadata = (input[:metadata] || {}).dup
|
|
55
|
+
|
|
56
|
+
processors.reverse_each do |processor|
|
|
57
|
+
result = call_processor(processor, input.merge(data: data, metadata: metadata))
|
|
58
|
+
data = result.delete(:data)
|
|
59
|
+
metadata.merge!(result)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
metadata.merge(data: data)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Public: Invoke processor.
|
|
66
|
+
#
|
|
67
|
+
# processor - Processor callables
|
|
68
|
+
# input - Hash of input data to pass to processor
|
|
69
|
+
#
|
|
70
|
+
# Returns a Hash with :data and other processor metadata key/values.
|
|
71
|
+
def call_processor(processor, input)
|
|
72
|
+
metadata = (input[:metadata] || {}).dup
|
|
73
|
+
metadata[:data] = input[:data]
|
|
74
|
+
|
|
75
|
+
case result = processor.call({data: "", metadata: {}}.merge(input))
|
|
76
|
+
when NilClass
|
|
77
|
+
metadata
|
|
78
|
+
when Hash
|
|
79
|
+
metadata.merge(result)
|
|
80
|
+
when String
|
|
81
|
+
metadata.merge(data: result)
|
|
82
|
+
else
|
|
83
|
+
raise TypeError, "invalid processor return type: #{result.class}"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Internal: Get processor defined cached key.
|
|
88
|
+
#
|
|
89
|
+
# processor - Processor function
|
|
90
|
+
#
|
|
91
|
+
# Returns JSON serializable key or nil.
|
|
92
|
+
def processor_cache_key(processor)
|
|
93
|
+
processor.cache_key if processor.respond_to?(:cache_key)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Internal: Get combined cache keys for set of processors.
|
|
97
|
+
#
|
|
98
|
+
# processors - Array of processor functions
|
|
99
|
+
#
|
|
100
|
+
# Returns Array of JSON serializable keys.
|
|
101
|
+
def processors_cache_keys(processors)
|
|
102
|
+
processors.map { |processor| processor_cache_key(processor) }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Internal: Set of all "simple" value types allowed to be returned in
|
|
106
|
+
# processor metadata.
|
|
107
|
+
VALID_METADATA_VALUE_TYPES = Set.new([
|
|
108
|
+
String,
|
|
109
|
+
Symbol,
|
|
110
|
+
TrueClass,
|
|
111
|
+
FalseClass,
|
|
112
|
+
NilClass
|
|
113
|
+
] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
|
|
114
|
+
|
|
115
|
+
# Internal: Set of all nested compound metadata types that can nest values.
|
|
116
|
+
VALID_METADATA_COMPOUND_TYPES = Set.new([
|
|
117
|
+
Array,
|
|
118
|
+
Hash,
|
|
119
|
+
Set
|
|
120
|
+
]).freeze
|
|
121
|
+
|
|
122
|
+
# Internal: Hash of all "simple" value types allowed to be returned in
|
|
123
|
+
# processor metadata.
|
|
124
|
+
VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash|
|
|
125
|
+
hash[type] = true
|
|
126
|
+
end.freeze
|
|
127
|
+
|
|
128
|
+
# Internal: Hash of all nested compound metadata types that can nest values.
|
|
129
|
+
VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash|
|
|
130
|
+
hash[type] = true
|
|
131
|
+
end.freeze
|
|
132
|
+
|
|
133
|
+
# Internal: Set of all allowed metadata types.
|
|
134
|
+
VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
|
|
135
|
+
|
|
136
|
+
# Internal: Validate returned result of calling a processor pipeline and
|
|
137
|
+
# raise a friendly user error message.
|
|
138
|
+
#
|
|
139
|
+
# result - Metadata Hash returned from call_processors
|
|
140
|
+
#
|
|
141
|
+
# Returns result or raises a TypeError.
|
|
142
|
+
def validate_processor_result!(result)
|
|
143
|
+
if !result.instance_of?(Hash)
|
|
144
|
+
raise TypeError, "processor metadata result was expected to be a Hash, but was #{result.class}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if !result[:data].instance_of?(String)
|
|
148
|
+
raise TypeError, "processor :data was expected to be a String, but as #{result[:data].class}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
result.each do |key, value|
|
|
152
|
+
if !key.instance_of?(Symbol)
|
|
153
|
+
raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if !valid_processor_metadata_value?(value)
|
|
157
|
+
raise TypeError, "processor metadata[:#{key}] returned a complex type: #{value.inspect}\n" +
|
|
158
|
+
"Only #{VALID_METADATA_TYPES.to_a.join(", ")} maybe used."
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
result
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Internal: Validate object is in validate metadata whitelist.
|
|
166
|
+
#
|
|
167
|
+
# value - Any Object
|
|
168
|
+
#
|
|
169
|
+
# Returns true if class is in whitelist otherwise false.
|
|
170
|
+
def valid_processor_metadata_value?(value)
|
|
171
|
+
if VALID_METADATA_VALUE_TYPES_HASH[value.class]
|
|
172
|
+
true
|
|
173
|
+
elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
|
|
174
|
+
value.all? { |v| valid_processor_metadata_value?(v) }
|
|
175
|
+
else
|
|
176
|
+
false
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|