Dry::Struct does not support initialize with keyword arguments

Having the following class:

class URL < Dry::Struct
  attr_reader :description
  attr_reader :url

  def initialize(description:, url:)
    @description = description
    @url = url
  end
end

And the code:

example_url = URL.new(description: "Example website", url: "https://example.com")

Fails with:

`initialize': wrong number of arguments (given 1, expected 0; required keywords: description, url) (ArgumentError)

Is it expected? Are keyword arguments not supported when using dry-struct?

Keyword arguments work fine, you’re having trouble because you’re not using the struct interface at all.

require 'dry/types'
require 'dry/struct'
require 'uri'

Types = Dry.Types(default: :strict)

module Types
  URL = Instance(URI::Generic).constructor { URI(_1) }
end

class URL < Dry::Struct
  attribute :description, Types::String
  attribute :url, Types::URL
end

URL.new(description: "Example website", url: "https://example.com")
# => #<URL description="Example website" url=#<URI::HTTPS https://example.com>>
1 Like

The more involved answer to your question is that defining your own initialize is almost never necessary, and what you are trying to do in the example would not work.

Struct::new collects the incoming attributes and performs a schema validation against your ::schema object (try inspecting URL.schema to see it). Anything that has not been declared with attribute will be discarded before initialize is even called.

So if you actually wanted to implement initialize, first of all you need to call super. And secondly, it will receive a single hash of attributes because that is the output of the schema validation.

1 Like