ruby

What is the Ruby equivalent of Python Dataclasses?


What is the counterpart for the Python Dataclass exist in Ruby?

In Python it is possible to use dataclasses to tersely define a class without explicitly defining an initialiser / __init__ method for it.

Without dataclasses this would look like this in Python (including arg typing):

class myNewDog2:
    def __init__(fur_colour: str, weight: float, is_microchipped: bool, is_asleep:bool=False):      
      self.fur_colour = fur_colour
      self.weight = weight
      self.is_microchipped = is_microchipped
      self.is_asleep = is_asleep
   
my_dog = myDog("tri-colour", 19.52, True)

But can be reduced to a form not requiring writing args out twice, using dataclasses:

from dataclasses import dataclass

@dataclass
class myDog2:
    fur_colour: str
    weight: float
    is_microchipped: bool
    is_asleep: bool = False # Optional arg / defaults to False
   
my_dog = myDog("tri-colour", 19.52, True)

This is how an equivalent class definition looks like in Ruby:

class MyDog
  def initialize(fur_colour:, weight:, is_microchipped:, is_asleep: false)
    @fur_colour = fur_colour
    @weight = weight
    @is_microchipped = is_microchipped
    @is_asleep = is_asleep
  end 
end

How would I define this class in Ruby just as tersely as in Python? Is it possible to tell Ruby to fill in the blanks on the constructor based on only on a definition of the attributes I want the class to accept and maintain?


Solution

  • A similar way in Ruby seems to be the Data class, which allows you to define simple value object like this:

    MyDog = Data.define(:fur_colour, :weight, :is_microchipped, :is_asleep)
    

    And you can create instances with positional or keyword arguments like this:

    my_dog = MyDog.new('tri-colour', 19.52, true, false) # or
    my_dog = MyDog.new(fur_colour: 'tri-colour', weight: 19.52, is_microchipped: true, is_asleep: false)
    

    Please note that the Data class doesn't support optional arguments, like the is_asleep argument in your example, yet (tested this with Ruby 3.3.1). You always need to provide the same number of arguments as defined.