メタプログラミングRuby まとめ
投稿日: | |
---|---|
タグ: |
Ruby
本稿は『メタプログラミングRuby』を読んだ自分用のまとめ。
Rubyの基本メソッド
- BasicObject#ancestors
- 継承関係
メソッドを呼び出す場合,ここで取得する配列の0から順番に検索され,使用される。 例えば,「"hoge".func」のようなメソッドを呼んだ場合,Stringから順に検索される。[String, Comparable, Object, Kernel, BasicObject]
- Kernel#p
- オブジェクトの中身を形成(Object#inspectメソッドを呼び出す)して出力する
- BasicObject#methods
- クラスで定義されたメソッド一覧
- public_methods
- protected_methods
- private_methods
- singleton_methods
- public・protected・private・特異メソッド一覧
- BasicObject#instance_varitables
- オブジェクトが持つインスタンス変数一覧
- Object#class
- クラスを取得
- Class#superclass
- スーパクラスを取得
オブジェクトモデル
- オープンクラス
Rubyでは,定義されたクラスを開いて,内容を変更することができる。
p String.methods.include?(:to_num) # false class String def to_num() self.to_i # ※ Rubyのメソッド定義ではreturnがない場合,最後に評価した値を返す end end a = "123" p a.to_num # 123
ちなみに既に定義されたメソッドがある場合,上書きする(モンキーパッチ)。
class Hoge def func() puts "hello" end end a = Hoge.new class Hoge def func() puts "bye" end end a.func() # byeを出力
- Refinements(Ruby2.0以降)
- usingを使用すると,引数で指定したモジュールで定義された拡張を現在のクラス、モジュールで有効にできる。
module RefStr refine String do def to_num() self.to_i end end end using RefStr "123".to_num
メソッド
- 動的ディスパッチ
Object#send(name [, args, ...]) -
実行時に呼び出すメソッドを動的に変更する。
class Hoge def func1() puts "hello" end def func2(str) puts "#{str}" end def func3() puts "bye" end end a = Hoge.new a.send(:func1) a.send(:func2, "yeah!") a.send("func3".to_sym) # 文字列 -> シンボル
- 動的メソッド
Module#define_method(methodname){|arg, ..| block } -
メソッドを動的に定義する。
define_method(:func1){|x| puts x} class Hoge define_method(:func2){|x| puts x} end func1("hello") Hoge.new.func2("bye!")
- Object#method_missing(methodname, [*args, &block])
-
メソッドが見つからない場合,method_missingが呼び出される。
class Hoge def method_missing(methodname) puts "No #{methodname}!" end end a = Hoge.new a.func # No func!
- ゴーストメソッド
def method_missing(methodname, *args, &blcok) if methodname==:func1 then puts "#{args}" else super.method_missing(methodname, args, block) end end func1 1 # [1] func2 2 # ↓ # NoMethodError: undefined method `func2' for main:Object # from (irb):8:in `method_missing' # from (irb):13 # from /usr/bin/irb:12:in `<main>'
その他
- 可変長引数(*v)
- 呼び出される側
func(*v) p v end
irb(main):002:0> func(1,2,3) [1, 2, 3] => [1, 2, 3]
- 呼び出す側
-
def func(a,b) puts "a=#{a}, b=#{b}" end
irb(main):015:0> args = [1,2].product(["a", "b"]) => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] irb(main):016:0> args.each{|a| func(*a)} a=1, b=a a=1, b=b a=2, b=a a=2, b=b => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] irb(main):017:0>