# Delegation question, where I want prototype style delegation

**URL:** <https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768>\
**Category:** Ruby\
**Created:** [May 6, 2008, 8:01am UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768 "2008-05-06T08:01:11Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![samrus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecd19e/32.png) [@samrus](https://www.ruby-forum.com/u/samrus)\
**Post date:** [May 6, 2008, 8:01am UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768/1 "2008-05-06T08:01:11Z")

</div>

I want to make an object that behaves like another object would, if that  
object had had it’s #each method redefined.

I can do this with extend(), but that permanently damages the object.

I can do it with delegate/method\_missing, except I need to reimplement  
every method of the delegatee, which sucks.

I could do this in prototype based languages, where you can effectively  
create a new object that behaves like another object with a few  
differences,  
but don’t see a way in an OO language like ruby.

Below is an example of what I want to do, implemented with extend.

But it has a problem, it modifies the target object, but I may want  
to create mutiple delegates to the  
target, each with a different set of “views”, that behave like the  
target object would if it  
had its #each method redefined.

Btw, what I’m actually doing is I have a calendar object, and I want  
to create various views  
of the calendar, ones including events but not todos, ones that appear  
to only have  
components that occur in a particular period, etc.

class Base  
include Enumerable

def initialize(ary)  
@ary = ary.to\_a  
end

def each  
@ary.each{|a| yield a}  
end

def show  
inject("show: ") {|accum, o| accum + o.to\_s + “,”}  
end  
end

module Negate  
def each(&block)  
super do |a|  
yield -a  
end  
end  
end

module Add10  
def each(&block)  
super do |a|  
yield a+10  
end  
end  
end

o = Base.new(1…3)  
o.extend Negate.dup  
o.extend Add10  
o.extend Negate.dup

o.each {|\_| puts \_ }

puts o.show

---

<div class="post-metadata">

**Author:** ![samrus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecd19e/32.png) [@samrus](https://www.ruby-forum.com/u/samrus)\
**Post date:** [May 6, 2008, 2:58pm UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768/2 "2008-05-06T14:58:43Z")

</div>

On May 6, 2008, at 1:00 AM, Sam R. wrote:

> I want to make an object that behaves like another object would, if  
> that  
> object had had it’s #each method redefined.

What you really want in this case is normal inheritance, so the  
overridden each() method replaces the original.

Then the only thick becomes getting the existing object into an  
equivalent subclass form. We can use a little Ruby magic to track  
subclasses and do the conversion for us:

class Base  
def self.subclasses  
@subclasses ||= []  
end

def self.inherited(subclass)  
subclasses \<\< subclass  
end

def self.subclass(snake\_case\_name)  
camel\_case\_name = snake\_case\_name.gsub(/(?:\A|\_)(.)/)  
{ $1.capitalize }  
subclasses.find { |sc| sc.to\_s == camel\_case\_name }  
end

include Enumerable

def initialize(ary)  
@ary = Array(ary)  
end

def each(&block)  
@ary.each(&block)  
end

def show  
“show: #{to\_a.join(”, “)}”  
end

def method\_missing(method, \*args, &block)  
if method.to\_s =~ /\Aas\_(\w+)\z/ and (sc = self.class.subclass($1))  
sc.new(@ary)  
else  
super  
end  
end  
end

class Negated \< Base  
def each  
super { |e| yield -e }  
end  
end

class Plus10 \< Base  
def each  
super { |e| yield e + 10 }  
end  
end

puts “Base:”  
b = Base.new(1…3)  
puts b.show

puts “Negated:”  
puts b.as\_negated.show

puts “Plus 10:”  
puts b.as\_plus\_10.show

**END**

Hope that helps.

James Edward G. II

---

<div class="post-metadata">

**Author:** ![samrus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecd19e/32.png) [@samrus](https://www.ruby-forum.com/u/samrus)\
**Post date:** [May 6, 2008, 4:27pm UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768/3 "2008-05-06T16:27:09Z")

</div>

On May 6, 2008, at 12:00 AM, Sam R. wrote:

> But it has a problem, it modifies the target object, but I may want  
> to create mutiple delegates to the  
> target, each with a different set of “views”, that behave like the  
> target object would if it  
> had its #each method redefined.

you can play with this:

cfp:~ \> cat a.rb  
class Base  
instance\_methods.each do |m|  
unless m[%r/^**/]  
old = m  
new = "**#{ old }\_\_"  
new \<\< ‘?’ if new.sub!(‘?’, ‘’)  
new \<\< ‘!’ if new.sub!(‘!’, ‘’)  
alias\_method new, old  
undef\_method old  
end  
end

def initialize object  
@object = object  
end

def method\_missing m, \*a, &b  
@object. **send** m, \*a, &b  
end

Delegates = {}

def / m  
Delegates[m] ||=  
**dup**. **instance\_eval** do  
extend m  
self  
end  
end  
end

module Reverse  
def each \*a, &b  
reverse.each \*a, &b  
end  
end

a = Base.new [2,4]

p a.each{}

p (a/Reverse).each{}

cfp:~ \> ruby a.rb  
[2, 4]  
[4, 2]

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![samrus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecd19e/32.png) [@samrus](https://www.ruby-forum.com/u/samrus)\
**Post date:** [May 7, 2008, 7:20am UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768/4 "2008-05-07T07:20:32Z")

</div>

On Tue, May 6, 2008 at 5:58 AM, James G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> On May 6, 2008, at 1:00 AM, Sam R. wrote:
> 
> > I want to make an object that behaves like another object would, if that  
> > object had had it’s #each method redefined.
> 
> What you really want in this case is normal inheritance, so the overridden  
> each() method replaces the original.

Educational code, but doesn’t quite do the trick, because the views  
aren’t stackable.

In my example I negated, added 10, and negated again. With yours:

puts “Stacked operations:”  
puts b.as\_negated.as\_plus\_10.as\_negated.show

=\> in `method_missing': undefined method `as\_plus\_10’ for  
#\<Negated:0x261ec @ary=[1, 2, 3]\> (NoMethodError)

The end result of this would have to be an instance of

class Negated \< Plus10 \< Negated \< Base  
end

or something…

Also, my real class has much more complex internal state and  
relationships, it isn’t just  
a wrapper for an Array, and creating a new instance isn’t desireable.  
I’m trying to create  
calendar views, where the view of the calendar looks like the real  
calendar (including  
reflecting changes in the base calendar), but iterates over only dates  
in a particular range,  
or only journal entries.

Thanks,  
Sam

---

<div class="post-metadata">

**Author:** ![samrus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ecd19e/32.png) [@samrus](https://www.ruby-forum.com/u/samrus)\
**Post date:** [May 7, 2008, 7:49am UTC](https://www.ruby-forum.com/t/delegation-question-where-i-want-prototype-style-delegation/136768/5 "2008-05-07T07:49:13Z")

</div>

On Tue, May 6, 2008 at 7:25 AM, ara.t.howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

Ara, thanks for the suggestion. It suffers from the same  
non-stackability problem:

p ((a/Reverse)/Reverse).each{}  
=\> [4,2]

However, the combination of this and James’ suggestion made me think  
maybe I should be cloning my src object, and then modifying it.  
clone() will get the singleton class, but won’t do a deep copy, so it  
will still share most of the internal state of the original class. I  
think this will work for me:

Classes defined as in my original, but do the extending like:

o = Base.new(1…3)  
n = o.clone.extend Negate.dup  
an = n.clone.extend Add.dup  
nan = an.clone.extend Negate.dup

puts o.show  
puts n.show  
puts an.show  
puts nan.show

% ruby m.rb  
show: 1,2,3,  
show: -1,-2,-3,  
show: 9,8,7,  
show: -9,-8,-7,
