プログラミング初心者のRubyゴールド勉強記録（文法）


# Rationalクラス
```irb
irb(main):002:0* 4/5 # 0になる
=> 0
irb(main):003:0> 4.0/5
=> 0.8
irb(main):004:0> 4/5r #分数で表示される
=> (4/5)
irb(main):005:0> (4/5r).to_f #小数点で表示される
=> 0.8
irb(main):006:0> 4/5.0
=> 0.8
```

# 多重代入と可変長引数
可変長引数は、以下3つを注意する

- デフォルト値は使えない
- 引数は配列として扱える
- 一つのメソッドに一つしか使えない

```irb
# 多重代入
irb(main):003:0* a,b,c = 1,2,3
=> [1, 2, 3]
irb(main):004:0> p a
1
=> 1
irb(main):005:0> p b
2
=> 2
irb(main):006:0> p c
3
=> 3

## 返り値に複数
irb(main):010:0* def foo
irb(main):011:1>   return 1,2,3
irb(main):012:1> end
=> :foo
irb(main):013:0> a,b,c = foo
=> [1, 2, 3]
irb(main):014:0> p a
1
=> 1
irb(main):015:0> p b
2
=> 2
irb(main):016:0> p c
3
=> 3

## 配列
irb(main):020:0* a,b,c = [1,2,3]
=> [1, 2, 3]

irb(main):026:0> (a,b),c = [1,2],3
=> [[1, 2], 3]

## 値の個数が足りない
irb(main):031:0* a,b,c = 1,2
=> [1, 2]
irb(main):032:0> p c
nil
=> nil

## 一つの変数に複数の値を代入
irb(main):033:0> a = 1,2
=> [1, 2]
irb(main):034:0> p a
[1, 2]
=> [1, 2]

## 最後の変数に余った値を代入
irb(main):037:0> a, *b = [1,2,3]
=> [1, 2, 3]
irb(main):038:0> p a
1
=> 1
irb(main):039:0> p b
[2, 3]
=> [2, 3] # 配列で返ってくる

# 可変長引数
irb(main):040:0> def foo a, *b
irb(main):041:1>   b
irb(main):042:1> end
=> :foo
irb(main):043:0> foo(1,2,3)
=> [2, 3] # 配列が返ってくる

## デフォルト値は使えない
irb(main):030:0* def hoge(*b=9)
irb(main):031:1> p b
irb(main):032:1> end
SyntaxError: (irb):30: syntax error, unexpected '=', expecting ')'

## 一つのメソッドに一つ
irb(main):038:0* def hoge(*a, *b)
irb(main):039:1> p a
irb(main):040:1> p b
irb(main):041:1> end
SyntaxError: (irb):38: syntax error, unexpected *
def hoge(*a, *b)
              ^
(irb):41: syntax error, unexpected keyword_end, expecting end-of-input

## 引数展開
irb(main):052:0> def foo1 a, *b
irb(main):053:1>   p *b
irb(main):054:1> end
=> :foo1
irb(main):055:0> foo1(1,2,3)
2
3
=> [2, 3]

irb(main):056:0> def foo1 a, *b
irb(main):057:1>   foo2(*b)
irb(main):058:1> end
=> :foo1
irb(main):048:0> def foo2 c, *d # *bの[2,3]が展開されて渡される
irb(main):049:1>   d
irb(main):050:1> end
=> :foo2

irb(main):060:0* foo1(1,2,3)
=> [3]
```

# 例外

- `rescue`だけ書くと`StandardError`から派生する全ての例外が対象となる
- `rescue`は複数指定が可能だが、最初にマッチしたものしか実行されない
- $! ... 同じスレッドとブロックで発生した最後の例外を組み込み変数`$!`として参照できる

```irb
irb(main):007:0* class Err1 < StandardError; end
=> nil
irb(main):008:0> class Err2 < Err1; end
=> nil
irb(main):009:0> begin
irb(main):010:1*   raise Err2
irb(main):011:1> rescue => e # こっちが先に書かれているので対象になる
irb(main):012:1>   puts "StandardError"
irb(main):013:1> rescue Err2 => ex # この例外処理は実行されない
irb(main):014:1>   puts ex.class
irb(main):015:1> end
StandardError
=> nil
```

## 例外クラスの階層
- Exception
	- ScriptError
		- SyntaxError(文法エラーがあった場合)
	- SignalException(補足していないシグナルを受けた場合)
	- **StandardError**
		- ArgumentError(引数の数が合わない場合や値が正しくない場合)
		- RuntimeError(特定の例外クラスには該当しないエラーが発生した場合や例外クラスを省略したraiseの呼び出し)
		- NameError(未定義のローカル変数や定数を参照した場合)
			- NoMethodError(未定義のメソッドを呼び出した場合)
		- ZeroDivisionError(整数に対し整数の0で除算を行った場合)

## 例外の再発生
```irb
irb(main):027:0* begin
irb(main):028:1*   1/0
irb(main):029:1> rescue ZeroDivisionError
irb(main):030:1>   p $!.class
irb(main):031:1>   raise
irb(main):032:1> end
ZeroDivisionError
ZeroDivisionError: divided by 0 # 最後に発生した例外を再度発生させてる
```

## retry
```irb
irb(main):037:0> begin
irb(main):038:1*   b = 1 / a
irb(main):039:1> rescue ZeroDivisionError
irb(main):040:1>   a += 1
irb(main):041:1>   retry # 再度begin節が実行される
irb(main):042:1> ensure # ensure節は一回だけ実行される
irb(main):043:1*   p b
irb(main):044:1> end
1
=> 1
```

## 帯域脱出
```irb
irb(main):049:0* def foo
irb(main):050:1>   throw :exit # throw = raise例外を発生させラベルと同じ名称のcatchに処理が映る。また、値を引数として渡すことができる
irb(main):051:1> end
=> :foo
irb(main):052:0> catch(:exit) {
irb(main):053:1*   foo
irb(main):054:1>   p 1
irb(main):055:1> }
=> nil
irb(main):056:0> p 2
2
```

# ブロック {}

- `ブロック{...}` の場合は()の省略ができない
- `do ... end` の場合は()の省略ができる

```irb
irb(main):002:0> 1.upto 5 do |x| puts x end
1
2
3
4
5
=> 1
irb(main):003:0> 1.upto 5 {|x| puts x } # {...}の場合は引数の()を省略できない
SyntaxError
irb(main):004:0> 1.upto(5) {|x| puts x }
1
2
3
4
5
=> 1
```

## ブロック付きメソッド

呼び出し元のブロックを実行するには

- `yield`で呼び出す
- &が付いた変数を定義するとProcオブジェクトとなるので、`Proc#call`で呼び出す

```ruby
# yieldを使う場合
def tag(name)
  puts "<#{name}>#{yield}</#{name}>"
end

tag(:p) {"Hello World"}
# 実行結果：<p>Hello World</p>

# Proc#callを使う場合
def tag(name, &block)
  puts "<#{name}>#{block.call}</#{name}>"
  p block.class #Procが表示される
end

tag(:p) {"Hello World"}
# 実行結果：<p>Hello World</p>
```