#近況報告
エンジニア転職成功しました。YouTubeもはじめました。
著者略歴
YUUKI
ポートフォリオサイト:Pooks
現在:RailsTutorial2周目
#第4章 難易度 ★★★ 8時間
挫折しないRailsチュートリアルの進め方を先にお読みください↓↓
この章ではRubyの基礎について解説する。
##組み込みヘルパー
まずはブランチを切る。
$ git checkout -b rails-flavored-ruby
とりあえずapplication.html.erb
ファイルを開く。
以下の行に注目
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
ここではRubyの概念である
- Railsの組み込み関数
- カッコを使わないメソッド呼び出し
- シンボル
- ハッシュ
この4つが使われているので、これから説明していく。
###カスタムヘルパー
新しく作ったメソッドは「カスタムヘルパー」と呼ぶ。
作成の仕方の解説する前に、まずは各ビューのタイトルで使われている組み込み関数に注目。
<% provide(:title, "Home") %>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
yieldメソッドにシンボルでタイトルを付け、provideメソッドでHomeという文字列を呼び出している。
すると、各ページでそれぞれ指定したタイトル文字が表示される。
しかし、このタイトルを与えていなければタイトルが空欄になってしまう。
もし与えられていない場合、| となり、ページタイトルが正しく表示されないので、この問題を解決する為にfull_tittleというヘルパー(新しく作ったfull_titleというメソッド)を使う。
ここでif文を用いてこう記述する。
# ページごとの完全なタイトルを返す。
def full_title(page_title = '')
base_title = 'Ruby on Rails Tutorial Sample App'
if page_title.empty? #page_titleは空でしょうか?
base_title
else
page_title + " | " + base_title
end
end
※if文の処理の中でコメントアウトするとエラーになるので注意。
こうすると、page_titleが空だった場合にbase-title変数を出力。
空じゃなかった場合に"|" を付け加えた文字を出力する。
これでapplication.html.erb
のタイトルタグがスッキリ♪
<title><%= full_title(yield(:title)) %></title>
コードを変えたのでテストも追加。
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App"
end
test "should get help" do
get static_pages_help_url
assert_response :success
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
end
test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
end
test "should get contact" do
get static_pages_contact_url
assert_response :success
assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
end
テストを確認するとエラー
4 tests, 8 assertions, 1 failures, 0 errors, 0 skips
HomeページにHome文字列が含まれているので当たり前ですね。
<% provide(:title, "Home") %>
これを消して再テスト。
4 tests, 8 assertions, 0 failures, 0 errors, 0 skips
OK
ここまでで、モジュール、メソッド定義、文字列の結合、戻り値というRubyの技術を使った。(らしい)
これから覚えていこう。
##文字列とメソッド
Railsにはirbの派生技Railsコンソールがあるが、クラウドIDE利用の場合はirbを使いやすくする為、とある設定をしておく。
nano ~/.irbc
でっかい画面が出てくるが、Tutorialの指示通りに設定して.irbrcファイルに設定を保存。
コンソールを起動。
$ rails c
FATAL: Listen error: unable to monitor directories for changes.
Visit https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers for info on how to fix this.
ファイルの監視がどーたらこーたらのエラーが出たので、指示通り以下のコマンドを実行。
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
再び起動。
$ rails c
Running via Spring preloader in process 13064
Loading development environment (Rails 5.1.6)
>>
できた。
なんかテキトーに打ってみよう。
>> rails = "Tutorialは難しい"
=> "Tutorialは難しい"
>> if rails == "Tutorialは簡単"
>> puts "凄いな"
>> else puts "難しいよね"
>> end
難しいよ
=> nil
おもろ。
###文字列
文字列を入力。
>> "" #空の文字列
=> ""
>> "foo" #空ではない文字列
=> "foo"
これを「文字列リテラル」と呼ぶ。
文字列を結合してみる。
>> "foo" + "bar"
=> "foobar"
結合できた。
文字列を組み立てる他の方法に式展開があるのでやってみる。
>> first_name = "Michael"
=> "Michael"
>> "#{first_name} Hartl"
=> "Michael Hartl"
>>
""の中に#{}を入れることで、変数を文字列の中に埋め込むことができる。
これを「式展開」と言う。
>> last_name = "Hartl"
=> "Hartl"
>> first_name + " " + last_name
=> "Michael Hartl"
>> "#{first_name} #{last_name}
"
=> "Michael Hartl\n"
>>
苗字と名前を変数に入れて出力したりできる。
####出力
文字列を出力する時はputsメソッドを使う。
>> puts "foo"
foo
=> nil
putsメソッドの戻り値にはnilが返ってくる(nil=何も無い)
putsを使って出力すると、改行文字である/nが自動的に出力の末尾に追加される。
putsと同じようなメソッドにprintがあるが、これの場合は改行文字は追加されない。
>> print "foo"
foo=> nil
なるほど。
意図的に改行する場合、\n
を文字列の末尾に追加する。
>> print "foo\n"
foo
=> nil
なお、Macの場合バックスラッシュはoption + ¥ コマンドで出る。
文字列はシングルクォートでも出力できる。
>> 'foo'
=> "foo"
ただし、シングルクォート文字列の中では式展開はできない。
>> '#{foo} bar'
=> "\#{foo} bar"
このように、変数がfooがそのまま表示される。
ではダブルクォートで#のような特殊文字を使うには??
\(バックスラッシュ)でエスケープする。
>> foo = "oraora"
=> "oraora"
>> "#{foo}"
=> "oraora"
>> "\#{foo}"
=> "\#{foo}"
シングルクォートの使い道として、入力した文字をエスケープせずに、そのまま保持するときに使う。
>> "#{foo}"
=> "oraora"
>> '#{foo}'
=> "\#{foo}"
なるほど。つまり、いちいち\でエスケープせずに済むってことね。
>> '\n'
=> "\\n"
なお、Rubyで\
そのものをエスケープする場合は、もう一つ\
が必要。
>> 'Newlines (\n) and tabs (\t) both use the backslash character \.'
=> "Newlines (\\n) and tabs (\\t) both use the backslash character \\."
んで、演習の通り東京都 新宿区
の間のスペースをtabキーに置き換えてみる。
>> city = "東京都"
=> "東京都"
>> ku = "新宿区"
=> "新宿区"
>> puts city + "\t" + ku
東京都 新宿区
=> nil
>>
もしくは
>> puts "#{city}\t#{ku}"
東京都 新宿区
=> nil
後者の方が楽やな。
###オブジェクトとメッセージ受け渡し
オブジェクトはどんな場合でもメッセージに応答する。
例えば
>> "foobar".length
=> 6
footer
という文字列にlength
というメッセージを送っている。
これは文字数を返すメソッドである。
他にも
>> "foobat".empty?
=> false
>> "".empty?
=> true
empty?
メソッドは対象のオブジェクトが空かどうか聞いている。
1回目では空でないのでfalse,2回目は空なのでtrue
empty?
には?が付いており、このメソッドに対してtrueまたはfalseで返すことを
「論理値を返す」と言う。
メソッドに疑問符が付いた場合は、論理値を返す。
if と else で論理値を返すと以下の通り。
>> s = "foobar"
=> "foobar"
>> if s.empty?
>> "The string is empty"
>> else
?> "The string is nonempty"
>> end
=> "The string is nonempty"
条件を複数指定する時はelsif
を使う。(elseifではないので注意)
>> if s.nil?
>> "The yariable is nil"
>> elsif s.empty?
>> "The string is empty"
>> elsif s.include?("foo")
>> "The string includes 'foo'"
>> end
=> "The string includes 'foo'"
変数sの引数に文字列foo
が含まれていたので、The string includes foo
を返す。
>> x = "foo"
=> "foo"
>> y = ""
=> ""
>> puts "Both strings are empty "
Both strings are empty
=> nil
>> 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
!x.empty?
は変数xが空じゃない(not)場合x is not empty
を返す。
Rubyではあらゆるものがオブジェクトで、nilもオブジェクトに入る。
>> nil.to_s
=> ""
>> nil.empty?
NoMethodError: undefined method `empty?' for nil:NilClass
from (irb):50
>> nil.to_s.empty?
=> true
nil自身は存在自体が空なのでempty?だとエラーになるが、メソッドチェーンでto_s(文字情報)を持たせることにより、empty?メソッドが使えてtrue(空ですよ)と返ってくる。
また、Rubyでは後続ifと言って、 処理を書いた後に条件式を書くという手法がある。
>> string = "foobar"
=> "foobar"
>> puts "The string '#{string}' is nonempty." unless string.empty?
The string 'foobar' is nonempty.
=> nil
if文が1行で書けるので簡潔で美しいコードになる。らしい。
####バンバン(!!)について
パコるのパンパンではなくバンバン。
!!は演算子で、指定したオブジェクトを二回否定することで、どんなオブジェクトも強制的に論理値に変換してしまう。
>> !!nil
=> false
上記の!!nil
では、nilを二回否定している。nilは空なので、空を二回否定すると
nil→空じゃない→true→やっぱり空→false
となる。
nil以外だと、どんな値でもtrueになる。
>> !!0
=> true
ここで、色々書いてみる。
>> racecar.length
NameError: undefined local variable or method `racecar' for main:Object
Did you mean? trace_var
from (irb):52
>> "racecar".length
=> 7
>> "racecar".reverse
=> "racecar"
>> s = "racecar"
=> "racecar"
>> s == s.reverse
=> true
>> puts "It's a palindrome!" if s == s.reverse
It's a palindrome!
=> nil
reverse
メソッドはオブジェクトを逆にするので、sに代入されたrececar
を逆にしている。
###メソッドの定義
ターミナルでメソッドを定義して、引数に``を指定する。
>> 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.
=> nil
>> puts string_message("")
It's an empty string!
=> nil
>> puts string_message
It's an empty string!
=> nil
こうすると、変数が空だったらtrueの処理が返されて、空でなければfalseの処理が返される。
実際に定義したメソッドを使ってputsで引数に文字を代入すると、trueの処理が返されている。
見てわかる通り、falseを返すには引数を省略しても可
このように
def string_message(str = '')
書くと、str変数に引数を渡すことも渡さないこともできる。
引数を渡さない場合は、指定のデフォルト値が自動で返される。
####暗黙の戻り値
メソッド内で最後に評価された式の値が自動的に返されるという意味。
具体的には
def string_message(str = '')
return "it's an empty string!" if str.empty?
return "The string is nonempty."
end
このような記述の場合、空ならreturn "it〜"
が返される。
一行目のreturnで値が返されたあと、ifでstrが空でない場合は2行目のreturnの値が返される
しかし、「暗黙の戻り値」の理論からいくと2行目の「return」は必要ない。
なぜなら、最後に評価された式の値は自動で返されるから。
>> def string_message(str = '')
>> retrun "It's an empty string!" if str.empty?
>> "The string is nonempty."
>> end
=> :string_message
>> string_message("aa")
=> "The string is nonempty."
returnを抜いても自動で文字列が返されている。
同じように、引数の変数名にどんな名前を使っても、呼び出し側には何の影響も生じない。
>> def string_message(the_function_argument = '')
>> if the_function_argument.empty?
>> "It's an empty string!"
>> else
?> "The string is nonempty."
>> end
>> end
=> :string_message
>> puts string_message("")
It's an empty string!
=> nil
>> puts string_message("aa")
The string is nonempty.
=> nil
ここで、回文に対する簡単なテストをしてみる。
>> def palindrome_tester(s = '')
>> if s == s.reverse
>> puts "It's a palindrome!"
>> else
?> puts "It's not a palindrome."
>> end
>> end
=> :palindrome_tester
>> puts palindrome_tester("racecar")
It's a palindrome!
=> nil
>> puts palindrome_tester("onomatopoeia")
It's not a palindrome.
=> nil
>> palindrome_tester("racecar").nil?
It's a palindrome!
racecar
は回文なのでtrueの処理が返される。
onomatopoeia
は回分ではないのでfalseの処理が返される。
###titleヘルパー、再び
Webサイトのレイアウトで使うヘルパーメソッドでは
メソッド定義、変数割り当て、論理評価、制御フロー、文字列の式展開
これらの要素が使われている。
Rubyのコードを書く場合、モジュールを作成するたびに関連したメソッドを明示的に読み込んで使うのが普通だが、
Railsでは自動的にヘルパーモジュールを読み込んでくれるので、includeを使う必要がない。
これにより、full_title
メソッドは自動的にすべてのビューで利用できるようになっている。
module ApplicationHelper
# ページごとの完全なタイトルを返す #コメント行
def full_title(page_title = '') #メソッド定義とオプション引数
base_title = "Ruby on Rails Tutorial Sample App" #変数への代入
if page_title.empty? #page_titleは空でしょうか? #論理値テスト
base_title #暗黙の戻り値
else
page_title + " | " + base_title #文字列の結合
end
end
end
##データ構造
データ構造とは、データを効率よく処理するための配置方法のこと。
その中で重要な「配列」について説明する。
>> "foo bar baz".split
=> ["foo", "bar", "baz"]
これはfoo``bar``baz
と言う三つの文字列からなる配列である。
spiltメソッドでは、文字を指定して区切ることも可能。
>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]
上記では文字列x
で区切って配列を作っている。
また、配列の要素番号の数え方は他の言語同様、0から始まる0オリジンが採用されている。
>> a = [42, 8, 17]
=> [42, 8, 17]
>> a
=> [42, 8, 17]
>> a[0]
=> 42
>> a[1]
=> 8
>> a[2]
=> 17
aに三つの数字を配列として代入すると、最初の要素のデータが42
で、要素番号(添字)が0となっていることがわかる。
他にも、firstやsecondを使って各要素にアクセすることができる。
>> a
=> [42, 8, 17]
>> a.first
=> 42
>> a.second
=> 8
>> a.last
=> 17
>> a.last == a[-1]
=> true
a.last == a[-1]
では、a[3]とa[-1]が等しいこと意味している。
>> x = a.length
=> 3
>> x == 3
=> true
>> x == 1
=> false
>> x != 1
=> true
>> x >= 1
=> true
>> x < 1
=> false
上記ではaの文字列の長さをxに代入しているので、3が返される。
!=はイコールでない
なので、xは1より大きい為trueが返されている。
>> a
=> [42, 8, 17] #配列aの中身
>> a.empty? #配列aは空か聞いている
=> false
>> a.include?(42) #配列aに42が含まれているか聞いている
=> true
>> a.sort #配列aを昇順ソート(小さい順)に並べ替える
=> [8, 17, 42]
>> a.reverse #配列aを逆に並べ替える
=> [17, 8, 42]
>> a.shuffle #配列aをシャッフルさせる
=> [8, 42, 17]
>> a #配列aの中身は変わっていない
=> [42, 8, 17]
ここで、配列aの中身を変えてみる。
>> a
=> [42, 8, 17]
>> a.sort!
=> [8, 17, 42]
>> a
=> [8, 17, 42]
!
をメソッドの末尾に添えることで、配列の内容を変更できる。
>> a
=> [42, 8, 17]
>> a.sort!
=> [8, 17, 42]
>> a
=> [8, 17, 42]
>> a.push(6)
=> [8, 17, 42, 6]
>> a << 7
=> [8, 17, 42, 6, 7]
>> a << "foo" << "bar"
=> [8, 17, 42, 6, 7, "foo", "bar"]
push
や<<
でデータを後ろに追加させていく。
foo
とbar
を<<
のように、メソッドチェーンで連結させることも可能。
>> a
=> [8, 17, 42, 6, 7, "foo", "bar"]
>> a.join
=> "8174267foobar"
>> a.join(',')
=> "8,17,42,6,7,foo,bar"
joinメソッドでは配列の各要素を文字列に変換し、結合した文字列を返す。
引数に,
を指定すると、区切り文字として結合した文字列を返す。
>> 0..9
=> 0..9
>> 0..9.to_a
NoMethodError: undefined method `to_a' for 9:Integer
Did you mean? to_c
to_f
to_d
to_i
to_r
to_s
from (irb):47
>> (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
to_aメソッドで途中の配列を全て得ることができる。
>> a = %w[foo bar baz quux]
=> ["foo", "bar", "baz", "quux"]
>> a[0..2]
=> ["foo", "bar", "baz"]
%wでそれぞれの配列を文字列に変換できる。
インデックスに-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]
=> [2, 3, 4, 5, 6, 7, 8, 9]
length
の-1、つまり0の一個後ろの9番目までの要素を返し、
a[2..-1]で要素番号9までを返している。
>> ('a'..'e').to_a
=> ["a", "b", "c", "d", "e"]
文字列に対しても範囲オブジェクトが使える。
色々やってみる
>> a = %w["A man,a plan,a canal,Panama"]
=> ["\"A", "man,a", "plan,a", "canal,Panama\""]
%wで文字列をコンマで区切りに、配列にする。
>> def palindroe_tester(s)
>> if s==s.reverse
>> puts "It's a palindrome!"
>> else
?> puts "It's not a palindrome."
>> end
>> end
=> :palindroe_tester
>> palindroe_tester(s)
It's not a palindrome.
=> nil
変数sが回文であればtrue処理を行い、回文でなければfalse処理を行う。
>> 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.split.join.downcase)
It's a palindrome!
=> nil
変数sを分割し、さらに連結させて文字列に、そしてs.downcase
が回文であるかチェック。
(結果はtrue回文)
>> you = ('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"]
>> you
=> ["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"]
>> you[6]
=> "g"
>> you[-7]
=> "t"
変数youにアルファベット文字を代入し、7番目の文字と後ろから7番目の文字を取り出した。
###ブロック
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
each
のあとの{}の部分をブロックと呼ぶ。
具体的には、iと言うローカル変数に1〜5までの数値を一個ずつ渡して、それぞれ実行している。
因みに、ブロック部分をdoとendで囲うことも可能。
>> (1..5).each do |i|
?> puts 2 * i
>> end
2
4
6
8
10
=> 1..5
do〜
でブロックを示し、endで処理を実行している。
この記法はブロックを複数指定する場合に使いやすい。
>> (1..5).each do |number|
?> puts 2 * number
>> puts '--'
>> end
2
--
4
--
6
--
8
--
10
--
=> 1..5
このように--
を追加で行に挿入することができる。
ブロックの部分は変えても大丈夫。
>> 3.times { puts "Betelgeuse!"}
Betelgeuse!
Betelgeuse!
Betelgeuse!
=> 3
>> (1..5).map { |i| i**2 }
=> [1, 4, 9, 16, 25]
>> %w[a b c]
=> ["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"]
mapメソッドを使うことで、各要素をブロックで処理したあと配列にすることもできる。
ここで、単体テストのコードの確認。
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App"
end
ここにdo
が使われていることに注目。
このtestメソッドでは、文字列とブロックを引数にとって、テストが実行される時にブロック内のコードが実行される、というような解釈ができる。
演習をやってみる。
1:範囲オブジェクト0..16を使い、各要素の2乗を出力
>> (0..16).each do |jyo|
?> puts jyo ** 2
>> end
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
=> 0..16
2:yellerと言うメソッドを定義し、文字列の要素で構成された配列を受け取り、各要素を連結後に大文字にして返す。
>> def yeller(s)
>> s.join.upcase
>> end
=> :yeller
>> yeller(['o','l','d'])
=> "OLD"
3:random_subdomailというメソッドを定義し、ランダムな8文字を生成し、文字列として返す
>> def string_shuffle(s)
>> ('a'..'z').to_a.shuffle[0..7].join
>> end
=> :string_shuffle
>> string_shuffle('a'..'z')
=> "aofpcugm"
4:?の部分を、それぞれ適切なメソッドに置き換えてみる。
>> def string_shuffle(s)
>> s.split('').shuffle.join
>> end
=> :string_shuffle
>> string_shuffle("foobar")
=> "baroof"
メソッドに渡された文字をシャッフルしている。
###ハッシュとシンボル
ハッシュは基本的には配列として同じ。
配列と異なるのは、整数値以外のインデックス(要素の番号のこと)が使えことと、要素の並び順が保証されないことにある。
>> user = {} #{}は空のハッシュ
=> {}
>> user["first_name"] = "Michael" #キーが"first_name"、値が"Michael"
=> "Michael"
>> user["last_name"] = "Hartl" #キーが"last_name"、値が"Hartl"
=> "Hartl"
>> user["first_name"] #キー"first_name"にアクセする。
=> "Michael" #データの値の"Michael"が返される。
>> user
=> {"first_name"=>"Michael", "last_name"=>"Hartl"} #リベラル表記
ハッシュのインデックスをキー
と呼ぶ。
=>はハッシュロケット
と呼ぶ。
通常、ハッシュは{"キー値"}=>"データの値"
このように表記される。
####シンボル
シンボルとは、ハッシュのキーを:シンボル
という書き方で表す手法。
>> {:user => "Yuuki",:name => "Tetsuya"} #基本的な書き方
=> {:user=>"Yuuki", :name=>"Tetsuya"}
>> {user: "baka", name: "aho"} #省略した書き方
=> {:user=>"baka", :name=>"aho"}
このように、:
を前にして書くのが基本だが、
後ろにして=>
を無くし、省略することも可能。(こちらが一般的な書き方)
>> "name".split('')
=> ["n", "a", "m", "e"]
>> :name.split('')
NoMethodError: undefined method `split' for :name:Symbol
from (irb):11
>> "foobar".reverse
=> "raboof"
>> :foobar.reverse
NoMethodError: undefined method `reverse' for :foobar:Symbol
from (irb):13
シンボルは Ruby以外ではごく一部の言語でしか採用されない特殊なデータ形式である。
また、全ての文字が使える訳ではなく、例えば-
や2
は使えない。
>> :foo-bar
NameError: undefined local variable or method `bar' for main:Object
from (irb):26
>> :2foo
SyntaxError: (irb):27: syntax error, unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
:2foo
^
では、実際にシンボルで書いてみてデータの値を呼び出してみる。
>> user = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> user[:name]
=> "Michael Hartl"
>> user[:email]
=> "michael@example.com"
>> user[:password]
=> nil
このように、変数userにシンボルでnameとemailを指定すると、配列と同じように呼び出せる。
ただ、未定義のシンボルはnilが返される。これはつまり、ハッシュ値は単純にnilであることがわかる。
>> h1 = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h3 = { name: "Michael Hartl", email: "michael@example.com"}
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> h1 == h3
=> true
このように、省略した書き方やスペースがあってもなくてもデータの値は同じであることがわかる。
因みに、省略した記法を「ハッシュ記法」と呼ぶ。JavaScriptや他の言語で一般的に使用されている記法である。
省略記法の注意点として、単独のシンボルでは意味が成り立たない。
たとえば
>> :name
=> :name
>> name:
?> => "MM"
SyntaxError: (irb):32: syntax error, unexpected ':', expecting end-of-input
name:
引数を伴わないname:
では意味が成り立たない。
>> {name: "aaa"}
=> {:name=>"aaa"}
このように記せば返ってくる。
省略しない記法の使い方として、シンボルを強調させたい場合に使ったりする。
次に、params
変数を使ってシンボルを使ってみる。
>> params = {} #'params' というハッシュを定義する。
=> {}
>> params[:user] = { name: "Michael Hartl", email: "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"michael@example.com"}}
>> params[:user][:name] #'params'というハッシュのuserシンボルとnameシンボルを呼び出す。
=> "Michael Hartl"
>>
このように、Railsではネストされたハッシュも使われることが多い。
さらに、ハッシュとこれまでに習ったeachメソッドや変数展開を組み合わせて使ってみる。
>> flash = { success: "It worked!", danger: "It falied." } #`flash`と言う名前のハッシュを作成。
=> {:success=>"It worked!", :danger=>"It falied."}
>> flash.each do |key, value| #`flash`ハッシュに`key`と`value`と言うブロック変数を作る。
?> puts "key #{key.inspect} has value #{value.inspect}" #ブロック変数keyの値を文字列として返し、さらにブロック変数valueの値を文字列として返す。
>> end
key :success has value "It worked!"
key :danger has value "It falied."
=> {:success=>"It worked!", :danger=>"It falied."}
ハッシュのeachメソッドの場合、キーと値を二つに設定している。
この場合、一つ目のキーと値
と、二つ目のキーと値
、これをそれぞれペアごとに処理を繰り返す点に注意。
inspectはpメソッドというショートカットキーでも書ける。
>> p :name #puts :name.inspectと同じ
:name
=> :name
ここで演習をやってみる。
1:指定されたキーと値をそれぞれ出力
>> flash={one:"uno",two:"dos",three:"tres"}
=> {:one=>"uno", :two=>"dos", :three=>"tres"}
>> flash.each do |key,value|
?> puts "'#{key}'のスペイン語は'#{value}'"
>> end
'one'のスペイン語は'uno'
'two'のスペイン語は'dos'
'three'のスペイン語は'tres'
=> {:one=>"uno", :two=>"dos", :three=>"tres"}
2:3つのハッシュを作成し、キーと値を追加、そしてparamsというハッシュのハッシュを作成。
その後、ハッシュのハッシュの値が正しい値か確認。
>> params = {}
=> {}
>> params[:father] = person1
=> {:first=>"こんにちは", :last=>"にんにくです"}
>> params[:mother] = person2
=> {:first=>"おはよう", :last=>"魚です"}
>> params[:child] = person3
=> {:first=>"こんばんは", :last=>"おやすみ"}
>> params[:father][:first]
=> "こんにちは"
>> params[:father][:first] == person1[:first]
=> true
>> params[:mother][:first] == person2[:first]
=> true
>> params[:child][:first] == person3[:first]
=> true
3:userハッシュに三つのキーに適当な値を付けて、password_digestキーのみ16文字からなるランダム文字列を代入する。
>> user = {name: "YUUKI" , email: "yuukitetsuya@gggdgd" ,password_digest: ('a'..'z').to_a.shuffle[0..15].join} #a~zまでの文字を返しシャッフルメソッドで16文字列を選び繋げる
=> {:name=>"YUUKI", :email=>"yuukitetsuya@gggdgd", :password_digest=>"mhpfzsqivlkwojcd"}
4:mergeメソッドを実行した結果を推測
>> {"a" => 100,"b" => 200 }.merge({"b" => 300 })
=> {"a"=>100, "b"=>300}
末尾のキーと値に結合するようだ。
デフォルト値は変わらない模様。
###CSS
ここでCSSの読み込みについて確認してみる。
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
この文ではstylesheet_link_tag
メソッドを呼び、application
と言う引数でスタイルシートへのパスを示し、次の二つの引数(ハッシュ)で二つのキーと値を呼び出している。
media
はメディアタイプを示し、data-turbolinks-track
はコードが組み込み関数(ERb)のテンプレートに挿入され、実行が反映されるようになる設定を示している。
実際のソースコードを確認してみる。
<link rel="stylesheet" media="all" href="/assets/application.self-f0d704deea029cf000697e2c0181ec173a1b474645466ed843eb5ee7bb215794.css?body=1" data-turbolinks-track="reload">
なるほど。
##Rubyにおけるクラス
Rubyでは""で囲んだ文字列もオブジェクト。
つまり、
文字列のインスタンスを作成=文字列のオブジェクトを作成。
これをリテラルコンストラクタ
と言う
>> s = "foobar" #ダブルクォートで囲んだ文字列は、文字列のコンストラクタである。
=> "foobar"
>> s.class
=> String
変数sのclassはString(データ型:文字列)であることがわかる。
>> s = String.new("foobar") #String(文字列)の名前付きコンストラクタを作成
=> "foobar"
>> s.class
=> String
>> s == "foobar" #sと文字列"foobar"が同じである
=> true
配列の場合。
>> a = Array.new([1,3,2])
=> [1, 3, 2]
同じようにインスタンスが生成される。
ハッシュの場合。
>> h = Hash.new
=> {}
>> h[:foo]
=> nil
>> h = Hash.new(0)
=> {}
>> h[:foo]
=> 0
>> h.length
=> 0
Hash
と言うクラス自身に対して呼び出されるメソッド(newの部分)=クラスメソッド
Hash.new
で呼び出した結果=クラスのオブジェクト、インスタンス
h.length
のようなインスタンスに対して呼び出すメソッド=インスタンスメソッド
###クラス継承
superclassメソッドを使うことでクラス階層を調べることができる。
>> s = String.new("foobar")
=> "foobar"
>> s.class
=> String
>> s.class.superclass #Stringクラスの親クラスを調べる
=> Object
>> s.class.superclass.superclass #Objectクラスの親クラスを調べる
=> BasicObject
>> s.class.superclass.superclass.superclass #BasicObjectクラスの親クラスを調べる
=> nil #なし
Rubyに置ける全てのクラスは、最終的にスーパークラスを持たない**BasicObjectクラスを継承している。
ここで、自分でクラスを作成してみる。
>> class Word
>> def palindrome?(string)
>> string == string.reverse
>> end
>> end
=> :palindrome?
>> w = Word.new
=> #<Word:0x000000051b71a0>
>> w.palindrome?("fober")
=> false
>> w.palindrome?("foober")
=> false
>> w.palindrome?("level")
=> true
この書き方だと不自然らしい。
と言うのも、文字列を引数に取るメソッドを作るためだけにわざわざ新しいクラスを作る必要はないとのこと。
つまり、親クラスを継承したクラスを定義した方が良い
>> class Word < String
>> def palindrome?
>> self == self.reverse
>> end
>> end
=> :palindrome?
>> s = Word.new("level") #新しいWordを作成、`level`で初期化
=> "level"
>> s.palindrome? #Word(level)が回文かどうか
=> true
>> s.length "levelの文字数を調べる。
=> 5
>>
ちなみに、疑問符は真の場合trueを返す。
また、self
は文字列自身を返す
WordはStringクラスを継承している。
Stringクラスは文字列を表すオブジェクトを提供しているため、lengthメソッドが使える。
sの親クラスを遡ってみる。
>> s.class
=> Word
>> s.class.superclass
=> String
>> s.class.superclass.superclass
=> Object
>>
wordクラスの中では、selfはオブジェクト自身を表す。
つまり
self == self.reverse
の部分は、単語が回文であるかどうかを確認できる。
self == reverse
このように省略しても同じく動く。
###組み込みクラスの変更
継承を使わずとも、palindrome?
メソッドをString
クラスに追加できる。
Rubyでは組み込みの基本クラスの拡張が可能。
>> class String
>> def palindrome?
>> self == self.reverse
>> end
>> end
=> :palindrome?
>> "deified".palindrome?
=> true
しかし、組み込みクラスの変更は極めて強力なものなので、正当な理由がない限り使わない方がよいらしい。
>> "".blank?
=> true
>> " ".empty?
=> false
>> " ".blank?
=> true
>> nil.blank?
=> true
nil.blank?
では、String
クラスではなく、基底クラス(オブジェクト自身)を指している。
演習をやってみる。
1:回文調査。
>> def palindrome?
>> "racecar" == "racecar".reverse
>> "onomatopoeia" == "onomatopoeia".reverse?
>> end
=> :palindrome?
>> "racecar".palindrome?
=> true
>> "onomatopoeia".palindrome?
=> false
>> "Malayalam".reverse
=> "malayalaM"
>> "Malayalam".downcase.palindrome?
=> true
これだと長いのか。
クラス定義してちゃんとやってみよう。
>> class String
>> def palindrome?
>> self == self.reverse
>> end
>> end
=> :palindrome?
>> "racecar".palindrome?
=> true
>> "onomatopoeia".palindrome?
=> false
>> "Malayalam".downcase.palindrome?
=> true
2:shuffleメソッドの追加
>> class String
>> def shuffle
>> self.split('').shuffle.join
>> end
>> end
=> :shuffle
>> "racecar".shuffle
=> "arcecra"
3:selfを消してもうまく動くか
>> class String
>> def shuffle
>> split('').shuffle.join
>> end
>> end
=> :shuffle
>> "racecar".shuffle
=> "acrarce"
###コントローラクラス
今回はStaticPagesControllerを新たに生成し、コントローラの継承を調べてみる。
>> controller = StaticPagesController.new
=> #<StaticPagesController:0x00000004e213d8 @_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
図で表すと
出典:図 4.3: StaticPagesコントローラの継承階層
Railsコンソールでは、コントローラの中のアクションも呼び出すことができる。
>> controller.home
=> nil
homeアクションの中身は空なのでnilが返される。
Railsアクションには戻り値がない。しかも、第3章ではStaticPagesController.newを実行せずともControllerが動いていた。これはRubyとRailsが別物の振る舞いをしているためであり、この二つは全く別のもので考えなければならない。
###ユーザークラス
RailsConsoleで散々勉強した内容を実装する。
今回はユーザークラスをしてみる。
class User
attr_accessor :name, :email #インスタンス変数を読み書きするアクセサメソッドを生成。
def initialize(attributes = {}) #Userクラス生成時に自動実行されるメソッドを定義
@name = attributes[:name] #nameキーが存在しない場合、ハッシュはnilを返す
@email = attributes[:email] #emailキーが存在しない場合、ハッシュはnilを返す
end
def formatted_email #インスタンス変数に割り当てられた値をユーザーのメールアドレスとして構成する。
"#{@name} <#{@email}>" #@nameと@emailに割り当てられた値を表示
end
end
実際にRails Consoleで自作したクラスを試してみる。
>> require './example_user' #example_userの読み込み
=> true
>> example = User.new
=> #<User:0x000000053ec7e0 @name=nil, @email=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>"
ここで重要なのはexample.name
は@name
でexample.email
は@email
であること。
さっき書いたコードの内容が反映されている。
ここで、新たにユーザーを作成してみる。
>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com")
=> #<User:0x000000053b9778 @name="Michael Hartl", @email="mhartl@example.com">
>> user.formatted_email
=> "Michael Hartl <mhartl@example.com>"
User.new
の引数に書いた:name
と:email
はinitialize
メソッドにハッシュを渡していることになるので、@name
と@email
に値が渡されている。
user.formatted_email
では、実際に代入した値を表示している。
ちなみに、波括弧省略の記法を使っている。
演習1をやってみる
class User
attr_accessor :first_name,:last_name, :email
def initialize(attributes = {})
@first_name = attributes[:first_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}>" #`self`で`full_name`メソッドを呼び出すのがコツ
end
end
self
を使ってる点に注目。組み込み関数を使うためにselfを使う。
>> require './example_user'
=> true
>> example = User.new
=> #<User:0x0000000546b4c8 @first_name=nil, @last_name=nil, @email=nil>
>> example.first_name
=> nil
>> example.last_name
=> nil
>> example.first_name = "Michael"
=> "Michael"
>> example.last_name = "Hartl"
=> "Hartl"
>> example.email = "mhartl@example.com"
=> "mhartl@example.com"
>> example.formatted_email
=> "Michael Hartl <mhartl@example.com>"
>>
演習2
def alphabetical_name
"#{@last_name}, #{@first_name}"
end
上記の文を追加した。
>> require './example_user'
=> true
>> user = User.new
=> #<User:0x00000004105820 @first_name=nil, @last_name=nil, @email=nil>
>> user.first_name
=> nil
>> user.first_name = "Michael"
=> "Michael"
>> user.last_name = "Hartl"
=> "Hartl"
>> user.email = "mhartl@example.com"
=> "mhartl@example.com"
>> user.formatted_email
=> "Michael Hartl <mhartl@example.com>"
>> user.alphabetical_name
=> "Hartl, Michael"
できてるっぽい?
演習3
>> require './example_user'
=> true
>> user = User.new
=> #<User:0x00000003ca3278 @first_name=nil, @last_name=nil, @email=nil>
>> user.first_name = "Michael"
=> "Michael"
>> user.last_name = "Hartl"
=> "Hartl"
>> user.email = "example@user.com"
=> "example@user.com"
>> user.full_name.split == user.alphabetical_name.split(',').reverse
=> true
よし、true。
##Git
やっと終わった。。
example_user.rbを削除して、コミット後にmasterブランチにマージ。
rm example_user.rb
$ git commit -am "Add a full_title helper"
[rails-flavored-ruby 3a37e004] Add a full_title helper
7 files changed, 21 insertions(+), 9 deletions(-)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
ec2-user:~/environment/sample_app (master)
$ git merge rails-flavored-ruby
あ、一応テストもしておこう。
$ rails t
4 tests, 8 assertions, 0 failures, 0 errors, 0 skips
まぁguardで自動テストできるんだけど。
最後にpush,デプロイ
$ git push
$ git push heroku
やっっとおわったー!!!
なげえええよwww
とりあえずRubyの基本構文とクラスの仕組み、メソッドの読み出しのルールは今回の章で覚えられたかな。
まだ4章とか死にそう。
#単語集
- irb
インタラクティブRubyのこと。
入力したRubyの文を実行して結果を出力するプログラム。
立ち上げ方はターミナルでirb
return。
nil?
で空かどうか聞いているので、nilなのでtrueが表示される。
$ irb
2.4.1 :001 >
あとは実験的にRubyのコードを書けばOK。
- バックスラッシュ
option + ¥コマンドで\
- エスケープ
特殊文字の無効化のこと。例えば、\を無効化すること。
- メソッド
オブジェクトに渡されるメッセージのこと。
実体は「そのオブジェクト内で定義されたメソッド」
- include?("test")
オブジェクトの引数に文字列(この場合はtest)が含まれていればtrue,含まれていなければfalseを返す。
- to_s
配列に数値を文字列として格納する。
例
s = 12.to_s
変数sに12を文字列として格納する。
- メソッドチェーン
メソッドを連結させること。
- unless
条件式が偽の時に使うメソッド。if分で偽の部分だけ処理したい場合に使う。
- ミックスイン
関連したメソッドをまとめる方法の一つ。includeメソッドを使ってモジュールを読み込める。
- split
文字列を自然に配列に変換するメソッドのこと。
- ゼロオリジン
配列の要素番号がインデックス0から始まること。
1から始まる「1オリジン」もある。
0オリジンでは0〜9で10個、1オリジンでは1~10で10個と違いがある。
- push
pushとは、スタックというデータを一時的に格納しておくための配列「バッファ」の一つである
「スタック」にデータを格納すること。スタックはLIFO(Last In Fisrt Out)
と言う形式でデータを取り出す。
- to_a
範囲オブジェクトのこと。指定された範囲のオブジェクトを返す。
- %w
配列を作るメソッド。文字列の配列に変換する。
- downcase
指定したオブジェクトの大文字を小文字に変えるメソッド。
- each
オブジェクトに含まれている要素を順に取り出すメソッド。配列や、範囲オブジェクトで使われる。
do~endで囲めば要素がなくなるまで繰り返し処理される。
ブロック変数の指定は||で囲む。
例
(1..5).each { |i| puts 2* i } #1〜5までの数値をiに代入し、それぞれ2を掛けて処理する。
2
4
6
8
10
=> 1..5
- times
指定した回数を繰り返すメソッド。
例
3.times do
puts "tes"
end
tes
tes
tes #tesが三回繰り返される
timesメソッドではブロックに変数を使う必要がない
- map
渡された要素の数だけ繰り返しブロックを処理し、配列にして返す
- ネスト
子要素のこと。たとえば
.ccc {
.bbb {
}
}
の.bbb
は.ccc
にネストされたセレクタである。
- inspect
要求されたオブジェクトを表現する文字列を返す。
- コンストラクタ
インスタンスを作成したタイミングで実行されるメソッド。
- blank?
nilまたは空のオブジェクトをチェックできる。
nilまたは空の時にtrueを返す。RubyのメソッドではなくRailsで拡張されたメソッドのため、Rubyのみでは使えない。
- 相対パス
カレントディレクトリ(現在の場所)から見たパス。pwd
コマンドで確認できる
- 絶対パス
全体から見たパス。