#Rails風味のRuby
■第4章
第3章のRailsアプリケーションを基にRubyを扱っていく。
##4.1 動機
Rubyの基礎知識が全くない中でも、Railsアプリケーションの骨組みを作り上げ、さらにテストまで行うことができた。この章ではもっといろんなことをやっていく。
まずはトピックブランチを作成して作業を進める
$git checkout -b rails-flavored-ruby
###4.1.1 組み込みヘルパー
app/views/layouts/application.html.erb
の中身について解説。
###4.1.2 カスタムヘルパー
4.1.1と同じファイルの解説。
しビューの1つからprovide呼び出しを削除すると、そのページ固有のタイトルの代わりに次のタイトルが表示される
| Ruby on Rails Tutorial Sample App
余分な縦棒が入ってしまう。ページタイトルが正しく表示されない問題を解決するために、full_titleというヘルパーを作成する。
これでapp/views/layouts/application.html.erbを書き換えると、|が入ったり入らなかったりしてくれる。
test/controllers/static_pages_controller_test.rbのテストを更新。これでテストしてみると
$ rails test
3 tests, 6 assertions, 1 failures, 0 errors, 0 skips
Redに。テストがパスするためには、Homeページのビューからprovideを行を削除。これでテストはパスできました。
##4.2 文字列とメソッド
Railsコンソールはirb (IRB: Interactive RuBy) を拡張して作られているので、Rubyの機能をすべて使うことできる。
ホームディレクトリに.irbrcファイルを作ってみる
$ nano ~/.irbrc
irbファイルの中身に追記して、保存。
$ rails console
Loading development environment
>>
Railsコンソールを起動したらこんな感じに。デフォルトではdevelopment(開発)環境で実行される。(他にtest(テスト)環境とproduction(本番)環境がある)railsコンソールでおかしくなったらCtrl+cで強制的に抜け出す。Ctrl+Dで正常に抜け出す。
###4.2.1 コメント
#
でコメントを残せる。
###4.2.2 文字列
文字列(string)は、Webアプリケーションにおいておそらく最も重要なデータ構造。
ここらへんは一回やったことあるので割愛。
###4.2.3 オブジェクトとメッセージ受け渡し
Rubyでは、あらゆるものがオブジェクトです。文字列やnilですらオブジェクト。
ここでもいろんなメソッドの紹介。
###4.2.4 メソッドの定義
defでやる。rubyでは戻り値がなくても暗黙の戻り値がある。
###4.2.5 titleヘルパー、再び
module ApplicationHelperについて
モジュールは、関連したメソッドをまとめる方法の1つで、includeメソッドを使ってモジュールを読み込むことができます (ミックスイン(mixed in)とも呼びます)。Railsでは自動的にヘルパーモジュールを読み込んでくれるので、include行をわざわざ書く必要がない。
full_titleメソッドは自動的にすべてのビューで利用できるようになっている。
##4.3 他のデータ構造
Webアプリケーションは突き詰めればただの文字列だが、文字列を作るための文字列以外のデータ構造も必要。
###4.3.1 配列と範囲演算子
配列とかはちょっと怪しいとこなんで、コード書いていきたいと思います。
splitメソッドを使うと、文字列を自然に変換した配列を得られる。
>> "foo bar baz".split
=> ["foo", "bar", "baz"]
このメソッドにより、3つの文字列からなる配列ができた。
xで切り分けることも
>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]
数字以外でも配列の要素にアクセスできる。
>> a # 配列「a」の内容を確認する
=> [42, 8, 17]
>> a.first
=> 42
>> a.second
=> 8
>> a.last
=> 17
>> a.last == a[-1] # == を使って比較する
=> true
length
以外にもいろんなメソッドが。
>> a
=> [42, 8, 17]
>> a.empty?
=> false
>> a.include?(42)
=> true
>> a.sort
=> [8, 17, 42]
>> a.reverse
=> [17, 8, 42]
>> a.shuffle
=> [17, 42, 8]
>> a
=> [42, 8, 17]
push
メソッドで要素の追加も可能。
>> a.push(6) # 6を配列に追加する
=> [42, 8, 17, 6]
>> a << 7 # 7を配列に追加する
=> [42, 8, 17, 6, 7]
>> a << "foo" << "bar" # 配列に連続して追加する
=> [42, 8, 17, 6, 7, "foo", "bar"]
split
の逆のことをjoin
で出来る。
>> a
=> [42, 8, 17, 6, 7, "foo", "bar"]
>> a.join # 単純に連結する
=> "4281767foobar"
>> a.join(', ') # カンマ+スペースを使って連結する
=> "42, 8, 17, 6, 7, foo, bar"
範囲(range)をto_a
メソッドで配列に
>> (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
文字列の取り出しにも使える。
>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a[0..2]
=> ["foo", "bar", "baz"]
a[-1]は必然的に末尾指定できる。
>> a = (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> a[2..(a.length-1)] # 明示的に配列の長さを使って選択
=> [2, 3, 4, 5, 6, 7, 8, 9]
>> a[2..-1] # 添字に-1を使って選択
=> [2, 3, 4, 5, 6, 7, 8, 9]
文字列に対してもメソッドを使える。
>> ('a'..'e').to_a
=> ["a", "b", "c", "d", "e"]
###4.3.2 ブロック
配列と範囲はいずれも、ブロックを伴うさまざまなメソッドに対して応答することができる。ブロックはRubyの強力な機能。
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
>> (1..5).each do |i|
?> puts 2 * i
>> end
2
4
6
8
10
=> 1..5
同じ結果に。{ |i| puts 2 * i }
がブロックと呼ばれる部分。JavaとかC触った時も似たようなことやりましたね。複数行の記述も可能。
map
メソッドを使った事例も。
>> (1..5).map { |i| i**2 } # 「**」記法は冪乗 (べき乗)
=> [1, 4, 9, 16, 25]
>> %w[a b c] # %w で文字列の配列を作成
=> ["a", "b", "c"]
>> %w[a b c].map { |char| char.upcase }
=> ["A", "B", "C"]
>> %w[A B C].map { |char| char.downcase }
=> ["a", "b", "c"]
このメソッドは渡されたブロックを配列や範囲オブジェクトの各要素に適用し、その結果を返す。
メソッドにシンボルを使うパターンも。
>> %w[A B C].map(&:downcase)
=> ["a", "b", "c"]
###4.3.3 ハッシュとシンボル
ハッシュは本質的には配列と同じですが、インデックスとして整数値以外のものも使える点が配列と異なる。
>> user = {} # {}は空のハッシュ
=> {}
>> user["first_name"] = "Michael" # キーが "first_name" で値が "Michael"
=> "Michael"
>> user["last_name"] = "Hartl" # キーが "last_name" で値が "Hartl"
=> "Hartl"
>> user["first_name"] # 要素へのアクセスは配列の場合と似ている
=> "Michael"
>> user # ハッシュのリテラル表記
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
ハッシュは、キーと値のペアを波カッコで囲んで表記する。キーと値のペアを持たない波カッコの組 ({}) は空のハッシュです。ここで重要なのは、ハッシュの波カッコは、ブロックの波カッコとはまったく別物であるという点。
1つの重要な違いとして、ハッシュでは要素の「並び順」が保証されないという点がある。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" }
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
=> によってリテラル表現するほうが簡単。
前コロンは=>が必要。
>> h1 = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
後コロンは=>が不要。
>> h2 = { name: "Michael Hartl", email: "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
Railsではハッシュのハッシュが多く使われている。
>> params = {} # 'params' というハッシュを定義する ('parameters' の略)。
=> {}
>> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" }
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
>> params[:user][:email]
=> "mhartl@example.com"
配列や範囲オブジェクトと同様、ハッシュもeachメソッドに応答する。
>> flash = { success: "It worked!", danger: "It failed." }
=> {:success=>"It worked!", :danger=>"It failed."}
>> flash.each do |key, value|
?> puts "Key #{key.inspect} has value #{value.inspect}"
>> end
Key :success has value "It worked!"
Key :danger has value "It failed."
inspectメソッドだとこんな感じに。
>> puts (1..5).to_a # 配列を文字列として出力
1
2
3
4
5
>> puts (1..5).to_a.inspect # 配列のリテラルを出力
[1, 2, 3, 4, 5]
>> puts :name, :name.inspect
name
:name
>> puts "It worked!", "It worked!".inspect
It worked!
"It worked!"
オブジェクトを表示するためにinspectを使うことは非常によくあるので、 pメソッドというショートカットがある。
>> p :name # 'puts :name.inspect' と同じ
:name_badge:
###4.3.4 CSS、再び
app/views/layouts/application.html.erb
の中身についていろいろ解説。
実は関数使うときに丸カッコがなくてもよい。
ハッシュは関数の引数の末尾なら波カッコがなくてもよい。
rubyは1行を80字以内に収めてコードを読みやすくしている。
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
上のコードではstylesheet_link_tag
メソッドを2つの引数で呼んでいる。最初の引数である文字列は、スタイルシートへのパスを示している。
次の引数であるハッシュには2つの要素があり、最初の要素はメディアタイプを示し、次の要素はRails 4.0で追加されたturbolinksという機能をオンにしている。この結果、<%= %> で囲まれているコードを実行した結果がERbのテンプレートに挿入されるようになる。
##4.4 Rubyにおけるクラス
Rubyは、多くのオブジェクト指向言語と同様、メソッドをまとめるのにクラスを使っている。
これらのクラスからインスタンスが生成されることでオブジェクトが作成される。
###4.4.1 コンストラクタ
>> s = "foobar" # ダブルクォートは実は文字列のコンストラクタ
=> "foobar"
>> s.class
=> String
文字列がclass
メソッドに応答しており、その文字列が所属するクラスを単に返している。
配列でも、文字列と同様にインスタンスを生成できる。
>> a = Array.new([1, 3, 2])
=> [1, 3, 2]
ハッシュの場合は若干異なる。
>> h = Hash.new
=> {}
>> h[:foo] # 存在しないキー (:foo) の値にアクセスしてみる
=> nil
>> h = Hash.new(0) # 存在しないキーのデフォルト値をnilから0にする
=> {}
>> h[:foo]
=> 0
メソッドがクラス自身(この場合はnew)に対して呼び出されるとき、このメソッドをクラスメソッドと呼ぶ。
クラスのnewメソッドを呼び出した結果は、そのクラスのオブジェクトであり、これはクラスのインスタンスとも呼ばれます。length
のように、インスタンスに対して呼び出すメソッドはインスタンスメソッドと呼ばれます。
###4.4.2 クラス継承
スーパークラスについての記述。割愛
###4.4.3 組み込みクラスの変更
割愛。
###4.4.4 コントローラクラス
割愛。
##感想
今回の章はだいぶ内容理解にも頭を使ったので結構疲れました...
インスタンスとかクラスとかの内容は、他の言語でも似たようなことやったので、良い復習になりました。