Ruby on Rails tutorialを通してのメモ (第4章)
前回まで
- application.html.erbにRubyのコードを挿入し、ページのタイトルが実際にアクセスしたページのタイトルになるように少し動的なページを作成することができました。
- 今回から4章に入ります。Rubyのコードについて学んで行きましょう。
4章
@ 4.1 動機
リスト4.1: サンプルアプリケーションのレイアウト
app/views/layouts/application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- Railsのviewでは膨大な数の組み込み関数が使え、新しい関数を作成することができます。
<%= yield(:title) %> | Ruby on Rails Tutorial Sample App
- こちらではページタイトルの定義に依存しています。
<% provide(:title, "Home") %> <h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p>
- このようにviewでprovideが使われています。
- タイトルが与えていなかった場合に、タイトルが空欄になります。
- 全てのページで異なるタイトルに変更できるようにオプションを与える必要があります。
- このviewからprovideを削除すると
| Ruby on Rails Tutorial Sample App
- 余分な" | "が表示されてしまいます。
- ページタイトルが正しく表示されない場合に、full_titleというヘルパーを作成します。
- このヘルパーはページタイトルが定義されていない場合は基本タイトル「Ruby on Rails Tutorial Sample App」を返し、定義されている場合は基本タイトルに" | "とページタイトルを追加して返すようにします。
リスト4.2: full_titleヘルパーを定義する
app/helpers/application_helper.rb
module ApplicationHelper # ページごとの完全なタイトルを返します。 def full_title(page_title = '') base_title = "Ruby on Rails Tutorial Sample App" if page_title.empty? base_title else page_title + " | " + base_title end end end
- このヘルパーを作成すると、
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
- このapplication.html.erbのレイアウトが、
<title><%= full_title(yield(:title)) %></title>
- このように端的に書くことができます。
リスト4.3: full_titleヘルパーを使ったWebサイトのレイアウト
app/views/layouts/application.html.erb
<!DOCTYPE html> <html> <head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>
- このヘルパーを定義することで、Homeページにこれまで表示されていた余分なHomeという単語を表示せず、基本タイトルのみを正しく表示することができます。
- これを行うために以前のテストコードを"Home"という文字が表示されないことを確認するように更新します。
リスト4.4: Homeページのタイトル確認用にテストを更新する
test/controllers/static_pages_controller_test.rb
require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" end
- ここでテストスイートを実行し、テストが失敗することを確認します。
リスト4.5: RED
$ rails test 3 tests, 6 assertions, 1 failures, 0 errors, 0 skips
- テストが失敗したことが確認できたでしょうか
リスト4.6: ページタイトルをカスタマイズせずに表示するHomeページ
app/views/static_pages/home.html.erb
<h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p>
- 最初の行を削除した結果、テストはパスするはずです。
@ 4.2 文字列とメソッド
@ 4.2.1 コメント
@ 4.2.2 文字列
省略します。 (書いてある通りだと思うので...)
- オブジェクトは、 メッセージに応答する。
- オブジェクトに渡されるメッセージは一般的にメソッドと呼ばれる。
- メソッドの実体は、そのオブジェクト内で定義されたメソッドです。
- lengthメソッドは文字列の文字数を返す。"footbar"は6文字なので返り値は'6'になります。
>> "foobar".empty? => false >> "".empty? => true
- empty?メソッドは文字列が空なら(長さがゼロ)ならtrue,文字列が存在するときはfalseを返すメソッドです。
- Rubyではempty?のような疑問符があるメソッド(?)ようにtrue,またはfalseという論理値(boolean)を返すことを、末尾の疑問符で示す慣習があります。論理値(boolean)は、特に処理の流れを変更する時に有用です。
>> s = "foobar" >> if s.empty? >> "The string is empty" >> else >> "The string is nonempty" >> end => "The string is nonempty"
- こちらでは変数sに文字列"foobar"を代入して、if文で empty?メソッドにより文字列の有無で論理値を返すプログラムが書かれています。
>> if s.nil? >> "The variable is nil" >> elsif s.empty? >> "The string is empty" >> elsif s.include?("foo") >> "The string includes 'foo'" >> end => "The string includes 'foo'"
- 条件文を二つ以上含めたい場合は、elsif(else + if)を使います。
- 条件が一つの時(一つ前のプログラム)はelseによる条件は一つしか使っていませんでしたね?
>> x = "foo" => "foo" >> y = "" => "" >> puts "Both strings are empty" if x.empty? && y.empty? => nil >> puts "One of the strings is empty" if x.empty? || y.empty? "One of the strings is empty" => nil >> puts "x is not empty" if !x.empty? "x is not empty" => nil
- 論理値はそれぞれ&&(and)や| |(or),!(not)で表すこともできます。
- nilがメソッドに対応する例は
>> nil.to_s => ""
- nilに対してメソッドを複数繋げてチェーン(chain)として渡せることを確認します。
- ↑の記事は有用だと思いました。😂
puts "x is not empty" if !x.empty?
- このコードはifが中盤に書かれています。これは、ifの後の条件式が真(true)の時のみ実行される式(後置if)になっています。
- 簡潔にコードを書くことができます。
- もし、falseを返したい時は、unlessをキーワードとして使えます。
>> string = "foobar" >> puts "The string '#{string}' is nonempty." unless string.empty? The string 'foobar' is nonempty. => nil
- Rubyのオブジェクトでは、オブジェクトの論理値がfalseになるのは、false自身とnilの二つです。
- !!を使用するとそのオブジェクトを2回否定するのでどのオブジェクトも論理値(true,false)に変換できます。
>> !!nil => false
>> !!0 => true
@ 4.2.4 メソッドの定義
- Railsコンソールでもhomeアクションや4.2で作成したヘルパーと同じ方法でメソッドを定義することができる。
- 引数を1つ取り、引数が空かどうかに基づいたメッセージを返すstring_messageというメソッドを定義してみる。
>> def string_message(str = '') >> if str.empty? >> "It's an empty string!" >> else >> "The string is nonempty." >> end >> end => :string_message >> puts string_message("foobar") The string is nonempty. >> puts string_message("") It's an empty string! >> puts string_message It's an empty string!
- 最後の「puts string_message」のようにメソッドの引数を省略することも可能です。 (引数にデフォルト値を含めているので)
def string_message(str = '')
- str変数に引数を渡すことも渡さないこともできる。渡さない場合は指定のデフォルト値が自動的に使われる。
- Rubyメソッドには「暗黙の戻り値がある」
- メソッド内で最後に評価された式の値が自動的に返される。
- 引数のstrがそらかどうかに応じて2つのメッセージ文字列のうちいずれかを返す。Rubyでは戻り値を明示的に指定することもできる。
>> def string_message(str = '') >> return "It's an empty string!" if str.empty? >> return "The string is nonempty." >> end
- このメソッドは先ほどのメソッドと同じ結果を返す。
- 2番目のreturnはなくとも良い。
- メソッド内の最後に置かれた式("The string is nonempty.")は、returnキーワードがなくても暗黙で値を返す。
- 両方にteturnを使う方が見た目の対称性が保たれる。
- メソッドで引数の変数名にどんな名前を使用しても、メソッドの呼び出し側には何の影響も生じない。
- 最初の例のstrを別の変数名(the_function_arugumentなど)に変更しても、メソッドの呼び出し方は全く同じ。
@ 4.2.5 titleヘルパー、再び
- full_titleヘルパーのコードを理解するための準備が整った。
- コメントを使用して各行に注釈を追加している。
リスト4.11: 注釈付きのtitle_helper.
app/helpers/application_helper.rb
module ApplicationHelper # ページごとの完全なタイトルを返します。 # コメント行 def full_title(page_title = '') # メソッド定義とオプション引数 base_title = "Ruby on Rails Tutorial Sample App" # 変数への代入 if page_title.empty? # 論理値テスト base_title # 暗黙の戻り値 else page_title + " | " + base_title # 文字列の結合 end end end
- Webサイトのレイアウトで使うコンパクトなヘルパーメソッドでは、以下のような要素が投入される。
- メソッドの定義
- 変数割り当て
- 論理評価
- 制御フロー
- 文字列の式展開
- module ApplicationHelperについて
- モジュールは関連したメソッドをまとめる方法の一つ
- includeメソッドを使ってモジュールを読み込むことができる。(mixed inと呼ばれる)
- Railsでは自動的にヘルパーモジュールを読み込んでくれるため、include行を書く必要がない。
- full_titleメソッドは自動的にすべてのビューで利用できるようなっている。
@ 4.3 他のデータ構造
@ 4.3.1 配列と範囲演算子
- 配列(array)は、特定の順序を持つ要素のリストのこと。
- 配列を理解することはハッシュやRailsのデータモデル(関連付け、後述する。)を理解するための重要な基盤となる。
- splitメソッドを使用すると、文字列を自然に変換した(整数)配列を得ることができる。
>> "foo bar baz".split # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]
- このsplitメソッドを使用することにより、三つの文字列からなる配列が返ってきた。
- デフォルトで空白が区切り文字として使われるが、次のように区切り文字を指定することもできる。
>> "fooxbarxbaz".split('x') => ["foo", "bar", "baz"]
- 配列なので、ゼロオリジンを採用している。 (配列は0から始まるがなぜか?↓結構難しい。配列は0から始まるものだ。と理解した方が一旦はよさそう。)
- 配列の最初の要素のインデックスが0から始まり、2番目は1...と続く。
>> a = [42, 8, 17] => [42, 8, 17] >> a[0] # Rubyでは角カッコで配列にアクセスする => 42 >> a[1] => 8 >> a[2] => 17 >> a[-1] # 配列の添字はマイナスにもなれる! => 17
- 配列の要素にアクセスするには角カッコを使う。Rubyではそれ以外のアクセス方法もある。
>> a # 配列「a」の内容を確認する => [42, 8, 17] >> a.first => 42 >> a.second => 8 >> a.last => 17 >> a.last == a[-1] # == を使って比較する => true
- 最後の行ではa.last(42)とa[-1](aという配列の後ろからマイナス1番目つまり最初の42)を「==」により比較している。因みに等しくないは「!=」という比較演算子で表現できる。
>> x = a.length # 配列も文字列と同様lengthメソッドに応答する => 3 >> x == 3 => true >> x == 1 => false >> x != 1 => true >> x >= 1 => true >> x < 1 => false
- 配列は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]
- 上の様々なメソッド を実行した場合にもaの値は変更されていない。
- 配列の内容を変更したい場合は、そのメソッドに対応する「破壊的」メソッドを使用する。つまり「!」を追加したものを使用する。
>> a => [42, 8, 17] >> a.sort! => [8, 17, 42] >> a => [8, 17, 42]
- 「!」を使用することにより配列の要素の順番が変わっていることが確認できる。
- 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"]
- 最後の例(a << "" << "")のように要素の追加をチェーン(chain)することができている。
- 他の多くの言語の配列とは異なり、Rubyでは異なる型が配列の中で共存できる。(整数と文字列)
- 文字列を整数に変換するとき、splitメソッドを使用した。joinメソッドはこれとは逆で区切りをなくした要素を作る。
>> a => [42, 8, 17, 6, 7, "foo", "bar"] >> a.join # 単純に連結する => "4281767foobar" >> a.join(', ') # カンマ+スペースを使って連結する => "42, 8, 17, 6, 7, foo, bar"
- to_aメソッドを使用してみる。
>> 0..9 => 0..9 >> 0..9.to_a # おっと、9に対してto_aを呼んでしまっていますね NoMethodError: undefined method `to_a' for 9:Fixnum >> (0..9).to_a # 丸カッコを使い、範囲オブジェクトに対してto_aを呼びましょう => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- 括弧が必要 らしい。
- [0...2]のような範囲は配列の要素を取り出すのに便利。
>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換 => ["foo", "bar", "baz", "quux"] >> a[0..2] => ["foo", "bar", "baz"]
- インデックスに-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]
@ 4.3.2 ブロック
- 配列と範囲( [ ] や... ) )はさまざまなメソッドに対して応答することができる。
>> (1..5).each { |i| puts 2 * i } 2 4 6 8 10 => 1..5
- このコードでは、範囲オブジェクトである(1..5)に対してeachメソッドを呼び出している。
- { |i| puts 2 * i }はブロックと呼ばれる。
- |i|は変数名が「 | 」に囲まれている。eachメソッドでは、iという変数を使用してブロックを操作できる。 範囲( ... )に含まれるそれぞれの値をこの変数( i )に代入してブロックを実行する。
- doとendを使用して示すことができる。(私はこちらの方が使用したことが多いです。😉)
>> (1..5).each do |number| ?> puts 2 * number >> puts '--' >> end 2 -- 4 -- 6 -- 8 -- 10 -- => 1..5
- each do の後の変数「 i 」の代わりに「 number 」を使用している。
- mapメソッドを使用したブロックの使用例↓,mapメソッドは渡されたブロックを範囲オブジェクトの要素に対して適用し、その結果を返す。
>> 3.times { puts "Betelgeuse!" } # 3.timesではブロックに変数を使っていない "Betelgeuse!" "Betelgeuse!" "Betelgeuse!" => 3 >> (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"]
- 後半の2つの例では、mapのブロックで内で宣言した(char)に対してメソッドを呼び出している。
- 次のように書き方を省略することができる。( => (&:downcase) ) メソッドにシンボル( : )が使われている。
>> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"] >> %w[A B C].map(&:downcase) => ["a", "b", "c"]
- ブロックの例として単体テストの場合↓
est "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" end
- テストコードにdoが含まれている。テスト本体がブロックでできている。
- 文字列(説明文)とブロックを引数にテストが実行される時ブロック内の文が実行される。
('a'..'z').to_a.shuffle[0..7].join
- ↑のコードについて理解してみる。↓
>> ('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'..'z').to_a.shuffle # シャッフルする => ["c", "g", "l", "k", "h", "z", "s", "i", "n", "d", "y", "u", "t", "j", "q", "b", "r", "o", "f", "e", "w", "v", "m", "a", "x", "p"] >> ('a'..'z').to_a.shuffle[0..7] # 配列の冒頭8つの要素を取り出す => ["f", "w", "i", "a", "h", "p", "c", "x"] >> ('a'..'z').to_a.shuffle[0..7].join # 取り出した要素を結合して1つの文字列にする => "mznpybuj"
- 今更ですが結構分かりやすい説明で助かります。。🤔
@ 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"}
- ハッシュはキーと値をペアとして「 { } 」で囲む。
- キーと値のペアを持たない「 { } 」は空のハッシュ。
- 「 { } 」はブロックの「 { } 」とは別もの。
- ハッシュと配列の大きな違いは、並び順が保証されていないということ。順序を決める場合は配列を使う必要がある。
- ↓のようにハッシュロケットの表現方法がある。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" } => {"last_name"=>"Hartl", "first_name"=>"Michael"}
>> "name".split('') => ["n", "a", "m", "e"] >> :name.split('') NoMethodError: undefined method `split' for :name:Symbol >> "foobar".reverse => "raboof" >> :foobar.reverse NoMethodError: undefined method `reverse' for :foobar:Symbol
- シンボルは、全ての文字が使えるわけでは無い。
>> :foo-bar
NameError: undefined local variable or method `bar' for main:Object
>> :2foo
SyntaxError
- ハッシュのキーとしてシンボルを採用する場合、userのハッシュは、↓のように定義できる。
>> user = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> user[:name] # :name に対応する値にアクセスする => "Michael Hartl" >> user[:password] # 未定義のキーに対応する値にアクセスする => nil
- 最後の例で未定義のハッシュはnilになることがわかる。
- ハッシュではシンボルをキーとして使う。
>> 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"} >> h1 == h2 => true
- キーの名前の後にコロンを置き、その後に値が続くように置き換える。
{ name: "Michael Hartl", email: "michael@example.com" }
- jsなどの他の言語のハッシュ記法に近い。
{ :name => "Michael Hartl" }
- ↑のコードと
{ name: "Michael Hartl" }
- ↑のコードは同じ。
リスト4.13: ハッシュの中のハッシュ
>> 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メソッドに対応する。
- 配列のeachメソッドはブロックの変数は一つだけだが、ハッシュのeachメソッドでは、ブロックの変数はキーと値の二つになっている。( flash.each do |key, value| )
- ハッシュに対してeachメソッドを実行すると、ハッシュの一つの「キー、値」のペアの処理を繰り返す。
- 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メソッド( 'puts :name.inspect' )というショートカットが使える。
>> p :name # 'puts :name.inspect' と同じ :name
@ 4.3.4 CSS、再び
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- ↑のコードでは↓のメソッドを呼んでいる。
stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- 「 ( ) 」がない。
- Rubyは「 ( ) 」を使用しなくても良い。つまり↓の二行は同じ。
# メソッド呼び出しの丸カッコは省略可能。 stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': 'reload') stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- media引数はハッシュだが、「 { } 」が無い。
- ハッシュがメソッド呼び出しの最後の引数である場合は省略できる。 ↓
# 最後の引数がハッシュの場合、波カッコは省略可能。 stylesheet_link_tag 'application', { media: 'all', 'data-turbolinks-track': 'reload' } stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload
- ↓のようなコードでも正常に実行できる。
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
- 途中で改行が含まれているにも関わらず、正常に実行できるのは、Rubyは改行と空行を区別していないため。
- 行を分割したのはコードを読みやすくするため。
stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
- ↑のコードではstylesheet_link_tagメソッドを二つの引数で呼んでいる。
- 最初の引数の文字列( 'application','data-turbolinks-track' )はスタイルシートへのパスを示している。
- 次の引数であるハッシュは要素が二つある。
- 最初の要素がメディアタイプ(media:)
- 次の要素がturbolinksという機能をオンにしている。
- <%= %>で囲まれたコードを実行した結果がERbのテンプレートに挿入される。ブラウザ上でこのページのソースを表示すると、必要なスタイルシートが含まれていることを確認できる。
リスト 4.14: 読み込まれたCSSによって生成されたHTMLソース
<link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />
@ 4.4 Rubyにおけるクラス
- Rubyではあらゆるものがオブジェクトである。
- 実際にオブジェクトをいくつか定義してみる。
- Rubyはメソッドをまとめるのにクラスを使っている。
- これらのクラスからインスタンスが生成されオブジェクトが作成される。
- オブジェクト思考の具体例を示す。
@ 4.4.1 コンストラクタ
>> s = "foobar" # ダブルクォートは実は文字列のコンストラクタ => "foobar" >> s.class => String
- ↑では文字列がclassメソッドに応答している。その文字列が所属するクラスを返している。
- 明示的に名前付きコンストラクタを使うことができる。
- 名前付きコンストラクタはクラスに対してnewメソッドを呼び出している。
>> s = String.new("foobar") # 文字列の名前付きコンストラクタ => "foobar" >> s.class => String >> s == "foobar" => true
- 配列でも文字列と同様にインスタンスを生成できる。
>> a = Array.new([1, 3, 2]) => [1, 3, 2]
- 配列のコンストラクタの「Array.new」は配列の初期値を引数にとる。
- ハッシュのHash.newはハッシュのデフォルト値を引数に取る。(キーが存在しない場合のデフォルトの値)
>> h = Hash.new => {} >> h[:foo] # 存在しないキー (:foo) の値にアクセスしてみる => nil >> h = Hash.new(0) # 存在しないキーのデフォルト値をnilから0にする => {} >> h[:foo] => 0
- メソッドがクラス自身(new)の場合はこのメソッドをクラスメソッドと呼ぶ。
- クラスのnewメソッドを呼び出した結果はそのクラスのオブジェクトであり、クラスのインスタンスとも呼ばれる。
- lengthのようにインスタンス(array.length)に対して呼び出すメソッドはインスタンスメソッドと呼ぶ。
@ 4.4.2 クラス継承
- superclassメソッドを使うとクラス階層がわかり、クラスについて分かりやすくなる。
>> s = String.new("foobar") => "foobar" >> s.class # 変数sのクラスを調べる => String >> s.class.superclass # Stringクラスの親クラスを調べる => Object >> s.class.superclass.superclass # Ruby 1.9からBasicObjectが導入 => BasicObject >> s.class.superclass.superclass.superclass => nil
- 図4.1のようにStringクラスのスーパークラスはobjectクラスで、objectクラスのスーパークラスはBasicobjectだが、このクラスはスーパークラスを持っていない。
- Rubyのクラスは最終的にスーパークラスを持たないBasicobjectクラスを継承している。
- クラス継承の仕組みがあることから、Rubyはあらゆるものがオブジェクトである。
- クラスについての理解を深めるために、自分でクラスを作成してみる。
- Wordクラスを作成する。
- 単語を前後ろどちらから読んでも同じならばtrueを返すpalindrome?(回文)メソッド を作成してみる。
>> class Word >> def palindrome?(string) >> string == string.reverse >> end >> end => :palindrome?
- このクラスとメソッド は ↓のように使うことができる。
>> w = Word.new # Wordオブジェクトを作成する => #<Word:0x22d0b20> >> w.palindrome?("foobar") => false >> w.palindrome?("level") => true
- 文字列「w.palindrome?("文字列")」を引数にとるメソッド「palindrome」を作るために新しいクラスを使っている。(本来ならば ↓ のようにWordクラスはStringクラスを継承する)
リスト4.15:コンソールでWordクラスを定義する
>> class Word < String # WordクラスはStringクラスを継承する >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse # selfは文字列自身を表します >> end >> end => :palindrome?
- ↑のコードは継承のためのRubyのword < String 記法。
- 新しいpalindrome?メソッドだけではなく、Stringクラスが扱える全てのメソッドがWordクラスで使えるようになる。
>> s = Word.new("level") # 新しいWordを作成し、"level" で初期化する => "level" >> s.palindrome? # Wordが回文かどうかを調べるメソッド => true >> s.length # WordはStringで扱える全てのメソッドを継承している => 5
- wordクラスはStringクラウを継承しているためクラス階層を確認できる。
>> s.class => Word >> s.class.superclass => String >> s.class.superclass.superclass => Object
- Rubyではselfキーワードを使ってクラスの中から自分自身が持つ単語にアクセスすることができる。
- Wordクラスの中では、selfはオブジェクト自身を指す。
self == self.reverse
- ↑のコードを使い、単語が回文であるかを確認できる。
- Stringクラス内部ではメソッドや属性を呼び出すときのself.も省略可能。
self == reverse
@ 4.4.3 組み込みクラスの変更
- 仮に継承を使わずpalindrome?メソッドをStringクラス自身に追加して(Stringクラスを拡張して)使う方法があればWordクラスを作らなくてもよい。
>> "level".palindrome? NoMethodError: undefined method `palindrome?' for "level":String
- Rubyでは組み込みの基本クラスの拡張が可能。
- Rubyのクラスはオープンで変更可能(誰でも自由に変更可能)
- つまり、クラス設計者でない開発者でもこれらのクラスにメソッドを自由に追加することができる。
>> class String >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse >> end >> end => :String >> "deified".palindrome? => true
>> "".blank? => true >> " ".empty? => false >> " ".blank? => true >> nil.blank? => true
@ 4.4.4 コントローラクラス
- StaticPagesコントローラで継承やクラスについて触れていた。
class StaticPagesController < ApplicationController def home end def help end def about end end
- StaticPagesControllerはApplicationControllerを継承していて、homeやhelp,aboutメソッドを定義している部分などについて説明できるようになった。。
- Railsコンソールは、セッションごとにローカルのRails環境を読み込む。
- コンソール内で明示的にコントローラを作成したり、そのクラス階層を調べたりすることができる。
>> controller = StaticPagesController.new => #<StaticPagesController:0x22855d0> >> 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
- Railsコンソールでは、その中からコントローラのアクション(メソッド)を呼ぶこともできる。
>> controller.home => nil
- Railsのアクションには戻り値がない。
- homeアクションはWebページを表示するためのもの。値を返すものではない。
- 第3章で一度もStaticPagesControlelr.newを実行していなかった。
- RailsはRubyで書かれているがRubyとは別物。
- Railsクラスは普通のRubyオブジェクトと同様に振舞うが、多くのクラスにはRails独自の仕様(魔法?🙄)担っているため分けて学習する必要がある。
@ 4.4.5 ユーザークラス
- 最後に、Userクラスを最初から作成してみる。
- アプリケーションのルートディレクトににexample_user.rbファイルを作成し、そこにリスト4.17のように書く。
リスト4.17: example_userで使うコード
example_user.rb
class User attr_accessor :name, :email def initialize(attributes = {}) @name = attributes[:name] @email = attributes[:email] end def formatted_email "#{@name} <#{@email}>" end end
- 順番に中身を見ていく。
attr_accessor :name, :email
- ユーザ名とメールアドレス(属性attribute)に対応するaccessorをそれぞれ作成する。
- accessorを作成すると↓二つが定義される。
- データを取り出すメソッド(getter)
- データを代入するメソッド(setter)
- この行を実行し、インスタンス変数@nameと@email にアクセスするためのメソッドが用意される。
- Railsでは、インスタンス変数をコントローラ内で宣言するだけでビューで使えるようになる。
- 一般的にはそのクラス内であればどこからでもアクセスできる変数として使われる。
- インスタンス変数は常に@記号で始まり、未定義ならnilになる。
- 次の行のinitializeは、Rubyのメソッド
- User.newを実行すると自動的に呼び出される。
- この場合はattributesという引数を一つ取る。
def initialize(attributes = {}) @name = attributes[:name] @email = attributes[:email] end
- ↑のコードではattributes変数は空のハッシュデフォルトの値として持つ。
- 名前やメールアドレスのないユーザをinitializeメソッドにより最初に作ることができる。
- 最後にformatted_emailメソッドは、文字列の式展開を利用し@nameと@emailに割り当てられた値をユーザーのメールアドレスとして構成する。
def formatted_email "#{@name} <#{@email}>" end
>> require './example_user' # example_userのコードを読み込む方法 => true >> example = User.new => #<User:0x224ceec @email=nil, @name=nil> >> example.name # attributes[:name]は存在しないのでnil => nil >> example.name = "Example User" # 名前を代入する => "Example User" >> example.email = "user@example.com" # メールアドレスを代入する => "user@example.com" >> example.formatted_email => "Example User <user@example.com>"
- requireのパスの'./example_user'の'.'は現在作業しているディレクトリ(カレントディレクトリ) という意味を示す。
- 次のコードで空のexmaple_userを作成する。(example = User.new)
- 次に対応する属性にそれぞれ手動で値を代入すると名前とメールアドレスを与えることができる。(attr_accessorを使っているため =>attr_accessor :name, :email )
example.name = "Example User"
- @name変数に"Example User"とemail属性にも値を設定している。値はformatted_emailメソッドで使われる。
- 最後のハッシュ引数の{}を省略すると同様にinitializeメソッドにハッシュを渡すことで属性が定義済みの他のユーザを作成することができる。
> user = User.new(name: "Michael Hartl", email: "mhartl@example.com") => #<User:0x225167c @email="mhartl@example.com", @name="Michael Hartl"> >> user.formatted_email => "Michael Hartl <mhartl@example.com>"
@ 4.5 最後に
- 不要ファイルの削除..
$ rm example_user.rb
- 「deified」という単語は回文である🧐
to be continued...
- かなり長文でかつ文章の統一感がなく、申し訳ないです。数日間に分けて実施しました。
- 結構自分自身も文章の理解に苦しみました。
- この章はRubyの基本構文の話になるので、新しい発見も多く、内容が濃い印象でした。
- 次からやっとコーディングです!!!!🤗
オススメの曲
🔥🔥🔥🔥🔥🔥