# 6. クラス、モジュール

- 6.1 クラス定義は、一度に行わなければなりませんか
- 6.2 クラス変数はありますか
- 6.3 クラスのインスタンス変数とは何ですか
- 6.4 特異メソッドとは何ですか
- 6.5 クラスメソッドはありますか
- 6.6 特異クラスとは何ですか
- 6.7 モジュール関数とは何ですか
- 6.8 クラスとモジュールの違いは何ですか
- 6.9 モジュールはサブクラスを作りますか
- 6.10 クラス定義の中でクラスメソッドを定義するのと、トップレベルでクラスメソッドを定義する違いは何ですか
- 6.11 `load`と`require`はどう違いますか
- 6.12 `include`と`extend`はどう違いますか
- 6.13 `self` というのは何ですか
- 6.14 `MatchData` の `begin`、`end` は何を返しますか
- 6.15 クラス名からクラスを得ることはできますか

## 6.1 クラス定義は、一度に行わなければなりませんか

同じクラスを再定義すると、前のクラス定義に追加されていきます。 メソッドを再定義した場合には後のものが上書きしますので、前のものは 失われます。

## 6.2 クラス変数はありますか

1.6より実装されました。`@@'で始まる変数はクラス変数です。

    class Foo
      @@F = 0
      def foo
        @@F += 1
        print @@F, "\n"
      end
    end

1.4以前までは定数に代入されたコンテナクラス(Array、Hashなど) がクラス変数の代わりに使用されていました。

    class Foo
      F = [0]
      def foo
        F[0] += 1
        print F[0], "\n"
      end
    end

## 6.3 クラスのインスタンス変数とは何ですか

    class Foo
      @a = 123 # (1)
      def foo
        p @a  # (2) ... 123でなくnilになる。
      end
    end

(1)がクラスのインスタンス変数、(2)が通常のインスタンス変数です。(2)は クラス`Foo`のインスタンスに属するのに対し、(1)は`Foo`というクラ スオブジェクト(Classのインスタンス)に属します。

インスタンスメソッドからクラスのインスタンス変数に直接アクセスすること はできません。

上のように初期化されていないインスタンス変数とみなされ、`nil`になり ます。

## 6.4 特異メソッドとは何ですか

特異メソッドは特定のインスタンスに固有のメソッドです。

こんな感じで使います。

    foo = Foo.new
    def foo.hello
      print "Hello\n"
    end
    foo.hello

クラスにあるメソッドを追加したいが、わざわざサブクラスを作るほどのこと でもない、といった場合に有効です。

Javaをやってる人は匿名のインナークラスに似てると思うかもしれませんね。

## 6.5 クラスメソッドはありますか

クラスの特異メソッドをクラスメソッドと呼びます。特異メソッドは オブジェクトの固有のメソッドだと説明したばかりですが、Rubyには、 メタクラスという概念があり、すべてのクラスは、同名のメタクラスと いうものを持っていて、これは、Classクラスのインスタンスになって います。ここにクラスメソッドが定義されます。

形式的にはクラス名をレシーバーとして呼べるメソッドということに なります。

Classのインスタンスである`Foo`の特異メソッドを考えてみま しょう。

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

呼び出す時はこうです。

    Foo.test

何か気付きませんか？

そう、これはいわゆるクラスメソッドですね。

もちろんClassで定義されているメソッドもクラスメソッドとして使えま す。

## 6.6 特異クラスとは何ですか

すでに特異メソッドについては 触れました。

簡単におさらいするとRubyではオブジェクト(インスタンス)に対してメソッド を追加することができるわけです。

この考えをもう少し進めるとクラスに対する他の操作をオブジェクトに対して も行えるようにしたくなってきませんか？

なってこないよ、と言わないで(^^;

これを可能にするのが特異クラスという機構です。

    class Foo
      def hello
        print "hello.\n"
      end
    end

    foo = Foo.new
    foo.hello

    #=> hello.

    class << foo
      attr :name, true
      def hello
        print "hello. I'm ", @name, ".\n"
      end
    end

    foo.name = "Tom"
    foo.hello

    #=> hello. I'm Tom.

なんかすごいですよね。

ではここで問題。

Q. `private_class_method`を使わずにクラスメソッドをprivateにするにはどうすればよいでしょう？

ヒント: クラスメソッドはクラスの特異メソッドでしたね。

ちょっとトリッキーですが、こんなふうにできます。

    class Foo
      # ...
    end

    class << Foo
      def class_method
        print "class method\n"
      end
      private :class_method
    end
    Foo.class_method #=> Error

特異メソッドを定義するには、このように特異クラスで定義する方法と 直接 def obj.method という風に定義してしまう方法があります。

ちょっと性格は違いますが、モジュールでは、モジュール関数にする ことにより、特異メソッド(と同時にprivateメソッド)を定義する ことができます。

## 6.7 モジュール関数とは何ですか

モジュールの特異メソッドとして、また同時にprivateメソッドして定義されて いるメソッドをRubyではモジュール関数と呼びます。例えば

    Math.sqrt(2)

のように用いることも、

    include Math
    sqrt(2)

のように`include`して用いることもでき、とても便利です。

あるメソッドをモジュール関数にするには、モジュール定義の中で

    module_function :method_name

とします。

## 6.8 クラスとモジュールの違いは何ですか

モジュールはインスタンスを作れません。 クラスはincludeすることができません。

## 6.9 モジュールはサブクラスを作りますか

モジュールは、クラス(モジュール)にincludeされることにより、多重継承に 相当するMix-inを実現します。これは直接の継承であるサブクラスとは 異なりますが、includeされたクラスは、モジュールとis_a?の関係を 持ちます。

## 6.10 クラス定義の中でクラスメソッドを定義するのと、トップレベルでクラスメソッドを定義する違いは何ですか

前者では定数を直接参照することができます。後者ではクラス名をつけて参照 しなければなりません。

## 6.11 `load`と`require`はどう違いますか

`load`はRubyで書かれたソース(`*.rb`)のみロードします。

`require`は`*.o`ファイルもロードします。さらに一度 `require`したファイルは2度`require`してもロードしません。

ロードパスも違います。

## 6.12 `include`と`extend`はどう違いますか

`include`は`module`をクラス(モジュール)にインクルードして、 メソッドを関数形式で呼べるようにし、`extend`は `module`をオブジェクト(インスタンス)にインクルードして、メソッドを 特異メソッドとして追加します。

## 6.13 `self` というのは何ですか

`self`は、メソッドが適用されるオブジェクトそれ自身を表わします。 関数形式のメソッドは、`self`をレシーバーとします。

## 6.14 MatchData の `begin`、`end` は何を返しますか

*1

`$~` に作用して、`$0`、`$1`などの元の文字列での開始位置、 終了位置を返します。タブ展開の例を参照 してください。

## 6.15 クラス名からクラスを得ることはできますか

例えば classname = "SomeClass" のときに SomeClass クラスの インスタンスを作りたいというときです。この問題には主に 二通りの解決策があります。

1. eval(classname).new
2. Object.const_get(classname).new

1 は簡単ですしネストしたクラス (Net::HTTP など) にも対応できますが、 CGI 環境などで迂闊に使うと危険です。

一方、2 の方法ではネストしたクラスに対応できません。 次のようにするとネストしたクラスも扱えるようになります。

    # Ruby 1.8 以降でいいなら
    c = classname.split(/::/).inject(Object) {|c,name| c.const_get(name) }
    c.new

    # Ruby 1.6 にも対応するなら
    c = Object
    classname.split(/::/).each do |name|
      c = c.const_get(name)
    end
    c.new

*1 この項目がこのページにあるのはおかしい気がする

links: [Array] [Class] [FAQ::クラス、モジュール] [FAQ::組み込みライブラリ] [Hash] [MatchData]
reverse link: [Ruby FAQ]