先日RubyKaigi2015に参加してきまして、Ruby2.3.0-preview2が出た!との事。
新機能をいち早く触ってみたのでご紹介します。
frozen-string-literal
ソースファイル内の全ての文字列リテラルを不変にする新しいマジックコメントとコマンドラインオプションが導入される、とのことです。
# frozen-string-literal :true
SAMPLE = 'sample'
class Sample
def self.reverse_string
SAMPLE.reverse!
end
end
p Sample.reverse_string
# => RuntimeError: can't modify frozen String
もしくは--enable=frozen-string-literal
というパラメータを渡すこともできます。
またデバッグ用に--debug=frozen-string-literal
オプションを渡すとエラーが発生したオブジェクトがどこで生成されたかを知ることができるようです。
safe navigation operator &.
またの名をぼっちoperatorだそうです。nilのハンドリングを簡単にしてくれるものだそうです。
ex:obj&.foo
実例ですと以下のような感じでしょうか。
user = User.find(1)
=> #<User:0x007fa586b97700
@attributes=
{"id"=>1,
"name"=>"hoge",
"email"=>"hoge@fuga.com",
"image"=>
#<User::Image:0x007fa586b95a18
@attributes=
{"url"=>"http://hogehoge.jpg",
"id"=>1,
}>,
}>
user.image&.url #=> 'http://hogehoge.jpg'
user = User.find(1)
=> #<User:0x007fa586b97700
@attributes=
{"id"=>1,
"name"=>"hoge",
"email"=>"hoge@fuga.com",
"image"=>nil,
}>
user.image&.url #=> nil
このレベルだとuser.image.try(:url)
でもいい気がしますね。
did_you_mean
did_you_mean gemがbundleされました。
typo多い私としては非常に助かるでございます。
sample = 'sample'
smple << '_test'
#=> NameError: undefined local variable or method `smple' for main:Object
# Did you mean? sample
ArrayクラスとHashクラスに関するupdate
Array#bsearch_index
条件を満たす値を二分探索で検索するArray#bsearch
のindexを返します。
list = [ 1, 3, 6, 9, 12 ]
list.bsearch_index { |x| x >= 5 } #=> 2
list.bsearch { |x| x >= 5 } #=> 6
Array#dig / Hash#dig
digメソッドです。ネストされたArrayやHashにアクセスできる、とのこと。
# Arrayクラスの場合
list = [[1, 2], [[3, 4], [5, 6]]]
list.dig 0 #=> [1, 2]
list.dig(0, 0) #=> 1
list.dig(1, 0, 0) #=> 3
# Hashクラスの場合
list = { a: 'b', c: { d: 'e', f: 'g' } }
list.dig :a #=> 'b'
list.dig(:c, :d) #=> 'e'
# Hashの中に配列がある場合
list = { a: 'b', c: { d: 'e', f: 'g' }, h: [[1, 2], [[3, 4], [5, 6]]] }
list.dig(:h, 0, 0) #=> 1
たとえば日本の地域、県名、市名のハッシュから市名を抜き出すとか?
areas = {
area: { id: 1, name: '関東',
prefecture: { id: 1, name: '東京',
city: [
{ id: 1, name: '目黒' },
{ id: 1, name: '恵比寿' },
{ id: 1, name: '渋谷' }
]
}
}
}
areas.dig(:area, :prefecture, :city, 2, :name) #=> '渋谷'
実際は関東の下も配列で複数の県名がぶら下がる形になるでしょうし、
配列のindexをいかに取得するか?でキレイに書けるかどうか変わってきそうですね。
Hash#fetch_values
Hashのvaluesを一括で取得します。
list = { a: 1, b: {c: 2, d: 3 }, e: 4, g: 5 }
list.fetch_values(:a, :e) #=> [1, 4]
list.fetch_values(:a, :b, :g) #=> [1, {:c=>2, :d=>3}, 5]
list.fetch_values(:c) #=> KeyError: key not found: :c
値がhash形式であっても、そのまま取得できるんですね。
合わせ技でこんなことも。
list = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
list.fetch_value(:a, :c, :e).bearch_index { |x| x >= 4 } #=> 2
例えばこんな使い方とかいかがでしょうか。
place = Place.find(1)
=> #<Place:0x007fa586b97700
@attributes=
{"id"=>1,
"name"=>"hoge",
"images"=>
[#<Place::Image:0x007fa586b95a18
@attributes=
{"url"=>"http://hogehoge.jpg",
"id"=>1,
}>,
#<Place::Image:0x007fa586b95b21
@attributes=
{"url"=>"http://hogehuga.jpg",
"id"=>2,
}>,
}>
id, name, images = user.attributes.fetch_values('id', 'name', 'images')
id #=> 1
name #=> "hoge"
images #=>[#<Place::Image:0x007fa586b95a18
# @attributes=
# {"url"=>"http://hogehoge.jpg",
# "id"=>1,
# }>,
# #<Place::Image:0x007fa586b95b21
# @attributes=
# {"url"=>"http://hogehuga.jpg",
# "id"=>2,
# }>]
Hash#<=, Hash#<, Hash#>=, Hash#>
Hashの包含関係を判定します。
{a: 1, b: 2} >= {a: 1} #=> true
{a: 1, b: 2} >= {a: 1, b: 2} #=> true
{a: 1, b: 2} > {a: 1, b: 2} #=> false
Hash#to_proc
Hashをproc化します。
list = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
list.to_proc(:a) #=> 1
# mapに渡す
[:a, :b, :c].map(&list) #=> [1, 2, 3]
procという便利なクラスがあったんですね。そもそもそこからして発見でした。
いかがでしたでしょうか?
新しく追加された機能とArrayとHashについての変更点をまとめてみました。
詳しくはhttps://github.com/ruby/ruby/blob/v2_3_0_preview2/NEWS を見てみて下さいね。
例年通りであれば2015/12/25にRuby2.3.0がリリースになります。良いRuby Lifeを!