Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

正オブジェクトの否定の否定はTrue

数値や文字列、selfといった正オブジェクトの否定の否定はTrueなのです!
...私も最初スクリプトを読んだ時は何事かと思いましたが...
pryで挙動を見ると意味を理解していただけるかと...

self
#=> main

!self
#=> false

!!self
#=> true

_人人人人人人人_
> 突然のTrue <
 ̄Y^Y^Y^Y^Y^Y ̄

他のオブジェクトでも挙動は同じです

"hoge"
#=> "hoge"

!"hoge"
#=> false

!!"hoge"
#=> true

1
#=> 1

!1
#=> false

!!1
#=> true

逆に、負のオブジェクトは否定されるとTrue、更に否定でfalseになります。

!!false
#=> false

これを生かしたのがActiveSupportのObject#blank?です。

class Object
  # An object is blank if it's false, empty, or a whitespace string.
  # For example, '', '   ', +nil+, [], and {} are all blank.
  #
  # This simplifies
  #
  #   address.nil? || 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
##中略
end

empty?メソッドが何かを返してくれれば、それを否定(#!)します。
何か存在すればfalseを返します。
falseの否定はtrue...。
empty?が無い場合はselfを否定する事でfalseを取り出します。*1
というわけで、少なくとも存在している場合はtrueを返してくれるわけです。
ついでに、モノが存在しているか確認するpresent?は!blank?と男前な実装になっています。
...このクラス、ちょっと人の事否定しすぎじゃないですかねぇ...?

追記(2016/05/03)

Chromium上でJavaScriptも同様の挙動になる事を確認しました。

*1:実際にはパフォーマンス対策なのかNil、False、True、Numericは専用にblank?を実装し、Array、Hash、Stringはempty?メソッドエイリアスしていたりしますが...