Ruby メソッド定義せずにメソッドを定義する方法
解決済
回答 4
投稿
- 評価
- クリップ 0
- VIEW 1,548
あるコードの中にメソッド定義をしていないのに
普段みない方法でputsでclass名.new.nameみたいな感じで出力していました。
これは一体どういうことなのでしょうか?
どなたか何かご存知であれば教えてください。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
1. クラスの継承や mix-in をしている
2. オープンクラスとして他のファイルで定義してる
3. define_method や eval などで定義してる
4. method_missing をオーバーライドしている
おそらく method_missing が一番気付きにくいので、そちらだとして説明します。
通常、未定義のメソッドを呼び出すとメソッドが未定義というエラー(NoMethodError)が発生します。
実際にはメソッドが見つからない場合
method_missing
というメソッドを呼び出して、その中でエラーを投げています。
そのため、
method_missing
をオーバーライドして、メソッド名に合わせた処理を行えば、
あたかも定義した覚えのないメソッドが使えるようになります。
class Foo
def method_missing(method_symbol, *args)
if (method_symbol == :name)
# メソッド名(シンボル名)が 「 name 」 の場合
self.class.to_s
else
# その他は親クラス(Object)の method_missing を呼び出す
# → NoMethodError を発生させる
super(method_symbol, *args)
end
end
end
p Foo.new.name # "Foo"
こういった機能は メタプログラミング といって、便利だけど危険なので、慣れないうちはあまり使うことのはお勧めしません。
ただ、 Rails などではこの機能が多用されていて、定義したはずのないメソッドをいろいろと使うことになります。こういったことができるというのは知っておいた方がいいと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
以下は method_missing について説明します。
Rubyのmethod_missingの基本的な使い方 より引用。
...上の例では、hoge() というメソッドを定義していないけど、hode(...) の呼び出しはエラーになりません。
class Clazz
def method_missing(name, *args)
puts "Method #{name} was called with #{args.map{|a| a.inspect}.join(',')}"
end
end
clazz = Clazz.new
clazz.hoge('foo', 'bar', 'buz') # => Method hoge was called with "foo","bar","buz"
...
hoge() の呼び出しは method_missing に制御が渡り、 メソッド名 "hoge" と 呼び出し時のパラメータが渡ります。
そして、上の例では、その メソッド名と呼び出し時のパラメータから文字列生成して返しています。
実際の利用に際しては method_missing の中での処理をいろいろ工夫をします。
例:
xml を生成する場合、どんなタグ名を出力するかは利用状況に左右されます。
タグ種類毎に メソッドを用意するというのは不可能です。では、どう対処するか?
一つの方法としてmethod_missing を利用することが考えられます。
次のコードをご覧ください。
class Myxml
def method_missing(name, *args)
puts "<#{name}>"
yield if block_given?
puts "</#{name}>"
end
end
builder = Myxml.new
builder.html {
builder.body {
builder.h1
builder.pr
}
}
これを実行すると、次の出力が得られます。
<html>
<body>
<h1>
</h1>
<pr>
</pr>
</body>
</html>
Myxml クラスでは html(), body(), h1(), pr() といったメソッドを定義していませんが、その名前でメソッドを呼びだせています。
そして、それらしく タグが出力されています。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
このメソッドだったら、クラスやモジュールにメソッドを定義して
defによるメソッド定義を使わなくてもメソッドを定義できますので。
詳しくはRubyのリファレンスでdefine_methodを調べていただければ
良いかと思いますよ。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
あるコードの中にメソッド定義をしていないのに
普段みない方法でputsでclass名.new.nameみたいな感じで出力していました。
とのことですが、その class名 のクラスを、仮に
MyClass
とします。
また、おっしゃられている
普段みない方法
の反対に、「普段みる方法」を
def ・・・end
と記述することでの
メソッド定義という前提のもとに回答します。
MyClassの中で、nameメソッドが、defを使って
def name
・・・・
end
と定義されていなくても、
puts MyClass.new.name
で、MyClassオブジェクトのnameという属性を表示させることができるように
するコードの例として、もう1つ以下が挙げられます。
class MyClass
attr_accessor :name
def initialize
@name = "hello"
end
end
puts MyClass.new.name
上記を実行すると、
hello
と表示されます。
参考までに、以下は「メタプログラミングRuby」P.154からの引用です。
attr_accessor()のようなメソッドはクラスマクロと呼ばれる。クラスマクロは
キーワードのように見えるが、クラス定義の中で使える単なるクラスメソッドである。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.13%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる