Rails の便利なメソッド（Array 編）

この前、[数値オブジェクト](http://qiita.com/pekepek/items/86e1585d0af8a0692731)の拡張メソッドをまとめたので、次は Array の Rails 便利メソッドをまとめました。

# 可読性を向上させる
## `from(position)`, `to(position)`

位置を指定して値を取り出せる。`from` は引数の位置「から」、`to` は引数の位置「まで」。

```rb
[0, 1, 2, 3].from(1) #=> [1, 2, 3]
[0, 1, 2, 3].to(2) #=> [0, 1, 2]
```

`from` と同じことをしようとすると

```rb
[0, 1, 2, 3][1..-1] #=> [1, 2, 3]
[0, 1, 2, 3][1, 3] #=> [1, 2, 3]
```

という感じになるので、とても直観的。

## `second`, `third`, `fourth`, `fifth`, `forty_two`

パッと見の通り、その位置の値を返す。Ruby に `first` があるので、その続きですね。

```rb
[1, 2, 3].second #=> 2
[1, 2, 3].third #=> 3
(1..42).to_a.forty_two #=> 42
```

## `append`, `prepend`

`append` は `<<` のエイリアス、`prepend` は `unshift` のエイリアス。
ただのエイリアスだけど、これも直観的なので、個人的にはよく使います。

```rb
[0, 1, 2].append(3) #=> [0, 1, 2, 3]
[0, 1, 2].prepend(-1) #=> [-1, 0, 1, 2]
```

# グループ分けする
## `in_groups_of(number, fill_with = nil)`

与えた number の長さの配列にグループ化する。
「10 人を 3 人ずつの班に分ける」というような使い方ができる。

```rb
(1..10).to_a.in_groups_of(3) #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, nil, nil]]
```

デフォルトでは、要素数が number に足りない場合は `nil` が追加されるが、引数で指定する事も出来る。

```rb
(1..10).to_a.in_groups_of(3, 'hoge') #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, "hoge", "hoge"]]

# false を渡すと補完しなくなる
(1..10).to_a.in_groups_of(3, false) #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
```

さらにブロックで処理も与えられる。

```rb
('A'..'J').to_a.in_groups_of(3, false) {|g| puts "#{g.first}班 : #{g}" }
# A班 : ["A", "B", "C"]
# D班 : ["D", "E", "F"]
# G班 : ["G", "H", "I"]
# J班 : ["J"]
```

## `in_groups(number, fill_with = nil)`

与えた number の数にグループ化する。
「10 人を 3 つの班に分ける」というような使い方ができる。

```rb
(1..10).to_a.in_groups(3) #=> [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]
(1..10).to_a.in_groups(2) #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
```

この時、足りない要素数は 1 以内になるように分けてくれる。
また、同じように補完する値を指定可能。

```rb
(1..10).to_a.in_groups(3, 'hoge') #=> [[1, 2, 3, 4], [5, 6, 7, "hoge"], [8, 9, 10, "hoge"]]
(1..10).to_a.in_groups(3, false) #=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
```

ブロックも

```rb
('A'..'J').to_a.in_groups(3, false) {|e| puts "#{e.first}班 : #{e}" }
# A班 : ["A", "B", "C", "D"]
# E班 : ["E", "F", "G"]
# H班 : ["H", "I", "J"]
```

## `split(value = nil)`

指定した値にマッチ or ブロックの結果が true になるところで配列を分割する。

```rb
(1..5).to_a.split(3) #=> [[1, 2], [4, 5]]
[1, 2, 'a', 4, 5].split {|a| a.kind_of?(String) } #=> [[1, 2], [4, 5]]
```

# 文字列に変換する

## `to_sentence(options = {})`

要素を連結して、文字列に変換する。
その際、以下のオプションが指定できる

| オプション | 説明 |
|:--------:|:----:|
|`words_connector`| 要素を連結する際の文字列 |
|`two_words_connector`| 配列の要素が 2 の場合の連結文字列 |
|`last_word_connector`| 最後の要素を連結する際の文字列 |
|`locale`| I18n 対応、言語を指定出来る |

```rb
['A', 'B', 'C'].to_sentence #=> "A, B, and C"

# 言語の指定
['A', 'B', 'C'].to_sentence(locale: :ja) #=> "AとBとC"

# 連結する文字列の指定
['A', 'B', 'C'].to_sentence(words_connector: ' と ') #=> "A と B, and C"
['A', 'B', 'C'].to_sentence(words_connector: ' と ', last_word_connector: ' そして ') #=> "A と B そして C"

# 要素が 2 つの場合は two_words_connector を使う
['A', 'B'].to_sentence(words_connector: ' と ', last_word_connector: ' そして ') #=> "A and B"
['A', 'B'].to_sentence(two_words_connector: ' あと ') #=> "A あと B"
```

全部のオプションを指定してみる

```yaml:locales/ja.yml
ja:
  support:
    array:
      words_connector: ' と '
      two_words_connector: ' そして '
      last_word_connector: ' 最後に '
```

```rb
('A'..'J').to_a.in_groups(4, false) {|g| puts "#{g.first}班 : #{g.to_sentence(locale: :ja)}" }
# A班 : A と B 最後に C
# D班 : D と E 最後に F
# G班 : G そして H
# I班 : I そして J
```

無理矢理（・・；

## `to_s(format = :default)`

[Numeric クラスで拡張されている事を紹介しましたが](http://qiita.com/pekepek/items/86e1585d0af8a0692731#to_sformat-options)、Array クラスでも拡張されています。
ただ、format が `:db` しかないのと、`id` 属性があるオブジェクトの配列にしか使えないのが残念。

```rb
User.all.to_a.to_s(:db) #=> "1,2,3,4,5,6,7,8"
```

このように id を `,` 区切りで連結して返します。

## `to_param`, `to_query`, `to_xml(options = {})`

左から URL のパス、クエリ、XML に変換した文字列を返す。

紹介しておいて何ですが、あんまり使い方が思いつかなかった。。。
まあ、ActionPack の `Renderers` とか `Redirect` で使われるているので、どちらかというと Rails 内で使うために用意されているのかな。ただ、ちょっとしたスクリプト書くときに便利かも。

```rb
%w(qiita.com pekepek items).to_param #=> "qiita.com/pekepek/items"
%w(Rails coding).to_query('hobbies') #=> "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"

puts [{foo: 1, bar: 2}, {baz: 'hogehoge'}].to_xml
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <foo type="integer">1</foo>
#     <bar type="integer">2</bar>
#   </object>
#   <object>
#     <baz>hogehoge</baz>
#   </object>
# </objects>
```

# その他
## `self.wrap(object)`

`Kernel#Array` 基本動作は同じだが、Range や Hash を引数にした場合に挙動が異なる。

```rb
# 引数が Array の場合
Array([1, 2, 3]) #=> [1, 2, 3]
Array.wrap([1, 2, 3]) #=> [1, 2, 3]

# Hash の場合
Array(a: 1, b: 2, c: 3) #=> [[:a, 1], [:b, 2], [:c, 3]]
Array.wrap(a: 1, b: 2, c: 3) #=> [{:a=>1, :b=>2, :c=>3}]

# Range の場合
Array(1..3) #=> [1, 2, 3]
Array.wrap(1..3) #=> [1..3]
```

ちゃんと配列にラップしてくれるメソッドという感じですね。

# Rails 5 で追加されるメソッド

最後に Rails 5 で追加されるメソッドも紹介。

## `second_to_last`, `third_to_last`

last の続きが追加された...!!

```rb
[1, 2, 3].third_to_last #=> 1
[1, 2, 3].second_to_last #=> 2
```

## `without(*elements)`

elements で指定した要素を除いた配列を返す。中身は `Array#-` してるだけ。

```rb
[1, 2, 3].without(1, 2) #=> [3]
```

## `inquiry`

元々 `String#inquiry` はあったが、Array にも追加された。
`hogehoge?` というメソッドが呼べるようになり、実際にメソッド名と同じ要素が合ったら `true` を返す。

```rb
users = %w(pekepek pokopok).inquiry #=> ["pekepek", "pokopok"]
users.pekepek? #=> true
users.pokopok? #=> true
users.tom? #=> false
```

`include?('pekepek')` とやっている事は同じですが、引数がないと見た目がすっきりしていいですね。

また、`inquiry` を呼ぶと、`any?` がオーバーライドされて、可変長引数を受け取れる様になります。元の `any?` と同じように引数が一つでもマッチしたら true を返します。

```rb
users = %w(pekepek pokopok).inquiry
users.any?('pekepek', 'hogehoge') #=> true
users.any?('hogehoge', 'fugafuga') #=> false
```

これは結構使いどころ多そうですね。


以上が Array の拡張メソッドです！