Rubyでは(Cなどとは異なり)制御構造は式であって、何らかの値を返すものが あります(返さないものもあります。値を返さない式を代入式の右辺に置くと parse error になります)。
RubyはC言語やPerlから引き継いだ制御構造を持ちますが、 その他にブロック付きメソッド呼び出しという 制御構造の抽象化を援助する機能があります。ブロック付きメソッド呼び出しは 繰り返しを始めとする制御構造をクラス設計者が定義する事が出来るものです.
例:
if age >= 12 then print "adult fee\n" else print "child fee\n" end gender = if foo.gender == "male" then "male" else "female" end
文法:
if 式 [then] 式 ... [elsif 式 [then] 式 ... ] ... [else 式 ... ] end
条件式を評価した結果が真である時、then
以下の式を評価します。
if
の条件式が偽であれば elsif
の条件を評価します。
elsif
節は複数指定でき、全ての if
および elsif
の条件式が偽であったとき else
節があればその式が評価されます。
if
式は、条件が成立した節(あるいは else
節)の最後に評価し
た式の結果を返します。else
節がなくいずれの条件も成り立たなけれ
ば nil
を返します。
Ruby では false
または nil
だけが偽で、それ以外は 0 や空文
字列も含め全て真です。
Ruby では if を繋げるのは elsif
であり、else if
(C のように)でも elif
(sh のように)でもないことに注意してください。
また if
の条件式が正規表現のリテラルである時には特別に
$_ =~ リテラル
であるかのように評価されます。
例:
print "debug\n" if $DEBUG
文法:
式 if 式
右辺の条件が成立する時に、左辺の式を評価してその結果を返します。
条件が成立しなければ nil
を返します。
例:
unless baby? feed_meat else feed_milk end
文法:
unless 式 [then] 式 ... [else 式 ... ] end
unless
は if
と反対で、条件式が偽の時に then
以下の
式を評価します。unless
式にelsif
を指定することはできませ
ん。
例:
print "stop\n" unless valid(passwd)
文法:
式 unless 式
右辺の条件が成立しない時に、左辺の式を評価してその結果を返します。
条件が成立しなければ nil
を返します。
例:
case $age when 0 .. 2 "baby" when 3 .. 6 "little child" when 7 .. 12 "child" when 13 .. 18 "youth" else "adult" end
文法:
case [式] [when 式 [, 式] ...[, `*' 式] [then] 式..].. [when `*' 式 [then] 式..].. [else 式..] end
case
は一つの式に対する一致判定による分岐を行います。when
節で指定された値と最初の式を評価した結果とを演算子 ===
を用いて
比較して、一致する場合には when
節の本体を評価します。
つまり、
case 式0 when 式1, 式2 stmt1 when 式3, 式4 stmt2 else stmt3 end
は以下の if
式とほぼ等価です。
_tmp = 式0 if 式1 === _tmp or 式2 === _tmp stmt1 elsif 式3 === _tmp or 式4 === _tmp stmt2 else stmt3 end
when 節の評価順序はこの上記 if 文に書き直した場合と同じです。つまり上 から順に(そして左から順に) === が評価されます。また「式0」は1回だけ評 価されます。
when 節の最後の式に `*' を前置すればその式は配列展開されます。
ary = [1,2,3] case v when *ary .. end
は、
case v when 1, 2, 3 .. end
と等価です。
===
がどのような条件で真になるかは、各クラスの ===
メソッ
ドの動作についてのドキュメントを参照して下さい。
case
の「式」を省略した場合、when
の条件式が偽でない最初の
式を評価します。
foo = false bar = true quu = false case when foo then puts 'foo is true' when bar then puts 'bar is true' when quu then puts 'quu is true' end # "bar is true"と表示される
case
は、条件が成立した when
節、(あるいは else
節)
の最後に評価した式の結果を返します。いずれの条件も成り立たなければ
nil
を返します。
例:
ary = [0,2,4,8,16,32,64,128,256,512,1024] i = 0 while i < ary.length print ary[i] i += 1 end
文法:
while 式 [do] ... end
式を評価した値が真の間、本体を繰り返し実行します。
while
は値を返しません。
ruby 1.7 feature: while
は nil
を返します。また、引
数を伴った break
により while
式の戻り値をその値にすること
もできます。
例:
sleep(60) while io_not_ready?
文法:
式 while 式
右辺の式を評価した値が真の間、左辺を繰り返し実行します。
左辺の式が rescue
節も ensure
節もない begin
である場合には、
それを最初に一回評価してから繰り返します。
ruby 1.7 feature: version 1.7 では、rescue/ensure 節があっても、 同様に解釈されます。
例:
send_request(data) begin res = get_response() end while res == 'Continue'
while
修飾した式は値を返しません。
ruby 1.7 feature: while
修飾した式は nil
を返します。
また、引数を伴った break
により while
修飾した式の戻り値を
その値にすることもできます。
例:
until f.eof? print f.gets end
文法:
until 式 [do] ... end
式を評価した値が真になるまで、本体を繰り返して実行します。
until
は、値を返しません。
ruby 1.7 feature: until
は nil
を返します。また、引
数を伴った break
により until
式の戻り値をその値にすること
もできます。
例:
print(f.gets) until f.eof?
文法:
式 until 式
右辺の式を評価した値が真になるまで、左辺を繰り返して実行しま す。
左辺の式が rescue
節も ensure
節もない begin
である場合には、
それを最初に一回評価してから繰り返します。
ruby 1.7 feature: version 1.7 では、rescue/ensure 節があっても、 同様に解釈されます
例:
send_request(data) begin res = get_response() end until res == 'OK'
until
修飾した式は値を返しません。
ruby 1.7 feature: until
修飾した式は nil
を返します。
また、引数を伴った break
により until
修飾した式の戻り値を
その値にすることもできます。
例:
for i in [1, 2, 3] print i*2, "\n" end
文法:
for lhs ... in 式 [do] 式.. end
式を評価した結果のオブジェクトの各要素に対して本体を繰り返し て実行します。これは以下の式とほぼ等価です。
(式).each `{' `|' lhs..`|' 式.. `}'
「ほぼ」というのは、do ... end
または{ }
による
ブロックは新しいローカル変数の有効範囲を導入するのに対し、
for
文はローカル変数のスコープに影響を及ぼさない点が
異なるからです。
for
は、in
に指定したオブジェクトの each
メソッドの戻り値を返します。
複数のループ変数指定は以下のような場合に使用します。
for i,j in [[1,2], [3,4], [5,6]] p [i,j] end => [1, 2] [3, 4] [5, 6]
for や each で配列要素を複数個ずつ取得しながらループすることは できません。
for i,j in [1, 2, 3] p [i,j] end => [1, nil] [2, nil] [3, nil] # [1,2] [3,nil] を期待するかもしれないがそうはならない
代わりにそのようなメソッド(イテレータ)を定義する必要があります。 each の例も参照してください。
class Array def each2 i = 0 while i < self.size yield self[i], self[i+1] i += 2 end end end
例:
i = 0 while i < 3 print i, "\n" break end
文法:
break break val ruby 1.7 feature
break
はもっとも内側のループを脱出します。ループとは
のいずれかを指します。C 言語と異なり、break
はループを脱出する作
用だけを持ち、case
を抜ける作用は持ちません。
break
によりループを抜けた for
やイテレータは nil
を返します。ruby 1.7 feature: ただし、引数を指定した場合はループ
の戻り値はその引数になります。
例:
# 空行を捨てるcat ARGF.each_line do |line| next if line.strip.empty? print line end
文法:
next next val ruby 1.7 feature
next
はもっとも内側のループの次の繰り返しにジャンプします。
イテレータでは、yield 呼び出し
の脱出になります。
next
により抜けた yield
式は nil
を返します。
ruby 1.7 feature: ただし、引数を指定した場合、yield
式の戻
り値はその引数になります。
例:
redo
文法:
redo
ループ条件のチェックを行なわず、現在の繰り返しをやり直します。
例:
retry
文法:
retry
イテレータ、ブロックまたはfor文の中で使われた場合には、そのイテレータ を起動しなおします。イテレータの引数も再評価されます。
for i in 1..5 retry if some_condition # i == 1 からやり直し end # ユーザ定義の "untilループ" def UNTIL(cond) return if cond yield retry end
retry
は、ループ以外に後述の rescue
節でも使えます。この場
合は、begin
式を始めからもう一度実行します。retry
を使うこ
とである処理が成功するまで処理を繰り返すようなループを作ることができます。
begin do_something # exception raised rescue # handles error retry # restart from beginning end
rescue
節やイテレータブロック、for 文以外で retry
が用い
られた場合には例外 LocalJumpError が発生します。
*1
イテレータ呼び出しにおける break
, next
, redo
,
retry
をまとめると以下のようになります。
def iter (a) : (b) yield (c) : (d) end iter { retry } -> (a) へ飛ぶ iter { redo } -> (b) へ飛ぶ iter { next } -> (c) へ飛ぶ iter { break } -> (d) へ飛ぶ
(a) は、厳密には引数評価から始まります。(b) はブロック実行の直前を指し ています(yield の引数が再評価されるわけではない)。(d) は、メソッドの終 了です。
def iter(var = p("(a)")) p " : " yield p "(c)" p " : " ensure p "(d)" end iter { p "(b)"; retry } # => (a) .. (b)(d)(a) .. (b)(d)(a) ... iter { p "(b)"; redo } # => (a) .. (b)(b)(b)(b) ... iter { p "(b)"; next } # => (a) .. (b)(c) .. (d) iter { p "(b)"; break } # => (a)..(b)(d)
例:
raise "you lose" # 例外 RuntimeError を発生させる # 以下の二つは SyntaxError を発生させる raise SyntaxError, "invalid syntax" raise SyntaxError.new("invalid syntax") raise # 最後の例外の再発生
文法:
raise raise messageまたはexception raise error_type, message raise error_type, message, traceback
例外を発生させます。第一の形式では直前の例外を再発生させます。 第二の形式では、引数が文字列であった場合、その文字列をメッセー ジとする RuntimeError 例外を発生させます。引数が例外 オブジェクトであった場合にはその例外を発生させます。第三の形式 では第一引数で指定された例外を、第二引数をメッセージとして発生さ せます。第四の形式の第三引数は $@または callerで得られる スタック情報で、例外が発生した場所を示します。
発生した例外は後述の begin
式の rescue
節で捕らえることができます。
その場合 rescue error_type => var
の形式を使えば
例外オブジェクトを得られます。このオブジェクトは組み込み
変数 $! でも得られます。また例外が
発生したソースコード上の位置は変数 $@ に格納されます。
raise は Ruby の予約語ではなく、Kernel モジュールで 定義されている関数的メソッドです。
例:
begin do_something rescue recover ensure must_to_do end
文法:
begin 式.. [rescue [error_type,..] [=> evar] [then] 式..].. [else 式..] [ensure 式..] end
本体の実行中に例外が発生した場合、rescue
節(複数指定できます)が
与えられていれば例外を捕捉できます。発生した例外と一致する
rescue
節が存在する時には rescue
節の本体が実行されます。
発生した例外は $! を使って参照することができます。また、
指定されていれば変数 evar にも $!
と同様に発生した例外が格
納されます。
begin raise "error message" rescue => evar p $! p evar end # => #<RuntimeError: error message> #<RuntimeError: error message>
例外の一致判定は例外のクラスが rescue
節で指定したクラスと同じか
またはサブクラスであるかどうか Object#kind_of? を用いて判
定されます*3。
error_type が省略された時は StandardError のサブクラスであ る全ての例外を捕捉します。Rubyの組み込み例外は(SystemExit や Interrupt のような脱出を目的としたものを除いて) StandardError のサブクラスです。
例外クラスのクラス階層については 例外クラス を参照してください。
rescue
では error_type は通常の引数と同じように評価され、
そのいずれかが一致すれば本体が実行されます。error_type を評価し
た値がクラスやモジュールでない場合には例外 TypeError が発生しま
す。
省略可能な else
節は、本体の実行によって例外が発生しなかった場合
に評価されます。
ensure
節が存在する時は begin
式を終了する直前に必ず
ensure
節の本体を評価します。
begin
式全体の評価値は、本体/rescue
節/else
節のうち
最後に評価された文の値です。また各節において文が存在しなかったときの値
はnil
です。いずれにしてもensure
節の値は無視されます。
例:
open("nonexistent file") rescue STDERR.puts "Warning: #$!"
文法:
式1 rescue 式2
式1で例外が発生したとき、式2を評価します。 以下と同じ意味です。捕捉する例外クラスを指定することはできません。 (つまり、StandardError 例外クラスのサブクラスだけしか捕捉できません)
begin 式1 rescue 式2 end
rescue修飾子を伴う式の値は例外が発生しなければ式1、例外が発生すれば式2 です。ただし、大抵の場合、優先順位の都合により式全体を括弧で囲む必要が あります。
var = open("nonexistent file") rescue false p var => nil # 値を持たない変数 var が定義されただけ var = (open("nonexistent file") rescue false) p var => false
特にメソッドの引数に渡す場合は二重に括弧が必要となります。
p(open("nonexistent file") rescue false) => parse error p((open("nonexistent file") rescue false)) => false
ruby 1.7 feature: 1.7 では、rescue の優先度が変更され、 この心配はなくなっています。
var = open("nonexistent file") rescue false p var => false p(open("nonexistent file") rescue false) => false
例:
return return 12 return 1,2,3
文法:
return [式[`,' 式 ... ]]
式の値を戻り値としてメソッドの実行を終了します。式が2つ以上
与えられた時には、それらを要素とする配列をメソッドの戻り値と
します。式が省略された場合には nil
を戻り値とします。
例:
BEGIN { ... }
文法:
BEGIN '{' 文.. '}'
初期化ルーチンを登録します。BEGIN
ブロックで指定した文は当該ファ
イルのどの文が実行されるより前に実行されます。複数のBEGIN
が指定
された場合には指定された順に実行されます。
BEGIN
ブロックはコンパイル時に登録されます。即ち一つの記述につき
ただ一回だけ登録が行われます。
if false BEGIN { p "begin" } end # => "begin"
BEGIN
ブロックは独立したローカル変数のスコープを導入するため、ロー
カル変数を外部と共有できません。ブロックの外と情報を伝達するには定数や
グローバル変数などを介する必要があります。
BEGIN { $foo, foo = true, true } p $foo # => true p foo # undefined local variable or method `foo' for main:Object (NameError)
BEGIN
はメソッド定義式中には書けません。parse error になります。
def foo BEGIN { p "begin" } end # => -:2: BEGIN in method
例:
END { ... }
文法:
END '{' 文.. '}'
「後始末」ルーチンを登録します。END
ブロックで指定した文はインタ
プリタが終了する時に実行されます。Ruby の終了時処理について詳しくは
終了処理を参照してください。
複数の END
ブロックを登録した場合は、登録したときと逆の順序で実
行されます。
END { p 1 } END { p 2 } END { p 3 } # => 3 2 1
END
ブロックは一つの記述につき最初の一回のみ有効です。たとえば以
下のようにループの中で実行しても複数の END
ブロックが登録される
わけではありません。そのような目的には at_exit を使
います。
5.times do |i| END { p i } end # => 0
END
をメソッド定義式中に書くと警告が出ます
*4。
意図的にこのようなことを行いたい場合は at_exit を使
います。
def foo END { p "end" } end p foo # => -:2: warning: END in method; use at_exit nil "end"
END
は、BEGIN
とは異なり実行時に後処理を登録します。したがっ
て、以下の例では END ブロックは実行されません。
if false END { p "end" } end
END
や at_exit で登録した後処理を取り消すこと
はできません。
END
ブロックは BEGIN
ブロックとは異なり周囲とスコープを共有し
ます。すなわちイテレータと同様のスコープを持ちます。
END
ブロックの中で発生した例外はその END
ブロックを中断し
ますが、すべての後始末ルーチンが実行されるよう、インタプリタは終了せず
にメッセージだけを出力します。
例:
END { p "FOO" } END { raise "bar"; p "BAR" } END { raise "baz"; p "BAZ" } => baz (RuntimeError) bar (RuntimeError) "FOO"
*1あるいは、突然エラーになってインタプリタが終了します。
retry #=> -:1: retry outside of rescue clause
*2あらい 2002-01-13: ensure は大域脱出を捕まえるので retry が (d)
に飛んでいるあまり良い例じゃないか
*3ruby 1.7 feature: 1.7 での例外の一致判定は
Module#=== を用いて行われます
*4ruby 1.8 feature: これは 1.8.1 から [ruby-dev:21513]