6. クラス、モジュール

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

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

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

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

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

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

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 loadrequireはどう違いますか

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

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

ロードパスも違います。

6.12 includeextendはどう違いますか

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

6.13 self というのは何ですか

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

6.14 MatchDatabeginend は何を返しますか

*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この項目がこのページにあるのはおかしい気がする



rubyist ML