先日、「Ruby Silver」こと「Ruby Association Certified Ruby Programmer Silver version 3」を受検し、めでたく合格することができました🙌
www.ruby.or.jp
記録のためにブログを書いていきます📝
受検のきっかけ
やったこと
受検当日
受検を終えて
おわりに
おまけ1:公式模擬試験にPRを出した
おまけ2(長文):Ruby Silver対策メモ
その他
strip, chomp, chop
pop, push, unshift, shift
concat, append
find, detect, select, filter, find_all
ファイルオープンのモード(r, r+,w, w+, a, a+)
product, zip, push, transpose, combination, permutation
sub, gsub, slice, scan
IOクラスのクラスメソッド(抜粋)
Fileクラスのクラスメソッド(抜粋)
Dirクラスのクラスメソッド(抜粋)
%記法
正規表現
進数
ヒアドキュメントの開始ラベル
受検のきっかけ
Ruby Silverは以前から取りたいと思っていたのですが、なかなか受検することができていませんでした。
昨年11月にフィヨルド ブートキャンプを卒業し、年始に「今年こそRuby Silver取らなきゃな〜」と呑気に思っていた矢先、Ruby の基礎力不足を感じる出来事がありました。
やりたいことは多々ありましたがまずこれはRuby Silverを取る機運だろうと思い、勢いで2月7日(土)の受検予約をしたのが1月21日(水)のことでした。
やったこと
予約をしてからは以下の試験対策を中心に行いつつ、気になる部分は公式ドキュメントを確認したり生成AIに類似問題を出してもらうなどして復習していきました。
どれも基本的には「50問やる→採点する→間違えたところを中心にチェック→同じ50問をやり直す」という流れで、1セットで2周解いていました。
あと、特に間違えた問題は必ずirb で実際にコードを実行するようにしました。「ここをこう書き換えたらどうなるかな?」みたいな試行錯誤は楽しかったし、学びも大きかったなと思います。
受検当日
試験会場は池袋のテストセンターでした。家族も一緒に出かけて、サンシャイン水族館 に行ってもらっている間に受検してきました。(僕もサンシャイン水族館 行きたかった😇)
試験時間は90分。時間は充分に余裕がありましたが、自信のない問題が10問ほどありました。何度も見直しをして、「よほどの勘違いがない限り自信のないやつが全部不正解でも80点は取れてるはず」という状態で試験を終了、結果は84点でした。
できれば90点以上取りたかったところですが、引き続き精進していきたいと思います。
「合格」の部分、ちょい要素が下にズレているのを修正したい
受検を終えて
試験勉強として繰り返し問題を解いたことで、Ruby の基本的な内容について復習できて良かったです。
時は大AI時代、資格試験の勉強がどこまで役に立つのか?という考え方もあるかもしれませんが、基本的なところから毎回AIに聞いていてはキリが無いですし、AIを使いこなすためにも自分自身の知識をちゃんと定着させていきたいと思っています。なので個人的には受検して良かったですし、勉強の楽しさや達成感を改めて感じることができたなーとも思います。
おわりに
無事合格できて、ホッと胸を撫で下ろしました。
次は基本情報技術者試験 を取ろうと思います🚀
www.ipa.go.jp
おまけ1:公式模擬試験にPRを出した
GitHub の模試をやっている途中に問題文の並びに違和感がある箇所があったので、修正のPRを出しました。マージされるといいな✨
github.com
おまけ2(長文):Ruby Silver対策メモ
今回、勉強中に何度も間違えてしまったところやうっかりミスしそうになったことを適宜メモしていました。
せっかくなのでおまけとして載せておきます!
(もしおかしいところがありましたら、そっとご指摘ください🙏)
その他
「その他」から紹介するのも変ですが、カテゴライズしにくかったやつ
Stringクラスにto_hメソッドは無い(Arrayクラスにはある)
" hoge " .to_h
[[:price , 100 ], [:amount , 5 ]].to_h
" 7 " .binary
式展開の省略記法(以下のようにそれぞれ{}を省略可能)
"#{$hoge}"→"#$hoge"
"#{@hoge}"→"#@hoge"
メソッド内では定数を定義できない
def hoge
x = 10
Y = x < 10 ? " C " : " D "
puts Y
end
hoge
strip, chomp, chop
chomp はAtCoderでよく使っていて無意識に覚えていたので助かりました。
strip:文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除く
chomp:末尾から改行コード("\r\n", "\r", "\n")を取り除く
chop:末尾の文字を取り除く。ただし、文字列の末尾が"\r\n"であれば2文字とも取り除く
上記それぞれ、strip! chomp! chop! の破壊的メソッドもある
s = " hello \n\n"
s.chomp
s.chomp
s.length
s.chomp!
s.chomp!
s.length
pop, push, unshift, shift
⚠️! が無いけど、全部破壊的メソッド
popは、末尾の1要素を破壊的に取り出す。引数nがある場合は末尾からn個の要素を取り出して配列で返す
pushは、末尾に引数の値を破壊的に追加する
shiftは、先頭の1要素を破壊的に取り出す。引数nがある場合は先頭からn個の要素を取り出して配列で返す
unshiftは、先頭に引数の値を破壊的に追加する
a = [1 , 2 , 3 , 4 , 5 ]
a.pop
a
a.pop(2 )
a
a.push(9 )
a
b = [1 , 2 , 3 , 4 , 5 ]
b.shift
b
b.shift(2 )
b
b.unshift(9 )
b
concat, append
self.concat(other):self(文字列)にotherを繋げる
self.append(other):self(配列)の末尾にotherを追加する
a = " hello "
a.concat(" world " )
a
b = " hello "
b.concat(" world " , " ! " )
b
c = [1 , 2 ]
c.append(3 )
c
d = [1 , 2 ]
d.append(3 , 4 )
d
find, detect, select, filter, find_all
find, detect:ブロックの値が真になる最初の要素を返す
select, filter, find_all:ブロックの値が真になる全ての要素を返す
a = [1 , 2 , 3 , 4 , 5 , 6 ]
a.find { |x| x > 3 }
a.detect { |x| x > 3 }
a.select { |x| x > 3 }
a.filter { |x| x > 3 }
a.find_all { |x| x > 3 }
ファイルオープンのモード(r, r+,w, w+, a, a+)
これ、覚えるのに苦労しました😇
r(readの略):読み込み専用(ファイルが無い場合はエラー)
r+:読み書き両方(ファイルが無い場合はエラー)
w(writeの略):書き込み専用(新規作成 or 開いた時に中身を消して先頭から書き込む)
w+:読み書き両方(新規作成 or 開いた時に中身を消して先頭から書き込む)
a(appendの略):追記専用(中身を残して末尾に追記される or 新規作成)
a+:読み書き両方(中身を残して末尾に追記される or 新規作成)
+は全て「読み書き両方」になる
r+は、読む+書く
w+は、書く+読む
a+は、書く(追記)+読む
特にr+とw+は同じ意味に見えるが、 r+は「読む」が起点なので、ファイルがない場合にエラー
オープンモードを省略したら、デフォルトのrになる
rewindは、「先頭に戻る」(ただし a, a+ では読み込み位置は戻るが、書き込みは常に末尾)
File .open(" test.txt " , " a+ " ) do |f|
f.rewind
f.write(" Z " )
f.rewind
puts f.read
end
product, zip, push, transpose, combination, permutation
combination と permutation は問題ではほぼ見かけなかったけど、セットで覚えました。
product:全組み合わせ(直積)を作る
zip:同じインデックス同士をペアにする(要素数 はレシーバに合わせる)
push:配列の末尾に引数をそのまま1要素として追加する(展開されない)
transpose:配列の行と列を入れ替える(要素数 が揃っていないとIndexError)
combination:順序を区別しない組み合わせ
permutation:順序を区別する順列
[1 , 2 ].product([3 , 4 ])
[1 , 2 ].zip([3 , 4 ])
[1 , 2 ].product([3 , 4 , 5 ])
[1 , 2 , 3 ].product([4 , 5 ])
[1 , 2 , 3 ].zip([4 , 5 ])
[1 , 2 ].zip([3 , 4 , 5 ])
[[1 , 2 ]].push([3 , 4 ])
[[1 , 2 ]].push([3 , 4 , 5 ])
[[1 , 2 , 3 ]].push([4 , 5 ])
[[1 , 2 ], [3 , 4 ]].transpose
[1 , 2 ].product([3 , 4 ]).transpose
[[1 , 2 ], [3 , 4 , 5 ]].transpose
[1 , 2 , 3 ].combination(2 ).to_a
[1 , 2 , 3 ].permutation(2 ).to_a
sub, gsub, slice, scan
⚠️ sub! gsub! slice! の破壊的メソッドがあるが、scanだけは無い
sub:マッチした最初の箇所のみ置換
gsub:マッチした全ての箇所を置換
slice:最初にマッチした文字列を返す
scan:マッチした文字列を配列で返す
" hello world " .sub(/ o / , " 0 " )
" hello world " .gsub(/ o / , " 0 " )
" hello world " .slice(/ o / )
" hello world " .scan(/ o / )
IOクラスのクラスメソッド(抜粋)
⚠️ IOはFileの親クラス(superclass)なので、IOにあるクラスメソッドはFileでも使える
IO.open # ファイルを開く
IO.read # ファイルを読む
IO.write # ファイルに書く
IO.readlines # 全行を配列で読む
IO.foreach # 1行ずつ処理
IO.select # IO監視
Fileクラスのクラスメソッド(抜粋)
クラスメソッド系はなかなか覚えられなかった…
ファイル操作
File.open # 開く
File.read # 読む
File.write # 書く
File.delete # 削除 ⚠️Dirクラスにもある
File.rename # 名前変更(⚠️Dirクラスメソッドじゃないけどディレクトリにも使える)
File.chmod # パーミッション変更
File.chown # オーナー変更
File.exist? # 存在するか ⚠️Dirクラスにもある
File.size # サイズ
File.mtime # 更新日時
パス文字列の操作
File.basename # パスからファイル名を取り出す
File.dirname # パスからディレクトリ名を取り出す ⚠️Dirクラスっぽいけど違う
File.extname # パスから拡張子を取り出す
File.join # パスを結合
File.split # パスを分割
Dirクラスのクラスメソッド(抜粋)
覚え方:Linux コマンドっぽい名前(pwd , cd, mkdir, rmdir)
(Linux コマンドを覚えていないのでこの覚え方はあまり活用できなかった😇)
Dir.pwd # 今いるディレクトリ
Dir.chdir # ディレクトリを移動
Dir.mkdir # ディレクトリを作る
Dir.delete # ディレクトリを削除 ⚠️Fileクラスにもある
Dir.rmdir # 同上(エイリアス)
Dir.unlink # 同上(エイリアス)
Dir.entries # 中身の一覧を取得
Dir.glob # パターンで検索
Dir.exist? # 存在するか ⚠️Fileクラスにもある
Dir.home # ホームディレクトリ
%記法
%!...!: ダブルクォート文字列(式展開:あり、%Qの省略形)
%Q(...): ダブルクォート文字列(式展開:あり、由来:Quote)
%q(...): シングルクォート文字列(式展開:なし、由来:quote)
%W(...): 文字列の配列(式展開:あり、由来:Words)
%w(...): 文字列の配列(式展開:なし、由来:words)
%I(...): シンボルの配列(式展開:あり、由来:Identifiers)
%i(...): シンボルの配列(式展開:なし、由来:identifiers)
%s(...): シンボル1つ(式展開:なし、由来:Symbol)
%r(...): 正規表現 (式展開:あり、由来:Regexp )
%x(...): コマンド実行(式展開:あり、由来:eXecute)
lang = " Ruby "
%w( #{lang} Python Java )
%W(#{ lang} Python Java )
%i(foo bar baz) .class
%i(foo bar baz) .first.class
語源から覚えるの大切だなと思いました。
小文字は、マッチするもの
\d(digitの略):数字(0-9)にマッチ
\w(wordの略):単語構成文字(a-z, A-Z, 0-9, _)にマッチ
\s(spaceの略):空白(スペース、タブ、改行)にマッチ
大文字にすると「否定」
\D:数字以外
\W:単語構成文字以外
\S:空白以外
位置を示すもの
^:行の先頭(複数行で各行にマッチ)
$:行の末尾(複数行で各行にマッチ)
\A:文字列の先頭(文字列全体の最初だけ)
\z:文字列の末尾(文字列全体の最後だけ)
量を示すもの
*:0回以上(a* → "", "a", "aaa")
+:1回以上(a+ → "a", "aaa"(""は×))
?:0回か1回(a? → "", "a")
{n}:ちょうどn回(a{3} → "aaa")
{n,m}:n回以上m回以下(a{2,4} → "aa", "aaa", "aaaa")
その他
.:任意の1文字(改行以外)
[]:文字クラス(どれか1つ)
[^]:否定の文字クラス
():グループ化
=~:マッチした位置(インデックス)を返す。マッチしなければnilを返す
s = " abc \n def \n ghi "
s.scan(/^\w+/ )
s.scan(/\A\w+/ )
" Ruby123 " =~ /\d+/
" Ruby123 " [/\d+/ ]
" hello " =~ / x /
" hello " =~ / l /
" hello " .match?(/ x / )
進数
2進数 0b、使える数字:0, 1
例 0b0001(1)、0b0110(6)、0b1010(10)
8進数 0o または 0、使える数字:0-7
例 0o10(8)、010(8)、0o25(21)、025(21)
10進数 プレフィックス なし、使える数字:0-9
例 10(10)、010や025は8進数になるので注意
16進数 0x、使える数字:0-9, a-f(A-Fも可)
例 0x10(16)、0x1F(31)、0x90(144)
関連メソッド
to_i(基数) 文字列を指定した基数で整数に変換
例 "10".to_i(2)(2)、"FF".to_i(16)(255)
to_i(0) プレフィックス から基数を自動判定
例 "0x10".to_i(0)(16)、"0b10".to_i(0)(2)
.hex 16進数文字列を整数に変換
例 "0x90".hex(144)、"FF".hex(255)
.oct 8進数文字列を整数に変換
例 "10".oct(8)、"77".oct(63)
0x10
010
0b10
" 0xFF " .to_i
" 0xFF " .to_i(16 )
" 0xFF " .to_i(0 )
" 0xFF " .hex
ヒアドキュメントの開始ラベル
"識別子"(ダブルクオート):式展開が有効
識別子(クオート無し):ダブルクオートと同じ
'識別子'(シングルクオート):式展開できない
`識別子`(バッククオート):コマンド出力
name = " Ruby "
a = <<EOS
Hello #{ name}
EOS
b = <<-EOS
Hello #{ name}
EOS
c = <<~EOS
Hello #{ name}
EOS
d = <<'EOS'
Hello #{name}
EOS
e = <<-'EOS'
Hello #{name}
EOS
p a
p b
p c
p d
p e