おぴよの気まぐれ日記

おぴよの気まぐれ日記

岡山やプログラミング、ファッションのこと、子育てや人生、生き方についての備忘録。

30歳まで残り2年の僕は人生を変えるためにRailsブートキャンプを始めようと思う(第4章:後半戦)

こんちには、opiyoです。

人生の生き残りをかけて始めた「Railsブートキャンプ」ですが、今日はRailsチュートリアル第4章をやっていこうと思います。

第4章は「Ruby」のお勉強です。早速やってみましょう!

この記事は後半戦になります。

前半戦はこちらからどうぞ。

opiyotan.hatenablog.com

クラス

  • メソッドをまとめるのにクラスを使用する
  • これらのクラスからインスタンスを作成するとオブジェクトができる
  • リテラルコンストラクタ
> s = "opiyo"
=> "opiyo"
> s.class
=> String
  • 名前付きコンストラクタとは、クラス名に対してnewメソッドを呼び出す
  • Hashの場合は引数がデフォルト値になる
# 文字列
> d = String.new("Opiyo")
=> "Opiyo"
> d.class
=> String
> d == "Opiyo"
=> true

# 配列
> a = Array.new([1, 3, 2])
=> [1, 3, 2]

# Hash
> h = Hash.new
=> {}
> h[:foo]            # 存在しないキー (:foo) の値にアクセスしてみる
=> nil
> h = Hash.new(0)    # 存在しないキーのデフォルト値をnilから0にする
=> {}
> h[:foo]
=> 0
  • クラスの継承
> s = String.new("foobar")
=> "foobar"
> s.class
=> String
> s.class.superclass
=> Object
> s.class.superclass.superclass
=> BasicObject
> s.class.superclass.superclass.superclass
=> nil
  • 組み込みの基本クラスの拡張が可能
> class String
>   # 文字列が回文であればtrueを返す
>   def palindrome?
>     self == self.reverse
>   end
> end
=> nil
> "deified".palindrome?
=> true
  • コントローラークラスの継承
> controller = StaticPagesController.new
=> #<StaticPagesController:0x007fec80a64130 @_action_has_layout=true, @_routes=nil, @_request=nil, @_response=nil>
> controller.class
=> StaticPagesController
> controller.class.superclass
=> ApplicationController
> controller.class.superclass.superclass
=> ActionController::Base
> controller.class.superclass.superclass.superclass
=> ActionController::Metal
> controller.class.superclass.superclass.superclass.superclass
=> AbstractController::Base
> controller.class.superclass.superclass.superclass.superclass.superclass
=> Object
> controller.class.superclass.superclass.superclass.superclass.superclass.superclass
=> BasicObject
> controller.class.superclass.superclass.superclass.superclass.superclass.superclass.superclass
=> nil

演習4.4.1 コンストラクタ

4.4.1.1

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

<回答>

> r = 1..10
=> 1..10
> r.class
=> Range

4.4.1.2

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

<回答>

> r = Range.new(1,10)
=> 1..10
> r.class
=> Range

4.4.1.3

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

<回答>

>  r = 1..10
=> 1..10
> rn = Range.new(1,10)
=> 1..10
> r == rn
=> true

演習4.4.2 クラス継承

4.4.2.1

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

<回答>

# Range
> r = Range.new(1,10)
=> 1..10
> r.class
=> Range
> r.class.superclass
=> Object
> r.class.superclass.superclass
=> BasicObject
> r.class.superclass.superclass.superclass
=> nil

# Hash
h = Hash.new(0)
=> {}
> h.class
=> Hash
> h.class.superclass
=> Object
> h.class.superclass.superclass
=> BasicObject
> h.class.superclass.superclass.superclass
=> nil

# Symbol
:symbol
=> :symbol
> :symbol.class
=> Symbol
> :symbol.class.superclass
=> Object
> :symbol.class.superclass.superclass
=> BasicObject
> :symbol.class.superclass.superclass.superclass
=> nil

4.4.2.2

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

<回答>

> class Word < String
>   def palindrome?
>     self == self.reverse
>   end
> end
=> :palindrome?
> s = Word.new("level")
=> "level"
> s.palindrome?
=> true
> s.length
=> 5

> class Word < String
>   def palindrome?
>     self == reverse
>     end
>   end
=> :palindrome?
> Word.new("level")
> s.palindrome?
=> true
> s.length
=> 5

演習 4.4.3 組み込みクラスの変更

4.4.3.1

<問題>palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? ヒント: downcaseメソッドで小文字にすることを忘れないで。

<回答>

> "racecar".palindrome?
=> true
> "onomatopoeia".palindrome?
=> false
> "Malayalam".downcase.palindrome?
=> true

4.4.3.2

<問題>リスト 4.16を参考に、Stringクラスにshuffleメソッドを追加してみてください。 ヒント: リスト 4.12も参考になります。

<回答>

> class String
>   def shuffle
>     self.split("").shuffle.join
>   end
> end
=> :shuffle
> "foobar".shuffle
=> "ofbaro"

4.4.3.3

<問題>リスト 4.16のコードにおいて、self.を削除してもうまく動くことを確認してください。

<回答>

> class String
>   def shuffle
>     split("").shuffle.join
>   end
> end
=> :shuffle
> "foobar".shuffle
=> "rafobo"

演習 4.4.4 コントローラークラス

4.4.4.1

<問題>第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。

<回答>

> u = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>

4.4.4.2

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

<回答>

> u.class
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime)
> u.class.superclass
=> ApplicationRecord(abstract)
> u.class.superclass.superclass
=> ActiveRecord::Base
> u.class.superclass.superclass.superclass
=> Object
> u.class.superclass.superclass.superclass.superclass
=> BasicObject
> u.class.superclass.superclass.superclass.superclass.superclass
=> nil

演習 4.4.5 ユーザークラス

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 :first_name, :last_name, :email

  def initialize(attributes = {})
    @name  = attributes[:first_name]
    @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
# rails c
> require './example_user'
=> true
> u = User.new(first_name: "Haku", last_name: "Nagano", email: "haku@co.jp")
=> #<User:0x007f8d718ab8c0 @first_name="Haku", @last_name="Nagano", @email="haku@co.jp">
> u.full_name
=> "HakuNagano"
> u.email = "Haku@co.jp"
=> "Haku@co.jp"
> u.formatted_email
=> "HakuNagano <Haku@co.jp>"

4.4.5.2

<問題>"Hartl, Michael" といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。

<回答>

  def alphabetical_name
    "#{first_name}, #{last_name}"
  end
# rails c
> require './example_user'
=> true
> u = User.new(first_name: "Haku", last_name: "Nagano", email: "haku@co.jp")
=> #<User:0x007f8d6b3d2048 @first_name="Haku", @last_name="Nagano", @email="haku@co.jp">
> u.alphabetical_name
=> "Haku, Nagano"

4.4.5.3

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

<回答> ?再度確認する