連載
» 2015年01月06日 20時15分 公開

若手エンジニア/初心者のためのRuby 2.1入門(12):難しいが強力! Rubyのメタプログラミング、self、特異クラス/メソッド、オープンクラスとモンキーパッチ (2/4)

[著:麻田優真、監修:山根剛司,株式会社アジャイルウェア]

クラス自体にメソッドを定義する「self」「特異メソッド」「特異クラス」

 多くのオブジェクト指向プログラミング言語では、「Klass」クラスに対して、「Klass.hoge」という形でメソッドを呼び出せるような仕組みが備わっています。言語により名前は違いますが、一般的に「クラスメソッド」と言う場合が多いようです。

 もちろん、Rubyでも同様のことができます。基本的な機能のように思えますが、実のところ、Rubyのメタプログラミングを理解する上で大切な、「self」「特異メソッド」「特異クラス」といった概念が登場する、奥の深い世界なのです。ここでは、それらの概念について説明します。

「現在のオブジェクト」を表すself

  • pryでselfを感じよう

 Rubyでコードを書いていると、そこにはいつも「self」が存在します。とはいえ、普段それを意識することはあまりないでしょう。「self」はRubyに組み込まれている読み取り専用の変数です。インスタンス変数にアクセスする場合や、メソッドを呼び出す場合にはこの「self」が重要な鍵となります。

 では、pryを使って、身近に存在する「self」を感じてみましょう。

[1] pry(main)> self
=> main
[2] pry(main)> self.class
=> Object

 Rubyのインタプリターを開いた状態を「トップレベル」と呼び、トップレベルでの「self」、すなわち現在のオブジェクトは「main」であることが[1]から分かります。[2]では、その「main」のクラスを「class」メソッドを使って調べており、「Object」クラスであることが分かります。つまり、トップレベルでは、「self」は「Object」クラスのオブジェクトである、ということです。

  • selfを観察する

 では、簡単なクラスの例を使って、「self」に何が入っているのかを観察しましょう。meta_programming_02.rbにコードを示します。

puts "====================="
p self
p self.class
puts "====================="
 
class Rabbit
  puts "====================="
  p self
  p self.class
  puts "====================="
 
  def jump
    puts "====================="
    p self
    p self.class
    puts "pyon pyon"
    puts "====================="
  end
end
 
Rabbit.new.jump
meta_programming_02.rb

$ ruby meta_programming_02.rb 
=====================
main
Object
=====================
=====================
Rabbit
Class
=====================
=====================
#<Rabbit:0x007fc43b0daf78>
Rabbit
pyon pyon
=====================

 コードの1〜4行目は、トップレベルでの「self」が何であるかを示しています。出力は実行例の2〜5行目が対応しています。pryで確かめた時と同様に、トップレベルでの「self」は「main」という名前のオブジェクトを返し、そのクラスは「Object」です。

 コードの7〜10行目は、クラスの定義の中での「self」が何であるかを示しています。出力は実行例の6〜9行目が対応しています。クラス定義の中では、「self」はRabbitクラスそのもの(Rubyではクラスそのものも、「Class」クラスのオブジェクトであることを思い出してください!)です。

 コードの13〜17行目は、メソッドの定義の中での「self」が何であるかを示しています。出力は実行例の10〜14行目が対応しています。メソッド定義の中では、「self」はRabbitクラスのオブジェクトであることが分かります。

 このように、「self」の中身は、コードの場所によって変わることが分かります。

  • 暗黙的なself

 ここまでの例で、「self」は確かにそこにあって、コードの場所によって変わることを確認しました。では、「self」はどこで役に立つのでしょうか? 答えは、メソッドやインスタンス変数へアクセスのときに役立ちます。その例をmeta_programming_03.rbとmeta_programming_04.rbに示しましょう。

class Rabbit
  def initialize
    @roar = "boo"
  end
 
  def _speak
    puts @roar
  end
 
  def speak
    _speak
  end
end
 
Rabbit.new.speak
meta_programming_03.rb
class Rabbit
  def initialize
    @roar = "boo"
  end
 
  def _speak
    puts @roar
  end
 
  def speak
    self._speak
  end
end
 
Rabbit.new.speak
meta_programming_04.rb
$ ruby meta_programming_03.rb 
boo
meta_programming_03(04).rbの実行例

 これらのコードでは、「Rabbit」クラスを定義して、コンストラクターでインスタンス変数「@roar」に、文字列booを設定しています。また、「_speak」および「speak」メソッドを定義しており、「speak」は「_speak」を呼び出すことによって、インスタンス変数「@roar」の内容を出力しています。

 meta_programming_03.rbとmeta_programming_04.rbの違いは、11行目の「_speak」の呼び出し部分です。これまで、meta_programming_03.rbのような記法を利用していましたが、これはmeta_programming_04.rbのように、明示的に「self」を指定することで呼び出すこともできます。

 Rubyでは、「{レシーバー(メソッドを呼び出す対象のオブジェクト)}.{メソッド}」という形でメソッドを呼び出すことが基本です。あるオブジェクト「obj」のメソッド「hoge」を呼び出す場合は、「obj.hoge」となります。

 レシーバーを省略した場合(meta_programming_03.rbの11行目)は、レシーバーとして暗黙的に「self」が使われるため、無事に「Rabbit」クラスの「_speak」メソッドが呼び出されています。また、7行目のようにインスタンス変数にアクセスする場合は、「self」のインスタンス変数が探索されて返されます。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。