rack-unreloader 1.4.0 → 1.8.0

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.
@@ -1,76 +1,6 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), '../lib/rack/unreloader')
2
- gem 'minitest'
3
- require 'minitest/autorun'
4
- require 'minitest/hooks'
5
-
6
- module ModifiedAt
7
- def set_modified_time(file, time)
8
- modified_times[File.expand_path(file)] = time
9
- end
10
-
11
- def modified_times
12
- @modified_times ||= {}
13
- end
14
-
15
- private
16
-
17
- def modified_at(file)
18
- modified_times[file] || super
19
- end
20
- end
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
21
2
 
22
3
  describe Rack::Unreloader do
23
- def code(i)
24
- "class App; def self.call(env) @a end; @a ||= []; @a << #{i}; end"
25
- end
26
-
27
- def update_app(code, file=@filename)
28
- ru.reloader.set_modified_time(file, @i += 1) if ru.reloader
29
- File.open(file, 'wb'){|f| f.write(code)}
30
- end
31
-
32
- def logger
33
- return @logger if @logger
34
- @logger = []
35
- def @logger.method_missing(meth, log)
36
- self << log
37
- end
38
- @logger
39
- end
40
-
41
- def base_ru(opts={})
42
- block = opts[:block] || proc{App}
43
- @ru = Rack::Unreloader.new({:logger=>logger, :cooldown=>0}.merge(opts), &block)
44
- @ru.reloader.extend ModifiedAt if @ru.reloader
45
- Object.const_set(:RU, @ru)
46
- end
47
-
48
- def ru(opts={})
49
- return @ru if @ru
50
- base_ru(opts)
51
- update_app(opts[:code]||code(1))
52
- @ru.require @filename
53
- @ru
54
- end
55
-
56
- def log_match(*logs)
57
- @logger.length.must_equal logs.length
58
- logs.zip(@logger).each{|l, log| l.is_a?(String) ? log.must_equal(l) : log.must_match(l)}
59
- end
60
-
61
- before do
62
- @i = 0
63
- @filename = 'spec/app.rb'
64
- end
65
-
66
- after do
67
- ru.reloader.clear! if ru.reloader
68
- Object.send(:remove_const, :RU)
69
- Object.send(:remove_const, :App) if defined?(::App)
70
- Object.send(:remove_const, :App2) if defined?(::App2)
71
- Dir['spec/app*.rb'].each{|f| File.delete(f)}
72
- end
73
-
74
4
  it "should not reload files automatically if cooldown option is nil" do
75
5
  ru(:cooldown => nil).call({}).must_equal [1]
76
6
  update_app(code(2))
@@ -100,6 +30,16 @@ describe Rack::Unreloader do
100
30
  %r{\ANew classes in .*spec/app\.rb: App\z}
101
31
  end
102
32
 
33
+ it "should stop monitoring file for changes if it is deleted constants contained in file and reload file if file changes" do
34
+ ru.call({}).must_equal [1]
35
+ file_delete('spec/app.rb')
36
+ proc{ru.call({})}.must_raise NameError
37
+ log_match %r{\ALoading.*spec/app\.rb\z},
38
+ %r{\ANew classes in .*spec/app\.rb: App\z},
39
+ %r{\AUnloading.*spec/app\.rb\z},
40
+ "Removed constant App"
41
+ end
42
+
103
43
  it "should check constants using ObjectSpace if require proc returns :ObjectSpace" do
104
44
  base_ru
105
45
  update_app(code(1))
@@ -191,7 +131,7 @@ describe Rack::Unreloader do
191
131
  end
192
132
 
193
133
  it "should not unload modules by name if :subclasses option used and module not present" do
194
- ru(:subclasses=>'Foo', :code=>"module App; def self.call(env) @a end; @a ||= []; @a << 1; end").call({}).must_equal [1]
134
+ ru(:subclasses=>'Foo', :code=>"module App; def self.call(env) @a end; class << self; alias call call; end; @a ||= []; @a << 1; end").call({}).must_equal [1]
195
135
  update_app("module App; def self.call(env) @a end; @a ||= []; @a << 2; end")
196
136
  ru.call({}).must_equal [1, 2]
197
137
  log_match %r{\ALoading.*spec/app\.rb\z},
@@ -203,7 +143,29 @@ describe Rack::Unreloader do
203
143
  ru.call({}).must_equal [1]
204
144
  update_app("module App; def self.call(env) @a end; @a ||= []; raise 'foo'; end")
205
145
  proc{ru.call({})}.must_raise RuntimeError
206
- defined?(::App).must_equal nil
146
+ defined?(::App).must_be_nil
147
+ update_app(code(2))
148
+ ru.call({}).must_equal [2]
149
+ log_match %r{\ALoading.*spec/app\.rb\z},
150
+ %r{\ANew classes in .*spec/app\.rb: App\z},
151
+ %r{\AUnloading.*spec/app\.rb\z},
152
+ "Removed constant App",
153
+ %r{\ALoading.*spec/app\.rb\z},
154
+ %r{\AFailed to load .*spec/app\.rb; removing partially defined constants\z},
155
+ "Removed constant App",
156
+ %r{\ALoading.*spec/app\.rb\z},
157
+ %r{\ANew classes in .*spec/app\.rb: App\z}
158
+ end
159
+
160
+ it "should support :handle_reload_errors option to return backtrace if there is an error reloading" do
161
+ ru(:handle_reload_errors=>true).call({}).must_equal [1]
162
+ update_app("module App; def self.call(env) @a end; @a ||= []; raise 'foo'; end")
163
+ rack_response = ru.call({})
164
+ rack_response[0].must_equal 500
165
+ rack_response[1]['Content-Type'].must_equal 'text/plain'
166
+ rack_response[1]['Content-Length'].must_match(rack_response[2][0].bytesize.to_s)
167
+ rack_response[2][0].must_match(/\/spec\/app\.rb:1/)
168
+ defined?(::App).must_be_nil
207
169
  update_app(code(2))
208
170
  ru.call({}).must_equal [2]
209
171
  log_match %r{\ALoading.*spec/app\.rb\z},
@@ -256,7 +218,7 @@ describe Rack::Unreloader do
256
218
 
257
219
  it "should allow specifying proc for which constants get removed" do
258
220
  base_ru
259
- update_app("class App; def self.call(env) [@a, App2.a] end; @a ||= []; @a << 1; end; class App2; def self.a; @a end; @a ||= []; @a << 2; end")
221
+ update_app("class App; def self.call(env) [@a, App2.a] end; class << self; alias call call; end; @a ||= []; @a << 1; end; class App2; def self.a; @a end; class << self; alias a a; end; @a ||= []; @a << 2; end")
260
222
  @ru.require('spec/app.rb'){|f| File.basename(f).sub(/\.rb/, '').capitalize}
261
223
  ru.call({}).must_equal [[1], [2]]
262
224
  update_app("class App; def self.call(env) [@a, App2.a] end; @a ||= []; @a << 3; end; class App2; def self.a; @a end; @a ||= []; @a << 4; end")
@@ -326,6 +288,20 @@ describe Rack::Unreloader do
326
288
  ru.call({}).must_equal 4
327
289
  end
328
290
 
291
+ it "should handle modules where name raises an exception" do
292
+ m = Module.new{def self.name; raise end}
293
+ ru(:code=>"module App; def self.call(env) @a end; @a ||= []; @a << 1; end").call({}).must_equal [1]
294
+ update_app("module App; def self.call(env) @a end; @a ||= []; @a << 2; end")
295
+ ru.call({}).must_equal [2]
296
+ log_match %r{\ALoading.*spec/app\.rb\z},
297
+ %r{\ANew classes in .*spec/app\.rb: App\z},
298
+ %r{\AUnloading.*spec/app\.rb\z},
299
+ "Removed constant App",
300
+ %r{\ALoading.*spec/app\.rb\z},
301
+ %r{\ANew classes in .*spec/app\.rb: App\z}
302
+ m
303
+ end
304
+
329
305
  describe "with a directory" do
330
306
  include Minitest::Hooks
331
307
 
@@ -336,7 +312,7 @@ describe Rack::Unreloader do
336
312
  end
337
313
 
338
314
  after do
339
- Dir['spec/dir/**/*.rb'].each{|f| File.delete(f)}
315
+ Dir['spec/dir/**/*.rb'].each{|f| file_delete(f)}
340
316
  end
341
317
 
342
318
  after(:all) do
@@ -391,7 +367,7 @@ describe Rack::Unreloader do
391
367
  ru.call({}).must_equal 3
392
368
  update_app("module C; B = 4; end", 'spec/dir/subdir2/app_mod2.rb')
393
369
  ru.call({}).must_equal 4
394
- File.delete 'spec/dir/subdir/app_mod.rb'
370
+ file_delete 'spec/dir/subdir/app_mod.rb'
395
371
  ru.call({}).must_equal 0
396
372
  end
397
373
 
@@ -412,7 +388,7 @@ describe Rack::Unreloader do
412
388
  ru.call({}).must_equal 561
413
389
  update_app("class App; end", 'spec/dir/appa.rb')
414
390
  ru.call({}).must_equal 61
415
- File.delete 'spec/dir/appb.rb'
391
+ file_delete 'spec/dir/appb.rb'
416
392
  ru.call({}).must_equal 1
417
393
  end
418
394
 
@@ -478,7 +454,7 @@ describe Rack::Unreloader do
478
454
  update_app("App.call[:foo] = 1", 'spec/dir/a.rb')
479
455
  @ru.require('spec/app.rb')
480
456
  ru.call({}).must_equal(:foo=>1)
481
- File.delete('spec/dir/a.rb')
457
+ file_delete('spec/dir/a.rb')
482
458
  update_app("App.call[:foo] = 2", 'spec/dir/b.rb')
483
459
  ru.call({}).must_equal(:foo=>2)
484
460
  log_match %r{\ALoading.*spec/app\.rb\z},
@@ -495,7 +471,7 @@ describe Rack::Unreloader do
495
471
  update_app("App.call[:foo] = 1", 'spec/dir/subdir/a.rb')
496
472
  @ru.require('spec/app.rb')
497
473
  ru.call({}).must_equal(:foo=>1)
498
- File.delete('spec/dir/subdir/a.rb')
474
+ file_delete('spec/dir/subdir/a.rb')
499
475
  update_app("App.call[:foo] = 2", 'spec/dir/subdir/b.rb')
500
476
  ru.call({}).must_equal(:foo=>2)
501
477
  log_match %r{\ALoading.*spec/app\.rb\z},
@@ -505,5 +481,35 @@ describe Rack::Unreloader do
505
481
  %r{\AUnloading .*/spec/dir/subdir/a.rb\z},
506
482
  %r{\ALoading.*spec/dir/subdir/b\.rb\z}
507
483
  end
484
+
485
+ it "should call hook when dropping files deleted from the directory" do
486
+ base_ru
487
+ deletes = []
488
+ Object.const_set(:Deletes, deletes)
489
+ update_app("class App; @a = {}; def self.call(env=nil) @a end; end; RU.require('spec/dir', :delete_hook=>proc{|f| Deletes << f})")
490
+ update_app("App.call[:foo] = 1", 'spec/dir/a.rb')
491
+ @ru.require('spec/app.rb', :delete_hook=>proc{|f| deletes << f})
492
+ ru.call({}).must_equal(:foo=>1)
493
+ file_delete('spec/dir/a.rb')
494
+ update_app("App.call[:foo] = 2", 'spec/dir/b.rb')
495
+ ru.call({}).must_equal(:foo=>2)
496
+ deletes.must_equal [File.expand_path('spec/dir/a.rb')]
497
+ file_delete('spec/dir/b.rb')
498
+ ru.call({}).must_equal(:foo=>2)
499
+ deletes.must_equal [File.expand_path('spec/dir/a.rb'), File.expand_path('spec/dir/b.rb')]
500
+ file_delete('spec/app.rb')
501
+ proc{ru.call({})}.must_raise NameError
502
+ deletes.must_equal [File.expand_path('spec/dir/a.rb'), File.expand_path('spec/dir/b.rb'), File.expand_path('spec/app.rb')]
503
+ log_match %r{\ALoading.*spec/app\.rb\z},
504
+ %r{\ALoading.*spec/dir/a\.rb\z},
505
+ %r{\ANew classes in .*spec/app\.rb: App\z},
506
+ %r{\ANew features in .*spec/app\.rb: .*spec/dir/a\.rb\z},
507
+ %r{\AUnloading .*/spec/dir/a.rb\z},
508
+ %r{\ALoading.*spec/dir/b\.rb\z},
509
+ %r{\AUnloading .*/spec/dir/b.rb\z},
510
+ %r{\AUnloading .*/spec/app.rb\z},
511
+ %r{\ARemoved constant App\z}
512
+ Object.send(:remove_const, :Deletes)
513
+ end
508
514
  end
509
515
  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.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-global_expectations
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: |
42
56
  Rack::Unreloader is a rack middleware that reloads application files when it
43
57
  detects changes, unloading constants defined in those files before reloading.
@@ -55,11 +69,17 @@ files:
55
69
  - Rakefile
56
70
  - lib/rack/unreloader.rb
57
71
  - lib/rack/unreloader/reloader.rb
72
+ - spec/spec_helper.rb
73
+ - spec/strip_paths_spec.rb
58
74
  - spec/unreloader_spec.rb
59
75
  homepage: http://github.com/jeremyevans/rack-unreloader
60
76
  licenses:
61
77
  - MIT
62
- metadata: {}
78
+ metadata:
79
+ bug_tracker_uri: https://github.com/jeremyevans/rack-unreloader/issues
80
+ changelog_uri: https://github.com/jeremyevans/rack-unreloader/blob/master/CHANGELOG
81
+ mailing_list_uri: https://github.com/jeremyevans/rack-unreloader/discussions
82
+ source_code_uri: https://github.com/jeremyevans/rack-unreloader
63
83
  post_install_message:
64
84
  rdoc_options:
65
85
  - "--quiet"
@@ -75,15 +95,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
95
  requirements:
76
96
  - - ">="
77
97
  - !ruby/object:Gem::Version
78
- version: '0'
98
+ version: 1.8.7
79
99
  required_rubygems_version: !ruby/object:Gem::Requirement
80
100
  requirements:
81
101
  - - ">="
82
102
  - !ruby/object:Gem::Version
83
103
  version: '0'
84
104
  requirements: []
85
- rubyforge_project:
86
- rubygems_version: 2.5.1
105
+ rubygems_version: 3.2.22
87
106
  signing_key:
88
107
  specification_version: 4
89
108
  summary: Reload application when files change, unloading constants first