というような感じになります(Ruby 1.6.7 + irb で動作確認をしています)。class Prototype attr :proto, true def method_missing(sel,*args); self.proto.send(sel,*args) end def klone obj=Prototype.new obj.proto=self obj end end bankAccount=Prototype.new def bankAccount.get_dollars(me) class << me; attr :dollars, true end me.dollars end def bankAccount.set_dollars(me,x) me.get_dollars(me) me.dollars=x end def bankAccount.deposit(me,x) me.set_dollars(me,me.get_dollars(me)+x) end def bankAccount.withdraw(me,x) me.set_dollars(me,[0,me.get_dollars(me)-x].max) end bankAccount.set_dollars(bankAccount,200) bankAccount.get_dollars(bankAccount) => 200 bankAccount.deposit(bankAccount,50) => 250 bankAccount.withdraw(bankAccount,100) => 150 bankAccount.withdraw(bankAccount,200) => 0 myAccount=bankAccount.klone myAccount.set_dollars(myAccount,100) => 100 myAccount.deposit(myAccount,400) => 500 bankAccount.get_dollars(bankAccount) => 0 stockAccount=bankAccount.klone def stockAccount.get_numShares(me) class << me; attr :numShares, true end me.numShares end def stockAccount.set_numShares(me,x) me.get_numShares(me) me.numShares=x end def stockAccount.get_pricePerShare(me) class << me; attr :pricePerShare, true end me.pricePerShare end def stockAccount.set_pricePerShare(me,x) me.get_pricePerShare(me) me.pricePerShare=x end def stockAccount.get_dollars(me) me.get_numShares(me)*me.get_pricePerShare(me) end def stockAccount.set_dollars(me,x) me.set_numShares(me,Float(x)/me.get_pricePerShare(me)) me.get_dollars(me) end stockAccount.set_numShares(stockAccount,10) stockAccount.set_pricePerShare(stockAccount,30) stockAccount.get_dollars(stockAccount) => 300 stockAccount.set_dollars(stockAccount,150) => 150.0 stockAccount.get_numShares(stockAccount) => 5.0 myStock=stockAccount.klone myStock.set_numShares(myStock,10) myStock.set_pricePerShare(myStock,30) myStock.set_dollars(myStock,600) => 600 myStock.get_numShares(myStock) => 20.0 myStock.deposit(myStock,60) => 660.0 myStock.get_numShares(myStock) => 22.0 myStock.withdraw(myStock,120) => 540.0 myStock.get_numShares(myStock) => 18.0 def bankAccount.deposit(me,x); me.set_dollars(me,me.get_dollars(me)+x*0.9) end bankAccount.deposit(bankAccount,100) ==> 90.0 # 0 + 100 * 0.9 myAccount.deposit(myAccount,100) ==> 590.0 # 500 + 100 * 0.9 stockAccount.deposit(stockAccount,100) ==> 240.0 # 150 + 100 * 0.9 myStock.deposit(myStock,100) ==> 630.0 # 540 + 100 * 0.9
のようにして比較的自由に、任意のコンパイル済みメソッドを任意のオブジェクトにバインドして評価することができます(コンパイル済みのメソッドを、メッセージ送信を介さずに、まるで通常の言語における関数のように起動しているわけですね)。この例では、抽象クラスである Number に定義されている #+ (オーバーライドするよう勧告のための例外を出すコード)を SmallInteger の 3 にバインドして評価し、わざとエラーを出させています。| method | method := Number compiledMethodAt: #+. 3 withArgs: {4} executeMethod: method "==> Error: My subclass should have overridden #''"
というようなことができます。つまり、3 にバインドバインドした + というメソッドをオブジェクトして取り出して、それをいったん、誰にもバインドされていない UnboundMethod にし、改めて 4 とバインドして評価する、というようなことです。3.method(:+).unbind.bind(4).call(5) => 9
このページを編集 (6836 bytes)
以下の 4 ページから参照されています。 |
This page has been visited 4107 times.