Ruby のオススメの機能７選

この記事は Ruby Advent Calendar 2015 の 8日目です。

比較的あまり知られていないと思うオススメの Ruby の機能を 7つ紹介します。

## `Enumerator.new`

`Enumerator.new` は知ってはいても、あまり使わない人が多いように思います。
私は非常によく使います。
理由は

* スコープを新たに導入したい
* Producer-Consumer パターン。値の生成と消費でフェーズの違いを明確化したい。
* そのメソッド内で1度使いたいだけなのに yield するメソッドを別に作るのはちょっと気が引ける。名前空間を汚したくない。
* 全部、一度配列にしちゃうとメモリが気になる。メモリ消費を節約したい。
* ネストを浅くしたい
* Enumerable モジュールの機能が欲しい

といったところです。

たとえば下記のようなかんじで使います。

```ruby
# Producer フェーズ
user_ids = Enumerator.new do |y|
  open("candidates.txt") do |f|
    f.each_line do |line|
      next if line.start_with?("#")
      user_id = line.chomp
      y << user_id
    end
  end
end

# Consumer フェーズ
user_ids.with_index 1 do |user_id, index|
  puts "#{index} #{user_id}"
end
```

上の例では Consumer フェーズが単純なので、直接書いてもいいのですが、複雑になってくるとネストを浅くできるメリットも活きてきて、`Enumerator.new` の良さが分かってきます。
`y` というのは慣習的な変数名で、`yielder` の頭文字です。`Yielder` オブジェクトだから　`y` ですね。

## `Object#tap`

`Object#tap` も多くの人が知っていますが、単にメソッドチェインの中でデバッグする目的で使う人が多いように思います。

私はいろんな状況で `Object#tap` をよく使います。
おもな理由は下記のとおりです。

* 変数の初期化とその利用でスコープ、フェーズの分割を明示したい
* 返り値を返すときに、最後にわざわざ `hash` とかオブジェクトを書くのに違和感を感じる。特に `map` などのブロックの場合とか。
* 昔 ActiveSupport にあった `Kernel#returning` のように値を返すときにすっきり書きたい

たとえば下記のように使います。

```ruby
alphabet_nums = {}.tap do |hash|
  ("a".."z").each.with_index 1 do |alphabet, index|
    hash[alphabet] = index
  end
end
```

こう書くと

```ruby
alphabet_nums = {}
("a".."z").each.with_index 1 do |alphabet, index|
  alphabet_nums[alphabet] = index
end
```
と書く場合に比べて、tap に囲まれた場所が初期化フェーズであることがよりコード中に明確に表現されていてわかりやすいように感じます。

上記の `alphabet_nums` が構築後は変更がない場合など特に、こう書いた方が構築中のブロック内だけ変更があるということが強調されていて、分かりやすいように感じます。

## `Float::INFINITY`
Ruby には無限大を表す `Float::INFINITY` という値があります。

`Float::INFINITY` を使うとコードをすっきり統一的に書けることがあります。

すべての数を扱うときとある範囲を扱うときの両方がありうる場合を例に説明します。

この場合よく下記のように書きますが、

```rb
# to が nil ならどんなに大きな値でもOK! to に値があればその値まで
if to.nil? || x < to
  do_something(x)
end
```

事前に to のデフォルト値を `Float::INFINITY` にしておけば、`nil` かどうかの判定は不要にできます。

```rb
to ||= Float::INFINITY # 事前に nil の場合は無限大を表す値を代入しておくことで
if x < to # スッキリ！！
  do_something(x)
end
```

`x < to` のような評価が一度だけであれば嬉しさはあまり伝わらないかもしれませんが、何度も出てくるような場合はスッキリした見た目で分かりやすくなります。

## `Enumerable#each_slice`

`Enumerable#each_slice` は何個かずつブロックに渡して順に処理を行えるメソッドです。
このメソッドそのものはよく知られているかと思いますが、似た処理を繰り返すときにすっきり書く方法を実例とともに紹介します。

「[電気料金を比較し、最適な電力会社を選ぼう！エネチェンジ](https://enechange.jp/)」のサイトの開発の中で `Enumerable#each_slice` を使った例が以下になります。

```ruby
require 'selenium-webdriver'
require "webdriver-user-agent"

driver = Webdriver::UserAgent.driver browser: :firefox, agent: :iphone, orientation: :portrait

url = "http://localhost:3000/"
driver.navigate.to url

%w(
  order[family_name] 山田
  order[given_name] 太郎
  order[family_name_kana] ヤマダ
  order[given_name_kana] タロウ
  order[postcode_1] 100
  order[postcode_2] 0001
  order[phone_number_1] 012
  order[phone_number_2] 3456
  order[phone_number_3] 7890
).each_slice(2) do |name, value|
  fields = driver.find_elements :name, name
  field = fields.first
  field.send_keys value
end
```

Selenium を使った自動操作の例ですが name 属性でエレメントを見つけてそこに自動入力させています。

2要素の配列を要素に持つ配列（配列の配列）を作ってもいいのですが、`each_slice` を使うことで、配列のネストを1個減らすことができています。
また、`%w()` を使うことで `""` や `,` を書く必要がなくなっているのでかなりすっきりした見た目になっています。

特にロジックに変化が少なくデータの改変が多いときはこのように `%w()` で一気にデータ部を記述して、`Enumerable#each_slice` で何個かずつ分割する方が分かりやすいように思います。

## `Array#shelljoin`

マイナーですが、Ruby標準ライブラリには `shellwords` というライブラリが含まれています。

`shellwords` を `require` すると `sh` 等でエスケープが必要な文字は自動的にエスケープしながら文字列を連結してくれる `Array#shelljoin` メソッドが追加されます。

```ruby
require 'shellwords'
["vlc", "Ruby on Rails.mp4"].shelljoin #=> "vlc Ruby\\ on\\ Rails.mp4"
```

外部コマンドを実行するときは自分でエスケープするよりも `Array#shelljoin` を使う方が確実で見通しも良くなります。


## `SecureRandom.hex`
セッションキーなどに用いるランダムな文字列を生成するには `securerandom` を `require` すると使えるようになる `SecureRandom.hex` を使うと便利です。

```ruby
require 'securerandom'
SecureRandom.hex # "396bc8f76cffce4d3bfea3d07f58b09b"
```

ランダムなメールアドレスの生成、一時ファイルの命名など、案外使います。

## Flip Flop 演算子

ほとんどだれも知らないと思われますが Flip Flop 演算子という記法があります。

条件文を `..` で結んで、最初の条件が満たされてから次の条件が満たされるまで `true` を返します。

この日本語ではわからないと思いますので、次の例を見てください。

```ruby
(1..5).each do |x|
  puts x if (x == 2) .. (x == 4)
end
```

この結果は次のようになります。

```ruby
2
3
4
```


この例では嬉しさは伝わりにくいと思いますので、もう一例紹介します。Markdown 形式で書かれているファイルの中で、Ruby のコードスニペットのところだけを処理するコードは下記のように書けます。

```rb
ARGF.each_line do |line|
  if (line.start_with?("```rb"))..(line.chomp == "```")
    do_something(line)
  end
end
```