Permalink
Browse files

blank? and present? commit to return singletons [Xavier Noria & Pavel…

… Pravosud]

The contract of blank? and present? was in principle to return Object, as we
generally do, the test suite and description was consistent with that, but some
examples had comments like "# => true".

This cannot be unclear, we either fix the examples, or update the contract.

Since users may be already assuming singletons due to the examples and the fact
that they were returned before 30ba7ee, the safest option seems to be to revise
the contract and the implementation of String#blank?

The motivation for 30ba7ee was to improve the performance of the predicate, the
refactor based on === is on par regarding speed.

With this commit we start documenting return types using YARD conventions. We
plan to document return types gradually.
  • Loading branch information...
fxn committed Dec 28, 2013
1 parent 7b89446 commit 126dc47665c65cd129967cbd8a5926dddd0aa514
@@ -1,3 +1,7 @@
* `blank?` and `present?` commit to return singletons.
*Xavier Noria*, *Pavel Pravosud*
* Fixed Float related error in NumberHelper with large precisions.
before:
@@ -4,36 +4,42 @@ class Object
# An object is blank if it's false, empty, or a whitespace string.
# For example, '', ' ', +nil+, [], and {} are all blank.
#
# This simplifies:
# This simplifies
#
# if address.nil? || address.empty?
# address.nil? || address.empty?
#
# ...to:
# to
#
# if address.blank?
# address.blank?
#
# @return [true, false]
def blank?
respond_to?(:empty?) ? empty? : !self
respond_to?(:empty?) ? !!empty? : !self

This comment has been minimized.

Show comment
Hide comment
@Bartuz

Bartuz Sep 11, 2015

Contributor

Why double !! ? It returns the TrueClass / FalseClass anynway

@Bartuz

Bartuz Sep 11, 2015

Contributor

Why double !! ? It returns the TrueClass / FalseClass anynway

This comment has been minimized.

Show comment
Hide comment
@fxn

fxn Sep 11, 2015

Member

Because it is a dynamic language and subject to polymorphism, you just can't rely on empty? returning singletons, what you need to guarantee is that you return one no matter what.

That's one of the reasons I prefer to document predicates using generic boolean semantics, because then everything is more transparent all the way up.

@fxn

fxn Sep 11, 2015

Member

Because it is a dynamic language and subject to polymorphism, you just can't rely on empty? returning singletons, what you need to guarantee is that you return one no matter what.

That's one of the reasons I prefer to document predicates using generic boolean semantics, because then everything is more transparent all the way up.

This comment has been minimized.

Show comment
Hide comment
@Bartuz

Bartuz Sep 11, 2015

Contributor

Thanks! It's very clever 👍

@Bartuz

Bartuz Sep 11, 2015

Contributor

Thanks! It's very clever 👍

end
# An object is present if it's not <tt>blank?</tt>.
# An object is present if it's not blank.
#
# @return [true, false]
def present?
!blank?
end
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
# Returns the receiver if it's present otherwise returns +nil+.
# <tt>object.presence</tt> is equivalent to
#
# This is handy for any representation of objects where blank is the same
# as not present at all. For example, this simplifies a common check for
# HTTP POST/query parameters:
# 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:
# becomes
#
# region = params[:state].presence || params[:country].presence || 'US'
#
# @return [Object]
def presence
self if present?
end
@@ -43,6 +49,8 @@ class NilClass
# +nil+ is blank:
#
# nil.blank? # => true
#
# @return [true]
def blank?
true
end
@@ -52,6 +60,8 @@ class FalseClass
# +false+ is blank:
#
# false.blank? # => true
#
# @return [true]
def blank?
true
end
@@ -61,6 +71,8 @@ class TrueClass
# +true+ is not blank:
#
# true.blank? # => false
#
# @return [false]
def blank?
false
end
@@ -71,6 +83,8 @@ class Array
#
# [].blank? # => true
# [1,2,3].blank? # => false
#
# @return [true, false]
alias_method :blank?, :empty?
end
@@ -79,20 +93,28 @@ class Hash
#
# {}.blank? # => true
# { key: 'value' }.blank? # => false
#
# @return [true, false]
alias_method :blank?, :empty?
end
class String
BLANK_MATCHER = /\A[[:space:]]*\z/
BLANK_RE = /\A[[:space:]]*\z/
# A string is blank if it's empty or contains whitespaces only:
#
# ''.blank? # => true
# ' '.blank? # => true
# ' '.blank? # => true
# ' something here '.blank? # => false
# ''.blank? # => true
# ' '.blank? # => true
# "\t\n\r".blank? # => true
# ' blah '.blank? # => false
#
# Unicode whitespace is supported:
#
# "\u00a0".blank? # => true
#
# @return [true, false]
def blank?
self =~ BLANK_MATCHER
BLANK_RE === self
end
end
@@ -101,6 +123,8 @@ class Numeric #:nodoc:
#
# 1.blank? # => false
# 0.blank? # => false
#
# @return [false]
def blank?
false
end
@@ -5,24 +5,28 @@
class BlankTest < ActiveSupport::TestCase
class EmptyTrue
def empty?() true; end
def empty?
0
end
end
class EmptyFalse
def empty?() false; end
def empty?
nil
end
end
BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', [], {} ]
BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', "\u00a0", [], {} ]
NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ]
def test_blank
BLANK.each { |v| assert v.blank?, "#{v.inspect} should be blank" }
NOT.each { |v| assert !v.blank?, "#{v.inspect} should not be blank" }
BLANK.each { |v| assert_equal true, v.blank?, "#{v.inspect} should be blank" }
NOT.each { |v| assert_equal false, v.blank?, "#{v.inspect} should not be blank" }
end
def test_present
BLANK.each { |v| assert !v.present?, "#{v.inspect} should not be present" }
NOT.each { |v| assert v.present?, "#{v.inspect} should be present" }
BLANK.each { |v| assert_equal false, v.present?, "#{v.inspect} should not be present" }
NOT.each { |v| assert_equal true, v.present?, "#{v.inspect} should be present" }
end
def test_presence

0 comments on commit 126dc47

Please sign in to comment.