best-ruby を読んでこんな書き方できたのかと思った記法 10 選

いろいろな Ruby の記法をまとめている [best-ruby](https://github.com/franzejr/best-ruby) を読んで、こんな書き方できたんだなあと思ったものをまとめました。


# 1. `|=` による代入

`|` は和集合を表す演算子ですが、

```rb
[1, 2, 3] | [2, 4]
#=> [1, 2, 3, 4]
```

`=` をつけると、和集合をそのまま変数に代入出来ます。

```rb
array = [1, 2, 3]
array |= [2, 4]

p array
#=> [1, 2, 3, 4]
```

`<<` を使って同じ事するよりちょっと簡単に書けます。

```rb
array = [1, 2, 3]

array << 2
array << 4

p array.uniq
#=> [1, 2, 3, 4]
```

ちょっと便利。

# 2. `Array#assoc` 

下記のように、配列の配列を Hash のように扱い、キーに対応する値を取得出来ます。

```rb
a = [%w(key1 value1), %w(key2 value2)]

a.assoc('key1')
#=> ["key1", "value1"]
a.assoc('key2')
#=> ["key2", "value2"]
a.assoc('key3')
#=> nil
```

`rassoc` で値から取得する事もできます。

```rb
a.rassoc('value1')
#=> ["key1", "value1"]
a.rassoc('value2')
#=> ["key2", "value2"]
```

あんまり、こういう形式で配列持つことないけど、何かの時に使えるかな...？

# 3. `Kernel#at_exit`

与えられたブロックを、プログラム終了時に実行します。

```rb
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` でも同じことが出来ますが、ブロック内に記述した場合は最初の一回しか有効になりません。

```rb
3.times do |i|
  END { puts "END#{i}" }
end

END { puts 'END' }

puts 'main_end'

# result
# main_end
# END
# END0
```

ちょっとしたスクリプト書く際に使えるかも。

# 4. `#{}` で囲まなくても文中の変数を表示できる

インスタンス変数、クラス変数、グローバル変数は `#{}` で囲む必要がなかったみたいです。

```rb
@instance = 'インスタンス変数'
@@class = 'クラス変数'
$global = 'グローバル変数'
variable = '変数'
CONSTANT = '定数'

"#@instance, #@@class, #$global, #variable, #CONSTANT"
#=> "インスタンス変数, クラス変数, グローバル変数, #variable, #CONSTANT"
```

`@`, `$` で変数って見分けがつくからですかね？
少しでもタイプ数を減らしたい！という方は！チーム開発で入れたら怒られそうだけど...

# 5. dump オプション

Ruby を実行する際に dump オプションを渡すと実行の debug などを出力してくれます。

```rb
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 みたいに % で変数を表示する

`"#{...}"` こう表示する以外の選択肢を考えたことなかったんですが、%で変数を渡せるんですね。

```rb
puts '%s: %03d' % ['Num', 42]
#=> Num: 042
puts '%s: %f' % ['Num', 42]
#=> Num: 42.000000
```

フォーマット指定するときわざわざ `sprintf` 使っていたので、知れてよかった。

# 7. `begin ...` で複数行キャッシュする

ワンライナーの場合は、インスタンス変数などを `||=` でよくキャッシュしますが、

```rb
def hoge
  @hoge ||= 'hogehoge' 
end
```

複数行の場合は、以下のようにしないとキャッシュ出来ないと思ってました。

```rb
def hoge
  return @hoge if @hoge

  a = 'hogehoge'
  b = 'fugafuga'
  @hoge = a + b
end
```

`||= begin ... end` と書いてもキャッシュされるんですね。

```rb
def hoge
  @hoge ||= begin
    a = 'hogehoge'
    b = 'fugafuga'
    a + b
  end
end
```

これはいろいろなところで使えそうだ！！

# 8. `Hash#fetch`

`Hash#fetch` でも Hash の値を取得することが出来るんですね。

```rb
params = {var: 42}

params.fetch(:var)
#=> 42
```

指定した key がなかった場合に nil じゃなくて、値を指定できるのが良いですね。

```rb
params[:missing]
#=> nil
params.fetch(:missing, 42)
#=> 42
params.fetch(:missing) {|key| "#{key} is not found" }
#=> "missing is not found"
```

default を指定しないと例外を発生します。

```rb
params.fetch(:missing)
#=> KeyError: key not found: :missing
#   from (pry):64:in `fetch'
```

必須のパラメーターで

```rb
raise if params[:id].nil?
```

みたいなブロックを入れてる場合は `fetch` を使った方がいいですね。

# 9. `PStore`, `YAML::Store`

わざわざ DB 用意したくないけど、ちょろっとデータストア使いたいって時に便利です。

```rb
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)` としてあげます。

```rb
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` を呼びます。

```rb
db.transaction { db.roots }
#=> [:name1, :age1, :name2, :age2]
``` 

毎回 `#transaction` を呼び出さないといけないのも辛い...。

また、`PStore` はバイナリ形式で保存しますが、`YAML::Store` を使うと、YAML で保存することも出来ます。

```rb
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

```rb
ObjectSpace.each_object(String) do |object|
  p object
end
```

実行するとすごいことになります。。。
`ObjectSpace.each_object(String)` で存在している `String` クラスのオブジェクトを全部取ってきて、イテレートするんですね。`ObjectSpace` なんてクラスがあったとは。

ちなみにクラスごとのオブジェクトの数は `count_objects` で取れるようです。

```rb
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}
```

以上です！まだまだ、知らない記法・メソッドがいっぱいあるなあ！