はじめに
2023年11月にRuby技術者認定試験Goldを受験しました。
結果は96点でした。
ある程度余裕をもって合格することができたので、以下を公開することにしました。
- 実際に出題された問題例
- 受験に向けて実施したこと
- 対策としてまとめていた点
受験に向けて実施したこと
勉強期間
Silver合格後、1ヶ月間(70H)ほど勉強しました。
- 10月28日 Ruby技術者認定試験 Silver 受験
- 11月23日 Ruby技術者認定試験 Gold 受験
参考にしたサイトや、使用した教材
勉強方法
問題集の解答から始めると、不明点が多すぎて、学習意欲がなくなりそうだったので、
受験者が公開しているサイトを参考にRuby Gold 3.1の出題傾向や、よく出る問題についての学習から開始することとしました。
その後、RexやRuby技術者認定試験合格教本などの模擬問題の解答を繰り返し、受験当日を迎えました。
Rexは平均90点以上取れるような状態となっておりました。
試験対策ポイントまとめ
私が試験学習をするにあたり、迷った点などを重点的にまとめておきます。
クラス変数
・レキシカルスコープは探索しない(現在のコンテキスト ⇒ 継承チェーンの順で探索)
・特異クラスと共通の値を保持
・特異クラス内のクラス変数の参照は特異クラスが定義されたブロックのコンテキストで行われる(自身のクラス及び継承チェーンは探索されない)
class C
@@val = 10 #=> 探索されない
end
module M
@@val = 20 #=> コメントアウトすると例外となる
class << C
p @@val #=> 20
end
end
クラスインスタンス変数
・特異クラスとは別の値を保持
class C
@val = 3
class << self
@val = 10
end
def self.val
@val
end
end
p C.val #⇒ 3
・サブクラスには継承されない
class B
@val = 100
p @val #⇒ 100
end
class C < B
p @val #⇒ nil
end
特異クラス
・クラスの特異クラスは、自身のクラスの定数は参照できない
・インスタンスの特異クラスからは、自身のクラスの定数を参照できる
以下は例外
class A
CONST = 'CONST'
end
class B
class << A
p CONST # => NameError
end
end
以下は例外とはならない
class A
CONST = 'CONST'
end
$a = A.new
class B
class << $a
p CONST #⇒ 'CONST'
end
end
定数
・定数の探索順は「自身のコンテキスト => レキシカルスコープ => 継承チェーン => トップレベル」の順で行われる。
・特異クラスの定数探索は定義されたブロックのコンテキストをまずは探索し、その後継承チェーンを探索する
class B
CONST = 'B'
end
module M
CONST = 'M' # コメントアウトするとBが出力
b = B.new
class << b
p CONST #⇒ 'M'
end
end
・モジュール内の定数参照はモジュールのコンテキストから定数を探索する(その後クラス定数は参照しない)
module M
CONST = 'M' #=> コメントアウトすると例外
def hoge
p CONST
end
end
class C
CONST = 'C'
include M
end
C.new.hoge
・ネストされた名前空間の定数参照について
# [コード1]
module M
CONST = 'M'
end
module M
class C
p CONST #=> M
end
end
# [コード2]
module M
CONST = 'M'
end
module M::C
class C
p CONST #=> 例外
end
end
・const_get
はレシーバ(self
)から検索を開始する
・const_defined?(:CONST, false)
⇒ 継承先を探索しない
・メソッド内の定数更新は例外が発生する。
クラス
-
super
は受け取った引数をそのままスーパークラスに渡す- 引数を渡さない場合は
super()
とする。
- 引数を渡さない場合は
class B
def initialize
end
end
class C < B
def initialize(*)
super #⇒ super()とすると例外は発生しない
end
end
C.new('hoge') #⇒例外
- サブクラスで
initialize
が定義されていない場合、スーパークラスのinitialize
が実行される。
モジュール
-
prepend
やinclude
はメソッドや定数を上書きはしない(参照を追加している)
prepend
はクラスの前に参照を追加
module M
end
class C
prepend M
end
p C.ancestors #=> [M, C, Object, Kernel, BasicObject]
include
はクラスの後に参照を追加
module M
end
class C
include M
end
p C.ancestors #=> [C, M, Object, Kernel, BasicObject]
-
prepend
やinclude
の複数指定 ⇒ 左側から読み込まれる
module M1
end
module M2
end
class C
prepend M1, M2
end
p C.ancestors #=> [M1, M2, C, Object, Kernel, BasicObject]
- 順番に読み込ませた場合
module M1
end
module M2
end
class C
prepend M1
prepend M2
end
p C.ancestors #=> [M2, M1, C, Object, Kernel, BasicObject]
- モジュールをミックスインした後に定義したメソッドも呼び出し可能
module M
end
class C
include M
end
module M
def hoge
p 'hoge'
end
end
C.new.hoge #=> "hoge"
Date
-
date << 1
1ヶ月前 -
date >> 1
1ヶ月後
require 'date'
p Date.new(2023, 11, 11) << 1 #=> #<Date: 2023-10-11 ((2460229j,0s,0n),+0s,2299161j)>
p Date.new(2023, 11, 11) >> 1 #=> #<Date: 2023-12-11 ((2460290j,0s,0n),+0s,2299161j)>
Refinement
・using
を宣言したスコープでのみ上書きする
・refine C do
は C
のインスタンスメソッドを上書きする
・クラスメソッドを上書きする場合はC.singleton_class
を指定して上書きする
・メソッド内でusing
を使用すると例外が発生する
・using
後にメソッドを再定義してもRefinement
が優先される
・using
を複数定義した場合は最後に宣言したusing
のみ有効
Forwardable
- extendでミックスインする
extend Forwardable
-
def delegator
,def delegators
を使用する
class_eval / module_eval / instance_eval
class_eval
⇒ クラスに対して、インスタンスメソッドを定義
instance_eval
⇒ インスタンスに対して特異メソッドを定義
・ブロックが定義されたコンテキストで定数やメソッドを探索する
・定義した定数はブロックが定義されたコンテキストで評価される(以下はTOPレベルで宣言したことになる)
mod = Module.new
mod.module_eval do
EVAL_CONST = 100
end
p EVAL_CONST #=> 100
・文字列を渡した場合はレシーバのコンテキストで評価される
mod = Module.new
mod.module_eval(<<-EOS)
EVAL_CONST = 100
EOS
p EVAL_CONST #=> 例外(トップレベルにはEVAL_CONSTは存在しない)
・クラスメソッドの定義する場合はself.hoge
とする
・instanceに対して、module_evalで定義されたメソッドは呼び出せないので、注意
m = Module.new
CONST = "Constant in Toplevel"
_proc = Proc.new do
CONST = "Constant in Proc"
end
m.module_eval(<<-EOS)
CONST = "Constant in Module instance"
def const
CONST
end
EOS
m.module_eval(&_proc)
p m.const #=> 例外となる
clone, dup
-
clone
は特異メソッドも含めた複製を作成 -
dup
は特異メソッドは含めない -
clone
もdup
はシャローコピー
do endと{}の結合度の違い
do ~ end
の方が結合度が高い
rescue
-
rescue Class
は指定したクラスとそのサブクラスを捕捉する-
rescue NameError
はNoMethodError
も捕捉
-
-
rescue
ブロックでのraise
は指定したクラスではなく実際に発生したエラーをthrow
-
rescue else
は例外が発生しなかった場合のみ実行 -
rescue ensure
は例外の発生有無に関わらず、必ず実行される
*args
*args
は引数がひとつでも配列として受け取る
def hoge(*args)
p args #=> [1]
end
hoge(1)
or, and
or
, and
は ||
, &&
より結合度が低い。
puts true and false #=> trueが出力
freeze
・破壊的変更は不可 ※配列に指定した場合各要素の破壊的変更は可能
・変数自体の値再代入は可能
以下は例外
array = ["a", "b", "c"].freeze
array = array.map!{|content| content.succ}
p array #⇒ 例外
以下は例外
char = { :a => "A" }.freeze
char[:a] = "B"
p char
array = [1,2,3].freeze
array[0] = 0 #⇒ 例外
以下は例外にならない
array = [1,2,[3,4]].freeze
array[2][0] = 0
p array #⇒ [1, 2, [0, 4]]
以下は例外にならない
array = ["a", "b", "c"].freeze
array.each do |chr|
chr.upcase!
end
p array #⇒ ["A", "B", "C"]
throw ~ catch
・戻り値は引数の二番目に指定
throw :done, [a,b,c]
RDoc
・*word*
⇒ 太字
・_word_
⇒ 斜体
・+word+
⇒ タイポライター
・*、 -
⇒ 番号なしリスト
*methods
・methods
⇒ レシーバのpublic + protected
なメソッドのみを取得
・public_methods
⇒ レシーバのpublic
なメソッドのみを取得
・private_methods
⇒ レシーバのprivate
なメソッドのみ
キーワード引数
引数が未指定の場合は例外が発生する
def hoge(foo:)
p foo
end
hoge(1) #⇒例外
alias, alias_method
-
alias
=> エイリアス名 メソッド名- ※カンマがあるとエラー、識別子/シンボルのみ指定可能
-
alias_method
=> エイリアス名, メソッド名- ※カンマは必要。シンボル/文字列のみ指定可能
undef, remove_method
remove_method
は現在のクラスからメソッドを削除。
継承元にメソッドが定義されてあれば継承元のメソッドが呼ばれる
undef_method
はメソッド呼び出しへのレスポンスを止める。
remove_method
と違い、継承元のクラスにメソッドが定義されていてもエラーとな流。
undef
後にメソッドを再定義した場合は呼び出し可能。
undef
後にモジュールをinclude
しても、呼び出しは不可。
Class#method_missing
class Class
def method_missing(id, *args)
puts "Class#method_missing" #=> ここでキャッチされる
end
end
class A
def method_missing(id, *args)
puts "A#method_missing"
end
end
A.dummy_method
const_missing
定数が見つからない時に実行
クラスメソッドとして定義する
class Object
def self.const_missing a
p "#{a}"
end
end
B #⇒ 'B'
proc, yield
Proc
の作成
・Proc.new{...}
・proc {...}
・lambda {...}
Proc
オブジェクトの呼び出し
・proc.call
, proc.yield
, proc[]
・yield
※callは付けない。
&block
&block
=> ブロックを明示的に受け取る
引数の最後に書かないとエラー
# 以下はエラー
def hoge(&block, *args)
block.call(*args)
end
オプション
-t
, -f
はない。
-I(include)
⇒ $LOAD_PATH
に追加で読み込むファイルを追加
e(evaluate)
⇒ 引数で渡した文字列を評価。結果を出力
-d(debug)
⇒ デバッグモード。スレッドの例外を捕捉
-h(help)
⇒ ヘルプ
-c(check)
⇒ 文法が正しいかチェック
-w(warning)
⇒ 冗長モード
-r(require)
⇒ スクリプト実行前に指定されたファイルの実行
組み込み定数
$0
⇒ 実行中のファイル名
$1..
⇒ 正規表現でマッチした文字
NULL
は組み込み定数ではない。
strptime / strftime
-
strptime
⇒ 文字列をTimeオブジェクトに変換 -
strftime
⇒ 日付オブジェクトを指定したフォーマットの文字列に変換
iso8601
-
Time.iso8601
⇒ iso文字列をTimeオブジェクトに変換 -
Time#iso8601
⇒ レシーバのTimeオブジェクトをiso8601形式の文字列に変換
classメソッド
- Classオブジェクトに対して実行 ⇒ Classが返る
- Classインスタンスに対して実行 ⇒ クラス名が返る
DATA, END
DATA
(File obj) ⇒ __END__
以降の文字列をファイルオブジェクトとして取得
===
- 範囲オブジェクトの範囲チェック
- インスタンスであるかチェック
トップレベルのメソッド
-
Object
クラスのprivate
メソッドとして扱われている
def hoge
puts 'hoge'
end
# 上記はhogeメソッドはObjectクラスのprivateメソッドとして取り扱われている
class Object
private
def hoge
puts 'hoge'
end
end
puts, print, p
-
puts
,print
⇒to_s
メソッドが呼ばれる -
p
⇒inspect
メソッドが呼ばれる
Module.nesting
・TOPレベルで実行すると、[]
が変える
・実行結果は内側から返る
module SuperMod::BaseMod
p Module.nesting
end
# => [SuperMod::BaseMod]
module SuperMod
module BaseMod
p Module.nesting
end
end
#=> [SuperMod::BaseMod, SuperMod]
出題傾向
自分の想定よりRuby Silverで出題されるようなメソッドの利用方法などに関する問題が多かった気がします。
出題された問題
- クラス, モジュール間の定数参照について
- モジュールをミックスインした場合の
super
によるメソッド呼び出し -
using
でRefinement
を有効にした場合のsuper
によるメソッド呼び出し - モジュールのクラスメソッドのミックスイン
- モジュールのクラスメソッドは
include
やprepend
ではクラスにミックスインできない。
- モジュールのクラスメソッドは
module M
def self.hoge
puts 'hoge'
end
end
class C
include M
end
puts C.methods.include?(:hoge) #=> false
- instance_variable_get
# どちらが正しいか
obj.instance_variable_get(:@foo) #=> こちらが正しい
obj.instance_variable_get(:foo)
- トップレベルに宣言したメソッドについて
-
Compartible
モジュールのミックスイン,<=>
でのソート - Procオブジェクトの作成方法について(
Proc.new {...}
orlambda {...}
)
出題されなかった問題
-
const_eval
,instance_eval
-
const_get
,const_defined?
- 特異クラス内での定数参照について
-
Enumerable
モジュール、Enumerator
,Enumerator::Yielder
さいごに
本記事が皆さんの合格に少しでも役立てれば幸いです🙏