1ヶ月後「Ruby Association Certified Ruby Programmer Gold version 2.1」に合格する方法

結論から言うと
**「合格教本で基礎を押さえて、ひたすら問題を解く」**だけです。

メタプログラミングは一切読まなくても合格できます。

学習時間は業務後2〜3時間(土日はあんまり勉強していない)を1ヶ月間くらい。

Rubyの実行環境を用意して極力コードを実行しながら行うとより効率がよいです。

<details><summary>**【補足】**</summary>
この記事は僕が試験対策でやったことと、実際に出た問題を解くための参考、「ここは押さえとくべき」というところを簡単にご紹介して、少しでも参考にして頂ければという気持ちで作成しました。<br> 合格教本の基礎問題、模擬問題だけでは試験範囲を押さえきれていません。
**教本には載ってない内容も結構出ます。**<br> 僕が試験を受けて「ここは押さえた方が合格につながる」と思う部分を後述しておりますので、参考になればと思います。おそらく教本だけでは合格できなかっただろうと思います。
<br>**「ITトレメ」「教本の問題集」にはないが試験で出たパターン**を可能な限り(主に時間と共に薄れゆく記憶を元に)抑えた[**問題集的なものを限定共有記事**](https://qiita.com/shunogu/private/6fbccfddee858e8923c3)で公開中ですのでよろしければご参照ください。
<br>まだまだ途中です。割と時間かかっている。現在10問くらい。(2019/07/04時点)理想50問程度(あくまでパターンを抑えるのが目的)。
</details>

以下やったことを順番に書いていきます。

## 【1】 基礎を固める

<details><summary>**【教材】**</summary>
[**『Ruby 技術者認定試験合格教本』**](https://www.amazon.co.jp/%EF%BC%BB%E6%94%B9%E8%A8%822%E7%89%88%EF%BC%BDRuby%E6%8A%80%E8%A1%93%E8%80%85%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC%EF%BC%88Silver-Gold%E5%AF%BE%E5%BF%9C%EF%BC%89Ruby%E5%85%AC%E5%BC%8F%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8-%E7%89%A7-%E4%BF%8A%E7%94%B7-ebook/dp/B0756VF9Y3)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320855/e3a31a44-55a2-6656-99e3-106aa4e42dfe.png)
</details>

<details><summary>**【自分用メモ作成】**</summary>
<br>**・** 第２章から第6章の内容をひたすらまとめる各項目ごとにQiitaの限定公開記事を作成。
<br>**・** 教本だけでは理解できない場合は**リファレンス、Qiita他記事**を参照
<br>**・** リファレンスは必ず**試験と同じバージョンのもの(2.1系)**を参照する
<br>**・** [paiza.IO](https://paiza.io/ja/projects/new)、irbで動作を確認する(大事)
<br>**・** paiza.IOだとRubyのバージョンが試験と違うので注意(paizaは2.5.3)
<br>**・** って言っても、2.1系にはArray#sumメソッドが無かったり、「Fixnumクラス/Bignumクラス」がIntegerクラスに統合する前だったりとかバージョンの違いは正直あんまり気にしてなかった。<br>というか、気にならなかった。けど、するべきだとは思うから一応。
<br>**・** 「**Array#sumメソッドは2.1にはない**」と覚えてただけで1問回答できた。
<br>**・** ちなみにArray#sumは2.4系から。Fixnum、Bignumの統合も2.4系から。
</details>

<details><summary>**【所感】**</summary>
丸写しするだけでも内容をまとめようと記事作ってたらそのうちわかってくる。
<br>ってやってれば、昨日までよく理解できなかったところが、次の日少し理解できたりする。
<br>電車の中でスマホで見る自分用メモとして使える(出退勤の時間無駄にしたくないし)
</details>

<details><summary>**こんな記事(一部)を作って片手でいつでもスマホで見れる用にまとめて見てました。**</summary>
![スクリーンショット 2019-06-18 19.32.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320855/e98a1708-89a0-5da4-a32b-ed74953f2596.png)
</details>

## 【2】 問題を解く

<details><summary>**【解いた問題集】**</summary>
**・** [**ITトレメ Ruby技術者認定【Gold】試験**](https://jibun.atmarkit.co.jp/scenter/ittrain/121_today_q.html)
<br>**・** 教本 基礎問題30問 / 模擬問題50問

<details><summary>**【所感】**</summary>
「解く→間違える→調べる→解く→正解する→もう一度解く→...」を繰り返して9割以上当たり前のように解けるようになれば、公開されてる問題集はこれをやるだけで十分だと今だから思える。
<br> １ヶ月後に試験受けるぞ!と意気込んだわけではなく、これを繰り返してたら1ヶ月くらい経って「そろそろいけるのでは？」という根拠ない自信が湧いてきたので、受けてみたら、「9割とまではいかないにしても7割では済まないだろう」という予想通り8割以上解けていた。
<br> おそらく2, 3回見直しをしても試験時間60分かかるかかからないかという感じになると思います。
<br> もう**試験のための勉強**をしなくてよくなったという安堵感。
</details>

<details><summary>**【出題範囲】**</summary>
[**Ruby Association**](https://www.ruby.or.jp/ja/certification/examination/) Gold出題範囲
![スクリーンショット 2019-06-18 21.48.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320855/4c3971d5-e98d-cb64-1a91-9320d3ff2052.png)
上から順番に合格教本と合わせながら見ていきます。
</details>

## 【実行環境】

### コマンドラインオプション

オプション`-l`の動作を覚える
Rubyのオプションには無いものを選択する問題は出るので覚える

```
Rubyで使用されるオプションを全て選択しなさい(複数)
1. -e
2. -w
3. -t
4. -r
5. -b
```
このパターン出た。
答え 1, 2, 4

---

### 組み込み定数

- 環境変数**ENV**のキー、代入する値共に文字列のみ指定可能
- 数値、シンボルの指定は不可

```ruby
ENV[:PATH] = "user/..." # => キーがシンボルなので指定不可
ENV['PATH'] = 1234 # => 代入する値が文字列ではないので指定不可
ENV['PATH'] = 'user/local...' # => どちらも文字列なので指定可
```

**【例題】**

```
Objectクラスに標準で定義されている組み込み定数ではないものを選びなさい。
1. NULL
2. ARGF
4. ENV
5. DATA
```

このパターン出た。これはサービス問題。
答えは1のNULL

---

### requireとload

動作を簡単にまとめました。これだけ覚えておけばいいと思います。

| 条件 | require | load |
|---|---|---|
| 同じファイルの実行 | **一度だけ**実行 | **何度も**実行 |
| ファイルの拡張子 | 省略できる(自動補完**する**) | 省略できない(自動補完**しない**) |
| バイナリエクステンション | ロード**できる** | ロード**できない** |

---

### 特殊変数

| 変数名 | 参照される値 |
|---|---|
| **$0**| 実行中のファイル名| |
| **$1** 〜 **$n**| n番目のカッコにマッチする文字列 |

※特殊変数に関しての問題はこの２つだけでした。他のも覚えとくべきかなとは思うけど。

```:ruby.rb
以下のコードについて正しいものを選択しなさい(２つ選択)
/(https://www(\.)(.*)/)/ =~ "https://www.qiita.com/"

1. $0の値は、ruby.rbである
2. $1の値は、https://www.qiita.com/である
3. $2の値は、.qiitaである
4. $3の値は、https://www.qiitaである

答え1, 2
```

このパターンは出ました。

---
### Rdoc

- 書式を覚えたら点取れます。

| 意味 | 書式 |
|---|---|
| **見出し** | = `<h1>` <br> == `<h2>` <br> === `<h3>` <br> ==== `<h4>` <br> ===== `<h5>` <br> ====== `<h6>` |
| **ボールド体(太字)** | `*text*` |
| **イタリック体** | `_text_` |
| **タイプライター体** | `+text+` |
| **リスト** | `*`または`-` |
| **番号付きリスト** | 数字 + `.` |
| **ラベル付きリスト** | `[]`で囲む <br> `:`で区切る |

---
## 【変数と定数】

### インスタンス変数

```ruby
class Foo
  def foo
    @value
  end
end

p Foo.new.foo # => nil
```

> 初期化されていない インスタンス変数を参照した時の値はnilです。

[**Ruby2.1.0 リファレンス: インスタンス変数**](https://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fvariables.html#instance)

---

### クラス変数

```ruby
class Foo
  @@value
  def bar
    @@value # => uninitialized class variable ... (NameError)
  end
end

p Foo.new.bar
```

初期化していないクラス変数を参照しようとすると例外発生。
[**Ruby2.1.0 リファレンス: クラス変数**](https://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fvariables.html#class)

---

### 定数

定数の探索経路はまず自クラス内を探し、なければ外側のクラスを探すといった感じ。

```ruby
CONST = "Top"

module Mod
  puts CONST # => Top
  puts ::CONST # => Top
  # モジュール内定数定義
  CONST = "Mod"
  puts CONST # => Mod まず自クラスから探索
  puts ::CONST # => Top
end

class Cls1
  puts CONST # => Top

  # クラス内定数
  CONST = "Cls1"
  puts CONST # => Cls1
  
  def func
    puts CONST
    puts ::CONST
    puts Mod::CONST
    #メソッド内で定数初期化
    # CONST = "func" # => dynamic constant assignment メソッド内で定数定義できない
  end

  include Mod
  puts CONST # => Cls1
  puts Mod::CONST # => Mod
end

# メソッドから参照
Cls1.new.func
# => Cls1
# => Top
# => Mod

class Cls2 < Cls1
  puts CONST # => Cls1

  CONST = "Cls2"
  puts CONST # => Cls2
  puts Cls1::CONST # => Cls1
  puts Mod::CONST # => Mod
end

p Cls1.ancestors # => [Cls1, Mod, Object, Kernel, BasicObject]
p Cls2.ancestors # => [Cls2, Cls1, Mod, Object, Kernel, BasicObject]

# 自クラスから探索開始。範囲演算子「::」を使用し探索開始経路を変更できる

::CONST # => トップレベルのCONSTを探す
Cls1::CONST # => Cls1クラス内のCONSTを探す
Mod::CONST # => Modモジュール内のCONSTを探す
```

**定数の初期化について**

```ruby
CONST = "a"
def foo1; p CONST; end
def foo2; p CONST = "b"; end # => dynamic constant assignment
def foo3; p CONST += "c"; end # => dynamic constant assignment
def foo4; p CONST << "d"; end

foo1 # => "a"
foo2 # 定義の段階でエラー
foo3 # 定義の段階でエラー
foo4 # => "ad" 破壊的なメソッドではないのでいけるらしいです
```

foo4の評価に関しては2、3日そんなバカなと現実として受け止める事が出来ませんでした。が、時間が経つとそれが当たり前の様に感じていた。この問題も出たので覚えてよかった。

## 【演算子】

### <=>演算子(メソッド)

既存のクラスから生成されたオブジェクト(数値や文字列)には、`<=>`演算子が定義されているが、自作したクラスのインスタンスには`<=>`演算子が定義されていないので、自作したクラス内で`<=>`メソッドを定義しないとsortメソッドなどを使用できない。

```ruby
class C
  attr_reader :num

  def initialize(num)
    @num = num
  end
end

class MyNum < C
  def <=>(other)
    @num <=> other.num
  end
end

var1 = C.new(3)
var2 = C.new(1)
var3 = C.new(2)
p [var1, var2, var3].sort.map{|n| n.num } # => `sort': comparison of C with C failed (ArgumentError)

num1 = MyNum.new(30)
num2 = MyNum.new(10)
num3 = MyNum.new(20)
p [num1, num2, num3].sort.map{|n| n.num } # => [10, 20, 30]
```

**<=>演算子(メソッド)の戻り値**

```ruby
p 1 <=> 2 # => -1
p 2 <=> 1 # => 1
p 1 <=> 1 # => 0

# 左がレシーバ　右が引数
```

| 条件 | 戻り値 |
|---|---|---|
| レシーバの方が小さい | -1 |
| レシーバの方が大きい | 1 |
| 同等 <br> ==がtrueな関係 | 0 |

---

## 【ブロック】

### 制御構文とメソッドのスコープ

**for文**

```ruby

for var in [0, 1, 2] do
    num = var
end

# 参照できる
p num # => 2
```

**eachメソッド**

```ruby
[1, 2, 3].each do |n|
  num = n
end

# 参照できない
p num # => undefined local variable or method `num'
```

**スコープを作るもの作らないものを表にまとめてみた**

| スコープを作る | スコープを作らない |
|---|---|
| loop | if |
| upto <br> downto | unless |
| times | for |
| each | while |
| each_with_index | case |

これくらい覚えとけば大丈夫。この辺はSilverでも範囲だった気がする。
メソッドのブロックはスコープを作るので、ブロック内部で初期化したローカル変数はブロック外で直接参照できない。
どういう理由でfor文は参照できて、eachメソッドはできないのかと言われたら、どなたかご存知でしたらご教授頂きたいです...。←こちらに関してはコメントでご回答を頂きました。



---

### Proc

Proc.newでブロックをオブジェクト化する。
そのオブジェクトに対して**`call`メソッドによって評価する**ということだけ覚えておけばいい。

```ruby
block = Proc.new{|x, y| p x + y }

block.call(1, 2) # => 3
```

[**こちらの記事(ブロック, Proc.new, lambda)**](https://qiita.com/ryo-ma/items/24c46592b45775e8644d)がすごくわかりやすかった。

---

### yield

```ruby
def method(arg)
  yield
  p block_given?
end

method(1) { p "Hello" }

# => "Hello"
# => true
```

[**Ruby2.1.0 リファレンス: yield**](https://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fcall.html#yield)
[**Ruby2.1.0 リファレンス: block_given?**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/block_given=3f.html)

**クロージャについて**

事前に定義している変数をブロック内で呼ぶ場合。
変数と同じ参照先の値をブロック内で更新するので、ブロック外で同じ変数の値を参照する際、値が更新されている。らしい。

```ruby
a = 1

def method
  yield
end

method { a += 1 }
p a # => 2
```

---

## 【例外処理】

### ensure節があるときの評価値

```ruby
def method
  begin
    "a"
  rescue
    "b"
  else
    "c"
  ensure
    "d"
  end
end

p method # => "c"
```

最後に評価されたrescure節、else節の値がそのbegin式の評価値になるらしい。
ensure節に関しては実行されるけど、評価値としては無視されるらしい。
教本にそんなこと書いてなかった気がするけど。

こちらの記事を参考にさせて頂きました。
[**Hatena Glog 記事**](http://tamata78.hatenablog.com/entry/2015/10/27/100000)

---

## 【大域脱出】

### catch/throw

`throw`から`catch`までジャンプする。ということだけ覚えておけばいい。

- タグ付けをして、同じタグの`catch`にジャンプする
- `throw`には、引数を渡すことができ、渡した引数を`catch`の戻り値とすることができる。

```ruby
a, b = catch :exit do
  for x in 1..10
    for y in 1..10
      throw :exit, [x, y] if x + y == 10
    end
  end
end
puts a, b

# => 1
# => 9
```

**タグ付けしないと動作しませんでした**
**catchのみ記述して、throwの代わりにその他脱出構文書いても動作はしました**

throw含め「このうち正常に動作するコードを選択しなさい(複数)」という問題は出てたと記憶しているので一応。

```ruby
a, b = catch :exit do
  for x in 1..10
    for y in 1..10
      return [x, y] if x + y == 10
    end
  end
end

a, b = catch :exit do
  for x in 1..10
    for y in 1..10
      break [x, y] if x + y == 10
    end
  end
end

a, b = catch :exit do
  for x in 1..10
    for y in 1..10
      next [x, y] if x + y == 10
    end
  end
end
```

[**Ruby2.1.0 リファレンス: 大域脱出**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/throw.html)

### その他脱出構文

| 構文 | 動作 |
|---|---|
| **return** | メソッドから抜ける |
| **break** | ループから抜ける |
| **next** | 処理を中断し次の処理を実行する |

**return**

```ruby
def foo
  return p "メソッドを抜ける" if true
  p "ここは実行されない"
end

foo # => "メソッドを抜ける"
```

**break**

```ruby
def foo
  [1, 2, 3].each do |num|
    break
    p num
  end
  p "ここは実行される"
end

foo # => "ここは実行される"
```

**next**

```ruby
def foo
  [1, 2, 3].each do |num|
    next if num == 2
    puts num
  end
end

foo
# => 1
# => 3
```

## 【引数】

### キーワード引数

```ruby
def qualification(level, rang: "Ruby")
  puts "#{rang} #{level}"
end

qualification("Gold") # => Ruby Gold
```

### 可変長引数/配列

```ruby
def func(arg, *args)
  p arg
  p args
  p *args
end

func *[1, 2, 3]

# 実行結果
1
[2, 3]
2
3
```

### 可変長引数/ハッシュ

```ruby
def func(**hash)
  p hash
  p **hash
end

func key: "val"

# 実行結果
{:key=>"val"}
{:key=>"val"}
```

**可変長引数**

- デフォルトの値は指定できない
- 1つのメソッドに対して１つしか指定できない

### ブロック引数

```ruby
def func(arg, &block)
  yield
  block.call
end

func(1){ p "ブロック引数" }

# 実行結果
{ p "ブロック引数" }
{ p "ブロック引数" }
```

`yield`でも`call`メソッドでも呼べる

[こちらの記事](https://qiita.com/rtoya/items/33617078501776fdcad7)にわかりやすくまとめてありました。
## 【ラムダ式】

試験では、「**文法**」と「`Proc.new`と`lambda`の違い」くらい覚えておけばいいと思います。

### 文法

```ruby
# lambda記法

# 書式①
lmd = lambda{ |a| p a }
lmd.call("Ruby") # => "Ruby"

# 書式②
lmd = ->(a){ p a }
lmd.call("Ruby") # => "Ruby"

# ①②どちらもProcクラスのインスタンスを生成する。
```

### Proc.newとlambdaの違い

|  | Proc | lambda |
|---|---|---|
| **引数が一致しない場合の動作** | nilを代入 | ArgumentError発生 |
| **returnの動作** | 生成元のスコープを脱出 | 呼び出し元に復帰 |

**引数が一致しない場合の動作**

```ruby
# Proc
proc = Proc.new{ |x, y| y }
p proc.call(1) # => nil 第２引数yにはnilが代入される

# lambda
lambda = ->(x, y){ y }
p lambda.call(1) # => ArgumentError 
```

**Proc.newのreturnとlambdaのreturn**

```ruby
# Procの場合
def proc_test
  proc = Proc.new{return "生成元のスコープ(メソッド)から脱出"}
  proc.call
  2 # ここは実行されない
end

p proc_test # => "生成元のスコープ(メソッド)から脱出"


# lambdaの場合
def lambda_test
  lambda = -> {return "呼び出し元へ復帰"}
  lambda.call
  2 # ここは実行される
end

p lambda_test # => 2
```

ラムダに関してはこれくらい覚えていれば大丈夫かと思いました。

[**こちらの記事(ブロック, Proc.new, lambda)**](https://qiita.com/ryo-ma/items/24c46592b45775e8644d)がすごくわかりやすかった。

## 【Objectクラス】

### method_missing

呼び出したメソッドが見つからない場合、`BasicObject`クラスの`method_missing`が呼び出され例外`NoMethodError`を発生させる

**デフォルトの定義**

- 第１引数 > 指定されたメソッド名
- 第２引数以降 > 指定された引数を渡す
- 例外`NoMethodError`を発生させる

```ruby
class C
end

p C.new.no_method

# 実行結果
undefined method `no_method' for #<C:0x00005636a82557f8> (NoMethodError)
```
Cクラスのオブジェクトには`no_method`メソッドを持っていないため、暗黙的に`method_missing`
メソッドが呼びだされ`NoMethodError`を発生させている

**method_missingの定義内容を変更してみる**

```ruby
class C
  def method_missing(name) # 引数nameには「no_method」が入る
    "メソッド #{name} は存在しません"
  end
end

p C.new.no_method

# 実行結果
"メソッド no_method は存在しません"
```

親にBasicObjectクラスを持つCクラスには、BasicObjectクラスで定義されたmethod_missingメソッドを知っている。Cクラスでそのmethod_missingの内容を書き換えてみた。
Cクラスのインスタンスには存在しないメソッドを呼ぶとCクラスで再定義したmethod_missingが呼ばれ処理を行う。

**親クラスのmethod_missingを呼んでみる**

```ruby
class C
  def method_missing(name)
    "メソッド #{name} は存在しません"
    super
  end
end

p C.new.no_method

# 実行結果
undefined method `no_method' for #<C:0x00005636a82557f8> (NoMethodError)
```

[**リファンレス: method_missing**](https://docs.ruby-lang.org/ja/2.1.0/method/BasicObject/i/method_missing.html)

---

### Object#freeze

**freezeメソッドとは**

- オブジェクトを凍結(変更を禁止)する
- 凍結されたオブジェクトの変更は**Ver2.1.0**では**RumtimeError**が発生、**Ver2.6.0**では**FrozenError**が発生
- 凍結されたオブジェクトを元に戻す方法はない
- 凍結されるのはオブジェクトであり、変数ではない
 - <font color="Red">代入などで変数の指すオブジェクトが変化するのは**freezeメソッド**では防げない</font>
 - <font color="Red">**freezeメソッド**が防ぐのは**破壊的な操作のみ**</font>。例えば**replaceメソッド**や**gsubメソッド**で変数の中身を変更しようとした場合

```ruby
var1 = "".freeze
var1 = "foo" # 代入は防げない
p var1 #=> "foo"

var1.replace("bar") # 凍結後、再代入すると破壊的メソッドで変更可能でした
p var1 # => "bar"

var1.freeze # 再度凍結
var1.replace("bar")# can't modify frozen string (RuntimeError)
```

[**リファレンス: Object#freeze**](https://ref.xaio.jp/ruby/classes/object/freeze)

---

### Object#dup

- オブジェクトを複製して返す
- オブジェクトの内容、taint情報をコピー

```ruby
a = "hoge"
# = > "hoge"

a.object_id
# => 47186718116820

b = a.dup
# => "hoge"

b.object_id
# => 47186718116580
```

---

### Object#clone

- オブジェクトを複製して返す
- オブジェクトの内容、taint情報、凍結状態(freeze)、特異メソッドをコピーする

**dupメソッド**、**cloneメソッド**での複製はシャローコピー(浅いコピー)であり、自分自身の複製しかできない。

```ruby
a = "hoge"
# = > "hoge"

a.object_id
# => 47168843196940

b = a.clone
# => "hoge"

b.object_id
# => 47168843196760
```

**dupとcloneの違いに関しての問題は出ました。**
どちらも変数の参照先まではコピーできない。

|メソッド| 概要 |
|---|---|
| **dup** | **・** オブジェクトの内容、taint情報をコピー <br> **・** 特異メソッド、凍結状態は**コピーしない** |
| **clone** | **・** 特異メソッド、凍結状態も**コピーする** |

---

### shallow copy(浅いコピー)とdeep copy(深いコピー)

|  | 概要 |
|:---:|:---|
| **shallow copy** | **・** オブジェクト自身を複製するだけ(オブジェクトの指している配列の要素までは複製しない) |
| **deep copy** | **・** Rubyでは**deep copy**を行う機能はない <br> **・** **Marshalモジュール**を用いて近いことは実現可能 **・** だが、**Marshalモジュール**が扱えないオブジェクトは複製できない |

[**リファレンス: Object#dup**](https://docs.ruby-lang.org/ja/2.1.0/method/Object/i/dup.html)

---

### Object#taint / #untaint / #tainted?

|  | 動作 |
|---|---|
| **tait** | **・** オブジェクトに汚染マークを付ける |
| **untaint** | **・** オブジェクトの汚染マークを外す |
| **tainted?** | **・** オブジェクトの汚染状態を確認する <br> **・** 汚染状態なら**true** 汚染状態ではない場合は**false**を返す |

```ruby
a = "string"
# => "string"

p a.tainted?
# => false

p a.taint
# => "string"

p a.tainted?
# => true

p a.untaint
# => "string"

p a.tainted?
# => false
```

[**リファレンス: taint**](https://docs.ruby-lang.org/ja/2.1.0/method/Object/i/taint.html)
[**リファレンス: セキュリティモデル**](https://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fsafelevel.html)

---

### Fiber
複数のタスクを切り替え、並行処理する機能

**Threadとの違い**

- **Fiber**はタスク切り替えのタイミングを**開発者がプログラム内で明示的に記述**する
- **Thread**のタスク切換えは**OSや仮想マシンが行う**

### Fiberクラスをインスタンス化して使う

```ruby
f = Fiber.new do
  (1..3).each do |i|
    Fiber.yield i
  end
  nil
end

p f.resume # => 1
p f.resume # => 2
p f.resume # => 3
p f.resume # => nil
p f.resume # FiberError(例外発生)
```

Fiber.newのブロック内の処理とそれ以外の処理を切り替えながら実行するサンプル。

- ファイバへコンテキストの切り替えは`resume`メソッドを使用する
- 対象のファイバ内の処理を終了するか`Fiber.yield`が呼ばれるまで処理を実行する
- 一回目の`f.resume`が呼び出されたタイミングで、ファイバ内に処理が移る
- `resume`の戻り値は`Fiber.yield`の引数を返す
  - なので、最初の１行目には`1`が出力される
  - 2, 3と順番に出力され`Fiber`を抜け、4回目は`nil`が出力される
- 5回目以降`resume`メソッドでファイバを呼んでも、実行する処理がないため、例外が発生する

**Fiberに関してはこれくらい覚えてれば大丈夫でした**

## 【Moduleクラス】

### class_evalとinstance_eval

[こちらの記事](https://qiita.com/y4u0t2a1r0/items/34c73d131b840c27c116)を参考にさせていただきました。

[リファレンス: class_eval](https://docs.ruby-lang.org/ja/2.1.0/method/Module/i/class_eval.html)

### Marshal

- Rubyのオブジェクトを文字列化し、ファイルに書き出し、読み戻しをする機能がある。
- 文字列化したデータを「**マーシャルデータ**」と呼ぶ
- Railsのセッション変数をクッキーやデータベースに登録するときに利用される
- 一部書き出せないクラスがある
- オブジェクト化には**Marshal.dumpメソッド**を使用する
- **Marshal.dumpメソッド**で文字列化できないオブジェクトが指定された場合は**TypeError**が発生する
- 文字列化できないオブジェクト
  - 名前のついていないクラスやモジュール。**ArgumentError**が発生
  - システムがオブジェクトの状態を保持するよな、**IOクラス、Dirクラス、Procクラス、Threadクラス**などのインスタンス
  - 特異メソッドを定義したオブジェクト
  - 上記オブジェクトを間接的に指定しているクラスのオブジェクト。初期値をブロックで指定した**Hashくクラス**のオブジェクトなど


**Rubyオブジェクトを文字列化する**

```ruby
p Marshal.dump({a: 1, b: 2, c: 5})
# 実行結果
"\x04\b{\b:\x06ai\x06:\x06bi\a:\x06ci\n"
```

2つ目の引数に**IOクラス**かそのサブクラスのオブジェクトを指定すると、そのオブジェクトに直接書き出す

**文字列化をした文字列をファイルに書き出す**

```Ruby
file = File.open("/tmp/marshaldata", "w+")
# => #<File:/tmp/marshaldata>

Marshal.dump({a: 1, b: 2, c: 3}, file)
# => #<File:/tmp/marshaldata>
```

**文字列化したマーシャルデータからRubyオブジェクトを復元する**

**Marshal.load**

```ruby
str = Marshal.dump({a: 1, b: 2, c: 3})
p str # => "\x04\b{\b:\x06ai\x06:\x06bi\a:\x06ci\b"

p Marshal.load(str) # => {:a=>1, :b=>2, :c=>3}
```

2つ目の引数に**IOクラス**かそのサブクラスのオブジェクトを指定すると、そのオブジェクトから直接読み戻す(復元)する

```ruby
file = File.open("/tmp/marshaldata", "w+")
# # => <File:/tmp/marshaldata>

Marshal.dump({a: 1, b: 2, c: 3}, file)
# # => <File:/tmp/marshaldata>

file.rewind
# => 0

p Marshal.load(file)
# => {:a=>1, :b=>2, :c=>3}
```



### Refinements

指定したクラス/モジュールに対して`refine`メソッドを使い変更を加える宣言をし、`using`メソッドで呼び出した以降から`reifne`メソッドで変更した内容を適用する

**usingの有効範囲**

- クラス/モジュール定義の外で`using`呼び出した場合は、ファイルの末尾まで
- クラス/モジュール定義の中で`using`を呼び出した場合は、そのクラス/モジュールの末尾まで
- `using`はメソッドの中で呼び出すことはできない。呼び出した場合`RuntimeError`が発生
- `using`を２行書いたとしても１つのメソッドで有効になる再定義は１つだけ。最後に書いた`using`が優先される

**refine/usingで制限してみる**

```ruby
class C
  def hoge
    puts "hogeを定義"
  end
end

module M
  refine C do
    def hoge
      puts "hogeの内容を変更: 変更を有効にしました"
    end
  end
end

c = C.new
c.hoge

using M

c.hoge

# 実行結果
hogeを定義
hogeの内容を変更: 変更を有効にしました
```

[**リファレンス: Refinements**](https://docs.ruby-lang.org/ja/2.1.0/method/Module/i/refine.html)

---

### include
- モジュールで定義したメソッドを**インスタンスメソッド**として追加する
- `include`したクラスより後に探索される

```ruby
module M
  def foo
    puts "foo"
  end
end

class C
  include M # モジュールMのメソッドをインスタンスメソッドとして追加
end

C.new.foo  # => foo
C.foo  # => NoMethodError

# 継承チェーン
p C.ancestors # => [C, M, Object, Kernel, BasicObject]
```

### prepend
- モジュールで定義したメソッドを**インスタンスメソッド**として追加する
- `prepend`したクラスより先に探索される

```ruby
module M
  def foo
    puts "foo"
  end
end

class C
  prepend M
end

# 継承チェーン
# prependを呼び出したクラスよりも先に定義
p C.ancestors # => [M, C, Object, Kernel, BasicObject]
```

### includeとprependの違い

どちらもモジュールのメソッドをクラスに取り込むが

| include | クラスの次に呼び出したモジュールをメソッド探索する |
|---|---|
| **prepend** | **クラスよりも前に呼び出したモジュールからメソッド探索する** |

```ruby
module M
    def method
        "1"
    end
end

class C1
  prepend M
  def method
      "2"
  end
end

class C2
    include M
    def method
        "3"
    end
end

p C1.new.method
p C2.new.method

# 実行結果
"1"
"3"
```

### extend

- モジュールで定義したメソッドを**特異メソッド**として追加する

```ruby
module M
  def foo
    puts "foo"
  end
end

class C
  extend M # モジュールMのメソッドをクラスメソッドとして追加
end

C.new.foo  # => NoMethodError
C.foo  # => foo
```

オブジェクト**にMix-in**

```ruby
module M
  def f
    puts "Hello"
  end
end

class C
end

c = C.new
c.extend(M)
c.f

# 実行結果
Hello
```

**継承チェーン**

```ruby
module M
end

class C
    extend M
end

p C.ancestors

# 実行結果
[C, Object, Kernel, BasicObject]
```

### Module#ancestors

- **Moduleクラス**のインスタンスメソッド
- クラス、モジュールのスーパークラスとインクルードしているモジュール を優先順位順に配列に格納して返します。
- レシーバが**Moduleクラスのインスタンス**か**classクラスのインスタンス**の場合に有効


```ruby
module M1
end

module M2
end

class Cls1
  include M1
end

class Cls2 < Cls1
  def foo
    p self.ancestors
  end
  include M2
end

Cls2.new.foo

# 実行結果
undefined method `ancestors' for #<Cls2:0x0000557a3e210710> (NoMethodError)
```

---

### append_features

**append_featuresを上書きする場合はsuperを書かないとincludeされない**



```ruby
module M
  def self.append_features(include_class_name)
    puts "append_features"
    super # このsuperを書かないとエラー発生
  end
  def func
    p "Hello World"
  end
end

class C
  include M
end

C.new.func

```

[**リファレンス: append_features**](https://ref.xaio.jp/ruby/classes/module/append_features)

---

### undef_method

- クラスやモジュールの**メソッドを未定義にして、呼び出せなくする。**
- 引数にメソッド名をシンボルか文字列で指定する(複数指定可)
- 戻り値はクラスやモジュール自身

```ruby
class C
  def func
    puts "Hello"
  end
end

c = C.new

c.func # => Hello

# class_evalメソッド
# ブロックをクラス定義やモジュール定義の中のコードであるように実行します。 
C.class_eval { undef_method :func }

c.func # => undefined method `func' for #<C:0x000056370fe002a8> (NoMethodError)
```

親クラスのメソッドをサブクラスで未定義にした場合は、`undef_method`を**呼び出したクラス**と**そのサブクラス**でメソッドを呼び出せなくなる。
ただし、**親クラスのメソッドには影響しない。**

```ruby
class C
    def func; puts "Hello"; end
end

class Child < C
    undef_method :func
end

class GrandChild < Child
end

C.new.func # => Hello
Child.new.func # => NoMethodError
GrandChild.new.func # => NoMethodError
```

### remove_method

- クラスやモジュールから**メソッドを削除**する
- 引数にはメソッド名をシンボルか文字列で指定する（複数指定可）
- 戻り値はクラスやモジュール自身

```Ruby
class C
    def func; puts "Hello"; end
end

C.class_eval { remove_method :func }

puts C.new.func

# 実行結果
undefined method `func' for #<C:0x000055b9766f5128> (NoMethodError)
```

- 削除できるのはそのクラス・モジュールで定義されたメソッドだけ
- 親クラスのメソッドは指定できない
- 削除したメソッドと同名のメソッドが親クラスにある場合は、親クラスのメソッドが呼び出される

```ruby
class C
    def f; puts "World"; end
end

class Child < C
    def f; puts "Hello"; end
end

child = Child.new
puts child.f

Child.class_eval { remove_method :f }

puts child.f
```

---

### alias_methodとalias

| メソッド名 | 概要 |
|---|---|
| **alias_method** | 引数に指定するメソッド名は**String**か**Symbol**で指定する |
| **alias** | 引数のメソッド名は**識別子**か**Symbol**で指定する |

```ruby
# 書式
alias_method 新メソッド名 旧メソッド名
alias 新メソッド名 旧メソッド名
```

**alias_methodの定義例**

```ruby
class String
  alias_method :hoge, :reverse
end

p "12345".hoge

# 実行結果
"54321"
```


**aliasの定義例**

```ruby
class String
  alias :hoge :reverse
end

p "12345".hoge

# 実行結果
"54321"
```

---

### const_missing

`metheod_missing`の定数版

```ruby
class Foo
  def self.const_missing(name)
    "定数 #{name} はありません"
  end
end

p ::Foo::C

# 実行結果
"定数 C はありません"
```

[**リファレンス: const_missing**](https://docs.ruby-lang.org/ja/2.1.0/method/Module/i/const_missing.html)

## 【karnelクラス】

### pとputsとprint

**内部動作に関して。**

| メソッド | 動作 |
|---|---|
| **p** | inspectメソッドが呼び出される | 
| **puts** | to_sメソッドが呼び出される |
| **print** | to_sメソッドが呼び出される |

**【例外】**
`+`メソッドなどで文字列を連結する場合は、`to_str`メソッドが呼び出される

[**リファンレス: p**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/puts.html)
[**リファレンス: puts**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/puts.html)
[**リファレンス: print**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/print.html)
[**リファレンス: to_str**](https://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_str.html)

```ruby
class C
  def initialize(str)
    @str = str
  end
  
  def inspect
    "inspect"
  end
  
  def to_s
    "to_s"
  end
  
  def to_str
    "to_str"
  end
end

p C.new ""             # => inspect
p "#{ C.new("") }"     # => "to_s"
p "" + C.new("")       # => "to_str"

puts C.new ""          # => to_s
puts "#{ C.new("") }"  # => to_s
puts "" + C.new("")    # => to_str

print C.new ""         # => to_s
print "#{ C.new("") }" # => to_s
print "" + C.new("")   # => to_str
```

---

### eval

そのままですが。

```ruby
a = nil
eval('a = RUBY_RELEASE_DATE')
p a #=> "2007-03-13"

eval('def fuga;p 777 end')
fuga #=> 777
```

[リファレンス: eval](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/eval.html)

### exit

- Rubyプログラムの実行を即座に終了させる
- 例外**SystemExit**を発生させる
- **`exit`**は例外として補足できる
- **`exit!`**は例外として補足できない

[**リファレンス: karnel#exit/exit!**](https://docs.ruby-lang.org/ja/2.1.0/method/Kernel/m/exit=21.html)

```ruby
def proc_exit
  begin
    exit
  rescue SystemExit
    puts "processing_exit"
  ensure
    puts "確保する"
  end
end

proc_exit

# 実行結果
processing_exit
確保する
```

### exit!

```ruby
def proc_exit!
  begin
    exit!
  rescue SystemExit
    puts "processing_exit"
  ensure
    puts "確保する"
  end
end

proc_exit! # =>処理を強制終了し、rescue節、ensure節の処理は通らない
```

---

## 【Enumerableクラス】

- メソッドの**遅延評価版**を提供するためのクラス

|以下のメソッドが遅延評価を行う|
|---|
|map/collect|
|flat_map/collect_concat|
|select/find_all|
|reject|
|grep, grep_v|
|take, take_while|
|drop, drop_while|
|slice_before, slice_after, slice_when|
|chunk, chunk_while|
|uniq|
|zip (※互換性のため、ブロックを渡さないケースのみlazy)|

### Enumerable#lazy

```ruby
a = [1, 2, 3, 4, 5].lazy.select { |e| e % 2 == 0 }
#<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3, 4, 5]>:select>

b = a.map { |e| e * 2 }
#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3, 4, 5]>:select>:map>

c = a.take(3)
#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3, 4, 5]>:select>:take(3)>

p c.to_a # ここで評価される
# => [2, 4]
```

[**リファレンス: Enumerable#lazy**](https://docs.ruby-lang.org/ja/2.1.0/class/Enumerator=3a=3aLazy.html)

## 【Arrayクラス】

### Array#push

- 配列の**末尾に**引数を要素として**追加**する
- 破壊的

```ruby
arr = [1, 2]
arr.push(3)

p arr

# 実行結果
[1, 2, 3]
```

---

### Array#pop

- 末尾の要素を取り出す/取り除く
- 破壊的

```ruby
arr = [1, 2, 3]
puts arr.pop # 取り出し/取り除き

p arr # 内容を変更された

# 実行結果
3
[1, 2]
```

---

### Array#shift

- 配列の先頭の要素を取り出す/取り除く返す
- 破壊的

```ruby
arr = [1, 2]
puts arr.shift

p arr

# 実行結果
1
[2]
```

---

### Array#unshift

- 引数を配列の先頭に追加する
- 破壊的

```ruby
arr = [1, 2]
arr.unshift(3)

p arr

# 実行結果
[3, 1, 2]
```

## 【Comparableクラス】

- インクルードしたクラスで比較演算子である<=>を元にオブジェクト同士の比較ができるようになる

| メソッド | <=>演算子の返り値 |
|---|---|
| **<** | 負の整数 |
| **<=** | 負の整数か0 |
| **==** | 0 |
| **>** | 正の整数 |
| **>=** | 正の整数か0 |
| **between?** | --- |

※この辺は[**リファレンス**](https://docs.ruby-lang.org/ja/2.1.0/class/Comparable.html)見たほうがわかりやすかった

### 自作クラスを定義してみる

```Ruby
class Sample
  def initialize(value)
    @value = value
  end
  
  def value
    @value
  end
  
  def <=>(other)
    other.value <=> self.value
  end
end
```

### 自作クラスにComparableモジュールをインクルードしてみる

```ruby
class Sample
  include Comparable

  def initialize(value)
    @value = value
  end
  
  def value
    @value
  end
  
  def <=>(other)
    other.value <=> self.value
  end
end

a = Sample.new(10)
#<Sample:0x000055c4a9f0cd00 @value=10>

b = Sample.new(5)
#<Sample:0x00005576e2290348 @value=5>

a < b
# => true

a <= b
# => true

a == b
# => false

a > b
# => false

a >= b
# => false
```

---

## 【数値】

### RationalとComplexの演算

```ruby
a = 1 + "(1/2r)".to_r
p a.class # => Rational

a = a + 1.0
p a.class # => Float

a = a + "(1/2r)".to_r
p a.class # => Float

a = a + "(1 + 2i)".to_c
p a.class # => Complex
```

## 【正規表現】

### 正規表現オブジェクト生成

```ruby
/Ruby Gold/             # => /Ruby Gold/
%r|Ruby Gold|           # => /Ruby Gold/
Regexp.new("Ruby Gold") # => /Ruby Gold/
```

### 文字列との比較

[特殊変数のところ](#特殊変数)でもふれたけど。`()`内にマッチした部分がグローバル変数に代入されるらしいです。って教本に書いているけどこれ覚えてたら点取れます。

| 変数名 | 参照される値 |
|---|---|
| **$0**| 実行中のファイル名| |
| **$1** 〜 **$n**| n番目のカッコにマッチする文字列 |

```ruby
%r|(https://www(\.)(.*)/)| =~ "https://www.qiita.com/"

p $1 # => "https://www.qiita.com/"
p $2 # => "."
p $3 # => "qiita.com"
```

### 後方参照

「マッチした文字列の前後」と「マッチした文字」を参照する、**正規表現の後方参照**と呼ぶものらしいです。


```ruby
%r|Ruby| =~ "u"

p $` # => "R"
p $& # => "u"
p $' # => "b"
```

### 正規表現記号

一応載せておきます
本に書いているけど、スマホで片手でっていう趣旨も一応ありますし...

| 記号 | 意味 |
|---|---|
| **.** | 改行以外の文字。 <br> mオプション指定の場合は改行にもマッチする |
| **\d** | 数字 |
| **\D** | 数字以外 |
| **\w** | 英数字とアンダースコア |
| **\W** | 英数字とアンダースコア以外 |
| **\s** | 空白文字(\t, \n, \r, \f) |
| **\S** | 空白以外 |
| **\A** | 先頭の文字(改行無視) |
| **\z** | 末尾の文字(改行無視) |
| **\Z** | 末尾の文字(改行にもマッチ) |
| **`*`** | 直前の文字の0回以上の繰り返し | /a*b/ | "ab" <br> "aab" <br> "aaab" |
| **+** | 直前の文字の1回以上の繰り返し | /a+b/ | "aab" <br> "aaab" |
| **{m}** | 直前の文字のm回の繰り返し | /a{2}b/ | "aab" |
| **{m,}** | 直前の文字の最低m回の繰り返し | /a{2,}b/ | "aab" <br> "aaab" <br> "aaaab" |
| **{m, n}** | 直前の文字の最低m回、最高n回の繰り返し | /a{2,3}b/ | "aab" <br> "aaab" |

**オプションも**

| オプション | 意味 |
|---|---|
| **i** | 大文字小文字を区別しない |
| **o** | 一度だけ式展開を行う |
| **x** | 空白と改行を無視する <br> #以降をコメントとして無視する |
| **m** | 記号「.」が改行にマッチする(複数行モード) |

---

## 【JSON】

**書き方**

```ruby
--- # 配列["red", "green", "blue"]

# JSONの表現
["red", "green", "blue"]

--- # ハッシュ{"country" => "japan", "state" => "tokyo"}

# JSONの表現
{"country": "japan", "state": "tokyo"}
```

### JSONの読み込みに使用するメソッド一覧

| メソッド | 動作 |
|---|---|
| **load** | 文字列からJSONを読み込む |
| **parse** | 文字列からJSONを読み込む |

---

**load**

| メソッド | 動作 |
|---|---|
| **load** | **・** 文字列からJSONを読み込む <br> **・** 文字列以外も**指定可能** |

```ruby
JSON.load(source, proc = nil)
```

- **`source`**にはJSON形式の文字列を指定する
- **to_str**, **to_io**, **read**などのメソッドを持つオブジェクトであれば文字列以外も指定できる
- **`proc`**には、要素を読み込むごとに呼び出される**Procオブジェクト**を渡すことができる

```ruby
require 'json'

json = <<-DATA
["Red", "Green", "Blue"]
DATA

p JSON.load(json)

# 実行結果
["Red", "Green", "Blue"]
```

**proc指定**

```ruby
require 'json'

json = <<-DATA
"Red"
"Green"
"Blue"
DATA

p JSON.load(json, lambda{|x| p x})

# 実行結果
["Red", "Green", "Blue"]
```


**文字列からJSONを読み込む**

```ruby
require 'json'

JSON.load(File.open(""data.json))
# 実行結果
["Red", "Green", "Blue"]
```

---

| メソッド | 動作 |
|---|---|
| **parse** | **・** 文字列からJSONを読み込む <br> **・** 文字列以外は**指定不可** |


**書式**

```ruby
JSON.parse(source, options = {})
```

- **options**には解釈するときのオプションを指定
 - [リファレンス: オプションなど](https://docs.ruby-lang.org/ja/2.1.0/class/JSON.html)

---

### JSONの書き込みに使用するメソッド

| メソッド | 動作 |
|---|---|
| **dump** | JSONの書き込み |

```Ruby
JSON.dump(obj, io = nil, limit = nil)
```

- **`obj`**に書き出したい対象のオブジェクト(書き出し元)を指定
- 文字列で結果を得たい場合は第２引数、第３引数を省略する
- ファイルに書き出したい場合は**`io`**にIOオブジェクトを指定する
- **`limit`**以上深くリンクしたオブジェクトをダンプしようとすると**ArgumentError**が発生する

```Ruby
require 'json'

array = ["Red", "Green", "blue"]

JSON.dump(array)

# 実行結果
"[\"Red\",\"Green\",\"blue\"]"
```

**ファイルに書き出したい場合**

```Ruby
require 'json'

array = ["Red", "Green", "blue"]

File.open("dump.json", "w") do |f|
  JSON.dump(array, f)
end
```

**to_jsonメソッド**

- 自身を JSON 形式の文字列に変換して返します
- 内部的にはハッシュにデータをセットしてから**Hash#to_json**を呼び出しています。

```ruby
require 'json'

h = {"a" => 1, "b" => 2}

p h.to_json
# => "{\"a\":1,\"b\":2}"

p to_json(h)
# => "\"main\""
```

[**リファレンス: to_jsonメソッド**](https://docs.ruby-lang.org/ja/2.1.0/method/Time/i/to_json.html)

## 【yaml】

```ruby
require 'yaml'

**書き方**

--- # 配列["red", "green", "blue"]

# yamlの表現
- red
- green
- blue

---# ハッシュ{"country" => "japan", "state" => "tokyo"}

# yamlの表現
country: japan
state: tokyo
```

### 読み込みメソッド一覧

| メソッド | 動作 |
|---|---|
| **load** | **・** YAMLデータが記録された文字列または**IO**インスタンスからHashクラスのインスタンスを生成 <br> **・** 文字列またはIOに複数の**YAML**記録されていても**最初のYAML**のみが生成され、残りは無視 |
| **load_file** | 引数に指定したパスのYAMLファイルからオブジェクトを生成。 <br> **・** 文字列またはIOに複数の**YAML**記録されていても**最初のYAML**のみが生成され、残りは無視 |
| **load_stream** | 引数のオブジェクトに記録された複数のYAMLデータを順番にロードし、結果を**YAML::Stream**のインスタンスで返す |
| **load_documents** | 引数のオブジェクトに記録された複数のYAMLデータを順番にロードし、それぞれをブロック内で処理する |

---

**YAML.load**

| メソッド | 動作 |
|---|---|
| **load** | **・** YAMLデータが記録された文字列または**IO**インスタンスからHashクラスのインスタンスを生成 <br> **・** 文字列またはIOに複数の**YAML**記録されていても**最初のYAML**のみが生成され、残りは無視 |

```ruby
require 'yaml'

yaml_data = <<-DATA
- red
- green
- blue
---
- yellow
- pink
- white
DATA

p YAML.load(yaml_data)

# 結果
["red", "green", "blue"]
```
---

**YAML.laod_file**

| メソッド | 動作 |
|---|---|
| **load_file** | 引数に指定したパスのYAMLファイルからオブジェクトを生成。 <br> **・** 文字列またはIOに複数の**YAML**記録されていても**最初のYAML**のみが生成され、残りは無視 |

```ruby
require 'yaml'

YAML.load_file "sample.yml"

# 結果
["red", "green", "blue"]
```
---

**YAML.load_stream**

| メソッド | 動作 |
|---|---|
| **load_stream** | 引数のオブジェクトに記録された複数のYAMLデータを順番にロードし、結果を**YAML::Stream**のインスタンスで返す |

```ruby
require 'yaml'

yaml_stream = YAML.laod_stream(File.open "sample.yml")

p yaml_stream

# 結果
[["red", "green", "blue"], ["yellow", "pink", "white"]]
```
---

**YAML.load_documents**

```ruby
require 'yaml'

YAML.load_documents(File.open "sample.yml") do |yaml|
  p yaml.first
end

# 結果
"red"
"yellow"
```
---

### 書き込みメソッド一覧

| メソッド | 動作 |
|---|---|
| **dump** | **・** 単一のインスタンスを文字列またはIOインスタンスに出力する <br> **・** 引数を省略すると**yaml形式** に変換した文字列を返し、引数を指定すると指定した出力先に**yaml形式**のデータを書き込む |
| **dump_stream** | 複数のオブジェクトを文字列に出力する |

---

**YAML.dump**

| メソッド | 動作 |
|---|---|
| **dump** | **・** 単一のインスタンスを文字列またはIOインスタンスに出力する <br> **・** 引数を省略すると**yaml形式** に変換した文字列を返し、引数を指定すると指定した出力先に**yaml形式**のデータを書き込む |

```ruby
require 'yaml'

# ===== 引数を省略した場合 =====

colors = ["red", "green", "yellow"]

YAML.dump colors

# 結果
"---\n- red\n- green\n- yellow\n"


# ===== 引数を指定した場合 =====

File.open("sample.yml", "w+") do |f|
  YAML.dump(colors, f)
end

# 結果
---
- red
- green
- blue
```
---

**YAML.dump_stream**

| メソッド | 動作 |
|---|---|
| **dump_stream** | 複数のオブジェクトを文字列に出力する |

```Ruby
require 'yaml'

# ===== 引数を省略した場合 =====

colors1 = ["red", "green", "yellow"]
colors2 = ["yellow", "pink", "white"]

YAML.dump_stream colors1, colors2

# 結果
"---\n- red\n- green\n- yellow\n---\n- yellow\n- pink\n- white\n"
```

## 【Socket】

### クラス図

Scoketライブラリに関しては、クラス名に**server**と付くものは「TCPS」「UNIX」ということを覚えておくだけで点が取れました。
全て覚えることは僕の記憶力ではちょっと無理でした...というかそこに注力するなら他のところにとも思うし。実際に試験で出た問題を模したものを後述しておきます。

![スクリーンショット 2019-06-25 23.04.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320855/ed4a4ec7-385f-9691-4609-37c09fcc1c1e.png)

### 模擬問題

```
socketライブラリについて正しい記述を選択しなさい(2つ)
1. socketライブラリにTCPSocketというクラスは存在する
2. socketライブラリにTCPServerというクラスは存在する
3. socketライブラリにUNIXServerというクラスは存在しない
4. socketライブラリにBasicServerというクラスは存在する

正解 1, 2
```

実際にこのパターンの問題が出ました。
[**ITトレメ**](https://jibun.atmarkit.co.jp/scenter/ittrain/121_today_q.html)や教本にもSocketの問題が数問あるのでそちらを解いておくだけで大丈夫だと思います。

## 【Date】

### クラス図

![スクリーンショット 2019-06-28 19.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320855/6c56c526-492c-30d1-80ca-8400156e777b.png)

### 日付の加減算

DateTimeクラス、Timeクラスもついでに。

**同クラスインスタンス同士の減算**

```ruby
require 'time'
require 'date'

time = Time.now
day = Date.new(2019)
datetime = DateTime.new

p (time - time).class         # => Float
p (day - day).class           # => Rational
p (datetime - datetime).class # => Rational
```

**日付の加減算**

```ruby
require "date"
require "time"

# Dateクラス
date = Date.new(2000, 1, 1)
puts date + 1
puts date >> 1
# => 2000-01-02
# => 2000-02-01

# DateTimeクラス
datetime = DateTime.new(2000, 1, 1)
puts datetime + 1
puts datetime >> 1
# => 2000-01-02T00:00:00+00:00
# => 2000-02-01T00:00:00+00:00

# Timeクラス
time = Time.new(2000, 1, 1, 0, 0, 0)
puts time + 1
# Timeだけ秒単位
# => 2000-01-01 00:00:01 +0000
```

日付の加減算は実際に出ました。2、３問取れた気がする。
`<<`、`>>`の演算結果は大なり小なりの関係で覚えたら覚えやすかったです。

- `date << 1`なら**dateより1小さいので1ヶ月前**
- `date >> 1`なら**dateより1大きいので1ヶ月後**

のように。って教本にも書いてあったようななかったような。小さいかったらなんで1ヶ月前になんねんという疑問もありつつ感覚的に覚えやすかったのでとしか...すみません。

## 【StringIO】

StringIOに関しては問題を解くだけでほとんど何も学習してません。ので、何も述べることができませんが、下記のような問題パターンは出題されました。というかStringIOの問題は下記のような問題パターンしか見たことありません。ので、StringIOについては下記のような問題パターンに答えれるようにしておくぐらいにして、あとは他に注力すべきだと思いました(試験を受けた所感)。なので問題だけ載せておきます。

```
stringioライブラリの説明として正しいものを選択しなさい。

文字列をファイルに読み書きすることができる
文字列をファイル入出力専用で扱うことができる
StringIOクラスはIOクラスのサブクラスである
文字列をIOオブジェクトのように扱うことができる

正解 4
```

## 【Thread】

**覚えること**

- Thread作成メソッド
- ライフサイクル
- 例外時の挙動

### スレッドを作成する

**スレッド作成メソッド**

- `Thread#new`
- `Thread#fork`
- `Thread#start`

引数に必ずブロックを渡す必要がある。
引数にブロックを指定しないと`Thread`は作成できず、`ThreadError`を返す

```ruby
Thread.new { 'Hello, World' }
Thread.fork { 'Good Morning World' }
Thread.start { 'Good Evening World' }

p Thread.list

[#<Thread:0x000055d8bd4c4b68 run>, #<Thread:0x000055d8bd7b04d0@Main.rb:1 dead>, #<Thread:0x000055d8bd7b0368@Main.rb:2 dead>, #<Thread:0x000055d8bd7b0250@Main.rb:3 run>]
```

### スレッドの状態(ライフサイクル)

- スレッドには５つの状態がある

**例**

```
<Thread:0x00007fdf4c154860@code11.rb:3 run> 末尾の「run」がそのスレッドの状態を表す
```

| 状態 | 意味 |
|---|---|
| **run** | 【**実行可能**または**実行中**】 <br> **生成直後**、**Thread#run**、 **Thread#wakeup**で起こされたスレッドはこの状態になる |
| **sleep** | 【**停止中**】 <br> **Thread#stop**や**Thread#join**により一時的に停止されたスレッドはこの状態になる |
| **aborting** | 【**終了処理**】 <br> **`Thread#kill`**などで終了されるスレッドは一時的にこの状態になる |
| **false** | 【正常に終了した】**Thread#kill**で終了したり、正常終了したスレッドの場合**`false`**が返る |
| **nil** | 例外などで終了した場合は**`nil`**が返る |
| **dead** | 【終了状態】 <br> **`Thread#kill`**等で終了したスレッドはこの状態になる。この状態のスレッドはどこからも参照されていなければ**`GC`**によりメモリ上からなくなり、この状態のスレッドは「死んで」いる |

### 例外時の挙動

マルチスレッドで例外が発生し、その例外が**rescueで補足されなかった場合**、例外が発生したスレッドだけが**警告なしで終了**し、**他のスレッドは実行を続ける**。

**例外は発生するが、メッセージは出力せず停止状態になる**ということ。

**-dオプション**を付けると**デバッグモード**で実行され、いずれかのスレッドで例外が発生した時点で**メッセージを出力**しインタプリタ全体が**中断する**

```ruby
t1 = Thread.start do
    raise ThreadError
end

loop {
    n = rand(0..3)
    puts n
    if n == 0
        break
    end
}
```

ということを覚えていたら点が取れました。

## 【メソッドの可視性】

### public / protected / privateの振る舞い

| 可視性 | 振る舞い |
|---|---|
| **public** | **どのインスタンスからでも**実行できる |
| **protected** | **自分自身**または**サブクラスのインスタンスから**実行できる |
| **private** | **レシーバを付けた呼び出しはできない** |

### public

```ruby
class C
  def call_method
    public_1
  end
  
  def with_receiver
    self.public_1
  end

  def public_1; "public_1"; end

  public

  def public_2; "public_2"; end
end

p C.new.public_1 # => "public_1"
p C.new.public_2 # => "public_2"
p C.new.call_method # => "public_1"
p C.new.with_receiver # => "public_1"
```

### protected

```ruby
class C
  def call_protected
    protected_method
  end
  
  def with_receiver
    self.protected_method
  end

  protected

  def protected_method; "protected"; end
end

p C.new.protected_method # => NoMethodError
p C.new.call_protected # => "protected"
p C.new.with_receiver # => "protected"
```

### private

```ruby
class C
  def call_private
    private_method
  end
  
  def with_receiver
    self.private_method # ここでNoMethodError発生
  end
  
  private

  def private_method; "private"; end
end

p C.new.call_private # => "private"
p C.new.private_method # => NoMethodError
p C.new.with_receiver # => # NoMethodError
```

### 可視性の変更

- メソッドの可視性はサブクラスで自由に変更できる

```ruby
class C
  def method_1; end
  def method_2; end

  private

  def method_3; end
end

class Child < C
  public :method_3
  protected :method_1
  private :method_2
end

p C.new.public_methods(false) # => [:method_1, :method_2]
p C.new.protected_methods(false) # => []
p C.new.private_methods(false) # => [:method_3]
p Child.new.public_methods(false) # => [:method_3]
p Child.new.protected_methods(false) # => [:method_1]
p Child.new.private_methods(false) # => [:method_2]
```

## 【クラスの継承】

> スーパークラスを省略してクラスを定義すると、自動的にObjectクラスを継承する。
つまりCクラスはObjectクラスを継承している。(合格教本p 125から引用)

```ruby
class C
end

class Child < C
end
p C.ancestors # => [C, Object, Kernel, BasicObject]
p Child.ancestors # => [Child, C, Object, Kernel, BasicObject]
```

## 【マーシャリングについて】

**マーシャリングとは**

- 異なる２つのシステム間で、データを交換できるようにデータを操作する処理。
- 例えば、JavaとC言語のデータ型の違いを吸収するために、データの型を変換するなどの処理のこと

### マーシャリングできないもの

- 無名クラス/モジュール
- システムがオブジェクトの状態を持つもの
  - Dir, File, IO, Socket等
- 特異メソッドを定義したオブジェクト

### マーシャリングできるもの

- ユーザーが作成したオブジェクトなど。
- マーシャリングできないものとして定義しているもの以外のもの

たぶん**「マーシャリングできるのはユーザーが作成したオブジェクトなど」**ということだけ覚えていれば1問解ける。

---

## 【参考】

こちらの記事の特に「Ruby Gold受けた人たちの復習ブログで知識を補う」は「合格教本ではわからない内容」かつ「試験で役に立つ内容」がたくさん載っていました。ので、見ておいて損はないと思います。

[**Ruby Gold 試験範囲を一気に見直す**](http://tamata78.hatenablog.com/entry/2015/11/03/101002)