質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.41%

  • Ruby

    8479questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby メソッド定義せずにメソッドを定義する方法

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 982

shin8

score 28

Ruby初心者です。
あるコードの中にメソッド定義をしていないのに
普段みない方法でputsでclass名.new.nameみたいな感じで出力していました。
これは一体どういうことなのでしょうか?
どなたか何かご存知であれば教えてください。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

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 を使っている例だったのではないかと想像されます。
以下は method_missing について説明します。

Rubyのmethod_missingの基本的な使い方 より引用。
...
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() というメソッドを定義していないけど、hode(...) の呼び出しはエラーになりません。
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

もしかしてdefine_methodのことですかね

このメソッドだったら、クラスやモジュールにメソッドを定義して
defによるメソッド定義を使わなくてもメソッドを定義できますので。

詳しくはRubyのリファレンスでdefine_methodを調べていただければ
良いかと思いますよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こんにちは。同じく、Ruby入門者です。

あるコードの中にメソッド定義をしていないのに
普段みない方法で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で質問しよう!

  • ただいまの回答率 90.41%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Ruby

    8479questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。