rack-unreloader 1.4.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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