Rails tutorial 第4章


## 演習1
1，
city変数に適当な市区町村名を、prefecture変数に適当な都道府県名を代入してください。

```
prefecture = "栃木県"
=> "栃木県"
city = "佐野市"
=> "佐野市"
```


2,
先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。
```
puts "#{prefecture} #{city}"
栃木県 佐野市
```

3,
上記の文字列の間にある半角スペースをタブに置き換えてみてください。（ヒント: 改行文字と同じで、タブも特殊文字です。）
```
"#{prefecture}\t#{city}"
栃木県  佐野市
```

## 演習2

1,
"racecar" の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。
```
"racecar".length
=> 7
```

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

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

4,リスト 4.8を実行すると、どんな結果になるでしょうか? 変数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
```

## 演習3

1，
リスト 4.9の（コードを書き込む）の部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。（ヒント: リスト 4.8の比較方法を参考にしてください。）
```
  def palindrome_tester(s)
    if s == s.reverse
     puts "It's a palindrome!"
    else
     puts "It's not a palindrome."
    end
  end
```

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

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

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


## 演習4
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"]
 
```

2,
今度は、変数aの要素を連結した結果（文字列）を、変数sに代入してみてください。
```
 s = a.join
=> "A man a plan a canal Panama"
```
3,
変数sを半角スペースで分割した後、もう一度連結して文字列にしてください。
（ヒント: メソッドチェーンを使うと1行でもできます。）リスト 4.9で使った回文をチェックするメソッドを
使って、（現状ではまだ）変数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
palindrome_tester(s)
It's not a palindrome.
=> nil
palindrome_tester(s.downcase)
It's a palindrome!
=> nil


```

4,
aからzまでの範囲オブジェクトを作成し、7番目の要素を取り出してみてください。
同様にして、後ろから7番目の要素を取り出してみてください。
（ヒント: 範囲オブジェクトを配列に変換するのを忘れないでください。）
```
a =("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[6]
=> "g"
a[-7]
=> "t"


```

## 演習5

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

def yeller(s)
s.map(&:upcase).join
end
=> :yeller
yeller(['o','l','d'])
=> "OLD"

```

3,
リスト 4.11の「?」の部分を、それぞれ適切なメソッドに置き換えてみてください。
（ヒント:split、shuffle、joinメソッドを組み合わせると、
メソッドに渡された文字列（引数）をシャッフルさせることができます。）
```
def string_shuffle(s)
s.split('').shuffle.join
end
=> :string_shuffle
string_shuffle('foobar')
=> "borofa"
```

mapメソッドが若干分かりづらいので、以下のサイトを参考にしました
mapメソッドの使い方
https://www.sejuku.net/blog/58958

mapメソッドとeachメソッドの違い
https://qiita.com/massaaaaan/items/d90d10cb023bedc74fb2





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

```


a = {:one => "uno",:two => "dos", :three => "tres"}
=> {:one=>"uno", :two=>"dos", :three=>"tres"}
a.each do |key, value|
puts "#{key}はスペイン語で#{value}"
end
oneはスペイン語でuno
twoはスペイン語でdos
threeはスペイン語でtres
=> {:one=>"uno", :two=>"two", :three=>"tres"}
```

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]と一致しているか確かめてみてください）
```
parson1 = {:first =>"山田",:last=>"太郎" }
=> {:first=>"山田", :last=>"太郎"}
parson2 = {:first =>"山田",:last=>"花子" }
=> {:first=>"山田", :last=>"花子"}
parson3 = {:first =>"山田",:last=>"次郎" }
=> {:first=>"山田", :last=>"次郎"}
params = {}
=> {}

params[:father] = parson1
=> {:first=>"山田", :last=>"太郎"}
params[:mother] = parson2
=> {:first=>"山田", :last=>"花子"}
params[:child] = parson3
=> {:first=>"山田", :last=>"次郎"}
params[:father][:first]
=> "山田"
params[:mother][:last]
=> "花子"
```

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

```
password_digest = ('a'..'z').to_a.shuffle[0..15].join
=> "ujlfmowrsqhetizd"
user = {:name=>"高橋遼平",:email=>"ryohei.mail", :password_digest =>password_digest}
=> {:name=>"高橋遼平", :email=>"ryohei.mail", :password_digest=>"ujlfmowrsqhetizd"}
```

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

```
{ "a" => 100, "b" => 200 }.merge({ "b" => 300 })
=> {"a"=>100, "b"=>300} #内容が重複する場合は上書きされる
```

## 演習7
1,
1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか?（復習です）

```
s = (1..10)
=> 1..10
s.class
=> Range
```

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

```
a = Range.new(1,10)
=> 1..10
a.class
=> Range
```

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

```
s == a
=> true
```

## 演習8
1,
Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。
```
s = (1..10)
=> 1..10
s.class
=> Range
s.class.superclass
=> Object
s.class.superclass.superclass
=> BasicObject
s.class.superclass.superclass.superclass
=> nil

Range < Object < BasicObject


#ハッシュの継承階層
h = {}
=> {}
h.class
=> Hash
h.class.superclass
=> Object
h.class.superclass.superclass
=> BasicObject
h.class.superclass.superclass.superclass
=> nil

Hash=>Object=>BasicObject


#シンボルの継承階層
s = :symbol
=> :symbol
s.class
=> Symbol
s.class.superclass
=> Object
s.class.superclass.superclass
=> BasicObject
s.class.superclass.superclass.superclass
=> nil

Symbol=>Object=>BasicObject
```


2,
リスト 4.14にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。

```
class Word < String             
  def palindrome?
  self == reverse     
 end
end
=> :palindrome?
 S = Word.new("level")
 S.palindrome?
=> true
```
## 演習9
palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? （ヒント: downcaseメソッドで小文字にすることをお忘れなく。）
```
class Word < String             
def palindrome?
    self == reverse     
    end
   end
=> :palindrome?

 d = "racecar"
 => "racecar"
d.palindrome?
=> true

e = "onomatopoeia"
=> "onomatopoeia"
e.palindrome?
=> false

india = "Malayalam"
=> "Malayalam"
india.downcase.palindrome?
=> true

#別に代入しなくてもよい
```
2，
リスト 4.15を参考に、Stringクラスにshuffleメソッドを追加してみてください。（ヒント: リスト 4.11も参考になります。）
```
 class String
   def shuffle
     self.split('').shuffle.join　　　
   end
 end
=> :shuffle  

#splitがないと以下のようなエラーが出る
 stack level too deep (SystemStackError)
理由は解析中

```
3，
リスト 4.15のコードにおいて、self.を削除してもうまく動くことを確認してください。
```
 class String
   def shuffle
     split('').shuffle.join
   end
 end
=> :shuffle
 "foobar".shuffle
=> "rfoabo"
```

## 演習10

1,
第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。
```
 User.new
=> #<User:0x00007f11395b09b8 id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
```

※本来ここはcd ../toy_app/という感じでディレクトリ移動してからrails consoleという手順を踏んでいるらしいのですが、私は第2章のレポジトリを分けて作成しているので、ややこしいので割愛しています。

本来はこちらの手順が正しいようです
```
$ cd ../toy_app/
$ rails c
>> User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>

```

2,
生成したuserオブジェクトのクラスの継承階層を調べてみてください。

```
 user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
 user.class
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime)
>> user.class.superclass
=> ApplicationRecord(abstract)
irb(main):006:0> user.class.superclass.superclass
=> ActiveRecord::Base
irb(main):007:0> user.class.superclass.superclass.superclass
=> Object
irb(main):008:0> user.class.superclass.superclass.superclass.superclass
=> BasicObject
irb(main):009:0> user.class.superclass.superclass.superclass.superclass.superclass
=> nil

```
ApplicationRecord < ActiveRecord::Base < Object <  BasicObject

## 演習11

Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って "Michael Hartl" といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドの@nameの部分を、full_nameに置き換えてみましょう（元々の結果と同じになっていれば成功です）

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

#@nameを削除し、@first_nameと@last_nameに分ける

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

  def formatted_email
    "#{self.full_name} <#{@email}>"
  end

  def full_name
    "#{@first_name}#{@last_name}"
  end
end

```

```
user = User.new(first_name: "Michael",last_name:"Hartl", email: "mhartl@example.com")
=> #<User:0x00007f3e1b8e5ca0 @email="mhartl@example.com", @first_name="Michael", @last_name="Hartl">
user.full_name
=> "MichaelHartl"
user.formatted_email
=> "MichaelHartl <mhartl@example.com>"
```

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 formatted_email
    "#{self.full_name} <#{@email}>"
  end

  def full_name
    "#{@first_name}#{@last_name}"
  end

  def alphabetical_name
    "#{@first_name}, #{@last_name} "
  end
end
```

```
user = User.new(first_name: "Michael",last_name: "Heartl" , email: "mhartl@example.com")
=> #<User:0x00007f84e1d2b640 @email="mhartl@example.com", @first_name="Michael", @last_name="Heartl">
user.alphabetical_name
=> "Heartl, Michael "
```

4,
full_name.splitとalphabetical_name.split(', ').reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。

```
require './example_user'
=> true
user = User.new(first_name: "Michael", last_name: "Hartl", email: "mhartl@example.com")
=> #<User:0x00007efe0b488900 @email="mhartl@example.com", @first_name="Michael", @last_name="Hartl">
user.full_name.split == user.alphabetical_name.split(', ').reverse
=> false
user.full_name.split
=> ["MichaelHartl"]
user.alphabetical_name.split(', ').reverse
=> ["Hartl ", "Michael"]
```
※この辺ですが結果がfalseになる人もいればtrueになる人と別れるかもしれません。
人によっては"#{@last_name}と#{@first_name}"が逆になっている回答もあったので
ここは素直に私がやってみた回答を入れておきます。使い方、考え方が合っていればまあ良いかな、と
間違っていたらご指摘ください。