rails-dev-boost 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c6be77bb649766e7ae7bfe30a7d45f848c62ec3
4
+ data.tar.gz: 380d7b77ab210ea426ee7a4369e46102e317bb5b
5
+ SHA512:
6
+ metadata.gz: e69c5b78346a397e7bc99069e323db29ea92dd3ced9cd2da58d3083e7fb625be6075c3482e85bccece82390bf681cf24e3615dee5b0c2b211a8cfcf86ec650e7
7
+ data.tar.gz: e4d005306b5d46d9f668cc241d8a9dfc735a51447da2f13cf6c6aaad97ab1f19580b997b0db78fe6308bc64af60f8ea80a002305153198d7c5562ae29fc37435
@@ -8,7 +8,7 @@ Alternative to Robert Pankowecki's [`active_reload`](https://github.com/paneq/ac
8
8
 
9
9
  ## Branches
10
10
 
11
- If you are using **Rails 3**: [`rails-dev-boost/master`](http://github.com/thedarkone/rails-dev-boost/tree/master) branch.
11
+ If you are using **Rails 3 and newer**: [`rails-dev-boost/master`](http://github.com/thedarkone/rails-dev-boost/tree/master) branch.
12
12
 
13
13
  If you are using **Rails 2.3**: [`rails-dev-boost/rails-2-3`](http://github.com/thedarkone/rails-dev-boost/tree/rails-2-3) branch.
14
14
 
@@ -29,7 +29,7 @@ I'm very interested in making the plugin as robust as possible and will work wit
29
29
 
30
30
  There is built-in debug mode in `rails-dev-boost` that can be enabled by putting this line a Rails initializer file:
31
31
 
32
- RailsDevelopmentBoost.debug!
32
+ RailsDevelopmentBoost.debug! if defined?(RailsDevelopmentBoost)
33
33
 
34
34
  After restarting your server `rails-dev-boost` will start to spewing detailed tracing information about its actions into your `development.log` file.
35
35
 
@@ -47,7 +47,7 @@ Usage through `Gemfile`:
47
47
 
48
48
  ```ruby
49
49
  group :development do
50
- gem 'rails-dev-boost', :git => 'git://github.com/thedarkone/rails-dev-boost.git', :require => 'rails_development_boost'
50
+ gem 'rails-dev-boost', :git => 'git://github.com/thedarkone/rails-dev-boost.git'
51
51
  end
52
52
  ```
53
53
 
@@ -279,6 +279,24 @@ class Blog < ActiveRecord::Base
279
279
  end
280
280
  ```
281
281
 
282
+ ## Asynchronous mode
283
+
284
+ By default `rails-dev-boost` now runs in an "async" mode, watching and unloading modified files in a separate thread. This allows for an even faster development mode because there is no longer a need to do a `File.mtime` check of all the `.rb` files at the beginning of the request.
285
+
286
+ To disable the async mode put the following code in a Rails initializer file (these are found in `config/initializers` directory):
287
+ ```ruby
288
+ RailsDevelopmentBoost.async = false
289
+ ```
290
+
291
+ ## `routes.rb` potentially not reloading
292
+
293
+ Since Rails 4.0 `ActiveSupport` now by default reloads `routes.rb` file **if any other auto-loaded `.rb` has changed**. This behavior is different from all previous Rails versions, where `routes.rb` had been reloaded **only if the `routes.rb` file itself had been changed**. This now results in `routes.rb` being reloading on all requests in which any other unrelated `.rb` has been changed, it is in my opinion an unnecessary slowdown, thus `rails-dev-boost` by default reverts Rails to the pre Rails 4.0 behavior.
294
+
295
+ To disable this patch and revert to the default Rails 4.0 behavior - put the following code in a Rails initializer file (these are found in `config/initializers` directory):
296
+ ```ruby
297
+ RailsDevelopmentBoost.reload_routes_on_any_change = true
298
+ ```
299
+
282
300
  ## FAQ
283
301
 
284
302
  ### Q: Since the plugin uses its special "unloading mechanism" won't everything break down?
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
@@ -13,6 +13,8 @@ module RailsDevelopmentBoost
13
13
  else
14
14
  ActionDispatch::Callbacks.before(:prepend => true) { ActiveSupport::Dependencies.unload_modified_files! }
15
15
  end
16
+
17
+ DependenciesPatch.enable_async_mode_by_default!
16
18
  end
17
19
  end
18
20
 
@@ -35,6 +37,8 @@ module RailsDevelopmentBoost
35
37
  else
36
38
  ActiveSupport.on_load(:action_controller) { ViewHelpersPatch.apply! }
37
39
  end
40
+
41
+ app.config.middleware.use 'RailsDevelopmentBoost::Async::Middleware'
38
42
  end
39
43
  end
40
44
  end
@@ -55,7 +59,12 @@ module RailsDevelopmentBoost
55
59
  DependenciesPatch.debug!
56
60
  end
57
61
 
58
- def self.async!
59
- DependenciesPatch.async!
62
+ def self.async=(new_value)
63
+ DependenciesPatch.async = new_value
64
+ end
65
+
66
+ class << self
67
+ attr_accessor :reload_routes_on_any_change
60
68
  end
69
+ self.reload_routes_on_any_change = false
61
70
  end
@@ -1,15 +1,29 @@
1
- require 'rb-fsevent'
2
1
  require 'monitor'
3
2
 
4
3
  module RailsDevelopmentBoost
5
4
  module Async
5
+ class Middleware
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ if DependenciesPatch.applied? && DependenciesPatch.async?
12
+ Async.synchronize { @app.call(env) }
13
+ else
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+
6
19
  extend self
20
+ autoload :Reactor, 'rails_development_boost/async/reactor'
7
21
 
8
22
  MONITOR = Monitor.new
9
23
 
10
24
  def heartbeat_check!
11
25
  if @reactor
12
- unless @reactor.alive?
26
+ unless @reactor.alive_and_watching?(ActiveSupport::Dependencies.autoload_paths)
13
27
  @reactor.stop
14
28
  @reactor = nil
15
29
  start!
@@ -25,13 +39,56 @@ module RailsDevelopmentBoost
25
39
  MONITOR.synchronize { yield }
26
40
  end
27
41
 
42
+ def usable?
43
+ Reactor.implementation
44
+ end
45
+
46
+ def process_new_async_value(new_value)
47
+ if new_value
48
+ if !Async.usable?
49
+ msg = 'Unable to start rails-dev-boost in an asynchronous mode. '
50
+ if gem_error = Reactor.gem_load_error
51
+ msg << "Please install the missing gem for even faster rails-dev-boost experience:\n#{gem_error}\n" <<
52
+ "If you can't use the suggest gem version please let me know at https://github.com/thedarkone/rails-dev-boost/issues !\n"
53
+ else
54
+ msg << "Are you running on a OS that is 'async-unsupported' by rails-dev-boost? Please open an issue on github: https://github.com/thedarkone/rails-dev-boost/issues !"
55
+ end
56
+ msg << "\nTo get rid of this message disable the rails-dev-boost's async mode by putting the following code " +
57
+ "in a Rails initializer file (these are found in config/initializers directory):\n" +
58
+ "\n\tRailsDevelopmentBoost.async = false if defined?(RailsDevelopmentBoost)\n\n"
59
+ async_warning(msg)
60
+ new_value = false
61
+ elsif in_console?
62
+ async_warning('Warning: using asynchronous mode in Rails console mode might result in surprising behaviour and is not recommended.')
63
+ end
64
+ end
65
+ new_value
66
+ end
67
+
68
+ def enable_by_default!(user_provided_value = false)
69
+ unless user_provided_value
70
+ DependenciesPatch.async = true unless usable? # trigger the warning message, unless there is a user supplied `async` setting
71
+ DependenciesPatch.async = !in_console?
72
+ end
73
+ end
74
+
28
75
  private
76
+ def in_console?
77
+ defined?(IRB) || defined?(Pry)
78
+ end
79
+
80
+ def async_warning(msg)
81
+ msg = msg.gsub(/^/, '[RAILS-DEV-BOOST] ')
82
+ Kernel.warn(msg)
83
+ Rails.logger.info(msg)
84
+ end
29
85
 
30
86
  def start!
31
- @reactor = Reactor.new
32
- @reactor.watch(ActiveSupport::Dependencies.autoload_paths) {|changed_dirs| unload_affected(changed_dirs)}
33
- @reactor.start!
34
- self.unloaded_something = LoadedFile.unload_modified! # don't miss-out on any of the file changes as the async thread hasn't been started as of yet
87
+ if @reactor = Reactor.get
88
+ @reactor.watch(ActiveSupport::Dependencies.autoload_paths) {|changed_dirs| unload_affected(changed_dirs)}
89
+ @reactor.start!
90
+ self.unloaded_something = LoadedFile.unload_modified! # don't miss-out on any of the file changes as the async thread hasn't been started as of yet
91
+ end
35
92
  end
36
93
 
37
94
  def re_raise_unload_error_if_any
@@ -45,9 +102,7 @@ module RailsDevelopmentBoost
45
102
  changed_dirs = changed_dirs.map {|changed_dir| File.expand_path(changed_dir).chomp(File::SEPARATOR)}
46
103
 
47
104
  synchronize do
48
- self.unloaded_something = LoadedFile::LOADED.each_file_unload_if_changed do |file|
49
- changed_dirs.any? {|changed_dir| file.path.starts_with?(changed_dir)} && file.changed?
50
- end
105
+ self.unloaded_something = LoadedFile::LOADED.unload_modified!(changed_dirs)
51
106
  end
52
107
  rescue Exception => e
53
108
  @unload_error ||= e
@@ -56,18 +111,5 @@ module RailsDevelopmentBoost
56
111
  def unloaded_something=(value)
57
112
  @unloaded_something ||= value
58
113
  end
59
-
60
- class Reactor
61
- delegate :alive?, :to => '@thread'
62
- delegate :watch, :stop, :to => '@watcher'
63
-
64
- def initialize
65
- @watcher = FSEvent.new
66
- end
67
-
68
- def start!
69
- @thread = Thread.new { @watcher.run }
70
- end
71
- end
72
114
  end
73
115
  end
@@ -0,0 +1,195 @@
1
+ require 'thread'
2
+ require 'set'
3
+
4
+ module RailsDevelopmentBoost
5
+ module Async
6
+ # Not using Listen gem directly, because I don't want to be storing/checking .rb files' SHA contents and would like to rely on mtime values exclusively.
7
+ module Reactor
8
+ class MissingNativeGem < StandardError
9
+ def initialize(gem_name, version)
10
+ gem_version_msg = indented_code("gem '#{gem_name}', '#{version}'")
11
+ super("by adding the following to your Gemfile:\n#{gem_version_msg}\n\nThis can go into the same :development group if (you are using one):\n" <<
12
+ indented_code("group :development do\n\tgem 'rails-dev-boost', :github => 'thedarkone/rails-dev-boost'#{gem_version_msg}\nend\n"))
13
+ end
14
+
15
+ private
16
+ def indented_code(msg)
17
+ "\n\t" << msg.gsub("\n", "\n\t")
18
+ end
19
+ end
20
+
21
+ extend self
22
+ attr_reader :gem_load_error
23
+
24
+ def get
25
+ if impl = implementation
26
+ impl.new
27
+ end
28
+ end
29
+
30
+ def implementation
31
+ defined?(@implementation) ? @implementation : (@implementation = find_usable_implementation)
32
+ end
33
+
34
+ def find_usable_implementation
35
+ [Darwin, Linux, Windows].find(&:usable?)
36
+ rescue MissingNativeGem => e
37
+ @gem_load_error ||= e.message
38
+ nil
39
+ end
40
+
41
+ class Base
42
+ def initialize
43
+ @watcher = create_watcher
44
+ @directories = Set.new
45
+ end
46
+
47
+ def watch(directories, &block)
48
+ @directories.merge(directories)
49
+ watch_internal(directories, &block)
50
+ end
51
+
52
+ def start!
53
+ @thread = Thread.new { start_watcher! }
54
+ end
55
+
56
+ def stop
57
+ @watcher.stop
58
+ stop_thread
59
+ end
60
+
61
+ def alive_and_watching?(directories)
62
+ @thread.alive? && directories.all? {|directory| @directories.include?(directory)}
63
+ end
64
+
65
+ private
66
+ def watch_internal(directories, &block)
67
+ @watcher.watch(directories, &block)
68
+ end
69
+
70
+ def stop_thread
71
+ @thread.join if @thread
72
+ end
73
+
74
+ def start_watcher!
75
+ @watcher.run
76
+ end
77
+
78
+ class << self
79
+ def usable?
80
+ gem_check! if platform_match?
81
+ end
82
+
83
+ private
84
+ def platform_match?
85
+ require 'rbconfig'
86
+ RbConfig::CONFIG['target_os'] =~ self::TARGET_OS_REGEX
87
+ end
88
+
89
+ def gem_check!
90
+ defined?(@gem_loaded) ? @gem_loaded : @gem_loaded = load_gem!
91
+ end
92
+
93
+ def load_gem!
94
+ gem(self::GEM_NAME, self::GEM_VERSION)
95
+ require(self::GEM_NAME)
96
+ true
97
+ rescue Gem::LoadError
98
+ raise MissingNativeGem.new(self::GEM_NAME, self::GEM_VERSION)
99
+ end
100
+ end
101
+ end
102
+
103
+ class Darwin < Base
104
+ TARGET_OS_REGEX = /darwin(1.+)?$/i
105
+ GEM_NAME = 'rb-fsevent'
106
+ GEM_VERSION = '>= 0.9.1'
107
+
108
+ private
109
+ def create_watcher
110
+ FSEvent.new
111
+ end
112
+ end
113
+
114
+ # Errors, comments and other gotchas taken from Listen gem (https://github.com/guard/listen)
115
+ class Linux < Base
116
+ TARGET_OS_REGEX = /linux/i
117
+ GEM_NAME = 'rb-inotify'
118
+ GEM_VERSION = '>= 0.8.8'
119
+
120
+ EVENTS = [:recursive, :attrib, :create, :delete, :move, :close_write]
121
+
122
+ # The message to show when the limit of inotify watchers is not enough
123
+ #
124
+ INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
125
+ Listen error: unable to monitor directories for changes.
126
+
127
+ Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
128
+ for information on how to solve this issue.
129
+ EOS
130
+
131
+ private
132
+ def watch_internal(directories)
133
+ directories.each do |directory|
134
+ @watcher.watch(directory, *EVENTS) do |event|
135
+ unless root?(event) || file_event_on_a_dir?(event)
136
+ if File.file?(absolute_name = event.absolute_name)
137
+ yield [File.dirname(absolute_name)]
138
+ elsif File.directory?(absolute_name)
139
+ yield [absolute_name]
140
+ end
141
+ end
142
+ end
143
+ end
144
+ rescue Errno::ENOSPC
145
+ abort(INOTIFY_LIMIT_MESSAGE)
146
+ end
147
+
148
+ def root?(event) # Event on root directory
149
+ event.name.empty? # same as event.name == ""
150
+ end
151
+
152
+ # INotify reports changes to files inside directories as events
153
+ # on the directories themselves too.
154
+ #
155
+ # @see http://linux.die.net/man/7/inotify
156
+ def file_event_on_a_dir?(event)
157
+ # event.flags.include?(:isdir) and event.flags & [:close, :modify] != []
158
+ flags = event.flags
159
+ flags.include?(:isdir) && (flags.include?(:close) || flags.include?(:modify))
160
+ end
161
+
162
+ def create_watcher
163
+ INotify::Notifier.new
164
+ end
165
+
166
+ def stop_thread
167
+ Thread.kill(@thread) if @thread
168
+ end
169
+ end
170
+
171
+ class Windows < Base
172
+ TARGET_OS_REGEX = /mswin|mingw|cygwin/i
173
+ GEM_NAME = 'wdm'
174
+ GEM_VERSION = '>= 0.0.3'
175
+
176
+ private
177
+ def watch_internal(directories)
178
+ directories.each do |directory|
179
+ @watcher.watch_recursively(directory) do |change|
180
+ yield [File.dirname(change.path)]
181
+ end
182
+ end
183
+ end
184
+
185
+ def create_watcher
186
+ WDM::Monitor.new
187
+ end
188
+
189
+ def start_watcher!
190
+ @watcher.run!
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -18,13 +18,22 @@ module RailsDevelopmentBoost
18
18
 
19
19
  patch = self
20
20
  ActiveSupport::Dependencies.module_eval do
21
- alias_method :local_const_defined?, :uninherited_const_defined? unless method_defined?(:local_const_defined?) # pre 4da45060 compatibility
21
+ unless method_defined?(:local_const_defined?) # pre 4da45060 compatibility
22
+ if method_defined?(:uninherited_const_defined?)
23
+ alias_method :local_const_defined?, :uninherited_const_defined?
24
+ else # post 4.0 compat
25
+ def local_const_defined?(mod, const_name)
26
+ mod.const_defined?(const_name, false)
27
+ end
28
+ end
29
+ end
22
30
  remove_possible_method :remove_unloadable_constants!
23
31
  remove_possible_method :clear
24
32
  include patch
25
33
  alias_method_chain :load_file, 'constant_tracking'
26
34
  alias_method_chain :remove_constant, 'handling_of_connections'
27
35
  extend patch
36
+ @routes_path_loading = nil
28
37
  end
29
38
 
30
39
  ActiveSupport::Dependencies::Loadable.module_eval do
@@ -45,23 +54,24 @@ module RailsDevelopmentBoost
45
54
  end
46
55
  end
47
56
 
48
- def self.async!
49
- @async = true
57
+ def self.async=(new_value)
58
+ @async = Async.process_new_async_value(new_value)
50
59
  end
51
60
 
52
61
  def self.async?
53
62
  @async
54
63
  end
55
64
 
65
+ def self.enable_async_mode_by_default!
66
+ Async.enable_by_default!(defined?(@async))
67
+ end
68
+
56
69
  def self.applied?
57
70
  ActiveSupport::Dependencies < self
58
71
  end
59
72
 
60
73
  autoload :InstrumentationPatch, 'rails_development_boost/dependencies_patch/instrumentation_patch'
61
74
 
62
- mattr_accessor :constants_being_removed
63
- self.constants_being_removed = []
64
-
65
75
  mattr_accessor :explicit_dependencies
66
76
  self.explicit_dependencies = {}
67
77
 
@@ -91,6 +101,12 @@ module RailsDevelopmentBoost
91
101
  end while const_name.sub!(/::[^:]+\Z/, NOTHING)
92
102
  false
93
103
  end
104
+
105
+ def load_path_to_real_path(path)
106
+ expanded_path = File.expand_path(path)
107
+ expanded_path << '.rb' unless path =~ /\.r(?:b|ake)\Z/
108
+ expanded_path
109
+ end
94
110
  end
95
111
 
96
112
  class ModuleCache
@@ -154,12 +170,50 @@ module RailsDevelopmentBoost
154
170
  end
155
171
  end
156
172
 
173
+ class ConstantsHeap < Array
174
+ NAMESPACE_SEPARATOR = '::'
175
+
176
+ def initialize(*args)
177
+ super
178
+ @seen = Set.new
179
+ end
180
+
181
+ def add_const?(const_name, force_insert = false)
182
+ if @seen.add?(const_name) || force_insert
183
+ (self[const_name.count(NAMESPACE_SEPARATOR)] ||= []) << const_name
184
+ true
185
+ else
186
+ false
187
+ end
188
+ end
189
+
190
+ def pop_next_const
191
+ reverse_each do |slot|
192
+ if const_name = slot.try(:pop)
193
+ return const_name
194
+ end
195
+ end
196
+ nil
197
+ end
198
+
199
+ def seen?(const_name)
200
+ @seen.include?(const_name)
201
+ end
202
+
203
+ def clear_seen
204
+ @seen.clear
205
+ end
206
+ end
207
+
208
+ mattr_accessor :constants_to_remove
209
+ self.constants_to_remove = ConstantsHeap.new
210
+
157
211
  def unload_modified_files!
158
- unloaded_something = unload_modified_files_internal!
159
- load_failure = clear_load_failure
160
- unloaded_something || load_failure
161
- ensure
162
- async_synchronize { @module_cache = nil }
212
+ async_synchronize do
213
+ unloaded_something = unload_modified_files_internal!
214
+ load_failure = clear_load_failure
215
+ unloaded_something || load_failure
216
+ end
163
217
  end
164
218
 
165
219
  def remove_explicitely_unloadable_constants!
@@ -173,7 +227,10 @@ module RailsDevelopmentBoost
173
227
  # Augmented `load_file'.
174
228
  def load_file_with_constant_tracking(path, *args)
175
229
  async_synchronize do
176
- @module_cache = nil # nuking the module_cache helps to avoid any stale-class issues when the async mode is used in a console session
230
+ if @module_cache
231
+ @module_cache = nil
232
+ constants_to_remove.clear_seen
233
+ end
177
234
  load_file_with_constant_tracking_internal(path, args)
178
235
  end
179
236
  end
@@ -187,6 +244,14 @@ module RailsDevelopmentBoost
187
244
  currently_loading.pop
188
245
  end
189
246
 
247
+ def loading_routes_file(path)
248
+ prev_value = @routes_path_loading
249
+ @routes_path_loading = Util.load_path_to_real_path(path)
250
+ yield
251
+ ensure
252
+ @routes_path_loading = prev_value
253
+ end
254
+
190
255
  def associate_constants_to_file(constants, file_path)
191
256
  # freezing strings before using them as Hash keys is slightly more memory efficient
192
257
  constants.map!(&:freeze)
@@ -195,13 +260,32 @@ module RailsDevelopmentBoost
195
260
  LoadedFile.for(file_path).add_constants(constants)
196
261
  end
197
262
 
263
+ def schedule_const_for_unloading(const_name)
264
+ if constants_to_remove.add_const?(const_name)
265
+ if qualified_const_defined?(const_name) && object = const_name.constantize
266
+ @module_cache ||= ModuleCache.new # make sure module_cache has been created
267
+ schedule_dependent_constants_for_removal(const_name, object)
268
+ end
269
+ true
270
+ end
271
+ end
272
+
273
+ def process_consts_scheduled_for_removal
274
+ unless @now_removing_const
275
+ @now_removing_const = true
276
+ begin
277
+ process_consts_scheduled_for_removal_internal
278
+ ensure
279
+ @now_removing_const = nil
280
+ end
281
+ end
282
+ end
283
+
198
284
  # Augmented `remove_constant'.
199
285
  def remove_constant_with_handling_of_connections(const_name)
200
286
  async_synchronize do
201
- module_cache # make sure module_cache has been created
202
- prevent_further_removal_of(const_name) do
203
- unprotected_remove_constant(const_name)
204
- end
287
+ schedule_const_for_unloading(const_name)
288
+ process_consts_scheduled_for_removal
205
289
  end
206
290
  end
207
291
 
@@ -247,6 +331,20 @@ module RailsDevelopmentBoost
247
331
  end
248
332
 
249
333
  private
334
+ def process_consts_scheduled_for_removal_internal
335
+ heap = constants_to_remove
336
+ result = nil
337
+ while const_to_remove = heap.pop_next_const
338
+ begin
339
+ result = unprotected_remove_constant(const_to_remove, qualified_const_defined?(const_to_remove) && const_to_remove.constantize)
340
+ rescue Exception
341
+ heap.add_const?(const_to_remove, true)
342
+ raise
343
+ end
344
+ end
345
+ result
346
+ end
347
+
250
348
  def unload_modified_files_internal!
251
349
  log_call
252
350
  if DependenciesPatch.async?
@@ -270,6 +368,9 @@ module RailsDevelopmentBoost
270
368
 
271
369
  # Associate newly loaded constants to the file just loaded
272
370
  associate_constants_to_file(new_constants, path)
371
+ if routes_path_loading = @routes_path_loading
372
+ RoutesLoadedFile.for(routes_path_loading).associate_with(LoadedFile.for(path))
373
+ end
273
374
  end
274
375
 
275
376
  result
@@ -282,16 +383,17 @@ module RailsDevelopmentBoost
282
383
  yield
283
384
  end
284
385
  end
285
-
286
- def unprotected_remove_constant(const_name)
287
- if qualified_const_defined?(const_name) && object = const_name.constantize
288
- handle_connected_constants(object, const_name)
289
- LoadedFile.unload_files_with_const!(const_name)
290
- if object.kind_of?(Module)
291
- remove_parent_modules_if_autoloaded(object)
292
- remove_child_module_constants(object, const_name)
293
- end
386
+
387
+ def schedule_dependent_constants_for_removal(const_name, object)
388
+ handle_connected_constants(object, const_name)
389
+ LoadedFile.schedule_for_unloading_files_with_const!(const_name)
390
+ if object.kind_of?(Module)
391
+ remove_parent_modules_if_autoloaded(object)
392
+ remove_child_module_constants(object, const_name)
294
393
  end
394
+ end
395
+
396
+ def unprotected_remove_constant(const_name, object)
295
397
  result = remove_constant_without_handling_of_connections(const_name)
296
398
  clear_tracks_of_removed_const(const_name, object)
297
399
  result
@@ -299,17 +401,19 @@ module RailsDevelopmentBoost
299
401
 
300
402
  def error_loading_file(file_path, e)
301
403
  LoadedFile.for(file_path).stale! if LoadedFile.loaded?(file_path)
302
- @load_failure = true
404
+ # only the errors that blow through the full stack are load failures, this lets user code handle failed load failures by rescuing raised exceptions without triggering a full dependecies reload
405
+ @load_failure = true if currently_loading.size == 1
303
406
  raise e
304
407
  end
305
408
 
306
409
  def handle_connected_constants(object, const_name)
307
410
  return unless Module === object && qualified_const_defined?(const_name)
411
+ remove_nested_constants(const_name)
308
412
  remove_explicit_dependencies_of(const_name)
309
413
  remove_dependent_modules(object)
414
+ # TODO move these into the cleanup phase
310
415
  update_activerecord_related_references(object)
311
416
  update_mongoid_related_references(object)
312
- remove_nested_constants(const_name)
313
417
  end
314
418
 
315
419
  def remove_nested_constants(const_name)
@@ -317,7 +421,7 @@ module RailsDevelopmentBoost
317
421
  end
318
422
 
319
423
  def remove_nested_constant(parent_const, child_const)
320
- remove_constant(child_const)
424
+ schedule_const_for_unloading(child_const)
321
425
  end
322
426
 
323
427
  # AS::Dependencies doesn't track same-file nested constants, so we need to look out for them on our own.
@@ -339,7 +443,7 @@ module RailsDevelopmentBoost
339
443
  end
340
444
 
341
445
  def remove_autoloaded_parent_module(initial_object, parent_object)
342
- remove_constant(parent_object._mod_name)
446
+ schedule_const_for_unloading(parent_object._mod_name)
343
447
  end
344
448
 
345
449
  def autoloaded_object?(object) # faster than going through Dependencies.autoloaded?
@@ -373,7 +477,7 @@ module RailsDevelopmentBoost
373
477
  end
374
478
 
375
479
  def remove_child_module_constant(parent_object, full_child_const_name)
376
- remove_constant(full_child_const_name)
480
+ schedule_const_for_unloading(full_child_const_name)
377
481
  end
378
482
 
379
483
  def remove_explicit_dependencies_of(const_name)
@@ -385,21 +489,23 @@ module RailsDevelopmentBoost
385
489
  end
386
490
 
387
491
  def remove_explicit_dependency(const_name, depending_const)
388
- remove_constant(depending_const)
492
+ schedule_const_for_unloading(depending_const)
389
493
  end
390
494
 
391
495
  def clear_tracks_of_removed_const(const_name, object = nil)
392
496
  autoloaded_constants.delete(const_name)
393
- @module_cache.remove_const(const_name, object)
497
+ # @module_cache might be nil if remove_constant has been called with a non-existent constant, ie: it hasn't been checked with `qualified_const_defined?`. Because AS::Dep doesn't blow, neither
498
+ # should we.
499
+ @module_cache.remove_const(const_name, object) if @module_cache
394
500
  LoadedFile.const_unloaded(const_name)
395
501
  end
396
502
 
397
503
  def remove_dependent_modules(mod)
398
- module_cache.each_dependent_on(mod) {|other| remove_dependent_constant(mod, other)}
504
+ @module_cache.each_dependent_on(mod) {|other| remove_dependent_constant(mod, other)}
399
505
  end
400
506
 
401
507
  def remove_dependent_constant(original_module, dependent_module)
402
- remove_constant(dependent_module._mod_name)
508
+ schedule_const_for_unloading(dependent_module._mod_name)
403
509
  end
404
510
 
405
511
  AR_REFLECTION_CACHES = [:@klass]
@@ -419,10 +525,10 @@ module RailsDevelopmentBoost
419
525
  def update_mongoid_related_references(klass)
420
526
  if defined?(Mongoid::Document) && klass < Mongoid::Document
421
527
  while (superclass = Util.first_non_anonymous_superclass(superclass || klass)) != Object && superclass < Mongoid::Document
422
- remove_constant(superclass._mod_name) # this is necessary to nuke the @_types caches
528
+ schedule_const_for_unloading(superclass._mod_name) # this is necessary to nuke the @_types caches
423
529
  end
424
530
 
425
- module_cache.each_dependent_on(Mongoid::Document) do |model|
531
+ @module_cache.each_dependent_on(Mongoid::Document) do |model|
426
532
  clean_up_relation_caches(model.relations, klass, MONGOID_RELATION_CACHES)
427
533
  end
428
534
  end
@@ -435,20 +541,5 @@ module RailsDevelopmentBoost
435
541
  end
436
542
  end
437
543
  end
438
-
439
- def module_cache
440
- @module_cache ||= ModuleCache.new
441
- end
442
-
443
- def prevent_further_removal_of(const_name)
444
- return if constants_being_removed.include?(const_name)
445
-
446
- constants_being_removed << const_name
447
- begin
448
- yield
449
- ensure
450
- constants_being_removed.delete(const_name)
451
- end
452
- end
453
544
  end
454
545
  end
@@ -2,7 +2,7 @@ module RailsDevelopmentBoost
2
2
  module DependenciesPatch
3
3
  module InstrumentationPatch
4
4
  module Instrumenter
5
- delegate :boost_log, :to => 'ActiveSupport::Dependencies'
5
+ delegate :boost_log, :boost_log_nested, :boost_log_schedule_const_removal, :to => 'ActiveSupport::Dependencies'
6
6
 
7
7
  def self.included(mod)
8
8
  mod.extend(ClassMethods)
@@ -38,9 +38,14 @@ module RailsDevelopmentBoost
38
38
  add_constants_without_instrumentation(new_constants)
39
39
  end
40
40
 
41
- def unload_dependent_file_with_instrumentation(dependent_file)
42
- boost_log('UNLOAD_DEPENDENT', "#{boost_inspect}: #{dependent_file.boost_inspect}")
43
- unload_dependent_file_without_instrumentation(dependent_file)
41
+ def dependent_file_schedule_for_unloading_with_instrumentation!(dependent_file)
42
+ boost_log('SCHEDULE_DEPENDENT', "#{boost_inspect}: #{dependent_file.boost_inspect}")
43
+ dependent_file_schedule_for_unloading_without_instrumentation!(dependent_file)
44
+ end
45
+
46
+ def schedule_const_for_unloading_with_instrumentation(const_name)
47
+ boost_log_schedule_const_removal('SCHEDULE_REMOVAL', const_name, const_name)
48
+ schedule_const_for_unloading_without_instrumentation(const_name)
44
49
  end
45
50
 
46
51
  private
@@ -69,9 +74,9 @@ module RailsDevelopmentBoost
69
74
  end
70
75
  end
71
76
 
72
- def unload_containing_file_with_instrumentation(const_name, file)
73
- boost_log('UNLOAD_CONTAINING_FILE', "#{const_name} -> #{file.boost_inspect}")
74
- unload_containing_file_without_instrumentation(const_name, file)
77
+ def schedule_containing_file_with_instrumentation(const_name, file)
78
+ boost_log('SCHEDULE_CONTAINING_FILE', "#{const_name} -> #{file.boost_inspect}")
79
+ schedule_containing_file_without_instrumentation(const_name, file)
75
80
  end
76
81
  end
77
82
  end
@@ -79,14 +84,14 @@ module RailsDevelopmentBoost
79
84
  module Files
80
85
  include Instrumenter
81
86
 
82
- def unload_modified_file_with_instrumentation(file)
87
+ def schedule_modified_file_with_instrumentation(file)
83
88
  boost_log('CHANGED', "#{file.boost_inspect}")
84
- unload_modified_file_without_instrumentation(file)
89
+ boost_log_nested { schedule_modified_file_without_instrumentation(file) }
85
90
  end
86
91
 
87
- def unload_decorator_file_with_instrumentation(file)
88
- boost_log('UNLOAD_DECORATOR_FILE', "#{file.boost_inspect}")
89
- unload_decorator_file_without_instrumentation(file)
92
+ def schedule_decorator_file_with_instrumentation(file)
93
+ boost_log('SCHEDULE_DECORATOR_FILE', "#{file.boost_inspect}")
94
+ schedule_decorator_file_without_instrumentation(file)
90
95
  end
91
96
  end
92
97
 
@@ -123,15 +128,23 @@ module RailsDevelopmentBoost
123
128
  raw_boost_log("#{ "[#{action}] " if action}#{msg}")
124
129
  end
125
130
 
126
- private
127
- def unprotected_remove_constant(const_name)
128
- boost_log('REMOVING', const_name)
131
+ def boost_log_schedule_const_removal(action, msg, const_name)
132
+ action = "#{action} | #{ActiveSupport::Dependencies.constants_to_remove.seen?(const_name) ? 'SKIP' : 'SCHEDULED'}"
133
+ boost_log(action, msg)
134
+ end
135
+
136
+ def boost_log_nested
129
137
  @removal_nesting = (@removal_nesting || 0) + 1
130
- super
138
+ yield
131
139
  ensure
132
140
  @removal_nesting -= 1
133
141
  end
134
142
 
143
+ private
144
+ def schedule_dependent_constants_for_removal(const_name, object)
145
+ boost_log_nested { super }
146
+ end
147
+
135
148
  def error_loading_file(file_path, e)
136
149
  description = RailsDevelopmentBoost::LoadedFile.loaded?(file_path) ? RailsDevelopmentBoost::LoadedFile.for(file_path).boost_inspect : file_path
137
150
  boost_log('ERROR_WHILE_LOADING', "#{description}: #{e.inspect}")
@@ -139,32 +152,34 @@ module RailsDevelopmentBoost
139
152
  end
140
153
 
141
154
  def remove_explicit_dependency(const_name, depending_const)
142
- boost_log('EXPLICIT_DEPENDENCY', "#{const_name} -> #{depending_const}")
155
+ boost_log_schedule_const_removal('EXPLICIT_DEPENDENCY', "#{const_name} -> #{depending_const}", depending_const)
143
156
  super
144
157
  end
145
158
 
146
159
  def remove_dependent_constant(original_module, dependent_module)
147
- boost_log('DEPENDENT_MODULE', "#{original_module._mod_name} -> #{dependent_module._mod_name}")
160
+ const_name = dependent_module._mod_name
161
+ boost_log_schedule_const_removal('DEPENDENT_MODULE', "#{original_module._mod_name} -> #{const_name}", const_name)
148
162
  super
149
163
  end
150
164
 
151
165
  def remove_autoloaded_parent_module(initial_object, parent_object)
152
- boost_log('REMOVE_PARENT', "#{initial_object._mod_name} -> #{parent_object._mod_name}")
166
+ const_name = parent_object._mod_name
167
+ boost_log_schedule_const_removal('REMOVE_PARENT', "#{initial_object._mod_name} -> #{const_name}", const_name)
153
168
  super
154
169
  end
155
170
 
156
171
  def remove_child_module_constant(parent_object, full_child_const_name)
157
- boost_log('REMOVE_CHILD', "#{parent_object._mod_name} -> #{full_child_const_name}")
172
+ boost_log_schedule_const_removal('REMOVE_CHILD', "#{parent_object._mod_name} -> #{full_child_const_name}", full_child_const_name)
158
173
  super
159
174
  end
160
175
 
161
176
  def remove_nested_constant(parent_const, child_const)
162
- boost_log('REMOVE_NESTED', "#{parent_const} :: #{child_const.sub(/\A#{parent_const}::/, '')}")
177
+ boost_log_schedule_const_removal('REMOVE_NESTED', "#{parent_const} :: #{child_const.sub(/\A#{parent_const}::/, '')}", child_const)
163
178
  super
164
179
  end
165
180
 
166
181
  def raw_boost_log(msg)
167
- Rails.logger.info("[DEV-BOOST] #{"\t" * (@removal_nesting || 0)}#{msg}")
182
+ Rails.logger.info("[DEV-BOOST] #{" " * (@removal_nesting || 0)}#{msg}")
168
183
  end
169
184
  end
170
185
  end
@@ -3,8 +3,16 @@ require 'active_support/descendants_tracker'
3
3
  module RailsDevelopmentBoost
4
4
  module DescendantsTrackerPatch
5
5
  def self.apply!
6
+ # removing the .clear method across all Rails/Ruby versions
7
+ begin
8
+ ActiveSupport::DescendantsTracker.send(:remove_method, :clear)
9
+ rescue NameError
10
+ end
11
+ begin
12
+ ActiveSupport::DescendantsTracker.singleton_class.send(:remove_method, :clear)
13
+ rescue NameError
14
+ end
6
15
  ActiveSupport::DescendantsTracker.extend self
7
- ActiveSupport::DescendantsTracker.singleton_class.remove_possible_method :clear
8
16
  end
9
17
 
10
18
  def delete(klass)
@@ -5,11 +5,10 @@ module RailsDevelopmentBoost
5
5
  end
6
6
 
7
7
  def load(file, wrap = false)
8
- expanded_path = File.expand_path(file)
8
+ real_path = DependenciesPatch::Util.load_path_to_real_path(file)
9
9
  # force the manual #load calls for autoloadable files to go through the AS::Dep stack
10
- if ActiveSupport::Dependencies.in_autoload_path?(expanded_path)
11
- expanded_path << '.rb' unless expanded_path =~ /\.(rb|rake)\Z/
12
- ActiveSupport::Dependencies.load_file_from_explicit_load(expanded_path)
10
+ if ActiveSupport::Dependencies.in_autoload_path?(real_path)
11
+ ActiveSupport::Dependencies.load_file_from_explicit_load(real_path)
13
12
  else
14
13
  super
15
14
  end
@@ -1,40 +1,69 @@
1
+ require 'set'
2
+
1
3
  module RailsDevelopmentBoost
2
4
  class LoadedFile
3
5
  class Files < Hash
4
6
  def initialize(*args)
7
+ @directories = {}
5
8
  super {|hash, file_path| hash[file_path] = LoadedFile.new(file_path)}
6
9
  end
7
10
 
8
- def unload_modified!
9
- each_file_unload_if_changed {|file| file.changed?}
11
+ def []=(file_path, loaded_file)
12
+ (@directories[loaded_file.dirname] ||= Set.new) << loaded_file
13
+ super
14
+ end
15
+
16
+ def delete(file_path)
17
+ if loaded_file = super
18
+ dirname = loaded_file.dirname
19
+ if @directories[dirname].delete(loaded_file).empty?
20
+ @directories.delete(dirname)
21
+ end
22
+ end
23
+ loaded_file
10
24
  end
11
25
 
12
- def each_file_unload_if_changed
26
+ def unload_modified!(filter_directories = nil)
13
27
  unloaded_something = false
14
- values.each do |file|
15
- if yield(file)
16
- unload_modified_file(file)
28
+ find_files_in(filter_directories).each do |file|
29
+ if file.changed?
30
+ schedule_modified_file(file)
17
31
  unloaded_something = true
18
32
  end
19
33
  end
20
34
  if unloaded_something
21
35
  values.each do |file|
22
- unload_decorator_file(file) if file.decorator_like?
36
+ schedule_decorator_file(file) if file.decorator_like?
23
37
  end
24
38
  end
39
+ ActiveSupport::Dependencies.process_consts_scheduled_for_removal
25
40
  unloaded_something
26
41
  end
27
42
 
28
- def unload_modified_file(file)
29
- file.unload!
43
+ def find_files_in(filter_directories = nil)
44
+ if filter_directories
45
+ arr = []
46
+ @directories.each_pair do |dirname, files|
47
+ arr.concat(files.to_a) if filter_directories.any? {|filter_directory| dirname.starts_with?(filter_directory)}
48
+ end
49
+ arr
50
+ else
51
+ values
52
+ end
30
53
  end
31
54
 
32
- def unload_decorator_file(file)
33
- file.unload!
55
+ def schedule_modified_file(file)
56
+ file.schedule_consts_for_unloading!
57
+ end
58
+
59
+ def schedule_decorator_file(file)
60
+ file.schedule_consts_for_unloading!
34
61
  end
35
62
 
36
63
  def constants
37
- values.map(&:constants).flatten
64
+ arr = []
65
+ each_value {|file| arr.concat(file.constants)}
66
+ arr
38
67
  end
39
68
 
40
69
  def stored?(file)
@@ -110,16 +139,20 @@ module RailsDevelopmentBoost
110
139
  @constants |= new_constants
111
140
  end
112
141
 
142
+ def dirname
143
+ File.dirname(@path)
144
+ end
145
+
113
146
  # "decorator" files are popular with certain Rails frameworks (spree/refinerycms etc.) they don't define their own constants, instead
114
147
  # they are usually used for adding methods to other classes via Model.class_eval { def meth; end }
115
148
  def decorator_like?
116
149
  @constants.empty? && !INTERDEPENDENCIES[self]
117
150
  end
118
151
 
119
- def unload!
152
+ def schedule_consts_for_unloading!
120
153
  guard_double_unloading do
121
- INTERDEPENDENCIES.each_dependent_on(self) {|dependent_file| unload_dependent_file(dependent_file)}
122
- @constants.dup.each {|const| ActiveSupport::Dependencies.remove_constant(const)}
154
+ INTERDEPENDENCIES.each_dependent_on(self) {|dependent_file| dependent_file_schedule_for_unloading!(dependent_file)}
155
+ @constants.dup.each {|const| schedule_const_for_unloading(const)}
123
156
  clean_up_if_necessary
124
157
  end
125
158
  end
@@ -166,8 +199,8 @@ module RailsDevelopmentBoost
166
199
  @path.eql?(other)
167
200
  end
168
201
 
169
- def unload_dependent_file(dependent_file)
170
- dependent_file.unload!
202
+ def dependent_file_schedule_for_unloading!(dependent_file)
203
+ dependent_file.schedule_consts_for_unloading!
171
204
  end
172
205
 
173
206
  def guard_double_unloading
@@ -206,6 +239,10 @@ module RailsDevelopmentBoost
206
239
  INTERDEPENDENCIES.each_dependent_on(self, &:stale!)
207
240
  end
208
241
 
242
+ def schedule_const_for_unloading(const_name)
243
+ ActiveSupport::Dependencies.schedule_const_for_unloading(const_name)
244
+ end
245
+
209
246
  class << self
210
247
  def unload_modified!
211
248
  LOADED.unload_modified!
@@ -227,12 +264,12 @@ module RailsDevelopmentBoost
227
264
  CONSTANTS_TO_FILES[const_name]
228
265
  end
229
266
 
230
- def unload_files_with_const!(const_name)
231
- CONSTANTS_TO_FILES.each_file_with_const(const_name) {|file| unload_containing_file(const_name, file)}
267
+ def schedule_for_unloading_files_with_const!(const_name)
268
+ CONSTANTS_TO_FILES.each_file_with_const(const_name) {|file| schedule_containing_file(const_name, file)}
232
269
  end
233
270
 
234
- def unload_containing_file(const_name, file)
235
- file.unload!
271
+ def schedule_containing_file(const_name, file)
272
+ file.schedule_consts_for_unloading!
236
273
  end
237
274
 
238
275
  def const_unloaded(const_name)
@@ -250,4 +287,28 @@ module RailsDevelopmentBoost
250
287
  File.mtime(@path).to_i rescue nil
251
288
  end
252
289
  end
290
+
291
+ class RoutesLoadedFile < LoadedFile
292
+ def decorator_like?
293
+ false
294
+ end
295
+
296
+ def changed?
297
+ false
298
+ end
299
+
300
+ def schedule_consts_for_unloading!
301
+ Reloader.routes_reloader.force_execute!
302
+ end
303
+
304
+ def add_constants(new_constants)
305
+ end
306
+
307
+ def clean_up_if_necessary
308
+ end
309
+
310
+ def self.for(file_path)
311
+ LOADED.loaded?(file_path) ? LOADED[file_path] : LOADED[file_path] = new(file_path)
312
+ end
313
+ end
253
314
  end
@@ -1,10 +1,41 @@
1
1
  module RailsDevelopmentBoost
2
2
  module Reloader # replacement for the Rails' post fa1d9a file_update_checker
3
+ module RoutesReloaderPatch
4
+ def force_execute!
5
+ @force_execute = true
6
+ end
7
+
8
+ def updated?
9
+ @force_execute = true if result = super
10
+ result
11
+ end
12
+
13
+ def execute
14
+ if RailsDevelopmentBoost.reload_routes_on_any_change || @in_execute_if_updated || @force_execute || updated?
15
+ @force_execute = false
16
+ super
17
+ end
18
+ end
19
+
20
+ def load(file, wrap = false)
21
+ ActiveSupport::Dependencies.loading_routes_file(file) { super }
22
+ end
23
+
24
+ def execute_if_updated
25
+ old_in_execute_if_updated = @in_execute_if_updated
26
+ @in_execute_if_updated = true
27
+ super
28
+ ensure
29
+ @in_execute_if_updated = old_in_execute_if_updated
30
+ end
31
+ end
32
+
3
33
  extend self
4
34
 
5
35
  def hook_in!
6
36
  Rails.application.reloaders.unshift(self)
7
37
  ActionDispatch::Reloader.to_prepare(:prepend => true) { RailsDevelopmentBoost::Reloader.execute_if_updated }
38
+ patch_routes_reloader! if Rails::VERSION::MAJOR >= 4
8
39
  end
9
40
 
10
41
  def execute
@@ -20,7 +51,19 @@ module RailsDevelopmentBoost
20
51
 
21
52
  alias_method :updated?, :execute
22
53
 
54
+ def routes_reloader
55
+ Rails.application.respond_to?(:routes_reloader) && Rails.application.routes_reloader
56
+ end
57
+
23
58
  private
59
+ # Rails 4.0+ calls routes_reloader.execute instead of routes_reloader.execute_if_updated because an autoloaded Rails::Engine might be mounted via routes.rb, therefore if any constants
60
+ # are unloaded this triggers the reloading of routes.rb, we would like to avoid that.
61
+ def patch_routes_reloader!
62
+ if reloader = routes_reloader
63
+ reloader.extend(RoutesReloaderPatch)
64
+ end
65
+ end
66
+
24
67
  def init
25
68
  Rails.application.reloaders.delete_if do |reloader|
26
69
  if rails_file_checker?(reloader)
@@ -43,7 +86,7 @@ module RailsDevelopmentBoost
43
86
  if (dir_glob = reloader.instance_variable_get(:@glob)).kind_of?(String)
44
87
  autoload_paths = ActiveSupport::Dependencies.autoload_paths
45
88
  dir_glob.sub(/\A\{/, '').sub(/\}\Z/, '').split(',').all? do |glob_path|
46
- autoload_paths.any? {|autoload_path| glob_path.starts_with?(autoload_path)}
89
+ autoload_paths.any? {|autoload_path| glob_path.starts_with?(autoload_path.to_s)}
47
90
  end
48
91
  end
49
92
  end
metadata CHANGED
@@ -1,50 +1,40 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rails-dev-boost
3
- version: !ruby/object:Gem::Version
4
- hash: 21
5
- prerelease:
6
- segments:
7
- - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Roman Le Negrate
14
8
  - thedarkone
15
9
  autorequire:
16
10
  bindir: bin
17
11
  cert_chain: []
18
-
19
- date: 2012-10-02 00:00:00 +02:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
23
- name: rails
24
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
28
- - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 7
31
- segments:
32
- - 3
33
- - 0
34
- version: "3.0"
12
+ date: 2014-04-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.0'
35
21
  type: :runtime
36
- version_requirements: *id001
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '3.0'
37
28
  description: Make your Rails app 10 times faster in development mode
38
29
  email: roman.lenegrate@gmail.com
39
30
  executables: []
40
-
41
31
  extensions: []
42
-
43
- extra_rdoc_files:
32
+ extra_rdoc_files:
44
33
  - LICENSE
45
34
  - README.markdown
46
- files:
35
+ files:
47
36
  - lib/rails-dev-boost.rb
37
+ - lib/rails_development_boost/async/reactor.rb
48
38
  - lib/rails_development_boost/async.rb
49
39
  - lib/rails_development_boost/dependencies_patch/instrumentation_patch.rb
50
40
  - lib/rails_development_boost/dependencies_patch.rb
@@ -92,41 +82,31 @@ files:
92
82
  - LICENSE
93
83
  - README.markdown
94
84
  - VERSION
95
- has_rdoc: true
96
85
  homepage: http://github.com/thedarkone/rails-dev-boost
97
86
  licenses: []
98
-
87
+ metadata: {}
99
88
  post_install_message:
100
- rdoc_options:
89
+ rdoc_options:
101
90
  - --charset=UTF-8
102
- require_paths:
91
+ require_paths:
103
92
  - lib
104
- required_ruby_version: !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- hash: 3
110
- segments:
111
- - 0
112
- version: "0"
113
- required_rubygems_version: !ruby/object:Gem::Requirement
114
- none: false
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- hash: 3
119
- segments:
120
- - 0
121
- version: "0"
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
122
103
  requirements: []
123
-
124
104
  rubyforge_project:
125
- rubygems_version: 1.5.2
105
+ rubygems_version: 2.0.14
126
106
  signing_key:
127
107
  specification_version: 3
128
108
  summary: Speeds up Rails development mode
129
- test_files:
109
+ test_files:
130
110
  - test/constants/active_record/comment.rb
131
111
  - test/constants/active_record/message.rb
132
112
  - test/constants/active_record/other.rb