まえがき
3章 制御構造/メソッド/組み込み関数
3-1 演算子
3-1-2 メソッドとして定義されている演算子
| ^ & <=> == === =~ > >= < <= << >> +@ -@
+ - * / % ** ~ [] []= ` ! != !~
演算子メソッドの独自定義
「+」演算子のメソッドを引き算として定義してみる
class MyNumber
def initialize(val)
@val = val
end
def +(other)
@val - other
end
end
val = MyNumber.new(3)
puts val + 3 # 0
3-2 基本的な制御構造
3-2-1 条件分岐
case文はJavaより柔軟性が高い
case文で正規表現を使ったパターン
stone = 'sardonyx'
case stone
when /ruby/
puts '7月'
when /peridot|sardonyx/
puts '8月'
else
puts 'よくわかりません'
end
case文は最後に評価した値を返す
detected =
case stone
when /ruby/
'7月'
when /peridot|sardonyx/
'8月'
else
'よくわかりません'
end
puts detected
case文はwhenの値をレシーバーとして「===」メソッドで比較している
class MyString
def initialize(val)
@val = val
end
def ===(other)
@val.upcase == other.upcase
end
end
a = MyString.new('A')
b = MyString.new('B')
c = MyString.new('C')
case 'a'
when a
puts 'Aでした'
when b
puts 'Bでした'
when c
puts 'Cでした'
else
puts 'どれでもありませんでした'
end
3-2-3 ジャンプ構文
next (Javaでいうcontinue)
ループの中でnextを呼ぶと次の繰り返しに移る
languages = %w(Prel Python Ruby Smalltalk JavaScript)
languages.each do |language|
puts language
next unless language == 'Ruby'
puts 'I found Ruby!!!'
end
redo
ループの中でredoを呼ぶともう一度その処理をやり直す
languages = %w(Prel Python Ruby Smalltalk JavaScript)
languages.each do |language|
puts language
if language == 'Ruby'
puts 'I found Ruby!!!'
redo if rand(2) == 1 # 無限ループになるのをさける
end
end
3-3 例外処理
3-3-2 例外を制御する
raiseで投げる、rescueで受け取る
raiseで投げる、rescueで受け取る
begin
raise 'error!'
rescue => e
puts e.class # RuntimeError
puts e.message
puts e.backtrace
end
投げる例外を指定する
投げる例外を指定する
begin
raise StandardError, 'error!'
rescue => e
puts e.class
puts e.message
puts e.backtrace
end
受け取る例外を指定する
受け取る例外を指定する
5.times do |n|
begin
if n%3 == 0
raise LoadError
elsif n%3 == 1
raise NameError
else
raise ArgumentError
end
rescue LoadError => e
puts 'rescue LoadError'
rescue ArgumentError, NameError => e
puts "rescue #{e.class}"
end
end
後置rescue
後置rescue
result = (1 / 0 rescue false)
puts result # false
ensure (Javaでいうfinally)
例外発生に関わらず必ず実行したい処理はensure節に書く
begin
file = File.open('test.txt')
file.each_line do |l|
puts l
end
rescue => e
puts e.class
puts e.message
puts e.backtrace
ensure
file.close if file
end
else
例外発生しなかった時だけ実行する処理はelse節に書く
begin
file = File.open('test.txt')
file.each_line do |l|
puts l
end
rescue => e
puts e.class
puts e.message
puts e.backtrace
else
puts 'ファイルが開けました!!'
ensure
file.close if file
end
retry
rescue句の中でretryを呼び出すとbegin節の処理をやり直す
begin
failed ||= 0
puts 'trying...'
raise
rescue
failed += 1
retry if failed < 5
end
3-5 メソッド定義と呼び出し
3-5-1 メソッド呼び出しと括弧
メソッド呼び出しの括弧は省略可能
メソッド呼び出しの括弧は省略可能
puts 'hello'
puts('hello')
括弧を付けるかどうかの判断基準(の一例)
- 戻り値を得るための式として記述する場合は括弧を付ける
- 手続きを実行する場合は括弧を省略する
3-5-2 メソッド呼び出しとローカル変数
レシーバと括弧、引数のないメソッドと変数は変数が優先される
レシーバと括弧、引数のないメソッドと変数は変数が優先される
sweet = 'honey'
def sweet
'salt'
end
puts sweet # honey
puts sweet() # salt
3-5-3 メソッドと定数
大文字で始まるメソッドをレシーバ・引数なしで呼び出そうとするとエラーになる
大文字で始まるメソッドをレシーバ・引数なしで呼び出そうとするとエラーになる
def Hello
puts 'Hello, My method!!'
end
begin
Hello
rescue => e
puts "#{e.class}, #{e.message}" # NameError, uninitialized constant Hello
end
3-5-5 省略可能な仮引数
メソッドの引数には任意の式を与えることができる
メソッドの引数には任意の式を与えることができる
def greet(name, message = 'Hi')
puts "#{message}, #{name}"
end
greet 'kamatama'
greet 'kamatama', 'Hello!!!'
3-5-6 可変長引数
引数の先頭に*を付けることで、任意の数の引数を配列として受け取ることができる
引数の先頭に*を付けることで、任意の数の引数を配列として受け取ることができる
def greet_messages(name, *messages)
messages.each do |message|
puts "#{message}, #{name}"
end
end
greet_messages 'kamatama', 'Hi!!', 'Hello!!'
3-5-7 配列の展開
実引数の頭に*を付けると配列を複数の引数として渡すことができる
実引数の頭に*を付けると配列を複数の引数として渡すことができる
def greet_twice(name, first_message, second_message)
puts "#{first_message}, #{name}"
puts "#{second_message}, #{name}"
end
greetings = %w(Hello Hola)
greet_twice 'kamatama', *greetings
# 引数に指定しない数を渡すとArgumentErrorになる
begin
greetings = %w(Hello Hola Hey)
greet_twice 'kamatama', *greetings
rescue => e
puts "#{e.class}, #{e.message}"
end
3-5-8 ブロック
メソッドはブロック(一連の処理を含んだオブジェクト)を受け取ることができる。
yieldをメソッドの中で呼び出すと、受け取ったブロックを実行する
def block_sample
puts 'stand up'
yield
puts 'sit down'
end
block_sample do
puts 'walk'
end
ブロックは最後に評価された式を返り値として返すことができる
ブロックは最後に評価された式を返り値として返すことができる
def display_value
puts yield
end
display_value do
4423
end
仮引数の先頭に&を付けることでメソッドにブロックを渡すことができる
yieldとの違いは仮引数はオブジェクト(Procクラス)なので、他のメソッドにさらに引数として渡すことができる
仮引数の先頭に&を付けることでメソッドにブロックを渡すことができる
def block_sample_with_block_arg(&block)
puts 'stand up'
block.call if block
puts 'sit down'
end
block_sample_with_block_arg do
puts 'walk'
end
ブロックの仕様用途
繰り返し処理
配列の要素を全部大文字にした新しい配列を作る
people = %w(Alice Bob Carol)
puts people.map{|person| person.upcase}.inspect # ["ALICE", "BOB", "CAROL"]
前後の処理を共通化できる場合
- ファイルのオープン/クローズ
- DBへの接続/切断
- トランザクションの開始/終了
- ロックと解放
- ...など
課題
課題1
1-1. 以下の仕様を満たすModクラスを作成し、Modクラスとwhen句を使ってFizzBuzzを完成させる
- 整数のインスタンス変数(valとする)を保持する
- 引数をvalで割った余りが0の場合のみtrueを返す「===」メソッドを持つ
課題2
2-1. 以下の仕様を満たすtimeメソッドを作り、実行してみる
- ブロックを引数に取り、ブロックの処理時間(秒)を出力する
- 例外が発生した場合も処理時間は計測できる