Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

guard extension methods from being redefined later

  • Loading branch information...
commit 01f21665b561f55ec34e20b99ad8f9b3407a2283 1 parent bfcdf8c
@cldwalker authored
Showing with 71 additions and 24 deletions.
  1. +15 −0 lib/watchdog.rb
  2. +56 −24 spec/watchdog_spec.rb
View
15 lib/watchdog.rb
@@ -7,7 +7,21 @@ def initialize(meth, from, to)
class ExtendError < Error; end
class IncludeError < Error; end
+ def self.guard(mod, guarded)
+ guard_mod = Module.new { class << self; attr_accessor :existing; end }
+ guard_mod.existing = mod
+ guard_meth = guarded.is_a?(Module) ? :method_added : :singleton_method_added
+ guard_mod.send(:define_method, guard_meth) do |meth|
+ if guard_mod.existing.instance_methods.include?(meth)
+ raise Watchdog::Error.new(meth, self, mod)
+ end
+ super
+ end
+ guarded.extend guard_mod
+ end
+
def append_features(mod)
+ Watchdog.guard(self, mod)
existing = mod.private_instance_methods + mod.instance_methods
(existing & self.instance_methods).each do |m|
raise IncludeError.new(m, self, mod)
@@ -16,6 +30,7 @@ def append_features(mod)
end
def extend_object(obj)
+ Watchdog.guard(self, obj)
self.instance_methods.each do |m|
raise ExtendError.new(m, self, obj) if obj.respond_to?(m, true)
end
View
80 spec/watchdog_spec.rb
@@ -8,42 +8,74 @@ def create_methods(obj, *meths)
end
context "when extended" do
- let(:safe_module) { create_methods Module.new.extend(Watchdog), :blah }
+ let(:extensions) { create_methods Module.new.extend(Watchdog), :blah }
- it "doesn't raise error if no methods conflict" do
- existing = Object.new
- lambda { existing.extend safe_module }.should_not raise_error
- end
+ context "new extension method" do
+ it "doesn't raise error if no existing methods conflict" do
+ existing = Object.new
+ lambda { existing.extend extensions }.should_not raise_error
+ end
+
+ it "raises error if existing public methods conflict" do
+ existing = create_methods Object.new, :blah
+ lambda { existing.extend extensions }.should raise_error(Watchdog::ExtendError)
+ end
- it "raises error if public methods conflict" do
- existing = create_methods Object.new, :blah
- lambda { existing.extend safe_module }.should raise_error(Watchdog::ExtendError)
+ it "raises error if existing private methods conflict" do
+ existing = create_methods Object.new, :blah
+ class <<existing; self.send :private, :blah; end
+ lambda { existing.extend extensions }.should raise_error(Watchdog::ExtendError)
+ end
end
- it "raises error if private methods conflict" do
- existing = create_methods Object.new, :blah
- class <<existing; self.send :private, :blah; end
- lambda { existing.extend safe_module }.should raise_error(Watchdog::ExtendError)
+ context "new method" do
+ it "doesn't raise error if it doesn't redefine extension methods" do
+ existing = Object.new.extend extensions
+ lambda { def existing.bling; end }.should_not raise_error(Watchdog::Error)
+ end
+
+ it "raises error if it redefines extension methods" do
+ existing = Object.new.extend extensions
+ lambda { def existing.blah; end }.should raise_error(Watchdog::Error)
+ end
end
end
context "when included" do
- let(:safe_module) { create_methods Module.new.extend(Watchdog), :blah }
+ let(:extensions) { create_methods Module.new.extend(Watchdog), :blah }
- it "doesn't raise error if no methods conflict" do
- existing = Module.new
- lambda { existing.send :include, safe_module }.should_not raise_error
- end
+ context "new extension method" do
+ it "doesn't raise error if no existing methods conflict" do
+ existing = Module.new
+ lambda { existing.send :include, extensions }.should_not raise_error
+ end
+
+ it "raises error if existing public methods conflict" do
+ existing = create_methods Module.new, :blah
+ lambda { existing.send :include, extensions }.should raise_error(Watchdog::IncludeError)
+ end
- it "raises error if public methods conflict" do
- existing = create_methods Module.new, :blah
- lambda { existing.send :include, safe_module }.should raise_error(Watchdog::IncludeError)
+ it "raises error if existing private methods conflict" do
+ existing = create_methods Module.new, :blah
+ existing.send :private, :blah
+ lambda { existing.send :include, extensions }.should raise_error(Watchdog::IncludeError)
+ end
end
- it "raises error if private methods conflict" do
- existing = create_methods Module.new, :blah
- existing.send :private, :blah
- lambda { existing.send :include, safe_module }.should raise_error(Watchdog::IncludeError)
+ context "new method" do
+ it "doesn't raise error if it doesn't redefine extension methods" do
+ existing = Module.new.send :include, extensions
+ lambda {
+ existing.send(:define_method, :bling) { }
+ }.should_not raise_error(Watchdog::Error)
+ end
+
+ it "raises error if it redefines extension methods" do
+ existing = Module.new.send :include, extensions
+ lambda {
+ existing.send(:define_method, :blah) { }
+ }.should raise_error(Watchdog::Error)
+ end
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.