Блог Половнёва

Value Data-объекты в Руби

Я как-то пропустил, а в Руби 3.2 завезли класс Data для создания value objects:

Recipient = Data.define(:name, :email, :role)

vasyan = Recipient.new(name: "Vasyan", email: "vasyan@stark.com", role: :cc)

vasyan.email # vasyan@stark.com
vasyan.role # :cc

# При этом
vasyan.email = "foo" # undefined method 'email='

Пример посложнее с кастомными методами:

Measure = Data.define(:amount, :unit) do
  def <=>(other)
    return unless other.is_a?(self.class) && other.unit == unit
    amount <=> other.amount
  end

  include Comparable
end

Measure[3, 'm'] < Measure[5, 'm'] #=> true
Measure[3, 'm'] < Measure[5, 'kg'] # ArgumentError

Отличается от Struct двумя ключевыми моментами. Во-первых, Data не генерирует сеттеры (attr_writer) для атрибутов. Во-вторых, Data не включает Enumerable, поэтому в нем нет each, each_pair, filter и прочих. Короче, Data — это идеальный вариант для минималистичных неизменяемых value objects.

P. S. Ещё больше постов о программировании, тестах и культуре разработки у меня в Телеграме.