bootsnap 1.9.4 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,66 +1,42 @@
1
1
  # frozen_string_literal: true
2
- require('bootsnap/bootsnap')
2
+
3
+ require("bootsnap/bootsnap")
3
4
 
4
5
  module Bootsnap
5
6
  module CompileCache
6
7
  module YAML
7
- class << self
8
- attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
9
-
10
- def input_to_storage(contents, _)
11
- obj = strict_load(contents)
12
- msgpack_factory.dump(obj)
13
- rescue NoMethodError, RangeError
14
- # The object included things that we can't serialize
15
- raise(Uncompilable)
16
- end
8
+ UnsupportedTags = Class.new(StandardError)
17
9
 
18
- def storage_to_output(data, kwargs)
19
- if kwargs && kwargs.key?(:symbolize_names)
20
- kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
21
- end
22
- msgpack_factory.load(data, kwargs)
23
- end
24
-
25
- def input_to_output(data, kwargs)
26
- if ::YAML.respond_to?(:unsafe_load)
27
- ::YAML.unsafe_load(data, **(kwargs || {}))
28
- else
29
- ::YAML.load(data, **(kwargs || {}))
30
- end
31
- end
10
+ class << self
11
+ attr_accessor(:msgpack_factory, :supported_options)
12
+ attr_reader(:implementation, :cache_dir)
32
13
 
33
- def strict_load(payload, *args)
34
- ast = ::YAML.parse(payload)
35
- return ast unless ast
36
- strict_visitor.create(*args).visit(ast)
14
+ def cache_dir=(cache_dir)
15
+ @cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}yaml" : "#{cache_dir}-yaml"
37
16
  end
38
- ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
39
17
 
40
- def precompile(path, cache_dir: YAML.cache_dir)
18
+ def precompile(path)
41
19
  Bootsnap::CompileCache::Native.precompile(
42
20
  cache_dir,
43
21
  path.to_s,
44
- Bootsnap::CompileCache::YAML,
22
+ @implementation,
45
23
  )
46
24
  end
47
25
 
48
26
  def install!(cache_dir)
49
27
  self.cache_dir = cache_dir
50
28
  init!
51
- ::YAML.singleton_class.prepend(Patch)
29
+ ::YAML.singleton_class.prepend(@implementation::Patch)
52
30
  end
53
31
 
54
32
  def init!
55
- require('yaml')
56
- require('msgpack')
57
- require('date')
33
+ require("yaml")
34
+ require("msgpack")
35
+ require("date")
58
36
 
59
- if Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
60
- Patch.send(:remove_method, :unsafe_load_file)
61
- end
62
- if Patch.method_defined?(:load_file) && ::YAML::VERSION >= '4'
63
- Patch.send(:remove_method, :load_file)
37
+ @implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
38
+ if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
39
+ @implementation::Patch.send(:remove_method, :unsafe_load_file)
64
40
  end
65
41
 
66
42
  # MessagePack serializes symbols as strings by default.
@@ -74,7 +50,7 @@ module Bootsnap
74
50
  MessagePack::Timestamp::TYPE, # or just -1
75
51
  Time,
76
52
  packer: MessagePack::Time::Packer,
77
- unpacker: MessagePack::Time::Unpacker
53
+ unpacker: MessagePack::Time::Unpacker,
78
54
  )
79
55
 
80
56
  marshal_fallback = {
@@ -94,70 +70,232 @@ module Bootsnap
94
70
  self.supported_options = []
95
71
  params = ::YAML.method(:load).parameters
96
72
  if params.include?([:key, :symbolize_names])
97
- self.supported_options << :symbolize_names
73
+ supported_options << :symbolize_names
98
74
  end
99
75
  if params.include?([:key, :freeze])
100
- if factory.load(factory.dump('yaml'), freeze: true).frozen?
101
- self.supported_options << :freeze
76
+ if factory.load(factory.dump("yaml"), freeze: true).frozen?
77
+ supported_options << :freeze
102
78
  end
103
79
  end
104
- self.supported_options.freeze
80
+ supported_options.freeze
81
+ end
82
+
83
+ def patch
84
+ @implementation::Patch
85
+ end
86
+
87
+ def strict_load(payload)
88
+ ast = ::YAML.parse(payload)
89
+ return ast unless ast
90
+
91
+ strict_visitor.create.visit(ast)
105
92
  end
106
93
 
107
94
  def strict_visitor
108
95
  self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
109
96
  def visit(target)
110
97
  if target.tag
111
- raise Uncompilable, "YAML tags are not supported: #{target.tag}"
98
+ raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
112
99
  end
100
+
113
101
  super
114
102
  end
115
103
  end
116
104
  end
117
105
  end
118
106
 
119
- module Patch
120
- def load_file(path, *args)
121
- return super if args.size > 1
122
- if kwargs = args.first
123
- return super unless kwargs.is_a?(Hash)
124
- return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
107
+ module Psych4
108
+ extend self
109
+
110
+ def input_to_storage(contents, _)
111
+ obj = SafeLoad.input_to_storage(contents, nil)
112
+ if UNCOMPILABLE.equal?(obj)
113
+ obj = UnsafeLoad.input_to_storage(contents, nil)
125
114
  end
115
+ obj
116
+ end
126
117
 
127
- begin
128
- ::Bootsnap::CompileCache::Native.fetch(
129
- Bootsnap::CompileCache::YAML.cache_dir,
130
- File.realpath(path),
131
- ::Bootsnap::CompileCache::YAML,
132
- kwargs,
133
- )
134
- rescue Errno::EACCES
135
- ::Bootsnap::CompileCache.permission_error(path)
118
+ module UnsafeLoad
119
+ extend self
120
+
121
+ def input_to_storage(contents, _)
122
+ obj = CompileCache::YAML.strict_load(contents)
123
+ packer = CompileCache::YAML.msgpack_factory.packer
124
+ packer.pack(false) # not safe loaded
125
+ packer.pack(obj)
126
+ packer.to_s
127
+ rescue NoMethodError, RangeError, UnsupportedTags
128
+ UNCOMPILABLE # The object included things that we can't serialize
129
+ end
130
+
131
+ def storage_to_output(data, kwargs)
132
+ if kwargs&.key?(:symbolize_names)
133
+ kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
134
+ end
135
+
136
+ unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
137
+ unpacker.feed(data)
138
+ _safe_loaded = unpacker.unpack
139
+ unpacker.unpack
140
+ end
141
+
142
+ def input_to_output(data, kwargs)
143
+ ::YAML.unsafe_load(data, **(kwargs || {}))
136
144
  end
137
145
  end
138
146
 
139
- ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
147
+ module SafeLoad
148
+ extend self
140
149
 
141
- def unsafe_load_file(path, *args)
142
- return super if args.size > 1
143
- if kwargs = args.first
144
- return super unless kwargs.is_a?(Hash)
145
- return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
150
+ def input_to_storage(contents, _)
151
+ obj = ::YAML.load(contents)
152
+ packer = CompileCache::YAML.msgpack_factory.packer
153
+ packer.pack(true) # safe loaded
154
+ packer.pack(obj)
155
+ packer.to_s
156
+ rescue NoMethodError, RangeError, Psych::DisallowedClass, Psych::BadAlias
157
+ UNCOMPILABLE # The object included things that we can't serialize
146
158
  end
147
159
 
148
- begin
149
- ::Bootsnap::CompileCache::Native.fetch(
150
- Bootsnap::CompileCache::YAML.cache_dir,
151
- File.realpath(path),
152
- ::Bootsnap::CompileCache::YAML,
153
- kwargs,
154
- )
155
- rescue Errno::EACCES
156
- ::Bootsnap::CompileCache.permission_error(path)
160
+ def storage_to_output(data, kwargs)
161
+ if kwargs&.key?(:symbolize_names)
162
+ kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
163
+ end
164
+
165
+ unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
166
+ unpacker.feed(data)
167
+ safe_loaded = unpacker.unpack
168
+ if safe_loaded
169
+ unpacker.unpack
170
+ else
171
+ UNCOMPILABLE
172
+ end
173
+ end
174
+
175
+ def input_to_output(data, kwargs)
176
+ ::YAML.load(data, **(kwargs || {}))
177
+ end
178
+ end
179
+
180
+ module Patch
181
+ def load_file(path, *args)
182
+ return super if args.size > 1
183
+
184
+ if (kwargs = args.first)
185
+ return super unless kwargs.is_a?(Hash)
186
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
187
+ end
188
+
189
+ begin
190
+ ::Bootsnap::CompileCache::Native.fetch(
191
+ Bootsnap::CompileCache::YAML.cache_dir,
192
+ File.realpath(path),
193
+ ::Bootsnap::CompileCache::YAML::Psych4::SafeLoad,
194
+ kwargs,
195
+ )
196
+ rescue Errno::EACCES
197
+ ::Bootsnap::CompileCache.permission_error(path)
198
+ end
199
+ end
200
+
201
+ ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
202
+
203
+ def unsafe_load_file(path, *args)
204
+ return super if args.size > 1
205
+
206
+ if (kwargs = args.first)
207
+ return super unless kwargs.is_a?(Hash)
208
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
209
+ end
210
+
211
+ begin
212
+ ::Bootsnap::CompileCache::Native.fetch(
213
+ Bootsnap::CompileCache::YAML.cache_dir,
214
+ File.realpath(path),
215
+ ::Bootsnap::CompileCache::YAML::Psych4::UnsafeLoad,
216
+ kwargs,
217
+ )
218
+ rescue Errno::EACCES
219
+ ::Bootsnap::CompileCache.permission_error(path)
220
+ end
221
+ end
222
+
223
+ ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
224
+ end
225
+ end
226
+
227
+ module Psych3
228
+ extend self
229
+
230
+ def input_to_storage(contents, _)
231
+ obj = CompileCache::YAML.strict_load(contents)
232
+ packer = CompileCache::YAML.msgpack_factory.packer
233
+ packer.pack(false) # not safe loaded
234
+ packer.pack(obj)
235
+ packer.to_s
236
+ rescue NoMethodError, RangeError, UnsupportedTags
237
+ UNCOMPILABLE # The object included things that we can't serialize
238
+ end
239
+
240
+ def storage_to_output(data, kwargs)
241
+ if kwargs&.key?(:symbolize_names)
242
+ kwargs[:symbolize_keys] = kwargs.delete(:symbolize_names)
157
243
  end
244
+ unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
245
+ unpacker.feed(data)
246
+ _safe_loaded = unpacker.unpack
247
+ unpacker.unpack
158
248
  end
159
249
 
160
- ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
250
+ def input_to_output(data, kwargs)
251
+ ::YAML.load(data, **(kwargs || {}))
252
+ end
253
+
254
+ module Patch
255
+ def load_file(path, *args)
256
+ return super if args.size > 1
257
+
258
+ if (kwargs = args.first)
259
+ return super unless kwargs.is_a?(Hash)
260
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
261
+ end
262
+
263
+ begin
264
+ ::Bootsnap::CompileCache::Native.fetch(
265
+ Bootsnap::CompileCache::YAML.cache_dir,
266
+ File.realpath(path),
267
+ ::Bootsnap::CompileCache::YAML::Psych3,
268
+ kwargs,
269
+ )
270
+ rescue Errno::EACCES
271
+ ::Bootsnap::CompileCache.permission_error(path)
272
+ end
273
+ end
274
+
275
+ ruby2_keywords :load_file if respond_to?(:ruby2_keywords, true)
276
+
277
+ def unsafe_load_file(path, *args)
278
+ return super if args.size > 1
279
+
280
+ if (kwargs = args.first)
281
+ return super unless kwargs.is_a?(Hash)
282
+ return super unless (kwargs.keys - ::Bootsnap::CompileCache::YAML.supported_options).empty?
283
+ end
284
+
285
+ begin
286
+ ::Bootsnap::CompileCache::Native.fetch(
287
+ Bootsnap::CompileCache::YAML.cache_dir,
288
+ File.realpath(path),
289
+ ::Bootsnap::CompileCache::YAML::Psych3,
290
+ kwargs,
291
+ )
292
+ rescue Errno::EACCES
293
+ ::Bootsnap::CompileCache.permission_error(path)
294
+ end
295
+ end
296
+
297
+ ruby2_keywords :unsafe_load_file if respond_to?(:ruby2_keywords, true)
298
+ end
161
299
  end
162
300
  end
163
301
  end
@@ -1,13 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
4
  module CompileCache
4
- Error = Class.new(StandardError)
5
+ UNCOMPILABLE = BasicObject.new
6
+
7
+ Error = Class.new(StandardError)
5
8
  PermissionError = Class.new(Error)
6
9
 
7
10
  def self.setup(cache_dir:, iseq:, yaml:, json:)
8
11
  if iseq
9
12
  if supported?
10
- require_relative('compile_cache/iseq')
13
+ require_relative("compile_cache/iseq")
11
14
  Bootsnap::CompileCache::ISeq.install!(cache_dir)
12
15
  elsif $VERBOSE
13
16
  warn("[bootsnap/setup] bytecode caching is not supported on this implementation of Ruby")
@@ -16,7 +19,7 @@ module Bootsnap
16
19
 
17
20
  if yaml
18
21
  if supported?
19
- require_relative('compile_cache/yaml')
22
+ require_relative("compile_cache/yaml")
20
23
  Bootsnap::CompileCache::YAML.install!(cache_dir)
21
24
  elsif $VERBOSE
22
25
  warn("[bootsnap/setup] YAML parsing caching is not supported on this implementation of Ruby")
@@ -25,7 +28,7 @@ module Bootsnap
25
28
 
26
29
  if json
27
30
  if supported?
28
- require_relative('compile_cache/json')
31
+ require_relative("compile_cache/json")
29
32
  Bootsnap::CompileCache::JSON.install!(cache_dir)
30
33
  elsif $VERBOSE
31
34
  warn("[bootsnap/setup] JSON parsing caching is not supported on this implementation of Ruby")
@@ -44,9 +47,9 @@ module Bootsnap
44
47
 
45
48
  def self.supported?
46
49
  # only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), Windows (RubyInstaller2) and >= 2.3.0
47
- RUBY_ENGINE == 'ruby' &&
48
- RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
49
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
50
+ RUBY_ENGINE == "ruby" &&
51
+ RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/ &&
52
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
50
53
  end
51
54
  end
52
55
  end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
4
  module ExplicitRequire
4
- ARCHDIR = RbConfig::CONFIG['archdir']
5
- RUBYLIBDIR = RbConfig::CONFIG['rubylibdir']
6
- DLEXT = RbConfig::CONFIG['DLEXT']
5
+ ARCHDIR = RbConfig::CONFIG["archdir"]
6
+ RUBYLIBDIR = RbConfig::CONFIG["rubylibdir"]
7
+ DLEXT = RbConfig::CONFIG["DLEXT"]
7
8
 
8
9
  def self.from_self(feature)
9
10
  require_relative("../#{feature}")
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative('../explicit_require')
3
+ require_relative("../explicit_require")
4
4
 
5
5
  module Bootsnap
6
6
  module LoadPathCache
@@ -28,15 +28,16 @@ module Bootsnap
28
28
  BUILTIN_FEATURES = $LOADED_FEATURES.each_with_object({}) do |feat, features|
29
29
  # Builtin features are of the form 'enumerator.so'.
30
30
  # All others include paths.
31
- next unless feat.size < 20 && !feat.include?('/')
31
+ next unless feat.size < 20 && !feat.include?("/")
32
32
 
33
- base = File.basename(feat, '.*') # enumerator.so -> enumerator
33
+ base = File.basename(feat, ".*") # enumerator.so -> enumerator
34
34
  ext = File.extname(feat) # .so
35
35
 
36
36
  features[feat] = nil # enumerator.so
37
37
  features[base] = nil # enumerator
38
38
 
39
39
  next unless [DOT_SO, *DL_EXTENSIONS].include?(ext)
40
+
40
41
  DL_EXTENSIONS.each do |dl_ext|
41
42
  features["#{base}#{dl_ext}"] = nil # enumerator.bundle
42
43
  end
@@ -50,7 +51,7 @@ module Bootsnap
50
51
 
51
52
  return feature if Bootsnap.absolute_path?(feature)
52
53
 
53
- if feature.start_with?('./', '../')
54
+ if feature.start_with?("./", "../")
54
55
  return try_extensions ? expand_path(feature) : File.expand_path(feature).freeze
55
56
  end
56
57
 
@@ -64,7 +65,7 @@ module Bootsnap
64
65
  # returns false as if it were already loaded; however, there is no
65
66
  # file to find on disk. We've pre-built a list of these, and we
66
67
  # return false if any of them is loaded.
67
- raise(LoadPathCache::ReturnFalse, '', []) if BUILTIN_FEATURES.key?(feature)
68
+ raise(LoadPathCache::ReturnFalse, "", []) if BUILTIN_FEATURES.key?(feature)
68
69
 
69
70
  # The feature wasn't found on our preliminary search through the index.
70
71
  # We resolve this differently depending on what the extension was.
@@ -73,13 +74,14 @@ module Bootsnap
73
74
  # native dynamic extension, e.g. .bundle or .so), we know it was a
74
75
  # failure and there's nothing more we can do to find the file.
75
76
  # no extension, .rb, (.bundle or .so)
76
- when '', *CACHED_EXTENSIONS
77
+ when "", *CACHED_EXTENSIONS
77
78
  nil
78
79
  # Ruby allows specifying native extensions as '.so' even when DLEXT
79
80
  # is '.bundle'. This is where we handle that case.
80
81
  when DOT_SO
81
82
  x = search_index(feature[0..-4] + DLEXT)
82
83
  return x if x
84
+
83
85
  if DLEXT2
84
86
  x = search_index(feature[0..-4] + DLEXT2)
85
87
  return x if x
@@ -87,7 +89,7 @@ module Bootsnap
87
89
  else
88
90
  # other, unknown extension. For example, `.rake`. Since we haven't
89
91
  # cached these, we legitimately need to run the load path search.
90
- raise(LoadPathCache::FallbackScan, '', [])
92
+ raise(LoadPathCache::FallbackScan, "", [])
91
93
  end
92
94
  end
93
95
 
@@ -95,16 +97,18 @@ module Bootsnap
95
97
  # cases where the file doesn't appear to be on the load path. We should
96
98
  # be able to detect newly-created files without rebooting the
97
99
  # application.
98
- raise(LoadPathCache::FallbackScan, '', []) if @development_mode
100
+ raise(LoadPathCache::FallbackScan, "", []) if @development_mode
99
101
  end
100
102
 
101
103
  def unshift_paths(sender, *paths)
102
104
  return unless sender == @path_obj
105
+
103
106
  @mutex.synchronize { unshift_paths_locked(*paths) }
104
107
  end
105
108
 
106
109
  def push_paths(sender, *paths)
107
110
  return unless sender == @path_obj
111
+
108
112
  @mutex.synchronize { push_paths_locked(*paths) }
109
113
  end
110
114
 
@@ -137,6 +141,7 @@ module Bootsnap
137
141
  p = Path.new(path)
138
142
  @has_relative_paths = true if p.relative?
139
143
  next if p.non_directory?
144
+
140
145
  expanded_path = p.expanded_path
141
146
  entries, dirs = p.entries_and_dirs(@store)
142
147
  # push -> low precedence -> set only if unset
@@ -151,6 +156,7 @@ module Bootsnap
151
156
  paths.map(&:to_s).reverse_each do |path|
152
157
  p = Path.new(path)
153
158
  next if p.non_directory?
159
+
154
160
  expanded_path = p.expanded_path
155
161
  entries, dirs = p.entries_and_dirs(@store)
156
162
  # unshift -> high precedence -> unconditional set
@@ -173,56 +179,62 @@ module Bootsnap
173
179
  end
174
180
 
175
181
  if DLEXT2
176
- def search_index(f, try_extensions: true)
182
+ def search_index(feature, try_extensions: true)
177
183
  if try_extensions
178
- try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
184
+ try_index(feature + DOT_RB) ||
185
+ try_index(feature + DLEXT) ||
186
+ try_index(feature + DLEXT2) ||
187
+ try_index(feature)
179
188
  else
180
- try_index(f)
189
+ try_index(feature)
181
190
  end
182
191
  end
183
192
 
184
- def maybe_append_extension(f)
185
- try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
193
+ def maybe_append_extension(feature)
194
+ try_ext(feature + DOT_RB) ||
195
+ try_ext(feature + DLEXT) ||
196
+ try_ext(feature + DLEXT2) ||
197
+ feature
186
198
  end
187
199
  else
188
- def search_index(f, try_extensions: true)
200
+ def search_index(feature, try_extensions: true)
189
201
  if try_extensions
190
- try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
202
+ try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
191
203
  else
192
- try_index(f)
204
+ try_index(feature)
193
205
  end
194
206
  end
195
207
 
196
- def maybe_append_extension(f)
197
- try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
208
+ def maybe_append_extension(feature)
209
+ try_ext(feature + DOT_RB) || try_ext(feature + DLEXT) || feature
198
210
  end
199
211
  end
200
212
 
201
213
  s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
202
214
  if s.respond_to?(:-@)
203
- if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= '2.7'
204
- def try_index(f)
205
- if (p = @index[f])
206
- -(File.join(p, f).freeze)
215
+ if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= "2.7"
216
+ def try_index(feature)
217
+ if (path = @index[feature])
218
+ -File.join(path, feature).freeze
207
219
  end
208
220
  end
209
221
  else
210
- def try_index(f)
211
- if (p = @index[f])
212
- -File.join(p, f).untaint
222
+ def try_index(feature)
223
+ if (path = @index[feature])
224
+ -File.join(path, feature).untaint
213
225
  end
214
226
  end
215
227
  end
216
228
  else
217
- def try_index(f)
218
- if (p = @index[f])
219
- File.join(p, f)
229
+ def try_index(feature)
230
+ if (path = @index[feature])
231
+ File.join(path, feature)
220
232
  end
221
233
  end
222
234
  end
223
235
 
224
- def try_ext(f)
225
- f if File.exist?(f)
236
+ def try_ext(feature)
237
+ feature if File.exist?(feature)
226
238
  end
227
239
  end
228
240
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
4
  module LoadPathCache
4
5
  module ChangeObserver
@@ -57,6 +58,7 @@ module Bootsnap
57
58
 
58
59
  def self.register(observer, arr)
59
60
  return if arr.frozen? # can't register observer, but no need to.
61
+
60
62
  arr.instance_variable_set(:@lpc_observer, observer)
61
63
  arr.extend(ArrayMixin)
62
64
  end