rails-dev-boost 0.1.1 → 0.2.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.
- data/README.markdown +240 -39
- data/VERSION +1 -1
- data/lib/rails-dev-boost.rb +1 -0
- data/lib/rails_development_boost.rb +44 -15
- data/lib/rails_development_boost/async.rb +73 -0
- data/lib/rails_development_boost/dependencies_patch.rb +245 -123
- data/lib/rails_development_boost/dependencies_patch/instrumentation_patch.rb +171 -0
- data/lib/rails_development_boost/descendants_tracker_patch.rb +2 -0
- data/lib/rails_development_boost/loadable_patch.rb +18 -0
- data/lib/rails_development_boost/loaded_file.rb +207 -30
- data/lib/rails_development_boost/observable_patch.rb +38 -0
- data/lib/rails_development_boost/reference_cleanup_patch.rb +14 -0
- data/lib/rails_development_boost/reference_patch.rb +4 -0
- data/lib/rails_development_boost/reloader.rb +51 -0
- data/lib/rails_development_boost/required_dependency.rb +36 -0
- data/lib/rails_development_boost/view_helpers_patch.rb +5 -1
- metadata +28 -26
- data/.gitignore +0 -1
- data/Rakefile +0 -52
- data/TODO.txt +0 -2
- data/init.rb +0 -3
- data/rails-dev-boost.gemspec +0 -116
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/dependencies'
|
2
|
+
|
1
3
|
module RailsDevelopmentBoost
|
2
4
|
module DependenciesPatch
|
3
5
|
module LoadablePatch
|
@@ -9,6 +11,8 @@ module RailsDevelopmentBoost
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def self.apply!
|
14
|
+
return if applied?
|
15
|
+
|
12
16
|
# retain the original method in case the application overwrites it on its modules/klasses
|
13
17
|
Module.send :alias_method, :_mod_name, :name
|
14
18
|
|
@@ -34,34 +38,130 @@ module RailsDevelopmentBoost
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def self.debug!
|
37
|
-
if
|
41
|
+
if applied?
|
38
42
|
InstrumentationPatch.apply!
|
39
43
|
else
|
40
44
|
@do_instrument = true
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
def self.async!
|
49
|
+
@async = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.async?
|
53
|
+
@async
|
54
|
+
end
|
48
55
|
|
49
|
-
|
50
|
-
|
56
|
+
def self.applied?
|
57
|
+
ActiveSupport::Dependencies < self
|
58
|
+
end
|
51
59
|
|
60
|
+
autoload :InstrumentationPatch, 'rails_development_boost/dependencies_patch/instrumentation_patch'
|
61
|
+
|
52
62
|
mattr_accessor :constants_being_removed
|
53
63
|
self.constants_being_removed = []
|
54
64
|
|
55
65
|
mattr_accessor :explicit_dependencies
|
56
66
|
self.explicit_dependencies = {}
|
57
67
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
68
|
+
mattr_accessor :currently_loading
|
69
|
+
self.currently_loading = []
|
70
|
+
|
71
|
+
module Util
|
72
|
+
extend self
|
73
|
+
|
74
|
+
def anonymous_const?(mod)
|
75
|
+
anonymous_const_name?(mod._mod_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
def anonymous_const_name?(const_name)
|
79
|
+
!const_name || const_name.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def first_non_anonymous_superclass(klass)
|
83
|
+
while (klass = klass.superclass) && anonymous_const?(klass); end
|
84
|
+
klass
|
85
|
+
end
|
86
|
+
|
87
|
+
NOTHING = ''
|
88
|
+
def in_autoloaded_namespace?(const_name) # careful, modifies passed in const_name!
|
89
|
+
begin
|
90
|
+
return true if LoadedFile.loaded_constant?(const_name)
|
91
|
+
end while const_name.sub!(/::[^:]+\Z/, NOTHING)
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ModuleCache
|
97
|
+
def initialize
|
98
|
+
@classes, @modules = [], []
|
99
|
+
ObjectSpace.each_object(Module) {|mod| self << mod if relevant?(mod)}
|
100
|
+
@singleton_ancestors = Hash.new {|h, klass| h[klass] = klass.singleton_class.ancestors}
|
101
|
+
end
|
102
|
+
|
103
|
+
def each_dependent_on(mod, &block)
|
104
|
+
arr = []
|
105
|
+
each_inheriting_from(mod) do |other|
|
106
|
+
mod_name = other._mod_name
|
107
|
+
arr << other if qualified_const_defined?(mod_name) && mod_name.constantize == other
|
108
|
+
end
|
109
|
+
arr.each(&block)
|
110
|
+
end
|
111
|
+
|
112
|
+
def remove_const(const_name, object)
|
113
|
+
if object && Class === object
|
114
|
+
remove_const_from_colletion(@classes, const_name, object)
|
115
|
+
else
|
116
|
+
[@classes, @modules].each {|collection| remove_const_from_colletion(collection, const_name, object)}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def <<(mod)
|
121
|
+
(Class === mod ? @classes : @modules) << mod
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
def relevant?(mod)
|
126
|
+
const_name = mod._mod_name
|
127
|
+
!Util.anonymous_const_name?(const_name) && Util.in_autoloaded_namespace?(const_name)
|
128
|
+
end
|
129
|
+
|
130
|
+
def remove_const_from_colletion(collection, const_name, object)
|
131
|
+
if object
|
132
|
+
collection.delete(object)
|
133
|
+
else
|
134
|
+
collection.delete_if {|mod| mod._mod_name == const_name}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def each_inheriting_from(mod_or_class)
|
139
|
+
if Class === mod_or_class
|
140
|
+
@classes.each do |other_class|
|
141
|
+
yield other_class if other_class < mod_or_class && Util.first_non_anonymous_superclass(other_class) == mod_or_class
|
142
|
+
end
|
143
|
+
else
|
144
|
+
[@classes, @modules].each do |collection|
|
145
|
+
collection.each do |other|
|
146
|
+
yield other if other < mod_or_class || @singleton_ancestors[other].include?(mod_or_class)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def qualified_const_defined?(const_name)
|
153
|
+
ActiveSupport::Dependencies.qualified_const_defined?(const_name)
|
62
154
|
end
|
63
155
|
end
|
64
156
|
|
157
|
+
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 }
|
163
|
+
end
|
164
|
+
|
65
165
|
def remove_explicitely_unloadable_constants!
|
66
166
|
explicitly_unloadable_constants.each { |const| remove_constant(const) }
|
67
167
|
end
|
@@ -71,26 +171,20 @@ module RailsDevelopmentBoost
|
|
71
171
|
end
|
72
172
|
|
73
173
|
# Augmented `load_file'.
|
74
|
-
def load_file_with_constant_tracking(path, *args
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
new_constants = autoloaded_constants - file_map.values.map(&:constants).flatten
|
79
|
-
|
80
|
-
# Associate newly loaded constants to the file just loaded
|
81
|
-
associate_constants_to_file(new_constants, path)
|
174
|
+
def load_file_with_constant_tracking(path, *args)
|
175
|
+
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
|
177
|
+
load_file_with_constant_tracking_internal(path, args)
|
82
178
|
end
|
83
|
-
|
84
|
-
result
|
85
179
|
end
|
86
180
|
|
87
181
|
def now_loading(path)
|
88
|
-
|
182
|
+
currently_loading << path
|
89
183
|
yield
|
90
184
|
rescue Exception => e
|
91
|
-
error_loading_file(
|
185
|
+
error_loading_file(currently_loading.last, e)
|
92
186
|
ensure
|
93
|
-
|
187
|
+
currently_loading.pop
|
94
188
|
end
|
95
189
|
|
96
190
|
def associate_constants_to_file(constants, file_path)
|
@@ -98,16 +192,13 @@ module RailsDevelopmentBoost
|
|
98
192
|
constants.map!(&:freeze)
|
99
193
|
file_path.freeze
|
100
194
|
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
def loaded_file_for(file_path)
|
105
|
-
file_map[file_path] ||= LoadedFile.new(file_path)
|
195
|
+
LoadedFile.for(file_path).add_constants(constants)
|
106
196
|
end
|
107
197
|
|
108
198
|
# Augmented `remove_constant'.
|
109
199
|
def remove_constant_with_handling_of_connections(const_name)
|
110
|
-
|
200
|
+
async_synchronize do
|
201
|
+
module_cache # make sure module_cache has been created
|
111
202
|
prevent_further_removal_of(const_name) do
|
112
203
|
unprotected_remove_constant(const_name)
|
113
204
|
end
|
@@ -116,31 +207,89 @@ module RailsDevelopmentBoost
|
|
116
207
|
|
117
208
|
def required_dependency(file_name)
|
118
209
|
# Rails uses require_dependency for loading helpers, we are however dealing with the helper problem elsewhere, so we can skip them
|
119
|
-
if
|
120
|
-
|
121
|
-
|
210
|
+
return if (curr_loading = currently_loading.last) && curr_loading =~ /_controller(?:\.rb)?\Z/ && file_name =~ /_helper(?:\.rb)?\Z/
|
211
|
+
|
212
|
+
if full_path = ActiveSupport::Dependencies.search_for_file(file_name)
|
213
|
+
RequiredDependency.new(curr_loading).related_files.each do |related_file|
|
214
|
+
LoadedFile.relate_files(related_file, full_path)
|
122
215
|
end
|
123
216
|
end
|
124
217
|
end
|
125
218
|
|
126
219
|
def add_explicit_dependency(parent, child)
|
127
|
-
(
|
220
|
+
if !Util.anonymous_const_name?(child_mod_name = child._mod_name) && !Util.anonymous_const_name?(parent_mod_name = parent._mod_name)
|
221
|
+
((explicit_dependencies[parent_mod_name] ||= []) << child_mod_name).uniq!
|
222
|
+
end
|
128
223
|
end
|
129
224
|
|
130
225
|
def handle_already_autoloaded_constants! # we might be late to the party and other gems/plugins might have already triggered autoloading of some constants
|
131
226
|
loaded.each do |require_path|
|
132
|
-
|
227
|
+
unless load_once_path?(require_path)
|
228
|
+
associate_constants_to_file(autoloaded_constants, "#{require_path}.rb") # slightly heavy-handed..
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def in_autoload_path?(expanded_file_path)
|
234
|
+
autoload_paths.any? do |autoload_path|
|
235
|
+
autoload_path = autoload_path.to_s # handle Pathnames
|
236
|
+
expanded_file_path.starts_with?(autoload_path.ends_with?('/') ? autoload_path : "#{autoload_path}/")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def load_file_from_explicit_load(expanded_path)
|
241
|
+
unless LoadedFile.loaded?(expanded_path)
|
242
|
+
load_file(expanded_path)
|
243
|
+
if LoadedFile.loaded?(expanded_path) && (file = LoadedFile.for(expanded_path)).decorator_like?
|
244
|
+
file.associate_to_greppable_constants
|
245
|
+
end
|
133
246
|
end
|
134
247
|
end
|
135
248
|
|
136
249
|
private
|
250
|
+
def unload_modified_files_internal!
|
251
|
+
log_call
|
252
|
+
if DependenciesPatch.async?
|
253
|
+
# because of the forking ruby servers (threads don't survive the forking),
|
254
|
+
# the Async heartbeat/init check needs to be here (instead of it being a boot time thing)
|
255
|
+
Async.heartbeat_check!
|
256
|
+
else
|
257
|
+
LoadedFile.unload_modified!
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def clear_load_failure
|
262
|
+
@load_failure.tap { @load_failure = false }
|
263
|
+
end
|
264
|
+
|
265
|
+
def load_file_with_constant_tracking_internal(path, args)
|
266
|
+
result = now_loading(path) { load_file_without_constant_tracking(path, *args) }
|
267
|
+
|
268
|
+
unless load_once_path?(path)
|
269
|
+
new_constants = autoloaded_constants - LoadedFile.loaded_constants
|
270
|
+
|
271
|
+
# Associate newly loaded constants to the file just loaded
|
272
|
+
associate_constants_to_file(new_constants, path)
|
273
|
+
end
|
274
|
+
|
275
|
+
result
|
276
|
+
end
|
277
|
+
|
278
|
+
def async_synchronize
|
279
|
+
if DependenciesPatch.async?
|
280
|
+
Async.synchronize { yield }
|
281
|
+
else
|
282
|
+
yield
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
137
286
|
def unprotected_remove_constant(const_name)
|
138
287
|
if qualified_const_defined?(const_name) && object = const_name.constantize
|
139
288
|
handle_connected_constants(object, const_name)
|
140
|
-
|
289
|
+
LoadedFile.unload_files_with_const!(const_name)
|
141
290
|
if object.kind_of?(Module)
|
142
291
|
remove_parent_modules_if_autoloaded(object)
|
143
|
-
remove_child_module_constants(object)
|
292
|
+
remove_child_module_constants(object, const_name)
|
144
293
|
end
|
145
294
|
end
|
146
295
|
result = remove_constant_without_handling_of_connections(const_name)
|
@@ -148,14 +297,9 @@ module RailsDevelopmentBoost
|
|
148
297
|
result
|
149
298
|
end
|
150
299
|
|
151
|
-
def unload_file(file)
|
152
|
-
file.constants.dup.each {|const| remove_constant(const)}
|
153
|
-
clean_up_if_no_constants(file)
|
154
|
-
end
|
155
|
-
alias_method :unload_modified_file, :unload_file
|
156
|
-
|
157
300
|
def error_loading_file(file_path, e)
|
158
|
-
|
301
|
+
LoadedFile.for(file_path).stale! if LoadedFile.loaded?(file_path)
|
302
|
+
@load_failure = true
|
159
303
|
raise e
|
160
304
|
end
|
161
305
|
|
@@ -164,32 +308,29 @@ module RailsDevelopmentBoost
|
|
164
308
|
remove_explicit_dependencies_of(const_name)
|
165
309
|
remove_dependent_modules(object)
|
166
310
|
update_activerecord_related_references(object)
|
311
|
+
update_mongoid_related_references(object)
|
167
312
|
remove_nested_constants(const_name)
|
168
313
|
end
|
169
314
|
|
170
315
|
def remove_nested_constants(const_name)
|
171
|
-
autoloaded_constants.grep(/\A#{const_name}::/)
|
316
|
+
autoloaded_constants.grep(/\A#{const_name}::/) { |const| remove_nested_constant(const_name, const) }
|
172
317
|
end
|
173
318
|
|
174
319
|
def remove_nested_constant(parent_const, child_const)
|
175
320
|
remove_constant(child_const)
|
176
321
|
end
|
177
322
|
|
178
|
-
def autoloaded_namespace_object?(object) # faster than going through Dependencies.autoloaded?
|
179
|
-
LoadedFile.constants_to_files[object._mod_name]
|
180
|
-
end
|
181
|
-
|
182
323
|
# AS::Dependencies doesn't track same-file nested constants, so we need to look out for them on our own.
|
183
324
|
# For example having loaded an abc.rb that looks like this:
|
184
325
|
# class Abc; class Inner; end; end
|
185
326
|
# AS::Dependencies would only add "Abc" constant name to its autoloaded_constants list, completely ignoring Abc::Inner. This in turn
|
186
327
|
# can cause problems for classes inheriting from Abc::Inner somewhere else in the app.
|
187
328
|
def remove_parent_modules_if_autoloaded(object)
|
188
|
-
unless
|
329
|
+
unless autoloaded_object?(object)
|
189
330
|
initial_object = object
|
190
331
|
|
191
332
|
while (object = object.parent) != Object
|
192
|
-
if
|
333
|
+
if autoloaded_object?(object)
|
193
334
|
remove_autoloaded_parent_module(initial_object, object)
|
194
335
|
break
|
195
336
|
end
|
@@ -201,39 +342,45 @@ module RailsDevelopmentBoost
|
|
201
342
|
remove_constant(parent_object._mod_name)
|
202
343
|
end
|
203
344
|
|
345
|
+
def autoloaded_object?(object) # faster than going through Dependencies.autoloaded?
|
346
|
+
LoadedFile.loaded_constant?(object._mod_name)
|
347
|
+
end
|
348
|
+
|
204
349
|
# AS::Dependencies doesn't track same-file nested constants, so we need to look out for them on our own and remove any dependent modules/constants
|
205
|
-
def remove_child_module_constants(object)
|
206
|
-
object.constants.each do |
|
350
|
+
def remove_child_module_constants(object, object_const_name)
|
351
|
+
object.constants.each do |child_const_name|
|
207
352
|
# we only care about "namespace" constants (classes/modules)
|
208
|
-
if
|
209
|
-
|
353
|
+
if (child_const = get_child_const(object, child_const_name)).kind_of?(Module)
|
354
|
+
# make sure this is not "const alias" created like this: module Y; end; module A; X = Y; end, const A::X is not a proper "namespacing module",
|
355
|
+
# but only an alias to Y module
|
356
|
+
if (full_child_const_name = child_const._mod_name) == "#{object_const_name}::#{child_const_name}"
|
357
|
+
remove_child_module_constant(object, full_child_const_name)
|
358
|
+
end
|
210
359
|
end
|
211
360
|
end
|
212
361
|
end
|
213
362
|
|
214
|
-
def
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
363
|
+
def get_child_const(object, child_const_name)
|
364
|
+
if local_const_defined?(object, child_const_name)
|
365
|
+
begin
|
366
|
+
object.const_get(child_const_name)
|
367
|
+
rescue NameError
|
368
|
+
# Apparently even though we get a list of constants through the native Module#constants and do a local_const_defined? check the const_get
|
369
|
+
# can still fail with a NameError (const undefined etc.)
|
370
|
+
# See https://github.com/thedarkone/rails-dev-boost/pull/33 for more details.
|
371
|
+
end
|
222
372
|
end
|
223
|
-
false
|
224
|
-
end
|
225
|
-
|
226
|
-
def remove_same_file_constants(const_name)
|
227
|
-
LoadedFile.each_file_with_const(const_name) {|file| unload_containing_file(const_name, file)}
|
228
373
|
end
|
229
374
|
|
230
|
-
def
|
231
|
-
|
375
|
+
def remove_child_module_constant(parent_object, full_child_const_name)
|
376
|
+
remove_constant(full_child_const_name)
|
232
377
|
end
|
233
378
|
|
234
379
|
def remove_explicit_dependencies_of(const_name)
|
235
380
|
if dependencies = explicit_dependencies.delete(const_name)
|
236
|
-
dependencies.
|
381
|
+
dependencies.each do |depending_const|
|
382
|
+
remove_explicit_dependency(const_name, depending_const) if LoadedFile.loaded_constant?(depending_const)
|
383
|
+
end
|
237
384
|
end
|
238
385
|
end
|
239
386
|
|
@@ -241,50 +388,21 @@ module RailsDevelopmentBoost
|
|
241
388
|
remove_constant(depending_const)
|
242
389
|
end
|
243
390
|
|
244
|
-
def clear_tracks_of_removed_const(const_name, object)
|
391
|
+
def clear_tracks_of_removed_const(const_name, object = nil)
|
245
392
|
autoloaded_constants.delete(const_name)
|
246
|
-
module_cache.
|
247
|
-
|
248
|
-
|
249
|
-
LoadedFile.each_file_with_const(const_name) do |file|
|
250
|
-
file.delete_constant(const_name)
|
251
|
-
clean_up_if_no_constants(file)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def clean_up_if_no_constants(file)
|
256
|
-
if file.constants.empty?
|
257
|
-
loaded.delete(file.require_path)
|
258
|
-
file_map.delete(file.path)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
def clean_up_references(const_name, object)
|
263
|
-
ActiveSupport::Dependencies::Reference.loose!(const_name)
|
264
|
-
ActiveSupport::DescendantsTracker.delete(object)
|
393
|
+
@module_cache.remove_const(const_name, object)
|
394
|
+
LoadedFile.const_unloaded(const_name)
|
265
395
|
end
|
266
396
|
|
267
397
|
def remove_dependent_modules(mod)
|
268
|
-
|
269
|
-
modules.dup.each do |other|
|
270
|
-
next unless other < mod || other.singleton_class.ancestors.include?(mod)
|
271
|
-
next unless first_non_anonymous_superclass(other) == mod if Class === mod
|
272
|
-
next unless qualified_const_defined?(other._mod_name) && other._mod_name.constantize == other
|
273
|
-
next unless in_autoloaded_namespace?(other)
|
274
|
-
remove_dependent_constant(mod, other)
|
275
|
-
end
|
276
|
-
end
|
398
|
+
module_cache.each_dependent_on(mod) {|other| remove_dependent_constant(mod, other)}
|
277
399
|
end
|
278
400
|
|
279
401
|
def remove_dependent_constant(original_module, dependent_module)
|
280
402
|
remove_constant(dependent_module._mod_name)
|
281
403
|
end
|
282
404
|
|
283
|
-
|
284
|
-
while (klass = klass.superclass) && anonymous?(klass); end
|
285
|
-
klass
|
286
|
-
end
|
287
|
-
|
405
|
+
AR_REFLECTION_CACHES = [:@klass]
|
288
406
|
# egrep -ohR '@\w*([ck]lass|refl|target|own)\w*' activerecord | sort | uniq
|
289
407
|
def update_activerecord_related_references(klass)
|
290
408
|
return unless defined?(ActiveRecord)
|
@@ -293,30 +411,34 @@ module RailsDevelopmentBoost
|
|
293
411
|
# Reset references held by macro reflections (klass is lazy loaded, so
|
294
412
|
# setting its cache to nil will force the name to be resolved again).
|
295
413
|
ActiveRecord::Base.descendants.each do |model|
|
296
|
-
model.reflections
|
297
|
-
reflection.instance_eval do
|
298
|
-
@klass = nil if @klass == klass
|
299
|
-
end
|
300
|
-
end
|
414
|
+
clean_up_relation_caches(model.reflections, klass, AR_REFLECTION_CACHES)
|
301
415
|
end
|
302
416
|
end
|
303
417
|
|
304
|
-
|
305
|
-
|
418
|
+
MONGOID_RELATION_CACHES = [:@klass, :@inverse_klass]
|
419
|
+
def update_mongoid_related_references(klass)
|
420
|
+
if defined?(Mongoid::Document) && klass < Mongoid::Document
|
421
|
+
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
|
423
|
+
end
|
424
|
+
|
425
|
+
module_cache.each_dependent_on(Mongoid::Document) do |model|
|
426
|
+
clean_up_relation_caches(model.relations, klass, MONGOID_RELATION_CACHES)
|
427
|
+
end
|
428
|
+
end
|
306
429
|
end
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
ObjectSpace.each_object(Module) { |mod| module_cache << mod unless anonymous?(mod) }
|
314
|
-
begin
|
315
|
-
yield module_cache
|
316
|
-
ensure
|
317
|
-
module_cache.clear
|
430
|
+
|
431
|
+
def clean_up_relation_caches(relations, klass, ivar_names)
|
432
|
+
relations.each_value do |relation|
|
433
|
+
ivar_names.each do |ivar_name|
|
434
|
+
relation.instance_variable_set(ivar_name, nil) if relation.instance_variable_get(ivar_name) == klass
|
435
|
+
end
|
318
436
|
end
|
319
437
|
end
|
438
|
+
|
439
|
+
def module_cache
|
440
|
+
@module_cache ||= ModuleCache.new
|
441
|
+
end
|
320
442
|
|
321
443
|
def prevent_further_removal_of(const_name)
|
322
444
|
return if constants_being_removed.include?(const_name)
|