1. てほどき


シェルから下記を打鍵して,Ruby で hello, world を印字しよう。

$ ruby -e 'puts "hello, world"'
hello, world
$

コマンド ruby は Ruby 言語のインタープリタであり,C 言語で実装されている。 -e オプションを与えると,それに続く引数を1行の Ruby プログラムと見なして実行する。 ここでは puts "hello, world" を実行した。

オプションの一覧は ruby -h を実行すると表示されます。

1行におさまらない複雑なプログラムを実行するには,Ruby プログラムをテキスト・ファイルに書き,そのファイル名を ruby コマンドに引数として与えるとよい。 普通はファイルの拡張子を .rb にする。

本当のことを言えば,拡張子を必ずしも .rb にする必要はありません。 拡張子を無しにしたり,テキスト・ファイルらしく .txt にしても,インタープリタは心広く受け入れてくれます。 しかし,今はさしあたり関係ありませんが,ファイルをライブラリとして使うときは,拡張子を .rb にしないと苦労します。 標準で用意されている便宜関数 require がその拡張子を前提にして作られているからです。 また,Emacs などのテキスト・エディタは拡張子をみて編集モードを Ruby 用に切り替えます。 一般に, 開発ツールの多くは拡張子をもとにファイルの種類を判定します。 ですから,いざとなれば踏み倒すことができるルールですが,特に理由がないかぎり,拡張子は .rb にしておくのが無難です。

複雑なプログラムではないが,試しに,下記の内容の hello.rb を作り,

puts "hello, world"

実行してみよう。

$ ruby hello.rb
hello, world
$

ここで puts は,いわゆる関数であり,引数として与えられた文字列 (ここでは "hello, workd") を印字する。 引数が文字列でなければ,その文字列表現 (例えば,整数 1 ならば文字列 "1") を得て,それを印字する。 複数の引数を与えてもよい。 puts は各引数ごとに,もしも引数の文字列表現が改行で終わっていなければ,改行する。

puts」という関数名は,文字列を引数にとり,文字列と改行を印字する同名の C 言語 標準ライブラリ関数 puts (put string) にちなんでいます。 オリジナルの関数と比べ,Ruby の puts は,文字列以外ならば自動的にその文字列表現を得るなど, 仕様が強化されているわけですが,とにかく,これから分かるように Ruby もまた C 言語の伝統を多く受け継いでいます。 当然,期待されるように Ruby の文字列では C 言語と同じような,つまり C++ や Java とも同じような,エスケープ列が使えます。 例えば,\t はタブ,\n は改行です。
puts の引数を "\thello,\nworld" としたとき,
"hello, world\n" としたとき,
"hello, world\n\n" としたとき,どうなるか確かめてみてください。 2番目の結果に納得がいかないときは,上の本文の最後の文をもう一度読み直してください。

関数に複数の引数を与えるときは,カンマで引数を区切る。 引数 (厳密にいえば,カンマで区切られたゼロ個以上の引数の並び) は丸括弧で囲む。 ただし,あいまいでなければ丸括弧を省略できる。 いままでの例では省略していた。 省略せずに書けば puts("hello, world") のようになる。

$ ruby -e 'puts(1, 2, 3)'
1
2
3
$ ruby -e 'puts 1, 2, 3'
1
2
3
$

デフォルトの設定では Ruby は漢字などのマルチバイト文字を認識せず,単にバイトの列として扱う。 ruby にオプション -Ku-Ke-Ks を与えたときは,それぞれ utf-8,euc-jp, shift_jis が文字エンコーディングとして設定される。 プログラムの字句解析や正規表現の解釈などでは,設定された文字エンコーディングが使われる。

とりわけ,プログラム中の文字列に "ソ" や "表" などのいわゆる SJIS ダメ文字が 含まれているときは,正しい字句解析のために -Ks が必須である。

Ruby には Java 言語で実装された jruby という処理系もあります。基本的には ruby と同じように使うことができますが,今のところ -Ks オプションを正しく実装しておらず,SJIS ダメ文字を含んだプログラムを必ずしも正しく字句解析することができません。
$ nkf -S sososo.rb
puts "ソソソ"
$ ruby sososo.rb | nkf
sososo.rb:1: unterminated string meets end of file
$ ruby -Ks sososo.rb | nkf
ソソソ
$ jruby -Ks sososo.rb | nkf
:1: sososo.rb:2: unterminated string meets end of file (SyntaxError)

ここまでで君は Ruby による hello, world をマスターした。 君は,今,たいていの文字列を Ruby で端末に表示できる。 もちろん,ただメッセージを表示できるだけではつまらない。 次のステップとして Ruby を電卓がわりに使うことをおぼえよう。

1.1 irb: 対話型 Ruby シェル

ruby には対話型 Ruby シェル irb が付属している。i は interactive (形容詞: 対話型の) を意味する。 irb は Ruby プログラムの簡単なテスト・ツールとして,手軽な Ruby 学習ツールとして,そして強力な電卓として使える。 終了するには Control-D を打鍵するか,exit または quit を入力する。

$ irb
irb(main):001:0> 5 + 6
=> 11
irb(main):002:0> quit
$ 

プロンプト irb(main):002:0> の意味は順に, 自分自身のコマンド名 (irb), ここでの self の文字列表現 (main), 入力テキストとしての行番号 (002), 入れ子のレベル (0),そして開始行 (>) である。 self は Ruby で重要な役割を演ずるが,まだ,しばらくは見なかったことにしよう。

入力された式が構文的に完結していないときは,自動的に次の行に継続される。 継続行ではプロンプトに > ではなく * が使われる。

irb(main):001:0> 1 +
irb(main):002:0* 2 + (
irb(main):003:1* (3 + 4 + 
irb(main):004:2* 5))
=> 15
irb(main):005:0>

ここで計算した 5 + 6 (⇒ 11) や 1 + 2 + ( (3 + 4 + 5)) (⇒ 15) は,実は Ruby の文法にしたがった「式」である。 多くのプログラミング言語と同じく,「式」はおなじみの四則演算と括弧と数だけには限られない。 真理値 truefalse や文字列も許される。

irb(main):005:0> true
=> true
irb(main):006:0> false
=> false
irb(main):007:0> "hello, world"
=> "hello, world"
irb(main):008:0> "hello\n world"
=> "hello\n world"
irb(main):009:0>

これから分かるように truefalse や文字列の計算結果の値は,数それ自身の計算結果の値と同じく,自分自身である。

irb(main):009:0> 4242.564
=> 4242.564
irb(main):010:0> 

つまり,難しく言えば,これらは自己評価的 (self-evaluating) な値といえる。 もちろん,これだけだったらほとんど何の役にも立たない。 重要なのは,単純な式から複雑な式を組み立てられることであり,文字列や数はその典型的な構成要素だということである。 式を組み立てる方法として四則演算があるが,より一般的な方法として 関数 の呼出しがある。

jruby 処理系で irb に相当するのは jirb コマンドです。使い方は irb と同様です。
irb は bash と同様,GNU readline による 行編集機能 を備えています。 カーソルキーや Emacs に準じたキー操作によって入力行を編集できます。 しかし,これはオプション機能であり,どこでも使えるとは限りません。 プラットフォームによっては,GNU ライセンス回避のため,不完全な readline 互換ライブラリが用意されている場合もあります。
一方,jirb は自分自身で同様の行編集機能を備えており, どのプラットフォームでも便利に行編集ができます。 ただし,jruby 1.1.6 は,まだ日本語入力に難があります。 irb や jirb で日本語入力ができないときは,コマンド行引数として --noreadline オプションを与えて,行編集機能を切ってみてください。
下記は,jirb でオプションをいろいろかえて文字列 "いろは" を入力してみた例です。 --noreadline オプションを与えたとき,入力行が正しくエコーバックされていることが分かります。 -Ku オプションを与えたとき,ひらがながマルチバイト文字として認識され, 出力がエスケープ列ではなくひらがなの "いろは" となっていることにも注意してください。 ここでは utf-8 端末を使っています。
$ jirb
irb(main):001:0> "?????"
=> "\343\201\204\343\202\215\343\201\257"
irb(main):002:0> exit
$ jirb -Ku
irb(main):001:0> "?????"
=> "いろは"
irb(main):002:0> exit
$ jirb --noreadline
irb(main):001:0> "いろは"
=> "\343\201\204\343\202\215\343\201\257"
irb(main):002:0> exit
$ jirb -Ku --noreadline
irb(main):001:0> "いろは"
=> "いろは"
irb(main):002:0> exit
$ 

1.2 nil

irb から Ruby の任意の関数を呼び出すことができる。 さっき習った puts を呼び出してみよう。

irb(main):006:0> puts "hello, world"
hello, world
=> nil
irb(main):007:0> 

puts の動作として hello, world が印字される。

ここで,puts が印字した行の,次の行にある「=>」に注目しよう。 今までの例では,その先には,式を計算した結果の値が書かれていた (5 + 6 に対する 11 など)。 今は「無」を意味する nil が書かれている。 つまり,puts結果の値 (result value,または単に result, 関数呼出しだから 戻り値, return value とも言う) は nil である。

Ruby には C/C++ で言うような,いわゆる void 関数はない。 すべての関数呼出し,さらにいえば,すべての文が,式としての何らかの結果の値を持つ。 結果の値に意味がないことを示すために nil を使う。

「すべての文がなんらかの結果の値を持つ」は,こうるさくいえば単純化した言い方です (こうるさくいえば,ですから,こだわりのない人は以下の段落をとばしても問題ありません)。
例えば,C++/Java と同じく Ruby でもループを中断するには break を使いますが, これ自体は Ruby が直接「値」として扱えるような値を持ちません。 値を持たせようと思っても持たせることはできません。ナンセンスです。 しかし,その場合でも,break されたループそのものは値を持ちます。 実際,break に引数を与えてその値を指定できます。 ですから,より正確には「Ruby のすべての文は,仮に結果の値があってもおかしくないならば,必ずなんらかの結果の値を持つ」です。
より厳密な議論を求めたい人は「継続」(continuation) をキーワードにして調べてみましょう。

Ruby では,「偽」である false と「無」である nil の二つだけが, 真理値としてのを表す。

irb(main):007:0> if nil then "Yes" else "No" end
=> "No"
irb(main):008:0> 

ここで if X then Y else Z end は, 妥当な任意の XYZ について, X の結果の値が真理値として真ならば Y を実行してその結果の値を返し, 偽ならば Z を実行してその結果の値を返す。

「真」である true を含め,他のすべての値は,真理値としてはと扱われる。

ですから,0 も空文字列 "" もすべて真と見なされます。 上記の if nil thennil0 などに置き換えて確かめてみましょう。

1.3 puts/p と to_s/inspect とオブジェクト指向

puts で文字列を印字するとき,クォーテーションマークは印字されない。 しかし,これまでの例から分かるように,「=>」の先では文字列は (上記の "No" などのように) クォーテーションマーク付きで印字される。

やがて Ruby でプログラミングを始めると,すぐにこのクォーテーションマーク付きの形式で文字列を印字したくなります。 文字列の末尾に余分な空白がついていないかどうか,整数の 11 なのか文字列の "11" なのか,すぐに分かるからです。 とりわけプログラムを作り上げている途中とかデバッグ時には,そういった詳しい情報が分かる文字列表現が役立ちます。

そのような形式で文字列を印字したいときは,関数 p を使う。 たった1文字の関数名だが,中身は puts と同格の立派な関数だ。

irb(main):008:0> p "hello, world"
"hello, world"
=> nil
irb(main):009:0> 

この putsp のすぐ裏側では,Ruby のいわゆる オブジェクト指向 のからくりが働いている。 さっそくだが,少し立ち寄ってみよう。

puts が任意の引数 x を印字するとき,その内部では x に属するメソッド (method, C++ 用語でいうメンバ関数) のうち,一般的な文字列表現を戻り値とする x.to_s() を呼び出して,その戻り値を印字している。 一方,p は,オブジェクト x の (可能ならば) より詳しい文字列表現を戻り値とする x.inspect() を呼び出して,その戻り値を印字している。

puts(x) x.to_s() の戻り値を印字する。
p(x) x.inspect() の戻り値を印字する。
これは単純化した説明です。 正確には,配列 (後述) と nil に対して特別扱いがあります。 ひととおり終わった後で実験してみましょう。

これがうまく働くのは,Ruby のどの値にも (つまり,どのオブジェクトにも) メソッド to_s と inspect が定義されていて,値の型に応じて (つまり,オブジェクトのクラスに応じて) 適切に実装されているからである。 つまり,ここではオブジェクト指向のからくりが持つ 多相性 (polymorphism) が使われている。

このメソッドの振舞は暗記すべき理屈ではない。 今すぐ君の手で試し,君の目で見ることができる事実だ。 文字列のあとにピリオドとメソッド名を続けて to_sinspect を呼び出してみよう。もちろん,丸括弧は書いても省略してよい。

irb(main):008:0> "hello, world".to_s
=> "hello, world"
irb(main):009:0> "hello, world".inspect
=> "\"hello, world\""
irb(main):010:0> 

ここで二つめの「=>」の先にある戻り値に含まれる \" は, C++ や Java でおなじみのエスケープ列であり,「"」1文字を表す。 つまり,inspect の戻り値は内部的には,1文字ごとに | で区切って書くと |"|h|e|l|l|o|,| |w|o|r|l|d|"| であり, たしかに元々の文字の列を「"」文字で囲んでいることが分かる。

この実行例から分かるように,文字列に対し,inspect は前後に「"」文字を付けるだけでなく, 文字列内の「"」文字をエスケープ列 \" にします。 文字列の中の文字として素直に書けない特別な文字にであったら,それをエスケープ列にかえて表現するわけです。
"\r\n".inspect がどんな結果になるか,確かめてみましょう。

整数も試してみよう。 今度は to_sinspect の両メソッドの結果が同じになる。

irb(main):010:0> 2.to_s
=> "2"
irb(main):011:0> 2.inspect
=> "2"
irb(main):012:0> 

プログラムのデバッグ用に,途中経過の値を印字するとき,p を使うと,打鍵数が少なく済み,しかも (可能ならば) より詳細な情報が得られて都合がよい。 逆にいえば,そのような便利さを求めたからこそ,たった1文字の奇妙な関数名が採用されたと言える。 その趣旨から,とりわけ p は引数の丸括弧を省いて使うのが普通である。

"hello, world".to_s2.inspect でピリオドの前にある "hello, world"2レシーバ (receiver) と呼ばれます。 メソッド呼出しをオブジェクトへの メッセージ (message) とみなしたとき, これらはそのメッセージの受取人と見ることができるからです。 この用語の背景には Smalltalk の伝統があり,それなりに広く普及しています。

1.4 self と private メソッド

ここまでの説明で,Ruby に普通の「関数」と,オブジェクト指向的な「メソッド」 (メンバ関数) の二つがあるように誤解させてしまったかもしれない。 実際には Ruby にいわゆる普通の関数はない。 すべてがなんらかのクラスに属する メソッド である。 関数のように見える puts にも レシーバ として C++/Java の this にあたる self が暗黙裏に与えられている。

そして puts は Ruby プログラムのどこからでも呼び出せます。 したがって,当然の帰結として,self は Ruby プログラムのあらゆるところに (場所により,文脈により,それぞれ値は違うかもしれないが) 存在していることになります。 もちろん,君が今 irb で Ruby と対話しているその場所も例外ではありません。

他の構文要素の内側というわけではない トップレベル (top level) にも,self は (まるで空気のように存在感がないけれども,たしかに) 存在している。 君はすでにその文字列表現 "main" をプロンプトの中に見ている。 self はズバリ self という名前でアクセスできる。さっそく確かめてみよう。 C++/Java の this と同様,メソッド呼出しのレシーバが self ならば,それを省略できる。 そのことも確かめてみよう。

irb(main):012:0> self
=> main
irb(main):013:0> self.inspect
=> "main"
irb(main):014:0> inspect
=> "main"
irb(main):015:0> to_s
=> "main"
irb(main):016:0> 

ここまでの例から想像できるように,putsp関数呼出しは,実は self. を省略したメソッド呼出しにほかならない。 ところが,そこからの当然の予想に反し,これらに陽に self. を接頭することはできない。

irb(main):016:0> self.puts 3
NoMethodError: private method `puts' called for main:Object
        from (irb):16
        from :0
irb(main):017:0> 

これは putsp が Ruby 独自の用語法でいうところの private メソッドとして定義されているからだ。 上記のエラーメッセージ "private method `puts' called for main:Object" は,private メソッド puts が,Object クラスのインスタンス main をレシーバとして呼び出されたことを咎めている。これは下記の第1項に反する。

  1. Ruby の private メソッドは,構文的にレシーバを指定できない
  2. Ruby の private メソッドは,public メソッドと同じく派生クラス (サブクラス, subclass とも) からアクセスできる

第1項の帰結として,自分自身,つまり self だけをレシーバとできることが「private」という形容の由来である。 しかし,一般的なオブジェクト指向の用語としての "private" といくらかでも似ている点は,ここまでである。

第2項により,基底クラス (スーパークラス, superclass とも) で用意した private メソッドは, そのすべての派生クラスの文脈で呼び出せることになる。 したがって,もしも仮にすべてのクラスの基底クラスであるような特別なクラスがあるとすれば, そこに private メソッドを用意することにより, (文脈により self の値は変わるけれども) そのメソッドは Ruby のすべての文脈で呼び出せることになる。

C++ と異なり,Java や Smalltalk と類似して,Ruby のクラス階層は単一の頂点をもつ 木構造 です。 そして Object クラスがその頂点として,すべてのクラスの基底クラスになっています。
Ruby 用語としての「モジュール」をまだ説明していませんが,参考のためにいえば,self は文脈によって次のように与えられます。

さらに,もしも private メソッドの動作が,レシーバである self の値に依存していなければ, そのメソッドは,すべての文脈で同じように振舞うことになる。 つまり,そのメソッドは事実上,いわゆる普通のグローバルな関数と同じになる。 これが pputs の正体である。

ここまで読んで,君は pputs のことを Object クラスで定義された private メソッドだと考えるかもしれません。 普通の Ruby プログラムの読み書きでは,そう考えて差しつかえありません。 しかし,真実は少し違います。 メソッド pputs の本当の定義場所は Kernel モジュールです。 3 章末尾 を参照してください。 これが本文で「用意」というあいまいな言い方をした理由です。
継承に関するクラスどうしの関係も,うるさく言えば,単純な木構造ではありません。 Java と異なり,Smalltalk と類似して, Object は,メタクラス (metaclass) である Class の1インスタンスです。 そして ClassModule の派生クラスであり, ModuleObject の派生クラスです。 したがって,その構造はむしろ 循環グラフ です (図としては 5 章の挿し絵の右半分を見てください。 ただし,この図はまだ近似表現です。ある意味では Object よりも基本的であり, ある意味ではそうではない微妙な Kernel モジュールを省略しています)。
しかし,いきなり,はじめからこの種の微妙な細部まで熟知する必要はありません。 さしあたり,Ruby がその単純そうな外見の裏に複雑さを隠していることだけ理解すれば十分です。 本チュートリアルで,あえて真実を垣間見せているのは,後で君が裏切られたと感じないようにするためです。

Ruby についての重要な資料の多くは,Ruby の話者だけに通じる独特な用語法で書かれている。 君が本当に Ruby をマスターするには,遅かれ早かれ,そういった資料にあたる必要があるが, そこに何気なく書いてある用語の定義を読み過ごすと意味がとれなくなる。 さしあたり道に迷わないように,繰返しになるが,次のことをよく銘記しておこう。

現在,広く使われているオブジェクト指向言語のなかで,このようなメソッドを private と形容しているのは Ruby だけである。 他の言語の経験と直感に頼って Ruby の奇妙な private を理解しようとしてはいけない。

現在の文脈で利用可能な private メソッドの一覧self.private_methods で得られる。 pputs が含まれていることを確認しよう。 きっと君は一覧の中に他の言語で親しんでいた名前をいくつか見つけるはずだ。 各メソッドの解説は, Ruby リファレンスマニュアル の「組み込み関数」のページにある。 名前におぼえがある関数について,Ruby ではどんな関数になっているのか,君自身の目と手で確かめてみよう。

irb(main):017:0> self.private_methods()
=> ["getc", "rand", "split", "initialize", "fail", "gsub!", "String", "putc", "e
xec", "sprintf", "load", "iterator?", "catch", "irb_binding", "proc", "p", "sub"
, "syscall", "callcc", "fork", "test", "caller", "Array", "puts", "chop!", "form
at", "require", "scan", "lambda", "block_given?", "throw", "warn", "gsub", "loop
", "open", "initialize_copy", "trap", "singleton_method_added", "exit!", "chomp!
", "gets", "autoload", "system", "trace_var", "irb_exit_org", "global_variables"
, "remove_instance_variable", "`", "chop", "Integer", "printf", "singleton_metho
d_removed", "abort", "readline", "eval", "untrace_var", "sleep", "local_variable
s", "select", "srand", "chomp", "raise", "print", "DelegateClass", "sub!", "Floa
t", "method_missing", "singleton_method_undefined", "autoload?", "binding", "at_
exit", "readlines", "set_trace_func"]
irb(main):018:0>
上記は self に対するメソッド呼出しで一覧が得られることを強調するための, ややわざとらしい例です。 実際に対話入力するときは,レシーバと括弧を省き, 結果の配列を sort メソッドでアルファベット順に整列させて,
private_methods.sort
のように打鍵するとよいでしょう。

1.4.1 配列

ここで private_methods メソッドの戻り値がブラケット [ ] で囲まれていることに注意しよう。 これは Ruby の 配列 (Array) の一例である。 Ruby の配列は,大ざっぱにいえば,Java の java.util.ArrayList や C++ の vector に相当する可変長の列である。 君がここで見ているように, inspect メソッドでは,各要素をカンマで区切り,前後をブラケットで囲んだものとして表現される。 君は,この表現と同じ表記方法で配列のオブジェクトを作ることができる。

配列について大体の感じをつかむため, 試しに irb で [1, 2, 3]["one", "two", "three"] と打鍵してみよう。 また,それに対して inspectto_s を呼び出してみよう。 また,pputs で表示してみよう。

irb(main):001:0> [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> [1, 2, 3].inspect
=> "[1, 2, 3]"
irb(main):003:0> [1, 2, 3].to_s
=> "123"
irb(main):004:0> ["one", "two", "three"]
=> ["one", "two", "three"]
irb(main):005:0> ["one", "two", "three"].inspect
=> "[\"one\", \"two\", \"three\"]"
irb(main):006:0> ["one", "two", "three"].to_s
=> "onetwothree"
irb(main):007:0> p [1, 2, 3]
[1, 2, 3]
=> nil
irb(main):008:0> puts [1, 2, 3]
1
2
3
=> nil
irb(main):009:0> p ["one", "two", "three"]
["one", "two", "three"]
=> nil
irb(main):010:0> puts ["one", "two", "three"]
one
two
three
=> nil
irb(main):011:0> 
配列に対する解説については 4 章 を見てください。 また,配列の抽象化・一般化には 6 章 で説明する Enumerable モジュールが重要な役割を演じます。

1.5 演算子と式と文

Ruby はその外見を伝統的な手続き型言語のように見せるため, おなじみの 単項 前置演算子 や 二項 中置演算子 を採用している。 その実体は,再定義可能なメソッド呼出しか,再定義不可能な制御構造である。

irb で 1.methods.sort を実行して,1 という 整数 オブジェクトに四則演算子と同名のメソッドがあることを確かめてみましょう。

優先順位にしたがって演算子を並べると次のようになる。

       ::
       []
       +(単項)  !  ~
       **
       -(単項)
       *  /  %
       +  -
       <<  >>
       &
       |  ^
       >  >=  <  <=
       <=>  ==   ===  !=   =~   !~
       &&
       ||
       ..  ...
       ?: (条件式)
       = (+=, -= ... )
       , =>
       not
       and or

君が C++ や Java で慣れ親しんできた演算子は Ruby でも概ね同じ意味で通用する。

ただし,!, &&, ||not, and, or は優先順位が異なる。 C++ と異なり,単なる代替つづりではない。 カンマ (,) と => は引数並びの区切りとハッシュ・リテラル (4 章) の区切りである。 厳密には演算子とは言えないが,表の中でこの位置を占めると考えるのが 合理的である。 これらのやや風変わりな仕様は Perl にちなんでいる。

1.2 節 で述べたように,Ruby ではあらゆる文が結果の値をもつ。 したがって,始めと終わりを文括弧などで明確にすることにより, 一つの項として自由に文を式に混ぜることができる。

irb(main):018:0> 1 + if 2 < 3 then p "hi"; 4 else 5 end
"hi"
=> 5
irb(main):019:0> [3, begin i = 3; while i < 10; i += 4 end; i end]
=> [3, 11]
irb(main):020:0> i
=> 11
irb(main):021:0>

ここで

  1. beginend は Java/C++ の { … } に相当する文括弧である。 (2.4 節)
  2. while; 文… end は Java/C++ の while (式) { 文… } に相当する制御構造である。 (2.3 節)
  3. 制御構造の構文で 改行 は空白と同じではない。 (Unix の B-Shell と同じく) セミコロン と同じである。(2 章 前書き)

である。 念のため,最初の例 「1 + if 2 < 3 then p "hi"; 4 else 5 end」 についてかみ砕いて説明しよう。 強調した部分が irb の出力となっている。

  1. この式は,1if 文 (2.1 節) の結果の和を求めている。
  2. if 文は,条件 2 < 3 が真だから, then 以降の p "hi"; 4 の値を結果とする。
  3. 関数呼出し (厳密に言えば,self を暗黙のレシーバとするメソッド呼出し) p "hi""hi" を印字して戻り値を nil とする。
  4. しかし,その戻り値は捨てられ,セミコロンの次の式が評価される。
  5. 次の式である 4 の結果の値,つまり 4 自身が if 文の結果となる。
  6. 結局,14 の和が求められる。
  7. 5 が得られる

下記はセミコロンのかわりに改行を使った例である。

irb(main):021:0> 10 + begin
irb(main):022:1*   i = 3
irb(main):023:1>   while i < 10
irb(main):024:2>     i += 4
irb(main):025:2>   end
irb(main):026:1>   i
irb(main):027:1> end
=> 21
irb(main):028:0> 

ただし,こうした書き方が可能だからといって,こうした書き方をしなければならない, ということでは決してない。 とりわけここに述べた説明用のわざとらしい例のように, 文字列 "hi" を印字したり,変数 i を後に残したりなどと, 文が副作用 (side effect) をもつときは,式と文を区別して 書いたほうが分かりやすい。 つまり,上記はむしろこう書いたほうがよい。

i = 3
while i < 10
  i += 4
end
10 + i

しかし,君は,Ruby では式と文を自由に混ぜることができる,という事実を忘れてはならない。 Lisp とも共通する Ruby のこの性質は,これから Ruby を学び,使っていく過程で時折姿を見せるだろう。

1.6 ローカル変数とメソッド定義

特に説明しなかったが,上の例では変数 i の代入と参照をしている。

Ruby は,事前に宣言しなくても 代入するだけ で変数を設けることができる。 君はそうしようと思えば irb を無尽蔵のメモリ機能付き電卓として使うことができる。

ところで,他の構文要素の内部ではない トップレベル で設けたこの変数は,どんな変数だろうか?

C++/Java の常識には反するが,驚くべきことに, Ruby では,この変数は ローカル変数 (local variable) と呼ばれる。 君は疑問に思うだろう。 ローカル変数とは,メソッドとか関数の中だけのローカルな変数のことではなかっただろうか? その前に,そもそも Ruby ではどのようにメソッドを定義するのだろうか?

メソッド定義 (2.5 節) はキーワード def で始まり,end で終わる。 メソッド定義の頭書きではメソッド名と仮引数を宣言できる。

def foo(x)   # メソッド foo と仮引数 (ローカル変数の一種) x の宣言
  …
  i = 3      # メソッド foo のローカル変数 i への代入end

i = 4        # トップレベルのローカル変数 i への代入 (上の i とは無関係)

仮引数は,メソッドに与えられる実引数との対応付けで設定されるローカル変数である。 メソッドの外側からそれを見ることはできない。 メソッド内部で,代入によってローカル変数を設けることもできる。 設けたローカル変数は,仮引数と同じくそのメソッドの呼出しのための変数になる。

宣言なしに代入によって変数が設けられる,という仕様はいかにもスクリプト言語らしい特徴です。 ここまでは常識の範囲内といってよいでしょう。ここで少し一般的な言語実装の議論に立ち寄ります。

Ruby に限らず,一般に,再帰可能なメソッドや関数,手続き (以下,単にメソッド) をもつ言語処理系の内部では, 実行時,メソッド呼出しごとに新しくフレーム (frame) が作られる。 概念的には,フレームとはローカル変数名からその値への写像である。 典型的には,メソッド呼出しごとにスタックに積み上げられ, メソッドから戻るごとに順に下ろされるから,スタック・フレーム (stack frame) と呼ばれる。

メソッドを呼び出したとき,その内部で使われるローカル変数の実体は,その呼出しのために作られたフレームの中に設けられる。 メソッドが自分自身を呼び出したとき,フレームが別々だから,呼出しごとにローカル変数は別々になる。 したがって,再帰的 (recursive) なメソッドを定義した場合でも,期待される通りに実行される。

ここまでは一般論です。C も C++ も C# も Java も Pascal も Lisp も Prolog も (今どきの) Fortran もすべて概念的にあてはまる話です。

トップレベルは決してメソッドの内部でも本体でもないが,Ruby はトップレベルにもフレームを作る。 おそらく,その動機は,「普通の変数への代入」を実装するとき, 現在有効なフレームにローカル変数を設ける,という処理に統一したかったのだろう。 結果として,トップレベルで i = 4 のような代入をしたとき, ローカル変数 (と同じように実装される変数) i がトップレベル用のフレームの中に設けられる。

もちろん,実装方式がローカル変数と同じでも,言葉としてはそぐわないのだから, 呼称としては別の名前を考えるべきだったのかもしれない。 実際には Ruby の設計者はそうしなかったし, その用語法は少なくとも今 Ruby を使っている人々のあいだで支持されている。 だから君は,たとえ奇天烈だと思っても,さしあたり「ローカル変数」という呼び方で納得する必要がある。 結局のところ,トップレベルが仮想的にメソッド内部にあると見なせば, その振舞をよく説明しているのだから,十分に妥当な選択と言える。

やや込み入ったことを述べましたが,現実のコードはほとんどメソッド定義の中に記述されますから, 実際の Ruby プログラミングにとって,トップレベルの変数が何ものかは重要ではありません。 よく知らなくても,数百行,数千行の優れた Ruby プログラムを書くことができます。 ここであえて触れたのは,トップレベルでのローカル変数という,一見すると奇妙な用語法に対し, 君が違和感と不安をおぼえないようにするためです。
実のところ,筆者による Algol 60 処理系でも,トップレベルの変数をスタック・フレームで実現しています (参照: PLY で作る Algol 60 処理系 §9. インタープリタ - 手続きとディスプレイとスタック)。 display 経由で入れ子の手続きからローカル変数へアクセスするならば,トップレベルの変数を このように実現するのは自然な方法です。
Ruby はそうではありません。 Ruby は文法の若干の類似性から Algol 系言語と呼ばれることがありますが,Algol やその代表的な派生言語と異なり,メソッド定義の外側の「ローカル変数」にアクセスできません。
irb(main):001:0> i = 100
=> 100
irb(main):002:0> def foo
irb(main):003:1>    puts i
irb(main):004:1> end
=> nil
irb(main):005:0> foo
NameError: undefined local variable or method `i' for main:Object
        from (irb):3:in `foo'
        from (irb):5
        from :0
irb(main):006:0> 
同様のことを Algol 60 でしたとき,エラーは起こりません。
$ algol60 -
begin
   integer i;
   procedure foo;
      print(i);
   i := 100;
   foo
end
^D
100
$ 
Algol との類似性だけから判断すれば,Ruby は典型的な実装方法を中途半端にまねた粗悪な模造品です。 しかし,Algol のかわりではなく,Ruby らしくプログラムを組むかぎり,こうした仕様が現実的な問題になることは,まずありません。 広域的に命名された値という役割は, Ruby では典型的には,定数インスタンス変数 が担います (本物の グローバル変数 もありますが,良い Ruby プログラムではあまり使いません)。 入れ子の関数定義に代わる優れた代替物として (Algol ではなく Ruby の用語法でいうところの) ブロックを使うことができます。 Ruby は Ruby です。

平凡な例だが,下記は,引数に 1 を足した値を返すメソッドの定義と,その呼出しである。 メソッド本体 (ここでは「n + 1」) の結果の値が,メソッド自体の戻り値となることに注目しよう。

irb(main):001:0> def add1(n)
irb(main):002:1>    n + 1
irb(main):003:1> end
=> nil
irb(main):004:0> add1(0)
=> 1
irb(main):005:0> add1(1)
=> 2
irb(main):006:0> add1(2)
=> 3
irb(main):007:0> 10 + add1(3)
=> 14
irb(main):008:0> 

1.6.1 さらにメソッド定義について

それほど平凡ではない例として,次のようにトップレベルでメソッドを定義し,それを呼び出してみよう。

irb(main):028:0> def foo(x)
irb(main):029:1>   if x <= 0
irb(main):030:2>     return []
irb(main):031:2>   else
irb(main):032:2*     return [x, foo(x - 1)]
irb(main):033:2>   end
irb(main):034:1> end
=> nil
irb(main):035:0> foo(3)
=> [3, [2, [1, []]]]
irb(main):036:0> 

foo は1個の仮引数 x を持つ。 return は C++/Java と同様の意味を持つ。 x がゼロ以下のとき,[] つまり空の配列が戻り値として返される。 そうでないとき,xfoo(x - 1) の値からなる長さ2の配列が 戻り値として返される。 最後に実行した文や式の結果の値が戻り値となるから,この例では return を省略して,式をじかに書いてもよい。 irb の「=> nil」から分かるように,メソッド定義それ自体は戻り値として nil を返す。

多くの場合,return は不要です。 しかし,末尾の位置にある式が,戻り値となることを意図しているのかどうか,コードだけからは 判然としないことがよくあります。 未来の君自身を含め,プログラムを読む人に意図をよく伝えるために return を陽に書いておくと親切です。

上記の定義の [x, foo(x - 1)]foo(x - 1).unshift(x)foo(x - 1).push(x) に変えて実験してみよう。 unshiftpush はどちらも Perl にちなんだ要素追加のメソッドである。 いろいろ変えて実験するときは,関数定義をファイル (例えば foo.rb) に格納して, それを変更するようにすると手間がかからない。 いろいろな引数を思いつきで試すには,irb を -r オプション付きで実行するとよい。 引数で指定したファイルを実行してから,対話セッションに入る。

$ emacs foo.rb
$ cat foo.rb
def foo(x)
  if x <= 0
    return []
  else
    return [x, foo(x - 1)]
  end
end
$ irb -r foo.rb
irb(main):001:0> foo(4)
=> [4, [3, [2, [1, []]]]]
irb(main):002:0> foo(0)
=> []
irb(main):003:0> exit
$ 

階乗関数,tarai 関数, Ackermann 関数など,君の知っているお気に入りの関数を書いて実行してみよう。 複数の仮引数を宣言するときは,実引数のときと同じようにカンマで区切ればよい。 多重に分岐するときは

if 式; 文… elsif 式; 文… elsif 式; 文… else 文… end

が使える (2.1 節)。 メソッドの名前は大文字で始めても小文字で始めてもよいが, ローカル変数の名前は (仮引数も含めて) 小文字で始める必要がある (3.5 節)。

$ emacs ackermann.rb
$ cat ackermann.rb
def Ackermann(m, n)
  if m == 0
    return n + 1
  elsif n == 0
    return Ackermann(m - 1, 1)
  else
    return Ackermann(m - 1, Ackermann(m, n - 1))
  end
end
$ irb -r ackermann.rb
irb(main):001:0> Ackermann(0, 0)
=> 1
irb(main):002:0> Ackermann(1, 1)
=> 3
irb(main):003:0> Ackermann(2, 3)
=> 9
irb(main):004:0> Ackermann(3, 4)
=> 125
irb(main):005:0> exit
$ 
よく知られているように,Ackermann 関数は,少し大きな引数を与えるだけで, 急激に呼出しの入れ子階層が深くなり,事実上,計算できなくなります。 使っている Ruby 処理系がそれにどこまで耐えられるか, どのようなエラーで終わるのか,一度は経験しておくとよいでしょう。

1.6.2 トップレベルのメソッド定義の真実

ところで,トップレベルでのメソッド定義は「メソッド」をどのようなものとして定義するのだろうか?

君が予想するとおり,ruby のトップレベルでのメソッド定義は, Object クラスの private メソッドとして「メソッド」を定義する。 より厳密にいえば,Objectprivate インスタンス・メソッド として定義する。

インスタンス・メソッドとは, そのクラスのすべてのインスタンスに対して定義されているメソッドのことです。 多くのオブジェクト指向言語で,普通にいうメソッドのことです。 Java のメソッドや C++ のメンバ関数はこれに相当します。 ですから,今までインスタンス・メソッドのことを単にメソッドと呼んできました。
Ruby では,Smalltalk と同じく,クラスもまた (メタクラスの) インスタンスですから, それ自身に対してもメソッドが定義されています。 インスタンスを生成する new は,Ruby ではそのようなメソッドとして用意されています。
a = Array.new(3)   # 長さ 3 の配列を生成する
このようなメソッドはインスタンス・メソッドと区別してクラス・メソッドと呼ばれます。 ただし,メタクラスの立場から見れば,それらは (メタクラスの) インスタンス・メソッドです。

つまり,メタクラスを意識する考え方では,すべてはインスタンス・メソッドです。 一方,メタクラスを意識しない観点では, インスタンス・メソッドとクラス・メソッドの2種類があります。

pputs に対する説明の繰り返しのようになるが, Object クラスは,(メタクラスも含めて) あらゆるクラスの基底クラスであり, Ruby のあらゆるオブジェクトは例外なく Object クラスのインスタンスである。 したがって,トップレベルで定義したメソッドは, 事実上,グローバルな関数としてどの文脈からも利用できる。

ただし,微妙な違いだが,非対話的インタープリタ ruby と異なり, irb は,その対話的なトップレベルで与えられたメソッドを, Object クラスの public インスタンス・メソッドとして定義する。 private ではなく public である。 実際にはこうなっても使い勝手は変わらない。ただ,レシーバを陽に指定できる点が異なる。

ここで私たちは pputs がそもそも private メソッドとして定義されていることに疑問を抱くべきなのかもしれません。 すべてのものの基底クラスである Object で用意されることが重要であって, private であることは,ほかならぬ irb が実証するように,実は重要ではありません。 むしろ,省略されているはずのレシーバ self を陽に接頭できないという制限により, 初学者にとっての「驚き」を増やしているだけかもしれません。

テキスト・ファイルに書いたメソッド定義を ruby に読み込ませたとき, それが確かに Object の private インスタンス・メソッドとして定義されること, それに対し irb で対話的に定義したとき,public インスタンス・メソッドとして定義されることを確かめてみよう。

実用上は決して勧められないが,定義を1行にまとめられることも確認しよう。 機械的に文末の改行をセミコロンにかえていけばよいが,実際にはセミコロンのほとんどは省略できる。 then という構文キーワードで if の条件とそれ以降の間のセミコロンを無くすことができる。

$ cat foo1.rb
def foo(x) if x <= 0 then [] else [x, foo(x - 1)] end end

p foo(5)
puts "Public:"
p Object.public_instance_methods.sort
puts "Private:"
p Object.private_instance_methods.sort
$ jruby foo1.rb
[5, [4, [3, [2, [1, []]]]]]
Public:
["==", "===", "=~", "__id__", "__send__", "class", "clone", "display", "dup", "e
ql?", "equal?", "extend", "freeze", "frozen?", "hash", "id", "inspect", "instanc
e_eval", "instance_exec", "instance_of?", "instance_variable_defined?", "instanc
e_variable_get", "instance_variable_set", "instance_variables", "is_a?", "kind_o
f?", "method", "methods", "nil?", "object_id", "private_methods", "protected_met
hods", "public_methods", "respond_to?", "send", "singleton_methods", "taint", "t
ainted?", "to_a", "to_s", "trap", "type", "untaint"]
Private:
["Array", "Float", "Integer", "String", "`", "abort", "at_exit", "autoload", "au
toload?", "binding", "block_given?", "callcc", "caller", "catch", "chomp", "chom
p!", "chop", "chop!", "eval", "exec", "exit", "exit!", "fail", "foo", "format", 
"gets", "global_variables", "gsub", "gsub!", "inherited", "initialize", "initial
ize_copy", "iterator?", "lambda", "load", "local_variables", "loop", "method_mis
sing", "open", "p", "print", "printf", "proc", "putc", "puts", "raise", "rand", 
"readline", "readlines", "remove_instance_variable", "require", "scan", "select"
, "set_trace_func", "singleton_method_added", "singleton_method_removed", "singl
eton_method_undefined", "sleep", "split", "sprintf", "srand", "sub", "sub!", "sy
stem", "test", "throw", "trace_var", "untrace_var", "warn"]
$ 
$ jirb
irb(main):001:0> def foo(x) if x <= 0 then [] else [x, foo(x - 1)] end end
=> nil
irb(main):002:0> foo(5)
=> [5, [4, [3, [2, [1, []]]]]]
irb(main):003:0> Object.public_instance_methods.sort
=> ["==", "===", "=~", "__id__", "__jtrap", "__send__", "class", "clone", "com",
 "display", "dup", "eql?", "equal?", "extend", "foo", "freeze", "frozen?", "hash
", "id", "include_class", "inspect", "instance_eval", "instance_exec", "instance
_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable
_set", "instance_variables", "is_a?", "java", "java_kind_of?", "javax", "kind_of
?", "method", "methods", "nil?", "object_id", "org", "private_methods", "protect
ed_methods", "public_methods", "respond_to?", "send", "singleton_methods", "tain
t", "tainted?", "to_a", "to_s", "trap", "type", "untaint"]
irb(main):004:0>

ここでメソッド定義を1行にまとめてみることを勧めたのは, 実験の便宜と,Ruby の構文規則のより深い理解をねらってのことである。 要領がつかめたら,もう普段はこんなことはしないようにしよう。

Ruby のプログラムは慣習的に 2 文字ずつ空白で字下げ される。 この慣習は実際によく守られているから,君も普段からその書き方に目と手を慣らした方がなにかと有利だろう。

1.6.3 Ruby のための Emacs の設定

ruby-mode が設定された GNU Emacs またはその派生エディタを使うと, ほとんど苦労することなく,慣習どおりに字下げを整えることができる。 おそらく,君が目にする多くの Emacs 環境で ruby-mode が設定済みになっているはずだ。 もしそうでなくても,ruby-moderuby のソースに同梱されているから,君自身でインストールすればよい。 いくつか似たようなファイルが同梱されているが,さしあたりプログラムの編集に必要なのは ruby-mode.el である。 これを /usr/share/emacs/site-lisp/ などのローカルな Emacs ライブラリ用ディレクトリに置き,~/.emacs ファイルに下記を追記すればよい。

(autoload 'ruby-mode "ruby-mode" "Ruby editing mode." t)
(nconc auto-mode-alist '(("\\.rb$" . ruby-mode)))

1行目は ruby-mode という Lisp 関数が最初に呼び出されたとき, "ruby-mode.el" という名前のファイルをライブラリ用のディレクトリから自動的に探し出してロードするようにする。 2行目は,.rb という拡張子のファイルが開かれたとき,ruby-mode という Lisp 関数を自動的に呼び出すようにする。

Ruby 言語の骨格には Lisp からインスパイアされた要素が多数ある。 Ruby をよりよく理解するために Lisp をかじってみることは,アイディアとして悪くない。 Emacs はそのための手頃で自己完結的な Lisp 学習用ツールとしても有用である。 そのときは, Emacs Lisp てほどき − .emacs を書くための − などが役立つだろう。

1.7 スクリプト例

ここまで述べた言語要素だけでも, 組込み関数等と適切に組み合わせることによって,多くのスクリプトを記述できる。 下記はコマンド行引数として与えられたテキスト・ファイルの内容を 行番号を付けて印字するスクリプトである。

#!/usr/bin/ruby -Ku
count = 0
while line = gets
  count += 1
  printf("%6d %s", count, line)
end

Unix 上でファイル catn.rb としてセーブしたときの実行例を示す。

$ chmod a+x catn.rb
$ ./catn.rb catn.rb
     1 #!/usr/bin/ruby -Ku
     2 count = 0
     3 while line = gets
     4   count += 1
     5   printf("%6d %s", count, line)
     6 end
$ 

第1行は,ファイルを Unix で実行可能な utf-8 の Ruby スクリプトにする。

#!/usr/bin/ruby -Ku

スクリプト catn.rb に対し,次のように poi.txt がコマンド行引数として与えられたとき,

$ ./catn.rb poi.txt

第1行の内容とあわせて次のようなコマンド行が自動的に組み立てられて実行される。

/usr/bin/ruby -Ku ./catn.rb poi.txt

このとき,ruby は,マルチバイト文字列を utf-8 文字列と解釈して, ./catn.rb を実行する。 poi.txt は Ruby プログラムへのコマンド行引数として扱われる (ただし,この例では,たまたまマルチバイト文字列を utf-8 として解釈しなければならない箇所がないから,-Ku は省略できる)

Ruby プログラムにとって # 以降は コメント であり, ./catn.rb の第1行は無視される。 ちなみに,Ruby に限らず Unix 上の多くのスクリプト言語が # 以降をコメント扱いするのは,この #! のメカニズムと相性が良いことが一因である。

#!/usr/bin/ruby -Ku

トップレベルにローカル変数 count を設けてその値を 0 にする。

count = 0

puts と同類の組込み関数 gets は,コマンド行引数をテキスト・ファイルの名前とみなし, 1回呼び出されるごとにファイルの内容を1行ずつ返す。 ファイルの内容が尽きたときは nil を返す。

gets を呼び出して,戻り値をローカル変数 line に代入する。 line は代入によって新しく設けられる。 代入演算の結果の値は,代入された値と等しい。 ファイルの内容が尽きて nil が結果の値となるまで,while の条件は成立する。

while line = gets

自己代入によって count の値を 1 だけ増やす。

  count += 1

やはり puts と同類の組込み関数 printf を使って書式付き印字を行う。その仕様は C/C++ の <stdio.h>printf 関数, Java の java.lang.System.out#printf メソッドと概ね同じである。

line に代入されている1行の内容には,行末の改行文字も含まれているから, 書式文字列で "%6d %s\n" のように改行文字を含めることはしない。

  printf("%6d %s", count, line)

1.8 変数の代入とオブジェクトのアイデンティティ

ところで上記の例で

line = gets

をしたとき,実際には何が起こっているのだろうか。 文字列を代入したとき,その内容が1文字ずつ変数 line にずらずらと転送されているのだろうか?

答えは否である。実際には (Java の場合と同じく) 文字列オブジェクトへの参照 (実質的にポインタ) だけが渡されるにすぎない。

このことを実験的に確かめるにはどうしたらよいだろうか?

いろいろ手段があるが,Ruby には直接的な方法が用意されている。 Object の public インスタンス・メソッド object_id (object identity) の戻り値をみればよい。 これはオブジェクトごとに実装依存の一意的な整数を返す。

このメソッドは Java の java.lang.System#identityHashCode(Object x) に相当します。 C++ ではオブジェクトへのポインタ値 &x が同様の目的に使われます。
Ruby は object_id の同義語として __id__ というメソッドも用意しています。

文字列について簡単に実験してみよう。

$ irb
irb(main):001:0> a = "a quick brown fox"
=> "a quick brown fox"
irb(main):002:0> a.object_id
=> 209382
irb(main):003:0> b = a
=> "a quick brown fox"
irb(main):004:0> b.object_id
=> 209382
irb(main):005:0> a += " jumps over"
=> "a quick brown fox jumps over"
irb(main):006:0> b
=> "a quick brown fox"
irb(main):007:0> a.object_id
=> 193772
irb(main):008:0> b.object_id
=> 209382
irb(main):009:0> 

この結果から分かるように,代入 b = a により,二つの変数は同じオブジェクトを指す。 a += " jumps over" により,a は文字列を連結して作られた新しい文字列を指す。

object_id は文字列に限らず,整数にも配列にも使える。いろいろ実験してみよう。

Java などと同じく Ruby では,文字列や配列を変数に代入したり,実引数から仮引数へと渡したり,戻り値として返したりするとき, 参照だけが効率良く渡される。

プログラミングにとって,このような参照渡しは,値の変更の影響範囲を考えるうえで重要である。 Java などと異なり Ruby の文字列は,普通の配列のようにブラケットで添え字を指定して,要素を参照したり,変更したりできる。 この機能をつかって文字列の一部を変更してみよう。

$ irb
irb(main):001:0> a = "a quick brown fox"
=> "a quick brown fox"
irb(main):002:0> b = a
=> "a quick brown fox"
irb(main):003:0> a[2] = "Q"
=> "Q"
irb(main):004:0> a
=> "a Quick brown fox"
irb(main):005:0> b
=> "a Quick brown fox"
irb(main):006:0> 

代入 b = a によって ab は同じ文字列オブジェクトを指しているから, a[2] = "Q" で文字列の (0 から数えて) 2 番目の文字を書き換えたとき,b からもその変更をみることができる。

配列についても同様に実験してみよう。

文字列と配列には concat (concatenate,連結する) というメソッドがあります。 a = "abc"; a.concat("def") のように使います。 + 演算と似ていますが,新しいオブジェクトを作るかわりにレシーバ自身を変更します。 これを使ったとき,値の変更はどこまで及ぶでしょうか?

まとめ

ここでは処理系の基本的な使い方と,Ruby 言語のごく基礎的な部分をひととおり導入した。

もしも,君が初心者で,ただ読み流しただけでここまでたどり着いたのならば, おそらく無味乾燥な知識の断片の集積だったように感じているだろう。 自分の手で irb を通して Ruby と対話すること, 書かれているとおりの入力を繰り返すだけでなく, こうしたらどうなるだろう,と思いついたことを自ら積極的に試してみることが大切である。


戻る


Copyright (c) 2007, 2008 Oki Software Co., Ltd.