【Railsチュートリアル】第4章 演習問題解答 1/2
の続きです。
ここからクラスを扱いだします。
- 1. 4.4.1 コンストラクタ
- 2. 4.4.2 クラス継承
- 3. 4.4.3 組み込みクラスの変更
- 4. 4.4.4 コントローラクラス
- 5. 4.4.5 ユーザークラス
- 5.1. 1.Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って “Michael Hartl” といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドのnameの部分を、full_nameに置き換えてみましょう (元々の結果と同じになっていれば成功です)
- 5.2. 2.”Hartl, Michael” といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。
- 5.3. 3.full_name.splitとalphabetical_name.split(’, ’).reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。
4.4.1 コンストラクタ
1.1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか? (復習です)
解答
リテラルコンストラクタってのはnewとかしないでクラス作ってくれちゃうやつ
そんな認識でいいんじゃないかな。ざっくりわかることも大事です。
つまりはRange.new(〜〜)ってしないでどうやってRangeオブジェクト作ってましたか?
って問題
こうやってやってましたね。
irb(main):166:0> a = 1..10 => 1..10 irb(main):167:0> a.class => Range
2.今度はRangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作ってみてください。ヒント: newメソッドに2つの引数を渡す必要があります
解答
Rangeは引数は始まりと終わりの2つ引数が必要です。
以下のようになります。
irb(main):169:0> b = Range.new(1,10) => 1..10
3.比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください
解答
変数名適当すぎたのを今になって後悔w
1.ではa,2.ではbとしていたので、以下のようになります。
irb(main):170:0> a == b => true
4.4.2 クラス継承
1.Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。
解答
先ほどのbを使って調べてみます。
irb(main):174:0> b.class => Range irb(main):175:0> b.class.superclass => Object irb(main):176:0> b.class.superclass.superclass => BasicObject irb(main):177:0> b.class.superclass.superclass.superclass => nil
Range=>Object=>BasicObject
となることがわかりました。
ハッシュも同様に
irb(main):180:0> h = {} => {} irb(main):181:0> h.class => Hash irb(main):182:0> h.class.superclass => Object irb(main):183:0> h.class.superclass.superclass => BasicObject irb(main):184:0> h.class.superclass.superclass.superclass => nil
Hash=>Object=>BasicObject
となります。
シンボルも同様に
irb(main):185:0> s = :symbol => :symbol irb(main):186:0> s.class => Symbol irb(main):187:0> s.class.superclass => Object irb(main):188:0> s.class.superclass.superclass => BasicObject irb(main):189:0> s.class.superclass.superclass.superclass => nil
となるので
Symbol=>Object=>BasicObject
となることがわかります。
2.リスト 4.15にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。
解答
self.reverseをreverseとして定義しました。
irb(main):190:0> class Word < String irb(main):191:1> def palindrome? irb(main):192:2> self == reverse irb(main):193:2> end irb(main):194:1> end => :palindrome?
Stringクラスを継承したWordクラスのインスタンスは
palindrome?というメソッドを使うことで回文かどうか調べられるようになったわけなので、
それを確かめたいと思います。
irb(main):201:0> ss = Word.new("abc") => "abc" irb(main):202:0> ss.palindrome? => false irb(main):203:0> ss = Word.new("abcba") => "abcba" irb(main):204:0> ss.palindrome? => true
最初はabcは回文でないのでfalse、abcbaは回文となるのでtrueを返します。
OKですね。
4.4.3 組み込みクラスの変更
Rubyは基本クラスまでいじれるんですよ。というのがミソ。
irb(main):205:0> class String irb(main):206:1> def palindrome? irb(main):207:2> self == self.reverse irb(main):208:2> end irb(main):209:1> end => :palindrome?
Stringクラスにpalindromeメソッドを追加しました。
1.palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? ヒント: downcaseメソッドで小文字にすることを忘れないで。
解答
ほぼ復習ですね。
irb(main):210:0> "racecar".palindrome? => true irb(main):211:0> "onomatopoeia".palindrome? => false irb(main):212:0> "Malayalam".downcase.palindrome? => true
2.リスト 4.16を参考に、Stringクラスにshuffleメソッドを追加してみてください。ヒント: リスト 4.12も参考になります。
解答
これも復習ですね。
irb(main):213:0> class String irb(main):214:1> def shuffle irb(main):215:2> self.split('').shuffle.join irb(main):216:2> end irb(main):217:1> end => :shuffle irb(main):218:0> "foobar".shuffle => "fraoob"
3.リスト 4.16のコードにおいて、self.を削除してもうまく動くことを確認してください。
解答
selfは省略できるというお話です。
irb(main):219:0> class String irb(main):220:1> def shuffle irb(main):221:2> split('').shuffle.join irb(main):222:2> end irb(main):223:1> end => :shuffle irb(main):224:0> "foobar".shuffle => "fobroa"
4.4.4 コントローラクラス
1.第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。
解答
実際に確かめてみればOKです。
$ cd ../toy_app/ $ rails c Running via Spring preloader in process 25622 Loading development environment (Rails 5.1.4) irb(main):001:0> User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
2.生成したuserオブジェクトのクラスの継承階層を調べてみてください。
解答
手順は変わりません。
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):002:0> user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> irb(main):003:0> user.class => User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime) irb(main):004:0> user.class.superclass => ApplicationRecord(abstract) irb(main):005:0> user.class.superclass.superclass => ActiveRecord::Base irb(main):006:0> user.class.superclass.superclass.superclass => Object irb(main):007:0> user.class.superclass.superclass.superclass.superclass => BasicObject irb(main):008:0> user.class.superclass.superclass.superclass.superclass.superclass => nil
User=>ApplicationRecord=>ActiveRecord::Base=>Object=>BasicObject
となります。
4.4.5 ユーザークラス
(オワビ)exsample_user.rbを作らずコンソールでやってしまいました…
結果は変わらないので、優しい目で見てください…
1.Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って “Michael Hartl” といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドのnameの部分を、full_nameに置き換えてみましょう (元々の結果と同じになっていれば成功です)
解答
ちょっと長いのでコメントいれてみました。
- nameがfirst_nameとlast_nameに分かれること
- formatted_emailで自クラスの関数を実行するためにselfを使用する
以上がポイントかと思います。
irb(main):444:0> class User irb(main):445:1> #nameを分割 irb(main):446:1* attr_accessor :first_name,:last_name, :email irb(main):447:1> irb(main):448:1* #nameを分割 irb(main):449:1* def initialize(attributes = {}) irb(main):450:2> @first_name = attributes[:first_name] irb(main):451:2> @last_name = attributes[:first_name] irb(main):452:2> @email = attributes[:email] irb(main):453:2> end irb(main):454:1> irb(main):455:1* #full_nameメソッドを追加 irb(main):456:1* def full_name irb(main):457:2> "#{@first_name} #{@last_name}" irb(main):458:2> end irb(main):459:1> irb(main):460:1* #nameをfull_nameにした irb(main):461:1* def formatted_email irb(main):462:2> "#{self.full_name} <#{@email}>" irb(main):463:2> end irb(main):464:1> end => :formatted_email irb(main):465:0> user = User.new => #<User:0x007fc1897b2a80 @first_name=nil, @last_name=nil, @email=nil> irb(main):466:0> user.first_name = "Michael" => "Michael" irb(main):467:0> user.last_name = "Hartl" => "Hartl" irb(main):468:0> user.email = "mhartl@example.com" => "mhartl@example.com" irb(main):469:0> user.formatted_email => "Michael Hartl <mhartl@example.com>"
2.”Hartl, Michael” といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。
解答
クラスは拡張ができるので、1から宣言せずとも追加するものだけ書けばいいです。
irb(main):480:0> class User irb(main):481:1> def alphabetical_name irb(main):482:2> "#{@last_name}, #{@first_name}" irb(main):483:2> end irb(main):484:1> end => :alphabetical_name irb(main):485:0> irb(main):486:0* user.alphabetical_name => "Hartl, Michael"
3.full_name.splitとalphabetical_name.split(’, ’).reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。
解答
両者実行して確かめれば良いです。
userを頭につけてくださいね。
irb(main):498:0> user.full_name.split => ["Michael", "Hartl"] irb(main):499:0> user.alphabetical_name.split(', ').reverse => ["Michael", "Hartl"]
あーやっちまった。
まあいいでしょうということにしておきましょう(そうさせてください)
(おまけ)
一応ちゃんとやりなおしました。
よかったら見てやってください。
プログラム
class User attr_accessor :first_name,:last_name, :email def initialize(attributes = {}) @first_name = attributes[:firt_name] @last_name = attributes[:last_name] @email = attributes[:email] end def full_name "#{@first_name} #{@last_name}" end def formatted_email "#{self.full_name} <#{@email}>" end def alphabetical_name "#{@last_name}, #{@first_name}" end end
コンソール実行結果
irb(main):001:0> require './example_user' => true irb(main):002:0> user = User.new => #<User:0x007fc189adae88 @first_name=nil, @last_name=nil, @email=nil> irb(main):003:0> user.first_name = "Michael" => "Michael" irb(main):004:0> user.last_name = "Hartl" => "Hartl" irb(main):005:0> user.email = "mhartl@example.com" => "mhartl@example.com" irb(main):006:0> user.formatted_email => "Michael Hartl <mhartl@example.com>" irb(main):007:0> user.alphabetical_name => "Hartl, Michael" irb(main):008:0> user.full_name.split => ["Michael", "Hartl"] irb(main):009:0> user.alphabetical_name.split(', ').reverse => ["Michael", "Hartl"]
4章長かったぁ。。
でもこの章は2周目で理解が深まるゾーンですね。
以上、コジマでした。