使用するための作業を取得しようとしているだけの場合は、代わりExpando
に使用してください。OpenStruct
しかし、教育的価値のためにこれを行っているのであれば、バグを修正しましょう。
への引数method_missing
これを呼び出すとperson.name = "Michael"
への呼び出しに変換されるperson.method_missing(:name=, "Michael")
ため、正規表現でパラメータを引き出す必要はありません。割り当てる値は別のパラメーターです。したがって、
if method_id.to_s[-1,1] == "=" #the last character, as a string
name=method_id.to_s[0...-1] #everything except the last character
#as a string
#We'll come back to that class_eval line in a minute
#We'll come back to the instance_variable_set line in a minute as well.
else
super.method_missing(method_id, *arguments)
end
instance_variable_set
インスタンス変数名はすべて文字で始まります@
。これは単なる構文糖衣ではなく、実際には名前の一部です。したがって、次の行を使用してインスタンス変数を設定する必要があります。
instance_variable_set("@#{name}", arguments[0])
(割り当てている値をarguments
配列から取得する方法にも注意してください)
class_eval
self.class
Expando
クラス全体を指します。を定義するattr_accessor
と、すべての expando がその属性のアクセサーを持ちます。私はそれがあなたが望むものだとは思わない。
むしろ、ブロック内で行う必要がありますclass << self
(これは のシングルトン クラスまたは固有クラスですself
)。これは の固有クラス内で動作しself
ます。
だから私たちは実行します
class << self; attr_accessor name.to_sym ; end
ただし、変数name
は実際には内部でアクセスできないため、最初にシングルトン クラスを選択してから を実行する必要がありますclass_eval
。これを行う一般的な方法は、これを独自のメソッドで出力eigenclass
することです。
def eigenclass
class << self; self; end
end
代わりに呼び出しself.eigenclass.class_eval { attr_accessor name.to_sym }
ます)
ソリューション
これらすべてを組み合わせると、最終的な解決策は次のようになります
class Expando
def eigenclass
class << self; self; end
end
def method_missing(method_id, *arguments)
if method_id.to_s[-1,1] == "="
name=method_id.to_s[0...-1]
eigenclass.class_eval{ attr_accessor name.to_sym }
instance_variable_set("@#{name}", arguments[0])
else
super.method_missing(method_id, *arguments)
end
end
end