ruby wayの動的特性の1つ
8424 ワード
1動的evaluateコード
グローバルメソッドevalはrubyコードの断片を含む文字列をコンパイルして実行します.これは実行時に構築できるpowerのメカニズムです.
実行されるコード.次の例を見てください.
出力は次のように仮定されます.
参照
a = 1
b = 2 + 3
c = `date`
そしてあなたのparametersはこうなるはずです{"a"=>1,"b"=>5,"c"=>"Mon Apr 30 21:17:47 CDT 2001"}.でもこれじゃ危ない
危険性が高く、「rm*」が入ってきたら憂鬱です.
rubyには、実行時にevaluateコード、class_を実行する3つの方法があります.eval, module_eval,instance_eval、最初の2つは同義で、この3つは
つの方法は実はしたことはすべて同じで、彼らはすべてevaluateの1つの文字列で、あるいは1つのblockで、しかしこの事をする時、彼らは
selfは彼ら自身の受信者に変わった.いくつかの例を見たいなら、rubyの内蔵ライブラリdelegateを見ることをお勧めします.rb.
evalメソッドは、ローカル変数の作成ドメインの外でevaluateを呼び出すこともできる.
Kernel#bindingメソッドを使用して、現在のバインドをオブジェクトに割り当てることができます.evalの2番目のパラメータはこのバインドです.
blockが付いている場合、このblockはこのバインドの一部として格納されます.
2 const_を使うget
const_getメソッドは、クラスまたはモジュールから定数の値を取得します.
これはevalの使用を避ける方法です.似たような方法もありますvariable_set, instance_variable_get和
define_method.
const_getはevalより速く、彼はもっと読むことができて、もっと明確です.
3クラスを名前で動的にインスタンス化
const_を使用できますgetメソッド.rubyのすべてのクラスは、通常、Objectのグローバルメンバーとして定数として命名される.
クラス名がネストされていると、エラーが表示されます.
なぜならconst_getメソッドはそれほどスマートではありませんが、私たちはこのようにすることができます.
4動的アクセスインスタンス変数
次の例を見てください.
ここで注意すべきは、変数のフルネームをパラメータとしなければならない、すなわち@記号をつけることである.
5 define_の使用method
defよりdefine_methodは普通の方法をオブジェクトやクラスに追加する方法にすぎない.
1つのメソッドの体内、または他の類似の場所で、このクラスを再開したい場合(つまり、いくつかのメソッドを追加したい場合)、このクラスがsingleton classでない限り.この場合、古いバージョンのrubyではevalを使用する必要がありますが、define_を使用することができます.method.なぜならdefine_methodはprivateなので、このように使用しなければなりません.
私たちもdefine_methodは直接クラスに挿入されます.
次のようにすることができます.
インスタンス・レベルで使用する場合は、次のようにします.
ここでsendを用いるのは、ruby 1ではsendもプライベートメソッドに用いることができるためである.9ではsendはプライベートメソッドには使用できない.
define_が見えますmethodメソッドには、このblockを定義するコンテキストを保持できることを意味するblockがパラメータとして追加されます.
クラス変数の例を次に示します.
インスタンス変数を読み込むとします.
なんとnilが印刷されています.どうしてですか.しかし、修正すると正しい値を出すことができます.
なぜなら、新しいメソッドのコンテキストは、クラスではなくオブジェクトインスタンスのコンテキストです.したがって、ここでのこのクラスのインスタンス変数は、オブジェクトのインスタンス変数によって
上書きされます.すなわち、ここで印刷されるのは、インスタンス変数@varです.
6 const_の使用missing
const_missingメソッドとmethod_missingは似ています.知らない定数を手に入れたい場合は、この方法が呼び出されます.
彼をクラスの方法として使用するには、次のようにします.
7定義の削除
例えば、私たちはそれを徹底的に削除したいと思っています.その時、undef(defとは正反対)を使うことができます.ローカル変数定数...クラスをundefできないことに注意してください.
ここではインスタンス変数をundefすることはできません.
そしてremove_methodとundef_methodメソッド、彼らの違いはとても細かいです:remove_methodは現在のメソッド定義をremoveします.undef_methodメソッドは、スーパークラスのメソッドなど、すべてのメソッド定義をremoveします.
remove_constはremoveを定数にします.
私たちは今removeを利用することができます.constは、クラスの定義を削除します(クラスの識別子は定数であるため).
remove_に注意constとremove_methodはすべて私有の方法です.
グローバルメソッドevalはrubyコードの断片を含む文字列をコンパイルして実行します.これは実行時に構築できるpowerのメカニズムです.
実行されるコード.次の例を見てください.
parameters = {}
ARGF.each do |line|
name, expr = line.split(/\s*=\s*/, 2)
parameters[name] = eval expr
end
出力は次のように仮定されます.
参照
a = 1
b = 2 + 3
c = `date`
そしてあなたのparametersはこうなるはずです{"a"=>1,"b"=>5,"c"=>"Mon Apr 30 21:17:47 CDT 2001"}.でもこれじゃ危ない
危険性が高く、「rm*」が入ってきたら憂鬱です.
rubyには、実行時にevaluateコード、class_を実行する3つの方法があります.eval, module_eval,instance_eval、最初の2つは同義で、この3つは
つの方法は実はしたことはすべて同じで、彼らはすべてevaluateの1つの文字列で、あるいは1つのblockで、しかしこの事をする時、彼らは
selfは彼ら自身の受信者に変わった.いくつかの例を見たいなら、rubyの内蔵ライブラリdelegateを見ることをお勧めします.rb.
evalメソッドは、ローカル変数の作成ドメインの外でevaluateを呼び出すこともできる.
Kernel#bindingメソッドを使用して、現在のバインドをオブジェクトに割り当てることができます.evalの2番目のパラメータはこのバインドです.
def some_ethod
a = "local variable"
return binding
end
the_binding = some_method
eval "a", the_binding # "local variable"
blockが付いている場合、このblockはこのバインドの一部として格納されます.
def some_method
return binding
end
the_binding = some_method { puts "hello" }
eval "yield", the_binding # hello
2 const_を使うget
const_getメソッドは、クラスまたはモジュールから定数の値を取得します.
str = "PI"
Math.const_get(str) # Evaluates to Math::PI
これはevalの使用を避ける方法です.似たような方法もありますvariable_set, instance_variable_get和
define_method.
const_getはevalより速く、彼はもっと読むことができて、もっと明確です.
3クラスを名前で動的にインスタンス化
const_を使用できますgetメソッド.rubyのすべてのクラスは、通常、Objectのグローバルメンバーとして定数として命名される.
classname = "Array"
klass = Object.const_get(classname)
x = klass.new(4, 1) # [1, 1, 1, 1]
クラス名がネストされていると、エラーが表示されます.
class Alpha
class Beta
class Gamma
FOOBAR = 237
end
end
end
str = "Alpha::Beta::Gamma::FOOBAR"
val = Object.const_get(str) # error!
なぜならconst_getメソッドはそれほどスマートではありませんが、私たちはこのようにすることができます.
str = "Alpha::Beta::Gamma::FOOBAR"
val = str.split("::").inject(Object) {|x,y| x.const_get(y) } # 237
4動的アクセスインスタンス変数
次の例を見てください.
class MyClass
attr_reader :alpha, :beta
def initialize(a,b,g)
@alpha, @beta, @gamma = a, b, g
end
end
x = MyClass.new(10,11,12)
x.instance_variable_set("@alpha",234)
p x.alpha # 234
x.instance_variable_set("@gamma",345) # 345
v = x.instance_variable_get("@gamma") # 345
ここで注意すべきは、変数のフルネームをパラメータとしなければならない、すなわち@記号をつけることである.
5 define_の使用method
defよりdefine_methodは普通の方法をオブジェクトやクラスに追加する方法にすぎない.
1つのメソッドの体内、または他の類似の場所で、このクラスを再開したい場合(つまり、いくつかのメソッドを追加したい場合)、このクラスがsingleton classでない限り.この場合、古いバージョンのrubyではevalを使用する必要がありますが、define_を使用することができます.method.なぜならdefine_methodはprivateなので、このように使用しなければなりません.
if today =~ /Saturday|Sunday/
Object.class_eval { define_method(:activity) { puts "Playing!" } }
else
Object.class_eval { define_method(:activity) { puts "Working!" } }
end
activity
私たちもdefine_methodは直接クラスに挿入されます.
class MyClass
define_method(:mymeth) { puts "This is my method." }
end
次のようにすることができます.
class MyClass
def self.new_method(name, &block)
define_method(name, &block)
end
end
MyClass.new_method(:mymeth) { puts "This is my method." }
x = MyClass.new
x.mymeth # Prints "This is my method."
インスタンス・レベルで使用する場合は、次のようにします.
class MyClass
def new_method(name, &block)
self.class.send(:define_method,name, &block)
end
end
x = MyClass.new
x.new_method(:mymeth) { puts "This is my method." }
x.mymeth # Prints "This is my method."
ここでsendを用いるのは、ruby 1ではsendもプライベートメソッドに用いることができるためである.9ではsendはプライベートメソッドには使用できない.
define_が見えますmethodメソッドには、このblockを定義するコンテキストを保持できることを意味するblockがパラメータとして追加されます.
class MyClass
def self.new_method(name, &block)
define_method(name, &block)
end
end
a,b = 3,79
MyClass.new_method(:compute) { a*b }
x = MyClass.new
puts x.compute # 237
a,b = 23,24
puts x.compute # 552
クラス変数の例を次に示します.
class SomeClass
@@var = 999
define_method(:peek) { @@var }
end
x = SomeClass.new
p x.peek # 999
インスタンス変数を読み込むとします.
class SomeClass
@var = 999
define_method(:peek) { @var }
end
x = SomeClass.new
p x.peek # prints nil
なんとnilが印刷されています.どうしてですか.しかし、修正すると正しい値を出すことができます.
class SomeClass
@var = 999
x = @var
define_method(:peek) { x }
end
x = SomeClass.new
p x.peek # 999
なぜなら、新しいメソッドのコンテキストは、クラスではなくオブジェクトインスタンスのコンテキストです.したがって、ここでのこのクラスのインスタンス変数は、オブジェクトのインスタンス変数によって
上書きされます.すなわち、ここで印刷されるのは、インスタンス変数@varです.
6 const_の使用missing
const_missingメソッドとmethod_missingは似ています.知らない定数を手に入れたい場合は、この方法が呼び出されます.
class Module
def const_missing(x)
"from Module"
end
end
class X
end
p X::BAR # "from Module"
p BAR # "from Module"
p Array::BAR # "from Module"
彼をクラスの方法として使用するには、次のようにします.
class Alpha
def self.const_missing(sym)
"Alpha has no #{sym}"
end
end
class Beta
def self.const_missing(sym)
"Beta has no #{sym}"
end
end
class A < Alpha
end
class B < Beta
end
p Alpha::FOO # "Alpha has no FOO"
p Beta::FOO # "Beta has no FOO"
p A::FOO # "Alpha has no FOO"
p B::FOO # "Beta has no FOO"
7定義の削除
例えば、私たちはそれを徹底的に削除したいと思っています.その時、undef(defとは正反対)を使うことができます.ローカル変数定数...クラスをundefできないことに注意してください.
def asbestos
puts "Now fireproof"
end
tax = 0.08
PI = 3
asbestos
puts "PI=#{PI}, tax=#{tax}"
undef asbestos
undef tax
undef PI
#
ここではインスタンス変数をundefすることはできません.
そしてremove_methodとundef_methodメソッド、彼らの違いはとても細かいです:remove_methodは現在のメソッド定義をremoveします.undef_methodメソッドは、スーパークラスのメソッドなど、すべてのメソッド定義をremoveします.
class Parent
def alpha
puts "parent alpha"
end
def beta
puts "parent beta"
end
end
class Child < Parent
def alpha
puts "child alpha"
end
def beta
puts "child beta"
end
remove_method :alpha # Remove "this" alpha
undef_method :beta # Remove every beta
end
x = Child.new
x.alpha # parent alpha
x.beta # Error!
remove_constはremoveを定数にします.
module Math
remove_const :PI
end
# No PI anymore!
私たちは今removeを利用することができます.constは、クラスの定義を削除します(クラスの識別子は定数であるため).
class BriefCandle
def test
p "aaa"
end
end
out_out = BriefCandle.new
class Object
remove_const :BriefCandle
end
out=BriefCandle.new
out_out.test
remove_に注意constとremove_methodはすべて私有の方法です.