Ruby
文字列とメソッド
式展開
>> first_name = "Michael" # 変数の代入
=> "Michael"
>> "#{first_name} Hartl" # 文字列の式展開
=> "Michael Hartl"
文字列の文字数
>> "foobar".length # 文字列に "length" というメッセージを送る
=> 6
empty?メソッド
Rubyでは、メソッドがtrueまたはfalseという論理値 (boolean) を返すことを、末尾の疑問符で示す慣習がある。
>> "foobar".empty?
=> false
>> "".empty?
=> true
論理値
論理値はそれぞれ && (and) や || (or)、! (not) オペレーターで表すこともできる
>> 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
メソッドチェーン
>> nil.empty?
NoMethodError: undefined method `empty?' for nil:NilClass
>> nil.to_s.empty? # メソッドチェーンの例
=> true
後続if
puts "x is not empty" if !x.empty?
unlessキーワードも後続ifと同様に使える。
(unless:条件式が偽の時に実行する)
>> string = "foobar"
>> puts "The string '#{string}' is nonempty." unless string.empty?
The string 'foobar' is nonempty.
=> nil
論理値
Rubyのオブジェクトのうち、オブジェクトそのものの論理値がfalseになるのは、false自身とnilの2つしかない。
演算子「!!」
!!という演算子を使うと、そのオブジェクトを2回否定することになるので、どんなオブジェクトも強制的に論理値に変換できる。
>> !!nil
=> false
>> !!0
=> true
メソッド
引数にデフォルト値を含めるとメソッドの引数を省略することも可能になる。
>> 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!
暗黙の戻り値
メソッド内で最後に評価された式の値が自動的に返される。(戻り値を明示的に指定することもできる)
次のメソッドは上のメソッドと同じ結果を返す。
>> def string_message(str = '')
>> return "It's an empty string!" if str.empty?
>> return "The string is nonempty."
>> end
カスタムヘルパーの例
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
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
.
.
.
</html>
他のデータ構造
splitメソッド
>> "foo bar baz".split # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]
>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]
配列
>> a = [42, 8, 17]
=> [42, 8, 17]
>> a[0] # Rubyでは角カッコで配列にアクセスする
=> 42
>> a[1]
=> 8
>> a[-1] # 配列の添字はマイナスにもなれる!
=> 17
>> a # 配列「a」の内容を確認する
=> [42, 8, 17]
>> a.first
=> 42
>> a.last
=> 17
>> a.last == a[-1] # == を使って比較する
=> true
配列とメソッド
>> 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
=> [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"]
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]
>> a = %w[foo bar baz quux] # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a[0..2]
=> ["foo", "bar", "baz"]
>> 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"]
ブロック
短い1行のブロックには波カッコを使い、長い1行や複数行のブロックにはdo..end記法を使う。
波カッコ
>> (1..5).each { |i| puts 2 * i }
2
4
6
8
10
=> 1..5
上のコードでは、範囲オブジェクトである(1..5)に対してeachメソッドを呼び出している。メソッドに渡されている{ |i| puts 2 * i }が、ブロックと呼ばれている。|i|では変数名が縦棒「|」に囲まれているが、これはブロック変数に対して使うRubyの構文で、ブロックを操作するときに使う変数を指定している。この場合、範囲オブジェクトのeachメソッドは、iという1つのローカル変数を使ってブロックを操作できる。そして、範囲に含まれるそれぞれの値をこの変数に次々に代入してブロックを実行する。
do..end記法
>> (1..5).each do |i|
?> puts 2 * i
>> end
2
4
6
8
10
=> 1..5
>> (1..5).each do |number|
?> puts 2 * number
>> puts '--'
>> end
2
--
4
--
6
--
8
--
10
--
=> 1..5
ブロックの使用例(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つのようなケースでは省略記法が一般的で、次のように書くこともできる (この記法を“symbol-to-proc”と呼ぶ)。
>> %w[A B C].map { |char| char.downcase }
=> ["a", "b", "c"]
>> %w[A B C].map(&:downcase)
=> ["a", "b", "c"]
ブロックの使用例(単体テスト)
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App"
end
このtestメソッドは文字列 (説明文) とブロックを引数にとり、テストが実行されるときにブロック内の文が実行される、ということが理解できる
ランダムな文字列を生成するコード
('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"
ハッシュとシンボル
ハッシュは配列と似ているが、1つの重要な違いとして、ハッシュでは要素の「並び順」が保証されないという点がある。もし要素の順序が重要である場合は、配列を使う必要がある。
ハッシュは、キーと値のペアを波カッコで囲んで表記する。
>> 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"}
リテラル表現
リテラル表現:キーと値をハッシュロケットと呼ばれる => によって定義する。
Rubyにおける慣習として、ハッシュの最初と最後に空白を追加する。
>> user = { "first_name" => "Michael", "last_name" => "Hartl" }
=> {"last_name"=>"Hartl", "first_name"=>"Michael"}
シンボル
Railsでは文字列よりもシンボルを使う。
シンボルは文字列と似ているが、クォートで囲む代わりにコロンが前に置かれている点が異なる。(例えば :name)
>> user = { :name => "Michael Hartl", :email => "michael@example.com" }
=> {:name=>"Michael Hartl", :email=>"michael@example.com"}
>> user[:name] # :name に対応する値にアクセスする
=> "Michael Hartl"
>> user[:password] # 未定義のキーに対応する値にアクセスする
=> nil
2つ目の記法としては、シンボルとハッシュロケットの組み合わせを、次のようにキーの名前の (前ではなく) 後にコロンを置き、その後に値が続くように置き換えたものがある。
>> 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
ハッシュ
ハッシュの値にはほぼ何でも使うことができ、他のハッシュを使うことすらできる。
>> 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"
Railsでは、このようなハッシュのハッシュ (またはネストされたハッシュ) が大量に使われている。
ハッシュとeachメソッド
配列や範囲オブジェクトと同様、ハッシュも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メソッド
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
CSS
<%= 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'
ハッシュがメソッド呼び出しの最後の引数である場合は、波カッコを省略できる。
# 最後の引数がハッシュの場合、波カッコは省略可能。
stylesheet_link_tag 'application', { media: 'all',
'data-turbolinks-track': 'reload' }
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
Rubyは改行と空白を区別しない。行を分割した理由は、1行を80字以内に収めてソースコードを読みやすくするため。
stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload'
stylesheet_link_tagメソッドを2つの引数で呼んでいる。最初の引数である文字列は、スタイルシートへのパスを示している。次の引数であるハッシュには2つの要素があり、最初の要素はメディアタイプを示し、次の要素はRails 4.0で追加されたturbolinksという機能をオンにしている。
ブラウザ上でこのページのソースを表示すると、必要なスタイルシートが含まれていることを確認できる。
<link data-turbolinks-track="true" href="/assets/application.css"
media="all" rel="stylesheet" />
クラス
コンストラクタ
暗黙のリテラルコンストラクタ
>> s = "foobar" # ダブルクォートは実は文字列のコンストラクタ
=> "foobar"
>> s.class
=> String
名前付きコンストラクタ
>> s = String.new("foobar") # 文字列の名前付きコンストラクタ
=> "foobar"
>> s.class
=> String
>> s == "foobar"
=> true
配列のコンストラクタ
>> 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のように、インスタンスに対して呼び出すメソッドはインスタンスメソッドと呼ばれる。
クラス継承
クラス階層
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
クラス継承の例
>> class Word < String # WordクラスはStringクラスを継承する
>> # 文字列が回文であればtrueを返す
>> def palindrome?
>> self == self.reverse # selfは文字列自身を表します
>> end
>> end
=> :palindrome?
Stringクラスを継承することで、新しいpalindrome?メソッドだけではなく、Stringクラスが扱えるすべてのメソッドがWordクラスでも使える。
>> s = Word.new("level") # 新しいWordを作成し、"level" で初期化する
=> "level"
>> s.palindrome? # Wordが回文かどうかを調べるメソッド
=> true
>> s.length # WordはStringで扱える全てのメソッドを継承している
=> 5
>> s.class
=> Word
>> s.class.superclass
=> String
>> s.class.superclass.superclass
=> Object
また、Stringクラスの内部では、メソッドや属性を呼び出すときのself.も省略可能。
self == self.reverse
self == reverse
組み込みクラスの変更
わざわざWordクラスを作らなくても、継承を使わずにpalindrome?メソッドをStringクラス自身に追加する (つまりStringクラスを拡張する)ことで、palindrome?をリテラル文字列に対して直接実行できる。
>> class String
>> # 文字列が回文であればtrueを返す
>> def palindrome?
>> self == self.reverse
>> end
>> end
=> :String
>> "deified".palindrome?
=> true
ただし、真に正当な理由がない限り、組み込みクラスにメソッドを追加することは無作法であると考えられている。
RailsはWebアプリケーションでよく使うため、blank?メソッドをRuby に追加している。
>> "".blank?
=> true
>> " ".empty?
=> false
>> " ".blank?
=> true
>> nil.blank?
=> true
コントローラクラス
ユーザークラス
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) をそれぞれ作成する。
アクセサーを作成すると、そのデータを取り出すメソッド (getter) と、データに代入するメソッド (setter) をそれぞれ定義する。
具体的には、この行を実行したことにより、インスタンス変数@nameとインスタンス変数@emailにアクセスするためのメソッドが用意される。
Railsでは、インスタンス変数をコントローラ内で宣言するだけでビューで使えるようになる、といった点に主な利用価値がある。
def initialize(attributes = {})
@name = attributes[:name]
@email = attributes[:email]
end
initializeは、Rubyの特殊なメソッドで、 User.newを実行すると自動的に呼び出されるメソッドとなっている。この場合のinitializeメソッドは、attributesという引数を1つ取る。
attributes変数は空のハッシュをデフォルトの値として持つため、名前やメールアドレスのないユーザーを作ることができる(存在しないキーに対してハッシュはnilを返すので、:nameキーがなければattributes[:name]はnilになり、同じことがattributes[:email]にも言える。)。
def formatted_email
"#{@name} <#{@email}>"
end
formatted_emailメソッドは、文字列の式展開を利用して、@nameと@emailに割り当てられた値をユーザーのメールアドレスとして構成する。
@ 記号によって示されているとおり、@nameと@emailは両方ともインスタンス変数なので、自動的にformatted_emailメソッドで使えるようになる。
>> 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>"
Railsコンソールを起動し、example_userのコードをrequireして、自作したクラスを試しに使ってみる。
’./example_user’というパスは、カレントディレクトリ (現在のディレクトリ)からの相対パスでexample_userファイルを探すようにRubyに指示する。
>> 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>"
前述のように最後のハッシュ引数の波カッコは省略できる。
それと同じ要領でinitializeメソッドにハッシュを渡すことで、属性が定義済みの他のユーザを作成することができる。
これは一般にマスアサインメント (mass assignment) と呼ばれる技法で、Railsアプリケーションでよく使われる。