【第4章】Ruby on Rails チュートリアル 6.0(第6版)演習と解答まとめ

目的

Ruby on Rails Tutorial最新版の演習と解答の第4章です。
ながらくRailsチュートリアルは無料の教材として人気でしたが、第6版から有料化されました。第4章以降は有料(2020年6月13日現在、980円+税)です。

Ruby on Rails チュートリアル 6.0(第6版)を学習中です。
学習を進める中で演習問題の解答を自分なりにまとめていくことにしました。

アウトプットし、自分の理解を深めることを目的としています。 もし、記載内容に誤りがあった場合はコメントいただけると幸いです。

演習問題と解答

演習4.2.1

演習4.2.1.1

<問題>city変数に適当な市区町村を、prefecture変数に適当な都道府県を代入してください。

<解答>コンソールでの入力になるので、rails consoleでコンソールを開きます。

>> city = "新宿区"
=> "新宿区"
>> prefecture = "東京都"
=> "東京都"

演習4.2.1.2

<問題>先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。

>> puts "#{prefecture} #{city}"
東京都 新宿区
=> nil

演習4.2.1.3

<問題>上記の文字列の間にある半角スペースをタブに置き換えてみてください。(ヒント: 改行文字と同じで、タブも特殊文字です)

<解答>Macでバックスラッシュはoption+¥です。

>> puts "#{prefecture} \t #{city}"                                                                                                                                                              
東京都   新宿区
=> nil

演習4.2.1.4

<問題>タブに置き換えた文字列を、ダブルクォートからシングルクォートに置き換えてみるとどうなるでしょうか?

<解答>

>> puts '#{prefecture} \t #{city}'                                                                                                                                                              
#{prefecture} \t #{city}
=> nil

演習4.2.2

演習4.2.2.1

<問題>”racecar” の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。

<解答>

>> "racecar".length
=> 7

演習4.2.2.2

<問題>reverseメソッドを使って、”racecar”の文字列を逆から読むとどうなるか調べてみてください。

<解答>

>> "racecar".reverse
=> "racecar"

演習4.2.2.3

<問題>変数sに “racecar” を代入してください。その後、比較演算子(==)を使って変数sとs.reverseの値が同じであるかどうか、調べてみてください。

<解答>

>> s = "racecar"
=> "racecar"
>> s == "racecar"
=> true

演習4.2.2.4

<問題>リスト 4.9を実行すると、どんな結果になるでしょうか? 変数sに “onomatopoeia” という文字列を代入するとどうなるでしょうか?(ヒント: 上矢印(またはCtrl-Pコマンド)を使って以前に使ったコマンドを再利用すると一からコマンドを全部打ち込む必要がなくて便利ですよ。)

<解答>

>> puts "It's a palidrome!" if s == s.reverse
It's a palidrome!
=> nil
>> s = "onomatopoeia"
=> "onomatopoeia"
>> puts "It's a palidrome!" if s == s.reverse
=> nil

演習4.2.3

演習4.2.3.1

<問題>リスト 4.10のFILL_INの部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。ヒント: リスト 4.9の比較方法を参考にしてください。

<解答>

>> def palindrome_tester(s)
>> if s == s.reverse
>> puts "It's a palindrome!"
>> else
>> puts "It's not a palindrome."
>> end
>> end
=> :palindrome_tester

演習4.2.3.2

<問題>上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。1つ目は回文である、2つ目は回文でない、という結果になれば成功です。

>> palindrome_tester("racecar")
It's a palindrome!
=> nil
>> palindrome_tester("onomatopoeia")
It's not a palindrome.
=> nil

演習4.2.3.3

<問題>palindrome_tester(“racecar”)に対してnil?メソッドを呼び出し、戻り値がnilであるかどうかを確認してみてください(つまりnil?を呼び出した結果がtrueであることを確認してください)。このメソッドチェーンは、nil?メソッドがリスト 4.10の戻り値を受け取り、その結果を返しているという意味になります。

<解答>

>> palindrome_tester("racecar").nil?
It's a palindrome!
=> true

演習4.3.1

演習4.3.1.1

<問題>文字列「A man, a plan, a canal, Panama」を “, ” で分割して配列にし、変数aに代入してみてください。

<解答>

>>a= "A man, a plan, a canal, Panama".split(', ')
=> ["A man", "a plan", "a canal", "Panama"]

演習4.3.1.2

<問題>今度は、変数aの要素を連結した結果(文字列)を、変数sに代入してみてください。

<解答>

>>s=a.join
=> "A mana plana canalPanama"

演習4.3.1.3

<問題>変数sを半角スペースで分割した後、もう一度連結して文字列にしてください(ヒント: メソッドチェーンを使うと1行でもできます)。リスト 4.10で使った回文をチェックするメソッドを使って、(現状ではまだ)変数sが回文ではないことを確認してください。downcaseメソッドを使って、s.downcaseは回文であることを確認してください。

<解答>

>>def palindrome_tester(s)
>> if s==s.reverse
>>  puts "It's a palindrome!"
>> else
>>  puts "It's not a palindrome."
>> end
>>end
=> :palindrome_tester

>>s = s.split.join
=> "AmanaplanacanalPanama"

>>palindrome_tester(s)
=>It's not a palindrome.
=> nil

>>palindrome_tester(s.downcase)
=>It's a palindrome!
=> nil

演習4.3.1.4

<問題>aからzまでの範囲オブジェクトを作成し、7番目の要素を取り出してみてください。同様にして、後ろから7番目の要素を取り出してみてください。(ヒント: 範囲オブジェクトを配列に変換するのを忘れないでください)


>> ('a'..'z').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
>> ('a'..'z').to_a[6] #添字は0から始まるので7番目は[6]
=> "g"
>> ('a'..'z').to_a[-7] #添字にマイナスをつけると配列の後ろから取得できる この配列の場合a[-1]はzになる
=> "t"                 #後ろから7番目はa[-7]

演習4.3.2

演習4.3.2.1

<問題>範囲オブジェクト0..16を使って、各要素の2乗を出力してください。

<解答>

>> (0..16).each do |i|
?> puts i**2
>> end
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
=> 0..16

演習4.3.2.2

<問題>yeller(大声で叫ぶ)というメソッドを定義してください。このメソッドは、文字列の要素で構成された配列を受け取り、各要素を連結した後、大文字にして結果を返します。例えばyeller([‘o’, ‘l’, ‘d’])と実行したとき、”OLD”という結果が返ってくれば成功です。ヒント: mapとupcaseとjoinメソッドを使ってみましょう。

<解答>

>> def yeller(s)
>>   s.map(&:upcase).join
>> end
=> :yeller

>> yeller(['o','l','d'])
=> "OLD"

演習4.3.2.3

<問題>random_subdomainというメソッドを定義してください。このメソッドはランダムな8文字を生成し、文字列として返します。ヒント: サブドメインを作るときに使ったRubyコードをメソッド化したものです。

<解答>

>> def random_subdomain
>> ('a'..'z').to_a.shuffle[0..7].join
>> end
=> :random_subdomain

>> random_subdomain
=> "mhwenvxb"

演習4.3.2.4

<問題>リスト 4.12の「?」の部分を、それぞれ適切なメソッドに置き換えてみてください。ヒント:split、shuffle、joinメソッドを組み合わせると、メソッドに渡された文字列(引数)をシャッフルさせることができます。

<解答>

>> def string_shuffle(s)
>> s.split('').shuffle.join
>> end
=> :string_shuffle

>> string_shuffle("foobar")
=> "rafobo"

charsメソッドを使っても同じ処理が実装できる

>> def string_shuffle(s)
>> s.chars.shuffle.join
>> end
=> :string_shuffle

>> string_shuffle("foobar")
=> "obofra"

演習4.3.3

演習4.3.3.1

<問題>キーが’one’、’two’、’three’となっていて、それぞれの値が’uno’、’dos’、’tres’となっているハッシュを作ってみてください。その後、ハッシュの各要素をみて、それぞれのキーと値を”‘#{key}’のスペイン語は’#{value}'”といった形で出力してみてください。

<解答>

>> num = { 'one' => 'uno', 'two' => 'dos', 'three' => 'tres' }                                                                                                                                  
=> {"one"=>"uno", "two"=>"dos", "three"=>"tres"}

>> num['one']
=> "uno"

>> num.each do |key, value|
?> puts "#{key}のスペイン語は#{value}"
>> end
oneのスペイン語はuno
twoのスペイン語はdos
threeのスペイン語はtres
=> {"one"=>"uno", "two"=>"dos", "three"=>"tres"}

演習4.3.3.2

<問題>person1、person2、person3という3つのハッシュを作成し、それぞれのハッシュに:firstと:lastキーを追加し、適当な値(名前など)を入力してください。その後、次のようなparamsというハッシュのハッシュを作ってみてください。1)キーparams[:father]の値にperson1を代入、2)キーparams[:mother]の値にperson2を代入、3)キーparams[:child]の値にperson3を代入。最後に、ハッシュのハッシュを調べていき、正しい値になっているか確かめてみてください。(例えばparams[:father][:first]がperson1[:first]と一致しているか確かめてみてください)

<解答>

>> person1 = { first: 'Hiroshi', last: 'Nohara' }                                                                                                                                               
=> {:first=>"Hiroshi", :last=>"Nohara"}
>> person2 = { first: 'Misae', last: 'Nohara' }                                                                                                                                                 
=> {:first=>"Misae", :last=>"Nohara"}
>> person3 = { first: 'Shin-nosuke', last: 'Nohara' }                                                                                                                                           
=> {:first=>"Shin-nosuke", :last=>"Nohara"}
>> params = { father: person1, mother: person2, child: person3 }                                                                                                        
=> {:father=>{:first=>"Hiroshi", :last=>"Nohara"}, :mother=>{:first=>"Misae", :last=>"Nohara"}, :child=>{:first=>"Shin-nosuke", :last=>"Nohara"}}
>> params[:father][:last]                                                                                                                                               
=> "Nohara"
>> params[:child][:first]
=> "Shin-nosuke"

演習4.3.3.3

<問題>userというハッシュを定義してみてください。このハッシュは3つのキー:name、:email、:password_digestを持っていて、それぞれの値にあなたの名前、あなたのメールアドレス、そして16文字からなるランダムな文字列が代入されています。

<解答>

16文字のランダムな文字列の生成に演習4.3.2.3の知識とconcatメソッドを利用します。
concatメソッドを使えば配列の末尾に別の配列を連結できます。

>> pass = ('a'..'z').to_a.concat((0..9).to_a).shuffle[0..15].join
=> "nsfire428dgkmqho"

>> user = { name: "フリーター大学職員", email: "masakilog.net@example.com", password_digest: pass }
=> {:name=>"フリーター大学職員", :email=>"masakilog.net@example.com", :password_digest=>"nsfire428dgkmqho"}
>> 

演習4.3.3.4

<問題>

Ruby API(訳注: もしくはるりまサーチ)を使って、Hashクラスのmergeメソッドについて調べてみてください。次のコードを実行せずに、どのような結果が返ってくるか推測できますか? 推測できたら、実際にコードを実行して推測があっていたか確認してみましょう。

{ "a" => 100, "b" => 200 }.merge({ "b" => 300 })

<解答>

もとのハッシュとmergeの引数を比較して、重複するキーがある場合はmergeの引数に上書き(統合)したハッシュを返します。
破壊的な変更ではありません。

>> hash = { "a" => 100, "b" => 200 }                                                                                                                                                            
=> {"a"=>100, "b"=>200}
>> hash.merge( { "b" => 300 })                                                                                                                                                                  
=> {"a"=>100, "b"=>300}
>> hash
=> {"a"=>100, "b"=>200}

演習4.4.1

演習4.4.1.1

<問題>1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか?(復習です)

<解答>

>> a = 1..10
=> 1..10

演習4.4.1.2

<問題>今度はRangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作ってみてください。ヒント: newメソッドに2つの引数を渡す必要があります

<解答>

>> b = Range.new(1, 10)
=> 1..10

演習4.4.1.3

<問題>比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。

<解答>

>> a == b
=> true

演習4.4.2

演習4.4.2.1

<問題>Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。

<解答>

>> a.class
=> Range
>> a.class.superclass
=> Object
>> a.class.superclass.superclass
=> BasicObject
>> a.class.superclass.superclass.superclass
=> nil

演習4.4.2.2

<問題>リスト 4.15にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。

<解答>
動作確認のみなので省略。
ルビー本では、本問のような場合はselfキーワードはつけてもつけなくてもいいとのことです。
selfキーワードの注意点として、セッターメソッド呼び出し時はselfキーワードが必須である点があげられています。

コメント

タイトルとURLをコピーしました