Skip to content

Commit 7caeba1

Browse files
Define DelegateClass methods in separate module
Before this commit, modules included in a `DelegateClass` could not override delegate methods: ```ruby Base = Class.new do def foo "base" end end Helper = Module.new do def foo "helper" end end WithHelper = DelegateClass(Base) { include Helper } WithHelper.new(Base.new).foo # => "base" ``` This commit defines delegate methods in a separate module, so other modules can come before it in the method lookup chain: ```ruby WithHelper.new(Base.new).foo # => "helper" ``` Also, because of this change, methods in a `DelegateClass` block will properly override instead of redefine. Therefore, calling `super` is faster: **Benchmark script** ```ruby # frozen_string_literal: true require "benchmark/ips" $LOAD_PATH.prepend(".../delegate/lib") require "delegate" Base = Class.new do def foo end end Overridden = DelegateClass(Base) do def foo super end end overridden = Overridden.new(Base.new) Benchmark.ips do |x| x.report("super") { overridden.foo } end ``` **Before** ``` Warming up -------------------------------------- super 75.044k i/100ms Calculating ------------------------------------- super 759.506k (± 0.8%) i/s - 3.827M in 5.039488s ``` **After** ``` Warming up -------------------------------------- super 184.164k i/100ms Calculating ------------------------------------- super 1.835M (± 1.0%) i/s - 9.208M in 5.019711s ``` Fixes https://bugs.ruby-lang.org/issues/19079.
1 parent 5a19c23 commit 7caeba1

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

lib/delegate.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,16 +410,16 @@ def __setobj__(obj) # :nodoc:
410410
__raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
411411
@delegate_dc_obj = obj
412412
end
413+
end
414+
klass.include(Module.new do
413415
protected_instance_methods.each do |method|
414416
define_method(method, Delegator.delegating_block(method))
415-
alias_method(method, method)
416417
protected method
417418
end
418419
public_instance_methods.each do |method|
419420
define_method(method, Delegator.delegating_block(method))
420-
alias_method(method, method)
421421
end
422-
end
422+
end)
423423
klass.define_singleton_method :public_instance_methods do |all=true|
424424
super(all) | superclass.public_instance_methods
425425
end

test/test_delegate.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ def first
4141
assert_empty(warning)
4242
end
4343

44+
def test_delegate_class_block_with_override_from_module
45+
mod = Module.new do
46+
def first
47+
super.inspect
48+
end
49+
end
50+
klass = DelegateClass(Array) { include mod }
51+
assert_equal("1", klass.new([1]).first)
52+
end
53+
4454
def test_systemcallerror_eq
4555
e = SystemCallError.new(0)
4656
assert((SimpleDelegator.new(e) == e) == (e == SimpleDelegator.new(e)), "[ruby-dev:34808]")

0 commit comments

Comments
 (0)