sprockets 2.12.5 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,117 @@
1
+ module Sprockets
2
+ # Internal: HTTP URI utilities. Many adapted from Rack::Utils. Mixed into
3
+ # Environment.
4
+ module HTTPUtils
5
+ extend self
6
+
7
+ # Public: Test mime type against mime range.
8
+ #
9
+ # match_mime_type?('text/html', 'text/*') => true
10
+ # match_mime_type?('text/plain', '*') => true
11
+ # match_mime_type?('text/html', 'application/json') => false
12
+ #
13
+ # Returns true if the given value is a mime match for the given mime match
14
+ # specification, false otherwise.
15
+ def match_mime_type?(value, matcher)
16
+ v1, v2 = value.split('/', 2)
17
+ m1, m2 = matcher.split('/', 2)
18
+ (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2)
19
+ end
20
+
21
+ # Public: Return values from Hash where the key matches the mime type.
22
+ #
23
+ # hash - Hash of String matcher keys to Object values
24
+ # mime_type - String mime type
25
+ #
26
+ # Returns Array of Object values.
27
+ def match_mime_type_keys(hash, mime_type)
28
+ type, subtype = mime_type.split('/', 2)
29
+ [
30
+ hash["*"],
31
+ hash["*/*"],
32
+ hash["#{type}/*"],
33
+ hash["#{type}/#{subtype}"]
34
+ ].compact
35
+ end
36
+
37
+ # Internal: Parse Accept header quality values.
38
+ #
39
+ # Adapted from Rack::Utils#q_values.
40
+ #
41
+ # Returns an Array of [String, Float].
42
+ def parse_q_values(values)
43
+ values.to_s.split(/\s*,\s*/).map do |part|
44
+ value, parameters = part.split(/\s*;\s*/, 2)
45
+ quality = 1.0
46
+ if md = /\Aq=([\d.]+)/.match(parameters)
47
+ quality = md[1].to_f
48
+ end
49
+ [value, quality]
50
+ end
51
+ end
52
+
53
+ # Internal: Find all qvalue matches from an Array of available options.
54
+ #
55
+ # Adapted from Rack::Utils#q_values.
56
+ #
57
+ # Returns Array of matched Strings from available Array or [].
58
+ def find_q_matches(q_values, available, &matcher)
59
+ matcher ||= lambda { |a, b| a == b }
60
+
61
+ matches = []
62
+
63
+ case q_values
64
+ when Array
65
+ when String
66
+ q_values = parse_q_values(q_values)
67
+ when NilClass
68
+ q_values = []
69
+ else
70
+ raise TypeError, "unknown q_values type: #{q_values.class}"
71
+ end
72
+
73
+ q_values.each do |accepted, quality|
74
+ if match = available.find { |option| matcher.call(option, accepted) }
75
+ matches << [match, quality]
76
+ end
77
+ end
78
+
79
+ matches.sort_by! { |match, quality| -quality }
80
+ matches.map! { |match, quality| match }
81
+ matches
82
+ end
83
+
84
+ # Internal: Find the best qvalue match from an Array of available options.
85
+ #
86
+ # Adapted from Rack::Utils#q_values.
87
+ #
88
+ # Returns the matched String from available Array or nil.
89
+ def find_best_q_match(q_values, available, &matcher)
90
+ find_q_matches(q_values, available, &matcher).first
91
+ end
92
+
93
+ # Internal: Find the all qvalue match from an Array of available mime type
94
+ # options.
95
+ #
96
+ # Adapted from Rack::Utils#q_values.
97
+ #
98
+ # Returns Array of matched mime type Strings from available Array or [].
99
+ def find_mime_type_matches(q_value_header, available)
100
+ find_q_matches(q_value_header, available) do |a, b|
101
+ match_mime_type?(a, b)
102
+ end
103
+ end
104
+
105
+ # Internal: Find the best qvalue match from an Array of available mime type
106
+ # options.
107
+ #
108
+ # Adapted from Rack::Utils#q_values.
109
+ #
110
+ # Returns the matched mime type String from available Array or nil.
111
+ def find_best_mime_type_match(q_value_header, available)
112
+ find_best_q_match(q_value_header, available) do |a, b|
113
+ match_mime_type?(a, b)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -1,29 +1,49 @@
1
- require 'tilt'
2
-
3
1
  module Sprockets
4
- class JstProcessor < Tilt::Template
5
- self.default_mime_type = 'application/javascript'
6
-
2
+ # Public: .jst engine.
3
+ #
4
+ # Exports server side compiled templates to an object.
5
+ #
6
+ # Name your template "users/show.jst.ejs", "users/new.jst.eco", etc.
7
+ #
8
+ # To accept the default options
9
+ #
10
+ # environment.register_engine '.jst',
11
+ # JstProcessor,
12
+ # mime_type: 'application/javascript'
13
+ #
14
+ # Change the default namespace.
15
+ #
16
+ # environment.register_engine '.jst',
17
+ # JstProcessor.new(namespace: 'App.templates'),
18
+ # mime_type: 'application/javascript'
19
+ #
20
+ class JstProcessor
7
21
  def self.default_namespace
8
22
  'this.JST'
9
23
  end
10
24
 
11
- def prepare
12
- @namespace = self.class.default_namespace
25
+ # Public: Return singleton instance with default options.
26
+ #
27
+ # Returns JstProcessor object.
28
+ def self.instance
29
+ @instance ||= new
30
+ end
31
+
32
+ def self.call(input)
33
+ instance.call(input)
13
34
  end
14
35
 
15
- attr_reader :namespace
36
+ def initialize(options = {})
37
+ @namespace = options[:namespace] || self.class.default_namespace
38
+ end
16
39
 
17
- def evaluate(scope, locals, &block)
40
+ def call(input)
41
+ data = input[:data].gsub(/$(.)/m, "\\1 ").strip
42
+ key = input[:name]
18
43
  <<-JST
19
- (function() { #{namespace} || (#{namespace} = {}); #{namespace}[#{scope.logical_path.inspect}] = #{indent(data)};
44
+ (function() { #{@namespace} || (#{@namespace} = {}); #{@namespace}[#{key.inspect}] = #{data};
20
45
  }).call(this);
21
46
  JST
22
47
  end
23
-
24
- private
25
- def indent(string)
26
- string.gsub(/$(.)/m, "\\1 ").strip
27
- end
28
48
  end
29
49
  end
@@ -0,0 +1,330 @@
1
+ require 'pathname'
2
+ require 'sprockets/asset'
3
+ require 'sprockets/base'
4
+ require 'sprockets/cached_environment'
5
+ require 'sprockets/context'
6
+ require 'sprockets/manifest'
7
+ require 'sprockets/resolve'
8
+
9
+ module Sprockets
10
+ autoload :CoffeeScriptTemplate, 'sprockets/coffee_script_template'
11
+ autoload :EcoTemplate, 'sprockets/eco_template'
12
+ autoload :EjsTemplate, 'sprockets/ejs_template'
13
+ autoload :ERBTemplate, 'sprockets/erb_template'
14
+ autoload :SassTemplate, 'sprockets/sass_template'
15
+ autoload :ScssTemplate, 'sprockets/sass_template'
16
+
17
+ # Deprecated
18
+ Index = CachedEnvironment
19
+
20
+ class Base
21
+ include Resolve
22
+
23
+ # Deprecated: Change default return type of resolve() to return 2.x
24
+ # compatible plain filename String. 4.x will always return an Asset URI
25
+ # and a set of file system dependencies that had to be read to compute the
26
+ # result.
27
+ #
28
+ # 2.x
29
+ #
30
+ # resolve("foo.js")
31
+ # # => "/path/to/app/javascripts/foo.js"
32
+ #
33
+ # 3.x
34
+ #
35
+ # resolve("foo.js")
36
+ # # => "/path/to/app/javascripts/foo.js"
37
+ #
38
+ # resolve("foo.js", compat: true)
39
+ # # => "/path/to/app/javascripts/foo.js"
40
+ #
41
+ # resolve("foo.js", compat: false)
42
+ # # => [
43
+ # # "file:///path/to/app/javascripts/foo.js?type=application/javascript"
44
+ # # #<Set: {"file-digest:/path/to/app/javascripts/foo.js"}>
45
+ # # ]
46
+ #
47
+ # 4.x
48
+ #
49
+ # resolve("foo.js")
50
+ # # => [
51
+ # # "file:///path/to/app/javascripts/foo.js?type=application/javascript"
52
+ # # #<Set: {"file-digest:/path/to/app/javascripts/foo.js"}>
53
+ # # ]
54
+ #
55
+ def resolve_with_compat(path, options = {})
56
+ options = options.dup
57
+ if options.delete(:compat) { true }
58
+ uri, _ = resolve_without_compat(path, options)
59
+ if uri
60
+ path, _ = parse_asset_uri(uri)
61
+ path
62
+ else
63
+ nil
64
+ end
65
+ else
66
+ resolve_without_compat(path, options)
67
+ end
68
+ end
69
+ alias_method :resolve_without_compat, :resolve
70
+ alias_method :resolve, :resolve_with_compat
71
+
72
+ # Deprecated: Iterate over all logical paths with a matcher.
73
+ #
74
+ # Remove from 4.x.
75
+ #
76
+ # args - List of matcher objects.
77
+ #
78
+ # Returns Enumerator if no block is given.
79
+ def each_logical_path(*args, &block)
80
+ return to_enum(__method__, *args) unless block_given?
81
+
82
+ filters = args.flatten.map { |arg| Manifest.compile_match_filter(arg) }
83
+ logical_paths.each do |a, b|
84
+ if filters.any? { |f| f.call(a, b) }
85
+ if block.arity == 2
86
+ yield a, b
87
+ else
88
+ yield a
89
+ end
90
+ end
91
+ end
92
+
93
+ nil
94
+ end
95
+
96
+ # Deprecated: Enumerate over all logical paths in the environment.
97
+ #
98
+ # Returns an Enumerator of [logical_path, filename].
99
+ def logical_paths
100
+ return to_enum(__method__) unless block_given?
101
+
102
+ seen = Set.new
103
+
104
+ paths.each do |load_path|
105
+ stat_tree(load_path).each do |filename, stat|
106
+ next unless stat.file?
107
+
108
+ path = split_subpath(load_path, filename)
109
+ path, mime_type, _, _ = parse_path_extnames(path)
110
+ path = normalize_logical_path(path)
111
+ path += mime_types[mime_type][:extensions].first if mime_type
112
+
113
+ if !seen.include?(path)
114
+ yield path, filename
115
+ seen << path
116
+ end
117
+ end
118
+ end
119
+
120
+ nil
121
+ end
122
+
123
+ def cache_get(key)
124
+ cache.get(key)
125
+ end
126
+
127
+ def cache_set(key, value)
128
+ cache.set(key, value)
129
+ end
130
+
131
+ def normalize_logical_path(path)
132
+ dirname, basename = File.split(path)
133
+ path = dirname if basename == 'index'
134
+ path
135
+ end
136
+
137
+ private
138
+ # Deprecated: Seriously.
139
+ def matches_filter(filters, logical_path, filename)
140
+ return true if filters.empty?
141
+
142
+ filters.any? do |filter|
143
+ if filter.is_a?(Regexp)
144
+ filter.match(logical_path)
145
+ elsif filter.respond_to?(:call)
146
+ if filter.arity == 1
147
+ filter.call(logical_path)
148
+ else
149
+ filter.call(logical_path, filename.to_s)
150
+ end
151
+ else
152
+ File.fnmatch(filter.to_s, logical_path)
153
+ end
154
+ end
155
+ end
156
+
157
+ # URI.unescape is deprecated on 1.9. We need to use URI::Parser
158
+ # if its available.
159
+ if defined? URI::DEFAULT_PARSER
160
+ def unescape(str)
161
+ str = URI::DEFAULT_PARSER.unescape(str)
162
+ str.force_encoding(Encoding.default_internal) if Encoding.default_internal
163
+ str
164
+ end
165
+ else
166
+ def unescape(str)
167
+ URI.unescape(str)
168
+ end
169
+ end
170
+ end
171
+
172
+ class Asset
173
+ # Deprecated: Use #filename instead.
174
+ #
175
+ # Returns Pathname.
176
+ def pathname
177
+ @pathname ||= Pathname.new(filename)
178
+ end
179
+
180
+ # Deprecated: Expand asset into an `Array` of parts.
181
+ #
182
+ # Appending all of an assets body parts together should give you
183
+ # the asset's contents as a whole.
184
+ #
185
+ # This allows you to link to individual files for debugging
186
+ # purposes.
187
+ #
188
+ # Use Asset#included instead. Keeping a full copy of the bundle's processed
189
+ # assets in memory (and in cache) is expensive and redundant. The common use
190
+ # case is to relink to the assets anyway.
191
+ #
192
+ # Returns Array of Assets.
193
+ def to_a
194
+ if metadata[:included]
195
+ metadata[:included].map { |uri| @environment.load(uri) }
196
+ else
197
+ [self]
198
+ end
199
+ end
200
+
201
+ # Deprecated: Get all required Assets.
202
+ #
203
+ # See Asset#to_a
204
+ #
205
+ # Returns Array of Assets.
206
+ def dependencies
207
+ to_a.reject { |a| a.filename.eql?(self.filename) }
208
+ end
209
+
210
+ # Deprecated: Returns Time of the last time the source was modified.
211
+ #
212
+ # Time resolution is normalized to the nearest second.
213
+ #
214
+ # Returns Time.
215
+ def mtime
216
+ Time.at(@mtime)
217
+ end
218
+ end
219
+
220
+ class Context
221
+ # Deprecated: Change default return type of resolve() to return 2.x
222
+ # compatible plain filename String. 4.x will always return an Asset URI.
223
+ #
224
+ # 2.x
225
+ #
226
+ # resolve("foo.js")
227
+ # # => "/path/to/app/javascripts/foo.js"
228
+ #
229
+ # 3.x
230
+ #
231
+ # resolve("foo.js")
232
+ # # => "/path/to/app/javascripts/foo.js"
233
+ #
234
+ # resolve("foo.js", compat: true)
235
+ # # => "/path/to/app/javascripts/foo.js"
236
+ #
237
+ # resolve("foo.js", compat: false)
238
+ # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript"
239
+ #
240
+ # 4.x
241
+ #
242
+ # resolve("foo.js")
243
+ # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript"
244
+ #
245
+ def resolve_with_compat(path, options = {})
246
+ options = options.dup
247
+
248
+ # Support old :content_type option, prefer :accept going forward
249
+ if type = options.delete(:content_type)
250
+ type = self.content_type if type == :self
251
+ options[:accept] ||= type
252
+ end
253
+
254
+ if options.delete(:compat) { true }
255
+ uri = resolve_without_compat(path, options)
256
+ path, _ = environment.parse_asset_uri(uri)
257
+ path
258
+ else
259
+ resolve_without_compat(path, options)
260
+ end
261
+ end
262
+ alias_method :resolve_without_compat, :resolve
263
+ alias_method :resolve, :resolve_with_compat
264
+ end
265
+
266
+ class Manifest
267
+ # Deprecated: Compile logical path matching filter into a proc that can be
268
+ # passed to logical_paths.select(&proc).
269
+ #
270
+ # compile_match_filter(proc { |logical_path|
271
+ # File.extname(logical_path) == '.js'
272
+ # })
273
+ #
274
+ # compile_match_filter(/application.js/)
275
+ #
276
+ # compile_match_filter("foo/*.js")
277
+ #
278
+ # Returns a Proc or raise a TypeError.
279
+ def self.compile_match_filter(filter)
280
+ # If the filter is already a proc, great nothing to do.
281
+ if filter.respond_to?(:call)
282
+ filter
283
+ # If the filter is a regexp, wrap it in a proc that tests it against the
284
+ # logical path.
285
+ elsif filter.is_a?(Regexp)
286
+ proc { |logical_path| filter.match(logical_path) }
287
+ elsif filter.is_a?(String)
288
+ # If its an absolute path, detect the matching full filename
289
+ if PathUtils.absolute_path?(filter)
290
+ proc { |logical_path, filename| filename == filter.to_s }
291
+ else
292
+ # Otherwise do an fnmatch against the logical path.
293
+ proc { |logical_path| File.fnmatch(filter.to_s, logical_path) }
294
+ end
295
+ else
296
+ raise TypeError, "unknown filter type: #{filter.inspect}"
297
+ end
298
+ end
299
+
300
+ def self.simple_logical_path?(str)
301
+ str.is_a?(String) &&
302
+ !PathUtils.absolute_path?(str) &&
303
+ str !~ /\*|\*\*|\?|\[|\]|\{|\}/
304
+ end
305
+
306
+ def self.compute_alias_logical_path(path)
307
+ dirname, basename = File.split(path)
308
+ extname = File.extname(basename)
309
+ if File.basename(basename, extname) == 'index'
310
+ "#{dirname}#{extname}"
311
+ else
312
+ nil
313
+ end
314
+ end
315
+
316
+ # Deprecated: Filter logical paths in environment. Useful for selecting what
317
+ # files you want to compile.
318
+ #
319
+ # Returns an Enumerator.
320
+ def filter_logical_paths(*args)
321
+ filters = args.flatten.map { |arg| self.class.compile_match_filter(arg) }
322
+ environment.cached.logical_paths.select do |a, b|
323
+ filters.any? { |f| f.call(a, b) }
324
+ end
325
+ end
326
+
327
+ # Deprecated alias.
328
+ alias_method :find_logical_paths, :filter_logical_paths
329
+ end
330
+ end
@@ -0,0 +1,35 @@
1
+ require 'delegate'
2
+
3
+ module Sprockets
4
+ # Deprecated: Wraps legacy process Procs with new processor call signature.
5
+ #
6
+ # Will be removed in Sprockets 4.x.
7
+ #
8
+ # LegacyProcProcessor.new(:compress,
9
+ # proc { |context, data| data.gsub(...) })
10
+ #
11
+ class LegacyProcProcessor < Delegator
12
+ def initialize(name, proc)
13
+ @name = name
14
+ @proc = proc
15
+ end
16
+
17
+ def __getobj__
18
+ @proc
19
+ end
20
+
21
+ def name
22
+ "Sprockets::LegacyProcProcessor (#{@name})"
23
+ end
24
+
25
+ def to_s
26
+ name
27
+ end
28
+
29
+ def call(input)
30
+ context = input[:environment].context_class.new(input)
31
+ data = @proc.call(context, input[:data])
32
+ context.metadata.merge(data: data.to_str)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ require 'delegate'
2
+
3
+ module Sprockets
4
+ # Deprecated: Wraps legacy engine and process Tilt templates with new
5
+ # processor call signature.
6
+ #
7
+ # Will be removed in Sprockets 4.x.
8
+ #
9
+ # LegacyTiltProcessor.new(Tilt::CoffeeScriptProcessor)
10
+ #
11
+ class LegacyTiltProcessor < Delegator
12
+ def initialize(klass)
13
+ @klass = klass
14
+ end
15
+
16
+ def __getobj__
17
+ @klass
18
+ end
19
+
20
+ def call(input)
21
+ filename = input[:filename]
22
+ data = input[:data]
23
+ context = input[:environment].context_class.new(input)
24
+
25
+ data = @klass.new(filename) { data }.render(context, {})
26
+ context.metadata.merge(data: data.to_str)
27
+ end
28
+ end
29
+ end