From: Thorsten Hater
Date: 2009-07-14T23:04:02+09:00
Subject: Re: Prototype-Based Inheritance (#214)
Hi,
a simple Solution, which works for static Prototypes:
module Prototype
def method_missing name, *args
# if we have a prototype forward to it's methods
# else propagate method missing upwards
if defined?(@__proto__) && @__proto__
@__proto__.send name,*args
else
super
end
end
def set_prototype pt
# clone the prototype, so we can freely modify
# it's attributes w/o interference with others
@__proto__ = pt.clone
end
end
As said above this is a simple solution, but it should work for all classes
and is easily written.
But it comes at the cost of duplicating arbitrarily complex objects (perhaps
many times) and just allows static prototypes.
I couldn't come up with a solution which filters writing access to the
proto-
type (apart from simple regexing) but allows modification from the
parentside.
Possibly one could use observers and method_defined hooks for this, but the
complexity would be rather high on this way.
Best regards,
Thorsten
David Masover wrote:
> On Sunday 12 July 2009 12:49:55 pm lith wrote:
>
>
>> def prototype=(prototype)
>> merge!(prototype) {|k,o,n| o}
>>
>
> I based my implementation on Javascript, and one of the nice properties there
> is that the prototype can change later. So, for example, in my implementation:
>
> irb(main):005:0> pele.favorite_food = 'hamburger'
> => "hamburger"
> irb(main):006:0> pele_jr.favorite_food
> => "hamburger"
> irb(main):007:0> pele
> => {:name=>"Pele", :sport=>"football", :position=>"Forward",
> :favorite_food=>"hamburger"}
> irb(main):008:0> pele_jr.favorite_food = 'cheeseburger'
> => "cheeseburger"
> irb(main):009:0> pele_jr.favorite_food
> => "cheeseburger"
> irb(main):010:0> pele.favorite_food
> => "hamburger"
>
> Of course, this is slower, but more powerful, I think.
>
>
>> when Proc
>> return val.call(self, *args)
>> end
>>
> [snip]
>
>> This would allow you to do something like:
>>
>> pele_jr.age = 20
>> pele_jr.foo = lambda {|this, a| this.age + a}
>> pele_jr.foo(10) #=> 30
>>
>
> Nice touch...
>
> Here's mine:
>
> module Prototype
> attr_accessor :prototype
> def method_missing *args
> prototype.public_send *args
> end
> end
>
> That's more generic than just hashes. Mix it into Object and it works on
> anything. Of course, it's not exactly convenient to have to define new values
> like this:
>
> pele = Object.new
> class << pele
> attr_accessor :name
> end
> pele.name = 'Pele'
>
> It also severely limits what you can do with some of the builtin classes like
> Fixnums that can't have a metaclass.
>
> And of course, to make it saner for the example (and because OpenStruct won't
> cooperate), I can do this:
>
> class Hash
> include Prototype
> def method_missing name, *args
> if has_key? name
> self[name]
> elsif name =~ /.=$/
> self[name.to_s.chomp('=').to_sym] = args.first
> else
> super
> end
> end
> end
>
>
--
Thorsten Hater
Institut fuer Theoretische Physik I
Ruhr-Universitaet Bochum
E-Mail: tp1@tp1.rub.de
Tel.: 0234/32-23-441
|