ruby silver受験前に個人的な注意ポイントまとめ

#概要
今週末がruby silverの試験なので
試験前にさっと見直せる様、ここ数日の勉強で理解に時間がかかったポイントをまとめておきます。
これから受験する方にとっても、参考になれば幸いです。

（2021/03/01 追記）
[無事合格しました！](https://qiita.com/k10/items/c97bdf7ddbeb4cc5929c)

#string
###to_h to_a
stringクラスにto_h,to_aメソッドはないので注意！

```ruby:to_h_to_a.rb
hoge = "a".to_h
# => NoMethodError

hoge = "a".to_a
# => NoMethodError
```

###to_i
to_iメソッドは、整数とみなされない文字が含まれていれば、その直前までを数値に変換する
変換対象が空文字列であれば 0 を返す

```ruby:to_i.rb
p "123abc".to_i # => 123
p "123-4".to_i # => 123
p "-123あいう".to_i # => -123
p "1a2b3c".to_i # => 1
p "".to_i # => 0
p "abc123".to_i # => 0
```

###定数
定数に再代入しようとすると警告が出るのはキホンのキだが
定数にメソッドを呼び出した結果、内容が書き変わったとしても警告は発生しない。
よくよく考えれば当然だが、間違えやすそうなので注意

```ruby:const.rb
HOGE = "hoge"
HOGE = "piyo" # => 警告が発生した後、"piyo"に再代入
p HOGE #=> "piyo"

HOGE.gsub!("piyo","fuga") # => 定数にメソッドを呼び出しても警告は発生しない
p HOGE #=> "fuga" 
```

#hash
###hashのデフォルト
Hash.new(default)で、デフォルトの値を設定して、空のHashを作成できる。
default引数が指定された場合は、valueにdefaultが入るが
defaultで作成された要素は、pメソッドなどでHashの内容を参照する際は対象外となる

```ruby:hash_default.rb
h = Hash.new("default_value")
h[:a]
h[:b] = 100

# :a 指定してあげるとデフォルト値が入っていることがわかるが
p h[:a] # => "default_value"
# 全体を表示させると、デフォルト値が入った:aは無視されている
p h  # => {:b=>100}
```

###繰り返し処理のブロックパラメータ
Hashにおける繰り返し処理のブロックパラメータはArrayで渡される。

```ruby:hash_each.rb
h = {a: 100, b: 200}
p h.class # => hash (これは当然hash)
h.each {|block| p block.class}
# => array array (ブロックパラメータのクラスはarray)
```

#array
###arrayの宣言の仕方による違い
Array()で宣言した場合と、Array.new()で宣言した場合とでは、ブロックの内容をどう扱うかが変わる。

```ruby:array_arraynew.rb
# Array(3)はArray([3])と宣言したことと同じ意味になる。この時ブロックの内容は無視される。
arr = Array(3){"a"}
p arr #=> [3]

# Array.new(3){"a"}と宣言すると、要素数が3の配列を作成し、ブロックの値でそれぞれを初期化する。
arrnew = Array.new(3){"a"}
p arrnew #=> ["a", "a", "a"]

# ちなみに、Array.new(3,"a")と宣言すると、要素数が3の配列を作成し、全ての要素を"a"で初期化する。
# このとき、"a"は同一のオブジェクトを参照する。
arrnew = Array.new(3){"a"}
p arrnew #=> ["a", "a", "a"]
```

#Enumerable
EnumerableはArrayクラスやHashクラスにincludeされているモジュール
早い話arrayとかhashで使える便利メソッドたちが、いっぱいあるモジュールってことだと思う。

###any?
any?は、真である要素が一つでもあればtrueを返す。
ブロックを伴う場合は、各要素に対してブロックを評価して、戻り値が真だったらそこでtrueを返す。
→つまり、戻り値が真になるまで繰り返し処理を続けるということ。

```ruby:any.rb
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

#10回Count.upを繰り返して、trueが返ってきたらただちに繰り返しストップ
[*1..10].any? do
  Count.up
end

p $val #=> 3
```

###select
select(またはfind_all)は、ブロックの戻り値が真になる要素を配列にして返す
→全ての要素をブロックに渡して評価するので、途中で止まらない

```ruby:select.rb
$val = 0

class Count
  def self.up
    $val = $val + 1
    $val == 3 ? true : false
  end
end

#10回Count.upを繰り返す。戻り値がtrueでもfalseでも最後までやり切る。
[*1..10].select do
  Count.up
end

p $val #=> 10
```
###partition
partitionは、ブロックの条件を満たす要素と満たさない要素に分割する

```ruby:partition.rb
# 変数が１つだけの場合は、分割された要素が配列で変数に代入される
a = (1..5).partition(&:odd?)
p a  #=> [[1, 3, 5], [2, 4]]

# 変数を２つ用意してあげると、多重代入になる
a,b = (1..5).partition(&:odd?) #=> odd?を満たす奇数はaに、偶数はbに分割される
p a  #=> [1, 3, 5]
p b  #=> [2, 4]

# 条件を満たさない側の変数を指定してあげてないと、条件を満たさない要素は無視される
a, = (1..5).partition(&:odd?) #=> 条件を満たさない側の変数がないので、偶数は無視
p a  #=> [1, 3, 5]

# ちなみに、要素を満たす側の変数はないとエラーになります
,b = (1..5).partition(&:odd?)
p b  #=> syntax error, unexpected ','
```

#Numeric
###step
終わりの数字はわかるけど、初めの数字ってどこからなんだろう？とわからなくなった事があったので確認。

```ruby:step.rb
def hoge
  x = 0
  1.step(5,1) do |i|
    x += 1
  end
  puts x
end
hoge #=> ５　（1,2,3,4,5 と、5回do~endを行う）
```

#文法
###引数の括弧を省略した時の挙動
引数の括弧を省略すると、メソッドと引数の結合が弱くなって、思わぬ挙動になるので注意

```ruby:abridgement_brackets.rb
v1 = 1 - 1 == 0
v2 = v1 || raise RuntimeError
puts v2 && false #=> syntax error

# raiseメソッドの引数の括弧が省略されているので、raiseとその引数のRuntimeErrorの結合が弱く
# ||の方が優先されてしまうため、以下の様に認識されてしまう。
# v2 = (v1 || raise)(RuntimeError)
# v1 || raiseの結果のメソッドに対し、引数がRuntimeErrorとなるため
# 当然そんなメソッドはないのでsyntax errorが出てしまう
```

単純な計算に見えても、括弧を省略しているだけでエラいことになる
（実際の開発で、こんなミスが起こらない様にしないとですね…）

```ruby:space.rb
def foo(n)
 n ** n
end
  
puts foo (3) * 3 #=>387420489

# fooと(3)の間にスペースが存在しているので、引数の括弧が省略されているとみなされてしまう…
# よって、(3) * 3の計算が優先されて、foo(9)と同様になってしまう。
# foo(3) * 3 #=> 81 を期待してて、387420489が出力されたら卒倒しそう
```

###同値比較
==, eql?, equal? はそれぞれ何が違うのか

```ruby:equal.rb
x = 1
y = 1.0

# == => 数値として同じ値ならtrue 1と1.0は同値と判定されるのでtrue
print x == y  #=> true

# eql? => オブジェクトのクラスが一緒かつ、同じ値ならtrue 今回はFixnumとFloatなのでfalse
print x.eql? y  #=> false

# equal? => 同じオブジェクトならtrue 今回はもちろんfalse
print x.equal? y  #=> false

# ちなみに、数字はどこで参照しても同じオブジェクトIDなので、以下の結果はtrue
print x.equal?(1)  #=> true
```

###パーセント記法
パーセント記法で、文字列だけではなくて他の値も作成できる

```ruby:percent.rb
# %s でシンボル作成
symbol = %s(abc)
p symbol  # => :abc 

# %w で、要素がシングルクォート文字列となる配列作成　区切り文字は空白なので、"や,は文字列となる
# シングルクォート文字列なので、式展開を行わない
drink = "tea"
single = %w(coffee, "water", #{drink})
p single  # => ["coffee,", "\"water\",", "\#{drink}"]

# %W で、要素がダブルクォート文字列となる配列作成　区切り文字は空白なので、"や,は文字列となる
# ダブルクォート文字列なので、式展開を行う
drink = "tea"
double = %W(coffee, "water", #{drink})
p double  # => ["coffee,", "\"water\",", "tea"]

# %r で正規表現作成
regex = %r([0-9]{3})
p regex  # => /[0-9]{3}/
```
###基数指示子
数値リテラルを、何進数で表現するか指定できる。
特に8進数がよく問われてる印象

```ruby:cardinal.rb
# 2進数（binary) ... 0b
puts 0b10 #=> 2

# 8進数（octal) ... 0o または 0 (←??? なんでこんな仕様にしちゃったんや…)
puts 0o10 #=> 8
puts 010 #=> 8
# エラーが出るのはどれ？という問題で、puts 090 という、いかにも本当にやらかしちゃいそうな選択肢がよくある
puts 090 #=> Invalid octal digit

# 10進数（decimal) ... 0d
puts 0b10 #=> 10

# 16進数（hexadecimal) ... 0x
puts 0x10 #=> 16
```

###ブロックを引数にとるメソッドにおけるスコープ
timesやmapなどのメソッドなどに与えられるブロックは、その中でスコープを作成するが
上位スコープで定義された変数はそのまま使える。
中から外は参照できるが、外から中は参照できないイメージ

```ruby:scope_in_times.rb
n = 10
hoge = 0
5.times do |i|
  hoge += n
  p hoge
    #=> 10 20 30 40 50 (hoge,nはブロックの外で定義されているが、参照できる)
  fuga = "fuga"
end

p hoge
 #=> 50 (当然だが、ブロック内での変更が反映されている)

p fuga
 #=> undefined local variable or method `fuga' for main:Object (NameError)
 # fugaはtimesのブロック内で定義されているので参照できない
```

###raiseメソッドの引数
例外の発生に使用するraiseは、第一引数に例外クラスかそのインスタンス、第二引数にメッセージを指定できる
どちらも省略する事ができ、第一引数を省略した場合は、RunTimeErrorクラスの例外が発生する

```ruby:raise.rb
raise "エラーだよ！" #=> エラーだよ！ (RuntimeError)
```
StandardErrorを継承しないクラスのインスタンスを、raiseメソッドの引数に指定すると、TypeErrorが発生する
ArgumentError,RuntimeError, NameError, NoMethodError, ZeroDivisionError はStandardErrorを継承している

```ruby:raise2.rb
raise ZeroDivisionError  #=> ZeroDivisionError (ZeroDivisionError)
```
もちろん自分で例外クラスを作成して、StandardErrorを継承すれば、それも補足する

```ruby:raise3.rb
class HogeException < StandardError
end

raise HogeException  #=> HogeException (HogeException)
```
StandardErrorを継承していないクラスのインスタンス（以下では、Arrayクラスのインスタンスが指定）
が引数に指定されている場合は、TypeErrorが発生する

```ruby:raise4.rb
raise [HogeException]  #=> exception class/object expected (TypeError)
```

###論理演算子
「左から右へ順に条件式を評価していき、式全体の評価が確定した場合、その場で評価を止めちゃう」
この性質を利用した問題が、初見だと理解し辛い。
&& …　左辺が真と評価されたときのみ右辺も評価(左辺が偽なら右辺は評価しない)
|| …　左辺が偽と評価されたときのみ右辺も評価(左辺が真なら右辺は評価しない)


```ruby:and_or.rb
ary = []
ary << 1 && false  #=> まず左辺が評価されるので arr << 1 は行われる
true || ary << 2  #=> 左辺評価の時点で真が確定するので、右辺の評価が行われない
false && ary << 3  #=> 左辺評価の時点で偽が確定するので、右辺の評価が行われない
false || ary << 4  #=> 左辺評価の時点では真か偽か確定しないので、右辺の評価が行われる（arr << 4）
p ary  #=> [1, 4]
```
#偉大なまとめたち
神がまとめてくださっているので、試験前に絶対みておく
いずれもよく出題されてる内容なので、覚えておくと吉ですね

K Sato様　（私と苗字とイニシャルが一緒でびっくり）
**[【Ruby】「!」が付かない破壊的メソッドまとめ](https://qiita.com/k-penguin-sato/items/ab2267ca99d5aedcc40a)**

Naoto Kishino様
**[Ruby IOクラスについて学ぶ](https://qiita.com/naotospace/items/bd0a5295e540e27936b3)**