Expose schema DSL to `value` and `maybe` with `:hash`

Closes #215
This commit is contained in:
Marc Busqué 2019-12-28 17:38:39 +01:00
parent c3fa27dcc7
commit e847e8c409
4 changed files with 77 additions and 11 deletions

View File

@ -38,20 +38,28 @@ puts errors.to_h.inspect
# }
```
It is equivalent to call `value` macro with `:hash` predicate and a block:
```ruby
schema = Dry::Schema.Params do
required(:address).value(:hash) do
# ...
end
end
```
### Nested Maybe `Hash`
If a nested hash could be `nil`, simply use `maybe` macro with a block:
```ruby
schema = Dry::Schema.Params do
required(:address).maybe do
hash do
required(:city).filled(:string, min_size?: 3)
required(:street).filled(:string)
required(:country).hash do
required(:name).filled(:string)
required(:code).filled(:string)
end
required(:address).maybe(:hash) do
required(:city).filled(:string, min_size?: 3)
required(:street).filled(:string)
required(:country).hash do
required(:name).filled(:string)
required(:code).filled(:string)
end
end
end

View File

@ -27,13 +27,18 @@ module Dry
end
trace.evaluate(*predicates, **opts)
trace.append(new(chain: false).instance_exec(&block)) if block
type_spec = opts[:type_spec]
if block && type_spec.equal?(:hash)
hash(&block)
elsif block
trace.append(new(chain: false).instance_exec(&block))
end
if trace.captures.empty?
raise ArgumentError, 'wrong number of arguments (given 0, expected at least 1)'
end
type_spec = opts[:type_spec]
each(type_spec.type.member) if type_spec.respond_to?(:member)
self

View File

@ -110,5 +110,33 @@ RSpec.describe 'Macros #maybe' do
)
end
end
end
context 'with a nested hash' do
subject(:schema) do
Dry::Schema.define do
required(:song).maybe(:hash) do
required(:title).filled
required(:author).filled
end
end
end
it 'passes when valid' do
song = { title: 'World', author: 'Joe' }
expect(schema.(song: song)).to be_success
end
it 'fails when not valid' do
song = { title: nil, author: 'Jane' }
expect(schema.(song: song).messages).to eql(
song: { title: ['must be filled'] }
)
end
it 'passes when nil' do
expect(schema.(song: nil)).to be_success
end
end
end

View File

@ -31,4 +31,29 @@ RSpec.describe Dry::Schema::Macros::Value do
expect { macro.not_here }.to raise_error(NoMethodError, /not_here/)
end
end
context 'with a nested hash' do
subject(:schema) do
Dry::Schema.define do
required(:song).value(:hash) do
required(:title).filled
required(:author).filled
end
end
end
it 'passes when valid' do
song = { title: 'World', author: 'Joe' }
expect(schema.(song: song)).to be_success
end
it 'fails when not valid' do
song = { title: nil, author: 'Jane' }
expect(schema.(song: song).messages).to eql(
song: { title: ['must be filled'] }
)
end
end
end