第1章 Ruby言語ミニマム

Ruby言語について、当面第一部を理解するのに必要な知識だけ簡単に解説して おく。プログラミング上のテクニックであるとか注意すべきところなんてもの は全く指摘しないので、この章を読んだからと言ってRubyプログラムが書ける ようになるわけではない。既にRuby言語の経験がある読者はこの章は飛ばし て問題ないだろう。

また文法については第二部で嫌というほど話すから、この章ではできるだけ文 法の詳細には関らないようにする。ハッシュリテラルなどバリエーションがあ る表記は最も多用されるもののみ示す。省略可能なものは原則的に省略せずに 示す。そのほうが構文規則がシンプルになるからだ。いちいち「省略できる」 とも言わない。

オブジェクト

文字列

Rubyプログラムが操作できるものは全てオブジェクトである。Javaのintlongのような「基本型(primitive)」はない。例えば以下のように書くと それは「content」 という内容を持った文字列オブジェクト(Stringオブジェクト)である。

"content"

単に文字列オブジェクトと言ったが、正確に言えばこれは文字列オブジェクト を生成する「式」である。だから、何回も書けばそのたびに別の文字列オブジェ クトが生成される。

"content"
"content"
"content"

ここでは「content」という内容を持った文字列オブジェクトが三つ生成される。

ところで、オブジェクトがそこにあるだけではプログラマには見え ない。オブジェクトを端末に表示する方法を教えておこう。

p("content")   # "content"と表示される

#」以降はコメントだ。今後、結果はコメントとして付けておくことに する。

p(……)」は関数pの呼び出しである。任意のオブジェクトを「そ れっぽく」表示してくれる。基本的にデバッグ用の関数だ。

厳密に言うとRubyには関数はないのだが、いまは関数と考えておいてよい。関 数はどこにいても使うことができる。

様々なリテラル

さて、直接オブジェクトを生成する式(リテラル)をもう少し説明しておこう。 まずは一般的なところで、整数と小数だ。

# 整数
1
2
100
9999999999999999999999999   # どんなに大きな数でも使える

# 小数
1.0
99.999
1.3e4     # 1.3×10^4

これも全てオブジェクトを生成する式であることを忘れないでほしい。 繰り返すが、Rubyには「基本型」はない。

以下の表現は配列オブジェクトを生成する。

[1, 2, 3]

このプログラムは整数1 2 3の三つをその順番で要素として持つ配列を生成す る。配列の要素には任意のオブジェクトが使えるので、こんなこともできる。

[1, "string", 2, ["nested", "array"]]

さらに、以下の表現はハッシュテーブルを生成する。

{"key"=>"value", "key2"=>"value2", "key3"=>"value3"}

ハッシュテーブルというのは、任意のオブジェクト同士の一対一対応を表す構 造だ。上記のように書くと次のような関係を記憶したテーブルができる。

"key"   →  "value"
"key2"  →  "value2"
"key3"  →  "value3"

こうやって作ったハッシュテーブルオブジェクトに「"key"に対応付けられて るのは何?」と聞けば、「"value"だよ」と教えてもらえる。どうやって聞 くか。それにはメソッドを使う。

メソッド呼び出し

オブジェクトに対してはメソッドが呼べる。C++用語ではメンバ関数である。 メソッドとは何か、という説明は必要ないと思うので記法だけ簡単に解説す る。

"content".upcase()

ここでは文字列オブジェクト(内容は「content」)に対してupcaseメソッド を呼び出している。upcaseはアルファベットの小文字を大文字にした新しい文 字列を返すメソッドなので、次のような結果になる。

p("content".upcase())   # "CONTENT"と表示される

メソッド呼び出しは連鎖してよい。

"content".upcase().downcase()

この場合、"content".upcase()の返り値のオブジェクトに対してdowncaseメソッ ドを呼ぶ、ということになる。

またJavaやC++のような公開フィールド(メンバ変数)はない。オブジェクト のインターフェイスはメソッドのみである。

プログラム

トップレベル

Rubyでは式をいきなり書けばそれがプログラムになる。 C++やJavaのようにmain()を定義する必要はない。

p("content")

これだけで完結したRubyプログラムである。このリストをfirst.rbという ファイルに入れたとすると、コマンドラインから次のように実行できる。

% ruby first.rb
"content"

rubyコマンドの-eオプションを使えばいちいちファイルを作る必要すらない。

% ruby -e 'p("content")'
"content"

ところで、pが書いてある場所はプログラムのネストレベルが一番低い、 つまりプログラム的には一番「上」なので、「トップレベル」と呼ばれている。 トップレベルがあるのはRubyのスクリプト言語としての大きな特徴だ。

Rubyは基本的に一行が一文である。終端のセミコロンなどは必要ない。 だから以下のプログラムは三文と解釈される。

p("content")
p("content".upcase())
p("CONTENT".downcase())

実行すればこうなる。

% ruby second.rb
"content"
"CONTENT"
"content"

ローカル変数

Rubyでは変数や定数は全てオブジェクトへの参照(reference)を 保持している。だから別の変数に代入しただけでコピーが起こったりはしない。 Javaならオブジェクト型変数、C++ならオブジェクトへのポインタを考えれば いいだろう。ただしそのポインタ自体の値は変更できない。

Rubyでは変数名の一文字目で変数の種別(スコープ)がわかるようになってい る。アルファベット小文字かアンダーバーで始まるのがローカル変数だ。そし て「=」を使って代入を書ける。

str = "content"
arr = [1,2,3]

最初の代入が変数宣言を兼ねるので宣言は必要ない。また変数には 型がないのでどんなオブジェクトだろうと無差別に代入できる。 以下のプログラムは全く合法である。

lvar = "content"
lvar = [1,2,3]
lvar = 1

もっとも、やれるからと言ってやる必要はない。いろいろな種類のオブジェク トを一つの変数にごっちゃに入れたりすれば普通は読みにくくなるものだ。現 実にあるRubyプログラムなら、こういうことは滅多にしない。これはあくまで 例のための例である。

変数参照もごく常識的な記法だ。

str = "content"
p(str)           # "content"が表示される

それから変数がリファレンスを保持するという点を例で見ておこう。

a = "content"
b = a
c = b

このプログラムを実行したあと、a b c三つのローカル変数が指しているのは 同じオブジェクトで、一行目の"content"で生成した文字列オブジェクトであ る図1。

(reference)
図1: Rubyの変数はオブジェクトへの参照を保持する

ところで、ローカルと言うからにはどこかに対してローカルでなければならな いはずだが、しばらく後にならないとこの範囲を言うことができない。とりあ えずトップレベルは一つの「ローカル」スコープだ、ということだけ言ってお こう。

定数

変数名が大文字で始まるのが定数である。定数と言うからには(最初の)一回 しか代入できないものだ。

Const = "content"
PI = 3.1415926535

p(Const)   # "content"と表示される

二回代入するとエラーになる。と言いたいのだが、実は警告だけでエラーにな らない。これは、Rubyプログラム自体を操作するアプリケーション、例えば 開発環境などで、同じファイルを二回ロードしたときにエラーにならないよう にするためだ。つまり実用のためにやむを得ず認めているだけで、本当はエラー にしたいのである。実際にもバージョン1.1まではエラーになっていた。

C = 1
C = 2   # 現実には警告が出るだけだが、理念としてはエラー

さて、定数という言葉で騙される人が多いのだが、定数というのは「いったん 指すオブジェクトを記憶したら二度と変えない」という意味である。定数の指 すオブジェクトそれ自体が変わらないわけではない。英語で言うなら、 constantよりもread onlyのほうがよりよく意図を示しているだろう (図2)。 ちなみにオブジェクト自体が変化しないよう指示するにはfreezeという 別の方法を使う。

(const)
図2: 定数はread onlyの意味

そして実は定数のスコープについてもまだ話せない。次の節でクラスとからめて 話すことにする。

制御構造

Rubyは制御構造が豊富で並べるだけでも大変なので、 とりあえずifwhileはある、ということだけ言っておく。

if i < 10 then
  # 本体
end

while i < 10 do
  # 本体
end

条件式ではfalsenilという二つのオブジェクトだけが偽で、 残りのあらゆるオブジェクトは真になる。0や空文字列ももちろん真だ。

それとついでに、falseだけでは収まりが悪いからtrueもある。 これも当然真だ。

クラスとメソッド

クラス

本来オブジェクト指向システムにおいてメソッドとはオブジェクトに所属する ものだ。だがそれはあくまで理想の世界でのこと。普通のプログラムなら同じ メソッドの集合を持つオブジェクトがたくさんあるわけで、もしバカ正直にオブ ジェクト単位で呼び出せるメソッドを記憶していたりしたら大変なことになっ てしまう。そこで普通はクラスとかマルチメソッドのような仕組みを利用し て定義の重複をなくすわけだ。

Rubyでは、オブジェクトとメソッドを結びつける仕組みとして伝統的な「クラス」 の概念を採用している。即ち全てのオブジェクトはただ一つのクラスに所属 しており、呼び出せるメソッドをクラスで決める。このときオブジェクトのこ とを「○○クラスのインスタンス(instance)」と言うのだった。

例えば文字列"str"Stringクラスのインスタンスである。そしてその Stringクラスにはupcasedowncasestrip、その他いろいろなメソッド が定義されているので、あたかも全ての文字列オブジェクトがこれらのメソッドに 反応できるかのように見えるわけだ。

# みんなStringクラスに属するので同じメソッドが定義されている
       "content".upcase()
"This is a pen.".upcase()
    "chapter II".upcase()

       "content".length()
"This is a pen.".length()
    "chapter II".length()

ところで、呼び出したメソッドが定義されていなかったらどうなるのだろう。 静的な言語ならコンパイルエラーになるところだが、Rubyでは実行時例外にな る。実際に試してみよう。この程度の長さなら-eでプログラムを渡してしま うのが便利だ。

% ruby -e '"str".bad_method()'
-e:1: undefined method `bad_method' for "str":String (NoMethodError)

メソッドが見付からないときはNoMethodErrorというエラーになるようだ。

それと最後に、いちいち「Stringupcaseメソッド」などと言うのは煩わ しいので専用の記法を用意しておこう。「String#upcase」で「Stringク ラスに定義されたupcaseメソッド」を示すことにする。

ちなみに「String.upcase」と書くとRubyの世界では全く別の意味を持つ。 それはどんな意味か。それは次の項で説明する。

クラス定義

ここまでは既に定義されているクラスの話だった。 独自のクラスももちろん定義できる。 クラスを定義するにはclass文を使う。

class C
end

これは新しいクラスCの定義だ。定義したら次のように使うことができる。

class C
end
c = C.new()   # クラスCのインスタンスを作成し変数cに代入

インスタンスを作成する記法はnew Cではないので注意。うーん、なんだか C.new()という記法はメソッド呼び出しみたいだな、と思った読者は鋭い。 Rubyではオブジェクトを生成する式は単なるメソッド呼び出しなのである。

まずRubyにおいてクラス名とは定数名と同義である。ではクラス名と同名の定数 には何が入っているのか。実は、クラスが入っている。Rubyではプログラムが さわれるものは全てオブジェクトだったから、クラスも当然オブジェクトとし て表現されている。これをクラスオブジェクトと呼んでおこう。全てのクラス オブジェクトはClassクラスのインスタンスである。

つまりclass文とは、新しいクラスオブジェクトを作り、クラス名と同名の定 数にそれを代入する、という操作である。一方インスタンスの生成とは、定数 を参照し、そのオブジェクトに対してメソッド(普通はnew)を呼ぶ、という 操作である。以下のような例を見ると、インスタンスの生成が普通のメソッド 呼び出しとなんら変わらないことがよくわかるだろう。

S = "content"
class C
end

S.upcase()  # 定数Sの指すオブジェクトを得てメソッドupcaseを呼び出す
C.new()     # 定数Cの指すオブジェクトを得てメソッドnewを呼び出す

そんなわけでRubyではnewは予約語ではない。

それから、作りたてのクラスのインスタンスでもpできるということを書いて おこう。

class C
end

c = C.new()
p(c)       # #<C:0x2acbd7e4>

さすがに文字列や整数のようにきれいに表示することはできないが、所属クラ スと内部IDを表示してくれる。ちなみにこのIDはオブジェクトを指すポインタ の値だったりする。

そうそう、すっかり忘れていたがメソッド名の記法についてだ。「Object.new」 はクラスオブジェクトObjectそれ自体に対して呼ぶメソッドnew、の意味にな る。「Object#new」と「Object.new」は全く別物なので厳密に区別しなければ いけない。

obj = Object.new()   # Object.new
obj.new()            # Object#new

現実にはObject#newなんてメソッドは定義されていないので このプログラムは二行目でエラーになる。あくまで表記の例として 受け取ってほしい。

メソッド定義

クラスが定義できてもメソッドが定義できなかったら意味がない。 我々のクラスCにもメソッドを定義してみよう。

class C
  def myupcase( str )
    return str.upcase()
  end
end

メソッドを定義するにはdef文を使う。この例ではmyupcaseという メソッドを定義した。パラメータは一つで名前はstrである。 変数のときと同じく、パラメータ変数や返り値の型を書く必要はない。 またパラメータの数はいくつでもよい。

定義したメソッドを使ってみる。メソッドはデフォルトで外から呼べる ようになっている。

c = C.new()
result = c.myupcase("content")
p(result)   # "CONTENT"が表示される

もちろん慣れればいちいち代入する必要はない。以下のように書いても同じで ある。

p(C.new().myupcase("content"))   # 同じく"CONTENT"が表示される

self

メソッド実行中は常に自分自身(メソッドが呼び出されたインスタンス)が 誰であるかという情報が保存されており、selfでその情報を取ることができる。 C++やJavaで言えばthisだ。確かめてみよう。

class C
  def get_self()
    return self
  end
end

c = C.new()
p(c)              # #<C:0x40274e44>
p(c.get_self())   # #<C:0x40274e44>

見てのとおり、二つの式は全く同一のオブジェクトを返している。 つまりcに対するメソッド呼び出しの中にいるときにはselfcであることが 確認できた。

では自分自身に対してメソッドを呼ぶにはどうしたらいいだろうか。 まずself経由で呼ぶ方法が考えられる。

class C
  def my_p( obj )
    self.real_my_p(obj)   # 自分自身に対してメソッドを呼ぶ
  end

  def real_my_p( obj )
    p(obj)
  end
end

C.new().my_p(1)   # 1を表示

しかし自分自身のメソッドを呼ぶのに「自分の」とわざわざ指定しなければな らないのは面倒だ。それでselfに対する呼び出しのときはメソッドを呼び出す 対象のオブジェクト(レシーバreceiver)を省略できるようになっている。

class C
  def my_p( obj )
    real_my_p(obj)   # レシーバ指定なしで呼べる
  end

  def real_my_p( obj )
    p(obj)
  end
end

C.new().my_p(1)   # 1を表示

インスタンス変数

オブジェクトはデータ + コードだ、という表現もあるくらいで、メソッドが定 義できるだけではあまり役に立たない。オブジェクト単位でデータを記憶でき る必要がある。即ちインスタンス変数である。C++で言えばメンバ変数だ。

Rubyの変数名ルール通り、一文字目が種別を決める。インスタンス変数は「@」 だ。

class C
  def set_i(value)
    @i = value
  end

  def get_i()
    return @i
  end
end

c = C.new()
c.set_i("ok")
p(c.get_i())   # "ok"を表示する

インスタンス変数はこれまでの変数とはちょっと変わっていて、代入しなくて も(定義しなくても)参照できる。その場合どうなるかというと……前のコー ドの続きとしてこんなことをやってみた。

c = C.new()
p(c.get_i())   # nilと表示される

setせずにgetしてみたら、nilと表示された。nilというのは「ない」 を意味するオブジェクトである。そこにオブジェクトがあるのに ないというのも不思議だが、そういうものなのだからしかたがない。

nilはリテラルのように使うこともできる。

p(nil)   # nilと表示される

initialize

これまで見てきたように、定義したばかりのクラスでもnewを呼べばインスタ ンスが作れる。それは確かにそうなのだが、クラス特有の初期化をしたいこと もあるだろう。そういうときはnewを変えるのではなくて、initializeという メソッドを定義しておく。そうするとnewの中でそれを呼んでくれる。

class C
  def initialize()
    @i = "ok"
  end
  def get_i()
    return @i
  end
end
c = C.new()
p(c.get_i())   # "ok"と表示される

ただ厳密に言うならこれはあくまでnewというメソッドの仕様であって 言語の仕様ではない。

継承

クラスは他のクラスを継承できる。例えばStringクラスはObjectクラスを 継承している。本書ではこの関係を図3のように縦の矢印で書く。

(supersub)
図3: 継承

この図の場合、継承されるほうのクラス(Object)はスーパークラスとか 上位クラスと呼ぶ。継承したクラス(String)はサブクラスまたは 下位クラスと呼ぶ。この点C++とは用語が違うので注意してほしい。 Javaとは同じだ。

とにかく試してみよう。我々の作ったクラスにも他のクラスを継承させてみる。 クラスを継承して作るには(スーパークラスを指定するには)次のように書く。

class C < SuperClassName
end

これまでのようにスーパークラスを省略して書いたときは暗黙のうちに Objectというクラスがスーパークラスになる。

さてなんのために継承するかと言えば、もちろんメソッドを引き継ぐためだ。 引き継ぐというのは、あたかもスーパークラスでのメソッド定義をサブクラス でもう一度繰り返したかのように働く、ということである。これも試してみよう。

class C
  def hello()
    return "hello"
  end
end

class Sub < C
end

sub = Sub.new()
p(sub.hello())   # "hello"を表示する

helloはクラスCで定義されたメソッドだが、Subクラスのインスタンス に対しても呼ぶことができた。もちろん今度も変数に代入する必要はない。以 下のように書いても同じだ。

p(Sub.new().hello())

同じ名前のメソッドを定義すればオーバーライドできる。C++や Object Pascal(Delphi)では予約語virtualなどで明示的に指定したメソッド しかオーバーライドできないが、Rubyでは全メソッドが無条件にオーバーライ ド可能である。

class C
  def hello()
    return "Hello"
  end
end

class Sub < C
  def hello()
    return "Hello from Sub"
  end
end

p(Sub.new().hello())   # "Hello from Sub"を表示する
p(C.new().hello())     # "Hello"を表示する

またクラスは何段継承してもよい。例えば図4のように。こ の場合FixnumObjectNumericIntegerのメソッド全て を引き継ぐわけだ。同名のメソッドがあるときはより近いクラスのメソッドが 優先される。型によるオーバーロードなんてものは一切ないので条件は非常に 単純である。

(multiinherit)
図4: 多段の継承

それと、C++だと何も継承しないクラスというものを作れるが、Rubyでは必ず Objectクラスを直接または間接に継承しなければならない。つまり継承関係の 図を書くとObjectを頂点とする一本のツリーになる。例えば基本ライブラリの 重要クラスの継承関係をツリーにすると図5のような感じだ。

(classtree)
図5: Rubyのクラスツリー

スーパークラスは一度(定義するときに)決めたらそれきりで、その後は 絶対に変えられない。つまりクラスツリーには新しいクラスが追加されること はあっても位置が移動したり削除されたりすることはない。

変数の継承……?

Rubyでは変数(インスタンス変数)は継承するものではない。継承しようにも、 そのクラスでどんな変数が使われるか、クラスには情報がないからだ。

だがメソッドさえ継承されればその継承したメソッドが呼ばれたときに(下位 クラスのインスタンスで)インスタンス変数への代入が起こる。つまり定義さ れる。そうすれば、インスタンス変数の名前空間はインスタンスごとに完全に フラットなので、どのクラスのメソッドからだろうとアクセスできるようにな る。

class A
  def initialize()   # newの過程で呼ばれる
    @i = "ok"
  end
end

class B < A
  def print_i()
    p(@i)
  end
end

B.new().print_i()   # "ok"と表示される

この挙動が納得できないならクラスと継承を潰して考えてしまうといい。クラ スCのインスタンスobjがあるとしたら、まずCのスーパークラスのメソッ ドが全部Cに定義されているとして考える。もちろんオーバーライドの規則 はちゃんと考慮しよう。そして今度はCのメソッドをobjにくっつけてしま う(図6)。この強烈な「モノ感」がRubyのオブジェクト指向の 特徴である。

(objimage)
図6: Rubyのオブジェクトのイメージ

モジュール

スーパークラスは一つしか指定できなかった。つまりRubyは見ためには 単一継承のように見える。しかし実際にはモジュールがあるために 多重継承と同等の能力を持つ。次にそのモジュールについて説明しよう。

モジュールを一言で言えば、スーパークラスを指定できず、インスタンスも 作れないクラスだ。定義は次のように書く。

module M
end

これでモジュールMが定義された。メソッドもクラスと全く同じに 定義できる。

module M
  def myupcase( str )
    return str.upcase()
  end
end

しかしインスタンスが作れないので直接は呼び出せない。そこでどうする かと言うと、他のクラスに「インクルード」して使う。すると あたかもそのモジュールをクラスが継承したかのように扱うことができる ようになる。

module M
  def myupcase( str )
    return str.upcase()
  end
end

class C
  include M
end

p(C.new().myupcase("content"))  # "CONTENT"と表示される

クラスCでは何のメソッドも定義していないのにmyupcaseを呼び出すことがで きた。つまりこれはモジュールMのメソッドを「継承」したということである。 インクルードは機能的には継承と全く同じものだ。メソッド定義もインスタン ス変数のアクセスもなんら制限されない。

モジュールはスーパークラスを指定できない、と言ったが、 別のモジュールをインクルードすることならできる。

module M
end

module M2
  include M
end

つまりこれまた機能的にはスーパークラスを指定できるのに等しい。ただクラス が上位に来ることだけは決してない。あくまでモジュールの上にはモジュール だけが許される。

メソッドの継承も含めた例を以下に示す。

module OneMore
  def method_OneMore()
    p("OneMore")
  end
end

module M
  include OneMore

  def method_M()
    p("M")
  end
end

class C
  include M
end

C.new().method_M()         # "M"が表示される
C.new().method_OneMore()   # "OneMore"が表示される

クラスと同じように継承を書けば図7のようになる。

(modinherit)
図7: 多段のインクルード

ところでクラスCにはスーパークラスもあるが、それとモジュールの関係はど うなるのだろう。例えば次のような場合を考えよう。

# modcls.rb

class Cls
  def test()
    return "class"
  end
end

module Mod
  def test()
    return "module"
  end
end

class C < Cls
  include Mod
end

p(B.new().test())   # "class"? "module"?

CClsを継承し、Modをインクルードしている。この場合、表示されるのは "class"だろうか、"module"だろうか。つまりモジュールとクラスのどちらが より「近い」のだろうか。RubyのことはRubyに聞け、ということで実行してみる。

% ruby modcls.rb
"module"

スーパークラスよりモジュールが優先されるようだ。

一般的に言うと、Rubyではモジュールをインクルードするとそのクラスと スーパークラスの「間」にはさまるような形で継承する。絵にするなら 図8のように書けるだろう。

(modclass)
図8: クラスとモジュールの相関関係

またモジュールにインクルードされているモジュールも考えれば 図9のようになる。

(modclass2)
図9: クラスとモジュールの相関関係(2)

プログラム(II)

注意。この節は非常に重要で、しかも静的な言語だけを使ってきたプログラ マにはなじみにくい要素を説明している。他は斜め読みでもいいが、ここだけ は注意して読んでほしい。説明も比較的丁寧に行う。

定数のネスト

まず定数について復習。大文字から始まるのが定数で、次のように して定義できた。

Const = 3

そしてこの定数を参照するときは次のようにするのだった。

p(Const)   # 3を表示する

実はこれは次のようにも書ける。

p(::Const)   # 同じく3を表示する

頭に::が付くと「トップレベルで定義された定数である」ことを示す。ファイ ルシステムのパスに例えてみるといい。ルートディレクトリにvmunixというファ イルがあったとしよう。/にいるときは単にvmunixと書けばアクセスできる。 またフルパスで/vmunixと指定することもできる。Const::Constもその関係 と同じである。トップレベルにいる間は単にConstと書いてもいいし、フルパ スで::Constと書いてもいい。

ではファイルシステムのディレクトリにあたるものはRubyではなんだろうか。 それはクラス定義文とモジュール定義文である。しかし二つあると長くて面倒 なので以後はまとめてクラス定義文で代表することにしておこう。そのクラス 定義文中では定数レベルが上がる(ディレクトリの中に入る)。

class SomeClass
  Const = 3
end

p(::SomeClass::Const)   # 3と表示する
p(  SomeClass::Const)   # 同じ。3と表示する

SomeClassはトップレベルで定義されたクラス即ち定数なので単にSomeClassと 書いても::SomeClassと書いても参照できる。そしてそのクラス定義にネスト している定数Constは「SomeClassの中にある」Constということで、 ::SomeClass::Constになる。

ディレクトリの中にまたディレクトリを作れるように、クラスの中でク ラスを作ることもできる。例えばこのように。

class C        # ::C
  class C2     # ::C::C2
    class C3   # ::C::C2::C3
    end
  end
end

ところで、クラス定義文の中で定義した定数は常にフルパスで書かなければいけな いのだろうか。もちろんそんなことはない。ファイルシステムの例えと同じで、 同じレベルのクラス定義文の「なか」にいれば::なしで参照できる。つま りこういうことである。

class SomeClass
  Const = 3
  p(Const)   # 3と表示する
end

あれっ、と思わなかっただろうか。なんと、クラス定義文中だろうと 実行されるプログラムが書けてしまうのである。静的な言語(だけ) に慣れている人だとこれは相当に意外だと思う。筆者も初めて見たときはギョッ とした。

いちおう付け加えておくと、もちろんメソッドの中からでも定数は見える。参 照規則はそのクラス定義文の中(メソッドの外)と全く同じである。

class C
  Const = "ok"
  def test()
    p(Const)
  end
end

C.new().test()   # "ok"を表示

全ては実行される

ここで全体を見据えて一つ書いておこう。 Rubyではプログラムのほとんどの部分が「実行される」。 定数定義・クラス定義文・メソッド定義文やその他 ほとんどのものは見た通りの順番で、実行される。

例えば次のコードを見てほしい。 今までに使った構造をいろいろ使ってみた。

 1:  p("first")
 2:
 3:  class C < Object
 4:    Const = "in C"
 5:
 6:    p(Const)
 7:
 8:    def myupcase(str)
 9:       return str.upcase()
10:    end
11:  end
12:
13:  p(C.new().myupcase("content"))

このプログラムは以下の順番で実行される。

1: p("first")"first"と表示する。
3: < Object定数Objectを参照しクラスオブジェクトObjectを得る
3: class CObjectをスーパークラスとする新しいクラスオブジェクトを生成、定数Cに代入
4: Const = "in C"::C::Constを定義。値は"in C"
6: p(Const)::C::Constを表示。"in C"を表示する。
8: def myupcase(...)...endメソッドC#myupcaseを定義。
13: C.new().myupcase(...)定数Cを参照し、それに対しnewを呼び出し、さらにそれに対しmyupcaseを呼び出す。
9: return str.upcase()"CONTENT"を返す。
13: p(...)"CONTENT"を表示。

ローカル変数のスコープ

これでようやくローカル変数のスコープについて話すことができる。

トップレベル、クラス定義文内、モジュール定義文内、メソッド本体、はそれぞれ 完全に独立したローカル変数スコープを持つ。つまり次のプログラムにあるlvarは 全て別の変数であり、相互に行き来がない。

lvar = 'toplevel'

class C
  lvar = 'in C'
  def method()
    lvar = 'in C#method'
  end
end

p(lvar)   # "toplevel"と表示される

module M
  lvar = 'in M'
end

p(lvar)   # "toplevel"と表示される

コンテキストとしてのself

以前、メソッドを実行中は自分自身(メソッドを呼び出したオブジェクト)が selfになると言った。それは正しいのだが、半分でしかない。実はRubyプログ ラム実行中はどこにいようとselfが設定されている。つまりトップレベルにも クラス定義文にもselfがあるのだ。

例えばトップレベルでもselfがある。トップレベルのselfは、mainという。 なんの変哲もない、Objectクラスのインスタンスだ。mainは とりあえずselfを設定するために用意されているだけで、 それ自体にあまり深い意味があるわけではない。

そんなわけでトップレベルのself即ちmainObjectのインスタンスなの で、トップレベルでもObjectのメソッドが呼べるということになる。そして ObjectにはKernelというモジュールがインクルードされており、そこで pputsなどの「関数風メソッド」が定義されている (図10)。だからこそトップレベルでもpputsが呼べるのだ。

(Kernel)
図10: mainObjectKernel

だから本当はpも関数ではなくメソッドなのである。ただ、Kernelで定義され ているため、どこにいようと、つまりselfのクラスがなんだろうと、「自分の」 メソッドとして関数のように呼べてしまうのだ。だからRubyには本当の意味で の「関数」は存在しない。あるのはメソッドだけである。

ちなみにそういう関数風メソッドにはpputsの他にも print puts printf sprintf gets fork execなどなど、 どこかで見たような 名前のものがたくさん存在する。このへんの名前の選びかたを見ると Rubyの性格がなんとなく想像できるのではなかろうか。

さて、どこにでもselfが設定されているということはクラス定義文中にも 同じようにselfがあるはずだ。クラス定義中のselfはそのクラス (クラスオブジェクト)である。だからこんなふうになる。

class C
  p(self)   # C
end

これが一体何の役に立つのだろう。 実はもう非常に役立つ例を目にしている。これだ。

module M
end
class C
  include M
end

実はこのincludeはクラスオブジェクトCに対するメソッド呼び出しである。ま だ言っていないことだが、Rubyではメソッド呼び出しの括弧が省略できるのだ。 これまではクラス定義文の話が済んでいなかったので、メソッド呼び出しに見 えてしまわないようにあえて括弧を外しておいた。

ロード

Rubyではライブラリのロードも全て実行時に行われる。 通常はこう書く。

require("library_name")

見ためを裏切らずrequireはメソッドである。予約語ですらない。こう書くと こう書いた場所でロードが実行されて、そのライブラリ(のコード)に実行が 移る。Javaのパッケージのような概念はRubyにはないので、ライブラリ名の 名前空間を分離したいときはファイルをディレクトリに入れて分離する。

require("somelib/file1")
require("somelib/file2")

そしてライブラリの中では普通class文やmodule文でもってクラスなどを定義 するわけだ。トップレベルの定数スコープはファイルの別に関係なくフラット なので別のファイルで定義したクラスも最初から見える。クラス名の名前空間 を分離したいときは以下のように明示的にモジュールにネストさせる。

# net ライブラリの名前空間分離の例
module Net
  class SMTP
    # ...
  end
  class POP
    # ...
  end
  class HTTP
    # ...
  end
end

クラスについてさらに

まだ続く定数の話

これまで定数のスコープをファイルシステムに例え てきたが、ここからはその例えはすっかり忘れていただきたい。

定数にはまだまだ仕掛けがある。 まず、「外」のクラスにある定数も見ることができる。

Const = "ok"
class C
  p(Const)   # "ok"を表示
end

なぜこうなっているかと言うと、モジュールを名前空間として使うときに 便利だからだ。どういうことか、先程のnetライブラリの例に少し追加した もので説明しよう。

module Net
  class SMTP
    # メソッドでNet::SMTPHelperを使う
  end
  class SMTPHelper   # Net::SMTPを補助するクラス
  end
end

こういう場合、SMTPクラスの中からもSMTPHelperと書いただけで 参照できるほうが便利ではないだろうか。 そこで「外のクラスが見えると便利」という結論になるわけだ。

「外」のクラスは何段ネストしていても参照できる。同じ名前の定数が複数のネ ストレベルで定義されているときは、内側から順番に見ていって最初に見付かっ たものが参照される。

Const = "far"
class C
  Const = "near" # こちらのほうが上のConstより近い
  class C2
    class C3
      p(Const)   # "near"を表示
    end
  end
end

また定数にはもう一つ検索パスがある。どんどん外のクラスを探していって トップレベルまで行っても見付からなかった場合は、さらに自分の スーパークラスの定数も見るのだ。

class A
  Const = "ok"
end
class B < A
  p(Const)   # "ok"を表示
end

全く、ややこしいことこのうえない。

まとめよう。定数を探すときは、まず外のクラスを探し次にスーパークラスを 探す。例えば、かなり作為的だが、以下のようなクラス階層があったとする。

class A1
end
class A2 < A1
end
class A3 < A2
  class B1
  end
  class B2 < B1
  end
  class B3 < B2
    class C1
    end
    class C2 < C1
    end
    class C3 < C2
      p(Const)
    end
  end
end

C3で定数Constを参照すると図11の順番で検索される。

(constref)
図11: 定数の検索順序

一点注意。外のクラスのスーパークラス、例えばA1B2は全く検索されない。 検索するのは、外ならあくまで外方向に向かってのみ、スーパークラス ならスーパークラス方向のみだ。でないととんでもない数のクラスを検索する ことになりかねないし、そんなに複雑なものは挙動が予測できない。

メタクラス

オブジェクトならばメソッドを呼べる、と言った。呼べるメソッドはオブジェ クトのクラスで決まるとも言った。ならばクラスオブジェクトにも「そのクラス」 があるのだろうか(図12)。

(classclass)
図12: クラスのクラスは?

こういうときRubyでは実際に確かめてみることができる。 「自分の所属するクラス(クラスオブジェクト)を返す メソッド」Object#classがあるからだ。

p("string".class())   # Stringと表示された
p(String.class())     # Classと表示された
p(Object.class())     # Classと表示された

StringClassというクラスに所属しているらしい。 ではさらにClassのクラスはなんだろう。

p(Class.class())      # Classと表示された

またClassらしい。つまりどんなオブジェクトだろうと .class().class().class()……と辿っていけばClassに行き着き、 そこでループにはまってどんづまりになる(図13)。

(ccc)
図13: クラスのクラスのクラスの……

Classはクラスのクラスだ。そして「○○の○○」という再帰構造を 持つもののことを「メタ○○」と言うから、Classは「メタクラス」 である。

メタオブジェクト

では今度は対象を変えて、モジュールについて考えてみる。モジュールもやは りオブジェクトなので、クラスと全く同じように「そのクラス」があるはずだ。 見てみよう。

module M
end
p(M.class())   # Moduleと表示される

モジュールオブジェクトのクラスはModuleと言うらしい。 ではModuleクラスのクラスは何だろう。

p(Module.class())   # Class

これまたClassだ。

それなら今度は方向を変えて継承関係を調べてみる。 ClassModuleのスーパークラスはなんだろうか。 RubyではClass#superclassでそれを調べられる。

p(Class.superclass())    # Module
p(Module.superclass())   # Object
p(Object.superclass())   # nil

なんと、ClassModuleの下位クラスであった。 これらの事実からRubyの重要クラスの関係を図示すると 図14のようになる。

(metaobjects)
図14: Rubyの重要クラスの関係

今まで何の説明もなくnewincludeを使ってきたが、これでようやく正体を 説明できる。newは実はClassクラスで定義されたメソッドなのである。だから どんなクラスでも(Classのインスタンスだから)いきなりnewが使えるわけだ。 しかしModuleにはnewが定義されていないのでインスタンスが作れない。また includeModuleクラスで定義されているから、モジュールに対してもクラスに 対してもincludeが呼べる。

この三つのクラス、ObjectModuleClassはRubyの根幹を支えるオブ ジェクトたちだ。言ってみれば、この三つのオブジェクトがRubyのオブジェク ト世界自体を記述しているわけだ。つまりオブジェクトを記述するオブジェク トである。ならばObject Module ClassはRubyの「メタオブジェクト」だ。

特異メソッド

オブジェクトならばメソッドを呼べる、と言った。呼べるメソッドはオブジェ クトのクラスで決まるとも言った。だが理念としてはメソッドはオブジェクトに 所属するのだということも言ったと思う。あくまでクラスは同じメソッドを 何度も定義してやる手間を省くための仕掛けだと。

そこでだ。実はRubyにはクラスとは関係なく個々のオブジェクト(インスタン ス)に対してメソッドを定義する仕組みもあるのだ。それにはこう書く。

obj = Object.new()
def obj.my_first()
  puts("My first singleton method")
end
obj.my_first()   # My first singleton methodと表示

知ってのとおりObjectは全クラスのルートである。そんな重要クラスに my_firstなどという変な名前のメソッドが定義されているはずがない。そし てobjObjectのインスタンスである。しかしobjに対してmy_firstと いうメソッドを呼ぶことができる。つまり間違いなく、所属するクラスとは全 く全然なにも関係ないメソッドが定義されている。このような、オブジェクト ごとに定義されたメソッドのことを特異メソッド(singleton method)と 言う。

特異メソッドはどんなときに使うか。まずJavaやC++で言う スタティックメソッドの ようなものを定義するときだ。つまりインスタンスを生成しなくても使えるメ ソッドである。こういうメソッドはRubyではクラスオブジェクトの特異メソッ ドとして表現されるのだ。

例えばUNIXのunlinkというシステムコールがある。ファイルのエントリをファ イルシステムから削除する命令だ。RubyではこれをダイレクトにFileクラスの 特異メソッドunlinkとして使えるようにしてある。それを使ってみよう。

File.unlink("core")  # コアダンプを消す

いちいち「Fileオブジェクトの特異メソッドunlink」と言うのは面倒なので、 これからは単に「File.unlink」と書くことにする。間違えてこれを 「File#unlink」と書いたり、逆に「Fileで定義されたメソッドwrite」を 「File.write」と書いたりしないでほしい。

▼メソッド記法のまとめ

記法呼び出せる対象呼び出し例
File.unlinkFileクラス自身File.unlink("core")
File#writeFileのインスタンスf.write("str")

クラス変数

クラス変数はruby 1.6から加わった、比較的新しい機能だ。定数と同じくクラ スに所属しており、クラスと、そのインスタンスの両方から代入・参照できる。 例を見てみよう。変数名の頭を@@にしたものがクラス変数である。

class C
  @@cvar = "ok"
  p(@@cvar)      # "ok"を表示

  def print_cvar()
    p(@@cvar)
  end
end

C.new().print_cvar()  # "ok"を表示

クラス変数も最初の代入が定義を兼ねているので、次のように代入前に 参照すると実行時エラーになる。@こそ付くものの、インスタンス変数 とは振舞いがまるで違うのだ。

% ruby -e '
class C
  @@cvar
end
'
-e:3: uninitialized class variable @@cvar in C (NameError)

ここではちょっと横着して-eオプションでプログラムを与えてみた。 ''で囲まれている三行がプログラムだ。

またクラス変数は継承する。言いかたを変えると、下位クラスから上位 クラスのクラス変数を代入・参照できる。

class A
  @@cvar = "ok"
end

class B < A
  p(@@cvar)            # "ok"を表示
  def print_cvar()
    p(@@cvar)
  end
end

B.new().print_cvar()   # "ok"を表示

グローバル変数

最後に、いちおうグローバル変数もある。プログラムのどこからでも代入・参 照できるのがグローバル変数だ。変数名一文字目を$にしたのがグローバル変数 である。

$gvar = "global variable"
p($gvar)   # "global variable"と表示

グローバル変数はインスタンス変数と同じく、あらゆる名前が代入前に 定義されていると見做せる。つまり代入前に参照しても nilを返すだけでエラーにはならない。


御意見・御感想・誤殖の指摘などは 青木峰郎 <aamine@loveruby.net> までお願いします。

『Rubyソースコード完全解説』 はインプレスダイレクトで御予約・御購入いただけます (書籍紹介ページへ飛びます)。

Copyright (c) 2002-2004 Minero Aoki, All rights reserved.