LoginSignup
5
0

Ruby Gold受験振り返り

Last updated at Posted at 2023-08-30

RubyGoldを受験した結果を振り返る

RubyGoldを受験してきましたので、備忘録としてまとめます。

経緯

2022年7月(当時大学4年生)に自分のスキルアップのために、RubySilverの試験を受験しまして、その時は80/100(合格ボーダーは75)で合格しました。

それから一ヶ月程度経った後に、RubyGoldの試験対策を始め、手始め模擬問題集を見てみましたが、最初の感想は「レベルが違う。。。」でした。(実際に初見で解いて30点しか取れませんでした。。。)

そこから、大学の研究室やアルバイトの合間を縫ってRubyGoldの勉強(後に説明)をしていましたが、気づいたら2023年3月。

「やばい!もう社会人じゃん!」

これはまずいと思いましたよね。

そこから勉強の時間を増やして3ヶ月経過しました。

しかし、結果は落ちました。。。

66点。。。原因はわかっています。それを後半説明します。

勉強方法

箇条書きで説明していきますね。

個人的に時間がかかったのは、メタプログラミングRubyです。

結構量あるし、何より頭に入ってきづらかった!(個人差あり)

ただ、公式問題集に載っていないのに試験に出てくる知識はメタプログラミングRubyで勉強していくしかなさそうでした。

あとはRexで問題をひたすら解いていくことをお勧めします。

  1. 問題を解いていく
  2. 答え合わせをして解説を読む
  3. irbで動作確認
    (詳しい原理や機能は、ChatGPTに聞くのをお勧めします。)

この繰り返しです。

Rex

Rexを解いていく中で理解に苦戦した問題5つを紹介します。

第一問

class C
  CONST = "Hello, world"
end

ccc = C.new

class D
  class << ccc
    def say
      CONST
    end
  end
end

p $c.say   #=> Hello, world

わかる人にはわかるんだろうけど、なんか苦手意識を持っている。。。

$cはクラスCのインスタンス。sayメソッドは$cの特異クラスのメソッド(クラスCのインスタンスの特異クラスのメソッド)。

  1. $cの特異クラスを探索→定数CONSTがない。
  2. $cのスーパークラス(クラスC)を探索→CONSTが定義されている!

なので答えはHello worldとなります。(解説を書いていたら理解できた。。。)

第二問

mmm = Module.new

mmm.module_eval do
  EVAL_CONST = 100
end

puts "EVAL_CONST is defined? #{mmm.const_defined?(:EVAL_CONST)}"   #=> true
puts "EVAL_CONST is defined? #{mmm.const_defined?(:EVAL_CONST, false)}"   #=> false
puts "EVAL_CONST is defined? #{Object.const_defined?(:EVAL_CONST)}"   #=> true
puts "EVAL_CONST is defined? #{Object.const_defined?(:EVAL_CONST, false)}"   #=> true

この問題はmodのレキシカルスコープ内でEVAL_CONSTが定義されているかいないかの問題となります。

まず、module_evalで定義された定数はトップレベルで定義されます。そのため、3、4行目の評価式はどちらもtrueになります。

次に、modEVAL_CONSTはあるか?という話になるのですが、modEVAL_CONSTは定義されていません。ただ、const_defined?メソッドは第二引数にfalseを設定すると、「継承元の探索を行わない」。falseを指定しないと、「継承元の探索を行う」という形となります。

つまり、1行目の評価式は継承元の探索を行い、2行目の評価式は継承元の探索を行わないとという形になります。

modの継承元は、「Moduleクラス→Objectクラス」となります。ObjectクラスにはEVAL_CONSTが定義されていますので、1行目ではtrueが返されます。

一方で、2行目の評価式では、継承元の探索が行われないので、modのスコープ内を探索したらそれで終了。なので、falseが返されます。

1行目が難しいですよね。

第三問

mmm = Module.new

mmm.module_eval <<-RUBY
  EVAL_CONST = 100
RUBY

puts "EVAL_CONST is defined? #{mmm.const_defined?(:EVAL_CONST)}"   #=> true
puts "EVAL_CONST is defined? #{mmm.const_defined?(:EVAL_CONST, false)}"   #=> true
puts "EVAL_CONST is defined? #{Object.const_defined?(:EVAL_CONST)}"   #=> false
puts "EVAL_CONST is defined? #{Object.const_defined?(:EVAL_CONST, false)}"   #=> false

これは、第二問の定数の定義をヒアドキュメントを使用して定義した場合です。

ヒアドキュメントで定義した時のEVAL_CONSTmodのスコープ内でのみ探索することが可能となります。

つまり、1、2行目の評価式ではtrueが、3、4行目の評価式ではfalseが返されます。

第四問

「同じ結果になる選択肢はどれですか(複数選択)」という問題です。

module M
  CONST = "Hello, world"

  class C
    def awesome_method
      CONST
    end
  end
end

p M::C.new.awesome_method   #=> Hello, world

---

選択肢1
module M
  CONST = "Hello, world"
end

class M::C
  def awesome_method
    CONST
  end
end

p M::C.new.awesome_method   #=>例外が起こります

---

選択肢2
class C
end

module M
  CONST = "Hello, world"

  C.class_eval do
    def awesome_method
      CONST
    end
  end
end

p C.new.awesome_method   #=> Hello, world

---

選択肢3
class C
  CONST = "Hello, world"
end

module M
  C.class_eval(<<-CODE)
    def awesome_method
      CONST
    end
  CODE
end

p C.new.awesome_method   #=> Hello, world

---

選択肢4
class C
  CONST = "Hello, world"
end

module M
  C.class_eval do
    def awesome_method
      CONST
    end
  end
end

p C.new.awesome_method   #=> 例外が起こります

これはややこしいです。。。

まず、選択肢1は、awesome_methodメソッド内のCONSTが参照できるものがないため、例外が起こります。
参照できない理由として、CONSTを定義しているコードが同じコンテキスト内に存在しないからです。

選択肢2は、class_eval(ブロック)で定義した場合のネストの状態、スコープを考えます。ネストの状態は、ブロックで定義されているので、class_evalブロックが定義されている場所がネストとなります。つまり、モジュールMです。ネストがモジュールM=定数のスコープもモジュールMであることがわかります。運よくモジュールMで定数は定義されているので、正常に文字列が出力されます。

選択肢3は、選択肢2と似ていますが、定数が定義されている場所とヒアドキュメントが使用されていることに注意が必要です。ヒアドキュメントが使用されている場合のネストは、class_evalのレシーバです。つまり、クラスCです。ネストがクラスC=定数のスコープもクラスCです。運よく定数はクラスCに定義されているので、正常に文字列が出力されます。

選択肢4は、運が良くないですね。動きは選択肢2と同じですが、スコープ内(モジュールM内)に定数が定義されていないですね。なので、例外が起こります。

第五問

class Object
  CONST = "1"
  def const_succ
    CONST.succ!
  end
end

class Child1
  const_succ
  class << self
    const_succ
  end
end

class Child2
  const_succ
  def initialize
    const_succ
  end
end

Child1.new
Child2.new

p Object::CONST

まず、このコードたちを実行した時に、以下の順番で処理がされていきます。

  1. クラスの定義
  2. インスタンスの呼び出し
  3. Object::CONSTの呼び出し

まず、クラスの定義時に行われる処理を説明していきます。Objectクラスを定義する時には、定数の定義(CONST="1")とconst_succメソッドの定義(CONST="2")がされます。次にChild1クラスを定義する時には、最初のconst_succ(CONST="3")が実行されます。しかし、Child1クラスの特異クラス内にあるconst_succが実行されません。次にChild2クラスを定義する時には、最初のconst_succ(CONST="4")が実行されます。しかし、initializeメソッド内のconst_succは実行されません。

次にインスタンスの呼び出し時に行われる処理を説明します。Child1.newを呼び出したときには、最初のconst_succは呼び出されません。また、Child1クラスの特異クラス内にあるconst_succも呼び出されません。次に、Child2.newを呼び出したときには、initializeメソッド内のconst_succ(CONST="5")が呼び出されます。

最後にObject::CONSTが呼ばれた時にはCONSTの値は"5"なので、出力される値は"5"です。

ちなみに、インスタンスの呼び出し時にconst_succが呼ばれない理由として、const_succがそれぞれのクラスメソッドとして呼び出されているからです。

落ちた原因

さて、最後に試験に落ちてしまった原因ですが、自分がRubySilverを受験したのはバージョン2.1のものです。しかし、今回受験したのはバージョン3.0でした。

テストセンターで問題を解く時、「Version3.0」という文字が目に入り、「マジか、、、やばい」と思いました。
それに試験問題は全然違かったです。

Rexをメインに使用してバージョン3.0を受験することを考えている人は一旦考えてください。
こちらの記事こちらの記事で対策記事が書かれていますので、一度こちらをお読みください!

その他記事は以下にまとめておきます。

https://zenn.dev/universato/articles/20221011-z-rubygold3
https://ankh-systems.co.jp/blog/51

しかし、バージョン3.0の模擬問題が出ていないので対策しづらいです。。。
コツコツ地道に対策をしていきます。。。

まとめ

RubyGoldを受けようとしている人は、RubySilverよりも格段にレベルが上がると思っておいた方がいいです。

個人差はあるかもしれないですが、以下の点については十分に対策をした方が良いと思います。

  • 定数のスコープ、ネスト
  • ブロック
  • クラスメソッドとインスタンスメソッドの違い
  • module_evalclass_evalinstance_evalの違い
  • メソッドや定数の探索順

あと、バージョン2.1と3.0はそこそこ問題がずれているので注意をしてください!

以上

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0