diff --git a/lib/bootsnap/load_path_cache/cache.rb b/lib/bootsnap/load_path_cache/cache.rb index 0c3c7a1..32dc8b8 100644 --- a/lib/bootsnap/load_path_cache/cache.rb +++ b/lib/bootsnap/load_path_cache/cache.rb @@ -114,7 +114,7 @@ def push_paths(sender, *paths) def reinitialize(path_obj = @path_obj) @mutex.synchronize do @path_obj = path_obj - ChangeObserver.register(self, @path_obj) + ChangeObserver.register(@path_obj, self) @index = {} @dirs = {} @generated_at = now diff --git a/lib/bootsnap/load_path_cache/change_observer.rb b/lib/bootsnap/load_path_cache/change_observer.rb index 9322566..53f936c 100644 --- a/lib/bootsnap/load_path_cache/change_observer.rb +++ b/lib/bootsnap/load_path_cache/change_observer.rb @@ -56,11 +56,22 @@ def uniq!(*args) end end - def self.register(observer, arr) + def self.register(arr, observer) return if arr.frozen? # can't register observer, but no need to. arr.instance_variable_set(:@lpc_observer, observer) - arr.extend(ArrayMixin) + ArrayMixin.instance_methods.each do |method_name| + arr.singleton_class.send(:define_method, method_name, ArrayMixin.instance_method(method_name)) + end + end + + def self.unregister(arr) + return unless arr.instance_variable_get(:@lpc_observer) + + ArrayMixin.instance_methods.each do |method_name| + arr.singleton_class.send(:remove_method, method_name) + end + arr.instance_variable_set(:@lpc_observer, nil) end end end diff --git a/test/load_path_cache/change_observer_test.rb b/test/load_path_cache/change_observer_test.rb index 743a2f3..2099027 100644 --- a/test/load_path_cache/change_observer_test.rb +++ b/test/load_path_cache/change_observer_test.rb @@ -8,7 +8,7 @@ class ChangeObserverTest < MiniTest::Test def setup @observer = Object.new @arr = [] - ChangeObserver.register(@observer, @arr) + ChangeObserver.register(@arr, @observer) end def test_observes_changes @@ -31,6 +31,25 @@ def test_observes_changes @arr.prepend("j", "k") end + def test_unregister + @observer.expects(:push_paths).never + @observer.expects(:unshift_paths).never + @observer.expects(:reinitialize).never + + ChangeObserver.unregister(@arr) + + @arr << "a" + @arr.push("b", "c") + @arr.append("d", "e") + @arr.unshift("f", "g") + @arr.concat(%w(h i)) + @arr.prepend("j", "k") + @arr.delete(3) + @arr.compact! + @arr.map!(&:upcase) + assert_equal %w(J K F G A B C D E H I), @arr + end + def test_reinitializes_on_aggressive_modifications @observer.expects(:push_paths).with(@arr, "a", "b", "c") @arr.push("a", "b", "c") @@ -45,11 +64,11 @@ def test_reinitializes_on_aggressive_modifications def test_register_frozen # just assert no crash - ChangeObserver.register(@observer, @arr.dup.freeze) + ChangeObserver.register(@arr.dup.freeze, @observer) end def test_register_twice_observes_once - ChangeObserver.register(@observer, @arr) + ChangeObserver.register(@arr, @observer) @observer.expects(:push_paths).with(@arr, "a").once @arr << "a"