From: Matthias Reitinger Date: 2009-07-20T12:05:07+09:00 Subject: Re: [QUIZ] Prototype-Based Inheritance (#214) Daniel Moore wrote: > ## Prototype-Based Inheritance (#214) I decided to give it a shot: require 'ostruct' class Prototype < OpenStruct attr_reader :prototype def prototype=(new_prototype) if new_prototype.prototypes.include?(self) raise ArgumentError, "circular prototype chain" end @prototype = new_prototype end def prototypes if @prototype.nil? [] else [@prototype] + @prototype.prototypes end end def delete_slot(name) name = name.to_sym if @table.has_key?(name) meta = class << self; self; end meta.send(:remove_method, name) meta.send(:remove_method, :"#{name}=") end delete_field(name) end def method_missing(mid, *args) if @prototype.nil? || mid.id2name =~ /=$/ super else @prototype.send(mid, *args) end end end Most of the functionality is inherited from OpenStruct. The trip down the prototype chain happens in method_missing. A short IRB session should explain the usage: >> require 'prototype' true >> starbucks = Prototype.new(:name => "Starbucks", :drink_size => 3) => # >> new_coffee_shop = Prototype.new(:name => "New") => # >> new_coffee_shop.prototype = starbucks => # >> new_coffee_shop.drink_size => 3 >> new_coffee_shop.drink_size += 1 => 4 >> new_coffee_shop.drink_size => 4 >> new_coffee_shop.delete_slot(:drink_size) => 4 >> new_coffee_shop.drink_size => 3 >> another_coffee_shop = Prototype.new(:name => "Another") => # >> another_coffee_shop.prototype = new_coffee_shop => # >> another_coffee_shop.drink_size => 3 >> another_coffee_shop.prototypes => [#, #] >> starbucks.prototype = another_coffee_shop ArgumentError: circular prototype chain from ./prototype.rb:8:in `prototype=' from (irb):23 >> -Matthias