LoginSignup
11
9

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-08-27

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

# 置き換えても一見うまく動いているが…
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

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

  • 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

  • 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

  • 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

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

Array

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

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 とはならない。

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

必ず self を返してほしいなら、Object#tap を使えば安全。

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9