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
@@ -1,62 +1,43 @@
1
- require 'sprockets/engines'
1
+ # frozen_string_literal: true
2
+ require 'sprockets/file_reader'
2
3
  require 'sprockets/mime'
3
- require 'sprockets/processor'
4
+ require 'sprockets/processor_utils'
5
+ require 'sprockets/uri_utils'
4
6
  require 'sprockets/utils'
5
7
 
6
8
  module Sprockets
7
9
  # `Processing` is an internal mixin whose public methods are exposed on
8
- # the `Environment` and `Index` classes.
10
+ # the `Environment` and `CachedEnvironment` classes.
9
11
  module Processing
10
- # Returns an `Array` of format extension `String`s.
11
- #
12
- # format_extensions
13
- # # => ['.js', '.css']
14
- #
15
- def format_extensions
16
- @trail.extensions - @engines.keys
12
+ include ProcessorUtils, URIUtils, Utils
13
+
14
+ def pipelines
15
+ config[:pipelines]
17
16
  end
18
17
 
19
- # Deprecated alias for `preprocessors`.
20
- def processors(*args)
21
- preprocessors(*args)
18
+ # Registers a pipeline that will be called by `call_processor` method.
19
+ def register_pipeline(name, proc = nil, &block)
20
+ proc ||= block
21
+
22
+ self.config = hash_reassoc(config, :pipeline_exts) do |pipeline_exts|
23
+ pipeline_exts.merge(".#{name}".freeze => name.to_sym)
24
+ end
25
+
26
+ self.config = hash_reassoc(config, :pipelines) do |pipelines|
27
+ pipelines.merge(name.to_sym => proc)
28
+ end
22
29
  end
23
30
 
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
31
  # Preprocessors are ran before Postprocessors and Engine
29
32
  # processors.
30
- #
31
- # All `Processor`s must follow the `Tilt::Template` interface. It is
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
33
+ def preprocessors
34
+ config[:preprocessors]
39
35
  end
36
+ alias_method :processors, :preprocessors
40
37
 
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
38
  # Postprocessors are ran after Preprocessors and Engine processors.
46
- #
47
- # All `Processor`s must follow the `Tilt::Template` interface. It is
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)
39
+ def postprocessors
40
+ config[:postprocessors]
60
41
  end
61
42
 
62
43
  # Registers a new Preprocessor `klass` for `mime_type`.
@@ -65,181 +46,182 @@ module Sprockets
65
46
  #
66
47
  # A block can be passed for to create a shorthand processor.
67
48
  #
68
- # register_preprocessor 'text/css', :my_processor do |context, data|
69
- # data.gsub(...)
49
+ # register_preprocessor 'text/css' do |input|
50
+ # input[:data].gsub(...)
70
51
  # end
71
52
  #
72
- def register_preprocessor(mime_type, klass, &block)
73
- if block_given?
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)
53
+ def register_preprocessor(*args, &block)
54
+ register_config_processor(:preprocessors, *args, &block)
55
+ compute_transformers!(self.config[:registered_transformers])
82
56
  end
57
+ alias_method :register_processor, :register_preprocessor
83
58
 
84
59
  # Registers a new Postprocessor `klass` for `mime_type`.
85
60
  #
86
- # register_postprocessor 'text/css', Sprockets::CharsetNormalizer
61
+ # register_postprocessor 'application/javascript', Sprockets::DirectiveProcessor
87
62
  #
88
63
  # A block can be passed for to create a shorthand processor.
89
64
  #
90
- # register_postprocessor 'text/css', :my_processor do |context, data|
91
- # data.gsub(...)
65
+ # register_postprocessor 'application/javascript' do |input|
66
+ # input[:data].gsub(...)
92
67
  # end
93
68
  #
94
- def register_postprocessor(mime_type, klass, &block)
95
- if block_given?
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)
69
+ def register_postprocessor(*args, &block)
70
+ register_config_processor(:postprocessors, *args, &block)
71
+ compute_transformers!(self.config[:registered_transformers])
109
72
  end
110
73
 
111
74
  # Remove Preprocessor `klass` for `mime_type`.
112
75
  #
113
76
  # unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor
114
77
  #
115
- def unregister_preprocessor(mime_type, klass)
116
- if klass.is_a?(String) || klass.is_a?(Symbol)
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)
78
+ def unregister_preprocessor(*args)
79
+ unregister_config_processor(:preprocessors, *args)
80
+ compute_transformers!(self.config[:registered_transformers])
124
81
  end
82
+ alias_method :unregister_processor, :unregister_preprocessor
125
83
 
126
84
  # Remove Postprocessor `klass` for `mime_type`.
127
85
  #
128
86
  # unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor
129
87
  #
130
- def unregister_postprocessor(mime_type, klass)
131
- if klass.is_a?(String) || klass.is_a?(Symbol)
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)
88
+ def unregister_postprocessor(*args)
89
+ unregister_config_processor(:postprocessors, *args)
90
+ compute_transformers!(self.config[:registered_transformers])
139
91
  end
140
92
 
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
93
  # Bundle Processors are ran on concatenated assets rather than
146
94
  # individual files.
147
- #
148
- # All `Processor`s must follow the `Tilt::Template` interface. It is
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
95
+ def bundle_processors
96
+ config[:bundle_processors]
156
97
  end
157
98
 
158
99
  # Registers a new Bundle Processor `klass` for `mime_type`.
159
100
  #
160
- # register_bundle_processor 'text/css', Sprockets::CharsetNormalizer
101
+ # register_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
161
102
  #
162
103
  # A block can be passed for to create a shorthand processor.
163
104
  #
164
- # register_bundle_processor :my_processor do |context, data|
165
- # data.gsub(...)
105
+ # register_bundle_processor 'application/javascript' do |input|
106
+ # input[:data].gsub(...)
166
107
  # end
167
108
  #
168
- def register_bundle_processor(mime_type, klass, &block)
169
- if block_given?
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)
109
+ def register_bundle_processor(*args, &block)
110
+ register_config_processor(:bundle_processors, *args, &block)
178
111
  end
179
112
 
180
113
  # Remove Bundle Processor `klass` for `mime_type`.
181
114
  #
182
- # unregister_bundle_processor 'text/css', Sprockets::CharsetNormalizer
115
+ # unregister_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
116
+ #
117
+ def unregister_bundle_processor(*args)
118
+ unregister_config_processor(:bundle_processors, *args)
119
+ end
120
+
121
+ # Public: Register bundle metadata reducer function.
122
+ #
123
+ # Examples
183
124
  #
184
- def unregister_bundle_processor(mime_type, klass)
185
- if klass.is_a?(String) || klass.is_a?(Symbol)
186
- klass = @bundle_processors[mime_type].detect { |cls|
187
- cls.respond_to?(:name) &&
188
- cls.name == "Sprockets::Processor (#{klass})"
189
- }
125
+ # Sprockets.register_bundle_metadata_reducer 'application/javascript', :jshint_errors, [], :+
126
+ #
127
+ # Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, 0 { |total, count|
128
+ # total + count
129
+ # }
130
+ #
131
+ # mime_type - String MIME Type. Use '*/*' applies to all types.
132
+ # key - Symbol metadata key
133
+ # initial - Initial memo to pass to the reduce function (default: nil)
134
+ # block - Proc accepting the memo accumulator and current value
135
+ #
136
+ # Returns nothing.
137
+ def register_bundle_metadata_reducer(mime_type, key, *args, &block)
138
+ case args.size
139
+ when 0
140
+ reducer = block
141
+ when 1
142
+ if block_given?
143
+ initial = args[0]
144
+ reducer = block
145
+ else
146
+ initial = nil
147
+ reducer = args[0].to_proc
148
+ end
149
+ when 2
150
+ initial = args[0]
151
+ reducer = args[1].to_proc
152
+ else
153
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 0..2)"
190
154
  end
191
155
 
192
- @bundle_processors[mime_type].delete(klass)
156
+ self.config = hash_reassoc(config, :bundle_reducers, mime_type) do |reducers|
157
+ reducers.merge(key => [initial, reducer])
158
+ end
193
159
  end
194
160
 
195
- # Return CSS compressor or nil if none is set
196
- def css_compressor
197
- bundle_processors('text/css').detect { |klass|
198
- klass.respond_to?(:name) &&
199
- klass.name == 'Sprockets::Processor (css_compressor)'
200
- }
201
- end
161
+ protected
162
+ def resolve_processors_cache_key_uri(uri)
163
+ params = parse_uri_query_params(uri[11..-1])
164
+ processors = processors_for(params[:type], params[:file_type], params[:pipeline])
165
+ processors_cache_keys(processors)
166
+ end
202
167
 
203
- # Assign a compressor to run on `text/css` assets.
204
- #
205
- # The compressor object must respond to `compress` or `compile`.
206
- def css_compressor=(compressor)
207
- unregister_bundle_processor 'text/css', :css_compressor
208
- return unless compressor
168
+ def build_processors_uri(type, file_type, pipeline)
169
+ query = encode_uri_query_params(
170
+ type: type,
171
+ file_type: file_type,
172
+ pipeline: pipeline
173
+ )
174
+ "processors:#{query}"
175
+ end
209
176
 
210
- register_bundle_processor 'text/css', :css_compressor do |context, data|
211
- compressor.compress(data)
177
+ def processors_for(type, file_type, pipeline)
178
+ pipeline ||= :default
179
+ if fn = config[:pipelines][pipeline.to_sym]
180
+ fn.call(self, type, file_type)
181
+ else
182
+ raise Error, "no pipeline: #{pipeline}"
183
+ end
212
184
  end
213
- end
214
185
 
215
- # Return JS compressor or nil if none is set
216
- def js_compressor
217
- bundle_processors('application/javascript').detect { |klass|
218
- klass.respond_to?(:name) &&
219
- klass.name == 'Sprockets::Processor (js_compressor)'
220
- }
221
- end
186
+ def default_processors_for(type, file_type)
187
+ bundled_processors = config[:bundle_processors][type]
188
+ if bundled_processors.any?
189
+ bundled_processors
190
+ else
191
+ self_processors_for(type, file_type)
192
+ end
193
+ end
222
194
 
223
- # Assign a compressor to run on `application/javascript` assets.
224
- #
225
- # The compressor object must respond to `compress` or `compile`.
226
- def js_compressor=(compressor)
227
- unregister_bundle_processor 'application/javascript', :js_compressor
228
- return unless compressor
195
+ def self_processors_for(type, file_type)
196
+ processors = []
229
197
 
230
- register_bundle_processor 'application/javascript', :js_compressor do |context, data|
231
- compressor.compress(data)
198
+ processors.concat config[:postprocessors][type]
199
+ if type != file_type && processor = config[:transformers][file_type][type]
200
+ processors << processor
201
+ end
202
+ processors.concat config[:preprocessors][file_type]
203
+
204
+ if processors.any? || mime_type_charset_detecter(type)
205
+ processors << FileReader
206
+ end
207
+
208
+ processors
232
209
  end
233
- end
234
210
 
235
211
  private
236
- def add_engine_to_trail(ext, klass)
237
- @trail.append_extension(ext.to_s)
212
+ def register_config_processor(type, mime_type, processor = nil, &block)
213
+ processor ||= block
214
+
215
+ self.config = hash_reassoc(config, type, mime_type) do |processors|
216
+ processors.unshift(processor)
217
+ processors
218
+ end
219
+ end
238
220
 
239
- if klass.respond_to?(:default_mime_type) && klass.default_mime_type
240
- if format_ext = extension_for_mime_type(klass.default_mime_type)
241
- @trail.alias_extension(ext.to_s, format_ext)
242
- end
221
+ def unregister_config_processor(type, mime_type, processor)
222
+ self.config = hash_reassoc(config, type, mime_type) do |processors|
223
+ processors.delete_if { |p| p == processor || p.class == processor }
224
+ processors
243
225
  end
244
226
  end
245
227
  end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+
4
+ module Sprockets
5
+ # Functional utilities for dealing with Processor functions.
6
+ #
7
+ # A Processor is a general function that may modify or transform an asset as
8
+ # part of the pipeline. CoffeeScript to JavaScript conversion, Minification
9
+ # or Concatenation are all implemented as separate Processor steps.
10
+ #
11
+ # Processors maybe any object that responds to call. So procs or a class that
12
+ # defines a self.call method.
13
+ #
14
+ # For ergonomics, processors may return a number of shorthand values.
15
+ # Unfortunately, this means that processors can not compose via ordinary
16
+ # function composition. The composition helpers here can help.
17
+ module ProcessorUtils
18
+ extend self
19
+
20
+ class CompositeProcessor < Struct.new(:processor_strategy, :param, :processors) # :nodoc:
21
+ SINGULAR = lambda { |param, input| ProcessorUtils.call_processor param, input }
22
+ PLURAL = lambda { |param, input| ProcessorUtils.call_processors param, input }
23
+
24
+ def self.create(processors)
25
+ if processors.length == 1
26
+ new SINGULAR, processors.first, processors
27
+ else
28
+ new PLURAL, processors, processors
29
+ end
30
+ end
31
+
32
+ def call(input)
33
+ processor_strategy.call param, input
34
+ end
35
+
36
+ def cache_key
37
+ ProcessorUtils.processors_cache_keys(processors)
38
+ end
39
+ end
40
+
41
+ # Public: Compose processors in right to left order.
42
+ #
43
+ # processors - Array of processors callables
44
+ #
45
+ # Returns a composed Proc.
46
+ def compose_processors(*processors)
47
+ CompositeProcessor.create processors
48
+ end
49
+
50
+ # Public: Invoke list of processors in right to left order.
51
+ #
52
+ # The right to left order processing mirrors standard function composition.
53
+ # Think about:
54
+ #
55
+ # bundle.call(uglify.call(coffee.call(input)))
56
+ #
57
+ # processors - Array of processor callables
58
+ # input - Hash of input data to pass to each processor
59
+ #
60
+ # Returns a Hash with :data and other processor metadata key/values.
61
+ def call_processors(processors, input)
62
+ data = input[:data] || ""
63
+ metadata = (input[:metadata] || {}).dup
64
+
65
+ processors.reverse_each do |processor|
66
+ result = call_processor(processor, input.merge(data: data, metadata: metadata))
67
+ data = result.delete(:data)
68
+ metadata.merge!(result)
69
+ end
70
+
71
+ metadata.merge(data: data)
72
+ end
73
+
74
+ # Public: Invoke processor.
75
+ #
76
+ # processor - Processor callables
77
+ # input - Hash of input data to pass to processor
78
+ #
79
+ # Returns a Hash with :data and other processor metadata key/values.
80
+ def call_processor(processor, input)
81
+ metadata = (input[:metadata] || {}).dup
82
+ metadata[:data] = input[:data]
83
+
84
+ case result = processor.call({data: "", metadata: {}}.merge(input))
85
+ when NilClass
86
+ metadata
87
+ when Hash
88
+ metadata.merge(result)
89
+ when String
90
+ metadata.merge(data: result)
91
+ else
92
+ raise TypeError, "invalid processor return type: #{result.class}"
93
+ end
94
+ end
95
+
96
+ # Internal: Get processor defined cached key.
97
+ #
98
+ # processor - Processor function
99
+ #
100
+ # Returns JSON serializable key or nil.
101
+ def processor_cache_key(processor)
102
+ processor.cache_key if processor.respond_to?(:cache_key)
103
+ end
104
+
105
+ # Internal: Get combined cache keys for set of processors.
106
+ #
107
+ # processors - Array of processor functions
108
+ #
109
+ # Returns Array of JSON serializable keys.
110
+ def processors_cache_keys(processors)
111
+ processors.map { |processor| processor_cache_key(processor) }
112
+ end
113
+
114
+ # Internal: Set of all "simple" value types allowed to be returned in
115
+ # processor metadata.
116
+ VALID_METADATA_VALUE_TYPES = Set.new([
117
+ String,
118
+ Symbol,
119
+ TrueClass,
120
+ FalseClass,
121
+ NilClass,
122
+ Integer
123
+ ]).freeze
124
+
125
+ # Internal: Set of all nested compound metadata types that can nest values.
126
+ VALID_METADATA_COMPOUND_TYPES = Set.new([
127
+ Array,
128
+ Hash,
129
+ Set
130
+ ]).freeze
131
+
132
+ # Internal: Hash of all "simple" value types allowed to be returned in
133
+ # processor metadata.
134
+ VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash|
135
+ hash[type] = true
136
+ end.freeze
137
+
138
+ # Internal: Hash of all nested compound metadata types that can nest values.
139
+ VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash|
140
+ hash[type] = true
141
+ end.freeze
142
+
143
+ # Internal: Set of all allowed metadata types.
144
+ VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
145
+
146
+ # Internal: Validate returned result of calling a processor pipeline and
147
+ # raise a friendly user error message.
148
+ #
149
+ # result - Metadata Hash returned from call_processors
150
+ #
151
+ # Returns result or raises a TypeError.
152
+ def validate_processor_result!(result)
153
+ if !result.instance_of?(Hash)
154
+ raise TypeError, "processor metadata result was expected to be a Hash, but was #{result.class}"
155
+ end
156
+
157
+ if !result[:data].instance_of?(String)
158
+ raise TypeError, "processor :data was expected to be a String, but as #{result[:data].class}"
159
+ end
160
+
161
+ result.each do |key, value|
162
+ if !key.instance_of?(Symbol)
163
+ raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
164
+ end
165
+ end
166
+
167
+ result
168
+ end
169
+ end
170
+ end