気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Ruby Gold対策(文法)

文法の試験範囲 (Gold試験出題数 15/50 約30% )
試験で問われるポイントについて整理していきます。

ブロック

do〜end、{}の違い(結合度のお話)

do〜endと{}では{}の方が結合度が強いという違いがある。
そのため以下の2点について気をつける必要がある。

do〜endを用いる場合は戻り値確認用のpを使ってはいけない。

p (1..10).inject(0) do | sum, i|
  sum + 1
end
#=> TypeError: 0 is not a symbol nor a string

# 上記は以下と同じだと解釈され、do〜endは無視されてしまっている
p ((1..10).inject(0))
#=> TypeError: 0 is not a symbol nor a string

#{}だとinject(0)と{}の結合度が強く、正しく解釈されるため、問題なし
p (1..10).inject(0) { | sum, i|
  sum + 1
}
#=> 10

{}の前のメソッド引数は括弧を明示する。

# {}は結合度が強いため、0の引数が{}と解釈されてしまっている
3.downto 0 {|i| puts i}
#=> SyntaxError: (irb):1: syntax error, unexpected '{', expecting end-of-input

# do〜endならエラーとならないがわかりづらいため、この場合も括弧を明示すべき
3.downto 0 do |i| puts i end
#=> 3
#=> 2
#=> 1
#=> 0

do〜end、{}の使い分け(要約)

{}
式の結果を使いたいとき、リソース開放させたいときに使う。

  • ブロック付きメソッドがインラインの場合
  • ブロック付きメソッドの戻り値を利用する場合
  • ブロック付きメソッドからさらにメソッドチェーンする場合
  • リソース管理のためにブロックを使う場合

do end

  • 上記以外の場合

do〜end、{}の使い分け(詳細)

{}:ブロック付きメソッドがインラインの場合

[1, 2, 3].each {|e| puts e}  

{}:ブロック付きメソッドの戻り値を利用する場合

cubic = [1, 2, 3].map {|e| e ** 3}

{}:ブロック付きメソッドからさらにメソッドチェーンする場合

(1..10).select {|e| e.even?}.map {|e| e ** 3}

{}:リソース管理のためにブロックを使う場合
ブロックを抜け出す時にブロック引数のオブジェクトが自動的に解放される。よってcloseが不要

open("foo.txt") {|f|
  puts f.read
}

do end:上記以外の場合

[1, 2, 3].each do |e|
  puts e
end

こちらの内容を転記。私もこのルールで今後、書いていきます。
Rubyのブロック構文の書き分け(do end,{}) - ぬいぐるみライフ(仮)

例外処理

rescueにおける引数省略時のエラー捕捉

StandardErrorを継承したエラーは捕捉される

class MyError1 < StandardError; end

begin
  raise MyError1
rescue => e
  puts "StandardError!!"
end
puts "End"

#=> StandardError!!
#=> End

Exceptionを継承したエラーは捕捉されない

class MyError2 < Exception; end

begin
  raise MyError2
rescue => e
  puts "Exception!!"
end
puts "End"

#=> End

StandardErrorを継承する例外はアプリケーションエラーの位置付け
Exceptionを継承する例外(StandardErrorは除く。Interrupt 例外など)は捕捉して 継続しないようなエラーが定義されている。よって引数省略時に捕捉するエラーはStandardError。納得した。

例外の階層

  • Exception
    • fatal
    • NoMemoryError
    • ScriptError
      • NotImplementedError
      • LoadError
      • SyntaxError
    • SecurityError
    • SignalException
      • Interrupt
    • StandardError
      • ArgumentError

    • SystemExit
    • SystemStackError

StandardError以外は即処理が停止するような例外ばかり。

exit

exitはSystemExit例外を発生させる。resucueしないと処理が終了する

begin
  exit
rescue SystemExit
  puts "SystemExit"
end
puts "End"

SystemExit
End

後置rescueの動作

この場合は補足する例外の指定はできない。StanderdErrorしか補足できない

# 通常の例外の書き方
begin
  @user.name
rescue
  "Unkown"
end

# 後置の例外の書き方
@user.name rescue "Unkown"

大域脱出

breakではできない、2重ループから一気に抜ける方法。

catch :label do
  0.upto(3) do |x|
    0.upto(3) do |y|
      puts "x=#{x}, y=#{y}"
      throw :label if y == 1
    end
  end
end

x=0, y=0
x=0, y=1

どんなに深くても「throw ラベル名」でcatch内から一気に脱出できる。
いわゆるgo to文みたいなもの

参考URL

若手エンジニア/初心者のためのRuby 2.1入門(9):Rubyの例外とその捕捉――基本のbegin〜rescue〜endからensure、else、retry、後置rescueまで (4/4) - @IT