# クラス／メソッドの定義

- クラス定義
- 特異クラス定義
- モジュール定義
- メソッド定義
  - メソッド定義のネスト
  - メソッドの評価
- 特異メソッド定義
- クラスメソッドの定義
- 呼び出し制限
- 定義に関する操作
  - alias
  - undef
  - defined?

## クラス定義

例:

    class Foo < Super
      def test
         :
      end
         :
    end

文法:

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

文法:ruby 1.7 feature

    class 識別子 [`<' superclass ]
      式..
    [rescue [error_type,..] [=> evar] [then]
      式..]..
    [else
      式..]
    [ensure
      式..]
    end

クラスを定義します。クラス名はアルファベットの大文字で始まる識別子です。 ruby 1.7 feature: version 1.7 では、rescue/ensure 節を指定で きます。

クラス定義は、識別子で指定した定数へのクラスの代入になります (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

ruby 1.8 feature: クラス Foo が既に定義されていれば、以下の書き 方もできます。

    class Foo
    end

    class Foo::Bar
    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") という形式が使われる

クラス定義式は値を返しません。 ruby 1.7 feature: クラス定義式は、最後に評価した式の結果を返します。最後に評価した式 が値を返さない場合は nil を返します。

## 特異クラス定義

例:

    obj = Object.new # obj = nil でも可
    class << obj
      def test
         :
      end
         :
    end

文法:

    class `<<' expr
      式..
    end

文法:ruby 1.7 feature

    class `<<' expr
      式..
    [rescue [error_type,..] [=> evar] [then]
      式..]..
    [else
      式..]
    [ensure
      式..]
    end

クラス定義と同じ構文で特定のオブジェクトにメソッドやインスタンス変数を 定義/追加します。この構文の内部で定義したメソッドや定数は指定した オブジェクトに対してだけ有効になります。 Object#clone で生成したオブジェクトには引き継がれますが， Object#dup で生成したオブジェクトには引き継がれません． ruby 1.7 feature: version 1.7 では、rescue/ensure 節を指定で きます。

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

## モジュール定義

例:

    module Foo
      def test
         :
      end
         :
    end

文法:

    module 識別子
      式..
    end

文法:ruby 1.7 feature

    module 識別子
      式..
    [rescue [error_type,..] [=> evar] [then]
      式..]..
    [else
      式..]
    [ensure
      式..]
    end

モジュールを定義します。モジュール名はアルファベットの大文字 で始まる識別子です。 ruby 1.7 feature: version 1.7 では、rescue/ensure 節を指定で きます。

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

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

モジュール定義式は値を返しません。 ruby 1.7 feature: モジュール定義式は、最後に評価した式の結果を返します。最後に評価した式 が値を返さない場合は nil を返します。

## メソッド定義

例:

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

文法:

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

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

例:

    def hello    # 引数のないメソッド。
      puts "Hello, world!"
    end

    def foo(a, b)    # 引数のあるメソッド。括弧を省いてdef foo a, bとも
      a + 3 * b
    end

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

例:

    class Vector2D
      attr_accessor :x, :y   # インスタンス変数@x, @yに対応するゲッタとセッタを定義
      def initialize(x, y)   # コンストラクタ
        @x = x; @y = y   # @がつくのがインスタンス変数（メンバ変数）
      end
      def ==(other_vec)   # いわゆる演算子オーバーライド
        other_vec.x == @x && other_vec.y == @y
      end
      def +(other_vec)
        Vector2D.new(other_vec.x + @x, other_vec.y + @y)
      end
      ...
    end
    vec0 = Vector2D.new(10, 20); vec1 = Vector2D.new(20, 30)
    p vec0 + vec1 == Vector2D.new(30, 50) #=> true

仮引数にデフォルト式が与えられた場合、メソッド呼び出しで実引数を省略し たときのデフォルト値になります。 ただし実引数との対応を取るため、i番目の引数にデフォルト値を指定したならば、 i+1番目以降でも全てデフォルト値を指定するか、可変長引数を利用しなければなりません（詳細は後述）。 デフォルト式の評価は呼び出し時にメソッド定義内のコンテキストで行われます。

例:

    def foo(x, y = 1)    # 2番目の引数yにデフォルト値を指定
      10 * x + y
    end
    p foo(1, 5)  #=> 15
    p foo(3)     #=> 31
    p foo        #=> ArgumentError (wrong number of arguments)

    $gvar = 3
    def bar(x, y = $gvar)  # 確かに定義時には$gvar == 3だが
      10 * x + y
    end
    $gvar = 7
    # 呼び出し時の$gvarの値が使われる
    p bar(5)   #=> 57 (!= 53)

最後の仮引数の直前に `*` がある場合には残りの実引数はみな配列とし てこの引数に格納されます。 可変長引数などと呼ばれる機能です。

例:

    def foo(x, *xs)
      puts "#{x} : #{xs.inspect}"   # Object#inspect は p のような詳細な内部表示
    end
    foo(1)        #=> 1 : []
    foo(1, 2)     #=> 1 : [2]
    foo(1, 2, 3)  #=> 1 : [2, 3]

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

例:

    def foo(cnt, &block_arg)
      cnt.times { block_arg.call } # ブロックに収まったProcオブジェクトはcallで実行
    end
    foo(3) { print "Ruby! " } #=> Ruby! Ruby! Ruby!

メソッド定義において、仮引数はその種類毎に以下の順序でしか指定すること はできません。いずれも省略することは可能です。

- デフォルト式のない引数(複数指定可)
- デフォルト式のある引数(複数指定可)
- `*` を伴う引数(1つだけ指定可)
- `&` を伴う引数(1つだけ指定可)

例:

    # すべて持つ
    def foo(arg0, arg1, arg2 = 10, *rest, &block)
      block.call if block
      puts "#{arg0}: #{arg1}: #{arg2}?: #{rest.inspect}"
    end
    foo(1, 2, 3, 4, 5) { print "Args are " }  #=> Args are 1: 2: 3?: [4, 5]

例: イテレータの定義

    # 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(シェル)のコ マンド実行の挙動に不具合がある場合などに利用できます*1。

またメソッド実行時の例外を捕捉するために begin 式と同様 の`rescue`, `else`, `ensure` 節を指定できます。

メソッド定義式は値を返しません。 ruby 1.7 feature: メソッド定義式は、nil を返します。

### メソッド定義のネスト

特異メソッド定義を除くメソッド定義式は ネストできません。

ruby 1.7 feature: 1.7 以降ネスト可能になりました。ネストされた定 義式はそれを定義したメソッドが実行された時に定義されます。このことを除 けば、普通のメソッド定義式と同じです。以下の例を参照してください。 *2

    class Foo
      def foo
        def bar
          p :bar
        end
      end

      def Foo.method_added(name)
        puts "method \"#{name}\" was added"
      end
    end
    obj = Foo.new
    obj.bar rescue nil # => undefined method `bar' for #<Foo:0x4019eda4>
    obj.foo            # => method "foo" was added
    obj.foo            # => warning: method redefined; discarding old bar
    Foo.new.bar        # => :bar  (他のインスタンスでも定義済み)

version 1.6 以前は、同じことを行うのに instance_eval を使 う必要がありました(この場合特異メソッドが定義されるので少し異なります)。

    class Foo
      def foo
        instance_eval <<-END
          def bar
            p :bar
          end
        END
      end
    end

    obj = Foo.new
    def obj.singleton_method_added(name)
        puts "singleton method \"#{name}\" was added"
    end                # => singleton method "singleton_method_added" was added

    obj.bar rescue nil # => undefined method `bar' for #<Foo:0x4019eda4>
    obj.foo            # => singleton method "bar" was added

    obj.foo            # => warning: method redefined; discarding old bar
                       # => singleton method "bar" was added
    Foo.new.bar        # => undefined method `bar' for #<Foo:0x4019eda4>

または、以下のように書くこともできます。*3

    class Foo
       def foo
         instance_eval {
           def bar
             p :bar
           end
         }
       end
     end

### メソッドの評価

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

- 指定されていれば引数のデフォルト式
- メソッドの本体
- 指定されていれば例外の発生の有無によりメソッド定義式の `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 1.7 feature: 特異メソッド定義式は、nil を返します。

## クラスメソッドの定義

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 を参照して ください。

## 呼び出し制限

メソッドは `public`、`private`、`protected` の三通りの 呼び出し制限を持ちます。

- `public` に設定されたメソッドは制限なしに呼び出せます。
- `private` に設定されたメソッドは関数形式でしか呼び出せません。
- `protected` に設定されたメソッドは、そのメソッドを持つオブジェクト のメソッド定義式内でなければ呼び出せません。

例: protected の可視性

    class Foo
      def foo
       p caller.last
      end
      protected :foo
    end

    obj = Foo.new

    # そのままでは呼べない
    obj.foo rescue nil    # => -:11 - private method `foo' called for #<Foo:0x401a1860> (NameError)

    # クラス定義内でも呼べない
    class Foo
      Foo.new.foo rescue nil # => -:15 - protected method `foo' called for #<Foo:0x4019eea8>
      # メソッド定義式内で呼べる
      def bar
        self.foo
      end
    end
    Foo.new.bar             # => ["-:21"]

    # 特異メソッド定義式内でも呼べる
    def obj.bar
      self.foo rescue nil
    end
    obj.bar                 # => ["-:27"]

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

例:

    def foo           # デフォルトは private
    end

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

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

      def initialize  # initialize は private
      end
    end

`private` と `protected` は同じ目的(そのメソッドを隠し外から呼 べないようにする)で使用されますが、以下のような例では、`private` は使えず、`protected` を利用する必要があります。 *4

    class Foo
      def _val
        @val
      end
      protected :_val

      def op(other)

        # other も Foo のインスタンスを想定
        # _val が private だと関数形式でしか呼べないため
        # このように利用できない

        self._val + other._val
      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 はこのことを利用して組み込み変数 に英語名をつけます。 ruby 1.7 feature: version 1.6 では、グローバル変数の別名づけは、 特定の組み込み変数だけが対象でした。version 1.7 ではこの制限は取り除か れています。

    # 特殊な変数のエイリアスは一方の変更が他方に反映される
    $_ = 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

$&, $1, $2, などは直前のマッチの結果値が設定された場合だけ真を返します。

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

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

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

- "super"
- "method"
- "yield"
- "self"
- "nil"
- "true"
- "false"
- "assignment"
- "local-variable"
- "local-variable(in-block)"
- "global-variable"
- "instance-variable"
- "constant"
- "class variable"
- "$&", "$`", "$1", "$2", ...
- "expression"

*1 実際の応用例が [ruby-talk:10006],[ruby-dev:12829]にあります
*2 version 1.8.0 には、ネストして定義したメソッドが Object のインスタンス メソッドになるというバグがありました
*3 1.6 以前は、def 式内の def 式が parser で許されなかったのでこのように書くことはできませんでした
*4 正確には、`private` には関数を定義する目的があるが、呼び 出し制限の目的でも(ここに挙げた制限があるにもかかわらず) `protected` よりは `private` が使われることの方が多いようだ

links: [Class] [Module] [NameError] [Object] [Proc] [Symbol] [importenv.rb] [ruby 1.7 feature] [ruby 1.8 feature] [クラス／メソッドの定義] [メソッド呼び出し] [演算子式] [制御構造] [組み込み関数] [組み込み変数]
reverse links: [1.6.8から1.8.0への変更点(まとめ)] [Module] [Object] [Rubyの文法] [Rubyリファレンスマニュアル] [ToDo] [UnboundMethod] [ruby 1.6 feature] [ruby 1.7 feature] [ruby 1.8 feature] [ruby 1.8.3 feature] [プログラム] [メソッド呼び出し] [機能別索引] [変数と定数]