初心者がRubyの基礎を覚えたところで他人のコードを読むようになると、*args
や map(&:to_s)
のような謎の記法がでてきます。
この手の記法は名前がわからないとググラビリティが低くなるため、人によってはつまづきとなることが多いようです。
尋ねられることがたまにありますので、この機会にRails開発でよく使われるものを中心にまとめてみます。
引数
*args
変数名の冒頭に*
(アスタリスク)が付いているもので、「可変長引数」または「splat引数」とかいいます。
引数を複数個設定でき、さらにメソッド内部で引数を配列として受け取ることができます。
def splatter(*args)
p args
end
splatter('foo')
# => ['foo']
splatter('foo', 'bar', 'baz')
# => ['foo', 'bar', 'baz']
なお、引数に*
をつけると配列を引数として渡せます。
def math_consts(name, value)
"#{name} = #{value}"
end
constants = [["π", Math::PI], ["e", Math::E]]
constants.each do |constant|
puts math_consts(*constant)
end
#=> π = 3.141592653589793
#=> e = 2.718281828459045
なお、慣用的にargumentsを表す*args
と名付けられることが多いですけど、ただの変数名なので*constants
でも何でも大丈夫です。
**opts
**
(アスタリスク2つ)も可変長引数ですが、こちらはキーワード引数をハッシュで受け取ることを表しています。
オプション設定が必要なメソッドで使われることが多いと思います。
def hello_with_option(msg, **opts)
name = opts[:name]
time = opts[:time] || Time.now
puts "#{msg} #{name}@#{time}"
end
hello_with_option("Hello!", name: "nashirox")
# => Hello! nashirox@2017-02-07 16:58:46 +0900
デフォルト引数で空ハッシュ opts = {}
を設定しても同じことになります。
&block
仮引数(例えばblock)に&
(アンパサンド)を前置すると、「ブロック引数」となります。
メソッドはこの仮引数を介してブロックを受け取れるようになります。
def this_is_block(&block)
block.call # yield でも同じ
end
this_is_block do
p "This is my block"
end
# => "This is my block"
より詳細には、&
を前置することでブロックをProcオブジェクト(手続きオブジェクト)に変換しています。
&:method_name
map
などブロックで配列の中身を受け取るようなメソッドに、ブロック代わりに&
を前置したメソッド名(:method_name
)を渡すことができます。
# 配列の要素をstringにして返す
[1, 2, 3].map(&:to_s)
# => ["1", "2", "3"]
# 上と同じ
[1, 2, 3].map { |i| i.to_s }
# => ["1", "2", "3"]
# 配列内の総和を得る
[1, 2, 3].inject(&:+)
# => 6
なぜこう言ったことができるかについてはProcに関する理解が必要なのでここでは割愛します、調べると色々出てくると思います。
_
_
(アンダースコア)を用いて、使わない変数名を宣言することができます。
fruits = [
['apple', 200], ['mango', 800], ['pineapple', 500]
]
p fruits.sort{ |(n1, p1), (n2, p2)| p2 <=> p1 }
このコードをw
オプション付きで実行すると警告が出ます。
$ ruby -w sample.rb
#=> sample.rb:5: warning: assigned but unused variable - n1
#=> sample.rb:5: warning: assigned but unused variable - n2
#=> [["mango", 800], ["pineapple", 500], ["apple", 200]]
警告を避けるためには_
を使うか、Ruby 2.0以降では_
を変数名に前置するだけで良いです。
fruits = [
['apple', 200], ['mango', 800], ['pineapple', 500]
]
# Ruby 1.9以前
p fruits.sort{ |(_, p1), (_, p2)| p2 <=> p1 }
#=> [["mango", 800], ["pineapple", 500], ["apple", 200]]
# Ruby 2.0以降
p fruits.sort{ |(_n1, p1), (_n2, p2)| p2 <=> p1 }
#=> [["mango", 800], ["pineapple", 500], ["apple", 200]]
def hoge _, name
puts _
puts name
end
実際には警告を避けるというより、その変数が使われない(ないしは捨てている)ことを明示したいときに書くことが多いです。
演算子
||=
通称「nilガード」などと呼ばれ、初期化イディオムとして使われます。
左辺が真だったら何もせず、偽だったら右辺を代入します。
# 初期化されていない変数の呼び出し
foo
# => NameError: undefined local variable or method `foo' for main:Object
# fooが偽なので右辺が代入される
foo ||= true
foo
# => true
# fooが代入されて真となるので、右辺が代入されない
foo ||= 'hoge'
foo
# => true
<=>
人によって(?)は未確認飛行物体のように見えるようで、「宇宙船演算子」や「UFO演算子」と通称されます。
左辺と右辺を比較して、左辺側が大きければ正の整数、逆に小さければ負の整数を返します。双方等しければ 0
、比較できなければ nil
を返します。
100 <=> 200 # => -1
200 <=> 100 # => 1
200 <=> 200 # => 0
100 <=> '100' # => nil
なお自作クラスで比較演算したい場合、Comparable
モジュールをクラスにインクルードし、<=>
演算子を定義することで可能になります。
class Human
include Comparable
attr_reader :age
def initialize(name, age)
@name = name
@age = age
end
def <=>(other)
@age <=> other.age
end
end
taro = Human.new("太郎", 25)
jiro = Human.new("次郎", 18)
p taro < jiro
# => false
p taro > jiro
# => true
p taro <=> jiro
# 1
->
ラムダ式で用いるリテラルで、「lambdaリテラル」や「アロー演算子」と呼ばれます。
# 定義
foo = -> (x) { x + x }
# 呼び出し
foo[5] # => 10
foo.(5) # => 10
foo.call 5 # => 10
# 通常のlambdaの書き方
bar = lambda { |x| x + x }
bar.call 5 # => 10
Railsだとモデルのスコープで使われたりしていますね。
class Comment < ActiveRecord::Base
scope :created_before, ->(date) { where("created_at < ?", date) }
end
Hoge::Foo
::
は「スコープ演算子」と呼ばれます。この演算子を利用して、あるクラスまたはモジュールで定義された定数を外部から参照することができます。
Railsの定数管理の手法として、initializers下にアプリケーション全体で使う定数を配置する方法などがありますね。
module Constants
AgeStart = 0
AgeEnd = 99
end
Constants
モジュールで登録可能年齢の上限と下限を定義して、モデルで呼び出します。
class Customer < ActiveRecord::Base
age_start = Constants::AgeStart #=> 0
age_end = Constants::AgeEnd #=> 99
validates :age, :inclusion => { :in => age_start..age_end }
end
なお、左辺無しの::Foo
と書けたりもして、これはトップレベルの定数を呼び出しています。
class Object
# Objectクラスに定数Fooを追加
Foo = 'foo'
end
::Foo
# => "foo"
&.
Ruby2.3から導入された、obj&.my_method
形式でのメソッド呼び出しです。呼称はSafe navigation operator、通称__ぼっち演算子__です
obj
がnilでなかったらmy_method
を実行します。
Rails使いはActiveSupportのtry!
をよく使うと思いますがあれと一緒で、言語の方がパクった取り入れたようです。
# railsだと今までこう書いていた
user.try!(:profile).try!(:sns).try!(:twitter)
# オブジェクトがnilならnilが返る
something_nil&.profile&.sns&.twitter
#=> nil
# nilでないオブジェクトでも存在しないメソッドを呼ぶとNoMethodError
building&.profile&.sns&.twitter
#=> NoMethodError: undefined method `profile?' for "building":Building
うまく活用すれば、呼び出し元がnilかも知れないと恐れる必要がなくありますね!
メソッド呼び出しは全部こいつでやれば安全
!!
すべてをtrueかfalseにします。
nilではなく、必ずfalseで返したい場合などに使います。
(なお、エクスクラメーションマークが一つだと否定演算子ですね)
!!nil #=> false
!!"abc" #=> true
!!false #=> false
どういうところに使うのかと、Railsだと次のよう使い方があるようです。
def logged_in?
!!session[:user_id]
end
呼び方ですが「二重否定」、欧米では「double-bang」や「bang-bang」などと言うようです(初めて知った)。
組み込み変数
$
で始まる変数はグローバル変数ですが、その中でも特別な役割が与えられている特殊な変数が「組み込み変数」です。
似たような記号が多くて覚えづらいのですが、最低限3つを押さえておけば良いと思います。
$0
現在実行中のRubyスクリプトの名前が入った変数です。
class Sample
def show_file_name
puts "This file name is #{$0}"
end
end
Sample.new.show_file_name
$ ruby sample.rb
# => This file name is sample.rb
$1, $2, $3..$n
最後に成功したパターンマッチでn番目の括弧にマッチした文字列が入っています。
最初の頃、$0
も仲間かと思ってたけど全然違う。
"foo bar baz" =~ /(f\w+)\s(\w+)/
p $1 #=> "foo"
p $2 #=> "bar"
p $3 #=> nil
$&
最後に成功した正規表現のパターンマッチでマッチした文字列が入っています。
"foo bar baz" =~ /(f\w+)\s(\w+)/
p $& #=> "foo bar"
組み込み定数
ENV
Rubyで標準で用意されている組み込み定数がいくつかありますが、Railsの開発でよく用いるのはENV
(エンブ)のみです。
ENV
は環境変数を表すオブジェクトで、ENV['KEY_NAME']
のような形でKEY_NAMEと合致する値を取り出すことができます。
Railsではsecret.yml
の中でENV["SECRET_KEY_BASE"]
のように環境変数を取り出しています。
development:
secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
test:
secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
環境変数をどう設定するかは割愛します。
その他記法
%w( )、%i( )、%s( )など
「パーセント記法」と呼ばれ、配列作成などによく使われます。
解説は各所に上がっていますので、詳細は別記事などを参照してください
# %w 文字列配列
fruits = %w(apple orange mango)
# => ['apple', 'orange', 'mango']
# %i シンボル配列
fruits = %i(apple orange mango)
# => [:apple, :orange, :mango]
なお、文字列配列は%記法を用いて書くことが推奨されています。
=>
「ハッシュロケット」と呼ばれ、ハッシュリテラルを書く際にキーと値を区切るものです。
なお、Ruby 1.9以降では別の書き方が出てきて、現在ではそちらが推奨です。ハッシュロケットはできるだけ使わない方ようにしてください。
# Ruby 1.8まで
{ "name" => "Alex" }
{ :name => "Alex" }
# Ruby 1.9 以降
{ name: "Alex" }
なお、ハッシュリテラルのキーがシンボルで、.
, -
等を含む場合、ハッシュロケットに統一するのが望ましいという考え方もあるようです。
good
{ :cookpad => 42,
:'cookpad.com' => 'foo',
}
bad
{ cookpad: 42,
:'cookpad.com' => 'foo',
}
以上です。なにか足すようなものがあったら追加します。
それではよきRubyライフを!