Ruby技術者認定試験 Goldの直前に振り返っておきたいところ

# 最初に

Ruby技術者認定試験 Goldを受けて、合格しました。

本番では多数の問題が、合格教本の問題と同じか類題でした。
勉強方法として合格教本とRExを解けるように勉強していけば、十分だと思います。

合格できた体験から、直前で振り返っておきたいこと等をまとめました。

# 合格教本 Gold 演習問題 基礎力確認問題 30問

「合格教本」の第8章「Gold 演習問題」の「基礎力確認問題 30問」から、
自分が使わないので覚えにくいところを中心に直前に見直したいものをまとめました。

あと、同じ問題が出題されたと書いてるところがありますが、
問題を持ち帰れないため、そう思っただけで、ちゃんと比較したら違うかもしれません。

- `-I`オプション(全く同じ問題が本番で出題)
  - 引数で指定したディレクトリを、変数`$LOAD_PATH`(配列)に追加する。
  - 環境変数`RUBYLIB`も、変数`$LOAD_PATH`(配列)に追加する。
  - ただし、`-I`オプションでの指定が、環境変数`RUBYLIB`に追加されるわけではない。
  - 引数で指定したディレクトリは、`require`や`load`が呼ばれたときに検索される
- 多重代入(左辺に複数の引数)で、右辺の配列は`*`をつけなくても展開される。
  - 多重代入で、右辺が1つの配列なら`*`はあってもなくてもいい。
    - 右辺が1つの配列で、左辺の方の変数が複数だと、親切に配列の`[]`を外してくれる。
  - 変数側が多い場合、不足は`nil`が代入される。  
    `x, y, z = [1, 2]`で、`z`は`nil`に。  
    この左辺の変数が多いケースが出題された。
- メソッド内での、定数の代入・更新は、文法エラー。
  - これは、コードから「どこでエラーになるか」という形で本番で出題された。
  - なお、refinementの`using`は、メソッド内で使えず、メソッド内で呼び出すと実行時エラー。
      - `using`はトップレベル以外でも使え、使ったスコープ内で適用される。 
- メソッド呼び出しの引数の記法
  - メソッドのブロックを`{}`で囲む場合は、普通の引数の`()`を省略できない。
  - メソッドのブロックを`do`と`end`で囲む場合は、普通の引数の`()`を省略できる。
  - 問題6は、同じ問題が出題された。
- `catch`と`throw`の第1引数は、tag。第1引数が必須。
  - `throw`の第2引数は、返り値。任意。任意なのが第2引数。
  - 本番で、第1引数がある選択肢が1つしかなかったので、余裕でした。
- 問題13と同じ問題があったし、問題14や問題18みたいなのも普通に出題されてた。 
- refinementは、`using`で適用。
  - 本番で問題20と同じ問題があった。`using`を選ぶだけの問題。
- `map`と`collect`は、エイリアス。Silverレベルの基本。
  - 本番でも問題24と似たような問題がでた。選択肢が微妙に違ったり。
- `(1..Float::INFINITY)`で、基本は整数が無限ループ。
  - 始点が`Integer`なら、終端が`Float`でも動く。
  - `lazy`で遅延処理。
  - 問題24は、同じ問題が本番で出題。
- Fiber
  - `Fiber.new`, `Fiber.yield`, `Fiber#resume`の名前と基礎的な使い方を覚える。
  - 本番では、`resume`を選ばせる問題が出題された。
- `Test::Unit`のテストメソッド名は、`test_`で始める。
  - `test_foo`で｢fooをテストする｣って感じなのだと思う。 
- `socket`ライブラリ：
    - あるクラス……`UDPSocket`, `BasicSocket`, `TCPSocket`
    - ないクラス……`BasicServer`, `UDPServer`
- `Date`, `DateTime`クラスは、`+ 1`で1日後、`>> 1`で1ヶ月後。
  - なお、`Time`クラスは、`+ 1`で1秒後、`>>`は存在しないメソッド。 
  - `Date`の`+`を選ぶ問題が、本番で出題されました。
- `Thread` 
  - `Thread.start`と`Thread.fork`は、エイリアス。
  - `new`, `start`, `fork`は、新しいスレッドを作成する。
      - `new`のみ、(一般的な`new`と同じで)`initialize`を呼び出す。
  - `Thread#run`はあるが、`Thread.run`はない。
      - `Thread#run`は、スレッドを再開する。
- `open-uri`ライブラリは、`Kernel`の`open`を再定義する(2.1時代の挙動)
  - 【余談】少なくとも今の3.0では`URI.open`等を使うべき。
  - ライブラリ名が本番で問われました！  
    誤答は`net/http`, `uri`, `open-http`



# 合格教本 Gold 演習問題 模擬試験 50問

「合格教本」の第8章「Gold 演習問題」の「模擬試験 50問」から、
自分が使わないので覚えにくいところを中心に直前に見直したいものをまとめました。

- `Integer`同士の割り算は、切り捨てられて`Integer`になる。
  基本だよね。本番で出題された。
- 親クラスでprivateなメソッドを、子クラスのみpublicに変更できる。
  2問ほど本番で出題された。
- `NoMethodError`は、`NameError`の子クラス。
  - 余談だが、`NameError`の子クラスは、他にないみたい。
- `extend`の挙動。`include`や`prepend`との違い。
  - 問題14の`extend`を選ぶだけの問題も、本番で出題されてた。 
- クラス内やメソッド内で`self`が何になるか。
  - メソッド内での`self`は、原則レシーバ。
  - 問題15は、同じ問題が本番で出題されてた。
- `exit`は、`SystemExit`という例外を発生。  
  - 実は、`SystemExit`を`rescue`すれば、プログラムは継続する。
  - `SystemExit`は、`Exception`の子クラスであり、`StandardError`の子孫ではない。
- stringioライブラリ。
  - 文字列を`IO`クラスと同じように扱える。同じインターフェイス。
  - `StringIO`は、`Strind`の子クラスでも、`IO`クラスの子クラスでもない。
  - ファイル入出力専用の文字列でもなければ、ファイルに読み書きする文字列でもない。
- トップレベルでのメソッド定義の意味。
  - `Object`クラスのインスタンスメソッド。`Kernel`でも`Module`でもない。
  - 可視性は`private`。
  - これ本番で同じ問題が出題されてた。本番の誤答は、`Kernel`だった気がする。
- 可変長引数
  - 可変長引数にデフォルト値付き引数は、指定でき**ない**(文法エラー)。  
    可変長引数で、実引数がない場合は、 空配列になる。
  - 可変長引数については、問題35と同じような問題が出題された。
      - 本番、可変長引数には`&`をつけるみたいな選択肢があったけど、絶対違うね。`*`。
- rdoc
  - `+word+`で、タイプライタ体(等幅)。
  - `_word_`で斜体(イタリック体)。
  - `*word*`で太字。
  - `*`で番号なしリスト。番号付きリストではなく。
      - `-`も番号なしリスト。番号つきリストは、数字に`.`をつける。 
- `Time`クラス同士の`-`による差分は、`Float`
- `Date`クラス同士・`DateTime`クラス同士の`-`による差分は、`Rational`
- クラスメソッドの基本的な定義2つ。問題40は、本番でも同じ問題が出題。
- クラスやモジュールは、`freeze`できる！
  - モジュールをインクルードしたクラスも、`freeze`できる。
- `clone`と`dup`。`dup`視点で本番で出題。
  - `clone`はfeezeや特異メソッドなどの情報も含めてコピーするが、`dup`は含めない。
  - `clone`も`dup`も、浅いコピー(シャローコピー)で、参照先のオブジェクトはコピーされない。  
    余談として、Railsには、深いコピーのメソッドが用意されている。
- マーシャリング
  - マーシャリングできる: ユーザーが作成したオブジェクト  
  - マーシャリングできない：   
      - 特異メソッドを持つオブジェクト
      - 無名クラスや無名モジュール
      - `IO`クラスのオブジェクト
          - システムの状態を保持するオブジェクトとして、  
        他に`File`, `Dir`, `Socket`も出来ない。
- JSON
  - `json`ライブラリは、`Hash`等の主要なクラスに`to_json`を追加する。
  - `to_json`や`JSON.dump`は、JSON文字列を生成する。 
  - `JSON`はクラスではなくモジュールなので、`JSON.new`は出来ない。
  - `JSON.to_json`はない。
- YAML
  - YAMLは、簡単な記法でデータの階層構造を表現できるフォーマット。
  - yamlライブラリは、`require`等で読み込む必要がある。
- `load`は、バイナリエクステンションをロードできない。
- `require`は、バイナリエクステンションをロードできる。
  - `require`は、`.rb`や`.so`の拡張子を補完する。
- Thread
  - 例外発生しても、メッセージの出力なしで停止状態になる。 
  - `-d`オプションをつけると、例外発生時にメッセージを出力して終了する。
      - デバッグのdかな 

# 実際に試験に出題されたところ

実際に本番の試験を受けてみて、まとめ足りないと思ったところをまとめました。

- 正規表現で、`+?`は1回以上の繰り返しで、最小のものがマッチする。
  - 最小量指定子というらしい。
- 指定した実行したときだけ、実行されるif文: `if __FILE__ == $0`
  - 疑似変数`__FILE__`は、`__FILE__`が書いてあるRubyのファイル名。
  - 特殊変数`$0`は、実行時に直接指定されたRubyのファイル名。
- YAML
  - YAMLは、簡単な記法でデータの階層構造を表現できるフォーマット。
  - yamlライブラリは、`require`等で読み込む必要がある。  
    jsonライブラリも、`require`等で読み込む必要がある。
  - `YAML.load`と`YAML.dump`のそれぞれの動作
  - 「YAMLをサポートしてる他の言語のプログラムとデータを共有できる」  
    こんな文の正誤を問う問題があったが抽象度が高くて、正誤がわからなかった。
- 例外処理の`begin`ブロックの`ensure`節は評価されても、返り値にならない。
- `included`と`append_features`の動作
  - 両方ともモジュールがインクルードされたタイミングで呼ばれる。
  - `included`は、モジュールがインクルードされたタイミングで呼ばれる動作を書く。 
  - `append_features`は`include`の実体なので、上書きするときは`super`を使う。
- 子クラスは`super`で、親クラスの同名のメソッドがprivateなものでも呼べる。
- 親クラスでprivateなメソッドを、子クラスのみpublicに変更できる。2問ほど出題された。

他、練習問題で十分な基本問題で出題されたもの。

- 基本的なクラスメソッドの定義方法を2つ選ばせる問題
- `initialize`でインスタンス変数に代入させる初期化を選ばせる問題
- `using`を選ばせる問題。
- `extend`を選ばせる問題。
  - 誤答は`extended`, `include`, `included`
- `attr_accessor`と`attr_reader`&`attr_writer`を2つ選ばせる問題
- `Comparable`モジュールを通して`<`等を使うために定義するのは`<=>`。  
  この`<=>`を選ばせる問題が出題された。
  - 【余談】sort, sort!で使うメソッドも`<=>`。
  - 【余談】`Enumerable`モジュールのメソッドで使うのは`each`メソッド。
- `Proc.new{ |x, y| ~ }`を選ぶ問題。これは厳密に、引数の数をチェックしない。
  - 誤答は、`lambda{ |x, y| ~ }`や`->(x, y){ ~ }`

## 本番で、出題されなかったところ

yamlは出題されましたが、基本的にライブラリはほとんど出題されまでした。
ライブラリは出題率が低いという話ですが、そうかもしれません。
また、RExに出題されるメタプログラミング要素の高いような、難しいメソッドは全く出題されませんでした。

- rdoc
- exitのSystemExit
- `__END__` と `DATA`
- enum_for, to_enum, Enumerator.new
- フリップ・フロップ
- ライブラリ
  - Test::Unit
  - socketライブラリ
  - stringioライブラリ
  - jsonライブラリ
  - singletonライブラリ
- attr(attr_reader等は出題された)
- alias, alias_method
- undef, undef_method, remove_method
- const_missing
- method_missing
- method_defined?
- singleton_class
- module_eval, class_eval
- instance_eval
- Module.nesting
- constants
- const_get
- instance_variable_get

合格教本の問題に`const_missing`, `method_missing`, `alias`あたりはあったような気がするので出題されても良さそうですが、自分が本番を受けた際は出題がなかったです。

# RExで練習問題を解いてみて

その他、REx等で練習問題を解いていて、振り返っておきたいところをまとめました。

## オプション

`-p`, `-l`, `-t`, `-f`は、RExの練習問題に出題されてたので、出題可能性が高いかも?

- Rubyのオプション(一部)
  - 存在する: `-n`, `-p`, `-a`, `-l`, `-r`, `-e`, `-h`, `-v`, `-I`
  - 存在しない: `-t`, `-f`

`-h`はhelpで、`-v`はversionで、よくあるやつで、多分出題されない。
追記: rubyコマンドの`-v`はversionではなく、verboseらしいです。
`-r`はrequireのrで、ライブラリを読み込める。`-I`オプションの動作を尋ねる質問の誤答の選択肢ででる。
`-e`はechoかな。Rubyの短いコードをコマンド上で実行する用。

その他の`-n`, `-p`, `-a`, `-l`は、個人的に使わないので覚えにくいので、
直前におさらいして短期記憶で詰め込む。
存在しないオプション`-t`と`-f`については、｢`true`と`false`のオプションはない｣と無理やり覚える。

## エラー

### raiseとrescueの省略するケース

```ruby
begin
  raise "error message"
rescue => e
  p e.class     #=> RuntimeError
end

p RuntimeError.ancestors #=> [RuntimeError, StandardError, Exception, Object, Kernel, BasicObject]
```

`raise`が引数なしのケースや第1引数が文字列のみのメッセージのケースだと、`RuntimeError`が発生する。
`raise`で引数を省略した場合は`RuntimeError`だが、
`rescue`の省略で拾う例外は`StandardError`とそのサブクラスである点に注意する。

なお、`RuntimeError`は、`StandardError`の子クラス。

### 例外処理の実行

```ruby
begin
  puts 1 / 0
rescue ArgumentError
  puts "ArgumentError"
else
  puts "Else: 例外が発生しなければ、実行される"
ensure
  puts "Ensure: 確実に実行される"
end

puts "ブロック外: 例外を拾えれば実行され、拾えなければ実行されない"
```

`begin`ブロックの`else`節は、例外が発生しなければ実行される。
たとえ、例外が生じれば、たとえ`rescue`で例外を拾えたとしても、`else`節は実行されない。
このあたり勘違いしやすい気がする。

`ensure`節は、例外発生の有無や例外を拾えるかにかかわらず、確実に実行される。
対して、`end`後のブロック外は、例外を拾えなかった場合に実行されない。

`else`節とブロック外で、実行の条件が異なる。

- `else`節は、例外が発生しなかったかどうか。
- `end`後のブロック外は、例外を拾えたかどうか。

## 定数探索の順番

1. レキシカルスコープ(`Module.nesting`)に則り、内側から外側のスコープへと探していく。
    - 最初が自身のいるクラス・モジュール
2. 継承順(`Module#ancestors`)で、親クラスを順に探していく。
3. トップレベル

## その他(定数、慣例などについて)

- 定数は、大文字始まり。一般に、クラスやモジュールも定数といえる。
- 大文字始まりのメソッドも存在し定義可能なので、厳密には大文字始まりだから定数ではない。
  - クラス名と同じ`Array`というメソッドも存在する。
- 慣例的に、定数は全て大文字で、クラス名･モジュール名(･メソッド名)はキャメルケース。

## クラス変数と定数の違い

```ruby
module M
  @@class_variable = 1
  class C
    @@class_variable = 2
    class << C
      p @@class_variable
    end
  end
end
```

定数は外のスコープまで探すが、クラス変数は外のスコープは探さない。
定数は特異クラスのスコープにその特異クラスの定数として存在するが、クラス変数はそうではない。

## Enumerator::Lazy

```ruby
p [].lazy.method(:force) #=> #<Method: Enumerator::Lazy(Enumerable)#force(to_a)(*)>
```

この出力を見るとわかるが、`Enumerator::Lazy#force`は`to_a`のエイリアス。
`to_a`のエイリアスなので配列を返す。  
たぶん強制的に配列を返す感じだから、あえて別名がある。

`Enumerator::Lazy`は自分で書くことがないので難しい問題が出たら困るかもしれないと思いましたが、本番では合格教本と同じ問題が出題されただけだったので、困りませんでした。

## RExと本番の感触の差異

本番を受けた感触とRExの違いとして、
RExは定数探索や動的な定義(メタプログラミング)の出題傾向が高く難しいです。

RExで出題頻度の高いもの

- 定数探索
- refinement
- class_eval, module_eval(メタプログラミング)
- alias, alias_method

自分が受けた本番の試験では、簡単な定数探索2問ほどで、`module_eval`, `method_defined?`, `alias_method`等のメソッドは全く出題されませんでした。
refinementの問題も蓋をあければ、`using`を選ぶだけの簡単な問題だけでした。

それから、RExは、複数の選択肢を選ぶ問題でも指示が不明確でしたが、
本番の試験では「1つ選びなさい」「2つ選びなさい」「複数選びなさい」等の何かしらの指示が全てあったように思います。

「RExはオーバーワークなのでは」って気持ちがなくもないですが、
RExで鍛えたおかげもあって試験が遥かに簡単に感じました。

# 現バージョン3.1と試験バージョン2.1の差異

Ruby技術者認定試験の対象バージョンがとても古くRuby 2.1で、
現行バージョンを使っていると差異があります。
学習中につまりやすいところがあるかもしれないので、いくつかまとめました。

- `Fixnum`と`Bignum`はRuby 2.4で`Integer`に統合。
  - 2.3以前では、`Integer`の子クラスに`Fixnum`と`Bignum`があった。
  - 2.1では`Integer#+`を定義しても、`Fixnum`に別に`+`が定義されているので、Ruby 2.1では`1 + 1`に影響がない。
- `Array`で`sum`メソッドが使えるようになったのは、Ruby 2.4。
  - Ruby 2.3以前は、`inject`メソッドで対処されていた。
  - Ruby 2.4で、`Enumerable#sum`が追加。
- `open-uri`ライブラリは、`Kernel`の`open`を再定義しなくなっている。
  - 2.1時代は`open`を再定義していたが、今は`URI.open`を使う。
- privateメソッドはレシーバを絶対につけれなかったが、Ruby 2.7から`self`をつけれる。
- [Rubyのinitializeのprotectedの可視性の変更(Qiita記事)](https://qiita.com/universato/items/848d7f53526c0b3ef2bb)
- 継承関係
  - 後から行った Module#include が無視されなくなった
    ｢[プロと読み解く Ruby 3.0 NEWS - クックパッド開発者ブログ](https://techlife.cookpad.com/entry/2020/12/25/155741)｣の真ん中よりいくらか下。
  - [Rubyのprependによる定数探索バグ(Qiita記事)](https://qiita.com/universato/items/2a3498257d85841a3f1a)  …… Ruby 3.1で修正されたバグ。

# 試験一般で気をつけること

- 問題文の否定や複数選択に気をつける。
  「以下の実行結果になるコードを選びなさい」ではなく
  「以下の実行結果になら**ない**コードを**すべて**選びなさい」かもしれない。

- 可変長引数に配列を渡す問題が出題されるかもしれない。気をつける。

```ruby
def hoge(*args)
  p args
end

hoge([1, 2, 3])
```

普通、可変長引数には複数個の数値などを渡す。
しかし、引数に1つの配列を渡すイレギュラーなケースがでてくるので、細心の注意を払う。

- 問題文で問われているテーマが、パッと見で違うことがあるかもしれない。
  - ｢これが問題文で問われてることかな｣って思ったら、そもそもの細かいところでエラーが発生してる等。

# 本番試験時を受けてみて、実際の流れ

持ち物は、案内書(？)を印刷して、免許証・保険証の2枚を持っていきました。
(身分証明書は、色々とパターンがあるみたいですが、2つ必要そうでした)

本番は、免許証は持ち込みで、それ以外は腕時計なども含めて全てロッカーに預けました。
残り時間は、パソコンで見れます。
持ちこんだのは、免許証、貸し出しのメモ用紙&シャープペンシル。
このメモ用紙とシャープペンシルは、最後返却します。

パソコンの操作性が悪かったです。
クリックできるように時間がかかるか、スクロールさせたり2回クリックしないと反応しない感じでした。

また、コードにシンタックスハイライトがついてないので、読みにくいです。

旗マークをクリックで、見直したいところにフラグを立てれました。

# 他の方の勉強記など

他の方の実際の受験記を読むと、似たような問題が出題されてそうだなと思いました。

- [気軽に楽しくプログラムと遊ぶ： Ruby Gold合格できました。感想と振り返り](https://tamata78.hatenablog.com/entry/2015/11/20/232429)  
- [Qiita: ruby gold 落ちました・・・](https://qiita.com/7sgg_m/items/95be0f9b80502218ad8c)  

他の方の受験記などを見ると`const_missing`や`freeze`が出題されてたぽいですが、
自分が受けた本番では出題されてなかったと思います。


# 最後に

合格するだろうと思ってましたが、受けるかどうかずっと迷ってましたが、
受けて合格してこれから先受けるかどうか迷わずに済むので良かったです。

現状、試験のバージョンはRuby 2.1ですが、これから先上がるのでしょうか？
もしバージョンが上がったりしたときは、自分自身この記事を参考にしたいです。