bootsnap 1.12.0 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/ext/bootsnap/extconf.rb +1 -1
- data/lib/bootsnap/cli.rb +10 -10
- data/lib/bootsnap/compile_cache/iseq.rb +3 -3
- data/lib/bootsnap/compile_cache/json.rb +9 -4
- data/lib/bootsnap/compile_cache/yaml.rb +16 -17
- data/lib/bootsnap/load_path_cache/cache.rb +11 -20
- data/lib/bootsnap/load_path_cache/change_observer.rb +13 -2
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +2 -9
- data/lib/bootsnap/load_path_cache/path.rb +13 -15
- data/lib/bootsnap/load_path_cache/store.rb +6 -10
- data/lib/bootsnap/load_path_cache.rb +15 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +10 -6
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40e594cf459a80b9e118cf8cdb6d9f306228fe682e3c2af3a1c2b70432f47890
|
4
|
+
data.tar.gz: c120e3c24944e9c0568615a0b6ec23d422e949755339c8ffa118f0265e85755b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45c52711bd2fbf273f93d27ea4a8ee71d04c81b7444f0f49aa9b672e131544103b74d3326afe5228122dc52844b681c1e18bbb59fe429b2a2216e182e90ac5e7
|
7
|
+
data.tar.gz: ad78b4da53ffc8d6653f74ed777bae1987704de2a76062bbebc2b1d3977baeca900b36066994957adf3cefbda446b4393dd18e41637d1a39f9adac42878b6732
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.13.0
|
4
|
+
|
5
|
+
* Stop decorating `Kernel.load`. This used to be very useful in development because the Rails "classic" autoloader
|
6
|
+
was using `Kernel.load` in dev and `Kernel.require` in production. But Zeitwerk is now the default, and it doesn't
|
7
|
+
use `Kernel.load` at all.
|
8
|
+
|
9
|
+
People still using the classic autoloader might want to stick to `bootsnap 1.12`.
|
10
|
+
|
11
|
+
* Add `Bootsnap.unload_cache!`. Applications can call it at the end of their boot sequence when they know
|
12
|
+
no more code will be loaded to reclaim a bit of memory.
|
13
|
+
|
3
14
|
# 1.12.0
|
4
15
|
|
5
16
|
* `bootsnap precompile` CLI will now also precompile `Rakefile` and `.rake` files.
|
data/ext/bootsnap/extconf.rb
CHANGED
data/lib/bootsnap/cli.rb
CHANGED
@@ -66,7 +66,7 @@ module Bootsnap
|
|
66
66
|
|
67
67
|
# Gems that include JSON or YAML files usually don't put them in `lib/`.
|
68
68
|
# So we look at the gem root.
|
69
|
-
gem_pattern = %r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems
|
69
|
+
gem_pattern = %r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems/[^/]+}
|
70
70
|
gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] }.compact.uniq
|
71
71
|
precompile_yaml_files(gem_paths, exclude: gem_exclude)
|
72
72
|
precompile_json_files(gem_paths, exclude: gem_exclude)
|
@@ -138,8 +138,8 @@ module Bootsnap
|
|
138
138
|
|
139
139
|
def precompile_yaml(*yaml_files)
|
140
140
|
Array(yaml_files).each do |yaml_file|
|
141
|
-
if CompileCache::YAML.precompile(yaml_file)
|
142
|
-
|
141
|
+
if CompileCache::YAML.precompile(yaml_file) && verbose
|
142
|
+
$stderr.puts(yaml_file)
|
143
143
|
end
|
144
144
|
end
|
145
145
|
end
|
@@ -161,8 +161,8 @@ module Bootsnap
|
|
161
161
|
|
162
162
|
def precompile_json(*json_files)
|
163
163
|
Array(json_files).each do |json_file|
|
164
|
-
if CompileCache::JSON.precompile(json_file)
|
165
|
-
|
164
|
+
if CompileCache::JSON.precompile(json_file) && verbose
|
165
|
+
$stderr.puts(json_file)
|
166
166
|
end
|
167
167
|
end
|
168
168
|
end
|
@@ -183,8 +183,8 @@ module Bootsnap
|
|
183
183
|
|
184
184
|
def precompile_ruby(*ruby_files)
|
185
185
|
Array(ruby_files).each do |ruby_file|
|
186
|
-
if CompileCache::ISeq.precompile(ruby_file)
|
187
|
-
|
186
|
+
if CompileCache::ISeq.precompile(ruby_file) && verbose
|
187
|
+
$stderr.puts(ruby_file)
|
188
188
|
end
|
189
189
|
end
|
190
190
|
end
|
@@ -203,9 +203,9 @@ module Bootsnap
|
|
203
203
|
end
|
204
204
|
|
205
205
|
def invalid_usage!(message)
|
206
|
-
|
207
|
-
|
208
|
-
|
206
|
+
$stderr.puts message
|
207
|
+
$stderr.puts
|
208
|
+
$stderr.puts parser
|
209
209
|
1
|
210
210
|
end
|
211
211
|
|
@@ -34,14 +34,14 @@ module Bootsnap
|
|
34
34
|
begin
|
35
35
|
iseq.to_binary
|
36
36
|
rescue TypeError
|
37
|
-
|
37
|
+
UNCOMPILABLE # ruby bug #18250
|
38
38
|
end
|
39
39
|
end
|
40
40
|
else
|
41
41
|
def self.input_to_storage(_, path)
|
42
42
|
RubyVM::InstructionSequence.compile_file(path).to_binary
|
43
43
|
rescue SyntaxError
|
44
|
-
|
44
|
+
UNCOMPILABLE # syntax error
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -49,7 +49,7 @@ module Bootsnap
|
|
49
49
|
RubyVM::InstructionSequence.load_from_binary(binary)
|
50
50
|
rescue RuntimeError => error
|
51
51
|
if error.message == "broken binary format"
|
52
|
-
|
52
|
+
$stderr.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
53
53
|
nil
|
54
54
|
else
|
55
55
|
raise
|
@@ -51,13 +51,18 @@ module Bootsnap
|
|
51
51
|
|
52
52
|
self.msgpack_factory = MessagePack::Factory.new
|
53
53
|
self.supported_options = [:symbolize_names]
|
54
|
-
if
|
55
|
-
|
56
|
-
self.supported_options = [:freeze]
|
57
|
-
end
|
54
|
+
if supports_freeze?
|
55
|
+
self.supported_options = [:freeze]
|
58
56
|
end
|
59
57
|
supported_options.freeze
|
60
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def supports_freeze?
|
63
|
+
::JSON.parse('["foo"]', freeze: true).first.frozen? &&
|
64
|
+
MessagePack.load(MessagePack.dump("foo"), freeze: true).frozen?
|
65
|
+
end
|
61
66
|
end
|
62
67
|
|
63
68
|
module Patch
|
@@ -64,6 +64,19 @@ module Bootsnap
|
|
64
64
|
@implementation::Patch.send(:remove_method, :unsafe_load_file)
|
65
65
|
end
|
66
66
|
|
67
|
+
unless const_defined?(:NoTagsVisitor)
|
68
|
+
visitor = Class.new(Psych::Visitors::ToRuby) do
|
69
|
+
def visit(target)
|
70
|
+
if target.tag
|
71
|
+
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
72
|
+
end
|
73
|
+
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
const_set(:NoTagsVisitor, visitor)
|
78
|
+
end
|
79
|
+
|
67
80
|
# MessagePack serializes symbols as strings by default.
|
68
81
|
# We want them to roundtrip cleanly, so we use a custom factory.
|
69
82
|
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
@@ -102,10 +115,8 @@ module Bootsnap
|
|
102
115
|
if params.include?([:key, :symbolize_names])
|
103
116
|
supported_options << :symbolize_names
|
104
117
|
end
|
105
|
-
if params.include?([:key, :freeze])
|
106
|
-
|
107
|
-
supported_options << :freeze
|
108
|
-
end
|
118
|
+
if params.include?([:key, :freeze]) && factory.load(factory.dump("yaml"), freeze: true).frozen?
|
119
|
+
supported_options << :freeze
|
109
120
|
end
|
110
121
|
supported_options.freeze
|
111
122
|
end
|
@@ -118,19 +129,7 @@ module Bootsnap
|
|
118
129
|
ast = ::YAML.parse(payload)
|
119
130
|
return ast unless ast
|
120
131
|
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
def strict_visitor
|
125
|
-
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
126
|
-
def visit(target)
|
127
|
-
if target.tag
|
128
|
-
raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
|
129
|
-
end
|
130
|
-
|
131
|
-
super
|
132
|
-
end
|
133
|
-
end
|
132
|
+
NoTagsVisitor.create.visit(ast)
|
134
133
|
end
|
135
134
|
end
|
136
135
|
|
@@ -45,20 +45,19 @@ module Bootsnap
|
|
45
45
|
|
46
46
|
# Try to resolve this feature to an absolute path without traversing the
|
47
47
|
# loadpath.
|
48
|
-
def find(feature
|
48
|
+
def find(feature)
|
49
49
|
reinitialize if (@has_relative_paths && dir_changed?) || stale?
|
50
50
|
feature = feature.to_s.freeze
|
51
51
|
|
52
52
|
return feature if Bootsnap.absolute_path?(feature)
|
53
53
|
|
54
54
|
if feature.start_with?("./", "../")
|
55
|
-
return
|
55
|
+
return expand_path(feature)
|
56
56
|
end
|
57
57
|
|
58
58
|
@mutex.synchronize do
|
59
|
-
x = search_index(feature
|
59
|
+
x = search_index(feature)
|
60
60
|
return x if x
|
61
|
-
return unless try_extensions
|
62
61
|
|
63
62
|
# Ruby has some built-in features that require lies about.
|
64
63
|
# For example, 'enumerator' is built in. If you require it, ruby
|
@@ -115,7 +114,7 @@ module Bootsnap
|
|
115
114
|
def reinitialize(path_obj = @path_obj)
|
116
115
|
@mutex.synchronize do
|
117
116
|
@path_obj = path_obj
|
118
|
-
ChangeObserver.register(
|
117
|
+
ChangeObserver.register(@path_obj, self)
|
119
118
|
@index = {}
|
120
119
|
@dirs = {}
|
121
120
|
@generated_at = now
|
@@ -183,15 +182,11 @@ module Bootsnap
|
|
183
182
|
end
|
184
183
|
|
185
184
|
if DLEXT2
|
186
|
-
def search_index(feature
|
187
|
-
|
188
|
-
try_index(feature +
|
189
|
-
|
190
|
-
try_index(feature + DLEXT2) ||
|
191
|
-
try_index(feature)
|
192
|
-
else
|
185
|
+
def search_index(feature)
|
186
|
+
try_index(feature + DOT_RB) ||
|
187
|
+
try_index(feature + DLEXT) ||
|
188
|
+
try_index(feature + DLEXT2) ||
|
193
189
|
try_index(feature)
|
194
|
-
end
|
195
190
|
end
|
196
191
|
|
197
192
|
def maybe_append_extension(feature)
|
@@ -201,12 +196,8 @@ module Bootsnap
|
|
201
196
|
feature
|
202
197
|
end
|
203
198
|
else
|
204
|
-
def search_index(feature
|
205
|
-
|
206
|
-
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
207
|
-
else
|
208
|
-
try_index(feature)
|
209
|
-
end
|
199
|
+
def search_index(feature)
|
200
|
+
try_index(feature + DOT_RB) || try_index(feature + DLEXT) || try_index(feature)
|
210
201
|
end
|
211
202
|
|
212
203
|
def maybe_append_extension(feature)
|
@@ -216,7 +207,7 @@ module Bootsnap
|
|
216
207
|
|
217
208
|
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
|
218
209
|
if s.respond_to?(:-@)
|
219
|
-
if (-s).equal?(s) && (-s.dup).equal?(s) || RUBY_VERSION >= "2.7"
|
210
|
+
if ((-s).equal?(s) && (-s.dup).equal?(s)) || RUBY_VERSION >= "2.7"
|
220
211
|
def try_index(feature)
|
221
212
|
if (path = @index[feature])
|
222
213
|
-File.join(path, feature).freeze
|
@@ -56,11 +56,22 @@ module Bootsnap
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
def self.register(
|
59
|
+
def self.register(arr, observer)
|
60
60
|
return if arr.frozen? # can't register observer, but no need to.
|
61
61
|
|
62
62
|
arr.instance_variable_set(:@lpc_observer, observer)
|
63
|
-
|
63
|
+
ArrayMixin.instance_methods.each do |method_name|
|
64
|
+
arr.singleton_class.send(:define_method, method_name, ArrayMixin.instance_method(method_name))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.unregister(arr)
|
69
|
+
return unless arr.instance_variable_get(:@lpc_observer)
|
70
|
+
|
71
|
+
ArrayMixin.instance_methods.each do |method_name|
|
72
|
+
arr.singleton_class.send(:remove_method, method_name)
|
73
|
+
end
|
74
|
+
arr.instance_variable_set(:@lpc_observer, nil)
|
64
75
|
end
|
65
76
|
end
|
66
77
|
end
|
@@ -6,6 +6,8 @@ module Kernel
|
|
6
6
|
alias_method(:require_without_bootsnap, :require)
|
7
7
|
|
8
8
|
def require(path)
|
9
|
+
return require_without_bootsnap(path) unless Bootsnap::LoadPathCache.enabled?
|
10
|
+
|
9
11
|
string_path = Bootsnap.rb_get_path(path)
|
10
12
|
return false if Bootsnap::LoadPathCache.loaded_features_index.key?(string_path)
|
11
13
|
|
@@ -32,13 +34,4 @@ module Kernel
|
|
32
34
|
return ret
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
36
|
-
alias_method(:load_without_bootsnap, :load)
|
37
|
-
def load(path, wrap = false)
|
38
|
-
if (resolved = Bootsnap::LoadPathCache.load_path_cache.find(Bootsnap.rb_get_path(path), try_extensions: false))
|
39
|
-
load_without_bootsnap(resolved, wrap)
|
40
|
-
else
|
41
|
-
load_without_bootsnap(path, wrap)
|
42
|
-
end
|
43
|
-
end
|
44
37
|
end
|
@@ -35,18 +35,18 @@ module Bootsnap
|
|
35
35
|
return self
|
36
36
|
end
|
37
37
|
|
38
|
-
if realpath
|
39
|
-
Path.new(realpath, real: true)
|
40
|
-
else
|
38
|
+
if realpath == path
|
41
39
|
@real = true
|
42
40
|
self
|
41
|
+
else
|
42
|
+
Path.new(realpath, real: true)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
# True if the path exists, but represents a non-directory object
|
47
47
|
def non_directory?
|
48
48
|
!File.stat(path).directory?
|
49
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
49
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
50
50
|
false
|
51
51
|
end
|
52
52
|
|
@@ -101,7 +101,7 @@ module Bootsnap
|
|
101
101
|
["", *dirs].each do |dir|
|
102
102
|
curr = begin
|
103
103
|
File.mtime("#{path}/#{dir}").to_i
|
104
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
104
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
105
105
|
-1
|
106
106
|
end
|
107
107
|
max = curr if curr > max
|
@@ -121,16 +121,14 @@ module Bootsnap
|
|
121
121
|
RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
|
122
122
|
|
123
123
|
def stability
|
124
|
-
@stability ||=
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
VOLATILE
|
133
|
-
end
|
124
|
+
@stability ||= if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
|
125
|
+
STABLE
|
126
|
+
elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
|
127
|
+
STABLE
|
128
|
+
elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
|
129
|
+
STABLE
|
130
|
+
else
|
131
|
+
VOLATILE
|
134
132
|
end
|
135
133
|
end
|
136
134
|
end
|
@@ -49,11 +49,9 @@ module Bootsnap
|
|
49
49
|
raise(NestedTransactionError) if @txn_mutex.owned?
|
50
50
|
|
51
51
|
@txn_mutex.synchronize do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
commit_transaction
|
56
|
-
end
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
commit_transaction
|
57
55
|
end
|
58
56
|
end
|
59
57
|
|
@@ -121,11 +119,9 @@ module Bootsnap
|
|
121
119
|
path = File.dirname(path)
|
122
120
|
end
|
123
121
|
stack.reverse_each do |dir|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
raise unless File.directory?(dir)
|
128
|
-
end
|
122
|
+
Dir.mkdir(dir)
|
123
|
+
rescue SystemCallError
|
124
|
+
raise unless File.directory?(dir)
|
129
125
|
end
|
130
126
|
end
|
131
127
|
end
|
@@ -21,8 +21,12 @@ module Bootsnap
|
|
21
21
|
|
22
22
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
23
23
|
|
24
|
+
@enabled = false
|
25
|
+
|
24
26
|
class << self
|
25
|
-
attr_reader(:load_path_cache, :loaded_features_index)
|
27
|
+
attr_reader(:load_path_cache, :loaded_features_index, :enabled)
|
28
|
+
alias_method :enabled?, :enabled
|
29
|
+
remove_method(:enabled)
|
26
30
|
|
27
31
|
def setup(cache_path:, development_mode:)
|
28
32
|
unless supported?
|
@@ -35,10 +39,20 @@ module Bootsnap
|
|
35
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
36
40
|
|
37
41
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
42
|
+
@enabled = true
|
38
43
|
require_relative("load_path_cache/core_ext/kernel_require")
|
39
44
|
require_relative("load_path_cache/core_ext/loaded_features")
|
40
45
|
end
|
41
46
|
|
47
|
+
def unload!
|
48
|
+
@enabled = false
|
49
|
+
@loaded_features_index = nil
|
50
|
+
@realpath_cache = nil
|
51
|
+
@load_path_cache = nil
|
52
|
+
ChangeObserver.unregister($LOAD_PATH)
|
53
|
+
::Kernel.alias_method(:require_relative, :require_relative_without_bootsnap)
|
54
|
+
end
|
55
|
+
|
42
56
|
def supported?
|
43
57
|
RUBY_ENGINE == "ruby" &&
|
44
58
|
RUBY_PLATFORM =~ /darwin|linux|bsd|mswin|mingw|cygwin/
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -47,35 +47,39 @@ module Bootsnap
|
|
47
47
|
)
|
48
48
|
unless autoload_paths_cache.nil?
|
49
49
|
warn "[DEPRECATED] Bootsnap's `autoload_paths_cache:` option is deprecated and will be removed. " \
|
50
|
-
|
51
|
-
|
50
|
+
"If you use Zeitwerk this option is useless, and if you are still using the classic autoloader " \
|
51
|
+
"upgrading is recommended."
|
52
52
|
end
|
53
53
|
|
54
54
|
unless disable_trace.nil?
|
55
55
|
warn "[DEPRECATED] Bootsnap's `disable_trace:` option is deprecated and will be removed. " \
|
56
|
-
|
56
|
+
"If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
|
57
57
|
end
|
58
58
|
|
59
59
|
if compile_cache_iseq && !iseq_cache_supported?
|
60
60
|
warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
|
61
|
-
|
61
|
+
"to turn `compile_cache_iseq` off on Ruby 2.5"
|
62
62
|
end
|
63
63
|
|
64
64
|
if load_path_cache
|
65
65
|
Bootsnap::LoadPathCache.setup(
|
66
|
-
cache_path: cache_dir
|
66
|
+
cache_path: "#{cache_dir}/bootsnap/load-path-cache",
|
67
67
|
development_mode: development_mode,
|
68
68
|
)
|
69
69
|
end
|
70
70
|
|
71
71
|
Bootsnap::CompileCache.setup(
|
72
|
-
cache_dir: cache_dir
|
72
|
+
cache_dir: "#{cache_dir}/bootsnap/compile-cache",
|
73
73
|
iseq: compile_cache_iseq,
|
74
74
|
yaml: compile_cache_yaml,
|
75
75
|
json: compile_cache_json,
|
76
76
|
)
|
77
77
|
end
|
78
78
|
|
79
|
+
def self.unload_cache!
|
80
|
+
LoadPathCache.unload!
|
81
|
+
end
|
82
|
+
|
79
83
|
def iseq_cache_supported?
|
80
84
|
return @iseq_cache_supported if defined? @iseq_cache_supported
|
81
85
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -76,14 +76,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
76
|
requirements:
|
77
77
|
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: 2.
|
79
|
+
version: 2.5.0
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
86
|
+
rubygems_version: 3.3.3
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
89
|
summary: Boot large ruby/rails apps faster
|