いろいろな Ruby の記法をまとめている best-ruby を読んで、こんな書き方できたんだなあと思ったものをまとめました。
1. |=
による代入
|
は和集合を表す演算子ですが、
[1, 2, 3] | [2, 4]
#=> [1, 2, 3, 4]
=
をつけると、和集合をそのまま変数に代入出来ます。
array = [1, 2, 3]
array |= [2, 4]
p array
#=> [1, 2, 3, 4]
<<
を使って同じ事するよりちょっと簡単に書けます。
array = [1, 2, 3]
array << 2
array << 4
p array.uniq
#=> [1, 2, 3, 4]
ちょっと便利。
2. Array#assoc
下記のように、配列の配列を Hash のように扱い、キーに対応する値を取得出来ます。
a = [%w(key1 value1), %w(key2 value2)]
a.assoc('key1')
#=> ["key1", "value1"]
a.assoc('key2')
#=> ["key2", "value2"]
a.assoc('key3')
#=> nil
rassoc
で値から取得する事もできます。
a.rassoc('value1')
#=> ["key1", "value1"]
a.rassoc('value2')
#=> ["key2", "value2"]
あんまり、こういう形式で配列持つことないけど、何かの時に使えるかな...?
3. Kernel#at_exit
与えられたブロックを、プログラム終了時に実行します。
3.times do |i|
at_exit { puts "at_exit#{i}" }
end
at_exit { puts 'at_exit' }
puts 'main_end'
# result
# main_end
# at_exit
# at_exit2
# at_exit1
# at_exit0
先に記述した式ほど、後に実行されます。
また、END
でも同じことが出来ますが、ブロック内に記述した場合は最初の一回しか有効になりません。
3.times do |i|
END { puts "END#{i}" }
end
END { puts 'END' }
puts 'main_end'
# result
# main_end
# END
# END0
ちょっとしたスクリプト書く際に使えるかも。
4. #{}
で囲まなくても文中の変数を表示できる
インスタンス変数、クラス変数、グローバル変数は #{}
で囲む必要がなかったみたいです。
@instance = 'インスタンス変数'
@@class = 'クラス変数'
$global = 'グローバル変数'
variable = '変数'
CONSTANT = '定数'
"#@instance, #@@class, #$global, #variable, #CONSTANT"
#=> "インスタンス変数, クラス変数, グローバル変数, #variable, #CONSTANT"
@
, $
で変数って見分けがつくからですかね?
少しでもタイプ数を減らしたい!という方は!チーム開発で入れたら怒られそうだけど...
5. dump オプション
Ruby を実行する際に dump オプションを渡すと実行の debug などを出力してくれます。
ruby -e 'puts { is_this_a_block }' --dump parsetree
ruby -e 'puts { is_this_a_block }' --dump parsetree_with_comment
# Output yacc's debug info when ruby parsing code.
ruby -e 'puts { is_this_a_block }' --dump yydebug
# Check ruby code syntax whether OK.
ruby -e 'puts { is_this_a_block }' --dump syntax
# Output yarv instructions info of compiled ruby code.
ruby -e 'puts { is_this_a_block }' --dump insns
シンタックスにミスがないか見てくれる --dump syntax
は良いですね。
6. C の printf みたいに % で変数を表示する
"#{...}"
こう表示する以外の選択肢を考えたことなかったんですが、%で変数を渡せるんですね。
puts '%s: %03d' % ['Num', 42]
#=> Num: 042
puts '%s: %f' % ['Num', 42]
#=> Num: 42.000000
フォーマット指定するときわざわざ sprintf
使っていたので、知れてよかった。
7. begin ...
で複数行キャッシュする
ワンライナーの場合は、インスタンス変数などを ||=
でよくキャッシュしますが、
def hoge
@hoge ||= 'hogehoge'
end
複数行の場合は、以下のようにしないとキャッシュ出来ないと思ってました。
def hoge
return @hoge if @hoge
a = 'hogehoge'
b = 'fugafuga'
@hoge = a + b
end
||= begin ... end
と書いてもキャッシュされるんですね。
def hoge
@hoge ||= begin
a = 'hogehoge'
b = 'fugafuga'
a + b
end
end
これはいろいろなところで使えそうだ!!
8. Hash#fetch
Hash#fetch
でも Hash の値を取得することが出来るんですね。
params = {var: 42}
params.fetch(:var)
#=> 42
指定した key がなかった場合に nil じゃなくて、値を指定できるのが良いですね。
params[:missing]
#=> nil
params.fetch(:missing, 42)
#=> 42
params.fetch(:missing) {|key| "#{key} is not found" }
#=> "missing is not found"
default を指定しないと例外を発生します。
params.fetch(:missing)
#=> KeyError: key not found: :missing
# from (pry):64:in `fetch'
必須のパラメーターで
raise if params[:id].nil?
みたいなブロックを入れてる場合は fetch
を使った方がいいですね。
9. PStore
, YAML::Store
わざわざ DB 用意したくないけど、ちょろっとデータストア使いたいって時に便利です。
require 'pstore'
db = PStore.new('mydatabase.pstore')
db.transaction do
db[:name1] = 'hogehoge さん'
db[:age1] = 20
end
db.transaction do
db[:name2] = 'fugafuga さん'
db[:age2] = 30
end
これで mydatabase.pstore
にバイナリファイルで保存されます。データを読み込みたい場合は、transaction(true)
としてあげます。
require 'pstore'
db = PStore.new('mydatabase.pstore')
db.transaction(true) do
p db[:name1]
p db[:age1]
p db[:name2]
p db[:age2]
end
# => "hogehoge さん"
# 20
# "fugafuga さん"
# 30
良いですね!ただ、name1
, name2
のように key を変えないといけないのがなあ...。DB のようには使えないか。
ちなみに 存在する key を調べたい場合は #roots
を呼びます。
db.transaction { db.roots }
#=> [:name1, :age1, :name2, :age2]
毎回 #transaction
を呼び出さないといけないのも辛い...。
また、PStore
はバイナリ形式で保存しますが、YAML::Store
を使うと、YAML で保存することも出来ます。
require 'yaml/store'
db = YAML::Store.new('mydatabase.yml')
db.transaction do
db[:name1] = 'hogehoge さん'
db[:age1] = 20
end
db.transaction do
db[:name2] = 'fugafuga さん'
db[:age2] = 30
end
#=> ---
# :name1: hogehoge さん
# :age1: 20
# :name2: fugafuga さん
# :age2: 30
簡単!
不便な点はありますが、使い方は簡単なので、これもちょっとしたスクリプト書く際に便利ですね。
10. ObjectSpace
ObjectSpace.each_object(String) do |object|
p object
end
実行するとすごいことになります。。。
ObjectSpace.each_object(String)
で存在している String
クラスのオブジェクトを全部取ってきて、イテレートするんですね。ObjectSpace
なんてクラスがあったとは。
ちなみにクラスごとのオブジェクトの数は count_objects
で取れるようです。
ObjectSpace.count_objects
#=>
{:TOTAL=>939121,
:FREE=>463526,
:T_OBJECT=>19063,
:T_CLASS=>11016,
:T_MODULE=>1823,
:T_FLOAT=>12,
:T_STRING=>261008,
:T_REGEXP=>4040,
:T_ARRAY=>65256,
:T_HASH=>7917,
:T_STRUCT=>762,
:T_BIGNUM=>15,
:T_FILE=>19,
:T_DATA=>57822,
:T_MATCH=>198,
:T_COMPLEX=>1,
:T_RATIONAL=>903,
:T_SYMBOL=>1115,
:T_NODE=>41880,
:T_ICLASS=>2745}
以上です!まだまだ、知らない記法・メソッドがいっぱいあるなあ!