クラス/メソッドの定義

クラス定義

例:

class Foo < Super
  def test
     :
  end
     :
end

文法:

class 識別子 [`<' superclass ]
  式..
end

クラスを定義します。クラス名はアルファベットの大文字で始まる識別子です。 *1

クラス定義は、識別子で指定した定数へのクラスの代入になります (Ruby では、クラスもオブジェクトの一つで Classクラスの インスタンスです)。

クラスが既に定義されいるとき、さらに同じクラス名でクラス定義を書くとク ラスの定義の追加になります。ただし、元のクラスと異なるスーパークラスを 明示的に指定して定義すると、元のクラスとは異なる新たなクラスを同名で定 義することになります(このとき、クラス名の定数を上書きすることになるの で警告メッセージが出ます)。

class Foo < Array
  def foo
  end
end

# 定義を追加(スーパークラス Array を明示的に指定しても同じ)
class Foo
  def bar
  end
end

# 別のクラスを定義(スーパークラスが異なるので)
class Foo < String
end
# => warning: already initialized constant Foo

クラス定義式の中は self がそのクラスであることと、 呼び出し制限のデフォルトが異なること以外 にトップレベルとの違いはありません。クラス定義式中には任意の式を書くこ とができクラス定義の際に実行されます。

クラス定義はネスト(入れ子)にして定義できます。以下の例で入れ子の外側の クラス Foo と内側のクラス Bar の間には(定数 Bar が Foo の中の定数 Foo::Bar であること以外には)継承関係などの機能的な関連はまったくありま せん。

class Foo
  class Bar
  end
end

クラスのネストは、意味的に関連するクラスを外側のクラス/モジュールでひ とまとまりにしたり、包含関係を表すために使用されます。

# 関連するクラスを Net というカテゴリにまとめる
# このような場合は外側は普通モジュールが利用される
# (Net のインスタンスがない。Net を include できるなどのため)
module Net
  class HTTP
  end
  class FTP
  end
end

obj = Net::HTTP.new

# あるいは

include Net
obj = HTTP.new

# 以下のような使い方は組込みのクラスにも見られる
# 利用者は File::Constants を include することで、
# File::RDONLY などと書かずに直接 RDONLY と書くことができる。
class File
  module Constants
     RDONLY = 0
     WRONLY = 1
  end
  include Constants
end

File.open("foo", File::RDONLY)

# あるいは

include File::Constants
File.open("foo", RDONLY)

# 上記はあくまでも例である。実際の File.open ではより簡便な 
# File.open("foo", "r") という形式が使われる

クラス定義式は値を返しません。

特異クラス定義

例:

class << obj
  def test
     :
  end
     :
end

文法:

class `<<' expr
  式..
end

クラス定義と同じ構文で特定のオブジェクトの機能を定義します。 この構文の内部で定義したメソッドや定数は指定したオブジェクト に対してだけ有効になります。

特異クラス定義式は、最後に評価した式の結果を返します。 最後に評価した式が値を返さない場合は nil を返します。

モジュール定義

例:

module Foo
  def test
     :
  end
     :
end

文法:

module 識別子
  式..
end

モジュールを定義します。モジュール名はアルファベットの大文字 で始まる識別子です。 *2

モジュール定義は、識別子で指定した定数へのモジュールの代入に なります(Ruby では、モジュールもオブジェクトの一つで Moduleクラスのインスタンスです)。

モジュールが既に定義されいるとき、さらに同じモジュール名でモ ジュール定義を書くとモジュールの定義の追加になります。

モジュール定義式は値を返しません。

メソッド定義

例:

def fact(n)
  if n == 1 then
     1
  else
    n * fact(n-1)
  end
end

文法:

def メソッド名 [`(' [arg ['=' default]] ... [`,' `*' arg] [',' '&' arg]`)']
  式..
[rescue [error_type,..] [=> evar] [then]
  式..]..
[else
  式..]
[ensure
  式..]
end

この定義のある場所にメソッドを定義します。すなわち、 クラス/モジュール定義中ならばそのクラス/モジュールのメソッドを 定義します。トップレベルならばどこからでも呼べるメソッドを 定義します。このようなメソッドは結果として他の言語における 「関数」のように使えます。

メソッド名としては通常の識別子の他に、再定義可能な演算子 (例: ==, +, -など 演算子式 を参照)も指定できます。

仮引数にデフォルト式が与えられた場合、メソッド呼び出しで実 引数を省略したときのデフォルト値になります(デフォルト式の 評価は呼び出し時にメソッド定義内のコンテキストで行われます)。

最後の仮引数の直前に * がある場合には残りの実引数は みな配列としてこの引数に格納されます。

例:

# 引数のないメソッド。以下 end は省略
def foo
end

# 引数のあるメソッド
def foo(arg, arg2)

# デフォルト引数のあるメソッド
def foo(arg = nil)

# ブロックをとる
def foo(arg, &block)

# すべて持つ
def foo(arg, arg2, arg3 = nil, *rest, &block)

# 演算子形式
def ==(other)
def +(other)
def *(other)

最後の仮引数の直前に & があるとこのメソッドに与えられているブロッ クが手続きオブジェクト(Proc)としてこの引数に格納されます。これは、 イテレータを定義する方法の一つです。(イテレータを 定義する代表的な方法は yield を呼び出すことです。 他に Proc.new/proc を使う方法などもありま す。) ブロックが与えられなかった場合のブロック引数の値はnilです。 *&が同時に指定される場合には&が後ろに来ます。

例: イテレータの定義

# yield を使う
def foo
  # block_given? は、メソッドがブロックを渡されて
  # 呼ばれたかどうかを判定する組込み関数
  if block_given?
    yield(1,2)
  end
end

# Proc.new を使う
def bar
  if block_given?
    Proc.new.call(1,2)    # proc.call(1,2) でも同じ(proc は組込み関数)
  end
end

    # 応用: 引数として Proc オブジェクトとブロックの
    # 両方を受け付けるイテレータを定義する例
    def foo(block = Proc.new)
      block.call(1,2)
    end
    foo(proc {|a,b| p [a,b]})
    foo {|a,b| p [a,b]}

# ブロック引数を使う
def baz(&block)
  if block
    block.call(1,2)
  end
end

そのほか特殊な形式をとるメソッド定義を以下に挙げます。

# 単項プラス/マイナス
def +@
def -@

# 要素代入
def foo=(value)             # obj.foo = value

# [] と []=
def [](key)                 # obj[key]
def []=(key, value)         # obj[key] = value
def []=(key, key2, value)   # obj[key, key2] = value

# バッククォート記法
def `(arg)                  # `arg` または %x(arg)

バッククォート記法の実装はメソッドなのでこのように再定義が可能です。普 通はこのメソッドを再定義するべきではありませんが、まれにOS(シェル)のコ マンド実行の挙動に不具合がある場合などに利用できます*3

通常のメソッド定義はネストできません*4。またメソッド実行時の例外を捕捉するために begin 式と同様のrescue, else, ensure 節を指定できます。

メソッド定義式は値を返しません。

メソッドの評価

メソッドが呼び出されると、以下の順で式が評価されます。

引数のデフォルト式も含め、すべてそのメソッドのコンテキストで評価されま す。

メソッドの戻り値は return に渡した値です。return が呼び出されなかった場合は、メソッドの本体から ensure 節実行直前 までの最後に評価した式の値を返します。

最後に評価した式が(whileなど)値を返さない式の場合は nil を返します。

またメソッドは定義する前に呼び出すことはできません。例えば

foo
def foo
  print "foo\n"
end

は未定義メソッドの呼び出しで例外 NameError を発生させます。

特異メソッド定義

例:

def foo.test
  print "this is foo\n"
end

文法:

def 式 `.' 識別子 [`(' [引数 [`=' default]] ... [`,' `*' 引数 ]`)']
  式..
[rescue [error_type,..] [=> evar] [then]
  式..]..
[else
  式..]
[ensure
  式..]
end

特異メソッドとはクラスではなくある特定のオブジェクトに固有の メソッドです。特異メソッドの定義はネストできます。

クラスの特異メソッドはそのサブクラスにも継承されます。言い替 えればクラスの特異メソッドは他のオブジェクト指向システムにお けるクラスメソッドの働きをすることになります。

特異メソッド定義式は値を返しません。

クラスメソッドの定義

Ruby におけるクラスメソッドとはクラスの特異メソッドのことです。Ruby で は、クラスもオブジェクトなので、普通のオブジェクトと同様に特異メソッド を定義できます。

したがって、何らかの方法でクラスオブジェクトにメソッドを定義すれば、そ れがクラスメソッドとなります。具体的には以下のようにして定義することが 出来ます(モジュールも同様です)。

# 特異メソッド方式。
class Hoge
  def Hoge.foo
  end
end

# クラス定義の外でも良い
def Hoge.bar
end

# 以下のようにすればクラス名が変わってもメソッド部の変更が不要
class Hoge
  def self.baz
    'To infinity and beyond!'
  end
end

# 特異クラス方式。複数のメソッドを一度に定義するとき向き
class << Hoge
  def bar
    'bar'
  end
end

# モジュールをクラスに extend すれば、モジュールのインスタンス
# メソッドがクラスメソッドになる
module Foo
  def foo
  end
end
class Hoge
  extend Foo
end

extend については、Object#extend を参照して ください。

呼び出し制限

メソッドは publicprivateprotected の三通りの 呼び出し制限を持ちます。

public に設定されたメソッドは制限なしに呼び出せます。 private に設定されたメソッドは関数形式でしか呼び出せません。 protected に設定されたメソッドは、そのメソッドが定義された クラスおよびその下位クラスのインスタンスからしか呼び出せません。

デフォルトでは def 式がクラス定義の外にあれば private、 クラス定義の中にあれば public に定義します。これは Module#publicModule#privateModule#protected を用いて変更できます。ただし initializeという名前のメソッドは定義する場所に関係なく常に privateになります。

例:

def foo           # デフォルトは private
end

class C
  def bar         # デフォルトは public
  end

  def ok          # デフォルトは public
  end
  private :ok     # …だが、ここで private に変わる

  def initialize  # initialize は private
  end
end

定義に関する操作

alias

例:

alias foo bar
alias :foo :bar
alias $MATCH $&

文法:

alias 新メソッド名 旧メソッド名
alias 新グローバル変数名 旧グローバル変数名

メソッドあるいはグローバル変数に別名をつけます。メソッド名に は識別子そのものか Symbol を指定します(obj.method のよ うな式を書くことはできません)。alias の引数はメソッド 呼び出し等の一切の評価は行われません。

メソッドの定義内で別名を付けるにはModuleクラスのメソッド Module#alias_method を利用して下さい。

別名を付けられたメソッドは、その時点でのメソッド定義を引き継 ぎ、元のメソッドが再定義されても、再定義前の古いメソッドと同 じ働きをします。あるメソッドの動作を変え、再定義するメソッド で元のメソッドの結果を利用したいときなどに利用されます。

# メソッド foo を定義
def foo
  "foo"
end

# 別名を設定(メソッド定義の待避)
alias :_orig_foo :foo

# foo を再定義(元の定義を利用)
def foo
  _orig_foo * 2
end

p foo  # => "foofoo"

グローバル変数の alias は一方の変更が他方に反映され、まった く同じ変数であるかのようになります。添付ライブラリの importenv.rb はこのことを利用して組込み変数 に英 語名をつけます。 *5

# 特殊な変数のエイリアスは一方の変更が他方に反映される
$_ = 1
alias $foo $_
$_ = 2
p [$foo, $_]   # => [2, 2]

# こちらは通常の変数のエイリアスで本当の意味での
# エイリアスにはならない。これは、version 1.6 ま
# での制限
$bar = 3
alias $foo $bar
$bar = 4
p [$foo, $bar] # => [3, 4]

ただし、正規表現の部分文字列に対応する変数 $1,$2, ... には別名を付けることができません。ま た、インタプリタに対して重要な意味のあるグローバル変数 (組込み変数を参照)を再定義すると動作に支障を来す場合が あります。

alias 式は nil を返します。

undef

例:

undef bar

文法:

undef メソッド名[, メソッド名[, ...]]

メソッドの定義を取り消します。メソッド名には識別子そのもの か Symbol を指定します(obj.method のような式を書くことはできません)。 undef の引数はメソッド呼び出し等の一切の評価は行われません。

メソッドの定義内で定義を取り消すにはModuleクラスのメソッ ド Module#undef_method を利用して下 さい。

undef のより正確な動作は、メソッド名とメソッド定義との 関係を取り除き、そのメソッド名を特殊な定義と関連づけます。この状態の メソッドの呼び出しは例えスーパークラスに同名のメソッドがあっても例外 NameError を発生させます。 (一方、メソッド Module#remove_method は、関係を取 り除くだけです。この違いは重要です)。

aliasによる別名定義と undefによる定義取り消しによってクラスのインタフェー スをスーパークラスと独立に変更することができます。ただし、メ ソッドがselfにメッセージを送っている場合もあるので、よく注意 しないと既存のメソッドが動作しなくなる可能性があります。

undef 式は nil を返します。

defined?

例:

defined? print
defined? File.print
defined?(foobar)
defined?($foobar)
defined?(@foobar)
defined?(Foobar)

文法:

defined? 式

式が定義されていなければ、偽を返します。定義されていれば式の種別 を表す文字列を返します。

定義されていないメソッド、undef されたメソッド、 Module#remove_method により削除さ れたメソッドのいずれに対しても defined? は偽を返します。

特別な用法として以下があります。

defined? yield

yield の呼び出しが可能なら真(文字列 "yield")を返します。 block_given? と同様にメソッドがブロック付きで呼ばれたか を判断する方法になります。

defined? super

super の実行が可能なら真(文字列 "super")を返します。

defined? a = 1
p a # => nil

"assignment" を返します。実際に代入は行いませんがローカル変数は定義されます。

/(.)/ =~ "foo"
p defined? $&  # => "$&"
p defined? $1  # => "$1"
p defined? $2  # => nil

大文字で始まるメソッド名に対しては () を明示しなければ定数の判定 を行ってしまいます。

def Foo(a,b)
end
p defined? Foo       # => nil
p defined? Foo()     # => "method"
Foo = 1
p defined? Foo       # => "constant"

以下は、defined? が返す値の一覧です。


*1ruby 1.7 feature: version 1.7 では、rescue/ensure 節を指定で きます
*2ruby 1.7 feature: version 1.7 では、rescue/ensure 節を指定で きます
*3 実際の応用例が ruby-talk:10006[外部],ruby-dev:12829[外部]にあります
*4ruby 1.7 feature: 1.7 以 降ネスト可能になりました
*5あらい 2001-11-04: 実際には特定の組込み変数だけが ここに書いた通りの挙動になる。version 1.7 ではこの制 限は取り除かれている