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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +296 -0
  3. data/LICENSE +2 -2
  4. data/README.md +235 -262
  5. data/bin/sprockets +1 -0
  6. data/lib/rake/sprocketstask.rb +5 -4
  7. data/lib/sprockets/asset.rb +143 -212
  8. data/lib/sprockets/autoload/closure.rb +7 -0
  9. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  10. data/lib/sprockets/autoload/eco.rb +7 -0
  11. data/lib/sprockets/autoload/ejs.rb +7 -0
  12. data/lib/sprockets/autoload/sass.rb +7 -0
  13. data/lib/sprockets/autoload/uglifier.rb +7 -0
  14. data/lib/sprockets/autoload/yui.rb +7 -0
  15. data/lib/sprockets/autoload.rb +11 -0
  16. data/lib/sprockets/base.rb +56 -393
  17. data/lib/sprockets/bower.rb +58 -0
  18. data/lib/sprockets/bundle.rb +69 -0
  19. data/lib/sprockets/cache/file_store.rb +168 -14
  20. data/lib/sprockets/cache/memory_store.rb +66 -0
  21. data/lib/sprockets/cache/null_store.rb +46 -0
  22. data/lib/sprockets/cache.rb +236 -0
  23. data/lib/sprockets/cached_environment.rb +69 -0
  24. data/lib/sprockets/closure_compressor.rb +35 -10
  25. data/lib/sprockets/coffee_script_processor.rb +25 -0
  26. data/lib/sprockets/coffee_script_template.rb +17 -0
  27. data/lib/sprockets/compressing.rb +44 -23
  28. data/lib/sprockets/configuration.rb +83 -0
  29. data/lib/sprockets/context.rb +86 -144
  30. data/lib/sprockets/dependencies.rb +73 -0
  31. data/lib/sprockets/deprecation.rb +90 -0
  32. data/lib/sprockets/digest_utils.rb +180 -0
  33. data/lib/sprockets/directive_processor.rb +207 -211
  34. data/lib/sprockets/eco_processor.rb +32 -0
  35. data/lib/sprockets/eco_template.rb +9 -30
  36. data/lib/sprockets/ejs_processor.rb +31 -0
  37. data/lib/sprockets/ejs_template.rb +9 -29
  38. data/lib/sprockets/encoding_utils.rb +261 -0
  39. data/lib/sprockets/engines.rb +53 -35
  40. data/lib/sprockets/environment.rb +17 -64
  41. data/lib/sprockets/erb_processor.rb +30 -0
  42. data/lib/sprockets/erb_template.rb +11 -0
  43. data/lib/sprockets/errors.rb +4 -13
  44. data/lib/sprockets/file_reader.rb +15 -0
  45. data/lib/sprockets/http_utils.rb +117 -0
  46. data/lib/sprockets/jst_processor.rb +35 -15
  47. data/lib/sprockets/legacy.rb +330 -0
  48. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  49. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  50. data/lib/sprockets/loader.rb +325 -0
  51. data/lib/sprockets/manifest.rb +202 -127
  52. data/lib/sprockets/manifest_utils.rb +45 -0
  53. data/lib/sprockets/mime.rb +112 -31
  54. data/lib/sprockets/path_dependency_utils.rb +85 -0
  55. data/lib/sprockets/path_digest_utils.rb +47 -0
  56. data/lib/sprockets/path_utils.rb +287 -0
  57. data/lib/sprockets/paths.rb +42 -19
  58. data/lib/sprockets/processing.rb +178 -126
  59. data/lib/sprockets/processor_utils.rb +180 -0
  60. data/lib/sprockets/resolve.rb +211 -0
  61. data/lib/sprockets/sass_cache_store.rb +22 -17
  62. data/lib/sprockets/sass_compressor.rb +39 -15
  63. data/lib/sprockets/sass_functions.rb +2 -70
  64. data/lib/sprockets/sass_importer.rb +2 -30
  65. data/lib/sprockets/sass_processor.rb +292 -0
  66. data/lib/sprockets/sass_template.rb +12 -59
  67. data/lib/sprockets/server.rb +129 -84
  68. data/lib/sprockets/transformers.rb +145 -0
  69. data/lib/sprockets/uglifier_compressor.rb +39 -12
  70. data/lib/sprockets/unloaded_asset.rb +137 -0
  71. data/lib/sprockets/uri_tar.rb +98 -0
  72. data/lib/sprockets/uri_utils.rb +188 -0
  73. data/lib/sprockets/utils/gzip.rb +67 -0
  74. data/lib/sprockets/utils.rb +210 -44
  75. data/lib/sprockets/version.rb +1 -1
  76. data/lib/sprockets/yui_compressor.rb +39 -11
  77. data/lib/sprockets.rb +142 -81
  78. metadata +96 -90
  79. data/lib/sprockets/asset_attributes.rb +0 -137
  80. data/lib/sprockets/bundled_asset.rb +0 -78
  81. data/lib/sprockets/caching.rb +0 -96
  82. data/lib/sprockets/charset_normalizer.rb +0 -41
  83. data/lib/sprockets/index.rb +0 -100
  84. data/lib/sprockets/processed_asset.rb +0 -152
  85. data/lib/sprockets/processor.rb +0 -32
  86. data/lib/sprockets/safety_colons.rb +0 -28
  87. data/lib/sprockets/scss_template.rb +0 -13
  88. data/lib/sprockets/static_asset.rb +0 -60
@@ -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/processor'
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 `Index` classes.
12
+ # the `Environment` and `CachedEnvironment` classes.
9
13
  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
14
+ include ProcessorUtils, URIUtils, Utils
15
+
16
+ def pipelines
17
+ config[:pipelines]
17
18
  end
18
19
 
19
- # Deprecated alias for `preprocessors`.
20
- def processors(*args)
21
- preprocessors(*args)
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
- # 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
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
- # 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)
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(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)
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 'text/css', Sprockets::CharsetNormalizer
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 'text/css', :my_processor do |context, data|
61
+ # register_postprocessor 'application/javascript', :my_processor do |context, data|
91
62
  # data.gsub(...)
92
63
  # end
93
64
  #
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)
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(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)
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(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)
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
- # 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
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 'text/css', Sprockets::CharsetNormalizer
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 'text/css', :my_processor do |context, data|
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(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)
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 'text/css', Sprockets::CharsetNormalizer
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
- 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
- }
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
- @bundle_processors[mime_type].delete(klass)
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 add_engine_to_trail(ext, klass)
197
- @trail.append_extension(ext.to_s)
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
- if klass.respond_to?(:default_mime_type) && klass.default_mime_type
200
- if format_ext = extension_for_mime_type(klass.default_mime_type)
201
- @trail.alias_extension(ext.to_s, format_ext)
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