Ruby で暗黙のブロックパラメータを使うための gem をつくった

Ruby で暗黙のブロックパラメータを使うための gem をつくりました。

- 元ネタ : 　[Rubyのブロックつらい問題を解決する暗黙のブロックパラメータ](http://qiita.com/supermomonga/items/b0576847b1b88e3cd400)
- github : [osyo-manga/gem-use_arguments](https://github.com/osyo-manga/gem-use_arguments)


## インストール

```shell
$ gem install use_arguments
```


## 定義される暗黙のブロックパラメータ

|パラメータ　|意味|
|:--------|:---|
|`_1, _2..._N`| 各引数の要素|
|`_`| `_1` と同じ|
|`_args`       | 全引数の配列|
|`_yield`      | ブロック引数|
|`_self`       | 呼び出された Proc オブジェクト自身|
|`_receiver`|ブロックを渡したメソッドのレシーバ|

## 使い方

使い方は簡単で、ブロックの引数を定義する代わりに `_1` や `_2` といったプレースホルダを変わりに使用します。

```ruby
require "use_arguments"

# Array クラスのメソッドに対して使用する
using UseArguments::Array

p [1, 2, 3].map { _1 + _1 }
# => [2, 4, 6]

# Hash クラスのメソッドに対して使用する
using UseArguments::Hash

data = {homu: 13, mami: 14, mado: 13}
p data.select { _2 < 14 }
# => {:homu=>13, :mado=>13}
```


### `Proc#use_args`

対象の `Proc` オブジェクトのブロック内で暗黙のパラメータを使えるようにする。

```ruby
require "use_arguments"

using UseArguments

p proc { _args }.use_args.call 1, 2, 3
# => [1, 2, 3]

plus = proc { _1 + _2 }.use_args
p plus.call 1, 2
# => 3

fact = proc { _1 == 1 ? 1 : _1 * _self.(_1 - 1); }.use_args
p fact.call 5
# => 120

f = proc { _yield 1, 2 }.use_args
p f.call { |a, b| a - b }
# => -1

p f.call &plus
# => 3

# 引数が配列の場合は配列を展開して受け取る
p proc { _1 + _1 }.use_args.call [1, 2]
# => 2

# lambda の場合は引数を展開しない
p lambda { _1 + _1 }.use_args.call [1, 2]
# => [1, 2, 1, 2]
```

### `Object#use_args`

`#use_args` を呼び出すことでメソッドのブロック内で暗黙のパラメータを使えるようにする。

```ruby
require "use_arguments"

using UseArguments

p [1, 2, 3].use_args.map { _1 * _1 }
# => [1, 4, 9]

p [1, 2, 3].use_args.select { _1 % 2 == 0 }
# => [2]
```

### `using UseArguments::{任意のクラス名}`

指定したクラスのメソッドに渡すブロック内で暗黙のパラメータを使えるようにする。

```ruby
require "use_arguments"

using UseArguments::Array
# もしくは
# using UseArguments.usable Array

p [1, 2, 3].map { _1 + _1 }
# => [2, 4, 6]

p [[1, 2], [3, 4]].map { _1 + _2 }
# => [3, 7]


using UseArguments::Hash

data = {homu: 13, mami: 14, mado: 13}
p data.select { _2 < 14 }
# => {:homu=>13, :mado=>13}

p data.map { "#{_1}:#{_2}" }
# => ["homu:13", "mami:14", "mado:13"]
```

## [注意点] 配列を渡した場合は配列が展開されて引数を受け取る

`use_args` に配列を渡した場合、その配列を展開して引数を受け取ります。

```ruby
p proc { _1 + _2 }.use_args.call [1, 2]
# => 3
```

これは次のように引数を受け取っていることを想定した挙動になっています。

```ruby
p proc { |_1, _2| _1 + _2 }.call [1, 2]
# => 3
```

この挙動はブロックを `proc` か `lambda` で定義したのかで変わります。  
`proc` の場合は引数の配列を展開し、`lambda` の場合は引数の配列を展開しません。

```ruby
proc { [_1, _2] }.use_args.call [1, 2] # => 3
lambda { [_1, _2] }.use_args.call [1, 2] # => Error

# proc の場合は渡されなかった引数のパラメータは nil を返す
proc { [_1, _2] }.use_args.call 1 # => [1, nil]

# lambda の場合はエラー
lambda { [_1, _2] }.use_args.call 1 # => Error

# 配列を展開する
[[1, 2], [3, 4]].use_args.map &proc{ _1 + _1 }
# => [2, 6]

# 配列を展開しない
[[1, 2], [3, 4]].use_args.map &lambda{ _1 + _1 }
# => [[1, 2, 1, 2], [3, 4, 3, 4]]
```

各メソッドに対して `do 〜 end` をブロックとして渡した場合は `proc` として扱われるので、引数の扱いを厳密にしたい場合は `lambda` を使用してください。


## その他

use_arguments では引数以外にも `_receiver` （メソッドを呼び出したレシーバオブジェクト）や `_self` （自分自身）などが定義されています。  
なので、引数意外にも次のようなコードを書くことができます。

```ruby
# 再帰
fact = proc { _1 == 1 ? 1 : _1 * _self.(_1 - 1); }.use_args
p fact.call 5
# => 120

p [1, 2, 3].use_args.map { _1 + _receiver.size }
# => [4, 5, 6]
```

このようにブロックをちょっと便利に書くこともできます。