rack-unreloader 1.8.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +14 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +38 -13
- data/lib/rack/unreloader/autoload_reloader.rb +89 -0
- data/lib/rack/unreloader/reloader.rb +8 -62
- data/lib/rack/unreloader.rb +93 -24
- metadata +8 -11
- data/Rakefile +0 -45
- data/spec/spec_helper.rb +0 -87
- data/spec/strip_paths_spec.rb +0 -858
- data/spec/unreloader_spec.rb +0 -515
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01a3ddc58ad8308cd61dd10991e7478f546bd7d1bc2fc4bb88203b4a37d7b335
|
4
|
+
data.tar.gz: ceff468f0b2755347859e3d2a408087379a056975e00c73fe35adc5854c3cbc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71c0dc1e1ebfcad459d8bf6d1533200ad071f857fe2b53fb7f26af1e079169eca3835b2b1eee4a39d572244bf3208bd51718120f7e89f4dcd5b646cbed6195ca
|
7
|
+
data.tar.gz: d9e9ab98a9b36a44d0d819f0142a1c9c49a21598a390da18c7cee48199cd365a0acac7c4fd95955e49b3f18a7ef8e0fe75bfa138312e3b2d16f57ebc7574731f
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
= 2.1.0 (2023-01-18)
|
2
|
+
|
3
|
+
* Add reload? and autoload? methods for determining what mode the unreloader is operating in (jeremyevans)
|
4
|
+
|
5
|
+
* Support :autoload option and autoload method for autoloading files and directories (jeremyevans)
|
6
|
+
|
7
|
+
= 2.0.0 (2022-06-23)
|
8
|
+
|
9
|
+
* Fix TypeError being raised when requiring a file results in an error (jeremyevans)
|
10
|
+
|
11
|
+
* Drop Unreloader#strip_path_prefix (jeremyevans)
|
12
|
+
|
13
|
+
* Drop Ruby 1.8 support (jeremyevans)
|
14
|
+
|
1
15
|
= 1.8.0 (2021-10-15)
|
2
16
|
|
3
17
|
* Avoid warnings in verbose warning mode on Ruby 3+ (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -195,7 +195,7 @@ class.
|
|
195
195
|
|
196
196
|
== Requiring
|
197
197
|
|
198
|
-
Rack::Unreloader#require is a little different than require in that it takes
|
198
|
+
Rack::Unreloader#require is a little different than Kernel#require in that it takes
|
199
199
|
a file glob, not a normal require path. For that reason, you must specify
|
200
200
|
the extension when requiring the file, and it will only look in the current
|
201
201
|
directory by default:
|
@@ -253,17 +253,44 @@ decide that instead of specifying the constants, ObjectSpace should be used to
|
|
253
253
|
automatically determine the constants loaded. You can specify this by having the
|
254
254
|
block return the :ObjectSpace symbol.
|
255
255
|
|
256
|
-
|
256
|
+
=== Autoload
|
257
257
|
|
258
|
-
|
259
|
-
|
260
|
-
|
258
|
+
To further speed things up in development mode, or when only running a subset of
|
259
|
+
tests, it can be helpful to autoload files instead of require them, so that if
|
260
|
+
the related constants are not accessed, you don't need to pay the cost of loading
|
261
|
+
the related files. To enable autoloading, pass the +:autoload+ option when
|
262
|
+
creating the reloader:
|
261
263
|
|
262
|
-
Unreloader.
|
263
|
-
Dir.chroot(Dir.pwd)
|
264
|
+
Unreloader = Rack::Unreloader.new(autoload: true){App}
|
264
265
|
|
265
|
-
|
266
|
-
|
266
|
+
Then, you can call +autoload+ instead of +require+:
|
267
|
+
|
268
|
+
Unreloader.autoload('models'){|f| File.basename(f).sub(/\.rb\z/, '').capitalize}
|
269
|
+
|
270
|
+
This will monitor the models directory for files, setting up autoloads for each
|
271
|
+
file. After the file has been loaded, normal reloading will happen for the
|
272
|
+
file. Note that for +autoload+, a block is required because the constant names
|
273
|
+
are needed before loading the file to setup the autoload.
|
274
|
+
|
275
|
+
If the <tt>reload: false</tt> option is given when creating the reloader,
|
276
|
+
autoloads will still be setup by +autoload+, but no reloading will happen. This
|
277
|
+
can be useful when testing subsets of an application. When testing subsets of
|
278
|
+
an application, you don't need reloading, but you can benefit from autoloading,
|
279
|
+
so parts of the application you are not testing are not loaded.
|
280
|
+
|
281
|
+
If you do not pass the +:autoload+ option when creating the reloader, then calls
|
282
|
+
to +autoload+ will implicitly be transformed to calls to +require+. This makes
|
283
|
+
it possible to use the same +autoload+ call in all cases, and handle four
|
284
|
+
separate scenarios:
|
285
|
+
|
286
|
+
1. Autoload then reload: Fast development mode startup, loading the minimum
|
287
|
+
number of files, but reloading if those files are changed
|
288
|
+
2. Autoload without reload: Useful for faster testing of a subset of an
|
289
|
+
application, so the untested subsets is not loaded.
|
290
|
+
3. Require then reload: Slower development mode startup, but have entire
|
291
|
+
application loaded before accepting requests
|
292
|
+
4. Require without reload: Normal production/testing mode with nothing autoloaded
|
293
|
+
or reloaded
|
267
294
|
|
268
295
|
== Usage Outside Rack
|
269
296
|
|
@@ -296,11 +323,9 @@ environment anytime there are any changes) are going to be more robust than
|
|
296
323
|
this approach, but probably slower. Be aware that you are trading robustness
|
297
324
|
for speed when using this library.
|
298
325
|
|
299
|
-
==
|
326
|
+
== Ruby Version Support
|
300
327
|
|
301
|
-
Rack::Unreloader works correctly on Ruby 1.
|
302
|
-
also works on older versions of JRuby if you use a proc to specify the constants
|
303
|
-
to unload.
|
328
|
+
Rack::Unreloader works correctly on Ruby 1.9.2+ and JRuby 9.1+.
|
304
329
|
|
305
330
|
== License
|
306
331
|
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative 'reloader'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Unreloader
|
5
|
+
class AutoloadReloader < Reloader
|
6
|
+
def initialize(opts={})
|
7
|
+
super
|
8
|
+
|
9
|
+
# Files that autoloads have been setup for, but have not yet been loaded.
|
10
|
+
# Hash with realpath keys and values that are arrays with the
|
11
|
+
# a block that will return constant name strings that will autoload the
|
12
|
+
# file, the modified time the file, and the delete hook.
|
13
|
+
@autoload_files = {}
|
14
|
+
|
15
|
+
# Directories where new files will be setup for autoloading.
|
16
|
+
# Uses same format as @monitor_dirs.
|
17
|
+
@autoload_dirs = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def autoload_dependencies(paths, opts={}, &block)
|
21
|
+
delete_hook = opts[:delete_hook]
|
22
|
+
|
23
|
+
Unreloader.expand_paths(paths).each do |file|
|
24
|
+
if File.directory?(file)
|
25
|
+
@autoload_dirs[file] = [nil, [], block, delete_hook]
|
26
|
+
check_autoload_dir(file)
|
27
|
+
else
|
28
|
+
# Comparisons against $LOADED_FEATURES need realpaths
|
29
|
+
@autoload_files[File.realpath(file)] = [block, modified_at(file), delete_hook]
|
30
|
+
Unreloader.autoload_constants(yield(file), file, @logger)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove_autoload(file, strings)
|
36
|
+
strings = Array(strings)
|
37
|
+
log("Removing autoload for #{file}: #{strings.join(" ")}") unless strings.empty?
|
38
|
+
strings.each do |s|
|
39
|
+
obj, mod = Unreloader.split_autoload(s)
|
40
|
+
# Assume that if the autoload string was valid to create the
|
41
|
+
# autoload, it is still valid when removing the autoload.
|
42
|
+
obj.send(:remove_const, mod)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_autoload_dir(dir)
|
47
|
+
subdir_times, files, block, delete_hook = md = @autoload_dirs[dir]
|
48
|
+
return if subdir_times && subdir_times.all?{|subdir, time| File.directory?(subdir) && modified_at(subdir) == time}
|
49
|
+
md[0] = subdir_times(dir)
|
50
|
+
|
51
|
+
cur_files = Unreloader.ruby_files(dir)
|
52
|
+
return if files == cur_files
|
53
|
+
|
54
|
+
removed_files = files - cur_files
|
55
|
+
new_files = cur_files - files
|
56
|
+
|
57
|
+
# Removed files that were never required should have the constant removed
|
58
|
+
# so that accesses to the constant do not attempt to autoload a file that
|
59
|
+
# no longer exists.
|
60
|
+
removed_files.each do |file|
|
61
|
+
remove_autoload(file, block.call(file)) unless @monitor_files[file]
|
62
|
+
end
|
63
|
+
|
64
|
+
# New files not yet loaded should have autoloads added for them.
|
65
|
+
autoload_dependencies(new_files, :delete_hook=>delete_hook, &block) unless new_files.empty?
|
66
|
+
|
67
|
+
files.replace(cur_files)
|
68
|
+
end
|
69
|
+
|
70
|
+
def reload!
|
71
|
+
(@autoload_files.keys & $LOADED_FEATURES).each do |file|
|
72
|
+
# Files setup for autoloads were autoloaded, move metadata to locations
|
73
|
+
# used for required files.
|
74
|
+
log("Autoloaded file required, setting up reloading: #{file}")
|
75
|
+
block, *metadata = @autoload_files.delete(file)
|
76
|
+
@constants_defined[file] = block
|
77
|
+
@monitor_files[file] = metadata
|
78
|
+
@files[file] = {:features=>Set.new, :constants=>Array(block.call(file))}
|
79
|
+
end
|
80
|
+
|
81
|
+
@autoload_dirs.each_key do |dir|
|
82
|
+
check_autoload_dir(dir)
|
83
|
+
end
|
84
|
+
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -5,12 +5,6 @@ module Rack
|
|
5
5
|
class Reloader
|
6
6
|
File = ::File
|
7
7
|
|
8
|
-
# Regexp for valid constant names, to prevent code execution.
|
9
|
-
VALID_CONSTANT_NAME_REGEXP = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.freeze
|
10
|
-
|
11
|
-
# Options hash to force loading of files even if they haven't changed.
|
12
|
-
FORCE = {:force=>true}.freeze
|
13
|
-
|
14
8
|
# Setup the reloader. Supports :logger and :subclasses options, see
|
15
9
|
# Rack::Unloader.new for details.
|
16
10
|
def initialize(opts={})
|
@@ -55,47 +49,6 @@ module Rack
|
|
55
49
|
@skip_reload = []
|
56
50
|
end
|
57
51
|
|
58
|
-
# Strip the given path prefix from the internal data structures.
|
59
|
-
def strip_path_prefix(path_prefix)
|
60
|
-
empty = ''.freeze
|
61
|
-
|
62
|
-
# Strip the path prefix from $LOADED_FEATURES, otherwise the reloading won't work.
|
63
|
-
# Hopefully a future version of ruby will do this automatically when chrooting.
|
64
|
-
$LOADED_FEATURES.map!{|s| s.sub(path_prefix, empty)}
|
65
|
-
|
66
|
-
fix_path = lambda do |s|
|
67
|
-
s.sub(path_prefix, empty)
|
68
|
-
end
|
69
|
-
|
70
|
-
[@dependency_order, @skip_reload].each do |a|
|
71
|
-
a.map!(&fix_path)
|
72
|
-
end
|
73
|
-
|
74
|
-
[@files, @old_entries].each do |hash|
|
75
|
-
hash.each do |k,h|
|
76
|
-
h[:features].map!(&fix_path)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
@monitor_dirs.each_value do |a|
|
81
|
-
a[1].map!(&fix_path)
|
82
|
-
end
|
83
|
-
|
84
|
-
@dependencies.each_value do |a|
|
85
|
-
a.map!(&fix_path)
|
86
|
-
end
|
87
|
-
|
88
|
-
[@files, @old_entries, @monitor_files, @monitor_dirs, @constants_defined, @dependencies].each do |hash|
|
89
|
-
hash.keys.each do |k|
|
90
|
-
if k.start_with?(path_prefix)
|
91
|
-
hash[fix_path.call(k)] = hash.delete(k)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
nil
|
97
|
-
end
|
98
|
-
|
99
52
|
# Unload all reloadable constants and features, and clear the list
|
100
53
|
# of files to monitor.
|
101
54
|
def clear!
|
@@ -157,11 +110,7 @@ module Rack
|
|
157
110
|
return if changed_files.empty?
|
158
111
|
|
159
112
|
unless @dependencies.empty?
|
160
|
-
changed_files = reload_files(changed_files)
|
161
|
-
changed_files.flatten!
|
162
|
-
changed_files.map!{|f| File.directory?(f) ? Unreloader.ruby_files(f) : f}
|
163
|
-
changed_files.flatten!
|
164
|
-
changed_files.uniq!
|
113
|
+
changed_files = Unreloader.expand_directory_paths(reload_files(changed_files))
|
165
114
|
|
166
115
|
order = @dependency_order
|
167
116
|
order &= changed_files
|
@@ -169,14 +118,14 @@ module Rack
|
|
169
118
|
end
|
170
119
|
|
171
120
|
unless @skip_reload.empty?
|
172
|
-
|
173
|
-
skip_reload.flatten!
|
174
|
-
skip_reload.uniq!
|
175
|
-
changed_files -= skip_reload
|
121
|
+
changed_files -= Unreloader.expand_directory_paths(@skip_reload)
|
176
122
|
end
|
177
123
|
|
124
|
+
changed_files.select! do |file|
|
125
|
+
@monitor_files.has_key?(file)
|
126
|
+
end
|
178
127
|
changed_files.each do |file|
|
179
|
-
safe_load(file
|
128
|
+
safe_load(file)
|
180
129
|
end
|
181
130
|
end
|
182
131
|
|
@@ -200,14 +149,14 @@ module Rack
|
|
200
149
|
begin
|
201
150
|
safe_load(file, options)
|
202
151
|
rescue NameError, LoadError => error
|
203
|
-
log "Cyclic dependency reload for #{error}"
|
152
|
+
log "Cyclic dependency reload for #{error.class}: #{error.message}"
|
204
153
|
rescue Exception => error
|
154
|
+
log "Error: #{error.class}: #{error.message}"
|
205
155
|
break
|
206
156
|
end
|
207
157
|
end
|
208
158
|
|
209
159
|
if error
|
210
|
-
log error
|
211
160
|
raise error
|
212
161
|
end
|
213
162
|
end
|
@@ -301,9 +250,6 @@ module Rack
|
|
301
250
|
# by the require, and rolling back the constants and features if there
|
302
251
|
# are any errors.
|
303
252
|
def safe_load(file, options={})
|
304
|
-
return unless @monitor_files.has_key?(file)
|
305
|
-
return unless options[:force] || file_changed?(file)
|
306
|
-
|
307
253
|
prepare(file) # might call #safe_load recursively
|
308
254
|
log "Loading #{file}"
|
309
255
|
begin
|
data/lib/rack/unreloader.rb
CHANGED
@@ -8,27 +8,31 @@ module Rack
|
|
8
8
|
# Mutex used to synchronize reloads
|
9
9
|
MUTEX = Monitor.new
|
10
10
|
|
11
|
-
# Reference to ::File as File
|
11
|
+
# Reference to ::File as File may return Rack::File by default.
|
12
12
|
File = ::File
|
13
13
|
|
14
|
+
# Regexp for valid constant names, to prevent code execution.
|
15
|
+
VALID_CONSTANT_NAME_REGEXP = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.freeze
|
16
|
+
|
14
17
|
# Given the list of paths, find all matching files, or matching ruby files
|
15
18
|
# in subdirecories if given a directory, and return an array of expanded
|
16
19
|
# paths.
|
17
20
|
def self.expand_directory_paths(paths)
|
18
|
-
expand_paths(paths)
|
19
|
-
|
20
|
-
|
21
|
+
paths = expand_paths(paths)
|
22
|
+
paths.map!{|f| File.directory?(f) ? ruby_files(f) : f}
|
23
|
+
paths.flatten!
|
24
|
+
paths
|
21
25
|
end
|
22
26
|
|
23
27
|
# Given the path glob or array of path globs, find all matching files
|
24
28
|
# or directories, and return an array of expanded paths.
|
25
29
|
def self.expand_paths(paths)
|
26
|
-
Array(paths).
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
paths = Array(paths).flatten
|
31
|
+
paths.map!{|path| Dir.glob(path).sort_by!{|filename| filename.count('/')}}
|
32
|
+
paths.flatten!
|
33
|
+
paths.map!{|path| File.expand_path(path)}
|
34
|
+
paths.uniq!
|
35
|
+
paths
|
32
36
|
end
|
33
37
|
|
34
38
|
# The .rb files in the given directory or any subdirectory.
|
@@ -40,11 +44,51 @@ module Rack
|
|
40
44
|
files.sort
|
41
45
|
end
|
42
46
|
|
47
|
+
# Autoload the file for the given objects. objs should be a string, symbol,
|
48
|
+
# or array of them holding a Ruby constant name. Access to the constant will
|
49
|
+
# load the related file. A non-nil logger will have output logged to it.
|
50
|
+
def self.autoload_constants(objs, file, logger)
|
51
|
+
strings = Array(objs).map(&:to_s)
|
52
|
+
if strings.empty?
|
53
|
+
# Remove file from $LOADED_FEATURES if there are no constants to autoload.
|
54
|
+
# In general that is because the file is part of another class that will
|
55
|
+
# handle loading the file separately, and if that class is reloaded, we
|
56
|
+
# want to remove the loaded feature so the file can get loaded again.
|
57
|
+
$LOADED_FEATURES.delete(file)
|
58
|
+
else
|
59
|
+
logger.info("Setting up autoload for #{file}: #{strings.join(' ')}") if logger
|
60
|
+
strings.each do |s|
|
61
|
+
obj, mod = split_autoload(s)
|
62
|
+
|
63
|
+
if obj
|
64
|
+
obj.autoload(mod, file)
|
65
|
+
elsif logger
|
66
|
+
logger.info("Invalid constant name: #{s}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Split the given string into an array. The first is a module/class to add the
|
73
|
+
# autoload to, and the second is the name of the constant to be autoloaded.
|
74
|
+
def self.split_autoload(mod_string)
|
75
|
+
if m = VALID_CONSTANT_NAME_REGEXP.match(mod_string)
|
76
|
+
ns, sep, mod = m[1].rpartition('::')
|
77
|
+
if sep.empty?
|
78
|
+
[Object, mod]
|
79
|
+
else
|
80
|
+
[Object.module_eval("::#{ns}", __FILE__, __LINE__), mod]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
43
85
|
# The Rack::Unreloader::Reloader instead related to this instance, if one.
|
44
86
|
attr_reader :reloader
|
45
87
|
|
46
88
|
# Setup the reloader. Options:
|
47
89
|
#
|
90
|
+
# :autoload :: Whether to allow autoloading. If not set to true, calls to
|
91
|
+
# autoload will eagerly require the related files instead of autoloading.
|
48
92
|
# :cooldown :: The number of seconds to wait between checks for changed files.
|
49
93
|
# Defaults to 1. Set to nil/false to not check for changed files.
|
50
94
|
# :handle_reload_errors :: Whether reload to handle reload errors by returning
|
@@ -58,12 +102,19 @@ module Rack
|
|
58
102
|
# match exactly, since modules don't have superclasses.
|
59
103
|
def initialize(opts={}, &block)
|
60
104
|
@app_block = block
|
105
|
+
@autoload = opts[:autoload]
|
106
|
+
@logger = opts[:logger]
|
61
107
|
if opts.fetch(:reload, true)
|
62
108
|
@cooldown = opts.fetch(:cooldown, 1)
|
63
109
|
@handle_reload_errors = opts[:handle_reload_errors]
|
64
110
|
@last = Time.at(0)
|
65
|
-
|
66
|
-
|
111
|
+
if @autoload
|
112
|
+
require_relative('unreloader/autoload_reloader')
|
113
|
+
@reloader = AutoloadReloader.new(opts)
|
114
|
+
else
|
115
|
+
require_relative('unreloader/reloader')
|
116
|
+
@reloader = Reloader.new(opts)
|
117
|
+
end
|
67
118
|
reload!
|
68
119
|
else
|
69
120
|
@reloader = @cooldown = @handle_reload_errors = false
|
@@ -86,6 +137,18 @@ module Rack
|
|
86
137
|
@app_block.call.call(env)
|
87
138
|
end
|
88
139
|
|
140
|
+
# Whether the unreloader is setup for reloading. If false, no reloading
|
141
|
+
# is done after the initial require.
|
142
|
+
def reload?
|
143
|
+
!!@reloader
|
144
|
+
end
|
145
|
+
|
146
|
+
# Whether the unreloader is setup for autoloading. If false, autoloads
|
147
|
+
# are treated as requires.
|
148
|
+
def autoload?
|
149
|
+
!!@autoload
|
150
|
+
end
|
151
|
+
|
89
152
|
# Add a file glob or array of file globs to monitor for changes.
|
90
153
|
# Options:
|
91
154
|
# :delete_hook :: When a file being monitored is deleted, call
|
@@ -98,6 +161,24 @@ module Rack
|
|
98
161
|
end
|
99
162
|
end
|
100
163
|
|
164
|
+
# Add a file glob or array of file global to autoload and monitor
|
165
|
+
# for changes. A block is required. It will be called with the
|
166
|
+
# path to be autoloaded, and should return the symbol for the
|
167
|
+
# constant name to autoload. Accepts the same options as #require.
|
168
|
+
def autoload(paths, opts={}, &block)
|
169
|
+
raise ArgumentError, "block required" unless block
|
170
|
+
|
171
|
+
if @autoload
|
172
|
+
if @reloader
|
173
|
+
@reloader.autoload_dependencies(paths, opts, &block)
|
174
|
+
else
|
175
|
+
Unreloader.expand_directory_paths(paths).each{|f| Unreloader.autoload_constants(yield(f), f, @logger)}
|
176
|
+
end
|
177
|
+
else
|
178
|
+
require(paths, opts, &block)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
101
182
|
# Records that each path in +files+ depends on +dependency+. If there
|
102
183
|
# is a modification to +dependency+, all related files will be reloaded
|
103
184
|
# after +dependency+ is reloaded. Both +dependency+ and each entry in +files+
|
@@ -128,17 +209,5 @@ module Rack
|
|
128
209
|
def reload!
|
129
210
|
@reloader.reload! if @reloader
|
130
211
|
end
|
131
|
-
|
132
|
-
# Strip the given path prefix from all absolute paths used by the
|
133
|
-
# reloader. This is designed when chrooting an application.
|
134
|
-
#
|
135
|
-
# Options:
|
136
|
-
# :strip_core :: Also strips the path prefix from $LOADED_FEATURES and
|
137
|
-
# $LOAD_PATH.
|
138
|
-
def strip_path_prefix(path_prefix, opts={})
|
139
|
-
if @reloader
|
140
|
-
@reloader.strip_path_prefix(path_prefix)
|
141
|
-
end
|
142
|
-
end
|
143
212
|
end
|
144
213
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-unreloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -66,12 +66,9 @@ files:
|
|
66
66
|
- CHANGELOG
|
67
67
|
- MIT-LICENSE
|
68
68
|
- README.rdoc
|
69
|
-
- Rakefile
|
70
69
|
- lib/rack/unreloader.rb
|
70
|
+
- lib/rack/unreloader/autoload_reloader.rb
|
71
71
|
- lib/rack/unreloader/reloader.rb
|
72
|
-
- spec/spec_helper.rb
|
73
|
-
- spec/strip_paths_spec.rb
|
74
|
-
- spec/unreloader_spec.rb
|
75
72
|
homepage: http://github.com/jeremyevans/rack-unreloader
|
76
73
|
licenses:
|
77
74
|
- MIT
|
@@ -80,7 +77,7 @@ metadata:
|
|
80
77
|
changelog_uri: https://github.com/jeremyevans/rack-unreloader/blob/master/CHANGELOG
|
81
78
|
mailing_list_uri: https://github.com/jeremyevans/rack-unreloader/discussions
|
82
79
|
source_code_uri: https://github.com/jeremyevans/rack-unreloader
|
83
|
-
post_install_message:
|
80
|
+
post_install_message:
|
84
81
|
rdoc_options:
|
85
82
|
- "--quiet"
|
86
83
|
- "--line-numbers"
|
@@ -95,15 +92,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
92
|
requirements:
|
96
93
|
- - ">="
|
97
94
|
- !ruby/object:Gem::Version
|
98
|
-
version: 1.
|
95
|
+
version: 1.9.2
|
99
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
97
|
requirements:
|
101
98
|
- - ">="
|
102
99
|
- !ruby/object:Gem::Version
|
103
100
|
version: '0'
|
104
101
|
requirements: []
|
105
|
-
rubygems_version: 3.
|
106
|
-
signing_key:
|
102
|
+
rubygems_version: 3.4.1
|
103
|
+
signing_key:
|
107
104
|
specification_version: 4
|
108
105
|
summary: Reload application when files change, unloading constants first
|
109
106
|
test_files: []
|
data/Rakefile
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require "rake"
|
2
|
-
require "rake/clean"
|
3
|
-
|
4
|
-
CLEAN.include ["rack-unreloader-*.gem", "rdoc"]
|
5
|
-
|
6
|
-
desc "Build rack-unreloader gem"
|
7
|
-
task :package=>[:clean] do |p|
|
8
|
-
sh %{#{FileUtils::RUBY} -S gem build rack-unreloader.gemspec}
|
9
|
-
end
|
10
|
-
|
11
|
-
### Specs
|
12
|
-
|
13
|
-
desc "Run specs"
|
14
|
-
task :spec do
|
15
|
-
sh "#{FileUtils::RUBY} #{'-w ' if RUBY_VERSION >= '3'}spec/unreloader_spec.rb"
|
16
|
-
end
|
17
|
-
|
18
|
-
task :default => :spec
|
19
|
-
|
20
|
-
### RDoc
|
21
|
-
|
22
|
-
RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Rack::Unreloader: Reload application when files change, unloading constants first']
|
23
|
-
|
24
|
-
begin
|
25
|
-
gem 'hanna-nouveau'
|
26
|
-
RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
|
27
|
-
rescue Gem::LoadError
|
28
|
-
end
|
29
|
-
|
30
|
-
rdoc_task_class = begin
|
31
|
-
require "rdoc/task"
|
32
|
-
RDoc::Task
|
33
|
-
rescue LoadError
|
34
|
-
require "rake/rdoctask"
|
35
|
-
Rake::RDocTask
|
36
|
-
end
|
37
|
-
|
38
|
-
RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
|
39
|
-
|
40
|
-
rdoc_task_class.new do |rdoc|
|
41
|
-
rdoc.rdoc_dir = "rdoc"
|
42
|
-
rdoc.options += RDOC_OPTS
|
43
|
-
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb"
|
44
|
-
end
|
45
|
-
|
data/spec/spec_helper.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), '../lib/rack/unreloader')
|
2
|
-
require 'rubygems'
|
3
|
-
$: << 'lib'
|
4
|
-
ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
|
5
|
-
gem 'minitest'
|
6
|
-
require 'minitest/global_expectations/autorun'
|
7
|
-
require 'minitest/hooks'
|
8
|
-
|
9
|
-
module ModifiedAt
|
10
|
-
def set_modified_time(file, time)
|
11
|
-
time = Time.now + time if time.is_a?(Integer)
|
12
|
-
modified_times[File.expand_path(file)] = time
|
13
|
-
end
|
14
|
-
|
15
|
-
def modified_times
|
16
|
-
@modified_times ||= {}
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def modified_at(file)
|
22
|
-
modified_times[file] || super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Minitest::Spec
|
27
|
-
def code(i)
|
28
|
-
"class App; class << self; def call(env) @a end; alias call call; end; @a ||= []; @a << #{i}; end"
|
29
|
-
end
|
30
|
-
|
31
|
-
def update_app(code, file=@filename)
|
32
|
-
if ru.reloader
|
33
|
-
ru.reloader.set_modified_time(File.dirname(file), @i += 1) unless File.file?(file)
|
34
|
-
ru.reloader.set_modified_time(file, @i += 1)
|
35
|
-
end
|
36
|
-
File.open(file, 'wb'){|f| f.write(code)}
|
37
|
-
end
|
38
|
-
|
39
|
-
def file_delete(file)
|
40
|
-
if ru.reloader
|
41
|
-
ru.reloader.set_modified_time(File.dirname(file), @i += 1)
|
42
|
-
end
|
43
|
-
File.delete(file)
|
44
|
-
end
|
45
|
-
|
46
|
-
def logger
|
47
|
-
return @logger if @logger
|
48
|
-
@logger = []
|
49
|
-
def @logger.method_missing(meth, log)
|
50
|
-
self << log
|
51
|
-
end
|
52
|
-
@logger
|
53
|
-
end
|
54
|
-
|
55
|
-
def base_ru(opts={})
|
56
|
-
block = opts[:block] || proc{App}
|
57
|
-
@ru = Rack::Unreloader.new({:logger=>logger, :cooldown=>0}.merge(opts), &block)
|
58
|
-
@ru.reloader.extend ModifiedAt if @ru.reloader
|
59
|
-
Object.const_set(:RU, @ru)
|
60
|
-
end
|
61
|
-
|
62
|
-
def ru(opts={})
|
63
|
-
return @ru if @ru
|
64
|
-
base_ru(opts)
|
65
|
-
update_app(opts[:code]||code(1))
|
66
|
-
@ru.require @filename
|
67
|
-
@ru
|
68
|
-
end
|
69
|
-
|
70
|
-
def log_match(*logs)
|
71
|
-
@logger.length.must_equal logs.length
|
72
|
-
logs.zip(@logger).each{|l, log| l.is_a?(String) ? log.must_equal(l) : log.must_match(l)}
|
73
|
-
end
|
74
|
-
|
75
|
-
before do
|
76
|
-
@i = 0
|
77
|
-
@filename = 'spec/app.rb'
|
78
|
-
end
|
79
|
-
|
80
|
-
after do
|
81
|
-
ru.reloader.clear! if ru.reloader
|
82
|
-
Object.send(:remove_const, :RU)
|
83
|
-
Object.send(:remove_const, :App) if defined?(::App)
|
84
|
-
Object.send(:remove_const, :App2) if defined?(::App2)
|
85
|
-
Dir['spec/app*.rb'].each{|f| File.delete(f)}
|
86
|
-
end
|
87
|
-
end
|