リフレクションとは?
プログラム実行中に、そのプログラムの情報を取得したり操作したりすること。
デバッグや、正しく定義できてるかの確認など開発をする上で欠かせないものだと思うので、きっちり使えるようにした方が開発スピードは向上します。
オブジェクトについて調べる
オブジェクトが持つインスタンス変数にアクセス
class Foo
def initialize
@foo = 1
@bar = 2
end
end
foo = Foo.new
# インスタンス変数名の確認
foo.instance_variables #=>[:@foo, :@bar]
# インスタンス変数の存在確認(@は必須)
foo.instance_variable_defined?(:@foo) #=> true
# インスタンス変数の値を参照
foo.instance_variable_get(:@foo) #=> 1
# インスタンス変数の値を更新(存在しない場合は新しく定義)
foo.instance_variable_set(:@foo, 2) #=> 2
オブジェクトが持つメソッドにアクセス
# 親クラスを定義
class ParentClass
def super_public; end
private
def super_private; end
protected
def super_protected; end
end
# 子クラスを定義
class ChildClass < ParentClass
def sub_public; end
def hello
puts 'Hello'
end
private
def sub_private; end
protected
def sub_protected; end
end
# 特異クラスを定義
def Child.new.singleton; end
child = Cgild.new
# プライベートメソッド以外を取得
child.methods #=> [:singleton, :sub_public, sub_protected, ...]
# パブリックメソッドを取得
child.public_methods #=> [:singleton, :sub_public, ...]
# プライベートメソッドを取得
child.private_methods #=> [:sub_private, :super_private, ...]
# プロテクテッドメソッドを取得
child.protected_methods #=> [:sub_protected, :super_protected]
# 特異メソッドを取得
child.singleton_methods #=> [:singleton]
child.methods(false) #=> [:singleton]
# メソッドが定義されている確認
child.respond_to?(:sub_public) #=> true
# メソッドの呼び出し
child.send(:hello) #=> "Hello"
クラスについて調べる
クラスが持つ値にアクセス
class Foo
@@foo = 'foo'
FOO = 'foo'
def bar
@@bar = 'bar'
end
end
# クラス変数を取得する
Foo.class_variables #=> [:@@foo]
# クラス変数が定義されているか確認(@@必須)
Foo.class_variable_defined?(@@foo) #=> true
# クラス変数の値を取得
Foo.class_variable_get(@@foo) #=> "foo"
# クラス変数に値を設定(存在しない場合は新しく作成)
Foo.classvariable_set(@@foo, 'set_foo') #=> "set_foo"
# クラス内に定義されている定数を確認
Foo.constants #=> [:FOO]
# 定数の値を取得する
Foo.const_get(:FOO) #=> "foo"
# 定数に値を設定(存在しない場合は新しく作成)
Foo.const_set(:FOO, 'set_foo') #=> "set_foo"
クラスが持つメソッドにアクセス
# 親クラスを定義
class ParentClass
def super_public; end
private
def super_private; end
protected
def super_protected; end
end
# 子クラスを定義
class ChildClass < ParentClass
def sub_public; end
def hello
puts 'Hello'
end
private
def sub_private; end
protected
def sub_protected; end
end
# プライベートメソッド以外のインスタンスメソッドを取得
ChildClass.instance_methods #=> [:sub_public, :sub_protected, :super_public, ...]
# パブリックメソッドを取得
ChildClass.public_instance_methods #=> [:sub_public, :super_public, ...]
# プライベートメソッドを取得
ChildClass.private_instance_methods #=> [:sub_private, :super_private, ...]
# プロテクテッドメソッドを取得
ChildClass.protected_instance_methods #=> [:sub_protected, super_protected]
# 指定されたメソッドがプライベートメソッド以外に定義されているか確認
ChildClass.method_defined?(:sub_public) #=> true
# 指定されたメソッドがパブリックメソッドに定義されているか確認
ChildClass.public_method_defined?(:sub_public) #=> true
# 指定されたメソッドがプライベートメソッドに定義されているか確認
ChildClass.private_method_defined?(:sub_private) #=> true
# 指定されたメソッドがプロテクテッドメソッドに定義されているか確認
ChildClass.protected_method_defined?(:sub_protected) #=> true
# クラスの継承構造を参照
ChildClass.ancestors #=> [ChildClass, ParentClass, ...]
# スーパークラスを参照
ChildClass.superclass #=> ParentClass
おわりに
「リフレクション」という聞き慣れない言葉ではあったかと思いますが、内容は結構日頃から似たようなことをしているかと思います。
いろんな操作があるので、必要な情報を取得したり設定できるようにしておきましょう!