! 発表の内容 !! 自己紹介 !! リフレクション機能の基本的考え方 !! 利用法 !! リフレクション機能概要 !! 実例 ! 自己紹介 !! 大林一平 !! 京大マイコンクラブ !! 京都大学理学研究科数学数理解析専攻D2 !!! 力学系分野 ! 自己紹介 !! Ruby/SDL !! RRSE !! Ruby Refactoring Browser(RRB) ! !! Ruby 1.8.6 を想定 !! 1.9.xでは変わっているかも ! 参考文献 !! RubyリファレンスのClass/Module/Objectの項 !! RHG(http://i.loveruby.net/ja/rhg/) !! Rubyのソースコード ! 基本 !! 大半の機能が「実行時処理」 !! 実行前の処理に手をだせない !!! 構文木をいじる方法がない !!! Lispのマクロのようなものがない !! 以下のクラスが中心的役割を果たす !!! Module/Class !!! Object !!! リファレンスのこれらの項が参考になる ! 利用法 !! ライブラリの作成に !! Inner DSL ! Rubyのリフレクション機能概要 !! 変数,定数関連 !! メソッド関連 !! クラス階層関連 !! eval !! hook ! 変数,定数関連 !! インスタンス変数(Object#) !!! instance_variable_{set,get} !!! instance_variable_defined? !!! instance_variables !! クラス変数 !! 定数 ! 変数,定数関連 !! ローカル変数 !!! local_variables !! グローバル変数 !!! global_variables !!! trace_var ! メソッド関連 !! 存在するメソッドの調査 !!! Module#instance_methods !!! Object#methods !!! Object#singleton_methods !!! Module#method_defined? !!! Object#respond_to? ! メソッド関連 !! メソッドの定義 !!! Module#define_method !!! Module#{remove,undef}_method !!! Module#alias_method !! Method, UnboundMethod !!! Object#method !!! Module#instance_method ! クラス階層 !! Module#include !! Object#extend !! Class#superclass !! Module#include? !! Module#ancestors !! Object#is_a? !! Module#=== ! eval関連 !! Module#module_eval !! Object#instance_eval !! eval ! eval関連 !! ブロックを取る場合 !! 文字列を取る場合 ! hook !! Object#method_missing !! Module#const_missing !! Module#method_added !! Module#method_{removed,undefined} !! Module#included !! Module#extended ! クラス階層と継承と特異クラス !! 特異クラスとは !!! あるオブジェクト固有のクラス ! クラス階層と継承と特異クラス class A < Object end a = A.new ! クラス階層と継承と特異クラス {{sps_bg("a1.png","center", 255)}} ! クラス階層と継承と特異クラス class < 32 A.new.bar # -> "barbar" ! Module#define_method !! そのモジュール/クラスにメソッドを定義 !! メソッドの中身はブロックで与える !! 外のローカル変数が見える !! 例 class A def initialize(); @y = 2; end define_method(:foo) {|x| x+@y} end A.new.foo(4) # -> 6 ! 例題の答え module Definable def define(name, val) define_method(name){ val } end end ! 例題2 !! デフォルト値つきattr_readerぽくする class A extend Definable define :foo, "foo" def baz(); @foo = "baz"; end end a = A.new a.foo # -> "foo" a.baz a.foo # -> "baz" ! 例題2回答 module Definable def define(name, val) ivname = "@#{name}" define_method(name) { if instance_variable_defined?(ivname) instance_variable_get(ivname) else val end } end end ! クラス変数もどきにしてみる class A extend Definable define :foo, "foo" end a = A.new a.foo # -> "foo" A.new.foo = "bar" a.foo # -> "bar" ! ローカル変数の共有 module Definable def define(name, val) define_method(name){ val } define_method("#{name}="){|v| val = v} end end ! さらなる課題 !! initialize時にインスタンス変数を初期化 !!! 実装はかなり変わる !!! 初期値をhashで与えられるようにしてみる !! インスタンス変数を使わないように変更 !!! foo=も定義するように変更 ! こつ !! 必要な情報はどのクラスが持っているかを意識する !! どのクラス/オブジェクトに情報を持たせるか意識する ! その他 !! アクセッサのないインスタンス変数の読み書き !! privateメソッドの外部からの呼びだし !! Railsみたいにメソッドが生えてくるようなこと ! 質問 !! どうぞ ! 終わり ! おまけ !! MethodとUnboundMethod !!! Object#method !!! Module#instance_method ! Method !! メソッドをオブジェクト化する (1..10).map(&3.method(:+)) ! UnboundMethod !! クラスからメソッドを取りだす !! インスタンスが存在しない状態 →つまりそのまま呼びだせない !! UnboundMethod#bind !!! Methodのインスタンスを生成 Time.instance_method(:to_s).bind(Time.now).call ! 特徴 !! Procと互換 !! メソッドの名前でなく実体を持つ !! 上書きしても元の情報を持つ ! 例題 class A extend Obsolete def a print "a\n" end obsolete :a end A.new.a ! 例題 module Obsolete def obsolete(name) old = instance_method(name) msg = "Warning: #{self.to_s}\##{name} is obsolete" define_method(name) {|*a| warn(msg) old.bind(self).call(*a) } end end