Railsチュートリアル第4章

#4.2　文字列とメソッド
##4.2.2　文字列
###演習1
city変数に適当な市区町村を、prefecture変数に適当な都道府県を代入してください。

```
>> city = "長岡京市"
=> "長岡京市"
>> prefecture
=> "京都府"
```
<br>
###演習2
先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。

```
>> puts "#{prefecture} #{city}"
京都府 長岡京市
=> nil
```
<br>
###演習3
上記の文字列の間にある半角スペースをタブに置き換えてみてください。(ヒント: 改行文字と同じで、タブも特殊文字です)

```
>> puts prefecture + " " + city
京都府 長岡京市
=> nil
```
<br>
###演習4
タブに置き換えた文字列を、ダブルクォートからシングルクォートに置き換えてみるとどうなるでしょうか?

```
>>  puts prefecture + ' ' + city                                                      
京都府 長岡京市
=> nil
```
##4.2.3　オブジェクトとメッセージ受け渡し
###演習1
"racecar" の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。

```
>> "racecar".length
=> 7
```
<br>
###演習2
reverseメソッドを使って、"racecar"の文字列を逆から読むとどうなるか調べてみてください。

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

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

```
>> puts "It's a palindrome!" if s == s.reverse
It's a palindrome!
=> nil

>> s = "onomatopoeia"
=> "onomatopoeia"
>> puts "It's a palindrome!" if s == s.reverse
=> nil
```
<br>
##4.2.4　メソッドの定義
###演習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
```
<br>
###演習2
上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。１つ目は回文である、２つ目は回文でない、という結果になれば成功です。

```
>> puts palindrome_tester("racecar")
It's a palindrome!

>> puts palindrome_tester("onomatopoeia")
It's not a palindrome.
```
<br>
###演習3
palindrome_tester("racecar")に対してnil?メソッドを呼び出し、戻り値がnilであるかどうかを確認してみてください (つまりnil?を呼び出した結果がtrueであることを確認してください)。このメソッドチェーンは、nil?メソッドがリスト 4.10の戻り値を受け取り、その結果を返しているという意味になります。

```
>> palindrome_tester("racecar").nil?
It's a palindrome!
=> true
```
#4.3　他のデータ構造
##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"]
```
<br>
###演習2
今度は、変数aの要素を連結した結果 (文字列) を、変数sに代入してみてください。

```
>> s = a.join
=> "A man a plan a canal Panama"
```
<br>
###演習3
変数sを半角スペースで分割した後、もう一度連結して文字列にしてください (ヒント: メソッドチェーンを使うと１行でもできます)。リスト 4.10で使った回文をチェックするメソッドを使って、(現状ではまだ) 変数sが回文ではないことを確認してください。downcaseメソッドを使って、s.downcaseは回文であることを確認してください。

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

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

>> puts palindrome_tester(s.split.join)
It's a palindrome!

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

```
>> az = ("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"]

>> az[6]
=> "g"
```
##4.3.2　ブロック
###演習1
範囲オブジェクト0..16を使って、各要素の２乗を出力してください。

```
>> (0..16).each do |number|
?> puts number * number
>> end
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
=> 0..16
``` 
<br>
###演習2
yeller (大声で叫ぶ) というメソッドを定義してください。このメソッドは、文字列の要素で構成された配列を受け取り、各要素を連結した後、大文字にして結果を返します。例えばyeller(['o', 'l', 'd'])と実行したとき、"OLD"という結果が返ってくれば成功です。ヒント: mapとupcaseとjoinメソッドを使ってみましょう。

```
>> def yeller(s)
>>   s.map(&:upcase).join
>> end
=> :yeller
>> yeller(['o','l','d'])
=> "OLD"
```
<br>
###演習3
random_subdomainというメソッドを定義してください。このメソッドはランダムな8文字を生成し、文字列として返します。ヒント: サブドメインを作るときに使ったRubyコードをメソッド化したものです。

```
>> def random_subdomain
>>   ('a'..'z').to_a.shuffle[0..7].join
>> end
=> :random_subdomain
>> random_subdomain
=> "vxasynrk"
```
<br>
###演習4
12の「?」の部分を、それぞれ適切なメソッドに置き換えてみてください。ヒント:split、shuffle、joinメソッドを組み合わせると、メソッドに渡された文字列 (引数) をシャッフルさせることができます。

```
>> def string_shuffle(s)
>>   s.split('').shuffle.join
>> end
=> :string_shuffle
>> string_shuffle("foobar")
=> "borfoa"
```
<br>
##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.each do |key,value|
?> puts "'#{key}'のスペイン語は'#{value}'"
>> end
'one'のスペイン語は'uno'
'two'のスペイン語は'dos'
'three'のスペイン語は'tres'
=> {:one=>"uno", :two=>"dos", :three=>"tres"}
```
<br>
###演習2
person1、person2、person3という３つのハッシュを作成し、それぞれのハッシュに:firstと:lastキーを追加し、適当な値 (名前など) を入力してください。その後、次のようなparamsというハッシュのハッシュを作ってみてください。1.) キーparams[:father]の値にperson1を代入、2). キーparams[:mother]の値にperson2を代入、3). キーparams[:child]の値にperson3を代入。最後に、ハッシュのハッシュを調べていき、正しい値になっているか確かめてみてください。(例えばparams[:father][:first]がperson1[:first]と一致しているか確かめてみてください)

```
>> person1 = { first: "O", last: "ton" }
=> {:first=>"O", :last=>"ton"}
>> person2 = { first: "O", last: "kan" }
=> {:first=>"O", :last=>"kan"}
>> person3 = { first: "Chi", last: "bi" }
=> {:first=>"Chi", :last=>"bi"}

>> params = {}
=> {}
>> params[:father] = person1
=> {:first=>"O", :last=>"ton"}
>> params[:mother] = person2
=> {:first=>"O", :last=>"kan"}
>> params[:child] = person3
=> {:first=>"Chi", :last=>"bi"}

>> params
=> {:father=>{:first=>"O", :last=>"ton"}, :mother=>{:first=>"O", :last=>"kan"}, :child=>{:first=>"Chi", :last=>"bi"}}

>> params[:father][:first] == person1[:first]
=> true
>> params[:father][:last] == person1[:last]                             
=> true

>> params[:mother][:first] == person2[:first]                               
=> true
>> params[:mother][:last] == person2[:last]                             
=> true

>> params[:child][:first] == person3[:first]                                
=> true
>> params[:child][:last] == person3[:last]                              
=> true
```
<br>
###演習3
userというハッシュを定義してみてください。このハッシュは３つのキー:name、:email、:password_digestを持っていて、それぞれの値にあなたの名前、あなたのメールアドレス、そして16文字からなるランダムな文字列が代入されています。

```
#16文字からなるランダムな文字列
>> ('a'..'z').to_a.shuffle[0..15].join
=> "xpymdiclnukwgeav"

>> user = { name: "nissiy", email: "nissy@email.com", password_digest: "xpymdiclnukwgeav" } 
=> {:name=>"nissiy", :email=>"nissy@email.com", :password_digest=>"xpymdiclnukwgeav"}
```
<br>
###演習4
Ruby API (訳注: もしくはるりまサーチ) を使って、Hashクラスのmergeメソッドについて調べてみてください。次のコードを実行せずに、どのような結果が返ってくるか推測できますか? 推測できたら、実際にコードを実行して推測があっていたか確認してみましょう。
``{ "a" => 100, "b" => 200 }.merge({ "b" => 300 })``

```
>> { "a" => 100, "b" => 200 }.merge({ "b" => 300 })
=> {"a"=>100, "b"=>300}
```
重複する``"b" => 200``は因数が適用される？
<br>
#4.4　Rubyにおけるクラス
##4.4.1　コンストラクタ
###演習1
1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか? (復習です)

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

```
>> b = Range.new(1,10)
=> 1..10
```
<br>
###演習3
比較演算子==を使って、上記２つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。
```
>> a == b
=> true
```
##4.4.2　クラス継承
###演習1
Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。

```
>> Range.superclass
=> Object
>> Range.superclass.superclass
=> BasicObject
>> Range.superclass.superclass.superclass
=> nil
```
```
>> Hash.superclass
=> Object
>> Hash.superclass.superclass
=> BasicObject
>> Hash.superclass.superclass.superclass
=> nil
```
```
>> Symbol.superclass
=> Object
>> Symbol.superclass.superclass
=> BasicObject
>> Symbol.superclass.superclass.superclass
=> nil
```
<br>
###演習2
リスト 4.15にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。

```
>> class Word < String
>>   def palindrome?
>>     self == reverse
>>   end
>> end
=> :palindrome?

>> s = Word.new("level")
=> "level"
>> s.palindrome?
=> true
```

##4.4.3　組み込みクラスの変更
###演習1
palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? ヒント: downcaseメソッドで小文字にすることを忘れないで。

```
>> class String
>>   def palindrome?
>>     self == self.reverse
>>   end
>> end
=> :palindrome?

>> "racecar".palindrome?
=> true

>> "onomatopoeia".palindrome?
=> false

>> "Malayalam".downcase.palindrome?
=> true
```
<br>
###演習2
リスト 4.16を参考に、Stringクラスにshuffleメソッドを追加してみてください。ヒント: リスト 4.12も参考になります。

```
>> class String
>>   def shuffle
>>     self.split('').shuffle.join
>>   end
>> end
=> :shuffle

>> "foobar".shuffle
=> "borafo"
```
<br>
###演習3
リスト 4.16のコードにおいて、self.を削除してもうまく動くことを確認してください。

```
>> class String
>>   def shuffle
>>     split('').shuffle.join
>>   end
>> end
=> :shuffle

>> "hogehoge".shuffle
=> "ggoeehoh"
```
##4.4.4　コントローラクラス
###演習1
第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。

```
>> User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
```
<br>
###演習2
生成したuserオブジェクトのクラスの継承階層を調べてみてください。

```
>> User.class
=> Class
>> User.class.superclass
=> Module
>> User.class.superclass.superclass
=> Object
>> User.class.superclass.superclass.superclass
=> BasicObject
>> User.class.superclass.superclass.superclass.superclass
=> nil
```
##4.4.5　ユーザークラス
###演習1
Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って "Michael Hartl" といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドのnameの部分を、full_nameに置き換えてみましょう (元々の結果と同じになっていれば成功です)

```example_user.rb
class User
  attr_accessor :name, :email

  def initialize(attributes = {})
    @first_name  = attributes[:first_name]
    @last_name  = attributes[:last_name]
    @email = attributes[:email]
  end
  
  def full_name
    @full_name = "#{@first_name} #{@last_name}"
  end

  def formatted_email
    "#{@full_name} <#{@email}>"
  end
end
```
```console
>> user = User.new(first_name: "Michael", last_name: "Hartl", email: "mhartl@example.com")
=> #<User:0x0000000003330bf0 @first_name="Michael", @last_name="Hartl", @email="mhartl@example.com">

>> user.full_name
=> "Michael Hartl"

>> user.formatted_email
=> "Michael Hartl <mhartl@example.com>"
```
<br>
###演習2
"Hartl, Michael" といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。

```example_user.rb
class User
  attr_accessor :name, :email

  def initialize(attributes = {})
    @first_name  = attributes[:first_name]
    @last_name  = attributes[:last_name]
    @email = attributes[:email]
  end
  
  def full_name
    @full_name = "#{@first_name} #{@last_name}"
  end
  
  def alphabetical_name
    @alphabetical_name =  "#{@last_name}, #{@first_name}"
  end

  def formatted_email
    "#{@full_name} <#{@email}>"
  end
end
```
```console
>> require './example_user'
=> true

>> user = User.new(first_name: "Michael", last_name: "Hartl", email: "mhartl@example.com")
=> #<User:0x00007fda40a440f8 @first_name="Michael", @last_name="Hartl", @email="mhartl@example.com">

>> user.alphabetical_name
=> "Michael, Hartl"
```
<br>
###演習3
full_name.splitとalphabetical_name.split(', ').reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。

```console
>> user.full_name.split
=> ["Michael", "Hartl"]

>> user.alphabetical_name.split(', ').reverse
=> ["Hartl", "Michael"]
```