【Ruby】RubySilverメモ

# 目的

実装やレビューにおいて困っている事は特に無いが、より良い実装にするためRubySilverに触れることで更に理解を深め、発想の引き出しを増やしたい。



# 教材
- https://rex.libertyfish.co.jp/
- https://gist.github.com/sean2121/945035ef2341f0c39bf40762cd8531e0
- [［改訂2版］Ruby技術者認定試験合格教本（Silver/Gold対応）](https://www.amazon.co.jp/［改訂2版］Ruby技術者認定試験合格教本（Silver-Gold対応）Ruby公式資格教科書-牧-俊男-ebook/dp/B0756VF9Y3/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=)


# 組み込み定数

|組み込み定数|値|
|-|-|
|[STDIN](https://docs.ruby-lang.org/ja/latest/method/Kernel/v/stdin.html)|標準入力|
|[STDOUT](https://docs.ruby-lang.org/ja/latest/method/Kernel/v/stdout.html)|標準出力|
|[STDERR](https://docs.ruby-lang.org/ja/latest/method/Kernel/v/stderr.html)|標準エラー出力|
|[DATA](https://docs.ruby-lang.org/ja/latest/method/Object/c/DATA.html)|スクリプトの `__END__` プログラム以降にアクセスする|
|[ENV](https://docs.ruby-lang.org/ja/latest/class/ENV.html)|環境変数|
|[ARGF](https://docs.ruby-lang.org/ja/latest/class/ARGF.html)|スクリプトに指定した引数をファイル名とみなし、それらのファイルを連結した1つの仮想ファイルを表す|
|[ARGV](https://docs.ruby-lang.org/ja/latest/method/Object/c/ARGV.html)|スクリプトに与えられた引数を表す配列|
|[RUBY_VERSION](https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_VERSION.html)|Rubyのバージョン|
|[RUBY_RELEASE_DATE](https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_RELEASE_DATE.html)|Rubyのリリース日|
|[RUBY_PLATFORM](https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_PLATFORM.html)|プラットフォーム|


# 組み込み変数
- https://docs.ruby-lang.org/ja/latest/class/Kernel.html#V_--21


# 予約語一覧
- https://docs.ruby-lang.org/ja/latest/doc/spec=2flexical.html#reserved

```rb
BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until
```

>予約語はクラス名、変数名などに用いることはできません。ただし接頭辞$, @、@@が先頭についたものは予約語とは見なされません。
また、def のあとやメソッド呼び出しのピリオドのあとなどメソッド名であるとはっきり分かる場所ではメソッド名として用いることができます。


# ローカル変数とメソッド名が同じ場合の挙動
```rb
hoge = 0

def hoge
  5 * 100
end

p hoge
```
```rb:実行結果
0
```

:::note
変数の定義が優先される
:::

現場ではまずやらない書き方だけど理解しておくことが大切。


# シンボルと文字列
- https://docs.ruby-lang.org/ja/latest/class/Symbol.html
> Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの`名前'を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。
>
>シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。
>
>名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。

```rb
p str1 = "aaa".object_id #=> 60
p str2 = "aaa".object_id #=> 80
p sym1 = :aaa.object_id  #=> 1082908
p sym2 = :aaa.object_id  #=> 1082908
```

:::note
シンボルは内部では整数として扱われるため、文字列よりも処理が速い。
よって、単にラベルとして扱いたい場合には文字列よりもシンボルの方が効率が良い。
:::



# 1行で書く

本来改行すべきところに`;`（セミコロン）を書く。

## クラス
```rb
class OriginalError < StandardError; end # ここ

begin
  # raise StandardError
  raise OriginalError
rescue OriginalError => e
  puts "1: #{e.class}"
rescue => e
  puts "2: #{e.class}"
end

#=> 1: OriginalError
```

## メソッド
```rb
def add(num1, num2); p num1 + num2; end

add(1, 2) #=> 3
```

## 条件分岐
```rb
a = 2

if a == 1; p 'a'; elsif a == 2; p 'b'; else; p 'c'; end  #=> "b"
```



# 多重代入

## 例
- https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#multiassign
```rb
foo, bar = [1, 2]     #=> foo = 1; bar = 2
foo, bar = 1, 2       #=> foo = 1; bar = 2
foo, bar = 1          #=> foo = 1; bar = nil

foo, bar, baz = 1, 2  #=> foo = 1; bar = 2; baz = nil
foo, bar = 1, 2, 3    #=> foo = 1; bar = 2
foo = 1, 2, 3         #=> foo = [1, 2, 3]
*foo = 1, 2, 3        #=> foo = [1, 2, 3]
foo,*bar = 1, 2, 3    #=> foo = 1; bar = [2, 3]
```


## 一部を括弧で囲う場合
```rb
(a, b), c = 1, 2, 3

p a  #=> 1
p b  #=> nil
p c  #=> 2
```
:::note warn
上記のように行うと 「`(a, b)`」 と 「`c`」 に対してそれぞれの値を代入を行う。
:::



# 引数
- https://shyu-61.hatenablog.com/entry/2021/01/01/010612

## 可変長引数
### 第一引数が可変長
```rb
def hoge(*n1, n2)
  p n1
  p n2
end

hoge 1, 2, 3, 4
```
```rb:実行結果
[1, 2, 3]
4
```

### 第二引数が可変長

```rb
def hoge(n1, *n2)
  p n1
  p n2
end

hoge 1, 2, 3, 4
```
```rb:実行結果
1
[2, 3, 4]
```


:::note warn
複数の引数を可変長にすると***syntax error***となる

例）
`hoge(n1, *n2, *n3)`
`hoge(*n1, n2, *n3)`
`hoge(*n1, *n2, *n3)`
#=> ***syntax error, unexpected `end', expecting end-of-input***
:::




## キーワード引数
```rb
def foo(a:, b:, c:400)
  p a + b + c
end

foo(a: 100, b: 200, c: 300) #=> 600
foo(a: 100, b: 200)         #=> 700
foo(a: 100)                 #=> sample.rb:1:in `foo': missing keyword: :b (ArgumentError)
foo(a: 100, b: 200, d: 300) #=> sample.rb:1:in `foo': unknown keyword: :d (ArgumentError)
```

:::note warn
デフォルト値がないキーワード引数を省略したり、
存在しないキーワード引数を指定すると、***ArgumentError***になる
:::



## オプション引数
- https://style.potepan.com/articles/33275.html
>Rubyにおけるハッシュのように自由にキーワードと値のペアで引数を記述し、それを引き渡せる機能です。そして引き渡した引数はメソッドの内部でハッシュのように扱えます。

```rb
def sample(**args)
  p args
  args.each do |key, value|
    puts "key: #{key}, value: #{value}"
  end
end

sample(a: 100, b: 200, c: 300)
#=> {:a=>100, :b=>200, :c=>300}
#   key: a, value: 100
#   key: b, value: 200
#   key: c, value: 300
```




# 演算子式

## ==, eql? equal?（オブジェクトの同値性と同一性）
- https://docs.ruby-lang.org/ja/latest/method/Object/i/eql=3f.html
- https://docs.ruby-lang.org/ja/latest/method/Object/i/equal=3f.html

```rb
x = 1
y = 1.0

a1 = "aaa"
a2 = 'aaa'
```

```rb:rails c
irb(main):005:0> x == y
=> true
irb(main):006:0> x.eql? y
=> false
irb(main):007:0> x.equal? y
=> false
irb(main):008:0> x.equal?(1)
=> true
```

```rb
irb(main):009:0> a1 == a2
=> true
irb(main):010:0> a1.eql? a2
=> true
irb(main):011:0> a1.equal? a2
=> false
```

:::note
- `==`はオブジェクトの内容が等しいか
- `eql?`はhashのkeyとして等しいか
- `equal?`はobject_idが等しいか
:::


## `===`
- https://docs.ruby-lang.org/ja/latest/doc/symref.html#eq
- https://docs.ruby-lang.org/ja/latest/method/Object/i/=3d=3d=3d.html
- https://docs.ruby-lang.org/ja/latest/method/Range/i/=3d=3d=3d.html

### そのクラスかどうか
```rb
p String === "ruby"  #=> true
p String === 1       #=> false

p Integer === 1      #=> true
p Integer === "ruby" #=> false
```

### 範囲に含まれるか
```rb
p (1..10) === 10      #=> true
p (1...10) === 10     #=> false

p ('a'..'z') === 'z'  #=> true
p ('a'...'z') === 'z' #=> false
```

### 正規表現にmatchするか
```rb
p /[0-9]{3}/ === "sample987" #=> true
p /[0-9]{3}/ === "sample"    #=> false
```



## `<=>` （UFO演算子）
- https://docs.ruby-lang.org/ja/latest/class/Integer.html#I_--3C--3D--3E

```rb
p 1000 <=> 999   #=> 1
p 1000 <=> 1000  #=> 0
p 999  <=> 1000  #=> -1
```

:::note
左辺 と 右辺 を比較し、左辺 が大きい時に1、等しい時に 0、小さい時に-1、比較できない時に nil を返す
:::

StringやArrayにもある
- https://docs.ruby-lang.org/ja/latest/method/String/i/=3c=3d=3e.html
- https://docs.ruby-lang.org/ja/latest/method/Array/i/=3c=3d=3e.html


## `&&`
- https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#and
>左辺を評価し、結果が偽であった場合はその値(つまり nil か false) を返します。左辺の評価結果が真であった場合には右辺を評価しその結果を返します。 and は同じ働きをする優先順位の低い演算子です。

### `and`との優先度の違い
```rb
p 'a' && 'b'  #=> "b"
p 'a' and 'b' #=> "a"
```

```rb
a1 = [1,2,3]
a2 = [4,2,3]

p a1 &&  a2  #=> [4, 2, 3]
p a1 and a2  #=> [1, 2, 3]
```

:::note
「**nil**または**false**であれば偽、それ以外はすべて真」として扱われる。
また、`and`は`&&`に比べ優先順位が低い。
:::

### どちらかがnilやfalseの場合
```rb
a1 = nil
a2 = false
a3 = [1, 2, 3]

p a1 && a3 # 左辺がnil
p a3 && a1 # 右辺がnil
p a2 && a3 # 左辺がfalse
p a3 && a2 # 右辺がfalse
```
```rb:実行結果
nil
nil
false
false
```

### 比較対象がnilとfalseの場合は、左辺を返す
```rb
p (nil && false)  #=> nil
p (false && nil)  #=> false
```



## `||`
- https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#or
>左辺を評価し、結果が真であった場合にはその値を返します。左辺の評価結果が偽であった場合には右辺を評価しその評価結果を返します。 or は同じ働きをする優先順位の低い演算子です。



### 両辺nilやfalseではない場合
```rb
a1 = [1,2,3]
a2 = [4,2,3]

p a1 || a2  #=> [1, 2, 3]
```

### 比較対象がnilとfalseの場合は、右辺を返す
```rb
p (nil || false)  #=> false
p (false || nil)  #=> nil
```

### `or`との優先度の違い
```rb
p false || true  #=> true
p false or true  #=> false
```




# クラス変数
```rb:例1
class Super
  @@foo = 0

  def foo
    @@foo
  end

  def foo=(value)
    @@foo = value
  end
end

class Sub < Super
  @@foo = 0

  def foo
    @@foo
  end

  def foo=(value)
    @@foo = value
  end
end

super1 = Super.new
super1.foo += 100
super2 = Super.new
super2.foo += 200
sub1 = Sub.new
sub1.foo += 50

puts "#{super1.foo}/#{super2.foo}/#{sub1.foo}" #=> 350/350/350
```

```rb:例2
class Super
  @@i = 0
  
  def self.count
    @@i += 1
  end
end

class Sub < Super; end

puts Super.count #=> 1
puts Sub.count   #=> 2
puts Super.count #=> 3
```


:::note 
クラス変数はクラス全体で共有され、クラスメソッド内やスーパークラス・サブクラスでも共有される。
:::


# ヒアドキュメント
- https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#here
- https://style.potepan.com/articles/35488.html

>EOD (End of Documentの略)
EOF (End of Fileの略)
EOL (End of Lineの略)
EOM (End of Messageの略)
EOS (End of Stringの略)
EOT (End of Textの略)

:::note
```rb
text = <<EOF
         Ruby,
           Silver
EOF

p text #=> "         Ruby,\n           Silver\n"
```
:::

:::note alert
終端行をインデントしているためエラー発生
```rb
text = <<EOF
         Ruby,
           Silver
         EOF

p text #=> can't find string "EOF" anywhere before EOF
```
:::

:::note
開始ラベルを`<<-識別子`のようにする事で、終端行をインデント出来る
```rb
text = <<-EOF
          Ruby,
            Silver
          EOF

puts text #=> "          Ruby,\n            Silver\n"
```
:::

:::note
開始ラベルを`<<~識別子`のようにする事で、空白の無い文字列として変数に格納
```rb
text = <<~EOF
          Ruby,
            Silver
          EOF

p text #=> #=> "Ruby,\n  Silver\n"
```
:::



# Array

## 複数の要素を持つ配列を生成する様々な方法

```rb
# 例1
['ruby'] * 3                     # 中身の要素が、すべて同一のオブジェクト
%w(ruby) * 3                     # 同一

# 例2
Array.new(3, 'ruby')             # 同一

# 例3
Array.new(3).fill('ruby')        # 同一

# 例4
Array.new(3) { 'ruby' }          # 別々

# 例5
'rubyrubyruby'.scan('ruby')      # 別々

# 例6
[] << 'ruby' << 'ruby' << 'ruby' # 別々
```

```rb:実行結果
["ruby", "ruby", "ruby"]
```

:::note warn
定義の仕方によって、オブジェクトの中身が異なるため注意。
下記は`Array.new(3, '初期値')`と`Array.new(3) { '初期値' }`の違い。

```rb
arr1 = Array.new(3, 'ruby')
arr1.each { |el| p el.object_id }
#=> 60
#   60
#   60
arr1[0].replace('RUBY')
p arr1 #=> ["RUBY", "RUBY", "RUBY"]

arr2 = Array.new(3) { 'ruby' }
arr2.each { |el| p el.object_id }
#=> 80
#   100
#   120
arr2[0].replace('RUBY')
p arr2 #=> ["RUBY", "ruby", "ruby"]
```

- `Array.new(3, '初期値')`は要素が全て**同一**のオブジェクトを生成する
- `Array.new(3) { '初期値' }`は要素が全て**別々**のオブジェクトを生成する
:::


### 文字列にアスタリスクをつけるだけでもArrayを作成出来る
```rb
*"a"  #=> ["a"]
```

### 一つの変数に多重代入した場合
```rb
obj = 'a', 'b'
p obj #=> ["a", "b"]
```


## 連番の要素を持つ配列を生成する様々な方法
```rb
# 例1
(1..10).to_a

# 例2
[*1..10]

# 例3
Array(1..10)

# 例4
(1..10).map { |i| i }

# 例5
(1..10).collect { |i| i }
```
```rb:実行結果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

- 文字列でも同様。
    - 例）`[*'a'..'z']`

:::note
`#map`と`#collect`は同じ動作をする
:::

## 要素の追加（いきなりn番目の要素を指定）
```rb
arr = [1]
arr[4] = 100
```
```rb:rails c
irb(main):001:0> arr = [1]
=> [1]
irb(main):002:0> arr[4] = 100
=> 100
irb(main):003:0> arr
=> [1, nil, nil, nil, 100]
```

## 指定した要素分を参照・代入する

### 参照
```rb
arr = ['a', 'b', 'c', 'd', 'e']
p arr[1, 3]  #=> ["b", "c", "d"]
```
インデックス1から、3つ分の要素を取得。

### 代入（指定範囲内）
```rb
arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 3] = ['z'] # 'z' でも同じ
p arr #=> ["a", "z", "e"]
```

```rb
arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 3] = 'x', 'y', 'z' # ['x', 'y', 'z'] でも同じ
p arr #=> ["a", "x", "y", "z", "e"]
```
指定数よりも過小 or 同じ場合は、代入した値に置き換わるイメージ。

### 代入(指定した範囲を超えた場合)
```rb
arr = ['a', 'b', 'c', 'd', 'e']
arr[1, 2] = 'x', 'y', 'z'
p arr #=> ["a", "x", "y", "z", "d", "e"]
```

指定数よりも余剰の場合は、全て代入された上で、元の要素が後続にずれる。



## 集合（Array）
```rb
a1 = [100, 100, 100, 200, 300]
a2 = [400, 100, 300]

puts "和集合: #{a1 | a2}"
puts "積集合: #{a1 & a2}"
puts "差集合: #{a1 - a2}"
```
```console:実行結果
和集合: [100, 200, 300, 400]
積集合: [100, 300]
差集合: [200]
```


## Array#sort
- https://docs.ruby-lang.org/ja/latest/method/Array/i/sort.html
>配列の内容をソートします。要素同士の比較は <=> 演算子を使って行います。sort はソートされた配列を生成して返します。 sort! は self を破壊的にソートし、self を返します。
>（省略）
>ブロックは第1引数が大きいなら正の整数、両者が等しいなら0、そして第1引数の方が小さいなら負の整数を返さなければいけません。両者を比較できない時は nil を返します。

```rb
ary = [7, 2, 9, 1, 4, 3, 6, 8, 0, 5]

ary.sort!{ |a, b| b <=> a } # 降順に並べ替え
ary  #=> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

ary.reverse!
ary  #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

:::note warn
`<=>`演算子で比較できない要素があると、**ArgumentError**が発生する
```rb
['a', 'b', 'c', 1, 2, 3].sort #=> comparison of String with 1 failed (ArgumentError)
```
:::

## Array#zip
- https://docs.ruby-lang.org/ja/latest/method/Array/i/zip.html
>自身と引数に渡した配列の各要素からなる配列の配列を生成して返します。生成される配列の要素数は self の要素数と同じです。
>ブロック付きで呼び出した場合は、 self と引数に渡した配列の各要素を順番にブロックに渡します。

```rb
p [1,2,3].zip([4,5,6], [7,8,9])
# => [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

p [1,2].zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B]]

p [1,2,3,4,5].zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B],
#     [3, :c, :C], [4, nil, :D], [5, nil, nil]]

p [1,2,3].zip([4,5,6], [7,8,9]) { |ary| p ary }
# => [1, 4, 7]
#    [2, 5, 8]
#    [3, 6, 9]
#    nil
```

## Array#product
- https://docs.ruby-lang.org/ja/latest/method/Array/i/product.html

>レシーバの配列と引数で与えられた配列（複数可）のそれぞれから要素を1個ずつとって配列とし，それらのすべての配列を要素とする配列を返します。

返される配列の長さは，レシーバと引数で与えられた配列の長さのすべての積になります。
```rb
[1, 2].product([3, 4])  #=> [[1, 3], [1, 4], [2, 3], [2, 4]]
```

## Array#transpose
- https://docs.ruby-lang.org/ja/latest/method/Array/i/transpose.html

>自身を行列と見立てて、行列の転置(行と列の入れ換え)を行います。
>転置した配列を生成して返します。
>空の配列に対しては空の配列を生成して返します。

```rb
[[1, 3], [1, 4], [2, 3], [2, 4]].transpose  #=> [[1, 1, 2, 2], [3, 4, 3, 4]]
```


## Array#slice
- https://docs.ruby-lang.org/ja/latest/method/Array/i/slice.html
>指定された自身の部分配列を返します。
```rb
p [1, 2, 3, 4].slice(2, 1) #=> [2]
p [0, 1, 2].slice(0, 2)    #=> [0, 1]
p [0, 1, 2].slice(2..3)    #=> [2]
p [0, 1, 2].slice(10, 1)   #=> nil
```


## Array#join
- https://docs.ruby-lang.org/ja/latest/method/Array/i/join.html
```rb
[1, 2, 3].join('-') #=> "1-2-3"
```

### `*`でも同じことが可能
```rb
[1, 2, 3] * '-' #=> "1-2-3"
```



## Array#shift
- https://docs.ruby-lang.org/ja/latest/method/Array/i/shift.html

>配列の先頭の要素を取り除いてそれを返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。
>空配列の場合、n が指定されていない場合は nil を、指定されている場合は空配列を返します。
>また、n が自身の要素数より少ない場合はその要素数の配列を返します。どちらの場合も自身は空配列となります。

```rb
arr = [0, 1, 2, 3, 4]
p arr.shift          #=> 0
p arr                #=> [1, 2, 3, 4]

p [].shift           #=> nil
p [].shift(1)        #=> []
```

:::note warn
破壊的メソッド
:::


## Array#prepend
- https://docs.ruby-lang.org/ja/latest/method/Array/i/prepend.html
>指定された obj を引数の最後から順番に配列の先頭に挿入します。引数を指定しなければ何もしません。

```rb
arr = [1,2,3]
arr.unshift
p arr             #=> [1, 2, 3]
arr.unshift 0
p arr             #=> [0, 1, 2, 3]
arr.unshift [0]
p arr             #=> [[0], 0, 1, 2, 3]
arr.unshift 1, 2
p arr             #=> [1, 2, [0], 0, 1, 2, 3]
```

:::note warn
破壊的メソッド
:::

## Array#pop
- https://docs.ruby-lang.org/ja/latest/method/Array/i/pop.html
>自身の末尾から要素を取り除いてそれを返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。

```rb
arr = [1, [2, 3], 4]
p arr.pop        # => 4
p arr.pop        # => [2, 3]
p arr            # => [1]

p arr.pop        # => 1
p arr.pop        # => nil
p arr            # => []

arr = [1, 2, 3]
p arr.pop(2)     #=> [2, 3]
p arr            #=> [1]
```
:::note warn
破壊的メソッド
:::


## Array#each_index
- https://docs.ruby-lang.org/ja/latest/method/Array/i/each_index.html
>各要素のインデックスに対してブロックを評価します。
```rb
[*'a'..'c'].each_index { |i| p i }
# => 0
#    1
#    2
```


## Array#clear
- https://docs.ruby-lang.org/ja/latest/method/Array/i/clear.html
>配列の要素をすべて削除して空にします。
```rb
ary = ['a', 'b']
ary.clear

p ary #=> []
```

:::note warn
破壊的メソッド
:::


# Hash

## Hashの定義
```rb
key = Class.new
value = 10000

# 例1
hash = {key => value}

# 例2
hash = Hash.new
hash[key] = value

# 例3
hash = Hash[key, value]

# 例4
hash = {}
hash.store(key, value)
```


## キーが重複している場合
```rb
hash = { a: 100, b: 200, c: 300, a: 10, c: 20 }
```

```rb:実行結果
irb(main):001:0> { a: 100, b: 200, c: 300, a: 10, c: 20 }
(irb):1: warning: key :a is duplicated and overwritten on line 1
(irb):1: warning: key :c is duplicated and overwritten on line 1
=> {:b=>200, :a=>10, :c=>20}
```

:::note warn
警告が出る。後ろのバリューに上書きされる。
:::

## Hashのvalueを複数取得する
- https://docs.ruby-lang.org/ja/latest/method/Hash/i/values_at.html
```rb
hash = { apple: 100, grape: 300 }

p hash.values_at(:apple, :grape)  #=> [100, 300]
```

## HashをArrayにする
```rb
{a: 100, b: 200}.to_a  #=> [[:a, 100], [:b, 200]]
```

## キーが存在するかどうか調べる
```rb
hash = { apple: 100, grape: 300 }

p hash.has_key?(:apple) #=> true
p hash.key?(:apple)     #=> true
p hash.include?(:apple) #=> true
p hash.member?(:apple)  #=> true
```

## メソッドの引数にHashを渡す
```rb
def sample(a, b, c)
  p c
end

sample 'a', 'b', {c: 'c', d: 'd', e: 'e'} #=> {:c=>"c", :d=>"d", :e=>"e"}
sample 'a', 'b', c: 'c', d: 'd', e: 'e'   #=> {:c=>"c", :d=>"d", :e=>"e"}
```
:::note
波括弧を省略した場合も、Hashとして渡される
:::


## Hash#invert
- https://docs.ruby-lang.org/ja/latest/method/Hash/i/invert.html
>値からキーへのハッシュを作成して返します。
>異なるキーに対して等しい値が登録されている場合、最後に定義されている値が使用されます。

```rb
h = { "a" => 0, "b" => 100, "c" => 200, "d" => 300, "e" => 300 }

p h.invert  #=> {0=>"a", 100=>"b", 200=>"c", 300=>"e"}
```
```rb
h = {a: 100, b: 100}

p h.invert  #=> {100=>:b}
```

## Hash#clear
- https://docs.ruby-lang.org/ja/latest/method/Hash/i/clear.html
>ハッシュの中身を空にします。
空にした後のselfを返します。デフォルト値の設定はクリアされません。
```rb
h = {apple: 100, grape: 300}
h.clear

p h  #=> {}
```
:::note warn
破壊的メソッド
:::


# Enumerable

## Enumerable#partition
- https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/partition.html
```rb
a, = (1..5).partition(&:odd?)

p a  #=> [1, 3, 5]
```
```rb:rails c
irb(main):001:0> (1..5).partition(&:odd?)
=> [[1, 3, 5], [2, 4]]
```

`a =`はともかく`a, =`っていう書き方でもエラーなく出来るんだな・・。

## Enumerable#each_cons
- https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/each_cons.html
>要素を重複ありで n 要素ずつに区切り、ブロックに渡して繰り返します。
>ブロックを省略した場合は重複ありで n 要素ずつ繰り返す Enumerator を返します。


```rb
(1..10).each_cons(3){ |v| p v }
# => [1, 2, 3]
#    [2, 3, 4]
#    [3, 4, 5]
#    [4, 5, 6]
#    [5, 6, 7]
#    [6, 7, 8]
#    [7, 8, 9]
#    [8, 9, 10]
```

実務ではまだ見かけたことないけど競プロとかで使えそう。


# Numeric
## Numeric#abs2
- https://docs.ruby-lang.org/ja/latest/method/Numeric/i/abs2.html

>自身の絶対値の 2 乗を返します。
```rb
p 5.abs2     # => 25
p -5.abs2    # => 25
p 5.0.abs2   # => 25.0
p -5.0.abs2  # => 25.0
```

## Numeric#step
- https://docs.ruby-lang.org/ja/latest/method/Numeric/i/step.html

>self からはじめ step を足しながら limit を越える前までブロックを繰り返します。
step は負の数も指定できます。また、limit や step には Float なども指定できます。

```rb:rails c
irb(main):001:0> 2.step(5){|n| p n}
2
3
4
5
=> 2
irb(main):002:0> 1.1.step(1.5, 0.1) {|n| p n}
1.1
1.2000000000000002
1.3
1.4000000000000001
1.5
=> 1.1
irb(main):003:0> 10.step(6, -1){|n| p n}
10
9
8
7
6
=> 10
irb(main):004:0> 3.step(by:2, to:10){|n| p n}
3
5
7
9
=> 3
irb(main):005:0> 1.step(5,1){|n| p n}
1
2
3
4
5
=> 1
```

:::note warn
>浮動小数点数の 0.1 は 2進数では正確な表現ができない
>(2進数で 0.1は 0.00011001100....となる)
:::



# String

## String#delete
- https://docs.ruby-lang.org/ja/latest/method/String/i/delete.html
>delete(*strs) -> String
>  self から strs に含まれる文字を取り除いた文字列を生成して返します。

```rb
p 'Ruby on Rails'.delete('Rails') #=> "uby on "
p '0123456789'.delete('0-48-')    #=> "5679"
```

:::note
`delete('0-48-')` は、`'0-4'`で0〜4までの数字を取り除き、`'8-'`では範囲指定とは見なされず、`8`と`-`を削除している。
:::



## String#split
- https://docs.ruby-lang.org/ja/latest/method/String/i/split.html
```rb
str1 = '10;20:30;40'
p str1.split(';|:')  #=> ["10;20:30;40"]
p str1.split(/;|:/)  #=> ["10", "20", "30", "40"]

str2 = 'a,b,c,d'
p str2.split(/,/, 2) #=> ["a", "b,c,d"]

str3 = 'A-B-C'
p str3.split /(-)/   #=> ["A", "-", "B", "-", "C"]
```


## String#strip
- https://docs.ruby-lang.org/ja/latest/method/String/i/strip.html
```rb
p "  abc  \r\n".strip    #=> "abc"
p "abc\n".strip          #=> "abc"
p "  abc".strip          #=> "abc"
p "abc".strip            #=> "abc"
p "  \0  abc  \0".strip  # => "\000  abc"   # 右側のみ "\0" も取り除く

str = "\tabc\n"
p str.strip              #=> "abc"
p str                    #=> "\tabc\n" (元の文字列は変化しない)
```
:::note
文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除く。
:::

## String#chomp
- https://docs.ruby-lang.org/ja/latest/method/String/i/chomp.html
```rb
p "foo\n".chomp             # => "foo"
p "foo\n".chomp("\n")       # => "foo"
p "foo\r\n".chomp("\r\n")   # => "foo"

$/ = "\n"   # デフォルト値と同じ
p "foo\r".chomp    # => "foo"
p "foo\r\n".chomp  # => "foo"
p "foo\n".chomp    # => "foo"
p "foo\n\r".chomp  # => "foo\n"

p "string\n".chomp(nil)  # => "string\n"

p "foo\r\n\n".chomp("")  # => "foo"
p "foo\n\r\n".chomp("")  # => "foo"
p "foo\n\r\r".chomp("")  # => "foo\n\r\r"
```

:::note
末尾から改行コードを取り除く。
:::


## String#chop
- https://docs.ruby-lang.org/ja/latest/method/String/i/chop.html
```rb:rails c
irb(main):001:0> str = "Sample   \r\n"
=> "Sample   \r\n"
irb(main):002:0> str.chop
=> "Sample   "
irb(main):003:0> str.chop
=> "Sample   "
irb(main):004:0> "Sample".chop
=> "Sampl"
irb(main):005:0> ''.chop
=> ""
```
:::note
末尾の文字を取り除く。空白は取り除かない。
ただし、文字列の末尾が"\r\n"であれば、2文字とも取り除く。
:::


## String#to_i
- https://docs.ruby-lang.org/ja/latest/method/String/i/to_i.html
```rb
arr = [
  "a".to_i(36),  # 36進数の "a" を10進数に変換すると 10 になる。
  "070".to_i(0), # to_i(0)は文字列を適切な進数として解釈する。結果として、56（8進数の70を10進数に変換した結果）が配列に格納される。
  nil.to_i,      # nil は整数に変換されると 0 になる。
  "0b0001".to_i  # "0b0001"は2進数。10進数に変換すると 1 になる。
]

p arr #=> [10, 56, 0, 0]
```

# Time
- https://docs.ruby-lang.org/ja/latest/class/Time.html
>時刻を表すクラスです。
>Time.now は現在の時刻を返します。
```rb
t = Time.now + (60 * 60 * 24) # 実行時の日時から24時間後(86400秒後)の日時
p t
```

# Date
- https://docs.ruby-lang.org/ja/latest/class/Date.html

|書式文字列|意味|
|---|---|
|%x|日付(%m/%d/%y)|
|%m|月を表す数字(01-12)|
|%M|分(00-59)|
|%d|日(01-31)|
|%D|日付(%m/%d/%y)|
|%y|西暦の下2桁(00-99)|
|%Y|西暦を表す数(9999)|


```rb
require 'date'

d1 = Date.new(2024, 12, 25)
p d1.strftime('%x')       #=> "12/25/24"
p d1.strftime('%D')       #=> "12/25/24"
p d1.strftime('%m/%d/%Y') #=> "12/25/2024"
p d1.strftime('%M/%d/%y') #=> "00/25/24"

d2 = Date.parse('2024-12-25')
p d2 += 10                #=> #<Date: 2025-01-04 ((2460680j,0s,0n),+0s,2299161j)>
p d2.year                 #=> 2025
p d2.strftime('%a')       #=> "Sat"
```

# Dir
- https://docs.ruby-lang.org/ja/latest/class/Dir.html
>ディレクトリの操作を行うためのクラスです。

```rb
Dir.chdir('/Users/sample/Desktop/Ruby')
p Dir.pwd # "/Users/sample/Desktop/Ruby"
```



# Thread
- https://docs.ruby-lang.org/ja/latest/class/Thread.html
>スレッドを表すクラスです。スレッドとはメモリ空間を共有して同時に実行される制御の流れです。 Thread を使うことで並行プログラミングが可能になります。

## Threadクラスのオブジェクトを生成するメソッド
```rb
Thread.new
Thread.fork
Thread.start
```


# File
- https://docs.ruby-lang.org/ja/latest/class/File.html
- https://docs.ruby-lang.org/ja/latest/method/Kernel/m/open.html
- https://docs.ruby-lang.org/ja/latest/method/IO/i/seek.html
- https://docs.ruby-lang.org/ja/latest/method/IO/i/rewind.html
- https://style.potepan.com/articles/27826.html
>`r`: 読み込み
`r+`: 読み書き 書き込み時はファイル文頭から上書き
`w`:  新規書き込み（ファイルが既に存在していればその内容を空に。）
`w+`: 読み書き 書き込み時は既存の内容を削除して新規作成
`a`:  追記書き込み
`a+`: 読み書き 書き込み時はファイル末尾に追記

## `'a'`
```rb:sample.rb
File.open('sample.txt', 'a') do |f|
  f.write("waiwai 1\n")
  f.write("waiwai 2\n")
end
```

実行：`ruby sample.rb`
```sample.txt
waiwai 1
waiwai 2
# 改行
```

もう一度実行：`ruby sample.rb`
```sample.txt
waiwai 1
waiwai 2
waiwai 1
waiwai 2
# 改行
```

## `'w'`
```rb:sample.rb
File.open('sample.txt', 'w') do |f|
  f.write("waiwai 1\n")
  f.seek(0, IO::SEEK_SET) # ファイルポインタを0の位置まで移動する
  f.write("waiwai 2\n")
end
```

実行：`ruby sample.rb`

```sample.txt
waiwai 2
# 改行
```

もう一度実行：`ruby sample.rb`
```sample.txt
waiwai 2
# 改行
```


### ファイルポインタの位置を変えて実行
```rb:sample.rb
File.open('sample.txt', 'w') do |f|
  f.write("waiwai 1\n")
  f.seek(3, IO::SEEK_SET) # ファイルポインタを3の位置まで移動する
  f.write("waiwai 2\n")
end
```

実行：`ruby sample.rb`

```sample.txt
waiwaiwai 2
# 改行
```


## `r+`
```txt:sample.txt(実行前)
recode 1
recode 2
recode 3
```

```rb
open('sample.txt', 'r+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
```
```txt:sample.txt(実行後)
RECODE 1
RECODE 2
RECODE 3
# 改行
```



## `'a+'`
```txt:sample.txt(実行前)
recode 1
recode 2
recode 3
```

```rb
open('sample.txt', 'a+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
```

```txt:sample.txt(実行後)
recode 1
recode 2
recode 3RECODE 1
RECODE 2
RECODE 3
# 改行
```

## `w+`
```txt:sample.txt(実行前)
recode 1
recode 2
recode 3
```
```rb
open('sample.txt', 'w+') do |f|
  data = f.read.upcase
  f.rewind # ファイルポインタを先頭に移動
  f.puts data
end
```
```txt:sample.txt(実行後)
# 改行1
# 改行2
```

## join
- https://docs.ruby-lang.org/ja/latest/class/File.html#S_JOIN
```rb
File.join('sample', 'ruby', 'silver') #=> "sample/ruby/silver"
```


# 問題例

※ 実行結果を問う問題（実際は選択式）

## 例1
```rb
p "ruby" * 3 **2
```

```rb:実行結果
"rubyrubyrubyrubyrubyrubyrubyrubyruby"
```

3の2乗分増えている。



## 例2
```rb
a = [100, 200, 300, 500, 700]
b = [100, 300, 400, 700, 800]
c = false || true ? true && false ? a | b : a & b : b ;
p c
```
```rb:実行結果
[100, 300, 700]
```

- `false || true`は ***true***
- `true && false`は ***false***
- よって、`a & b`（積集合）の値が表示される
- シンプルなイメージにすると以下
  - `c = false || true ? 三項演算子 : b ;`
    - 三項演算子の中で、もう一度三項演算子を使っている



## 例3

```rb
10.times{ |i| print i == 2..i == 5 ? 'T' : 'F' }
```
```rb:実行結果
FFTTTTFFFF
```

:::note
- `i == 2..i == 5`という書き方が出来る
:::



## 例4
```rb
arr = []
arr << 10 && false
true || arr << 20
false && arr << 30
false || arr << 40

p arr
```

```rb:実行結果
[10, 40]
```

:::note
- `&&`演算子：左辺が真と評価された場合のみ、右辺も評価される。
- `||`演算子：左辺が偽と評価された場合のみ、右辺が評価される。
:::




## 例5
```rb
p [1, 2, 3].inject{|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject(0){|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject([]){|x, y| x << y ** 2} rescue p $!
p [1, 2, 3].inject {|x, y| x + y ** 2} rescue p $!
p [1, 2, 3].inject do|x, y| x + y ** 2 end rescue p $!
```
```rb:実行結果
14
14
[1, 4, 9]
14
#<LocalJumpError: no block given>
```

:::note
`do ... end`と`{ ... }`を比べた場合、`{ ... }`の方が結合度が強い
:::


:::note
**#inject**で`do...end`を使用する場合は、以下のようにする
```rb
result = [1, 2, 3].inject(0) do |x, y|
  x + y ** 2
end

p result  #=> 14
```
:::

### Enumerable#inject
- https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/inject.html
>リストのたたみこみ演算を行います。

```rb
numbers = [1,90,40,39,29,10,30,50,69]
num = numbers.inject do |i, j|
  i > j ? i : j # ２つの整数値を比較し、より大きな値を取り出しそれをブロックに渡す
end

p num #=> 90
```

前回のブロックの戻り値をブロックに渡して繰り返し実行する



### `$!` とは
- https://docs.ruby-lang.org/ja/latest/method/Kernel/v/=21.html
>最後に例外が発生したときの Exception オブジェクトです。該当する例外がないときは nil です。
>Kernel.#raise によって設定されます。
>この変数はスレッドローカル、読み取り専用です。



## 例6
```rb
def hoge(step = 1)
  current = 0
  Proc.new {
    current += step
  }
end

p1 = hoge
p2 = hoge(5)

p1.call
p1.call
p1.call
p2.call
p2.call

p p2.call
```

```rb:実行結果
15
```

### Proc
- https://docs.ruby-lang.org/ja/latest/class/Proc.html
> Proc がローカル変数のスコープを保持している

- 今回の場合、`#hoge`は一度しか呼ばれていない
  - よって、ローカル変数`current`の初期化も一回のみ
  - 途中で`p2 = hoge(3)`等として`#hoge`を呼び出せば`current`は初期化される
- Procはローカル変数のスコープを保持している
  - `p2.call`が呼ばれる度に5ずつインクリメントされる
  - `p1`は`p1`で値を保持している

https://qiita.com/royal_straight_flush/items/4f0a5846bb370fa7d5b7



## 例7
```rb
class SuperCalc
  attr_reader :s
  def initialize(x, y)
   @s = x * y
  end
end

class SubCalc < SuperCalc
  attr_reader :v
  def initialize(x, y, z)
    super(x, y)
    @v = x * y * z
  end
end

obj = SubCalc.new(2,5,7)
puts "#{obj.s}, #{obj.v}"
```

```rb:実行結果
10, 70
```

- `super`を使えば、親クラスの同名のメソッドを呼び出すことが可能。
- `super`には通常のメソッドと同じように引数も指定可能。




## 例8
```rb
p "Ruby Silver".class
p String.superclass

class Hoge; end
class Foo < Hoge; end

p Hoge.superclass
p Foo.superclass
```

```rb:実行結果
String
Object
Object
Hoge
```

- https://docs.ruby-lang.org/ja/latest/method/Object/i/class.html
- https://docs.ruby-lang.org/ja/latest/method/Class/i/superclass.html

:::note
`#class`はオブジェクトのクラス、`#superclass`はそのクラスのスーパークラスを返す。明示的にスーパークラスを指定しない場合は、**Object**がスーパークラスとなる。
:::




## 例9

```rb
foo = ['a', 'b', 'c']
bar = foo
baz = foo.dup

bar[3] = 'd'
p foo
p bar
p baz
```

```rb:実行結果
["a", "b", "c", "d"]
["a", "b", "c", "d"]
["a", "b", "c"]
```

:::note
変数 `foo` と `bar` は同じ配列オブジェクトを参照している。
```rb
p foo.object_id #=> 60
p bar.object_id #=> 60
p baz.object_id #=> 80
```
:::


## 例10
```rb
class Object
  def food
    p 'rice'
  end
end

['a', 'b'].food
{a: 1, b: 2}.food
```

```rb:実行結果
"rice"
"rice"
```

:::note
**Array**クラス、**Hash**クラス共に**Object**クラスを継承している。
Rubyでは組み込みクラスを含め、定義済みのクラスに対してメソッド追加・既存メソッドの書き換えが可能。
:::


## 例11
```rb
print "waiwai\n" unless false || nil
```

```rb:実行結果
waiwai
```

:::note
`unless false || nil`の条件は、`if !false && !nil`と同じ意味（***ドモルガンの法則***）
:::