言語の特徴

Rubyがよく分類される言語としての位置づけは、

  • 純オブジェクト指向言語
  • 軽量言語
  • UNIX指向言語

などが挙げられます。

三つ目の表現はあまり聞きなれないかもしれませんが、 RubyはUNIXで培われた文化を色濃く受け継いでいます。 UNIXコマンド、C言語ライブラリ関数、Perlライブラリルーチンあたりから 借用されたネーミングは数多く、それに馴染んでいる人ならば 容易に動作を予測できるでしょう。 (が、リファレンスはちゃんと見ましょう :-)

また、この特徴を抜きにしても、Rubyはある面では非常に保守的な 手続き型言語です。

Rubyの導入

プログラミング言語/Ruby/RubyInstall?

動作を確認

Windowsならコマンドプロンプト、UNIXならシェルに

 ruby -v

と訪ねてみましょう。インストールに成功していれば、 バージョン情報を教えてくれるはずです。

Hello, world!

定番ですな。

 print "hello, world!"

Rubyドキュメントでの慣習

メソッドとかを説明文中に表記するさい、 それなりに決まった流儀があります。 知っておくとマニュアルとかが読みやすい鴨。

  • Hoge#piyo
  • Foo.bar
  • Vipper::IQ

上から順に、

  • Hogeクラスのオブジェクトが持つpiyoというメソッド
  • Fooクラスが持つメソッド(Javaでいうstaticメソッド)
  • Vipperクラスが持つ定数IQ

文法

Rubyは行指向型言語です。つまり、改行が一文の区切りとなります。

文末記号としてセミコロン';'も使えるのですが、一行に複数の文を書きたいのでもない限り必要ありませんし、推奨されてもいません。rubyのパーザはとかく巨大で複雑なので、少しでも負担を減らしてあげましょう。

 class NoVipError < StandardError ; end

↑セミコロンで文を区切る頻出例。中身のない例外クラスの定義。

なお、Cと同様に、バックスラッシュを打つことで行を継続させることができますし、メソッド呼び出しの引数も複数行にわたって書くことができます。

どこでなにが複数行にわたっての記述が可能か、ということはおおむねユーザの直感にそぐうように決められているので、問題はないでしょう(CやPerlプログラマなら、この直感はより鋭くなるでしょう)。

コメント

 #行末までコメントだぜ

シェルスクリプトやPerlと同じです。

 =begin
   RDを書くところ。
 =end

このように、「'=begin'」のみの行から「'=end'」のみの行 までの間もコメントとして処理系には無視される。 クラスやメソッドの説明をRD(Ruby Document)形式で 書くために使われたりする。

変数

Rubyの変数には型がなく、宣言は初回の代入と同時に 行われます(例外あり)。

Javaな人は「Objectクラスへの参照」型が唯一の型だ、 と考えてもいいかもしれません。Rubyの値はすべてオブジェクト であり、Objectクラスをスーパークラスに持ちますから。

Rubyの変数には数種類ありますが、その種類はPerlのファニー文字の ようにプレフィクスに左右されます。

ローカル変数 -- local_variable
普通に英数字・アンダーバーで名前をつけます。 宣言は代入と同時で、一度も代入していない変数名を参照すると叱られます。 なお、その場合、引数なし・カッコ省略メソッド呼び出しと区別が付かないので、rubyはそのように叱ります。
グローバル変数 -- $global_variable
危険なアイツ。 「$」を先頭に付けます。一度も代入せずに参照するとnilを返します。そういう意味でも危険です (「$var」と間違って「$val」とタイプしてもエラーになりません)。 自分で作った変数ならば、「「$」が先頭 = グローバル変数」なのですが、組み込み変数の中には例外があるので注意が必要です。
定数 -- Constant
Cの感覚な人は、たとえばArrayオブジェクトが入った定数Arrに向かって
Arr.push("hoge")
とかで内容を変えられることに困惑するかもしれません。 この場合、定数として変更不可能なのは「参照先」です。「参照先のオブジェクトの内容に関する変更の禁止」は、また別の方法があります。 大文字から名前が始まるとそれは定数とされ、constやfinalのような特別な修飾はありません。宣言(つまり代入)されていない定数を参照するとエラーになります。
インスタンス変数 -- @instance_variable
オブジェクトの状態。 「@」から始まり、宣言なしに参照するとnilを返します。 C++やJavaなひとはメンバ変数のことだと思ってください。 ただし可視性は設定できず、例外なくクラスの外からはアクセスできません。セッタ・ゲッタを定義する必要があります。
クラス変数 -- @@class_variable
同じクラスのインスタンスに共通の変数。 「@@」から始まり、宣言なしに参照するとエラーになります。 Javaな人はstaticなメンバと似たようなものだと思ってください。

リテラル

Rubyのリテラル表現は豊富です。以下に代表的なものを挙げます。

■数値リテラル(Numeric)

123整数
4567.89実数
?aaの文字コード

■文字列リテラル(String)

"double_quote"式展開などが解釈されます
'single_quote'書いたままになります
`back_quote`コマンドとして実行し、出力を値とします

■□式展開

 val = 123
 puts "put #{val} value"

上のコードの出力は

 put 123 value

となります。ダブルクォート文字列中に#{ ... }で囲った Rubyの式を書くと、それの値を文字列で表現して埋め込みます。

■配列リテラル(Array)

[12, "abc", 123.45]
... コンマで区切って要素を指定します。もちろん一つも要素を指定 しない(`[]'; 空の配列)ことも可能です。

■ハッシュリテラル(Hash)

{ "key" => "value", "KEY" => 123 }
... コンマで区切ってキーと値のペアを指定します。

■シンボルリテラル(Symbol)

:symbol ... symbolというSymbolオブジェクトを生成します。

ブロック付きメソッド呼び出し

メソッドに引数としてオブジェクトを渡すのみならず、処理のカタマリを渡すことができます。

 method_name(arg, ...) do |x|
   ...
 end
 method_name(arg, ...){|x|
   ...
 }

のように記述すると、method_name内に処理を引き渡せます。 いわゆるクロージャ、無名関数あたりのことだと思ってもらえると。

 def method_name(arg, ...)
   ...
   yield(x)
   ...
 end

引き渡した処理は、yield(x)のように、必要ならば引数を与えてメソッド内で呼び出せます。 イテレータなども、この機能によって実装されています。

■[少しわかる人へ]

要はレキシカルクロージャっぽいものを1つだけメソッドに与えてやる 機能が文法として用意されてると思ってもらえれば。

Rubyの真偽評価

以下に述べる条件分岐などで、Rubyの値(=オブシェクト)がどの ように真偽評価されるかを説明します。

結論から言うと、Rubyにおける偽とはfalseとnilであり、 それ以外のあらゆるオブジェクトは真です。

明示的に真を表す代表的な値にtrueがあります。

これら(true, false, nil)は予約語ではなく(嘘です。予約語です。が) それぞれTrueClass, FalseClass, NilClassの唯一のインスタンスです。

制御構造

条件分岐

■if文, if修飾子

 if expr then ...
 ... if expr
 if expr then
   ...
 end

exprを評価して真ならば、ブロック内を実行する。 最後のブロック形式の書き方では、thenは省略可能。

 if expr1 then
   ...  #(a)
 elsif expr2 then
   ...  #(b)
 else
   ...  #(c)
 end

expr1を評価して真ならば(a)部を実行して終わりますが、 そうでない場合、expr2の評価に移ります。

expr2の評価が真ならば(b)を実行し、 それもまた偽ならば(c)を実行します。 elsifはいくつでも使えますし、 もちろんelsifなしでいきなりelseを書いてもOKです。

■unless文, unless修飾子

ifに似た文法をとりますが、unlessは条件式の評価基準が逆です。 つまり、

 ... unless expr

は、exprの評価が偽のときだけ...を実行しますし、

 unless expr then
   ... (d)
 else
   ... (e)
 end

は、exprの評価が真ならば(d)部を実行し、 そうでなければ(e)部を実行します。 ただ、ifにおけるelsifに相当する文はありません。

繰り返し

Rubyにおける繰り返し(ループ)のための文とは、

  • while
  • until
  • for
  • イテレータ です。以下これら総称してただ単にループと呼びます。

■while文

 while cond do
   ...
 end

condの評価が真である限り、ブロック内を実行します。 doは省略可能です。

■until文

 until cond do
   ...
 end

は、if-unlessの関係と同じで、condの評価が偽である限り、 ブロック内を実行します。

■for文

 for x in list
   ...
 end

Rubyのfor文はCなどのものと違い、シェルスクリプトやPerlのforeachに近いです。これは、配列のように複数の要素の集合であるlistに対して、その各要素をxに取り出して順次処理していくときに使われます。

(listの基準 : listのクラスがCollectionだった場合、Collection#eachというメソッドが定義されている必要があります。これはイテレータというやつです。Rubyのforは内部的にこれを利用しています)

■イテレータ

例:Array#each

 array = [1, 2, 3, 4, 5]
 
 array.each do |x|
   p x #=>1, 2, 3, 4, 5
 end

ブロック付きメソッド呼び出しを利用して、 わざわざカウンタ用の変数を用意したり、脱出条件を書かなくても全要素 に対して同じ処理を繰り返せます。

 loop do
   ...
 end

のように、一見制御構造のようなイテレータから、

 n = 1
 
 n.upto(10) do |x|
   p x  #=>1, 2, 3, ..., 9, 10
 end

のように、用途が特化した便利なイテレータもあります。

■break, next, redo, retry

ループ内でのフロー制御文です。

break
現在のループから脱出します。
next
現在のループの、現在の回の残りの文を飛ばして、次の繰り返しに移ります。
redo
現在のループの、現在の回の繰り返しをまた初めからやり直します。
retry
現在のループを始めからやり直します。

例外処理

 begin
   ...  #(a)
 rescue ExClass => ex
   ...  #(b)
 else
   ...  #(c)
 ensure
   ...  #(d)
 end

begin ... endブロック内(の、(a)部)で起きた例外を、 rescueで捕捉します。

rescueのExClassには捕捉する例外クラスを指定し、 => ex で、exという変数に捕捉した例外オブジェクトを 代入します。どちらも省略可能で、ExClassを省略した場合は RuntimeErrorクラスを指定したとみなされます。

指定した例外クラスと、その全てのサブクラスのオブジェクトを 捕捉します。

elseは1つ以上のrescueと組で、例外が発生しなかった場合、 (c)部を実行します。

ensure以下の(d)部は、例外が捕捉されようがされまいが 実行する文を記述します。

もちろん、rescue、else、ensureは省略可能です。 …が、rescueの一つも書かずにbegin ... endでくくっても しょうがないんですが。

クラス定義

せっかくの純オブジェクト指向言語ですから、クラスの作り方をば。

 class ClassName < SuperClassName
   ...
 end

「< SuperClassName」は名の通り継承するクラスを指定します。省略すると自動的にObjectクラスを継承します。

ClassNameは大文字で始める必要があります。定数と同じです(というか、まんま定数なのですが)。

定義したクラスのインスタンスはobj = ClassName.new()のカタチで作れます。カタチを見て判るとおり、newは予約語ではなくメソッド名で、普通に変数名とかにも使えます。

生成したクラスを初期化したい場合、C++やJavaでいうコンストラクタのようなものを定義します。class ... end内で定義されるinitialize()というメソッドがそれです。newは自分の引数をinitializeに丸投げします。

クラスと似たようなものにモジュールがあります。

 module ModuleName
   ...
 end

モジュールはクラスと違って継承できず、インスタンスも持てません。

しかし、include ModuleNameによってそのモジュールで定義した機能をクラス定義中に取り込むことができます(Mix-In)。

■アクセス制御

 class ClassName
 public
   ... #(A)
 private
   ... #(B)
 protected
   ... #(C)
 end

(A)で定義したメソッドはクラス定義の外から(つまりそのクラスのインスタンスをレシーバにして)呼び出せます。

(B)で定義されたメソッドはクラス定義内からしか呼び出せません。

(C)で定義されたメソッドですが、C++やJavaのprotectedとは意味合いが違い、自分のクラスとそのサブクラスからだけ呼べるメソッドになります。

■attr系メソッド -- アクセサ定義

Rubyオブジェクトのインスタンス変数は外からはアクセスできません。がセッタとゲッタを定義することでその問題を回避します。

その場合、set_member(val)、get_member()のような名前で定義するのはRubyでは一般的ではありません。member=(val)、member()のように定義して、あたかもメンバやらプロパティへの代入や参照のように見せかけることができます。インスタンス変数名とメソッド名が衝突しないからです。

ただ、外からアクセスする必要があるインスタンス変数全てに、いちいち

 def member()
   @member
 end
 
 def member=(val)
   @member = val
 end

などと記述しているのは無駄すぎます。そこで、上記のような定義を行うことを請け負ってくれるメソッドがあります。

  • attr_reader ..... 前者(ゲッタ)を定義
  • attr_writer ..... 後者(セッタ)を定義
  • attr_accessor ... 両方を定義

テキトーな用語集

Matz
Rubyの生みの親であるまつもとゆきひろ氏のこと。
モルモン教
キリスト教の宗派。Matzはこの信者。よく煽りのネタにされたが、あまりにイジられすぎて、最早2chRubyスレの習慣と化しつつある。
Duck Typing
アヒルは、アヒルみたいに振舞うからアヒルとして認識されるんだぜ、という考え。つまりvipperがVipperクラスのインスタンスだからVipperなんだなー、と考える のではなく、 aori()やtsuri()など、Vipperらしい振る舞いをする(メソッドを持つ)からこそ、そのvipperというオブジェクトはVipperなんだなー、と捉える考え。
関数
Rubyに関数なんてものはない。 …が、例えばトップレベルで定義されたメソッドはレシーバなしで
n = method()
のように書ける。そのようなメソッドを関数と呼び習わす。

コードリーディング

プログラミング言語/Ruby/コードリーディング

周辺ツール/ライブラリ

プログラミング言語/Ruby/RubyToolLibrary?

参考書籍・WEBページ