self時々nilを返す破壊的メソッド

`self` を返す破壊的メソッドの中には `nil` をたまに返すものがあるので、新しいオブジェクトを返すメソッドの単純な置き換えとして使う際は注意がいる。

```ruby
# 置き換えても一見うまく動いているが…
str = "ABC\n"
str.downcase.chomp     #=> "abc"
str.downcase!.chomp!   #=> "abc"

# たまにおかしくなる場合がある
str = 'abc'
str.downcase.chomp     #=> "abc"
str.downcase!.chomp!   #=> NoMethodError: undefined method `chomp!' for nil:NilClass
```

では `nil` を返しうるメソッドと `self` を必ず返すメソッドの差は何か、ということが気になったので、よく使う `String`, `Array`, `Hash` クラスについてメソッドを調べてみた。結果として単純明快な規則までは分からなかったものの、種類毎にどちらのパターンか決まっている印象を受けた。
（ActiveSupportについては同じ規則でなく、実装の都合で決まっているように見える）

## Ruby
Ruby 2.5のリファレンスマニュアルから抜粋し、覚えやすいよう大まかな役割毎に分類した。（正確な動作説明はマニュアルを参照）

### [String](http://docs.ruby-lang.org/ja/2.5.0/class/String.html)

※ まともに書くと長いので、複数のメソッド名を正規表現でまとめている

- `self` または `nil` を返す破壊的メソッド
	- 特定文字の除去 : `delete(|_prefix|_suffix)!`, `chomp!`, `chop!`, `[lr]?strip!`, `squeeze!`
	- 大文字小文字の変換 : `upcase!`, `downcase!`, `swapcase!`, `capitalize!`
	- 置換 : `sub!`, `gsub!`, `tr!`, `tr_s!`
- 必ず `self` を返す破壊的メソッド
	- 初期化 : `clear`, `replace`
	- 文字列の追加 : `<<`, `concat`, `insert`
	- 並べ替え : `reverse!`
	- 次の文字列 : `succ!`, `next!`
	- エンコーディング : `encode!`, `force_encoding`, `scrub!`, `unicode_normalize!`

### [Array](http://docs.ruby-lang.org/ja/2.5.0/class/Array.html)

- `self` または `nil` を返す破壊的メソッド
	- 抽出 : `select!`, `reject!`, `compact!`, `uniq!`
	- 変形 : `flatten!`
- 必ず `self` を返す破壊的メソッド
	- 初期化 : `clear`, `fill`, `replace`
	- 要素の追加 : `<<`, `concat`, `insert`, `push`, `append`, `unshift`, `prepend`
	- 並べ替え : `sort!`, `sort_by!`, `shuffle!`, `reverse!`, `rotate!`
	- 抽出 : `keep_if`, `delete_if`
	- 要素の変換 : `collect!`, `map!`

### [Hash](http://docs.ruby-lang.org/ja/2.5.0/class/Hash.html)

- `self` または `nil` を返す破壊的メソッド
	- 抽出 : `select!`, `reject!`, `compact!`
- 必ず `self` を返す破壊的メソッド
	- 初期化 : `clear`, `replace`
	- 追加・更新 : `update`, `merge!`
	- 抽出 : `keep_if`, `delete_if`
	- 要素の変換 : `transform_keys!`, `transform_values!`
	- 再計算 : `rehash`
	- 設定変更 : `compare_by_identity`

## ActiveSupport
ActiveSupport 5.2.0のソースコードから抜粋した。新しいRubyに取り込まれたものについても記載する。

### [String](http://github.com/rails/rails/tree/v5.2.0/activesupport/lib/active_support/core_ext/string)

- `self` または `nil` を返す破壊的メソッド
	- 置換 : `indent!`
- 必ず `self` を返す破壊的メソッド
	- 特定文字の除去 : `remove!`
	- 置換 : `squish!`

### [Array](http://github.com/rails/rails/tree/v5.2.0/activesupport/lib/active_support/core_ext/array)

- `self` または `nil` を返す破壊的メソッド
	- (無し)
- 必ず `self` を返す破壊的メソッド
	- 要素の追加 : `append`, `prepend`

### [Hash](http://github.com/rails/rails/tree/v5.2.0/activesupport/lib/active_support/core_ext/hash)

※ まともに書くと長いので、複数のメソッド名を正規表現でまとめている

- `self` または `nil` を返す破壊的メソッド
	- 抽出 : `compact!`
- 必ず `self` を返す破壊的メソッド
	- 追加・更新 : `deep_merge!`, `reverse_(merge!|update)`, `with_defaults!`
	- 抽出 : `except!`
	- 要素の変換 : `transform_values!`, `(deep_)?(transform|stringify|symbolize)_keys!`, `to_options!`

## 補足
上に挙げた「`self` または `nil` を返す破壊的メソッド」は全て、実際に `nil` を返すのはオブジェクトに手を加えなかったとき。例えば置換の場合、全く同じ文字列に置換すれば `nil` とはならない。

```ruby
str = 'abc'
str.tr!('A', 'A')   #=> nil
str.tr!('a', 'a')   #=> "abc"
```

必ず `self` を返してほしいなら、[`Object#tap`](https://docs.ruby-lang.org/ja/2.3.0/method/Object/i/tap.html) を使えば安全。

```ruby
str = 'abc'
str.tap { |obj| obj.tr!('A', 'A') }   #=> "abc"
str.tap(&:downcase!).tap(&:chomp!)    #=> "abc"
```