From: David Masover Date: 2009-07-14T00:28:54+09:00 Subject: Re: Prototype-Based Inheritance (#214) 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