ruby文法復習用ノート

この記事は「こんな書き方もあったな」というのを簡単に __復習__ できるように作りました。そのため、実行結果が書いていなかったり、コード内で未定義の変数を使っていたりします。予めご了承ください。

間違い等ありましたら遠慮なくコメントください。

# 参考
[たのしいRuby、高橋征義、後藤裕蔵著、 まつもとゆきひろ監修、SBクリエイティブ株式会社、第6版2019年](https://www.amazon.co.jp/%E3%81%9F%E3%81%AE%E3%81%97%E3%81%84Ruby-%E7%AC%AC6%E7%89%88-%E9%AB%98%E6%A9%8B-%E5%BE%81%E7%BE%A9-ebook/dp/B07PNN3TYF/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=1671278506&sr=8-1)


# 1. 基本
- 動的型付け言語なので、型を明示的に指定はしない
- オブジェクト指向型言語なので、データをオブジェクトで表現する
- `a = 3`
- `b = "文字列"`
- nil : nullのこと
- 条件ではnilとfalseを偽、それ以外を真としている
- `do end`で囲まれている部分をブロックと言う
- 配列やハッシュに`*`を付けると、そのオブジェクトを展開することができる
- Rubyではスネーク方式で命名する
- Rubyにおけるthenは省略可能
- `do end`を`{ }`と書くこともできる
- `b=a`としたとき、`a`に破壊的な変更をすると`b`も変わる。`a.freeze`で防げる
- `a.dup`でオブジェクトをコピー

# 2. 文字列
```
"文字列" #=> 文字列
%Q{ "がエスケープされる } #=> "がエスケープされる
'特殊文字をそのままにする'
%q| 'がエスケープされる | #=> 'がエスケープされる
"\n" #=> 改行
"\\n" #=> エスケープ

```

## 2.1 メソッド
### 2.1.1 非破壊的
```
x = 3
print "あいう", x , "\n" #=> あいう3
print "あいう#{x}\n" #=> あいう3
puts # 文字列の最後で改行
p # 型に合わせて表示、特殊文字もそのまま表示 
pp # オブジェクトの構造に合わせて改行もしてくれる
printf("あいうえお") # C言語の`printf`とほぼ同じ
sprintf("あいうえお") # ただ文字列オブジェクトを作るだけ
format("あいうえお") # sprintfと同じ。%bなどで形式を指定する
s.to_sym # シンボルに変換
s.to_i # "32a".to_i => 32 "abc".to_i => 0
`コマンド` # コマンドの出力を文字列オブジェクトにする
s = "あいうえお"
s.length #=> 5
s.chars #=> ["あ","い","う","え","お"]
s.size # lengthと同じ
s.bytesize #=> 15
s[0] #=> あ
s[2,4] #=> うえお
s1 + s2 
s1 << s2 # +とおなじ
"あいう" < "あいえ" # 不等号
s.freeze # 変更不可 sに格納されているオブジェクトが変更できないだけで、s自体に新たなオブジェクトを代入することは可能。破壊的なメソッドとかは使えなくなる
# # frozen-string-literal :trueとコメントを書くことで、そのスクリプト内の全ての文字列に.freezeを付けたことになる
```
### 2.1.2 非破壊的
```
s.index("a") # 何文字目か(0始まり、左から探索) "1a1a1" => 1
s.index("a",1) # 1文字目以降から探す
s.rindex("a") # 右から探索 "1a1a1" => 3
s.include?("a") # 含むか
s.replace("a") # => "a"に置き換え
s.slice(/a/) # => マッチした最初の文字列を返す
```
### 2.1.3 `!`を付けると破壊的になる
```
s.delete("ac") # 与えられた文字列を全て削除する "abcabc" => "bb"
s.delete_prefix("a") # 先頭の文字列を削除する "abcabc" => "bcabc"
s.chop # 末尾を1文字削る "abcd" => "abc"
s.chomp # 末尾の改行を削る
s.strip # 先頭と末尾の空白を取り除く
s.upcase # "aBc" => "ABC"
s.downcase # "aBc" => "abc"
s.swapcase # "aBc" => "AbC"
s.capitalize # 先頭だけ大文字 "aBc" => "Abc"
s.tr("a","A") # 置き換え "aBc" => "ABc"
s.tr("ac","CA") # "aBc" => "CBA"
s.tr("a-e","A-E") # "aBc" => "ABC"
```

## 2.2 ヒアドキュメント (筆者の理解が足りてないので簡単に)
```
<<"EOB" # これは"あいうえお"と同じ
あいうえお
EOB

<<-"EOB" # 区切り文字の行頭の空白文字とタブ文字を無視
あいうえお
EOB

<<~"EOB" #　行頭の空白文字とタブ文字を無視
あいうえお
EOB
```

# 3. シンボル
- 文字列と似たオブジェクト
- 「シンボル」という型があると考えればよい
- 以下2つは同じもの
    - `x = :a`
    - `x = :"a"`
- `x.to_s` : 文字列に変換


# 4. 配列
- Rubyは0始まり
## 4.1 配列の生成
```
a = Array.new #=> []
a = Array.new(3) #=> [nil, nil, nil]
a = Array.new(3,0) #=> [0, 0, 0]
a = %w(I like basketball) #=> ["I", "like", "basketball"]
a = %i(i like basketball) #=> [:i, :like, :basketball]
a = "I,like,basketball".split(',') #=> ["I", "like", "basketball"]
a = "I,like,basketball".split('(,)') #=> ["I", ",",  "like", ",", "basketball"]
a = [1, 3, "hello", 2]
```
## 4.2 配列の参照
- 配列の要素数を超えたインデックスを参照した場合はエラーではなく`nil`が返る
- 負の値のインデックス`-n`を参照した場合は、配列の最後からn番目を返してくれる
```
a = ["a","b","c","d","e", "f"]
a[0] #=> "a"

# 配列の要素数を超えたインデックスを参照した場合は、最後の要素を指定したことになる
a[0..2] #=> ["a", "b", "c"]
a[-1..1] # 負の数はだめ => []
a[2,3] #=> ["c", "d", "e"]
a[-2,10] # 配列の最後から最初に戻ることは無い => ["e", "f"]
a.values_at(0,2,3) #=> ["a", "c", "d"]

a[0] = 12 # => [12, "b", "c", "d", "e", "f"]
a[1..2] = [4,5,6,7,8] #=> ["a", 4, 5, 6, 7, 8, "d", "e", "f"]
a[2,3] = [4,5,6,7,8] #=> ["a", "b", 4, 5, 6, 7, 8, "f"]
a[2,0] = [4,5,6,7,8] #=> ["a", "b", 4, 5, 6, 7, 8, "c", "d", "e", "f"]

a.each do |i|
  puts i
end

a.each_with_index do |value, index|
  pp [value,index] # indexが何番目か
end

```

## 4.3 メソッド
||先頭要素を|末尾要素を|
|---|---|---|
加える(破壊的)|unshift |push
取り出す(破壊的)|shift|pop
参照する|first|last

### 4.3.1 破壊的メソッド
```
a.unshift(3) # ["a","b","c"] => [3,"a","b","c"]
a.push(3) # ["a","b","c"] => ["a","b","c",3]
a << 3 # pushと同じ
a.shift #=> "a" ["a","b","c"] => ["b","c"]
a.shift(2) #=> ["a","b"] ["a","b","c"] => ["c"]
a.pop #=> "c" ["a","b","c"] => ["a","b"]
a.concat(b) # 配列の結合 +=と同じ
a.delete("a") # ["a","b","c"] => ["b","c"]
a.delete_at(1) # ["a","b","c"] => ["a","c"]
a.delete_if { |i| i == "a" } # ["a","b","c"] => ["b","c"]
a.fill("d") # 置き換え ["a","b","c"] => ["d","d","d"]
a.fill("d",2) # ["a","b","c"] => ["a","b","d"]
a.fill("x",1,2) # ["a","b","c","d","e","f"] => ["a","x","x","d","e","f"]
a.fill("x",3..4) # ["a","b","c","d","e","f"] => ["a","b","c","x","x","f"]
```

### 4.3.2 非破壊的メソッド
```
a = ["a","b","c","d","e","f"]
b = ["d","e","f","g","h","i",]
a.size #=> 6
a & b # 積集合 ["d", "e", "f"]
a | b # 和集合 "a", "b", "c", "d", "e", "f", "g", "h", "i"]
a + b # "|"と似ているが、重複を許す ["a", "b", "c", "d", "e", "f", "d", "e", "f", "g", "h", "i"]
a - b # ["a", "b", "c"]
a.first
a.last
a.sort_by { |i| i.size } # 昇順
a.zip(b) # [1,2][3,4,5] => [1,3],[2,4][nil,5]
[[1, 2], [3, 4]].transpose #=> [1,3],[2,4] 要素数が違うときはエラー
a.zip(b,c){ |i,j,k| puts i+j+k }
a.find{|x| x<3} # 真になる最初の要素を返す。見つからない時はnil　[2,3,4] => 2
a.detect{|x| x<3} # findと同じ


["a", "b", "c", "b"].tally  #=> {"a"=>1, "b"=>2, "c"=>1}

# 出てくる回数を数える
h = {}
[:a, :b, :c].tally(h)
[:a, :b, :d].tally(h) # h => {:a=>2, :b=>2, :c=>1, :d=>1}

a.inject {|x, y| x + y } # 第一引数に、1つ前の計算結果が入る
# [1, 2, 3, 4, 5, 6]=>21
a.inject {|x, y| x + y**2 } # [1,2,3] => 0+1**2=1 1+2**2=5 5+3**2=15 => 15

a.product(b) # [1,2,3] [4,5] =>  [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]

a.each_slice(3) do |i| # 3要素ずつ配列に渡す [1,2,3,4,5,6] => [1,2,3],[4,5,6]
  p i 
end
a.each_cons(3) do |i| # 3要素ずつ配列に渡す [1,2,3,4,5] => [1,2,3],[2,3,4],[3,4,5]
  p i 
end

a.any? do |i| # 1つでもtrueか
  i==3
end

a.partition(&:odd?) # 条件を満たすものと満たさないものに分ける [1,2,3,4] =? [[1,3],[2,4]]
```

### 4.3.3 `!`をつけると破壊的になる
```
a.compact # nilを除く
a.select { |i| i>3 } # 条件に当てはまるものだけにする
a.reject { |i| i>3 } # 条件に当てはまるものを除く
a.uniq # 重複を無くす
a.map { |i| i*2 } # 置き換え
a.collect { |i| i*2 } # mapと同じ
a.flatten # 入れ子になった配列を1つの配列にする
a.reverse # 順番を逆にする
a.sort # 昇順
a.sort { |i, j| i.size <=> j.size }
a.slice(3) # a[3] !をつけると["a", "b", "c", "b"] => ["a", "b", "c"]
a.slice(3..5) # a[3..5]
a.slice(3,2) # a[3,2]
```
### 4.3.4 初期化
```
a = Array.new(3,[0,0,0]) # 3つの要素が全て同じオブジェクトになる
a = Array.new(3) do # このようにすれば、違うオブジェクトになる
  [0,0,0]
end
a = Array.new(3) { |i| i**2 }
```

# 5. ハッシュ
`key1 == key2 && key1.eql?(key2)`のときのみ同じキーだと判断される
`eql?`は内容が同じなら、別オブジェクトでも`true`を返すメソッド
## 5.1 基本
```
h = {:basket=>5, "soccer"=>11, 9=>"baseball"}
h = {basket: 5, soccer: 11} # シンボルをキーにする場合
h = Hash[:basket, 5, :soccer, 11]
h = Hash.new
h = Hash.new(1) # 登録されてないキーを指定された時のデフォルト値
h = Hash.new do |hash, key| # デフォルト値をこのようにも定義できる
  hash[key] = key.length
end
h.fetch(:basket,1) # 登録していないキーならデフォルト値を返す

h[:basket]
h["soccer"]
h[9]
h[:basker] = 10
h.each do |key, value|
  puts key, value
end

h = {
  :sports => {:basket => 5, :baseball => 9}, 
  :music => {:solo => 1, :duo => 2}
}

# 以下4つは同じ。キーに持ってるかを判定
h.key?(:basket)
h.has_key?(:basket)
h.include?(:basket)
h.member?(:basket)

h.value?(5)
h.has_value?(5)

# キーの数
h.size
h.length

h.empty?

h.invert # キーとバリューを入れ替える
```
## 5.2 破壊的メソッド
```
h.delete(:basket)
h.delete(:no) do |key|
  puts key # キーが存在しないときの処理
end

h.delete_if do |key, value| # 1つも削除されない時は元のハッシュを返す 
  key == :soccer
end

g = h
h.clear # gもhも{}になる
```
## 5.3 !をつけると破壊的メソッド
```
h.reject do |key, value| # 1つも削除されない時はnilを返す
  key == :soccer
end

h1.merge(h2) # 2つのハッシュをくっつける
```
# 6 コメント
```
#コメント

=begin
コメント
=end
```
# 7 条件
- 偽 : `false`と`nil`
- 比較演算子 : `> < == !=`
    - `===` : 左辺がStringやInteger→`==`,左辺がRegexp→`=~`,左辺がクラスオブジェクト→右辺が左辺のインスタンスかどうかを判定してくれる
- 論理演算子 : `&& || !`
## 7.1 メソッド
- 語尾に`?`を付ける
- `empty?` : 文字列や配列が空なら`true`
- `nil?` : `nil`なら`true`
- `blank?` : `empty?`||`nil?`

## 7.2条件文
```
if a >= 10 then
  puts "aは10以上"
elsif a >= 0 then
  puts "aは0以上"
else
   puts "aは0未満"
end

puts "aは0" if a == 0

unless a >= 10 then
  puts "aは10以上ではない"
end

puts "aは0でない" unless a == 0

// case文は`===`で判定してる
case a
when 1, 2, 3 then
  puts "aは1or2or3"
when 4 then
  puts "aは2"
when 5, 6 then
  puts "aは5or6"
else
  puts "それ以外"
end

// aの所属するクラスでも分岐できる
case a
when String then
  puts "aはString"
when Numeric then
  puts "aはNumeric"
else
  puts "それ以外"
end

## 7.3 条件演算子(三項演算子)
max = a>b ? a : b

# Rubyにおいて条件文は、最後に評価した値を返す関数のようなもの
x = if a > b
  a
else
  b
end
```

# 8. 繰り返し(イテレーター)
```
while i<10
  puts i
  i = i+1
end

until i>=10
  puts i
  i = i+1
end

10.times do
  puts "hello"
end

10.times do |i| # => 0~9
  puts "#{i}回目の繰り返し"
end

0.upto(9) do |i| # 9も含む
  puts i
end

9.downto(0) do |i| # 0も含む
  puts i
end


0.step(5, 2) do |i| #=> 0,2,4,6,8
  puts i
end

object = 1..3
object = ["a", "b", "c"]

# 内部処理はeach文
for i in object do
  puts i
end

object.each do |i|
  puts i
end

loop do # 無限ループ
  puts "hello"
end
```

`break`:繰り返しを終了
`next`:次の繰り返しに移動
`redo`:もう1度同じ繰り返し

# 9. メソッド
- インスタンスメソッド
    - オブジェクトをレシーバーとするメソッド
    - `a.next`
- クラスメソッド
    - クラスをレシーバーとするメソッド
    - `クラス名.メソッド` or `クラス名::メソッド`
        - `File.open`
        - `File::open`
    - ドキュメントに書く際は`クラス名#メソッド`
- 関数的メソッド
    - レシーバーが省略されているメソッド
    - `print`
## 9.1 メソッド定義
- メソッド名を数字で始めてはいけない
- `return`を省略した場合
    - メソッドの中で最後の部分の値を返す
    - 最後の部分が`puts`などの値を返さない場合は`nil`を返す
- 実引数にハッシュを使うときは{}を省略できる

```
def f
  puts "Hello"
end

def f(a)
  puts a
end

def f(a,b,c)
  puts a,b,c
end

array = [1,2,3]
f(*array)

def f(a=3)
  puts a
end

# デフォルト値は右から指定する
def f(a, b, c=3)
  puts [a,b,c]
end

# *を付けると配列として扱ってくれる。引数の個数を指定したくない時に便利
def f(*a)
  pp a
end

f(1,2,3) #=> [1,2,3]

def f(a, *b)
  puts a,b
end

def f(a, *b, c)
  puts a,b,c
end

# キーワード付きで呼び出せる
def f(a:, b:)
  puts a
end

f(a:1, b:2)
hash = {a:1, b:2}
f(hash)

def f(a: 1)
  puts a
end

# ハッシュとして扱う。仮引数に定義していないキーワードを呼び出せる
def f(**a)
  pp a
end

f(x: 1, y: 2) #=> {:x=>1, :y=>2}

alias new_f f # エイリアスを追加
alias :new_f :f

undef f # 定義しなかったことにできる
undef :f
```

## 9.2 ブロック付きメソッド
- `yield`で、与えたブロックをそのまま実行
- `yield`の引数の数とブロックの変数の数が違う場合は、足りない部分は`nil`となる。多い部分は受け取らないだけ
- ブロックの中で`break`を呼ぶと、ブロック付き呼び出しの場所まで一機に帰ってくるため、メソッドの返り値は`nil`となる
- `break 0`などとすることで返り値を指定できる
```
def f
  yield
end

f do
  puts "hello"
end

def f
  if block_given?
    yield(3)
  end
end

f do |i|
  puts i*i
end

def f(a)
  if block_given?
    yield(a,3)
  end
end

f(2){ |i, j| puts i*j } # 2*3
f(2){ |i, j| puts i+j } # 2+3


array.each do |a|
  puts a
end

hash.each do |i, h|
  puts i
  puts h
end

file = File.open("a.txt")
file.each_line do |line|
  puts line
end
file.close

# 確実にファイルを閉じてくれる
File.open("a.txt") do |file|
  file.each_line do |line|
    puts line
  end
end

array.sort { |a, b| a.length <=> b.length } # 昇順
array.sort_by{ |i| i.length }

# 多くのイテレーター(eachのように反復処理できるやつ)はブロックが与えられないときはEnumeratorオブジェクトを返すから、collectやmapなどを続けて呼び出せる
s.each_line.collect do |line|
  line*2
end

s.each_byte.map do |byte|
  byte & 1
end

s.each_char.map do |char|
  char.next
end
```

# 10. ブロックをオブジェクトとして受け取る
```
a = Proc.new do |i|
  puts i
end

a.call(3)

# 最後の仮引数に`&`を付けると、実引数は`Proc`オブジェクトに包まれて渡される(ブロック引数)
def f(a, &b)
  puts a
  puts b.call(3)
end

f(5) do |i| #=> 5,9
  i**2
end

def g(&c)
  f(5,&c)
end

g() do |i| #=> 5,9
    i**2
end

array.each do |i; j|
  # jはブロック内だけで有効な変数。ブロックの外側と同じ名前の変数をブロック内で使いたいときとかに。
end
```

# 11. 他のファイルを取り込む
- `require "a.rb"` : カレントディレクトリ(実行ディレクトリ)からの相対パス。Gemファイルなどを呼び出すのに使う
- `requre_relative "a.rb"` : 実行ファイルからの相対パス。自分で作成したファイルなどを呼び出すのに使う
- `.rb`は省略可能


# 12. 変数

- ローカル変数 : `_local`または`local`
- グローバル変数 : `$glocal`
- インスタンス変数 : `@instance`
- クラス変数 : `@@classvariable`
- 定数 : `Constant`
    - rubyにおいて、定数を変更することができる。警告が出るだけ
    - また、定数が指すオブジェクトが変わっていなければ、オブジェクト自体に変更を加えても問題ない
```
MSG = 42
MSG += 5 #=> 警告
MSG = "a"
MSG.upcase! #=> 警告は出ない

```

# 13. 予約語
- 名前として使えない英単語

||||||||
| --- | --- | --- | --- | --- | --- | --- |
| \_\_LINE__ | \_\_ENCODING__ | \_\_FILE__ | BEGIN | END| alias | and 
| begin | break| case | class | def | defined? | do 
| else | elsif | end | ensure | false | for | if 
| in | module | next | nil | not | or | redo 
| rescue | retry | return | self | super | then | true 
| undef | unless | until | when | while | yield|
|

# 14. 多重代入
```
a, b, c = 5, 6, 7
a, b, *c = 5, 6, 7, 8, 9
a, *b, c = 5, 6, 7, 8, 9
a, b = b, a

array = [1, 2]
a, b = array
a, = array
```

# 15. クラス
## 15.1 基本
- スーパークラス:継承元のクラス
- サブクラス:継承先のクラス
- Rubyの全てのクラスは`BasicObject`クラスのサブクラス
- 通常のオブジェクトは`Object`クラスのサブクラス
- インスタンス変数
    - 同じインスタンス内なら値の参照、変更が可能
    - `@`を付ける
    - 定義する必要は無い
    - 初期化されていない場合`nil`を返す
- クラス変数
    - `@@`を付ける
    - クラスの全てのインスタンスで共通
    - `attr_accessor`などは使えない
- クラス内のメソッドでは、そのメソッドのレシーバーを`self`で呼び出せる
- クラス内のメソッド内でメソッドを呼ぶ際には、レシーバーは暗黙に`self`となる
- アクセス制限
    - `initialize`メソッドは常に`public`
    - `public`
        - インスタンスメソッドとして使えるように公開
    - `private`
        - レシーバーを省略した形でしか呼び出せなくする
        - 事実上インスタンスの外側から利用することができなくなる

    - `protected`
        - 同一のクラス、サブクラスなら、インスタンスメソッドとして使える
- 既存のクラスにメソッドを追加することもできる

```
array = Array.new
array.class # Arrayと同じ
array.instance_of?(Array) # インスタンスか
array.is_a?(Object) # そのクラスまたはサブクラスのオブジェクトか
array.class.ancestors #スーパークラスとインクルードしているモジュール => [Array, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]
array.class.superclass #=> Object

```

## 15.2 クラス定義
```
class A
  Const = 3
  @@ count = 0 # クラス変数
  def initialize(x) # コンストラクタ
    @x = x
  end


  private # これ以降がprivateになる
  
  def set_y(y)
    @y = y
  end

  public :set_y # メソッドをpublicにする
  
  def z= (z)
    @z = z
  end

  def output
    puts @x,@y,@z
  end

  public :output
end
  
  
  aa = A.new(1)
  aa.set_y(2)
  aa.z = 3
  aa.output
  A::Const

class B
  attr_reader :x # ゲッターの定義
  attr_writer :y # セッターの定義
  attr_accessor :z # アクセッサーの定義
end
```

## 15.3 クラスメソッド
```
class << A
  def f
    puts "hello"
  end
end

class A
  class << self
    def f
      puts "hello"
    end
  end
end

class A
  def self.f
    puts "hello"
  end
end

def A.f
  puts "hello"
end

A.hello
A.instance_methods

# 特定のオブジェクトのみメソッドを定義できる（特異メソッド）
str = "hello"

class << str
  def f
    puts "hello"
  end
end

str.hello
```

## 15.4 継承
- Rubyでは単純継承（単一継承）
    - 複数のスーパークラスを持つことができない
```
class MyArray < Array
  def [](i)
    ii = i % size
    # スーパークラスの同名メソッドを呼び出す
    super(ii)
  end
end
```

# 16 モジュール
## 16.1 基本
- Rubyでは名前空間と等しい
- 大文字で始める
```
module M
  def f
    puts "hello"
  end  
  modulle_function :f # モジュール関数として使えるようにする
end

# モジュール関数
M.f

include M
f
```

## 16.2 Mix-in
- 仮想的なスーパークラスとして振る舞う
- `include`
    - インスタンスメソッドを追加
    - moduleを後ろへ追加する
- `prepend`
    - インスタンスメソッドを追加
    - moduleを前を追加する
    - クラスのメソッドより前に呼ばれるので、メソッドを上書きできる
- `extend`
    - オブジェクト単位でモジュールをインクルード(特異メソッド)
    - もう一つの機能としてクラスメソッドを追加できる
```
# A → M → Object 
class A
  include M
end

aa = A.new
aa.f
A.include?(M) # クラスAがモジュールMを含むか

# M → A → Object 既存のメソッドを変更できる 
class A
  prepend M
end

srt = "hello"
str.extend(M)
str.f

class A
  extend M
end
```

# 17. 演算子

## 17.1 代入演算子
||||||||
| --- | --- | --- | --- | --- | --- | --- |
| &&= | \|\|= | ^= | &= | \|= | <<= | >>= |
| += | -= | *= | /= | %= | **= |

## 17.2 ビット演算
`~ & | ^ >> <<`
`<<` : 左にずらす

## 17.3 論理演算子
- 左側から順番に評価
- 論理式の真偽が決定すると、残りの式は評価されない
- 最後に評価された式が論理式全体の値になる

```
s = s || "hello"

# 変数にデフォルト値を与える定番の書き方
s ||= "hello"
s = array && array.first
s = array&.first # ↑の短縮系
```
## 17.4 範囲演算子
- 内部的には`succ`メソッドを呼んでいる(与えられた文字列の次の文字列を呼び出すメソッド)
```
r = Range.new(1, 5)
1..5 #=> 1..5
1.. # 1から始まる、無限に長い数列
(1..).take(5) # 最初の5要素を抜き出す => [1, 2, 3, 4, 5]
1...6 # 1~5まで
"a".."b" # "a"~"b"まで
r.to_a
```

## 17.5 演算子定義
- 再定義できない演算子
    - `:: && || .. ... ?: not = and or `
```

class A

  # 二項演算子
  # 演算子をメソッド名として、メソッドを定義する
  # 仮引数としてotherを用いることが多い
  def +(other)
    self.class.new( x + other.x, y + other.y)
  end

  # クラス名を入れてしまうと、継承したサブクラスでもAオブジェクトが返ってしまう
  def -(other)
    A.new(x - other.x, y - other.y)
  end


  # 単項演算子
  # `@`を付け絵定義する
  def +@
    dup # オブジェクトの内容をコピーしたものを返す
  end


  # 添え字メソッド
  def [](index) # a[2]とかに使う
  end

  def []=(index, val) # a[2] = 3とかに使う
  end
end
```

# 18. 例外処理
## 18.1 基本
```
# 例外クラスを指定しないと、StandardErrorとそのクラスを補足する
begin
  raise "Something went wrong!"
rescue => e
  puts $! # 最後に発生したエラーのメッセージ => "Something went wrong!"
  puts e.message # eのエラーメッセージ=> "Something went wrong!"
  puts $@ # 最後に発生したエラーのバックトレース
  puts e.backtrace # eのバックトレース
  puts e.class # エラーのクラス => RuntimeError
  retry
end


begin
  # 処理
rescue Errno::ENOENT, Errno::EACCES
  # 例外処理
end

val = "a"
x = Integer(val) rescue 0 # Integer(val)がエラーを出した時に0を返す => 0

def f
  # 処理
rescue => e
  #例外処理
end

begin
  # 処理
rescue
  # 例外処理
ensure
  # 後処理
end
```

## 18.2 例外発生
```
raise "エラー"
raise StandardError
raise StandardError, "エラー"

# `rescue`節内では、最後に発生した例外をもう一度発生させる
# `rescue`節外では、`RuntimeError`を発生
raise
```

# 19. 代表的なエラーメッセージ
- `syntax error` : 文法ミス
- `NameError` : 定義していないものが使われている
- `ArgumentError` : 引数ミス
- `TypeError` : メソッドの引数の型が違う
- `LoadError` : ライブラリを読み込めない
- `[BUG]` : Rubyや拡張ライブラリのエラー

# 20. `Numeric`

- Rubyはオーバーフローが無いらしい（いくらでも大きな値を扱える）
- 数値中の`_`は無視される `123_456`
- `Integer`と`Float`の掛け算は`Float`になる
- `Math`モジュールに色々なメソッドがある
    - `Math.sin(3.14)`
    - `Math.sqrt(2500)`
- 変換 : `to_f to_i to_r to_c`

|||
--- | ---
123 or 0d123|10進法整数
0123 or 0o123|8進法整数
0x123|16進法整数
0b0101|2進法整数
12.3 or 1.23e2|浮動小数点数
12.3r|有理数
123i|虚数


```
# 有理数(分数)
a = Rational(1,3) #=> 1/3
a.numerator # 分子 => 1 
a.denominator # 分母 => 3

# 複素数
b = Complex(1,3) #=> 1+3i
b.real #=> 1
b.imaginary #=>3

3**4 # 累乗 => 81
5.div(3) # 割り算 => 1
5.quo(3) # =>5/3
5.modulo(3) # 5%3
5.remainder(3) #=> 余り。符号は5に等しくなる
5.divmod(3) # => [1,2]

1.23.round # 少数第一位を四捨五入
1.23.round(1) # 少数第２位を四捨五入(少数第一位までにする)
1.23.ceil # 切り上げ => 2
1.23.floor # 切り捨て => 1
```

# 21. 乱数
```
# 0以上1未満のFloat型を返す
Random.rand

# 0以上3未満の整数型を返す
Random.rand(3)

# 0以上3未満のFloat型を返す
Random.rand(3.0)

# 種を与える
Random.new(1).rand # 毎回同じ値になる
```


# 22. 正規表現
## 22.1 基本
- `=~`で、何文字目で一致したかを返す
- 大文字小文字の区別無し`"abcde" =~ /bc/i`

- `-`は`[]`の中の最初か最後になることで、単なる文字の`-`として扱われる

```
r = /a/
r = Regexp.new("a")
r = Regexp.escape("a") # メタ文字をエスケープする
r = Regexp.quote("a") # escapeと同じ
r = Regexp.new("a", Regexp::IGNORECASE) # オプションを付ける
r = %r(a) # 下記4つは/がエスケープされる
r = %r<a>
r = %r|a|
r = %r{a}

"abc" =~ /a/
"abc" =~ /^a/ # 行頭 ※文字列の頭ではない
"abc" =~ /a$/ # 行末
"abc" =~ /[abc]/ # aまたはbまたはc
"abc" =~ /[A-Z]/ # A~Zのどれか
"abc" =~ /[a-z]/
"abc" =~ /[0-9]/
"abc" =~ /[A-Za-z]/
"abc" =~ /[A-Z0-9k]/ # A-Z0-9とk
"abc" =~ /[^a]/ # a以外
"abc" =~ /./ # 任意の1文字
"abc" =~ /\s/ # 空白、タブ、改行文字、改ページ文字 ※全角空白にはマッチしない
"abc" =~ /\d/ # 0-9 
"abc" =~ /\w/ # A-Za-z0-9
"abc" =~ /\A/ # 文字列の先頭 \Aabcなど
"abc" =~ /\z/ # 文字列の末尾。末尾が改行文字の場合はその1つ前にマッチ abc\zなど
"abc" =~ /\z/ # 文字列の末尾 abc\zなど
"abc" =~ /\[/ # メタ文字を普通の文字として扱う 
"abc" =~ /a*/ # 0回以上の繰り返し(一番長い部分にマッチ)
"abc" =~ /a*?/ # (一番短い部分にマッチ)
"abc" =~ /a+/ # 1回以上(一番長い部分にマッチ)
"abc" =~ /a+?/ # (一番短い部分にマッチ)
"abc" =~ /a?/ # 0または1個
"abc" =~ /a{3}/ # 3回の繰り返し 
"abc" =~ /a{3, 5}/ # 3~5回の繰り返し
"abc" =~ /(abc)+/ # abcの繰り返し
"abc" =~ /abc|def/ # abcまたはdef
"abc" =~ /a/i # 大文字小文字の違いを無視 
"abc" =~ /a/x # 正規表現内での空白、#以降を無視する。正規表現内にコメントを書きたいときなど
"abc" =~ /a/m # .が改行文字にもマッチ 
"abc" =~ /a/mi # mとi
```

## 22.2 キャプチャ(後方参照)
- `$n`でn番目の`()`内のマッチした文字列を取り出せる
```
"abc" = /(.)(.)(.)/
$1,$2,$3 #=> "a","b","c"

"abc" =~ /(.)(?:.)(.)/ # ?:をつけるとキャプチャ時に無視される
$1,$2 #=> "a","c"

"abc" =~ /b/
$` # マッチ部分より前 => "a"
$& # マッチした部分 => "b"
$' # マッチした部分より後ろ => "c"
```

### 22.3.1 破壊的メソッド
```
s.sub(/a/,"A") # 最初にマッチしたところを置き換える。ブロックを取ることもできる
s.sub(/b/) {|s| s.upcase } # /b/にマッチしたところを大文字に変える
s.gsub(/a/,"A") # マッチしたところ全てを置き換える
```

### 22.3.2 非破壊的メソッド
```
s.scan(/a/) # マッチする部分を配列の形で取得
s.scan(/(a)(b)/) # 二次元配列になる
s.scan(/a/) do |m|
  puts m
end
s.scan(/(a)(b)/) do |a,b|
  puts a,b
end 
```

# 23. IOクラス
## 23.1 基本
- 標準入力:`$stdin`からデータを受け取る
- 標準出力:`$stdout`へ出力
- 標準エラー出力:`$stderr`へ出力
- コマンドラインからの読み込み
    - i個目のコマンドライン引数を`AGRV[i]`のようにして取得できる
    - 0始まり
    - 型は文字列
```
# 標準出力の出力先をtext.txtに変える
# 標準エラー出力の出力先はコンソールのまま
ruby a.rb > test.txt
```
```
$stdin.tty? # 標準入力がコンソールかどうか
```



## 23.2 メソッド
```
# ファイルからの読み込み
file = File.open("a.txt") # デフォルトでは"r"が指定される
file = Open("a.txt")

file = File.open("a.txt","r") #  ファイルの先頭から読み込みのみ
file = File.open("a.txt","w") # 既存のファイルを0バイトに切り詰めるか新しくファイルを作成し、書き込みのみ
file = File.open("a.txt","a") # 存在しなければ新しくファイルを作成し、ファイル末尾に追記。書き込みのみ

file = File.open("a.txt","r+") # ファイルの先頭から読み書き可能 
file = File.open("a.txt","w+") # 既存のファイルを0バイトに切り詰めるか新しくファイルを作成し、読み書き可能
file = File.open("a.txt","a+") # 存在しなければ新しくファイルを作成し、ファイル末尾に追記。読み書き可能


file.close # File.openにブロックを渡すことで自動的にcloseされる
file = File.open("a.txt")
s = file.read(5) # 5バイト分読み込む。引数省略時は全て読み込む
puts s
file.close

puts File.read("a.txt")

file.closed?
File.binread("a.txt") # バイナリーモード
File.write("a.txt","hello")
File.binwrite("a.txt", "010101")

file = File.open("a.txt")
file.each_line do |line|
  p line
end
file.close

# 引数で区切られたものずつ読み込む(引数省略では"\n")
file.each("\n") do |line|
  p line
end

while line = file.gets("\n")
    puts line
end

file.each_char do |c| # 1文字ずつ
  puts c
end

while c = file.getc
  puts c
end

file.ungetc("a") # "a"をfileに戻せる(ファイル自体が変更されるわけではない)

file.each_byte do |b| # 1バイトずつ
  puts b
end

while b = file.getbyte
  puts b
end

file.ungetbyte("01") # 1バイト分の文字列をfileに戻す

file.readlines("\n") # 各行を要素とする配列の取得
file.lineno # 何行読み込んだか。変更可能な変数だが、ファイルポインタが変更されるわけではない

# 出力
file.puts 3 # 自動的にto_sが呼び出される
file.putc("abc") # 最初の1文字だけが出力
file.putc(50) # 文字コード50の文字が出力
file.write("abc") # 出力したバイト数を返す
file << "a" << "b"

# ファイルポインタ
file.pos
file.pos = 0
file.seek(5, IO::SEEK_SET) # 5バイト目の直後の位置にファイルポインタを移動
file.seek(5, IO::SEEK_CUR) # 今の位置から5先に移動
file.seek(5, IO::SEEK_END) # ファイルの末尾から5の位置に移動
file.rewind # ファイルポインタの先頭に戻す
file.truncate(5) # ファイルの長さを5に切り詰める
file.truncate(file.pos) # 現在のファイルポインタ以降を削除
file.binmode # バイナリーモードに変更
file.popen("コマンド") # fileから入力されたデータを使ってコマンドを実行する。コマンド実行時に得られる出力を返す


require "open-uri" # urlを普通のファイルのように開ける
require"stringio" # ファイルのような疑似的なオブジェクトを作れる　
```

# 24. Fileクラス
```
File.rename("a.txt","b/c.txt") # a.txtをb/c.txtにする
File.delete("a.txt")
File.unlink("a.txt") # delete
require "fileutils" # ファイルのコピーや移動等
file.stat # ファイルの情報色々
File.ctime("a.txt") # ファイル状態の最終変更時刻
File.mtime("a.txt") # ファイルの最終変更時刻
File.atime("a.txt") # ファイルの最終参照時刻
File.utime(Time.now, Time.now, "a.txt") # atime,mtimeを変更
File.exsist?("a.txt") # 存在するか
File.file?("a.txt") # ファイルか
File.directory?("a.txt") # ディレクトリか
File.readable?("a.txt")
File.writable?("a.txt")
File.size("a.txt")
File.size?("a.txt") # aのサイズが0より大きいか
File.zero?("a.txt") # サイズが0か
File.basename("a/b/c.txt") # ファイル名であるc.txtを返す
File.dirname("a/b/c.txt") # a/bを返す
File.extname("a/b/c.txt") # 拡張子を返す
File.split("a/b/c.txt") # ["a/b","c.txt"]
File.join("a/b", "c.txt") # "a/b/c.txt"
File.expand_path("a","b") # ディレクトリb内での相対パスaを、絶対パスにする。bが省略されたときはカレントディレクトリを指定したときになる
__FILE__ # 現在のソースファイル名

require "find" # ファイルを検索できる
require "tempfile" # 一時ファイルの管理に便利
require "fileutils" # ファイルの移動や作成などが簡単にできる
```

# 25. Dirクラス
```
Dir.pwd
Dir.chdir("a") # cd

dir = Dir.open("a") # Fileクラスと同じメソッドが多い
while n = dir.read
  puts n
end
dir.close
dir.each do |n|
  puts n
end
dir.read

# globによって、ターミナルと同じように*や?などのパターンを使うことができる
Dir.glob("*") # カレントディレクトリの全てのファイル名を取得
Dir.glob(".*") # カレントディレクトリの、隠しファイルを含む布部手のファイル名を取得
Dir.mkdir("a")
Dir.rmdir("a")

__dir__ # 現在のソースファイルのディレクトリ名
```

# 26. 文字コード
- Rubyの文字列、正規表現は、文字列のデータと、文字コードをセットで保持している
- 正規表現は同じエンコーディングの文字列とのみマッチする
- コマンドラインで`ruby -E Shift_JIS test.rb`や`irb -E Shift_JIS`などと書くことで出力用の文字コードを指定
- Fileクラスにおいて、`open`や`read`などでも`encoding`を指定できる
```
# encoding: Shift_JIS コメントでこれを書くことで、ソースコードの文字コードを指定できる。大文字、小文字は区別しない
# coding: Shift_JIS このように書いてもいい
s.encoding
s.encode("utf-8")

# Encodeクラス
Encoding.compativle?(s1, s2) # s1とs2に互換性があるか(連結できるか) 連結した際の文字コードを返す
Encoding.find("shift_jis") # #<Encoding:Shift_JIS>
Encoding.list # 一覧を返す
Encoding.name_list
Encoding.find("shift_jis").name # "Shift_JIS"

### nkfライブラリ
# s.nkf(オプション文字列、変換する文字列)
# 文字コードのみを変換する場合は、-xm0を常に指定するのが良き
NKF.nkf("-S -x -xm0", s) # Shift_JISをUTF-8にする
NKF.nkf("-x -xm0", s) # 元の文字コードを自動で判別してくれる
```

# 27. 日時
## 27.1 基本
```
t = Time.new # 現在時刻
Time.now
Time.mktime(2024) # 2024-01-01 00:00:00
Time.at(300) # 1970/1/1から300秒

t.year
t.month
t.day
t.hour
t.min
t.sec
t.usec # 小数点(マイクロ秒)
t.nsec # 小数点(ナノ秒)
t.wday # 週の何日目か
t.yday # 年の何日目か
t.to_i # 1970年1月1日からの秒数
t.zone # タイムゾーン
t.utc_offset # 標準時との差(秒)
t.utc # タイムゾーンを世界標準時に変更
t.localtime # タイムゾーンをローカルタイムに変更

t1 < t2
t2 - t1 # 秒数が帰る

t.to_s
```
## 27.2 フォーマッティング
- `t.strftime("%y-%m-%d")`のような形で`Time`をフォーマッティングできる

|コード|説明|例|
--- | --- | ---
%A|曜日|Sunday
%a|曜日|Sun
%B|月|January
%b|月|Jan
%c|日付、時刻|Sun Jan  1 00:00:00 2024
%d|日付|01
%H|時刻(24時間)|01
%I|時刻(12時間)|01
%j|その年の何日目か|366
%M|分|00
%m|月|01
%p|午前、午後|AM
%S|秒|00
%U|その年の何周目か(日曜始まり)|00
%W|その年の何周目か(月曜始まり)|00
%w|曜日(日曜日が0)|0
%X|時刻|00:00:00
%x|日付|01/02/24
%Y|西暦|2024
%Z|タイムゾーン|東京 (標準時)
%z|タイムゾーン|+0900
%%|%を出力できる|%

※プラットフォームによって実行結果が異なる場合がある

## 27.3 timeライブラリ
```
require "time"

t.iso8601 # ISO 8601の形式にフォーマッティング
Time.parse("2024/01/01") # 文字列をTimeオブジェクトにできる。様々な文字列に対応している
Time.strptime("11/9/2018", "%m/%d/%Y) # parseでは対応していない文字列もTimeオブジェクトにできる
Time.strptime("令和6年1月1日", "令和%Y年%d月%d日") do |y|
  y + 2018 # ブロックに年以外の情報を渡すことはできない
end
t.strptime("%Y/%m/%d") # 特定の形式で文字列を取り出す
```
## 27.4 dateライブラリ
```
require "date"

d = Date.today
d = Date.new(2024,1,1)
d = Date.new(2024,1,-1) # 2024/1/31
d.year
d.month
d.day
d.wday # 曜日(日曜日が0)
d.yday # 年の何日目か
d2 - d1 # 日数/1 と表示される
d + 1 # 1日先を取得
d += 1 # 1日先になる
d >> 2 # 2か月後の同じ日を取得
Date.new(2024,1,31) >> 1 # 2024/2/29
d.strftime("%Y/%m") # timeライブラリと同様に使えるが、時刻は全て0になる
Date.parse("R06.1.1")
t.to_date
d.to_time
```

# 28. Procクラス
- ブロックをオブジェクトにできるイメージ

```
pr = Proc.new do |s|
  puts s
end

pr = Proc do |s| # newを付けなくても同じ
  puts s
end

pr = proc do |s| # 小文字でも同じ
  puts s
end

pr.call("hello")
pr["hello"]
pr.yield("hello")
pr.("hello")
pr === "hello" # この書き方だと、引数は1つだけ。case文などに使えるようにこの形式が定義されている

pr = Proc do |*a|
  puts a
end

pr.call(1,2,3)
pr.call[1,2,3]

pr = Proc.new {|n| n%2 == 0}

(1..5).each do |i|
  case i
  when pr then puts i
  end
end

# lambdaメソッドでProcオブジェクトを生成
# 　引数の数のチェックが厳密になる
# 　ブロック内でreturnを使える
# 　lambdaメソッドでない場合のreturnは、Procオブジェクトを作成したメソッドから戻ろうとする
#  breakも同様
pr = lambda do|a,b,c|
  puts a,b,c
end

pr = -> (a,b,c) { puts a,b,c }

pr.call(1,2,3)

puts ["a","bc", "c", "defg","h"].sort_by { |a| a.length}

# :length.to_procオブジェクトが暗黙的に呼び出されることで、次のようにブロックを省略して書ける
puts ["a","bc", "c", "defg","h"].sort_by(&:length)

pr.arity # ブロック変数の数を返す ブロック変数が*aのように定義されているときは-1
pr.parameters # ブロック変数について、[種類, 変数名]の配列を返す
pr.lambda? # ラムダ式かどうか
pr.source_location # プロックが定義された位置[ファイル名, 行番号]

# クロージャー
# クラスのように手続きとデータの両方を保持できる
def counter
  c = 0
  Proc.new do
    c += 1
  end
end

c1 = counter
c1.call
c1.call
c2 = counter
c2.call
```

# 29. 組み込み変数
[こちらの記事](https://qiita.com/ittokunvim/items/2af62fa4e8227d05d95d)でまとめられている