Ruby の薦め
013554
最終更新日:Saturday, 21-May-2005 16:56:03 JST

Ruby は徹底したオブジェクト指向の,そして実に融通無碍な書き方のできるスクリプト言語です。

スクリプトですから実行速度を最優先にする数値計算や, リアルタイムに機器を制御するプログラムなどには向いていませんが, 簡単なフィルターや CGI から複雑な処理をするアプリケーションまで, 色々なことに使えます。

そして,何よりも気に入っているのは

面白くて,プログラムを書きやすい

ということです。

また,Linux 上だけでなく Windows などの多くのプラットフォーム上で動かせるようです。

私は Perl を好きになれませんでしたが,Ruby の美しさにはすっかり魅せられてしまいました。

このページは Ruby をまだ知らない人のために Ruby を紹介するためと, 自分の心覚えのために作りました。

Ruby は奥が深いので,簡単には紹介しきれませんが,少しづつ充実させていくつもりです。

目次

---- ( まだまだ続く予定 ) ----


文とコメント

■ 文

Ruby では改行またはセミコロンが文の区切りとみなされます。

改行とセミコロンが同じ扱いという点はC言語や PASCAL などと全く異なるので, なれるまで注意が必要です。

一行が長くなってしまったが文を区切りたくない場合には,改行の直前に \ を入れます。 こうすると \ の直後の改行コードは無視されて,次の行も文の続きとみなされます。 ( シェルスクリプトや FORTRAN の継続行のようなもの? )

文は,当然ですが先頭にあるものから順番に実行されてゆきます。

また Ruby の文は実行結果としての値を持ちます。

つまり,if 文や for 文なども値を持つので, その結果を変数に代入することができます。 この点もC言語や PASCAL などと大いに違う点であり, この性質を積極的に活用するとC言語や PASCAL などとは全く違う雰囲気のプログラムができあがります。

もっとも私はC言語や PASCAL になれているので,if 文の結果を変数に代入しようとは思いませんが ... 。

■ コメント

文字列の中などを除き,(地の文で) # があると, 以後の行末まではコメントとみなされて無視されます。

複数行のコメントを書く場合,一々,行頭に # を入れるのは面倒です。

複数行のコメントは =begin と =end で挟みます。 つまり,行頭が =begin で始まる行から, 行頭が =end で始まる行までは全てコメントとみなして無視されます。


実行方法

初めに Ruby のスクリプトの実行方法を説明しておきます。

■ コマンドラインで直接実行

短いスクリプトを実行したい場合などは,一々ファイルにスクリプトを書いて実行するのは面倒です。 そのような場合にはコマンドラインで直接実行してしまいましょう。

コマンド ruby の後ろにオプション -e を付けて,スクリプトの文字列を書きます。

文字列は ' または " で文字をはさみます。

基本はやっぱりこれ?

例1
$ ruby -e 'puts "Hellow world!" '
Hellow world!
$

赤い文字で書いた部分がキーボードから打ち込んだ部分です。 puts は文字列を標準出力に出力するための Ruby のコマンドです。 print でも出力できますが,puts の場合には最後に改行コードが出力されます。 例1では Ruby が起動され,puts "Hellow world!" というスクリプトが実行されて, 標準出力に Hellow world! という文字が出力されました。

本当は puts( "Hellow world!" ) が正式な書き方だと思いますが,Ruby では ( ) を省略することができます。

複数の文

Ruby では改行またはセミコロンが文の区切りとみなされます。

文がいくつかある場合にはセミコロンで区切るか,または改行してしまいます。 改行しても文字列の終わりを示す ' または " が入力されるまではスクリプトの続きとみなされます。

例2
$ ruby -e 'x=2 ; y=3 ; p x*y '
6
$ ruby -e "x=2 ; y=3 ; p x*y "
6
$

この例では ' を使っても " を使っても同じです。 p は引数の値(数値,文字列,その他)を標準出力に出力するコマンドです。

例3
$ ruby -e 'x=2
> y=3
> p x*y '
6
$

例3のように,途中で改行するとプロンプト > が表示されます。 最後に ' を入力するとスクリプトの入力が終了し,スクリプトが実行されます。

簡単なフィルター

標準入力やファイルなどからテキストを読み込んで, 適当な処理をしてから標準出力に書き出すコマンド(スクリプトなど)をフィルターと呼びます。

コマンドラインで直接実行できる簡単なフィルターの例として, 入力されたテキストを大文字に変換するフィルターを次に揚げます。

例4
$ ruby -n -e 'puts $_.upcase' testfile.txt

または
$ ruby -n -e 'puts $_.upcase' < testfile.txt

例4のようにオプション -n を付けると, ファイルが指定されればファイルから,ファイルが与えられなければ標準入力から一行づつ読み込んで 変数 $_ に代入されます。 例4では一行分の文字列 $_ のメソッド upcase を呼び出して, 全ての文字を大文字に変換し,コマンド puts で標準出力に書き出しています。 ( Ruby では文字列もオブジェクトです )

この処理は各行について繰り返され,行がなくなったら(ファイルの中身が無くなったら)終了します。

-n と同じようなオプションで -p というものがあります。 -p は -n と同様に一行づつ読み込んで $_ に代入し,スクリプトの最後で $_ を標準出力に出力します。

ですから次の二つのコマンドは全く同じ動作になります。

例5
$ ruby -n -e 'puts $_' testfile.txt

または
$ ruby -p -e ' '  testfile.txt

関数電卓の代わりに

ちょっとした計算をしたい時,関数電卓のように使うこともできます。

但し,Ruby では数学関数などは Math というモジュールの中で定義されているので,ちょっと面倒です。

例6
$ ruby -n -e 'p Math::sin(Math::PI/3)'
0.8660254038
$ 

上の例のように sin という数学関数や円周率 PI がモジュール Math の中で定義されていることを Math:: を付加して教えてやらなければならないのです。

何度も数学関数を使う場合には include Math を最初に実行して, モジュールを読み込んでしまいます。そうすれば一々 Math:: を付けなくてもよくなります。

例7
$ ruby -n -e 'include Math ; p sin(PI/3)'
0.8660254038
$ 

■ irb でインタラクティブに実行

irb を使うと Ruby のスクリプトをインタラクティブに実行することもできます。

例8
$ irb
irb(main):001:0> x=4 ; y=5
5
irb(main):002:0> x*y
20
irb(main):003:0> x+y
9
irb(main):004:0> exit
$ 

Ruby がインストールされているなら irb もインストールされていると思います。 関数電卓の代わりにするなら,こちらの方が便利かも?

なお,後の方で色々な例題を irb で実行しています。

■ スクリプトファイルを実行

ちょっと長いプログラム(スクリプト)になったり, 短いものでも何度も使うフィルターなどは, スクリプトをファイルに書いておいて実行します。

スクリプトが書かれたファイル(スクリプト,スクリプトファイル,プログラム)を実行する方法は2通りあります。

例えば次のプログラムを myprog.rb という名前のファイルに書いたとします。 拡張子を rb にしたことに特に意味はありません。 単なる習慣です。

簡単なプログラム例 myprog.rb
x="私"
y="貴方"
puts x + "と" + y

実行方法1

コマンドラインで ruby の後にプログラムファイルを指定することで実行できます。

実行例
$ ruby myprog.rb
私と貴方
$ 

一般的には

ruby オプション プログラム プログラムに渡すパラメーター

という形で実行します。

実行方法2

一々 Ruby を起動していたのではフィルターとしては不便です。 myprog.rb をコマンドのように実行できるようにしましょう。 そのためには myprog.rb の先頭行に #!/usr/bin/ruby を書き込みます。

ディストリビューションによっては /usr/bin 以外のところに ruby があるかもしれません。 どこに ruby がインストールされたのかが分からない場合にはコマンドラインで which ruby を実行してみて下さい。

変更したプログラム例 myprog.rb
#!/usr/bin/ruby
x="私"
y="貴方"
puts x + "と" + y

myprog.rb を書き換えたら保存して,chmod で実行許可を与えます。

これでコマンドラインで ./myprog.rb と入力すれば実行できるようになりました。

実行例
$ chmod  755 myprog.rb
$ ./myprog.rb
私と貴方
$ 

myprog.rb の前の ./ を忘れないで下さい!


クラスとオブジェクト

■ クラスとオブジェクトの簡単な例

いきなりですが,簡単なクラスを使ったプログラムを書いてみましょう。

クラスとオブジェクトの例 myprog2.rb
 1: #!/usr/bin/ruby
 2:
 3: # ここは class Animal の定義です
 4: class Animal
 5:
 6:   def initialize(name,koe)
 7:     @name=name
 8:     @koe=koe
 9:   end
10:
11:   def naku
12:     puts @koe
13:   end
14:
15: end
16:
17: # ここからはオブジェクトを作成しています
18:
19: horse=Animal.new("馬","ヒヒ〜〜ン")
20: dog=Animal.new("犬","ワンワン")
21:
22: # オブジェクトのメソッド naku を実行してみます
23:
24: horse.naku
25: dog.naku

行頭の数字とコロンは説明のために書いたものですから, プログラムファイルにこれらを書いてはいけませんよ。

1行目の #!/usr/bin/ruby はこのプログラムをコマンドとして実行できるようにするために書いたものです。

2行目や5行目は空行になっていますが,空行は無視されますから, 見やすくなるように適当に空行をいれましょう。

3行目や17行目は # で始まっています。# 以後に書かれたものはコメントとみなされて無視されます。

4行目から15行目までがクラス Animal の定義です。 クラスの名前は大文字で始めなければいけません。

クラス Animal の定義の中で,initialize と naku という2つのメソッドを定義しています。

initialize という名前のメソッドは特別で,このクラスのオブジェクトを作成した時に, 初期化するために呼ばれます。 引数を受け取る必要がない場合には def initialize と書きます。

7行目と8行目では受け取った引数 name と koe を, クラス Animal の中だけで使える変数 @name と @koe に代入しています。

@ から始まる変数はクラスの中だけで使えるものであり,同じクラスの他のメソッド(例えば naku ) の中でも使えます。

19行目と20行目でクラス Animal のオブジェクトを作成しています。 オブジェクトの作成は

クラス名.new(引数並び)
または
クラス名.new

という文で行います。

new というメソッドを呼び出していますが, オブジェクトが新しく作成されると initialize が自動的に呼ばれて new に渡された引数は initialize に渡されます。

24行目と25行目ではオブジェクトのメソッド naku を実行しています。


さて,プログラムが書けたら myprog2.rb という名前で保存し,chmod 755 myprog2.rb を実行して実行許可を与えてください。

このプログラムを実行すると以下のようになります。

実行例
$ ./myprog2.rb
ヒヒ〜〜ン
ワンワン
$ 

■ 数字も文字もオブジェクト!!

普通はプログラム言語の説明では,使える変数の型とか,定数の型とか,演算子とかの説明があって 制御文とかの説明にはいると思いますが, ここではいきなりクラスとオブジェクトの説明から入ってしまいました。

実は,Ruby は徹底的なオブジェクト指向の言語であり, 数字の2や3も Integer というクラスのオブジェクトなのです!

例えば 2+3 という文は 2 というオブジェクトの + というメソッドを呼び出して,引数 3 を渡しているのです。 ですから足し算は本来 2.+(3) と書くべきものなのですが, 習慣的に 2+3 と書く方が分かりやすいので,2+3 と書いてもよいことになっているのです。

実行例
$ irb
irb(main):001:0> 2+3
5
irb(main):002:0> 2.+(3)
5
irb(main):003:0> x=2
2
irb(main):004:0> x+3
5
irb(main):005:0>  x.+(3)
5

上記の例で x=2 という文は変数 x に単なる数値の 2 が代入されたのではありません。 クラス Integer のオブジェクトの 2 が代入されたのです。 ですから x=2 を実行した後では x はクラス Integer のオブジェクトとなり, このクラスで定義されている様々なメソッド +,-,*./,chr,succ,upto,downto,times, などを使うことができます。

実行例の続き
irb(main):006:0> x.succ
3
irb(main):007:0> x.times { puts '繰り返し' }
繰り返し
繰り返し
2
irb(main):008:0> 

文字列 'A' や 'AB' も,もちろんオブジェクトです。 'A' や 'AB' はクラス String のオブジェクトなので, このクラスで定義されている様々なメソッドを利用することができます。

実行例の続き
$ irb
irb(main):001:0> 'A'+'BC'
"ABC"
irb(main):002:0> "ABCD".length
4
irb(main):003:0> "ABCD".reverse
"DCBA"
irb(main):004:0> "ABCDE"[2,4]
"CDE"
irb(main):005:0> 

変数

Ruby ではあらかじめ変数を宣言しておく必要はありません。 プログラム中で最初に現れた(使用された)部分で宣言されたことになります。

先に述べたように Ruby では数字も文字列も皆それぞれのクラスのオブジェクトなので, 変数の型というものもありません。 変数 x に数字でも文字列でも配列でも,何でも代入することができます。 見方を変えれば,変数はどれもオブジェクト型という同じ型だと言ってもよいのかもしれません。

変数に整数型とか文字列型とかの型はありませんが, グローバル変数とか,ローカル変数など,いくつかの種類はあります。 これらの種類は変数名の最初の文字で決まります。

■ グローバル変数

グローバル変数は変数名が $ で始まります。

グローバル変数の例
$x
$year
$month

グローバル変数にはプログラムのどこからでもアクセスできます。

■ ローカル変数

ローカル変数は変数名が アルファベットの小文字 または _ で始まります。

ローカル変数の例
x
year
month

ローカル変数は関数定義の中,メソッドの中,ブロックの中などだけで有効な変数です ... 。

う〜〜ん。ローカル変数の有効範囲(スコープ)の説明は簡単にはできません。 本などで調べてください。

■ インスタンス変数

インスタンス変数は変数名が @ で始まります。

インスタンス変数の例
class City
  def initialize(name,code)
    @name=name
    @code=code
  end
end

インスタンス変数はクラスのメソッドの中だけで有効な変数です。

■ クラス変数

変数は変数名が @@ で始まります。

クラス変数の例
class City
  @@id=100
  def initialize(name,code)
    @name=name
    @code=code
  end
end

クラス変数は,そのクラスのオブジェクト全てに共通の変数のようです。

■ 定数

定数は名前が アルファベットの大文字 で始まります。

定数の例
Name="芦田"
Year=2004

定数には最初に一度だけ値を代入できます。


演算子

■ 演算子一覧

Ruby には様々な演算子があります。

優先順位 演算子 備考
1
 :: 
Math::sin(x) など
2
 [ ] 
配列要素など
3
 ** 
ベキ乗 2**3 など
4
 +(単項) -(単項) ! (否定) ~ (補数) 
! はメソッドではない
5
 * / % 
乗法,除法,剰余など
6
 + - 
加法,減法など
7
  << >>  
ビットシフトなど
8
  &  
ビット論理積
9
 | ^  
ビット論理和,排他的論理和
10
  > >=  <  <=  
不等号
11
  <=> == ===  !=  =~  !~  
比較演算子
12
 && 
論理積
13
 ||
論理和
14
 .. ... 
範囲指定
15
 ?: (三項演算子)
y = x ? 0 : 1
16
 = += -= *= /= %= **= 
&= |= <<= >>= ||= &&=
自己代入演算子 x += 2 など
17
 not 
論理否定
18
  and or 
論理積,和

この表の色付きの部分にある演算子は ! 以外はメソッドです。

( != と !~ もメソッドではないと書いてある本もあるのだが ..... 。)

つまり + や * などは単なる数値に作用する演算子ではなく, オブジェクトのメソッドなので,オブジェクトの種類(オブジェクトが属するクラスの種類)によって動作が変わります。 また,メソッドを自分で再定義して動作を変えることもできます。

+ の使用例
$ irb
irb(main):001:0> 3+5
8
irb(main):002:0> 'ABC'+'DEF'
"ABCDEF"
irb(main):003:0> [0,1,2]+[3,4]
[0, 1, 2, 3, 4]
irb(main):004:0>

このように,同じ記号の演算子でも,どのオブジェクトのメソッドなのかによって意味が変わりますから十分注意しましょう。 例えば表中では << をビットシフトと書きましたが,この記号はヒアドキュメントであったり, 配列に追加する記号であったりと,色々に使われています。

■ いくつかの演算子の意味

真と偽

Ruby では 偽は false か nil のことです。 false でも nil でもない値は全て真とみなされます。

偽であるもの
false , nil, FALSE, NIL
真であるもの
true , TRUE , 0 , 1 , -1 などの数値 , [ ] , '' , "" , "ABC" などの文字列 , その他

比較演算子

x <=> y は x < y の時 -1 ,x = y の時 0 ,x > y の時に 1 を返す演算子です。

但し,x,y は数値とは限りません。 オブジェクトの属するクラスに何らかの "大きさ" (順番)が定義されていて,その "大きさ" による比較の結果が -1 ,0 ,1 として返されるのです。

x == y ( = は2個 )は,x と y が等しい時 true ,等しくない時 false となります。

実は Ruby では "等しい" という意味に色々奥があるらしいのですが,詳しくは本などを読みましょう。

x != y は,x と y が等しい時 false ,等しくない時 true となります。

x === y ( = は3個 )は,case 文で x と y が "等しい" か否かの判定に使われるらしいです。 自分が作ったオブジェクトを case 文の中の条件判断で使用するのでない限り,=== を気にする必要はないでしょう。

と,思っていたら,ある範囲の中に入っているか否かの判定にも === が使えました。 範囲指定の実行例を見てください。

Regexp =~ String または String =~ Regexp は, String の中に正規表現 Regexp が含まれていればその位置(論理値としては真)を, 含まれていなければ nil(論理値としては偽) を返します。

=~ の使用例
irb(main):005:0> /Ab/ =~ "asAbd"
2
irb(main):006:0> /Ab/ =~ "asAcd"
nil
irb(main):007:0> "asAbd" =~ /Ab/
2
irb(main):008:0> 

Regexp !~ String または String !~ Regexp は,否定マッチと呼ばれ, 論理値としては ! ( Regexp =~ String ) と等価になります。 論理値としては等価と言った意味は,!~ の場合には true か false が返されるからです。

!~ の使用例
irb(main):008:0> /Ab/ !~ "asAbd"
false
irb(main):009:0> /Ab/ !~ "asAcd"
true
irb(main):010:0> 

範囲指定

x .. y (ピリオドが2個)は x から y までを表します。

x ... y (ピリオドが3個)は x から y 未満までを表します。

.. と ... の使用例
irb(main):010:0> (1..10).to_a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):011:0> (1...10).to_a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):012:0> ('A'..'D').to_a
["A", "B", "C", "D"]
irb(main):013:0> ('A'...'D').to_a
["A", "B", "C"]
irb(main):014:0> "ABCDEFG"[2..4]
"CDE"
irb(main):015:0> (1..10)===4
true
irb(main):016:0> (1..10)===14
false
irb(main):017:0> (0..10)===4.56
true
irb(main):018:0> (0..10)===24.56
false
irb(main):019:0> ('aa'..'bb')==='a'
false
irb(main):020:0> ('aa'..'bb')==='af'
true
irb(main):021:0> 

三項演算子

三項演算子は if 文のかわりに使うことができます。

a ? b : c は if a then b else c end と同じです。

三項演算子の使用例
$ irb
irb(main):001:0> x=2 ; y = x>2 ? 'A' : 'B' 
"B"
irb(main):002:0> x=5 ; y = x>2 ? 'A' : 'B' 
"A"

if 文と同じですと書きましたが,Ruby では

y = if x>2 then 'A' else 'B' end

という書き方が許されるのです。この式は

if x>2 then y='A' else y='B' end

と同じ結果を与えます。これらの式を

y = x>2 ? 'A' : 'B'

と書いた方がよいと思うか否かは個人の好みによるかも ... 。

自己代入演算子

自己代入演算子の += などはC言語にもありました。意味するところは同じです。

つまり x += a は x = x + a と同じです。

■ 代入

Ruby の代入には,結構,独特なものがあります。

代入の繰り返し

Ruby では数式や論理式はもちろん,あらゆる文が結果としての値を持ちますから, その結果を変数に代入できます。

代入文の結果は代入された値になりますから,それをさらに代入することができます。

代入の例
y = if x>2 then 'A' else 'B' end 

z = a = 0.56

z = a = 0.56 のような式は右から評価されていきます。

型を気にせず代入できる

C言語などならば整数型の変数 x には整数しか代入できませんが, Ruby には変数の型が無いので(あえて言えばオブジェクト型という唯一の型しかないので) 任意の変数 x にはどんなオブジェクトでも代入することができます。

つまり x=2 の直後に x="ABC" としてもかまわないのです。

代入の例
irb(main):001:0> x=2
2
irb(main):002:0> x="ABC"
"ABC"

代入の副作用?

Ruby がどのように実装されているのかは,よく分からないのですが, 2 や "ABC" は単なる数値や文字列ではなく,Integer や String というクラスのオブジェクトなので, 変数 x には常にオブジェクトを指すポインターのようなものが代入されるのだと思います。

ポインターのようなものが代入されるということは, うっかり代入すると副作用が起こるということです。

代入による副作用の例
irb(main):002:0> x="ABC"
"ABC"
irb(main):003:0> y=x
"ABC"
irb(main):004:0> y[0]='D'
"D"
irb(main):005:0> y
"DBC"
irb(main):006:0> x
"DBC"

上の例では x の値を y にコピーして y の方だけを変更しようとしたのですが, y を変更した時に元の x の方も変更されてしまいます。

元の x の方を変更したくない場合には y=x.clone とするか y=x.dup として, x と同じ内容のオブジェクトを作成して,それを y に代入しなければなりません。

但し,clone や dup を使っても,常に完全に同じオブジェクトが複製される訳ではありません。 今の例のように文字列などは問題ないのですが, 自分で定義したクラスのインスタンス変数が複雑なクラスのオブジェクトを指している場合, インスタンス変数はコピーされますが,インスタンス変数が指すオブジェクトは複製されません。 完全な複製を作りたかったらクラスの構造に応じて自分で中身をコピーしなければならないようです。

なお,x の値が数値の場合には, このような代入による副作用は生じないようです。

副作用の生じない例
irb(main):007:0> x=3
3
irb(main):008:0> y=x
3
irb(main):009:0> y=5
5
irb(main):010:0> x
3

多重代入

Ruby では2個以上の変数に同時に代入することができます。

多重代入の例
$ irb
irb(main):001:0> x,y = [ 12 , 'a' , 'Ashida' ]
[12, "a", "Ashida"]
irb(main):002:0> x
12
irb(main):003:0> y
"a"

上の例のように左辺の変数はコンマで区切って並べ, 右辺の値は [ ] でくくって配列にします。

左辺の変数それぞれに配列の要素が順番に代入されてゆきます。 余った要素は無視されます。

配列要素が足りない場合には,残った変数の値は nil になります。

なお,右辺の [ ] は省略することもできます。

多重代入の例 続き
irb(main):004:0> x,y = 12 , 'a' , 'Ashida' 
[12, "a", "Ashida"]
irb(main):005:0> x
12
irb(main):006:0> y
"a"

左辺の最後の変数の前に * を付けると,右辺で残った要素を配列にして代入します。

多重代入の例 続き
irb(main):007:0> x , *y = [ 12 , 'a' , 'Ashida' ]
[12, "a", "Ashida"]
irb(main):008:0> x
12
irb(main):009:0> y
["a", "Ashida"]

左辺の変数をいくつか ( ) でくくってグルーピングすることもできます。

グルーピングの例
$ irb
irb(main):001:0> x , y , z = [ 12 , [ 'a' , 'Ashida' ] ]
[12, ["a", "Ashida"]]
irb(main):002:0> x
12
irb(main):003:0> y
["a", "Ashida"]
irb(main):004:0> z
nil
irb(main):005:0> x , ( y , z ) = [ 12 , [ 'a' , 'Ashida' ] ]
[12, ["a", "Ashida"]]
irb(main):006:0> x
12
irb(main):007:0> y
"a"
irb(main):008:0> z
"Ashida"

文として x,y = 10,20 などと書けてもあまり嬉しくありませんが, このように多重代入が許されるということは, 関数の結果として2個以上の値を返したい場合などに便利です。

関数から多重代入で結果を受け取る例
$ irb
irb(main):001:0> def fun
irb(main):002:1>   a=2 ; b="Ashida" 
irb(main):003:1>  return [ a , b ]
irb(main):004:1> end
nil
irb(main):005:0> x,y = fun
[2, "Ashida"]
irb(main):006:0> x
2
irb(main):007:0> y
"Ashida"


条件分岐

■ if

if 文の一般的な形は次のようなものです。

if 文の書式
if 条件式 then

elsif 条件式 then
 文
else
 文
end

Ruby では改行はセミコロンで代用することができます。 つまり,以下のように書いても同じ意味になります。

if 文の書式
if 条件式 ; 文 ; elsif 条件式 ; 文 ; else ; 文 ; end

または
if 条件式 ; 文  elsif 条件式 ; 文  else  文  end

または
if 条件式 then 文  elsif 条件式 then 文  else  文  end

Ruby は融通の効く言語なので,elsif や end の前のセミコロンは省いても大丈夫のようです。

if 修飾子

if を文の後ろに置くこともできます。

if 修飾子の書式
文 if 条件式 

この時,条件式が真の場合にのみ前に置かれた文が実行されます。 結構この書き方も便利です。

■ unless

unless は if !(条件式) と同じです。ただし elsif はありません。

ちなみに,私は unless を使ったことはありません。

unless 文の書式
unless 条件式 then

else
 文
end

または
unless 条件式 then 文  else  文  end

unless 修飾子

if と同様に unless を文の後ろに置くこともできます。

unless 修飾子の書式
文 unless 条件式 

■ case

case 文の一般的な形は次のようなものです。

case 文の書式
case a 
  when x1,x2,x3
    文1
  when y1,y2,y3
    文2
else
 文3
end

a と x1 などの比較は == ではなく,=== で行われます。 つまり,単純に a と x1 が等しい場合だけでなく,a が x1 の範囲に入っている場合にも真になります。

case 文の例
プログラム myprog3.rb

#!/usr/bin/ruby

def hyouka(x)
  case x
    when 80..100
      '優'
    when 70...80
      '良'
    when 60...70
      '可'
    when  0...60
      '不可'
  else
      '/'
  end
end

puts hyouka(50)
puts hyouka(60)
puts hyouka(79.80)
puts hyouka(80)

実行結果
$ ./myprog3.rb
不可
可
良
優

この例では関数 hyouka を定義して呼び出しています。 関数は最後に実行された文(今の場合 case 文)の結果を返します。

case の when の部分は,今の場合 ..... を使った範囲指定になっています。


繰り返し

Ruby にも while や for といった繰り返しのための文がありますが, Ruby にはイテレーターという強力な武器があるので, これらの文の出番は他の言語に比べると少ないようです。

■ while

while 文の一般的な形は次のようなものです。

while 文の書式
while 条件式  do
  文
end

または
while 条件式 ; 文  end

条件式がである間,文を実行し続けます。 do は省略されることが多いようです。

while 修飾子

while を文の後ろに置くこともできます。

while 修飾子の書式
文 while 条件式 

■ until

until 文の一般的な形は次のようなものです。

until 文の書式
until 条件式  do
  文
end

または
until 条件式 ; 文  end

条件式がである間,文を実行し続けます。 do は省略されることが多いようです。

until 修飾子

until を文の後ろに置くこともできます。

until 修飾子の書式
文 until 条件式 

■ for

while や until は条件式の真偽によって繰り返しますが, Ruby の for は範囲や配列などの要素を取り出し, その要素の数だけ実行します。

for 文の書式
for 変数 in 配列など  do
  文
end

この時,配列などから取り出された要素が変数に代入されています。

for 文の例
for x in 0..3
  puts x
end

for x in [ 0,1,'A','B']
 puts x
end

実行結果
0
1
2
3
0
1
A
B

for はかなり強力ですが,後で述べるイテレーターの each を使うことの方が多いでしょう。

イテレーターの場合
(0..3).each { |x|
  puts x
}

[ 0,1,'A','B'].each { |x|
 puts x
}

実行結果
0
1
2
3
0
1
A
B

ちなみに (0..3).each { |x| ; puts x } は 0.upto(3){ |x| ; puts x } と書くことの方が多いかもしれません。 これもイテレーターです。

■ ローカル変数のスコープ

while , until , for などのループの中では,ループの外側のローカル変数を使用できます。 また,ループの中で初めて定義したローカル変数をループから抜けた後でも使用できます。

つまり,変数のスコープ(有効範囲)という意味では,ループの中も外も同じです。

一方,イテレーターの場合には, イテレーターのブロックの実行が始まる前に存在していたローカル変数はそのままブロックの中でも利用でき, ブロックが終了した時はブロック内で設定された値になっていますが, ブロック内部で初めて定義されたローカル変数はブロックの終了とともに消滅します。

■ ループからの脱出

while や until,for などのループの繰り返しを制御する文は以下のものたちです。

break 繰り返しを中断し,ループから脱出します。
next 文の実行を中断し,次のループへ飛びます。
つまり,next から end までの文を飛び越します。
redo ループ内の先頭の文に飛びます。

数値計算

Ruby はインタープリターなので数値計算はあまり得意ではないと思いますが, 一応,数学関数などがそろっていますから, 実行時間をあまり気にしなくてよいのなら,数値計算にも使うことができます。

また,整数は(メモリーが許す限り)何桁になってもかまわないし, 複素数,有理数,行列などの計算のライブラリーもありますから, ちょっとした計算には仲々便利です。

ちなみに,複素数(Complex),有理数(Rational),行列(Matrix)などのライブラリーは, Ruby で書かれており, Vine Linux では /usr/lib/ruby/バージョン番号/ の中にありますから, 使い方が分からない場合にはソースを見ることができます。

■ 数学関数

以下の数学関数や定数はモジュール Math の中で定義されているので, 例えば Math.sin(x) のようにモジュールを明示して呼び出すか, または,モジュール Math をインクルードして使います。

表記 意味
atan2(y,x) arctan(y/x) の値を [ -π,π ] の範囲で返す
cos(x) x の余弦
sin(x) x の正弦
tan(x) x の正接
exp(x) x の指数関数
log(x) x の自然対数
log10(x) x の常用対数
sqrt(x) x の平方根
frexp(x) x の指数部と仮数部からなる配列 [ 指数部 , 仮数部 ] を返す
ldexp(x,exp) x に 2 の exp 乗を掛けた数 x*2**exp を返す
PI 円周率
E Napier の定数
x**a x の a 乗 (これは標準の演算子なので Math は必要ない!)
数値計算の例1
$ irb
irb(main):001:0> Math.sin(Math::PI/3)
0.8660254038
irb(main):002:0> Math::sin(Math::PI/3)
0.8660254038
数値計算の例2
$ irb
irb(main):001:0> include Math
Object
irb(main):002:0> sin(PI/3)
0.8660254038
irb(main):003:0> atan2(1,sqrt(3))
0.5235987756
irb(main):004:0> atan2(1,sqrt(3))*6/PI
1

■ 多倍長整数

Ruby の整数には多倍長整数( Bignum )があります。 といっても,何も特別なことをして使うわけではなく, 普通に整数の計算をしていって,桁数が大きくなると自動的に多倍長整数として扱われるようです。

多倍長整数の計算の例
$ irb
irb(main):001:0> 1234*1234**30
677282650341660040089792666306037793886265518837783426965985431080199944431279156449282866806784

■ 複素数

複素数はライブラリー Complex を読み込んでから使います。

複素数は Complex.new(a,b) か Complex(a,b) で作成します。 また,純虚数は 2.im とか x.im というメソッドでも作成できます。

複素数の例
$ irb
irb(main):001:0> require "complex"
true
irb(main):002:0> a=Complex.new(1.0,2.0)
Complex(1.0, 2.0)
irb(main):003:0> b=Complex(3,4)
Complex(3, 4)
irb(main):004:0> x=5
5
irb(main):005:0> c=x.im
Complex(0, 5)
irb(main):006:0> a+b+c
Complex(4.0, 11.0)

以下の算術演算子や関数が複素数で利用できるように拡張されているようです。

演算子  +   -   *   /   %   **   <=>   ==  
関数  atan2 cos sin tan exp log log10 sqrt 
複素数の計算の例
$ irb
irb(main):001:0> require "complex"
true
irb(main):002:0> include Math
Object
irb(main):003:0> z=Complex(1.0 , sqrt(3.0) )
Complex(1.0, 1.732050808)
irb(main):004:0> log(z)
Complex(0.6931471806, 1.047197551)
irb(main):005:0> sin(z)
Complex(2.452532349, 1.479161976)
irb(main):006:0> sin(z)**2+cos(z)**2
Complex(1, 8.881784197e-16)

クラス Complex には以下のメソッドが定義されています。

メソッド 意味
abs z.abs = |z|
abs2 z.abs2 = |z|*|z|
arg z.arg = z の偏角
conjugate z.conjugate = z の共役複素数
image z.image = Im( z )
polar z.polar = [ z.abs , z.arg ]
real z.real = Re( z )
to_f z.to_f = Complex( z.real.to_f , z.image.to_f )
to_i z.to_i = Complex( z.real.to_i , z.image.to_i )
to_r z.to_r = Complex( z.real.to_r , z.image.to_r ) 有理数への変換
to_s z.to_s 文字列への変換
複素数のメソッドの例
$ irb
irb(main):001:0> require "complex"
true
irb(main):002:0> include Math
Object
irb(main):003:0> z=Complex(1.0,sqrt(3.0))
Complex(1.0, 1.732050808)
irb(main):004:0> z.abs
2.0
irb(main):005:0> z.abs2
4
irb(main):006:0> z.arg
1.047197551
irb(main):007:0> z.arg/PI
0.3333333333
irb(main):008:0> z.conjugate
Complex(1.0, -1.732050808)
irb(main):009:0> z.real
1.0
irb(main):010:0> z.image
1.732050808
irb(main):011:0> z.polar
[2.0, 1.047197551]
irb(main):012:0> z.to_s
"1.0+1.732050808i"

■ 有理数

有理数はライブラリー Rational を読み込んでから使います。

有理数は Rational.new(a,b) か Rational(a,b) で作成します。

詳しく知りたい方は /usr/lib/ruby/1.6/rational.rb を見てください。

有理数の例
$ irb
irb(main):001:0> require "rational"
true
irb(main):002:0> a=Rational.new(2,3)
Rational(2, 3)
irb(main):003:0> b=Rational(3,4)
Rational(3, 4)
irb(main):004:0> a+b
Rational(17, 12)
irb(main):005:0> a*b
Rational(1, 2)
irb(main):006:0> a/b
Rational(8, 9)
irb(main):007:0> a**3
Rational(8, 27)
irb(main):008:0> a.to_s
"2/3"

■ 行列

行列はライブラリー Matrix を読み込んでから使います。

行列は Matrix[[a00,a01,a02],[a10,a11,a12],[a20,a21,a22]] で作成します。

また,このライブラリーにはベクトル Vector[a0,a1,...] のクラスも定義されています。

転置行列,逆行列,行列式や行列とベクトルの積なども計算できるので, けっこう使えるかも?

詳しく知りたい方は /usr/lib/ruby/1.6/matrix.rb を見てください。

行列の例
$ irb
irb(main):001:0> require "matrix"
true
irb(main):002:0> a=Matrix[[1.0,2.0],[3.0,4.0]]
Matrix[[1.0, 2.0], [3.0, 4.0]]
irb(main):003:0> a*a
Matrix[[7.0, 10.0], [15.0, 22.0]]
irb(main):004:0> 2*a
Matrix[[2.0, 4.0], [6.0, 8.0]]
irb(main):005:0> b=a.inv
Matrix[[-2.0, 1.0], [1.5, -0.5]]
irb(main):006:0> a*b
Matrix[[1.0, 0.0], [0.0, 1.0]]
irb(main):007:0>
irb(main):008:0> a[1,1]
4.0
irb(main):009:0> a[0,1]
2.0
irb(main):010:0> a.row_size
2
irb(main):011:0> a.column_size
2
irb(main):012:0> a.row(0)
Vector[1.0, 2.0]
irb(main):013:0> a.row(1)
Vector[3.0, 4.0]
irb(main):014:0> a.column(0)
Vector[1.0, 3.0]
irb(main):015:0> a.column(1)
Vector[2.0, 4.0]
irb(main):016:0> a.regular?
true
irb(main):017:0> a.singular?
false
irb(main):018:0> a.det
-2.0
irb(main):019:0> a.rank
2
irb(main):020:0> a.trace
5.0
irb(main):021:0> a.tr
5.0
irb(main):022:0> a.transpose
Matrix[[1.0, 3.0], [2.0, 4.0]]
irb(main):023:0> a.t
Matrix[[1.0, 3.0], [2.0, 4.0]]
irb(main):024:0> a.to_s
"Matrix[[1.0, 2.0], [3.0, 4.0]]"

Matrix と Vector の計算例

irb(main):025:0> c=Vector[1,1]
Vector[1, 1]
irb(main):026:0> a*c
Vector[3.0, 7.0]

特別な行列の作成例

irb(main):027:0> Matrix.diagonal(1,2,3,4)
Matrix[[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]
irb(main):028:0> Matrix.scalar(4,2)
Matrix[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]
irb(main):029:0> Matrix.identity(4)
Matrix[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
irb(main):030:0> Matrix.unit(4)
Matrix[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
irb(main):031:0> Matrix.I(4)
Matrix[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
irb(main):032:0> Matrix.zero(4)
Matrix[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
複素数の行列の例
$ irb
irb(main):001:0> require "complex"
true
irb(main):002:0> require "matrix"
true
irb(main):003:0> sx=Matrix[[0,1],[1,0]]
Matrix[[0, 1], [1, 0]]
irb(main):004:0> sy=Matrix[[0,-1.im],[1.im,0]]
Matrix[[0, Complex(0, -1)], [Complex(0, 1), 0]]
irb(main):005:0> 
irb(main):006:0> sz=Matrix[[1,0],[0,-1]]
Matrix[[1, 0], [0, -1]]
irb(main):007:0> sx*sy
Matrix[[Complex(0, 1), Complex(0, 0)], [Complex(0, 0), Complex(0, -1)]]
irb(main):008:0> sx*sy/1.im
Matrix[[Complex(1, 0), Complex(0, 0)], [Complex(0, 0), Complex(-1, 0)]]
irb(main):009:0> include Math
Object
irb(main):010:0> cos(PI/4)*sx+sin(PI/4)*sy
Matrix[[0.0, Complex(0.7071067812, -0.7071067812)], [Complex(0.7071067812, 0.7071067812), 0.0]]
irb(main):011:0> a=cos(PI/4)*sx+sin(PI/4)*sy
Matrix[[0.0, Complex(0.7071067812, -0.7071067812)], [Complex(0.7071067812, 0.7071067812), 0.0]]
irb(main):012:0> a*a
Matrix[[Complex(1.0, 0.0), Complex(0.0, 0.0)], [Complex(0.0, 0.0), Complex(1.0, 0.0)]]
irb(main):013:0> 
irb(main):014:0> a.tr
0.0
irb(main):015:0> a.det
Complex(-1.0, 0.0)
irb(main):016:0> a.inv
Matrix[[Complex(0.0, 0.0), Complex(0.7071067812, -0.7071067812)], [Complex(0.7071067812, 0.7071067812),Complex(0.0, 0.0)]]

■ 例題)超簡易関数電卓

Ruby で数値計算をする例題として(??ちょっと違う??)超簡単な電卓プログラムを紹介しておきます。

簡易関数電卓プログラム
 1: #!/usr/bin/ruby
 2: require "readline"
 3: include Readline
 4: include Math
 5:
 6: prompt=">"
 7: while true do
 8:   s=readline(prompt,true)
 9:   p eval(s)
10: end

2行目と3行目は入力時に行編集機能が使えるようにするためのものです。 こうしておいて,6行目でプロンプト文字列を定義し,8行目のようにして入力すると, →や←で左右に移動して入力文字を修正できます。 また,ヒストリー機能もあるので,↑や↓などで前に入力した文字列を呼び出すこともできます。

計算は9行目で eval を呼び出して実行しています。 単に eval を呼び出しているだけですから,もちろん数値計算でなくても,Ruby のコマンドなら実行できます。

このプログラムを calc という名前で保存し,chmod で実行権限を与えて kterm の上で実行してみました。

実行例
[ashida@cactus ashida]$ calc
>x=4 ; y=5
5
>x+y
9
>sin(PI*x)
-4.898425415e-16
>exp(x)
54.59815003
>5.times { |n| puts(x*n) }
0
4
8
12
16
5
>exit
[ashida@cactus ashida]$ 

たった10行のプログラムですが,編集機能も使え,変数も使える関数電卓になります。 また,計算結果をマウスでコピー&ペーストして他のファイルに挿入できるので, 結構便利です。


リテラル

■ 数値リテラル

表記 意味
1234 10進整数
123_456_789 10進整数。アンダースコアーを入れてよい。
12.345 浮動少数点数
1.234e+5 または 1.234E+5 浮動少数点数
0x12ab または 0x12AB 16進整数
0123 8進整数
0b1101 または 0B1101 2進整数
?a 文字 a のコード
?\n など 文字 \n のコードなど
?\C-a など Ctrl-a のコードなど
?\M-a など メタ a のコードなど
?\M-\C-a など メタ Ctrl-a のコードなど

■ 文字列リテラル

文字列リテラルは普通はダブルクォーテーション " で文字列をはさんで表します。

バックスラッシュ記法( \ によるエスケープ )

表記 意味
\t タブ 0x09
\v 垂直タブ 0x0b
\n 改行 0x0a
\r キャリッジリターン 0x0d
\f 改ページ 0x0c
\b バックスペース 0x08
\a ベル 0x07
\e エスケープ 0x1b
\s 空白 0x20
\nnn 8進数表記( n は 0から7 )
\xnn 16進数表記
\ca など Ctrl-a など
\C-a など Ctrl-a など
\M-a など メタ a など
\M-\C-a など メタ Ctrl-a など
\\ \
\" "

式の値をリテラルに埋め込む

ダブルクォーテーションの中に #{式や変数} を書くと, 式や変数の値を文字列に変換して,文字列の中に埋め込むことができます。

#{式や変数} の例
$ irb
irb(main):001:0> x=5 ; y=3
3
irb(main):002:0> puts "x=#{x} y=#{y}  x+y=#{x+y}"
x=5 y=3  x+y=8
nil

シングルクォーテーション ' で文字列をはさんで表すこともできますが, シングルクォーテーションの場合には \\ \' 以外のバックスラッシュ記法( \ によるエスケープ )は無効になります。

ダブルクォーテーションやシングルクォーテーションの代わりに % を使って文字列を表す方法もありますが, 私は使ったことがないので,説明は省略します。

■ ヒアドキュメント

ヒアドキュメントの例
$ irb
irb(main):001:0> x=5 ; y=3
3
irb(main):002:0> st = <<"EOS"
irb(main):003:0" これは
irb(main):004:0" ヒアドキュメントの
irb(main):005:0" 例です。
irb(main):006:0" この中で #{x} なども使えます。
irb(main):007:0" EOS
"\244\263\244\354\244\317\n (省略)\250\244\336\244\271\241\243\n"
irb(main):008:0> puts st
これは
ヒアドキュメントの
例です。
この中で 5 なども使えます。
nil

■ コマンド出力

シェル上で実行できるコマンドを表す文字列をバッククォーテーション ` ではさむと,Ruby インタープリターは子プロセスとして,このコマンドを実行し, 得られた標準出力を文字列にして返します。

このコマンド文字列の中ではダブルクォーテーションの中と同様にバックスラッシュ記法( \ によるエスケープ )や #{式} を使うことができます。

コマンド出力の例
$ irb
irb(main):001:0> st=`date`
"2005\307\257  1\267\356  1\306\374 \305\332\315\313\306\374 17:46:27 JST\n"
irb(main):002:0> puts st
2005年  1月  1日 土曜日 17:46:27 JST
nil
irb(main):003:0> cm="date"
"date"
irb(main):004:0> puts `#{cm}`
2005年  1月  1日 土曜日 17:47:06 JST
nil

入出力

Ruby でファイルや標準入力,出力を利用するには実に様々な方法があります。 ここでは簡単な方法をいくつか紹介しておきます。

(実は私もあまり詳しくは知らない .... 。)

■ open と close

Ruby でもC言語などと同じように open でファイルを開き, 処理が終わったら close するという書き方もできます。

open と close の使用例
f=open("testfile","r")
while line=f.gets
   print line
end
f.close

open("ファイル名","オプション") のオプションは r , r+ , w , w+ , a , a+ が使え, さらにバイナリーモードにするために b を追加指定できるところなど,C言語と同じです。

オプション r や r+ では,ファイルのオープンに失敗した場合には例外が発生するので, begin rescue ensure end 構文などで例外処理をすべきですが, 詳しくは本などで調べて下さい。

rescue の使用例
begin
  f=open("testfile","r")
  while line=f.gets
    print line
  end
  f.close
rescue
  print "ERROR: #$!\n"
end

■ open と ブロック

open したファイルは原則として close で閉じるので, 処理が短く書ける場合にはブロックにしてしまうと close を書かなくてもブロックが終了した時に 自動的にファイルを閉じてくれます。

open とブロック の使用例
open("testfile","r") do |f|
  while line=f.gets
    print line
  end
end

■ File クラス

File クラスを利用すると,ファイルのオープンやクローズだけでなく, ファイル名を変更したり,ファイルを削除したり,あるいは属性を変更したりと, 様々なファイル操作ができます。

File.open の使用例
f=File.open("testfile","r")
while line=f.gets
   print line
end
f.close
File.open とブロック の使用例
File.open("testfile","r") do |f|
  while line=f.gets
    print line
  end
end
File.foreach の使用例
File.foreach("testfile") do |line|
  print line
end

■ ARGF の利用

ARGF (または $< )はコマンドライン引数として与えられたファイルを連結して一つのファイルにしたようなものです。

ARGF の使用例 その1
while line = ARGF.gets
  print line
end
ARGF の使用例 その2
for line in ARGF
  print line
end
ARGF の使用例 その3
ARGF.each do |line|
  print line
end

これらのスクリプトをコマンドラインで実行すると以下のようになります。 赤で書いた部分がキーボードから入力した部分です。

実行例 その1
[ashida@cactus File]$  ./test06.rb testfile*
これは入出力のテスト用ファイル testfile01 です。
内容に意味はありません。
これは入出力のテスト用ファイル testfile02 です。
内容に意味はありません。

ARGF はコマンドラインにファイル名が与えられないと, 自動的に標準入力から入力します。 ですから上記のスクリプトは入力をパイプラインから受け取ったり, リダイレクションを利用したりできます。

実行例 その2
[ashida@cactus File]$  cat testfile* | ./test06.rb
これは入出力のテスト用ファイル testfile01 です。
内容に意味はありません。
これは入出力のテスト用ファイル testfile02 です。
内容に意味はありません。
[ashida@cactus File]$
[ashida@cactus File]$ ./test06.rb < testfile01
これは入出力のテスト用ファイル testfile01 です。
内容に意味はありません。

■ 標準入出力

いうまでもなく,標準入力や標準出力などは自分でオープンしなくても, 最初からオープンしています。

■ 入力

Ruby では入力や出力は, ファイルや標準入出力と結びついた io オブジェクトのメソッドを呼び出して行います。

メソッド 意味
gets(区切り文字) 一行読み込んで,文字列として返す。行の区切り文字は省略可能。
既にファイル終端の場合には nil を返す。
readline(区切り文字) 一行読み込んで,文字列として返す。行の区切り文字は省略可能。
既にファイル終端の場合には例外 EOFError を発生させる。
getc 一文字読み込んでキャラクターコードを Fixnum として返す。
既にファイル終端の場合には nil を返す。
readchar 一文字読み込んでキャラクターコードを Fixnum として返す。
既にファイル終端の場合には例外 EOFError を発生させる。
ungetc(char) ストリームに char を戻す。
read(n) n バイト読み込んで文字列として返す。
既にファイル終端の場合には nil を返す。
n を省略するとファイルの最後までを読み込む。
each(区切り文字) 一行ずつ読み込んで,文字列としてブロックパラメーターに渡す。 行の区切り文字は省略可能。
each_byte 一文字読み込んでキャラクターコードを Fixnum としてブロックパラメーターに渡す。
readlines(区切り文字) ストリームの内容を全て読み込んで, 各行を文字列にして並べた配列を返す。 行の区切り文字は省略可能。

この他にも低レベルな入力メソッドの sysread などがあります。

■ 出力

出力は基本的に文字列を出力します。 もし引数のオブジェクトが String でない場合には自動的に to_s が呼び出されて String に変換されてから出力されます。

例えば print 5 は print 5.to_s+$\ と解釈されます。

print などのメソッドに複数の引数が与えられると,各引数の間に $, が挿入され,最後に $\ が付け加えられます。 但し,$, も $\ もデフォールトでは空文字列(空白ではない!)なので,何も追加されません。

セパレーター 名前 意味
$, 出力フィールドセパレーター 各引数の間に挿入される。デフォールトでは空。
$\ 出力レコードセパレーター 最後の引数の後ろに追加される。デフォールトでは空。
セパレーターの変更例
[ashida@cactus File]$ irb
irb(main):001:0> print 5,6,7
567nil
irb(main):002:0> $,="間"
"\264\326"
irb(main):003:0> $\="終わり\n"
"\275\252\244\357\244\352\n"
irb(main):004:0> print 5,6,7
5間6間7終わり
nil
メソッド 意味
print obj1 , obj2 obj1.to_s + $, + obj2.to_s + $\ を出力する。戻り値は nil 。
 << obj 
obj.to_s を出力する。戻り値は IO オブジェクト 。
 例)STDOUT << 5 << "hogehoge" << 6 
write obj obj.to_s を出力する。戻り値は実際に出力したバイト数 。
puts obj1, obj2 obj1.to_s + "\n" + obj2.to_s + "\n" を出力する。
putc char char を出力する。char が文字列の場合には char の先頭の文字を出力する。
printf(format,obj1,obj2) C言語の printf と同様。

フォーマット付き出力

フォーマットを指定した出力は printf で行えますが, 次のようにしても行えます。

フォーマット付き出力の例
[ashida@cactus File]$ irb
irb(main):001:0> STDOUT << sprintf("x=%10.6e y=%10.6e\n",2.5 , 3.141592)
x=2.500000e+00 y=3.141592e+00
#<IO:0x4027b07c>
irb(main):002:0> STDOUT << "x=%10.6e y=%10.6e\n" % [2.5 , 3.141592]
x=2.500000e+00 y=3.141592e+00
#<IO:0x4027b07c>

コマンドラインパラメーター

■ ARGV

C言語ではプログラムに与えられた引数の数と内容が main 関数の引数 argc と argv に渡されますが, Ruby では組み込み変数の ARGV に渡されます。

ARGV はコマンドライン引数からなる文字列の配列です。 ですから argc に対応するコマンドライン引数の個数は ARGV.size や ARGV.length で求めることができます。

ARGV の例
スクリプト
#!/usr/bin/ruby

puts ARGV.size, ARGV.length
puts ARGV
puts ARGV[0]
puts ARGV[1]


実行例
[ashida@cactus File]$ ./test08.rb -h testfile
2
2
-h
testfile
-h
testfile

C言語に慣れているいる人はちょっと注意が必要です。 C言語とは違って ARGV[0] は "./test08.rb" ではなくて, 最初の引数 "-h" が入ります!

■ getopts

コマンドラインは以下のような書式になっていることが多いでしょう。

コマンド -一文字オプション --長いオプション文字 ファイル1 ファイル2

このコマンドラインパラメーターの中からオプションの部分を取り出すのには getopts を使います。

ARGV の例
スクリプト
#!/usr/bin/ruby
require 'getopts'

puts ARGV.size
puts ARGV

getopts("hv","help","level:1")

puts ARGV.size
puts ARGV

puts $OPT_h
puts $OPT_v
puts $OPT_help
puts $OPT_level

実行例
[ashida@cactus File]$ ./test09.rb
0
0
false
false
false
1
[ashida@cactus File]$ ./test09.rb -h --level 6 testfile1 testfile2
5
-h
--level
6
testfile1
testfile2
2
testfile1
testfile2
true
false
false
6

配列

Ruby では配列は Array クラスとして定義されています。 C言語などの他の言語と違って,任意のオブジェクトを混在させて並べることができます。

■ 配列の作成

Ruby では配列の作り方も,何通りもあります。

配列の作成例
[ashida@cactus comp]$ irb
irb(main):001:0> a=[ 1,2,'ashida', 6.7 , "masami" ]
[1, 2, "ashida", 6.7, "masami"]
irb(main):002:0> b=Array[ "C" , "Ruby" , "Perl" ]
["C", "Ruby", "Perl"]
irb(main):003:0> c=Array.new(3,"apple")
["apple", "apple", "apple"]
irb(main):004:0> d=Array.new(4)
[nil, nil, nil, nil]

■ メソッドの例

配列の要素を取り出したり,要素を変更するには [] というメソッドを使います。
( Ruby では [] もメソッドです。)

添字は 0 から始まるので,a=[ 1,2,'ashida', 6.7 , "masami" ] の先頭要素は a[0] です。

以下の説明で i 番目という時,先頭の要素 a[0] は 0 番目と解釈して下さい。

要素へのアクセス
メソッド 意味
a[i] i 番目の要素を返す。a[i]=x は a[i] に x を代入する。
a[i..j] i 番目から j 番目までの要素を返す。 a[i..j]=b は a[i..j] を配列 b の内容と置き換える。
a[i,n] i 番目から n 個の要素を返す。 a[i,n]=b は a[i,n] を配列 b の内容と置き換える。
配列操作の例
[ashida@cactus comp]$ irb
irb(main):001:0> a=[0,1,2,3]
[0, 1, 2, 3]
irb(main):002:0> a[2,2]=[6]
[6]
irb(main):003:0> a
[0, 1, 6]
irb(main):004:0> a[2,1]=[7,8,9]
[7, 8, 9]
irb(main):005:0> a
[0, 1, 7, 8, 9]
irb(main):006:0> a[1..3]=[]
[]
irb(main):007:0> a
[0, 9]
演算
メソッド 意味
a + b 配列 a と配列 b を連結した配列を返す。
a * n 配列 a の n 回の繰り返し。
a - b 配列 a と配列 b の集合としての差。
a & b 配列 a と配列 b の集合としての積(共通部分)。
a | b 配列 a と配列 b の集合としての和。
a << obj 配列 a の最後に obj を付け加える(最後の要素が obj になる)。
配列操作の例
irb(main):001:0> a=[0,1]
[0, 1]
irb(main):002:0> a + [2,3]
[0, 1, 2, 3]
irb(main):003:0> a
[0, 1]
irb(main):004:0> a * 2
[0, 1, 0, 1]
irb(main):005:0> a
[0, 1]
irb(main):006:0> a += [2,2]
[0, 1, 2, 2]
irb(main):007:0> a
[0, 1, 2, 2]
irb(main):008:0> a - [0,2]
[1]
irb(main):009:0> a
[0, 1, 2, 2]
irb(main):010:0> a << 6 << 8
[0, 1, 2, 2, 6, 8]
irb(main):011:0> a
[0, 1, 2, 2, 6, 8]
置き換え,連結,削除など
メソッド 意味
a.fill(x,i,n) i 番目から n 個の要素を x で置き換える。n を省略すると i 番目から最後まで。
a.replace(b) 配列 a の要素を配列 b の要素で置き換える。
a.concat(b) 配列 a の最後に配列 b を破壊的に付け加える。つまり a=a+b とほぼ同じ。
a.delete(x) 要素 x を削除する。( x と同じ要素を全て削除する )
a.delete_at(i) i 番目の要素を削除する。
a.compact a.compact! 配列 a から nil である要素を削除する。 a.compact! は a = a.compact 。
a.join(st) 配列 a の要素を文字列に変換し,間に文字列 x を挿入する。
a.pop 配列 a の最後の要素を取り出して返し,最後の要素を削除する。
a.push(x) 配列 a の最後に x を追加する。a.concat([x])と同じ?
a.shift 配列 a の先頭の要素を取り出して返し,先頭の要素を削除する。
a.unshift(x) 配列 a の先頭に x を追加する。
a.to_s 配列 a を文字列にする。
a.uniq a.uniq! 配列 a の要素で等しいものを一つにする。 a.uniq! は a = a.uniq 。
a.reverse a.reverse! 配列 a の要素を逆の順番に並べ換えた配列を返す。 a.reverse! は a = a.reverse 。
a.sort a.sort! 配列 a の要素をソートした配列を返す。 a.sort! は a = a.sort 。

Ruby ではオブジェクト自身を変化させてしまうメソッド(破壊的なメソッド)にはメソッド名の最後に ! を付けることがあります。 なお,最後の ! も名前の一部です。

破壊的なメソッドの例
[ashida@cactus comp]$ irb
irb(main):001:0> a=[0,nil,2,3,2]
[0, nil, 2, 3, 2]
irb(main):002:0> a.compact
[0, 2, 3, 2]
irb(main):003:0> a
[0, nil, 2, 3, 2]
irb(main):004:0> a.compact!
[0, 2, 3, 2]
irb(main):005:0> a
[0, 2, 3, 2]
irb(main):006:0> a.uniq
[0, 2, 3]
irb(main):007:0> a
[0, 2, 3, 2]
irb(main):008:0> a.uniq!
[0, 2, 3]
irb(main):009:0> a
[0, 2, 3]
irb(main):010:0> a.reverse
[3, 2, 0]
irb(main):011:0> a
[0, 2, 3]
irb(main):012:0> a.reverse!
[3, 2, 0]
irb(main):013:0> a
[3, 2, 0]
irb(main):014:0> a.sort
[0, 2, 3]
irb(main):015:0> a
[3, 2, 0]
irb(main):016:0> a.sort!
[0, 2, 3]
irb(main):017:0> a
[0, 2, 3]

Ruby では同じような効果を持つ演算(操作,メソッド)がたくさんあるので, どれを使うか迷うところです。

次の例では配列 a の最後に要素を付け加えています。 a 自身は変わるのかどうかに注意して下さい。

配列操作の例
[ashida@cactus comp]$ irb
irb(main):001:0> a=[0,1,2]
[0, 1, 2]
irb(main):002:0> a
[0, 1, 2]
irb(main):003:0> a + [3]
[0, 1, 2, 3]
irb(main):004:0> a
[0, 1, 2]
irb(main):005:0> a.concat([3])
[0, 1, 2, 3]
irb(main):006:0> a
[0, 1, 2, 3]
irb(main):007:0> a << 4 << 5
[0, 1, 2, 3, 4, 5]
irb(main):008:0> a
[0, 1, 2, 3, 4, 5]
irb(main):009:0> a.push 6
[0, 1, 2, 3, 4, 5, 6]
irb(main):010:0> a
[0, 1, 2, 3, 4, 5, 6]
irb(main):011:0> a += [7]
[0, 1, 2, 3, 4, 5, 6, 7]
irb(main):012:0> a
[0, 1, 2, 3, 4, 5, 6, 7]
検索と検査
メソッド 意味
a.index(x) 配列 a の要素に x があればその添字を返し,なければ nil を返す。
a.include?(x) 配列 a に要素 x があれば true 無ければ false を返す。
a.nitems 配列 a の nil でない要素の数を返す。
a.empty? 配列 a の大きさが 0 の時 true それ以外では false 。
a.length または a.size 配列 a の大きさ(要素の個数)を返す。

イテレーター
メソッド 意味
a.each { |x| 文 } 配列 a の要素を順次 x に代入してブロックの文を実行する。
a.each_index { |i| 文 } 配列 a の要素のインデックス(添字)を順次 i に代入してブロックの文を実行する。
a.each_with_index { |x,i| 文 } 配列 a の要素を x ,インデックスを i に代入してブロックの文を実行する。
a.reverse_each { |x| 文 } 配列 a の要素を最後から逆順に x に代入してブロックの文を実行する。
a.sort { |a,b| 文 }  a.sort! { |a,b| 文 } 配列 a の要素をソートする。 文は要素 a と b の大きさの関係を a > b で正 ,a==b で 0 ,a < b で負を返す式を書く。
a.delete_if { |x| 文 } 配列 a の要素を順次 x に代入してブロックの文が真となる場合は,その要素を削除する。
a.collect { |x| 文 } a.collect! { |x| 文 } 配列 a の要素を順次 x に代入してブロックの文を実行した結果からなる配列を返す。

イテレーターの説明をまだしていないのですが,以下に例をあげておきます。

なお a.each { |x| 文 } などは a.each do |x| 文 end と書くこともできます。

配列のイテレーターの例
[ashida@cactus comp]$ irb
irb(main):001:0> a=['A','B']
["A", "B"]
irb(main):002:0> a.each { |x| puts x }
A
B
["A", "B"]
irb(main):003:0> a.each_index { |i| puts a[i] }
A
B
["A", "B"]
irb(main):004:0> a.each_with_index { |x,i| printf("%d 番目は %s\n",i,x) }
0 番目は A
1 番目は B
["A", "B"]
irb(main):005:0> a.reverse_each { |x| puts x }
B
A
["A", "B"]
irb(main):006:0> a.sort { |x,y| x<=>y }
["A", "B"]
irb(main):007:0> a.sort { |x,y| -(x<=>y) }
["B", "A"]
irb(main):008:0> a.delete_if { |x| x=='B' }
["A"]
irb(main):009:0> a=['A','B','C']
["A", "B", "C"]
irb(main):010:0> a.collect! { |x| x+'0' }
["A0", "B0", "C0"]
irb(main):011:0> a
["A0", "B0", "C0"]

ハッシュ

■ ハッシュの作成

ハッシュは配列のように任意のオブジェクトを収納できる入れ物です。

配列はインデックス(添字)で要素にアクセスしますが, ハッシュは「キー」で対応する「値」を取り出します。

ハッシュの作成例
[ashida@cactus comp]$ irb
irb(main):001:0> a = { 'apple'=>100 , 'orange'=>200 }
{"apple"=>100, "orange"=>200}
irb(main):002:0> b = Hash['ashida'=>0,'hara'=>1]
{"ashida"=>0, "hara"=>1}
irb(main):003:0> c = {0,1,2,3}
{0=>1, 2=>3}
irb(main):004:0> d = Hash[ 'a',0,'b',1,'c',2]
{"a"=>0, "b"=>1, "c"=>2}

上の例では 'apple' や 'orange' がキーで, 'apple' に対応する値が 100 です。

キーは文字列,数値などはもちろん,色々なオブジェクトでかまいません。 但し,キーの値が同じかどうかを判断できなければならないので, キーにするオブジェクトのクラスには, 整数値を返す hash というメソッドと真偽値を返す eql? という二つのメソッドが定義されていなければなりません。 詳しくは本などで調べて下さい。

■ メソッドの例

ハッシュのキーから値を取り出したり,値を変更するには [] というメソッドを使います。

要素へのアクセス
メソッド 意味
a[x] ハッシュ a の キー x に対応する値を返す。
a[x]=b ハッシュ a の キー x に対応する値に b を代入する。

存在しないキーを指定した場合にはハッシュのデフォールト値の nil が返されます。 ハッシュのデフォールト値はメソッド default= で変更することができます。 また,Hash.new() でデフォールト値を指定することもできます。

ハッシュのデフォールト値の例
[ashida@cactus comp]$ irb
irb(main):001:0> a={ 0,1,2,3 }
{0=>1, 2=>3}
irb(main):002:0> a[2]
3
irb(main):003:0> a[1]
nil
irb(main):004:0> a.default=-1
-1
irb(main):005:0> a[1]
-1
irb(main):006:0> a['ashida']
-1
irb(main):007:0> a[0]
1
irb(main):008:0> b=Hash.new(100)
{}
irb(main):009:0> b['ashida']=1
1
irb(main):010:0> b['hara']=2
2
irb(main):011:0> b
{"ashida"=>1, "hara"=>2}
irb(main):012:0> b['nagai']
100
要素の更新や削除など
メソッド 意味
h.update(h0) ハッシュ h の内容をハッシュ h0 で上書きする。
h.replace(h0) ハッシュ h の内容をハッシュ h0 と同じにする。
h.shift ハッシュ h から [ キー , 値 ] という配列を取り出し,この要素を h から削除する。
取り出す順序は不定。
h.clear ハッシュ h を空にする。つまり h={} になる。
h.delete(x) ハッシュ h からキー x に対応する要素を削除する。
h.default ハッシュ h にキーが存在しない場合のデフォールト値を返す。
h.default(x) ハッシュ h にキーが存在しない場合のデフォールト値を設定する。
h.key?(x) h.include?(x) ハッシュ h にキーが存在すれば真,存在しなければ偽を返す。
h.value?(v) ハッシュ h に値 v に対応付けられたキーが存在すれば真,存在しなければ偽を返す。
h.keys ハッシュ h の全てのキーを配列にして返す。
h.values ハッシュ h の全ての値を配列にして返す。
h.invert ハッシュ h のキーと値の役割を逆にしたハッシュを返す。
h.to_a ハッシュ h の要素を [[キー0 , 値0],[キー1 , 値1], ... ] という配列にして返す。
h.indexes(x0,x1,..) h.indices(x0,x1,..) キー x0,x1,... に対応する値を配列にして返す。
h.empty? ハッシュ h の大きさ(キーの個数)が 0 の時に真を返す。
h.length h.size ハッシュ h の大きさ(キーの個数)を返す。

イテレーター
メソッド 意味
h.each{ |x,v| 文 } ハッシュ h のキーを x に,値を v に順次代入してブロックの文を実行する。
h.each_key{ |x| 文 } ハッシュ h のキーを x に順次代入してブロックの文を実行する。
h.each_value{ |v| 文 } ハッシュ h の値を v に順次代入してブロックの文を実行する。
h.delete_if { |x,v| 文 } ハッシュ h のキーを x に,値を v に順次 x に代入してブロックの文が真となる場合は, その要素を削除する。

ハッシュのイテレーターの場合にはキーや値が代入される順番は不定です!


ブロックとイテレーター

Fortran ,Pascal や C言語などでは関数(や手続きなど)を引数として別の関数(や手続きなど)に渡すことができます。

ところが Ruby では関数やメソッドはオブジェクトではないので, 他の関数やメソッドの引数にすることができません。

Ruby では関数やメソッドを引数にする代わりに, 処理したい内容をブロックや手続きオブジェクトにして引数として渡します。

■ ブロック

処理したい内容を { } で囲んだものがブロックです。 { と } の代わりに do end で囲むこともできます。

{ 処理する文 } というブロックをそのまま引数として関数やメソッドに渡すことができます。 ブロックを渡された関数やメソッドの側で yield(引数) を実行すると, ブロックが実行されます。

ブロックを渡す例 その1
プログラム

 1: #!/usr/bin/ruby
 2:
 3: def fun0(a,b)
 4:   puts yield(a,b)
 5: end
 6:
 7: a=5
 8: fun0(1,2) { |x,y| x+y+a }
 9:
10: fun0(4,5) do |x,y| x*y end
11:
12: fun0(4,5) { |x,y| 
13:   printf("x=%d  y=%d  x*y=",x,y)
14:   x*y
15:   }
16:
17: fun0(3,6)

実行結果
[ashida@cactus]$ ./test001.rb
8
20
x=4  y=5  x*y=20
./test001.rb:4:in `fun0': no block given (LocalJumpError)
        from ./test001.rb:17

3行目から5行目までがブロックを受け取る関数の定義です。

4行目で yield を呼んでブロックを実行しています。yield の引数 a と b はブロックに渡されます。 yield の返す値はブロックの最後に実行した文の値です。

8行目では関数 fun0 にブロック { |x,y| x+y+a } を渡しています。 |x,y| は fun0 の中の yield から渡される引数です。

この例の a ように,ブロックの中ではブロックの外の変数にアクセスすることができます。

しかし,ブロックの中で初めて使った変数をブロックの外からアクセスすることはできません。

10行目では { } の代わりに do end でブロックにしてみました。

この関数定義では17行目のように,ブロックを渡さずに fun0 を呼び出すと実行時エラーになります。

ブロックを渡さない場合にも処理を継続したい場合には,例えば次のようにすればよいでしょう。

ブロックを渡す例 その2
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a,b)
 4:   if defined? yield
 5:     puts yield(a,b)
 6:   else
 7:     printf("x=%d  y=%d\n",a,b)
 8:   end
 9: end
10:
11: fun0(1,2) { |x,y| x+y }
12:
13: fun0(4,5) do |x,y| x*y end
14: 
15: fun0(4,5) { |x,y| 
16:   printf("x=%d  y=%d  x*y=",x,y)
17:   x*y
18:   }
19:
20: fun0(3,6)


実行結果
[ashida@cactus]$ ./test011.rb
3
20
x=4  y=5  x*y=20
x=3  y=6

4行目の defined? yield でブロックが渡されたか否かを判断しています。 defined? yield は,正しくは defined?( yield ) と書くのでしょうね。 Ruby では ( ) を省略することができるので ... 。

{ } と do end の違い

処理内容を { } で囲んだブロックと,do end で囲んだブロックでは, 識別子との結合強度が少し違うらしいです。

Ruby デスクトップリファレンスによると

{ } と do end の違い

a b  { |x| 文 }a( b{ |x| 文 } ) と解釈され,b{ |x| 文 }の実行結果が a( ) に渡される。

a b do |x| 文 enda(b) do |x| 文 end と解釈され,ブロック do |x| 文 enda( ) に渡される。

だそうです。(未確認!!)

ちなみに,私はどう解釈するのかが見ただけでは分からないような書き方は嫌いなので (一々規則を覚えていられないので), こう言う場合は積極的に ( ) を使って, どれとどれが結合しているのかが自分に分かるように書きます。

■ 手続きオブジェクト

さて,ブロックで処理を渡すというのは私にはとても新鮮で,面白いのですが, 同じ処理をいくつかの関数やメソッドに渡したり, 受け取ったブロックをそのまま別のメソッドに渡したい時などに困ります。

つまり,このままではブロックの使い回しが効かないのです。

こういう場合にはブロックを手続きオブジェクトにするとよいようです。

手続きオブジェクトの例
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a,b)
 4:   if defined? yield
 5:     puts yield(a,b)
 6:   else
 7:     printf("x=%d  y=%d\n",a,b)
 8:   end
 9: end
10:
11: p1=Proc.new{ |x,y| x+y }
12: p2=Proc.new do |x,y| x*y end
13: p3=Proc.new { |x,y| 
14:   printf("x=%d  y=%d  x*y=",x,y)
15:   x*y
16:   }
17:
18: fun0(1,2,&p1)
19: fun0(10,20,&p1)
20:
21: fun0(4,5,&p2) 
22: fun0(4,5,&p3)
23:
24: fun0(3,6)

実行結果
[ashida@cactus]$ ./test031.rb
3
30
20
x=4  y=5  x*y=20
x=3  y=6

3行目から9行目までの関数 fun0 の定義は前と同じですから, もちろんこのままでブロックを受け取ることができます。

なお,3行目の def fun0(a,b) def fun0(a,b,&block) などのように書くこともできます。 最後の引数の名前に & を付けると,この引数はブロックや手続きオブジェクトを表すことになります。 こう書いておけば,&block を他のメソッドなどに渡すことができます。

11行目から16行目ではブロックを Proc.new に渡して 手続きオブジェクト p1 , p2 , p3 を作成しています。

18,19,21,22行目では関数 fun0 に手続きオブジェクト p1 , p2 , p3 を渡しています。 手続きオブジェクトの名前の前に & を付けることを忘れないで下さい!

なお,手続きオブジェクトは p1.call(3,4) のようにして実行することができます。

■ イテレーター

Ruby では上記のようにブロックを受け取って実行することができる関数やメソッドをイテレーターと呼んでいます。 「イテレーター」というと,言葉の感じからブロックを繰り返し実行するように思えますが, 上記の例の fun0 ように一度しか実行しないものもイテレーターと呼んでいます。

渡されたブロックを繰り返し実行するイテレーターの代表はなんといっても配列などのメソッドの each でしょうか。

each の実行例
[ashida@cactus ashida]$ irb
irb(main):001:0> a=[ 10, 20,30 ]
[10, 20, 30]
irb(main):002:0> a.each { |x| puts x**2 }
100
400
900
[10, 20, 30]

上記の例では配列 a の要素が順次 x に代入されてブロックの文が実行されます。

ブロックの繰り返しの制御

ブロック内の文の繰り返しは break や next などで制御できます。

コマンド 意味
break ブロックの実行を終了する。またブロックを呼び出したメソッドも終了し,nil を返す。
next ブロックの実行を終了し,nil を返す。
redo ブロックの実行を最初からやり直す。
retry ブロックの実行を引数の評価のところからやり直す。

なんだか break と next の違いや redo と retry の違いが分かりませんね。

実際に使ってみましょう。

break の使用例
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a)
 4:   if defined? yield
 5:     0.upto(10) { |x|
 6:       puts yield(x,2*a)
 7:     }
 8:   else
 9:     puts '引数が無いよ!'
10:   end
11:   puts 'yield の後の文だよ。'
12: end
13:
14: fun0(2) { |x,y|
15:   if x < y then
16:     printf("x=%d y=%d x+y=",x,y)
17:     x+y
18:   else
19:     break
20:   end
21:  }

実行結果
[ashida@cactus iterator]$ ./test041.rb
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
[ashida@cactus iterator]$ 

このように,ブロックの中で break が実行されると,ブロックを呼び出した関数(やメソッド)の fun0 の実行が終了してしまいます。 従って,この例では11行目は実行されません!

次に19行目の break を next に変えてみます。

next の使用例
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a)
 4:   if defined? yield
 5:     0.upto(10) { |x|
 6:       puts yield(x,2*a)
 7:     }
 8:   else
 9:     puts '引数が無いよ!'
10:   end
11:   puts 'yield の後の文だよ。'
12: end
13:
14: fun0(2) { |x,y|
15:   if x < y then
16:     printf("x=%d y=%d x+y=",x,y)
17:     x+y
18:   else
19:     next
20:   end
21:  }

実行結果
[ashida@cactus iterator]$ ./test042.rb
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
nil
nil
nil
nil
nil
nil
nil
yield の後の文だよ。
[ashida@cactus iterator]$ 

このように,next ではブロックは実行を終了しますが,メソッドは実行し続けます。

次に redo にしてみます。

redo の使用例
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a)
 4:   if defined? yield
 5:     0.upto(10) { |x|
 6:       puts yield(x,2*a)
 7:     }
 8:   else
 9:     puts '引数が無いよ!'
10:   end
11:   puts 'yield の後の文だよ。'
12: end
13:
14: fun0(2) { |x,y|
15:   if x < y then
16:     printf("x=%d y=%d x+y=",x,y)
17:     x+y
18:   else
19:     printf("x=%d y=%d\n",x,y)
20:     redo
21:   end
22:  }

実行結果
[ashida@cactus iterator]$ ./test051.rb
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
x=4 y=4
x=4 y=4
x=4 y=4
x=4 y=4
x=4 y=4
x=4 y=4
(以下無限に続く Ctrl+C で止めよう!)

このように redo にすると,同じ x,y の値でブロックの先頭から実行を再開します。

従ってこの例では無限ループになってしまいます! (普通は無限ループにならないようにプログラムを書きます。)

最後に retry を試してみましょう。

retry の使用例
プログラム
 1: #!/usr/bin/ruby
 2:
 3: def fun0(a)
 4:   if defined? yield
 5:     0.upto(10) { |x|
 6:       puts yield(x,2*a)
 7:     }
 8:   else
 9:     puts '引数が無いよ!'
10:   end
11:   puts 'yield の後の文だよ。'
12: end
13:
14: fun0(2) { |x,y|
15:   if x < y then
16:     printf("x=%d y=%d x+y=",x,y)
17:     x+y
18:   else
19:     printf("x=%d y=%d\n",x,y)
20:     retry
21:   end
22:  }

実行結果
[ashida@cactus iterator]$ ./test052.rb
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
x=4 y=4
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
x=4 y=4
x=0 y=4 x+y=4
x=1 y=4 x+y=5
x=2 y=4 x+y=6
x=3 y=4 x+y=7
x=4 y=4

(以下無限に続く Ctrl+C で止めよう!)

今度もやはり無限ループになりますが,retry の場合には x,y の値が最初から繰り返されていることに注意して下さい!

■ Enumerable モジュール

モジュールの説明はまだしていませんが,とりあえずライブラリーのようなものだと思っていて下さい。

Enumerable モジュールでは each を使って様々な繰り返しのイテレーターを定義しています。 これらのイテレーターは Enumerable モジュールをインクルードすることで利用できるようになります。

Array , Hash , Dir , IO , Range , String , Struct などのクラスが Enumerable モジュールをインクルードしているので, これらのクラスでは以下の Enumerable モジュールのイテレーターを使用できるらしいです。

Enumerable モジュールのメソッド
イテレーター 意味
a.collect { |x| 文 } a の要素を順次 x に代入してブロックの文を実行した結果からなる配列を返す。
a.map { |x| 文 } a.collect と同じ(?)
a.each_with_index { |x,i| 文 } a の要素を x ,インデックスを i に代入してブロックの文を実行する。
a.find { |x| 文 } a の要素を順次 x に代入してブロックの文を実行し,文が真になった最初の要素を返す。
a.detect { |x| 文 } a.find と同じ(?)
a.find_all { |x| 文 } a の要素を順次 x に代入してブロックの文を実行し, 文が真になった要素の配列を返す。
a.select { |x| 文 } a.find_all と同じ(?)
a.grep(pattern) 正規表現 pattern に合致する要素の配列を返す。
a.grep(pattern) { |x| 文 } 正規表現 pattern に合致する要素に対して文を評価する。
a.include?(x) x と等しい要素を含むときに真を返す。
a.member?(x) include?(x) と同じ(?)
a.index(x) x と等しい要素のインデックスを返す。インデックスは 0 から始まる。 等しい要素がないときは nil を返す。
a.max 最大の要素を返す。
a.max { |x,y| 文 } ブロックを評価した値で最大となる要素を返す。 文は要素 x と y の大きさの関係を x > y で正 ,x==y で 0 ,x < y で負を返す式を書く。
a.min 最小の要素を返す。
a.min { |x,y| 文 } ブロックを評価した値で最大となる要素を返す。 文は要素 x と y の大きさの関係を x > y で正 ,x==y で 0 ,x < y で負を返す式を書く。
a.reject { |x| 文 } 各要素に対して文を評価し,真となる要素を除いた配列を返す。
a.sort 要素をソートした配列を返す。
a.sort { |x,y| 文 } ブロックの文を評価した値で要素をソートした配列を返す。 文は要素 x と y の大きさの関係を x > y で正 ,x==y で 0 ,x < y で負を返す式を書く。
a.to_a 全ての要素を含む配列を返す。


参考文献

私が買った Ruby 関係の本のリストです。(こんなに買ったのか ....。)

「オブジェクト指向スクリプト言語 Ruby」まつもとゆきひろ/石塚圭樹 共著,アスキー出版局,税別4000円
Ruby の作者まつもとゆきひろさん自らが書いた Ruby の解説書。一人最低1冊は購入するべし!
「Ruby プログラミング入門」原信一郎著,まつもとゆきひろ監修,オーム社,税別2800円
Ruby のマニュアルとして,私のような初心者プログラマー必携。
「Ruby ライブラリ編」金光雅夫編,アスキー,税別1600円
標準クラス,組み込み関数,添付ライブラリのマニュアル。プログラマー必携。
「プログラミング Ruby」デビット・トーマス+アンドリュー・ハント著,田和勝訳 まつもとゆきひろ監修, (株)ピアソン・エデュケーション,税別4800円
分厚くて高いけれど名著かもしれない。初心者から中級者にお薦め。
「Ruby デスクトップリファレンス」まつもとゆきひろ著,発行所オライリー・ジャパン,発売元オーム社,税別1000円
Ruby の文法のハンドブックです。薄い本なので1冊常備しておくと便利。
「Ruby/GTK プログラミング入門」三並慶佐著,技術評論社,税別2680円
Ruby で GTK+ を利用してグラフィカルなアプリケーションを作成する方法の解説書です。
「Ruby によるCGIプログラミング」三並慶佐著,株式会社SCC,税別2200円
「Ruby Gem Box ツール利用でここまでできる」RubyUnit 編著,オーム社開発局,税別2200円
う〜ん。BigFloat,Namazu,FXRuby,GTK,SDL,RWiki などの紹介? 解説?
「Ruby を256倍使うための本 極道(きわめみち)編」助田雅紀著,アスキー,税別1200円
「Ruby を256倍使うための本 無道編」青木峰郎著,アスキー,税別1200円
「Ruby を256倍使うための本 魔道編」るびきち著,アスキー,税別1200円
Ruby の本というより,RD の解説書です。
「Ruby を256倍使うための本 網道編」ただただし/arton共著,アスキー,税別1200円
Ruby で CGI を作ったり,eRuby で WEB ページを作る話。
「Ruby を256倍使うための本 邪道編」arton著,アスキー,税別1200円
Windows 上で Ruby を使う話です。私には関係ないのに,ついつい買ってしまった。

参考 URL

オブジェクト指向スクリプト言語 Ruby
Ruby の公式サイトです。 最新版 Ruby のダウンロード,インストールガイド,リファレンスマニュアル,FAQ, Ruby アプリケーションやライブラリーなどなど,お宝のてんこ盛り!
日本 RUby の会 Wiki
Ruby あれこれ
渡辺哲也さんのサイト。Ruby のスクリプトをたくさん公開しています。 Ruby プログラミングの参考になる。
Ruby 大衆化計画
るびきち さんのサイトです。



このページの先頭へ