こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

オープンクラスで再定義時に別で定義されたメソッドの

オープンクラスで再定義時に別で定義されたメソッドの呼び出しについてです。
ある編集不可能なクラス Hoge の fuga メソッドの戻り値によって、新たなメソッド piyo を定義したいと考え、次のコードを試してみました。

irb(main):001:0> class Hoge
irb(main):002:1> def fuga
irb(main):003:2> 1
irb(main):004:2> end
irb(main):005:1> end
=> :fuga
irb(main):006:0>
irb(main):007:0* class Hoge
irb(main):008:1> if self.fuga == 1
irb(main):009:2> def piyo
irb(main):010:3> puts "foobarbaz"
irb(main):011:3> end
irb(main):012:2> end
irb(main):013:1> end
NoMethodError: undefined method `fuga' for Hoge:Class
from (irb):8:in `<class:Hoge>'
from (irb):7
from /usr/bin/irb:11:in `<main>'

この目的の場合、8~12行目はどのような記述をすれば良いのでしょうか。
なお、Hoge のインスタンス作成後に特異メソッドとして piyo を追加のが都合上、難しい状態です。
バージョンは ruby 2.1.5p273 です。
よろしくお願いします。

投稿日時 - 2015-11-25 00:14:25

QNo.9085709

困ってます

質問者が選んだベストアンサー

fugaがクラスメソッドではなく、インスタンスメソッドとして定義されているのでその辺りで動かなくなっている感じですね。
Object#extendメソッドを使ったり幾つか回答がありますが、最小限の変更でやるなら下のようにnewメソッドでインスタンス作成をやる形で1箇所修正をかけるだけでいけそうですね。

class Hoge
def fuga
1
end
end

class Hoge
if self.new.fuga == 1
def piyo
puts "foobarbaz"
end
end
end

# Hoge.new.piyo # これで実行確認。うまく動きました

投稿日時 - 2015-11-25 12:05:37

お礼

ありがとうございます。
ご指摘のとおり、質問のコードは一旦インスタンス化することで動確できました。

クラス定義の中にあるコードがどのタイミングで動作しているのか、まだよく分かっていませんが、お話によるとインスタンスメソッドはインスタンス化されるまで未定義のようなのですね。Ruby の挙動を考えると、なるほどと感じました。

実は Hoge クラスは new によるインスタンス化ができず、別の編集不可能なモジュール関数の戻り値を受け取ってから使うクラスですので、`self.new.fuga` では対応することができませんでした(質問の条件不足で申し訳ありません)。
こちらについては、もう少し試行錯誤してみて、どうしても分からない場合に再提出させていただきたいと思います。
もちろん、私が提示しましたコードについては、動作できましたのでベストアンサーにさせていただきます。

ありがとうございました。

投稿日時 - 2015-11-25 14:35:15

このQ&Aは役に立ちましたか?

3人が「このQ&Aが役に立った」と投票しています

回答(1)