sprockets 3.7.2 → 4.0.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 +47 -267
- data/README.md +477 -321
- data/bin/sprockets +11 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets.rb +99 -39
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +31 -23
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +49 -12
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +40 -4
- data/lib/sprockets/cache.rb +36 -1
- data/lib/sprockets/cache/file_store.rb +25 -3
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +1 -0
- data/lib/sprockets/coffee_script_processor.rb +18 -4
- data/lib/sprockets/compressing.rb +43 -3
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +97 -24
- data/lib/sprockets/dependencies.rb +1 -0
- data/lib/sprockets/digest_utils.rb +25 -5
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +1 -0
- data/lib/sprockets/ejs_processor.rb +1 -0
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +87 -67
- data/lib/sprockets/manifest.rb +64 -62
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +87 -7
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -61
- data/lib/sprockets/processor_utils.rb +24 -35
- data/lib/sprockets/resolve.rb +177 -93
- data/lib/sprockets/sass_cache_store.rb +2 -6
- data/lib/sprockets/sass_compressor.rb +13 -1
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +30 -9
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +26 -23
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +21 -11
- data/lib/sprockets/unloaded_asset.rb +13 -11
- data/lib/sprockets/uri_tar.rb +1 -0
- data/lib/sprockets/uri_utils.rb +11 -8
- data/lib/sprockets/utils.rb +41 -74
- data/lib/sprockets/utils/gzip.rb +46 -14
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- metadata +127 -23
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -17
- data/lib/sprockets/deprecation.rb +0 -90
- data/lib/sprockets/eco_template.rb +0 -17
- data/lib/sprockets/ejs_template.rb +0 -17
- data/lib/sprockets/engines.rb +0 -92
- data/lib/sprockets/erb_template.rb +0 -11
- data/lib/sprockets/legacy.rb +0 -330
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -19
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'digest/md5'
|
2
3
|
require 'digest/sha1'
|
3
4
|
require 'digest/sha2'
|
@@ -62,7 +63,7 @@ module Sprockets
|
|
62
63
|
},
|
63
64
|
Set => ->(val, digest) {
|
64
65
|
digest << 'Set'.freeze
|
65
|
-
ADD_VALUE_TO_DIGEST[Array].call(val
|
66
|
+
ADD_VALUE_TO_DIGEST[Array].call(val, digest)
|
66
67
|
},
|
67
68
|
Encoding => ->(val, digest) {
|
68
69
|
digest << 'Encoding'.freeze
|
@@ -79,6 +80,9 @@ module Sprockets
|
|
79
80
|
digest << val.to_s
|
80
81
|
}
|
81
82
|
end
|
83
|
+
|
84
|
+
ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
|
85
|
+
|
82
86
|
ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
|
83
87
|
raise TypeError, "couldn't digest #{ val }"
|
84
88
|
}
|
@@ -93,10 +97,18 @@ module Sprockets
|
|
93
97
|
#
|
94
98
|
# Returns a String digest of the object.
|
95
99
|
def digest(obj)
|
96
|
-
digest
|
100
|
+
build_digest(obj).digest
|
101
|
+
end
|
97
102
|
|
98
|
-
|
99
|
-
|
103
|
+
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
104
|
+
#
|
105
|
+
# The same as `pack_hexdigest(digest(obj))`.
|
106
|
+
#
|
107
|
+
# obj - A JSON serializable object.
|
108
|
+
#
|
109
|
+
# Returns a String digest of the object.
|
110
|
+
def hexdigest(obj)
|
111
|
+
build_digest(obj).hexdigest!
|
100
112
|
end
|
101
113
|
|
102
114
|
# Internal: Pack a binary digest to a hex encoded string.
|
@@ -105,7 +117,7 @@ module Sprockets
|
|
105
117
|
#
|
106
118
|
# Returns hex String.
|
107
119
|
def pack_hexdigest(bin)
|
108
|
-
bin.unpack('H*').first
|
120
|
+
bin.unpack('H*'.freeze).first
|
109
121
|
end
|
110
122
|
|
111
123
|
# Internal: Unpack a hex encoded digest string into binary bytes.
|
@@ -176,5 +188,13 @@ module Sprockets
|
|
176
188
|
def hexdigest_integrity_uri(hexdigest)
|
177
189
|
integrity_uri(unpack_hexdigest(hexdigest))
|
178
190
|
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def build_digest(obj)
|
194
|
+
digest = digest_class.new
|
195
|
+
|
196
|
+
ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
|
197
|
+
digest
|
198
|
+
end
|
179
199
|
end
|
180
200
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'set'
|
2
3
|
require 'shellwords'
|
3
4
|
|
@@ -34,8 +35,6 @@ module Sprockets
|
|
34
35
|
# env.register_processor('text/css', MyProcessor)
|
35
36
|
#
|
36
37
|
class DirectiveProcessor
|
37
|
-
VERSION = '1'
|
38
|
-
|
39
38
|
# Directives are denoted by a `=` followed by the name, then
|
40
39
|
# argument list.
|
41
40
|
#
|
@@ -50,18 +49,16 @@ module Sprockets
|
|
50
49
|
/x
|
51
50
|
|
52
51
|
def self.instance
|
53
|
-
|
54
|
-
|
55
|
-
comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]]
|
56
|
-
)
|
52
|
+
# Default to C comment styles
|
53
|
+
@instance ||= new(comments: ["//", ["/*", "*/"]])
|
57
54
|
end
|
58
55
|
|
59
56
|
def self.call(input)
|
60
57
|
instance.call(input)
|
61
58
|
end
|
62
59
|
|
63
|
-
def initialize(
|
64
|
-
@header_pattern = compile_header_pattern(Array(
|
60
|
+
def initialize(comments: [])
|
61
|
+
@header_pattern = compile_header_pattern(Array(comments))
|
65
62
|
end
|
66
63
|
|
67
64
|
def call(input)
|
@@ -73,20 +70,28 @@ module Sprockets
|
|
73
70
|
@uri = input[:uri]
|
74
71
|
@filename = input[:filename]
|
75
72
|
@dirname = File.dirname(@filename)
|
76
|
-
|
73
|
+
# If loading a source map file like `application.js.map` resolve
|
74
|
+
# dependencies using `.js` instead of `.js.map`
|
75
|
+
@content_type = SourceMapProcessor.original_content_type(input[:content_type], error_when_not_found: false)
|
77
76
|
@required = Set.new(input[:metadata][:required])
|
78
77
|
@stubbed = Set.new(input[:metadata][:stubbed])
|
79
78
|
@links = Set.new(input[:metadata][:links])
|
80
79
|
@dependencies = Set.new(input[:metadata][:dependencies])
|
80
|
+
@to_link = Set.new
|
81
|
+
@to_load = Set.new
|
81
82
|
|
82
83
|
data, directives = process_source(input[:data])
|
83
84
|
process_directives(directives)
|
84
85
|
|
85
|
-
{
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
{
|
87
|
+
data: data,
|
88
|
+
required: @required,
|
89
|
+
stubbed: @stubbed,
|
90
|
+
links: @links,
|
91
|
+
to_load: @to_load,
|
92
|
+
to_link: @to_link,
|
93
|
+
dependencies: @dependencies
|
94
|
+
}
|
90
95
|
end
|
91
96
|
|
92
97
|
protected
|
@@ -116,9 +121,9 @@ module Sprockets
|
|
116
121
|
|
117
122
|
header, directives = extract_directives(header)
|
118
123
|
|
119
|
-
data = ""
|
124
|
+
data = +""
|
120
125
|
data.force_encoding(body.encoding)
|
121
|
-
data << header
|
126
|
+
data << header unless header.empty?
|
122
127
|
data << body
|
123
128
|
# Ensure body ends in a new line
|
124
129
|
data << "\n" if data.length > 0 && data[-1] != "\n"
|
@@ -134,7 +139,7 @@ module Sprockets
|
|
134
139
|
# [[1, "require", "foo"], [2, "require", "bar"]]
|
135
140
|
#
|
136
141
|
def extract_directives(header)
|
137
|
-
processed_header = ""
|
142
|
+
processed_header = +""
|
138
143
|
directives = []
|
139
144
|
|
140
145
|
header.lines.each_with_index do |line, index|
|
@@ -149,7 +154,11 @@ module Sprockets
|
|
149
154
|
processed_header << line
|
150
155
|
end
|
151
156
|
|
152
|
-
|
157
|
+
processed_header.chomp!
|
158
|
+
# Ensure header ends in a new line like before it was processed
|
159
|
+
processed_header << "\n" if processed_header.length > 0 && header[-1] == "\n"
|
160
|
+
|
161
|
+
return processed_header, directives
|
153
162
|
end
|
154
163
|
|
155
164
|
# Gathers comment directives in the source and processes them.
|
@@ -162,7 +171,7 @@ module Sprockets
|
|
162
171
|
# `process_require_glob_directive`.
|
163
172
|
#
|
164
173
|
# class DirectiveProcessor < Sprockets::DirectiveProcessor
|
165
|
-
# def process_require_glob_directive
|
174
|
+
# def process_require_glob_directive(glob)
|
166
175
|
# Dir["#{dirname}/#{glob}"].sort.each do |filename|
|
167
176
|
# require(filename)
|
168
177
|
# end
|
@@ -187,7 +196,7 @@ module Sprockets
|
|
187
196
|
|
188
197
|
# The `require` directive functions similar to Ruby's own `require`.
|
189
198
|
# It provides a way to declare a dependency on a file in your path
|
190
|
-
# and ensures
|
199
|
+
# and ensures it's only loaded once before the source file.
|
191
200
|
#
|
192
201
|
# `require` works with files in the environment path:
|
193
202
|
#
|
@@ -265,15 +274,15 @@ module Sprockets
|
|
265
274
|
# it.
|
266
275
|
#
|
267
276
|
# This is used for caching purposes. Any changes that would
|
268
|
-
#
|
269
|
-
# source file.
|
277
|
+
# invalidate the asset dependency will invalidate the cache of
|
278
|
+
# the source file.
|
270
279
|
#
|
271
280
|
# Unlike `depend_on`, the path must be a requirable asset.
|
272
281
|
#
|
273
282
|
# //= depend_on_asset "bar.js"
|
274
283
|
#
|
275
284
|
def process_depend_on_asset_directive(path)
|
276
|
-
|
285
|
+
to_load(resolve(path))
|
277
286
|
end
|
278
287
|
|
279
288
|
# Allows dependency to be excluded from the asset bundle.
|
@@ -297,7 +306,8 @@ module Sprockets
|
|
297
306
|
# /*= link "logo.png" */
|
298
307
|
#
|
299
308
|
def process_link_directive(path)
|
300
|
-
|
309
|
+
uri = to_load(resolve(path))
|
310
|
+
@to_link << uri
|
301
311
|
end
|
302
312
|
|
303
313
|
# `link_directory` links all the files inside a single
|
@@ -307,7 +317,7 @@ module Sprockets
|
|
307
317
|
# //= link_directory "./fonts"
|
308
318
|
#
|
309
319
|
# Use caution when linking against JS or CSS assets. Include an explicit
|
310
|
-
# extension or content type in these cases
|
320
|
+
# extension or content type in these cases.
|
311
321
|
#
|
312
322
|
# //= link_directory "./scripts" .js
|
313
323
|
#
|
@@ -323,7 +333,7 @@ module Sprockets
|
|
323
333
|
# //= link_tree "./images"
|
324
334
|
#
|
325
335
|
# Use caution when linking against JS or CSS assets. Include an explicit
|
326
|
-
# extension or content type in these cases
|
336
|
+
# extension or content type in these cases.
|
327
337
|
#
|
328
338
|
# //= link_tree "./styles" .css
|
329
339
|
#
|
@@ -354,15 +364,15 @@ module Sprockets
|
|
354
364
|
|
355
365
|
def link_paths(paths, deps, accept)
|
356
366
|
resolve_paths(paths, deps, accept: accept) do |uri|
|
357
|
-
@
|
367
|
+
@to_link << to_load(uri)
|
358
368
|
end
|
359
369
|
end
|
360
370
|
|
361
|
-
def resolve_paths(paths, deps,
|
371
|
+
def resolve_paths(paths, deps, **kargs)
|
362
372
|
@dependencies.merge(deps)
|
363
373
|
paths.each do |subpath, stat|
|
364
374
|
next if subpath == @filename || stat.directory?
|
365
|
-
uri, deps = @environment.resolve(subpath,
|
375
|
+
uri, deps = @environment.resolve(subpath, **kargs)
|
366
376
|
@dependencies.merge(deps)
|
367
377
|
yield uri if uri
|
368
378
|
end
|
@@ -384,19 +394,19 @@ module Sprockets
|
|
384
394
|
end
|
385
395
|
end
|
386
396
|
|
387
|
-
def
|
388
|
-
|
389
|
-
|
390
|
-
asset
|
397
|
+
def to_load(uri)
|
398
|
+
@to_load << uri
|
399
|
+
uri
|
391
400
|
end
|
392
401
|
|
393
|
-
def resolve(path,
|
402
|
+
def resolve(path, **kargs)
|
394
403
|
# Prevent absolute paths in directives
|
395
404
|
if @environment.absolute_path?(path)
|
396
405
|
raise FileOutsidePaths, "can't require absolute file: #{path}"
|
397
406
|
end
|
398
407
|
|
399
|
-
|
408
|
+
kargs[:base_path] = @dirname
|
409
|
+
uri, deps = @environment.resolve!(path, **kargs)
|
400
410
|
@dependencies.merge(deps)
|
401
411
|
uri
|
402
412
|
end
|
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/base'
|
2
3
|
require 'sprockets/cache/memory_store'
|
3
4
|
require 'sprockets/cached_environment'
|
4
5
|
|
5
6
|
module Sprockets
|
6
7
|
class Environment < Base
|
7
|
-
# `Environment` should initialized with your application's root
|
8
|
+
# `Environment` should be initialized with your application's root
|
8
9
|
# directory. This should be the same as your Rails or Rack root.
|
9
10
|
#
|
10
11
|
# env = Environment.new(Rails.root)
|
@@ -18,7 +19,7 @@ module Sprockets
|
|
18
19
|
|
19
20
|
# Returns a cached version of the environment.
|
20
21
|
#
|
21
|
-
# All its file system calls are cached which makes `cached` much
|
22
|
+
# All of its file system calls are cached which makes `cached` much
|
22
23
|
# faster. This behavior is ideal in production since the file
|
23
24
|
# system only changes between deploys.
|
24
25
|
def cached
|
@@ -26,8 +27,12 @@ module Sprockets
|
|
26
27
|
end
|
27
28
|
alias_method :index, :cached
|
28
29
|
|
29
|
-
def find_asset(*args)
|
30
|
-
cached.find_asset(*args)
|
30
|
+
def find_asset(*args, **options)
|
31
|
+
cached.find_asset(*args, **options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_asset!(*args)
|
35
|
+
cached.find_asset!(*args)
|
31
36
|
end
|
32
37
|
|
33
38
|
def find_all_linked_assets(*args, &block)
|
@@ -1,30 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'erb'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
4
|
+
class Sprockets::ERBProcessor
|
5
|
+
# Public: Return singleton instance with default options.
|
6
|
+
#
|
7
|
+
# Returns ERBProcessor object.
|
8
|
+
def self.instance
|
9
|
+
@instance ||= new
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def self.call(input)
|
13
|
+
instance.call(input)
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def initialize(&block)
|
17
|
+
@block = block
|
18
|
+
end
|
19
19
|
|
20
|
-
|
20
|
+
def call(input)
|
21
|
+
match = ERB.version.match(/\Aerb\.rb \[(?<version>[^ ]+) /)
|
22
|
+
if match && match[:version] >= "2.2.0" # Ruby 2.6+
|
23
|
+
engine = ::ERB.new(input[:data], trim_mode: '<>')
|
24
|
+
else
|
21
25
|
engine = ::ERB.new(input[:data], nil, '<>')
|
22
|
-
context = input[:environment].context_class.new(input)
|
23
|
-
klass = (class << context; self; end)
|
24
|
-
klass.class_eval(&@block) if @block
|
25
|
-
engine.def_method(klass, :_evaluate_template, input[:filename])
|
26
|
-
data = context._evaluate_template
|
27
|
-
context.metadata.merge(data: data)
|
28
26
|
end
|
27
|
+
engine.filename = input[:filename]
|
28
|
+
|
29
|
+
context = input[:environment].context_class.new(input)
|
30
|
+
klass = (class << context; self; end)
|
31
|
+
klass.const_set(:ENV, context.env_proxy)
|
32
|
+
klass.class_eval(&@block) if @block
|
33
|
+
|
34
|
+
data = engine.result(context.instance_eval('binding'))
|
35
|
+
context.metadata.merge(data: data)
|
29
36
|
end
|
30
37
|
end
|
data/lib/sprockets/errors.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Sprockets
|
2
|
+
module Exporters
|
3
|
+
# Convienence class for all exporters to inherit from
|
4
|
+
#
|
5
|
+
# An exporter is responsible for exporting a Sprockets::Asset
|
6
|
+
# to a file system. For example the Exporters::File class
|
7
|
+
# writes the asset to it's destination. The Exporters::Zlib class
|
8
|
+
# writes a gzip copy of the asset to disk.
|
9
|
+
class Base
|
10
|
+
attr_reader :asset, :environment, :directory, :target
|
11
|
+
|
12
|
+
# Public: Creates new instance
|
13
|
+
#
|
14
|
+
# Initialize will be called with
|
15
|
+
# keyword arguments:
|
16
|
+
#
|
17
|
+
# - asset: An instance of Sprockets::Asset.
|
18
|
+
# - environment: An instance of Sprockets::Environment.
|
19
|
+
# - directory: String representing the target directory to write to.
|
20
|
+
#
|
21
|
+
# These will all be stored as accessible values. In addition a
|
22
|
+
# +target+ will be available which is the target directory and
|
23
|
+
# the asset's digest path combined.
|
24
|
+
def initialize(asset: nil, environment: nil, directory: nil)
|
25
|
+
@asset = asset
|
26
|
+
@environment = environment
|
27
|
+
@directory = directory
|
28
|
+
@target = ::File.join(directory, asset.digest_path)
|
29
|
+
setup
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Callback that is executed after intialization
|
33
|
+
#
|
34
|
+
# Any setup that needs to be done can be performed in the +setup+
|
35
|
+
# method. It will be called immediately after initialization.
|
36
|
+
def setup
|
37
|
+
end
|
38
|
+
|
39
|
+
# Public: Handles logic for skipping exporter and notifying logger
|
40
|
+
#
|
41
|
+
# The `skip?` will be called before anything will be written.
|
42
|
+
# If `skip?` returns truthy it will not continue. This method
|
43
|
+
# takes a `logger` that responds to +debug+ and +info+. The `skip?`
|
44
|
+
# method is the only place expected to write to a logger, any other
|
45
|
+
# messages may produce jumbled logs.
|
46
|
+
def skip?(logger)
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Public: Contains logic for writing "exporting" asset to disk
|
51
|
+
#
|
52
|
+
# If the exporter is not skipped it then Sprockets will execute it's
|
53
|
+
# `call` method. This method takes no arguments and should only use
|
54
|
+
# elements passed in via initialize or stored in `setup`.
|
55
|
+
def call
|
56
|
+
raise "Must subclass and implement call"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Public: Yields a file that can be written to with the input
|
60
|
+
#
|
61
|
+
# `filename`. Defaults to the `target`. Method
|
62
|
+
# is safe to use in forked or threaded environments.
|
63
|
+
def write(filename = target)
|
64
|
+
FileUtils.mkdir_p File.dirname(filename)
|
65
|
+
PathUtils.atomic_write(filename) do |f|
|
66
|
+
yield f
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|