Dry::Schema default hash member?

(there is no dry-schema tag)

Hi,

This is what I’m trying to do: I have a configuration structure that can come from either command-line parameters or a file. There are also defaults to this configuration, and some of the members need to be coerced into objects. I would like to make one single authoritative schema for this structure.

The structure also has a couple nested hashes in it, which may not be supplied in either configuration or command-line switches, so I want to supply defaults. My problem is I have no idea how to say “this member of the schema is a hash which itself should have $THESE members with their own defaults, and if you omit the whole thing, use $THIS for a default.” Neither the tutorial nor reference documentation are clear on how to handle this use case.

module Types
  include Dry::Types()
end

DEFAULT_HASH = Types::Hash.default({ inner: 'value'.freeze }.freeze)

HashSchema = Dry::Schema.Params do
  optional(:outer).value(DEFAULT_HASH).hash do
    optional(:inner).value(Types::String.default 'value'.freeze)
  end

  optional(:other).value(DEFAULT_HASH)
end

p HashSchema.call({})
# => #<Dry::Schema::Result{:other=>{:inner=>"value"}} errors={}>

My expectation here is that :outer should be populated in addition to :other. I have tried another configuration creating a hash type with a schema (which crashes) but let’s just consider this one for now.

There’s no support for default values. We need to figure out whether this is the right place for such a feature first.

Ah, thanks. I suppose then the thing to do would be create a default structure and then deep-merge the instance data onto it, and then validate+coerce the result?

I would experiment with a solution where you apply a schema first, then apply setting default values. This way it will be very easy to do because it’ll be safe to work with the pre-processed hash. You can use default types from dry-types for this.