LoginSignup
2
1

More than 5 years have passed since last update.

Railsの拡張メソッド覚書

Last updated at Posted at 2018-01-24

はじめに

この業界に入り研修開けて半年、アウトプットも大切なのでテスト代わりにまとめようと思い、ちょこちょこ更新していきます。
一個一個確かめながら書くので長いし時間かかりそう。
指摘や改善点がありましたらよろしくお願いします。

実行環境

macOS 10.13.2
ruby 2.5.0
activesupport 5.1.4
pry

Active Support

blank? present?

require 'active_support'
require 'active_support/core_ext'

test = nil
test.blank? #=> true
test.present? #=> false
test.empty? #=> ”NoMethodError: undefined method `empty?' for nil:NilClass”

test = ""
test.blank? #=> true
test.present? =#> false

test = 0
test.blank? #=> false
test.present? #=> true

blank?とpresent?です。nil、falseとそれ以外を判定します。

blank?とempty?を混ぜて覚えてましたが、empty?はNilClassには使えません。

1/25追記
コメントで指摘されましたが、blank?は空白文字も空と判定しますので
empty?とは動作が違います。

自分の言い回しだとNilClassで使えるか否かのみに読み取れますね。ありがとうございます。

せっかくなのでもう少し深く掘り下げて説明しようと思います。

RailsGuidesの説明だと以下の通りです。

Railsアプリケーションは以下の値を空白(blank)とみなします。

  • nilとfalse

  • 空白文字 (whitespace) だけで構成された文字列 (以下の注釈参照)

  • 空欄の配列とハッシュ

  • その他、empty?メソッドに応答するオブジェクトはすべて空白として扱われます。

配列とハッシュにも使えるそうです。

実際に定義元も見てみましょう。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class Object
  # An object is blank if it's false, empty, or a whitespace string.
  # For example, +false+, '', '   ', +nil+, [], and {} are all blank.
  #
  # This simplifies
  #
  #   !address || address.empty?
  #
  # to
  #
  #   address.blank?
  #
  # @return [true, false]
  def blank?
    respond_to?(:empty?) ? !!empty? : !self
  end

  # An object is present if it's not blank.
  #
  # @return [true, false]
  def present?
    !blank?
  end

まずはObjectClassです。

present?は!blank?というのが読み取れます。ソースにコメントで例を書いてるのがありがたいですね。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class NilClass
  # +nil+ is blank:
  #
  #   nil.blank? # => true
  #
  # @return [true]
  def blank?
    true
  end
end

class FalseClass
  # +false+ is blank:
  #
  #   false.blank? # => true
  #
  # @return [true]
  def blank?
    true
  end
end

class TrueClass
  # +true+ is not blank:
  #
  #   true.blank? # => false
  #
  # @return [false]
  def blank?
    false
  end
end

次はNilClass、FalseClass、TrueClassの定義です。しっかりNilClassにも定義されています。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class Array
  # An array is blank if it's empty:
  #
  #   [].blank?      # => true
  #   [1,2,3].blank? # => false
  #
  # @return [true, false]
  alias_method :blank?, :empty?
end

class Hash
  # A hash is blank if it's empty:
  #
  #   {}.blank?                # => true
  #   { key: 'value' }.blank?  # => false
  #
  # @return [true, false]
  alias_method :blank?, :empty?
end

ArrayとHashはempty?が呼ばれていますね。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class String
  BLANK_RE = /\A[[:space:]]*\z/
  ENCODED_BLANKS = Concurrent::Map.new do |h, enc|
    h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING)
  end

  # A string is blank if it's empty or contains whitespaces only:
  #
  #   ''.blank?       # => true
  #   '   '.blank?    # => true
  #   "\t\n\r".blank? # => true
  #   ' blah '.blank? # => false
  #
  # Unicode whitespace is supported:
  #
  #   "\u00a0".blank? # => true
  #
  # @return [true, false]
  def blank?
    # The regexp that matches blank strings is expensive. For the case of empty
    # strings we can speed up this method (~3.5x) with an empty? call. The
    # penalty for the rest of strings is marginal.
    empty? ||
      begin
        BLANK_RE.match?(self)
      rescue Encoding::CompatibilityError
        ENCODED_BLANKS[self.encoding].match?(self)
      end
  end
end

指摘されたStringClassです。RailsGuidesにも注釈がありましたが、
文字列判定に[:space:]が使用されています。こちらで確認しましたらスペースやタブ、改行などが含まれるそうです。
それら以外がある場合はfalseになるようです。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class Numeric #:nodoc:
  # No number is blank:
  #
  #   1.blank? # => false
  #   0.blank? # => false
  #
  # @return [false]
  def blank?
    false
  end
end

class Time #:nodoc:
  # No Time is blank:
  #
  #   Time.now.blank? # => false
  #
  # @return [false]
  def blank?
    false
  end
end

最後はNumericClassとTimeClassです。数字と時間にはblankはないため必ずfalseが返ってくると書いてあります。

blank? present?のまとめ

  • blank?は[:space:]に含まれる文字とnilとfalseに対してtrueを返す。
  • present?はblank?の反対だよ。
  • String#empty?はlengthが0の場合にtrueを返すよ!

presence

require 'active_support'
require 'active_support/core_ext'

test = ""
foo = test.presence || "こっちが入るよ"
p foo #=> "こっちが入るよ"

test.presence #=> nil

test = "今回はこっち"
foo = test.presence || "こっちが入るよ"
p foo #=> "今回はこっち"

presenceメソッドはガイドみて知りました。

定義元も見ましょう。

rails/activesupport/lib/active_support/core_ext/object/blank.rb
class Object
  # Returns the receiver if it's present otherwise returns +nil+.
  # <tt>object.presence</tt> is equivalent to
  #
  #    object.present? ? object : nil
  #
  # For example, something like
  #
  #   state   = params[:state]   if params[:state].present?
  #   country = params[:country] if params[:country].present?
  #   region  = state || country || 'US'
  #
  # becomes
  #
  #   region = params[:state].presence || params[:country].presence || 'US'
  #
  # @return [Object]
  def presence
    self if present?
  end
end

コメントを見ればわかりますが、
present?をして
trueならそのオブジェクト自身、
falseならnilを返します。

使い方としては値が入っていればその値を使い、nilなら初期値を入れるみたいな使い方ですね。

# この書き方を
if foo.present?
  bar = foo
else
  bar = "初期値"
end

# 一行で書けてわかりやすい!
bar = foo.presence || "初期値"

presenceを覚えれば簡潔に書けそうです。

例にもあるようにparamsの代入でよく使えそうです。

presenceのまとめ

  • 自身に対してpresent?をしてるよ
  • trueなら自信を返すよ
  • falseならnilを返すよ
  • 初期値の代入とかで使えるよ

参考

Rails Guides Active Support コア拡張機能
Rubyのリファレンスみたいに書いてないのかな?と思ったらしっかり書いてありました。
Rails Guidesの情報量すごい

ブラケット表現 (Bracket Expression)
blank?で使われる[:space:]の説明

2
1
2

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
2
1