class Dry::Schema::DSL
@api public
UserSchema.(name: ‘Jame’, age: 21)
end
required(:age).filled(:integer, gt: 18)
required(:name).filled
UserSchema = Dry::Schema.Params do
@example instance-based definition shortcut
user_schema.(name: ‘Jame’, age: 21)
user_schema = UserSchema.new
end
end
required(:age).filled(:integer, gt: 18)
required(:name).filled
define do
class UserSchema < Dry::Schema::Params
@example class-based definition
- ‘Schema::JSON.define` - use with sub-classes
- `Schema::Params.define` - use with sub-classes
- `Schema.JSON`
- `Schema.Params`
- `Schema.define`
The DSL is exposed by:
The schema definition DSL class
def self.new(**options, &block)
- Api: - public
Returns:
-
(DSL)-
Other tags:
- See: Processor.define -
See: Schema.JSON -
See: Schema.Params -
See: Schema.define -
Options Hash:
(**options)-
:config(Config) -- A configuration object (optional) -
:parent(DSL) -- An instance of the parent DSL (optional) -
:compiler(Compiler) -- An instance of a rule compiler (must be compatible with `Schema::Compiler`) (optional) -
:processor(Class) -- The processor type (`Params`, `JSON` or a custom sub-class)
Parameters:
-
options(Hash) --
def self.new(**options, &block) dsl = super dsl.instance_eval(&block) if block dsl end
def array
- Api: - public
Returns:
-
(Dry::Types::Array::Member)-
def array -> member_type { type_registry['array'].of(resolve_type(member_type)) } end
def call
- Api: - private
Returns:
-
(Processor)-
def call steps = [key_coercer] steps << filter_schema.rule_applier if filter_rules? steps << value_coercer << rule_applier processor_type.new { |processor| steps.each { |step| processor << step } } end
def configure(&block)
- Api: - public
Returns:
-
(DSL)-
Other tags:
- See: Config -
def configure(&block) config.configure(&block) self end
def filter_rules?
- Api: - private
def filter_rules? instance_variable_defined?('@__filter_schema__') && !filter_schema.macros.empty? end
def filter_schema
- Api: - private
Other tags:
- See: Macros::Value#filter -
def filter_schema @__filter_schema__ ||= new end
def key(name, macro:, &block)
- Api: - public
Returns:
-
(Macros::Key)-
Parameters:
-
macro(Class) -- The macro sub-class (ie `Macros::Required` or any other `Macros::Key` subclass) -
name(Symbol) -- The key name
def key(name, macro:, &block) raise ArgumentError, "Key +#{name}+ is not a symbol" unless name.is_a?(::Symbol) set_type(name, Types::Any) macro = macro.new( name: name, compiler: compiler, schema_dsl: self, filter_schema: filter_schema ) macro.value(&block) if block macros << macro macro end
def key_coercer
- Api: - private
Returns:
-
(KeyCoercer)-
def key_coercer KeyCoercer.symbolized(key_map + parent_key_map) end
def key_map(types = self.types)
- Api: - protected
def key_map(types = self.types) keys = types.map { |key, type| key_spec(key, type) } km = KeyMap.new(keys) if key_map_type km.public_send(key_map_type) else km end end
def key_map_type
- Api: - private
def key_map_type processor_type.config.key_map_type end
def key_spec(name, type)
- Api: - private
def key_spec(name, type) if type.respond_to?(:keys) { name => key_map(type.name_key_map) } elsif type.respond_to?(:member) kv = key_spec(name, type.member) kv.equal?(name) ? name : kv.flatten(1) else name end end
def new(&block)
- Api: - private
Returns:
-
(Dry::Types::Safe)-
def new(&block) self.class.new(processor_type: processor_type, &block) end
def optional(name, &block)
- Api: - public
Returns:
-
(Macros::Optional)-
Parameters:
-
name(Symbol) -- The key name
Other tags:
- See: DSL#required -
def optional(name, &block) key(name, macro: Macros::Optional, &block) end
def parent_key_map
- Api: - private
def parent_key_map parent&.key_map || EMPTY_ARRAY end
def parent_rules
- Api: - private
def parent_rules parent&.rules || EMPTY_HASH end
def required(name, &block)
- Api: - public
Returns:
-
(Macros::Required)-
Parameters:
-
name(Symbol) -- The key name
def required(name, &block) key(name, macro: Macros::Required, &block) end
def resolve_type(spec)
- Api: - private
Returns:
-
(Dry::Types::Type)-
Parameters:
-
(Symbol, Array) --, Dry::Types::Type
def resolve_type(spec) case spec when ::Dry::Types::Type then spec when ::Array then spec.map { |s| resolve_type(s) }.reduce(:|) else type_registry[spec] end end
def rule_applier
- Api: - protected
Returns:
-
(RuleApplier)-
def rule_applier RuleApplier.new(rules, config: config) end
def rules
- Api: - protected
Other tags:
- See: #rule_applier -
def rules parent_rules.merge(macros.map { |m| [m.name, m.to_rule] }.to_h.compact) end
def set_type(name, spec)
- Api: - private
Returns:
-
(Dry::Types::Safe)-
Parameters:
-
spec(Symbol, Array) -- The type spec or a type object, Dry::Types::Type -
name(Symbol) -- The key name
def set_type(name, spec) type = resolve_type(spec) meta = { required: false, maybe: type.optional? } types[name] = type.meta(meta) end
def to_rule
-
(RuleApplier)-
def to_rule call.to_rule end
def type_registry
- Api: - private
def type_registry processor_type.config.type_registry end
def type_schema
- Api: - private
Returns:
-
(Dry::Types::Safe)-
def type_schema if parent parent.type_schema.schema(types) else type_registry['hash'].schema(types).lax end end
def value_coercer
- Api: - private
Returns:
-
(ValueCoercer)-
def value_coercer ValueCoercer.new(type_schema) end