Ruby技術者認定試験 Silver について2
<<識別子
行から識別子
行の直前までを文字列として扱います。このような表現方法をヒアドキュメントといいます。
今回の問題では、1行目から4行目までがヒアドキュメントとして扱われます。
5行目はただの文字列として解釈されます。
1: s = <<'EOF'
2: Hello,
3: Ruby
4: EOF
5: 'EOF'
識別子の開始ラベルによってヒアドキュメントの解釈の方法が異なります。
開始ラベル | 説明 |
---|---|
"識別子" | 式展開が有効 |
識別子 | ダブルクオートと同じ結果 |
'識別子' | 式展開できない |
`識別子` | コマンド出力 |
問題
次のコードを実行するとどうなりますか
s = <<'EOF'
Hello,
Ruby
EOF
'EOF'
p s
選択肢
"Hello,\nRuby\n"
と表示される
"Hello,\nRuby\nEOF"
と表示される
"Hello,Ruby"
と表示される
エラーが発生する
String#%
はフォーマットされた文字列を返します。
🔳
Enumerable#partition
はブロックの条件を満たす要素と満たさない要素に分割します。
問題では、a, =
と指定されているため、Enumerable#partition
の条件を満たす要素がa
に入ります。
条件を満たさない要素は変数が指定されていないため、無視されます。
問題
次のコードを実行するとどうなりますか
a, = (1..5).partition(&:odd?)
p a
[[2, 4]]
と表示される
[[1, 3, 5]]
と表示される
[2, 4]
と表示される
[1, 3, 5]
と表示される
>> a, = (1..5).partition(&:odd?)
=> [[1, 3, 5], [2, 4]]
>> p a
[1, 3, 5]
=> [1, 3, 5]
>>
#調べる 表記法(&:odd?)
自身が奇数であれば真を返します。 そうでない場合は偽を返します。
例:
5.odd? # => true
10.odd? # => false
https://workout-engineer.com/ruby-block-proc/
Procに関するもの。
🔳
..
は右辺を含みます。...
は右辺を含みません。
arr = [1, 2, 3, 4]
p arr[1..2]
p arr[1...2]
# <実行結果>
# [2, 3]
# [2]
🔳
String
にto_a
メソッドはありません。
p String.method_defined?(:to_a)
# <実行結果>
# false
問題
次のコードを実行するとどうなりますか
hoge = "a".to_a
puts hoge.class
String
と表示される
Array
と表示される
Hash
と表示される
エラーになる
🔳
Array#=
はArray#length
以上のインデックスに値を挿入すると、nil
で埋めます。
問題コードの実行結果が次の通りです。
1: a = [1]
2: a[5] = 10
3: p a
1: a => [1]
2: a => [1, nil, nil, nil, nil, 10]
問題
次のコードを実行するとどうなりますか
a = [1]
a[5] = 10
p a
🔳
p1
とp2
は別のProc
オブジェクトのため、hoge
メソッド内のcurrent
変数は共有されません。
よって、p2
の結果は6
になります。
問題
次のコードを実行するとどうなりますか
def hoge(step = 1)
current = 0
Proc.new {
current += step
}
end
p1 = hoge
p2 = hoge(2)
p1.call
p1.call
p1.call
p2.call
p2.call
p p2.call
9
と表示される
7
と表示される
6
と表示される
5
と表示される
#調べる
do ... end
と{ ... }
を比べた場合、{ ... }
の方が結合度が強いです。
問題の式の場合、do ... end
の結合度が弱いため、p([1, 2, 3, 4].map)
が評価されます。
問題のように式の内容を直接使用する際は、{ ... }
を使用します。
問題
次のコードを実行するとどうなりますか
p [1,2,3,4].map do |e| e * e end
[1, 4, 9, 16]
#<Enumerator: [1, 2, 3, 4]:map>
nil
エラーになる
可変長引数を2つ定義することはできません。
可変長引数の実行結果は次の通りになります。
def bar(n1, *n2, n3)
puts "n1: #{n1}, n2: #{n2}, n3: #{n3}" # n1: 5, n2: [6, 7], n3: 8
end
bar 5, 6, 7, 8
問題
実行してもエラーにならないコードを選べ
🔳s..e
やs...e
はRange
クラスの定義です。..
は終端を含み、...
は終端を含みません。
Enumerator#with_index(offset)
は要素にインデックスを添えてを繰り返します。
インデックスはoffset
から開始します。
問題
次のコードを実行するとどうなりますか
(10..15).to_a.map.with_index(1) do |elem, i|
puts i
end
1
2
3
4
5
6
0
1
2
3
4
5
6
5
4
3
2
1
5
4
3
2
1
0
🔳
Hash#each
のブロックパラメータはArray
で渡されます。
問題
次のコードを実行するとどうなりますか
h = {a: 100, b: 200}
h.each {|p|
p p.class
}
>> h = {a: 100, b: 200}
=> {:a=>100, :b=>200}
>> h.each {|p|
?> p p.class
>> }
Array
Array
=> {:a=>100, :b=>200}
市Array#each_cons(cnt)
はself
からcnt
個ずつ要素を取り出しブロックに渡します。ブロック引数には配列で渡されます。
取り出す要素は、[要素1, 要素2, 要素3], [要素2, 要素3, 要素4] ...
と1つづ前に進みます。
似たメソッドにArray#each_slick(cnt)
があります。
以下が、それぞれの実行結果です。
(1..10).each_cons(3) {|arr| p arr }
# <実行結果>
# [1, 2, 3]
# [2, 3, 4]
# [3, 4, 5]
# [4, 5, 6]
# [5, 6, 7]
# [6, 7, 8]
# [7, 8, 9]
# [8, 9, 10]
(1..10).each_slice(3) {|arr| p arr }
# <実行結果>
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
# [10]
問題
次のコードを実行するとどうなりますか
arr = (1..30).to_a
container = []
arr.each_cons(7) do |i|
container << i
end
p container.length
24
と表示される
5
と表示される
7
と表示される
0
と表示される
🔳Hash#to_a
はキーと値の2要素の配列を並べた配列を作成し、返します。
問題
次のコードを実行するとどうなりますか
h = {a: 100, b: 200}
p h.to_a
>> h = {a: 100, b: 200}
=> {:a=>100, :b=>200}
>> p h.to_a
[[:a, 100], [:b, 200]]
=> [[:a, 100], [:b, 200]]
🔳
String#==(other)
はother
が文字列の場合は、String#eql?
と同じ結果を返します。other
が文字列以外の場合は、other.to_s
の結果と比較します。
String#eql?
は同一文字列の場合にtrue
を返します。
ただし、自作クラスの場合はObject#eql?
をオーバーライドする必要があります。
さもなければ、同一の内容であるにもかかわらず、オブジェクトIDが異なるためfalse
になります。
問題
次のコードを実行するとどうなりますか
a1 = "abc"
a2 = 'abc'
print a1.eql? a2
print a1 == a2
>> a1 = "abc"
=> "abc"
>> a2 = 'abc'
=> "abc"
>>
?> print a1.eql? a2
true=> nil
>> print a1 == a2
true=> nil
🔳メソッドと変数の探索順位は変数が先です。
問題
次のコードを実行するとどうなりますか
hoge = 0
def hoge
x = 0
5.times do |i|
x += 1
end
x
end
puts hoge
>> hoge = 0
=> 0
>> def hoge
>> x = 0
>> 5.times do |i|
?> x += 1
>> end
>> x
>> end
=> :hoge
>> puts hoge
0
=> nil
String#%
はフォーマットされた文字列を返します。
フォーマットには、"%d"
や%s
などの指示子を用います。String#%
を用いると、指示子が引数の値で置換されます。
指示子の詳しい説明はRubyリファレンスを参照してください。
今回の問題では文字列"Hello"
にフォーマットに必要な指示子が無いためそのまま出力されます。
指示子を付与すれば次のように表示されます。
p "Hello%d" % 5 # => Hello5
問題
次のコードを実行するとどうなりますか
p "Hello" % 5
>> p "Hello" % 5
"Hello"
=> "Hello"
str.chop
は末尾の文字を取り除きます。ただし、文字列の末尾が"\r\n"
であれば、2文字とも取り除きます。
破壊的メソッドではないので、self
は影響を受けません。
Stringクラスの似たメソッドの説明を以下にまとめます。
メソッド名 | 説明 |
---|---|
strip |
文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除きます。 |
strip! |
文字列の先頭と末尾の空白文字(\t\r\n\f\v)を破壊的に取り除きます。 |
chomp |
末尾から改行コードを取り除きます。 |
chop |
末尾の文字を取り除きます。ただし、文字列の末尾が"\r\n" であれば、2文字とも取り除きます。 |
問題
次のコードを実行するとどうなりますか
str = "Liberty Fish \r\n"
str.chop
p str
🔳unless
は条件が成立しない場合に中の処理が実行されます。else
を用いることはできますが、elsif
を用いることはできません。
問題
次のコードを実行するとどうなりますか
def hoge(n)
unless n != 3
"hello"
elsif n == 5
"world"
end
end
str = ''
str.concat hoge(3)
str.concat hoge(5)
puts str
🔳
w+
recode 2
w+
は新規作成・読み込み + 書き込みモードで開きます。
既にファイルが存在する場合は、空になります。IO#seek
はファイルポインタを指定の位置に移動します。IO:SEEK_SET
がファイルの先頭からの位置を指定する識別子です。
よって、recode 1
を書き込み後にファイルの先頭にファイルポインタを移動し、recode 2
で上書きしています。
w
recode 2
w
は書き込みモードで開きます。
その他はw+
と同様です。
a+
recode 1
recode 2
a+
はファイルを読み込みモード + 追記書き込みモードで開きます。
ファイルの読み込みは、ファイルの先頭から行いますが、書き込みは、ファイルの末尾に行います。
a
recode 1
recode 2
a
はファイルを追記書き込みモードで開きます。
ファイルの読み込みを行うことはできません。読み込みを行なった場合は、not opened for reading (IOError)
が発生します。
問題
実行後の textfile.txt 内容になるようにXXXXに適切なコードを選べ。
ただし、空ファイルは作成済みである。
File.open('testfile.txt', XXXX) do |f|
f.write("recode 1\n")
f.seek(0, IO::SEEK_SET)
f.write("recode 2\n")
end
実行後の textfile.txt 内容
recode 1
recode 2
🔳
Hash#new(default)
は、空のHashを作成します。default
引数が指定された場合は、valueにdefault
が入ります。default
で作成された要素はp
メソッドなどでHash
の内容を参照する際は対象外になります。
問題
次のコードを実行するとどうなりますか
h = Hash.new("default value")
h[:a]
h[:b] = 100
p h
{:a => "default value", :b => 200}
と表示される
{:a => nil, :b => 200}
と表示される
{:b => 100}
と表示される
エラーが発生する
🔳
Array(3)
はArray([3])
と宣言したことと同じ意味になります。この時ブロックの内容は無視されます。
問題では、Fixnum
にupcase
メソッドが定義されていないためエラーになります。
Array#first
は配列の先頭要素を取得します。
Array.new(3){"a"}
は要素数3の配列を作成し、ブロックの値でそれぞれ初期化します。Array.new(3, "a")
は要素数3の配列を作成し、全要素を"a"
で初期化します。この時、"a"
は同一のオブジェクトを参照しています。
String#upcase
は非破壊メソッドなので、selfの内容は変わりません。String#upcase!
は破壊メソッドなので、selfの内容が変わります。
問題
実行結果にある結果を得るように選択肢からコードを選べ
#実行結果
["A", "a", "a"]
arr = Array(3){"a"}
arr.first.upcase
p arr
arr = Array(3){"a"}
arr.first.upcase!
p arr
arr = Array.new(3){"a"}
arr.first.upcase
p arr
arr = Array.new(3){"a"}
arr.first.upcase!
p arr
🔳Rubyではメソッド内で定数を定義することができません。
複数回メソッドを呼び出した場合に、定数が不定となるため定義できません。
宣言された場合は、SyntaxError
が発生します。
問題
以下のコードを実行するとどうなりますか
def hoge
x = 10
Y = x < 10 ? "C" : "D"
puts Y
end
hoge
🔳
Rubyの配列は0番からスタートします。
また、...
は終端を含みません。
よって、3番目から4番目のcd
が出力されます。
問題
次のコードを実行するとどうなりますか
str = "abcdefghijk"
p str[2...4]
🔳以下のコードはirbやpryではSyntaxErrorとなりますが、通常はSyntaxErrorとはなりません。
1: (1..10).each
2: .reverse_each
3: .each do |i|
4: puts i
5: end
以下のコードは1, 2行目の行末でバックスラッシュ()を記述することで、1行のコードとみなされます。
1: (1..10).each \
2: .reverse_each \
3: .each do |i|
4: puts i
5: end
問題
実行してもエラーにならないコードを選べ
(1..10).each
.reverse_each
.each do |i|
puts i
end
(1..10).each.
reverse_each.
each do |i|
puts i
end
(1..10).each \
.reverse_each \
.each do |i|
puts i
end
(1..10).to_a.each.
reverse_each.
each do |i|
puts i
end
"String"に"binary"メソッドはありません。
0xFF
:0x
は16進数を表すプレフィックスです。ここでは16進数を10進数に変換された、255
が表示されます。7.to_s(3)
:self
を3進数に変換した、21
が表示されます。
問題
次のコードのXXXX
に記述するとエラーが発生するコードはどれですか
puts XXXX
"80"
0xFF
7.to_s(3)
"7".binary
🔳Hash#delete(:key)
はレシーバーからkey
の項目を削除します。
このメソッドは破壊的メソッドです。
次のコードを実行するとどうなりますか
h = {a: 100, b: 200}
h.delete(:a)
p h
{:a => 100, :b => 200}
と表示される
{:a => nil, :b => 200}
と表示される
{:b => 200}
と表示される
エラーが発生する
🔳Time#+
はself
に加算します。単位は秒です。
問題
次のコード実行するとどうなりますか
puts Time.now + 3600
3600分後の時間を出力する
36秒後の時間を出力する
60分後の時間を出力する
6分後の時間を出力する
🔳Date#strftime
は引数のフォーマット文字列で日付を文字列で返します。
次の表が選択肢で使用されているフォーマット文字列の意味になります。
フォーマット文字列 | 意味 |
---|---|
%F |
日付(%Y-%m-%d ) |
%Y |
西暦4桁 |
%y |
西暦の下2桁(00-99) |
%m |
月を表す数字(01-12) |
%d |
日(01-31) |
問題
Date.today.strftime("%F")
と同じ動作をするコードを選びなさい
Date.today.strftime("%y-%m-%d")
Date.today.strftime("%y/%m/%d")
Date.today.strftime("%Y/%m/%d")
Date.today.strftime("%Y-%m-%d")
🔳数値を比較するメソッドの問題です。
Rubyでオブジェクトの比較をするメソッドは大きく分けて==
、eql?
、equal?
の3つがあります。
レシーバーをFixnumオブジェクトとした場合は次の通りです。
注意:Fixnum、BignumはRuby2.4からIntegerに統合されました。
-
==
Fixnumにあるメソッドです。
数値として等しいかを判定します。1
と1.0
は同じ数値として判定され、true
になります。p 1 == 1.0 # ture とされる
-
eql?
Numericクラスのメソッドです。
同じクラスのオブジェクトかつレシーバーにある==
メソッドで等しいと判定された場合にtrue
になります。p 1.eql? 1.0 # 1.0はFloatクラスのオブジェクトなので、`false`になります。 p 1.eql? (0 + 1) # 計算結果がFixnumクラスのオブジェクトかつ、数値として等しいので、`true`になります。
-
equal?
BasicObjectクラスのメソッドです。
オブジェクトIDが同じであれば、true
になります。
オブジェクトIDとは、オブジェクト毎に割り振られる整数値です。Fixnumなどのイミュータブルオブジェクトは常に同じオブジェクトIDになります。p 1.equal? 1.0 p 1.equal? (1 + 0)
この問題の実行結果は次のとおりです。
x = 1
y = 1.0
print x == y # 数値として等しいので、trueになります。
print x.eql? y # 1.0はFloatクラスのオブジェクトなので、falseになります。
print x.equal? y # 1.0は異なるオブジェクトIDを持つので、falseになります。
print x.equal?(1) # 1はどこで参照しても同じオブジェクトIDなので、trueになります。
答えはtruefalsefalsetrue
です。
問題
次のプログラムを実行するとどうなりますか。
x = 1
y = 1.0
print x == y
print x.eql? y
print x.equal? y
print x.equal?(1)
truetruetruetrue
と表示される
falsefalsefalsefalse
と表示される
truefalsefalsefalse
と表示される
truefalsefalsetrue
と表示される