nil?, empty?, blank? в Rails. Яка між ними різниця?

2 хв. читання

В Ruby є відразу декілька схожих методів, що перевіряють чи має змінна значення. До того ж в Rails є декілька власних методів. В яких ситуаціях вони можуть бути корисні? Розберімо кожен з них.

nil?

  • Вбудований метод Ruby

  • Можна використовувати на будь-якій змінній.

  • Повертає true тільки для nil

nil.nil?
# => true

false.nil?
# => false

0.nil?
# => false

"".nil?
# => false

empty?

  • Вбудований метод Ruby

  • Можна використовувати на колекціях: Array, Hash, Set і т.д. Повертає true, коли в колекції немає елементів.

[].empty?
# => true

{}.empty?
# => true

Set.new.empty?
# => true
  • Але цей метод недоступний для Enumerable. Не всі ітеровані об'єкти, що повертають значення можуть знати мають вони елементи чи ні. Більше про enumerators тут.
fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

fib.empty?
# NoMethodError: undefined method `empty?' for #Enumerator:
  • Також його можна застосовувати на рядках (тому що рядок це колекція символів)
" ".empty?
# => false
  • Проблема empty? в тому, що вам потрібно знати яким класом ви оперуєте, аби не отримати помилку.

Ось тут в гру вступає Rails з розширенням ActiveSupport та методом blank?.

blank?

  • Метод з Rails

  • nil та false, очевидно, вважаються пустими.

class NilClass
  def blank?
    true
  end
end

class FalseClass
  def blank?
    true
  end
end
  • true — навпаки
class TrueClass
  #   true.blank? # => false
  def blank?
    false
  end
end
  • Array та Hash будуть blank? якщо вони empty?. Це реалізовано за допомогою alias_method. Ви можете спитати: «а як же Set?». Я відповім, але трохи згодом.
class Array
  #   [].blank?      # => true
  #   [1,2,3].blank? # => false
  alias_method :blank?, :empty?
end

class Hash
  #   {}.blank?                # => true
  #   { key: 'value' }.blank?  # => false
  alias_method :blank?, :empty?
end
  • Поведінка String#blank? трохи відрізняється від empty?, тепер якщо рядок складається з пробілів та невидимих символів, він все одно blank?.
class String
  BLANK_RE = /\\A[[:space:]]*\\z/
  #
  #   ''.blank?       # => true
  #   '   '.blank?    # => true
  #   "\	\
\
".blank? # => true
  #   ' blah '.blank? # => false
  #
  # Юнікодівські пробіли також підтримуються
  #
  #   "\\u00a0".blank? # => true
  #
  def blank?
    empty? || BLANK_RE.match?(self)
  end
end

Це досить зручно для веб-додатків, адже в більшості випадків вам потрібен рядок з текстом, а не пробілами.

  • Для решти класів цей метод ідентичний empty?. Цікаво, що там же і знаходиться документація методу.
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

Ви можете без проблем реалізувати цей метод для власного класу.

class Car
  def initialize
    @passengers = []
  end

  def enter(passenger)
    @passengers << passenger
  end

  def empty?
    @passengers.empty?
  end

  def run
    # ...
  end
end

car = Car.new
car.blank?
# => true

car.enter("robert")

car.blank?
# => false
  • Числа та час не можуть бути пустими. Чесно кажучи, я не здогадуюсь чому ці методи реалізовані окремо і чому недостатньо реалізації в Object. Можливо, для того щоб зайвий раз не перевіряти наявність empty?, якого немає.
class Numeric #:nodoc:
  #   1.blank? # => false
  #   0.blank? # => false
  def blank?
    false
  end
end

class Time #:nodoc:
  #   Time.now.blank? # => false
  def blank?
    false
  end
end

present?

  • Метод з Rails

  • present? це просто інвертований blank? і може бути використаний для чого завгодно.

class Object
  def present?
    !blank?
  end
end

presence

Цей метод теж з Rails. Іноді вам потрібно писати ось таку логіку:

params[:state] || params[:country] || 'US'

Але в більшості випадків параметри приходять з форми, тому можуть бути й пустими (або складатися з пробілів), і ви отримаєте '' замість 'US'. Тут потрібен presence. Замість

state   = params[:state]   if params[:state].present?
country = params[:country] if params[:country].present?
region  = state || country || 'US'

Ви пишете

params[:state].presence || params[:country].presence || 'US'

Його реалізація дуже проста!

class Object
  def presence
    self if present?
  end
end

Так що ж мені використовувати?!

Якщо ви працюєте з Rails, я рекомендую використовувати present? та/або blank?. Вони доступні для всіх об'єктів, працюють інтуїтивно-зрозуміло і вам більше не потрібно вручну перевіряти на nil.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація