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 を付けて,スクリプトの文字列を書きます。
文字列は ' または " で文字をはさみます。
$ ruby -e 'puts "Hellow world!" ' Hellow world! $
赤い文字で書いた部分がキーボードから打ち込んだ部分です。 puts は文字列を標準出力に出力するための Ruby のコマンドです。 print でも出力できますが,puts の場合には最後に改行コードが出力されます。 例1では Ruby が起動され,puts "Hellow world!" というスクリプトが実行されて, 標準出力に Hellow world! という文字が出力されました。
本当は puts( "Hellow world!" ) が正式な書き方だと思いますが,Ruby では ( ) を省略することができます。
Ruby では改行またはセミコロンが文の区切りとみなされます。
文がいくつかある場合にはセミコロンで区切るか,または改行してしまいます。 改行しても文字列の終わりを示す ' または " が入力されるまではスクリプトの続きとみなされます。
$ ruby -e 'x=2 ; y=3 ; p x*y ' 6 $ ruby -e "x=2 ; y=3 ; p x*y " 6 $
この例では ' を使っても " を使っても同じです。 p は引数の値(数値,文字列,その他)を標準出力に出力するコマンドです。
$ ruby -e 'x=2 > y=3 > p x*y ' 6 $
例3のように,途中で改行するとプロンプト > が表示されます。 最後に ' を入力するとスクリプトの入力が終了し,スクリプトが実行されます。
標準入力やファイルなどからテキストを読み込んで, 適当な処理をしてから標準出力に書き出すコマンド(スクリプトなど)をフィルターと呼びます。
コマンドラインで直接実行できる簡単なフィルターの例として, 入力されたテキストを大文字に変換するフィルターを次に揚げます。
$ ruby -n -e 'puts $_.upcase' testfile.txt または $ ruby -n -e 'puts $_.upcase' < testfile.txt
例4のようにオプション -n を付けると, ファイルが指定されればファイルから,ファイルが与えられなければ標準入力から一行づつ読み込んで 変数 $_ に代入されます。 例4では一行分の文字列 $_ のメソッド upcase を呼び出して, 全ての文字を大文字に変換し,コマンド puts で標準出力に書き出しています。 ( Ruby では文字列もオブジェクトです )
この処理は各行について繰り返され,行がなくなったら(ファイルの中身が無くなったら)終了します。
-n と同じようなオプションで -p というものがあります。 -p は -n と同様に一行づつ読み込んで $_ に代入し,スクリプトの最後で $_ を標準出力に出力します。
ですから次の二つのコマンドは全く同じ動作になります。
$ ruby -n -e 'puts $_' testfile.txt または $ ruby -p -e ' ' testfile.txt
ちょっとした計算をしたい時,関数電卓のように使うこともできます。
但し,Ruby では数学関数などは Math というモジュールの中で定義されているので,ちょっと面倒です。
$ ruby -n -e 'p Math::sin(Math::PI/3)' 0.8660254038 $
上の例のように sin という数学関数や円周率 PI がモジュール Math の中で定義されていることを Math:: を付加して教えてやらなければならないのです。
何度も数学関数を使う場合には include Math を最初に実行して, モジュールを読み込んでしまいます。そうすれば一々 Math:: を付けなくてもよくなります。
$ ruby -n -e 'include Math ; p sin(PI/3)' 0.8660254038 $
irb を使うと Ruby のスクリプトをインタラクティブに実行することもできます。
$ 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 にしたことに特に意味はありません。 単なる習慣です。
x="私" y="貴方" puts x + "と" + y
コマンドラインで ruby の後にプログラムファイルを指定することで実行できます。
$ ruby myprog.rb 私と貴方 $
一般的には
という形で実行します。
一々 Ruby を起動していたのではフィルターとしては不便です。 myprog.rb をコマンドのように実行できるようにしましょう。 そのためには myprog.rb の先頭行に #!/usr/bin/ruby を書き込みます。
ディストリビューションによっては /usr/bin 以外のところに ruby があるかもしれません。 どこに ruby がインストールされたのかが分からない場合にはコマンドラインで which ruby を実行してみて下さい。
#!/usr/bin/ruby x="私" y="貴方" puts x + "と" + y
myprog.rb を書き換えたら保存して,chmod で実行許可を与えます。
これでコマンドラインで ./myprog.rb と入力すれば実行できるようになりました。
$ chmod 755 myprog.rb $ ./myprog.rb 私と貴方 $
myprog.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 というメソッドを呼び出していますが, オブジェクトが新しく作成されると 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 でもない値は全て真とみなされます。
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 では
という書き方が許されるのです。この式は
と同じ結果を与えます。これらの式を
と書いた方がよいと思うか否かは個人の好みによるかも ... 。
自己代入演算子の += などは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 条件式 then 文 elsif 条件式 then 文 else 文 end
Ruby では改行はセミコロンで代用することができます。 つまり,以下のように書いても同じ意味になります。
if 条件式 ; 文 ; elsif 条件式 ; 文 ; else ; 文 ; end または if 条件式 ; 文 elsif 条件式 ; 文 else 文 end または if 条件式 then 文 elsif 条件式 then 文 else 文 end
Ruby は融通の効く言語なので,elsif や end の前のセミコロンは省いても大丈夫のようです。
if を文の後ろに置くこともできます。
文 if 条件式
この時,条件式が真の場合にのみ前に置かれた文が実行されます。 結構この書き方も便利です。
unless は if !(条件式) と同じです。ただし elsif はありません。
ちなみに,私は unless を使ったことはありません。
unless 条件式 then 文 else 文 end または unless 条件式 then 文 else 文 end
if と同様に unless を文の後ろに置くこともできます。
文 unless 条件式
case 文の一般的な形は次のようなものです。
case a
when x1,x2,x3
文1
when y1,y2,y3
文2
else
文3
end
a と x1 などの比較は == ではなく,=== で行われます。 つまり,単純に a と x1 が等しい場合だけでなく,a が x1 の範囲に入っている場合にも真になります。
プログラム 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 条件式 do 文 end または while 条件式 ; 文 end
条件式が真である間,文を実行し続けます。 do は省略されることが多いようです。
while を文の後ろに置くこともできます。
文 while 条件式
until 文の一般的な形は次のようなものです。
until 条件式 do 文 end または until 条件式 ; 文 end
条件式が偽である間,文を実行し続けます。 do は省略されることが多いようです。
until を文の後ろに置くこともできます。
文 until 条件式
while や until は条件式の真偽によって繰り返しますが, Ruby の for は範囲や配列などの要素を取り出し, その要素の数だけ実行します。
for 変数 in 配列など do 文 end
この時,配列などから取り出された要素が変数に代入されています。
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 は必要ない!) |
$ irb irb(main):001:0> Math.sin(Math::PI/3) 0.8660254038 irb(main):002:0> Math::sin(Math::PI/3) 0.8660254038
$ 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 でファイルや標準入力,出力を利用するには実に様々な方法があります。 ここでは簡単な方法をいくつか紹介しておきます。
(実は私もあまり詳しくは知らない .... 。)
Ruby でもC言語などと同じように 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 構文などで例外処理をすべきですが, 詳しくは本などで調べて下さい。
begin
f=open("testfile","r")
while line=f.gets
print line
end
f.close
rescue
print "ERROR: #$!\n"
end
open したファイルは原則として close で閉じるので, 処理が短く書ける場合にはブロックにしてしまうと close を書かなくてもブロックが終了した時に 自動的にファイルを閉じてくれます。
open("testfile","r") do |f|
while line=f.gets
print line
end
end
File クラスを利用すると,ファイルのオープンやクローズだけでなく, ファイル名を変更したり,ファイルを削除したり,あるいは属性を変更したりと, 様々なファイル操作ができます。
f=File.open("testfile","r")
while line=f.gets
print line
end
f.close
File.open("testfile","r") do |f|
while line=f.gets
print line
end
end
File.foreach("testfile") do |line|
print line
end
ARGF (または $< )はコマンドライン引数として与えられたファイルを連結して一つのファイルにしたようなものです。
while line = ARGF.gets print line end
for line in ARGF print line end
ARGF.each do |line| print line end
これらのスクリプトをコマンドラインで実行すると以下のようになります。 赤で書いた部分がキーボードから入力した部分です。
[ashida@cactus File]$ ./test06.rb testfile* これは入出力のテスト用ファイル testfile01 です。 内容に意味はありません。 これは入出力のテスト用ファイル testfile02 です。 内容に意味はありません。
ARGF はコマンドラインにファイル名が与えられないと, 自動的に標準入力から入力します。 ですから上記のスクリプトは入力をパイプラインから受け取ったり, リダイレクションを利用したりできます。
[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>
C言語ではプログラムに与えられた引数の数と内容が main 関数の引数 argc と argv に渡されますが, Ruby では組み込み変数の ARGV に渡されます。
ARGV はコマンドライン引数からなる文字列の配列です。 ですから argc に対応するコマンドライン引数の個数は ARGV.size や ARGV.length で求めることができます。
スクリプト #!/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" が入ります!
コマンドラインは以下のような書式になっていることが多いでしょう。
コマンド -一文字オプション --長いオプション文字 ファイル1 ファイル2
このコマンドラインパラメーターの中からオプションの部分を取り出すのには getopts を使います。
スクリプト
#!/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: #!/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 を呼び出すと実行時エラーになります。
ブロックを渡さない場合にも処理を継続したい場合には,例えば次のようにすればよいでしょう。
プログラム
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 で囲んだブロックでは, 識別子との結合強度が少し違うらしいです。
Ruby デスクトップリファレンスによると
a b { |x| 文 } は a( b{ |x| 文 } ) と解釈され,b{ |x| 文 }の実行結果が a( ) に渡される。
a b do |x| 文 end は a(b) do |x| 文 end と解釈され,ブロック do |x| 文 end が a( ) に渡される。
だそうです。(未確認!!)
ちなみに,私はどう解釈するのかが見ただけでは分からないような書き方は嫌いなので (一々規則を覚えていられないので), こう言う場合は積極的に ( ) を使って, どれとどれが結合しているのかが自分に分かるように書きます。
さて,ブロックで処理を渡すというのは私にはとても新鮮で,面白いのですが, 同じ処理をいくつかの関数やメソッドに渡したり, 受け取ったブロックをそのまま別のメソッドに渡したい時などに困ります。
つまり,このままではブロックの使い回しが効かないのです。
こういう場合にはブロックを手続きオブジェクトにするとよいようです。
プログラム
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 でしょうか。
[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 の違いが分かりませんね。
実際に使ってみましょう。
プログラム
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 に変えてみます。
プログラム
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 にしてみます。
プログラム
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 を試してみましょう。
プログラム
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 モジュールでは each を使って様々な繰り返しのイテレーターを定義しています。 これらのイテレーターは Enumerable モジュールをインクルードすることで利用できるようになります。
Array , Hash , Dir , IO , Range , String , Struct などのクラスが 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 関係の本のリストです。(こんなに買ったのか ....。)