ようへいの日々精進XP

よかろうもん

2018 年 02 月 20 日(火)

ジョギング

  • 香椎浜 x 2
  • どうも走りがギクシャクしていて, たった 2 周しかしていないのに, 足の疲労感も半端ない

日課

  • (腕立て x 50 + 腹筋 x 30) x 3

奥さん

  • 寒暖差が大きくなってきているので, 少し体調を崩した感じ
  • せっかく暖かくなったのに..., 明日は休んで養生して欲しい

今日のるびぃ ~ ブランクスレート ~

引き続き, メタプログラミングRuby 第2版 の読書メモ.

ブランクスレート

  • 最小限のメソッドしかない状態のクラス
  • スーパークラスの継承したメソッドが不要であれば, それを削除することで衝突を回避出来る

BasicObject

  • スーパークラスを指定しなければデフォルトで Object クラスを継承する
  • Object クラスは BasicObject のサブクラス
[5] pry(main)> BasicObject.instance_methods
=> [:!, :equal?, :__binding__, :instance_eval, :instance_exec, :==, :!=, :__id__, :__send__]
[6] pry(main)> BasicObject.instance_methods.count
=> 9
[7] pry(main)> Object.instance_methods.count
=> 65

こちらより抜粋.

class Proxy < BasicObject
  def initialize(target)
    @target = target
  end

  def method_missing(message, *args)
    @target.__send__(message, *args)
  end
end

これを実行すると...

[1] pry(main)> class Proxy < BasicObject
[1] pry(main)*   def initialize(target)  
[1] pry(main)*     @target = target    
[1] pry(main)*   end    
[1] pry(main)*   
[1] pry(main)*   def method_missing(message, *args)  
[1] pry(main)*     @target.__send__(message, *args)    
[1] pry(main)*   end    
[1] pry(main)* end  
=> :method_missing
[2] pry(main)> Proxy.new(1).to_s # method_missing を介して 1.to_s が呼ばれる
=> "1"
[3] pry(main)> Proxy.new(1).to_f # method_missing を介して 1.to_f が呼ばれる
=> 1.0
[4] pry(main)> Proxy.new(1) + 2 # method_missing を介して 1 + 2 が呼ばれる... Ruby では + もメソッド :desuyone:
=> 3
[5] pry(main)> Proxy.new(1).display
1=> nil

極端な method_missing と BasicObject な例

class Cls1
  def method_missing(method, *args)
    puts "called #{method}(#{args.join(', ')})"
  end
end

Cls1.new.display

これを実行すると...

[15] pry(main)> class Cls1
[15] pry(main)*   def method_missing(method, *args)  
[15] pry(main)*     puts "called #{method}(#{args.join(', ')})"    
[15] pry(main)*   end    
[15] pry(main)* end  
=> :method_missing
[16] pry(main)> 
[17] pry(main)> Cls1.new.display
#<Cls1:0x000055f0aca64058>=> nil

Object#dispaly が呼ばれている雰囲気. これを BasicObject を継承してブランクスレートすると...

class Cls1 < BasicObject
  def method_missing(method, *args)
    puts "called #{method}(#{args.join(', ')})"
  end
end

Cls1.new.display

BasicObject を継承してブランクスレートすると...

[1] pry(main)> class Cls1 < BasicObject
[1] pry(main)*   def method_missing(method, *args)  
[1] pry(main)*     puts "called #{method}(#{args.join(', ')})"    
[1] pry(main)*   end    
[1] pry(main)* end  
=> :method_missing
[2] pry(main)> 
[3] pry(main)> Cls1.new.display
SystemStackError: stack level too deep
from (pry):3:in `method_missing'

とうとう呼ばれるメソッドが無くなって SystemStackError: stack level too deep となり無限ループとなる (呼び出すメソッドが存在していない為)

ふむふむ.