Class: Dry::Schema::DSL

Inherits:
Object
  • Object
show all
Extended by:
Initializer
Defined in:
lib/dry/schema/dsl.rb

Overview

The schema definition DSL class

The DSL is exposed by:

- `Schema.define`
- `Schema.Params`
- `Schema.JSON`
- `Schema::Params.define` - use with sub-classes
- `Schema::JSON.define` - use with sub-classes

Examples:

class-based definition

class UserSchema < Dry::Schema::Params
  define do
    required(:name).filled
    required(:age).filled(:integer, gt: 18)
  end
end

user_schema = UserSchema.new
user_schema.(name: 'Jame', age: 21)

instance-based definition shortcut

UserSchema = Dry::Schema.Params do
  required(:name).filled
  required(:age).filled(:integer, gt: 18)
end

UserSchema.(name: 'Jame', age: 21)

Constant Summary collapse

Types =
Schema::Types

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new(**options, &block) ⇒ DSL

Build a new DSL object and evaluate provided block

Parameters:

  • options (Hash)

Options Hash (**options):

  • :processor (Class)

    The processor type (‘Params`, `JSON` or a custom sub-class)

  • :compiler (Compiler)

    An instance of a rule compiler (must be compatible with ‘Schema::Compiler`) (optional)

  • :parent (Array[DSL])

    One or more instances of the parent DSL (optional)

  • :config (Config)

    A configuration object (optional)

Returns:

See Also:



81
82
83
84
85
86
# File 'lib/dry/schema/dsl.rb', line 81

def self.new(**options, &block)
  dsl = super
  dsl.instance_eval(&block) if block
  dsl.instance_variable_set("@compiler", options[:compiler]) if options[:compiler]
  dsl
end

Instance Method Details

#[](name) ⇒ Macros::Core

Return a macro with the provided name

Parameters:

  • name (Symbol)

Returns:



124
125
126
# File 'lib/dry/schema/dsl.rb', line 124

def [](name)
  macros.detect { |macro| macro.name.equal?(name) }
end

#after(key, &block) ⇒ DSL

Method allows steps injection to the processor

Examples:

after(:rule_applier) do |input|
  input.compact
end

Returns:



267
268
269
270
# File 'lib/dry/schema/dsl.rb', line 267

def after(key, &block)
  steps.after(key, &block)
  self
end

#arrayDry::Types::Array::Member

A shortcut for defining an array type with a member

Examples:

required(:tags).filled(array[:string])

Returns:

  • (Dry::Types::Array::Member)


238
239
240
# File 'lib/dry/schema/dsl.rb', line 238

def array
  -> member_type { type_registry["array"].of(resolve_type(member_type)) }
end

#before(key, &block) ⇒ DSL

Method allows steps injection to the processor

Examples:

before(:rule_applier) do |input|
  input.compact
end

Returns:



252
253
254
255
# File 'lib/dry/schema/dsl.rb', line 252

def before(key, &block)
  steps.before(key, &block)
  self
end

#callProcessor, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Build a processor based on DSL’s definitions

Returns:



195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/dry/schema/dsl.rb', line 195

def call
  all_steps = parents.map(&:steps) + [steps]

  result_steps = all_steps.inject { |result, steps| result.merge(steps) }

  result_steps[:key_validator] = key_validator if config.validate_keys
  result_steps[:key_coercer] = key_coercer
  result_steps[:value_coercer] = value_coercer
  result_steps[:rule_applier] = rule_applier
  result_steps[:filter_schema] = filter_schema.rule_applier if filter_rules?

  processor_type.new(schema_dsl: self, steps: result_steps)
end

#compilerObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



108
109
110
# File 'lib/dry/schema/dsl.rb', line 108

def compiler
  @compiler ||= Compiler.new(predicates)
end

#configConfig

Returns Configuration object exposed via ‘#configure` method.

Returns:

  • (Config)

    Configuration object exposed via ‘#configure` method



55
# File 'lib/dry/schema/dsl.rb', line 55

option :config, optional: true, default: proc { default_config }

#configure(&block) ⇒ DSL

Provide customized configuration for your schema

Examples:

Dry::Schema.define do
  configure do |config|
    config.messages.backend = :i18n
  end
end

Returns:

See Also:



102
103
104
105
# File 'lib/dry/schema/dsl.rb', line 102

def configure(&block)
  config.configure(&block)
  self
end

#custom_type?(name) ⇒ Bool

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a custom type was set under provided key name

Returns:

  • (Bool)


328
329
330
# File 'lib/dry/schema/dsl.rb', line 328

def custom_type?(name)
  !types[name].meta[:default].equal?(true)
end

#filter_rules?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if any filter rules were defined

Returns:

  • (Boolean)


365
366
367
368
369
370
371
# File 'lib/dry/schema/dsl.rb', line 365

def filter_rules?
  if instance_variable_defined?("@filter_schema_dsl") && !filter_schema_dsl.macros.empty?
    return true
  end

  parents.any?(&:filter_rules?)
end

#filter_schemaObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



349
350
351
# File 'lib/dry/schema/dsl.rb', line 349

def filter_schema
  filter_schema_dsl.call
end

#filter_schema_dslObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Build an input schema DSL used by ‘filter` API

See Also:

  • Macros::Value#filter


358
359
360
# File 'lib/dry/schema/dsl.rb', line 358

def filter_schema_dsl
  @filter_schema_dsl ||= new(parent: parent_filter_schemas)
end

#key(name, macro:, &block) ⇒ Macros::Key

A generic method for defining keys

Parameters:

  • name (Symbol)

    The key name

  • macro (Class)

    The macro sub-class (ie ‘Macros::Required` or any other `Macros::Key` subclass)

Returns:

Raises:

  • (ArgumentError)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/dry/schema/dsl.rb', line 173

def key(name, macro:, &block)
  raise ArgumentError, "Key +#{name}+ is not a symbol" unless name.is_a?(::Symbol)

  set_type(name, Types::Any.meta(default: true))

  macro = macro.new(
    name: name,
    compiler: compiler,
    schema_dsl: self,
    filter_schema_dsl: filter_schema_dsl
  )

  macro.value(&block) if block
  macros << macro
  macro
end

#macrosArray

Returns An array with macros defined within the DSL.

Returns:

  • (Array)

    An array with macros defined within the DSL



46
# File 'lib/dry/schema/dsl.rb', line 46

option :macros, default: -> { EMPTY_ARRAY.dup }

#merge(other) ⇒ DSL

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Merge with another dsl

Returns:



214
215
216
217
218
219
220
221
# File 'lib/dry/schema/dsl.rb', line 214

def merge(other)
  new(
    parent: parents + other.parents,
    macros: macros + other.macros,
    types: types.merge(other.types),
    steps: steps.merge(other.steps)
  )
end

#merge_types(op_class, lhs, rhs) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



381
382
383
# File 'lib/dry/schema/dsl.rb', line 381

def merge_types(op_class, lhs, rhs)
  types_merger.(op_class, lhs, rhs)
end

#new(klass: self.class, **options, &block) ⇒ Dry::Types::Safe

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return a new DSL instance using the same processor type

Returns:

  • (Dry::Types::Safe)


304
305
306
# File 'lib/dry/schema/dsl.rb', line 304

def new(klass: self.class, **options, &block)
  klass.new(**options, processor_type: processor_type, config: config, &block)
end

#optional(name, &block) ⇒ Macros::Optional

Define an optional key

This works exactly the same as ‘required` except that if a key is not present rules will not be applied

Parameters:

  • name (Symbol)

    The key name

Returns:

See Also:



160
161
162
# File 'lib/dry/schema/dsl.rb', line 160

def optional(name, &block)
  key(name, macro: Macros::Optional, &block)
end

#parentObject

The parent (last from parents) which is used for copying non mergeable configuration

Returns:

  • DSL



52
# File 'lib/dry/schema/dsl.rb', line 52

option :parent, Types::Coercible::Array, default: -> { EMPTY_ARRAY.dup }, as: :parents

#pathPath, Array

Returns Path under which the schema is defined.

Returns:

  • (Path, Array)

    Path under which the schema is defined



61
# File 'lib/dry/schema/dsl.rb', line 61

option :path, -> *args { Path[*args] if args.any? }, default: proc { EMPTY_ARRAY }

#predicatesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



113
114
115
# File 'lib/dry/schema/dsl.rb', line 113

def predicates
  @predicates ||= config.predicates
end

#processor_typeCompiler

Returns The type of the processor (Params, JSON, or a custom sub-class).

Returns:

  • (Compiler)

    The type of the processor (Params, JSON, or a custom sub-class)



43
# File 'lib/dry/schema/dsl.rb', line 43

option :processor_type, default: -> { Processor }

#required(name, &block) ⇒ Macros::Required

Define a required key

Examples:

required(:name).filled

required(:age).value(:integer)

required(:user_limit).value(:integer, gt?: 0)

required(:tags).filled { array? | str? }

Parameters:

  • name (Symbol)

    The key name

Returns:



144
145
146
# File 'lib/dry/schema/dsl.rb', line 144

def required(name, &block)
  key(name, macro: Macros::Required, &block)
end

#resolve_type(spec) ⇒ Dry::Types::Type

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Resolve type object from the provided spec

Parameters:

  • spec (Symbol, Array<Symbol>, Dry::Types::Type)

Returns:

  • (Dry::Types::Type)


339
340
341
342
343
344
345
346
# File 'lib/dry/schema/dsl.rb', line 339

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

#set_type(name, spec) ⇒ Dry::Types::Safe

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set a type for the given key name

Parameters:

  • name (Symbol)

    The key name

  • spec (Symbol, Array<Symbol>, Dry::Types::Type)

    The type spec or a type object

Returns:

  • (Dry::Types::Safe)


316
317
318
319
320
321
# File 'lib/dry/schema/dsl.rb', line 316

def set_type(name, spec)
  type = resolve_type(spec)
  meta = {required: false, maybe: type.optional?}

  @types[name] = type.meta(meta)
end

#stepsProcessorSteps

Returns Steps for the processor.

Returns:



58
# File 'lib/dry/schema/dsl.rb', line 58

option :steps, default: proc { ProcessorSteps.new }

#strict_type_schemaDry::Types::Schema

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return type schema used when composing subschemas

Returns:

  • (Dry::Types::Schema)


295
296
297
# File 'lib/dry/schema/dsl.rb', line 295

def strict_type_schema
  type_registry["hash"].schema(types)
end

#to_ruleRuleApplier

Cast this DSL into a rule object

Returns:



226
227
228
# File 'lib/dry/schema/dsl.rb', line 226

def to_rule
  call.to_rule
end

#type_schemaDry::Types::Lax

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return type schema used by the value coercer

Returns:

  • (Dry::Types::Lax)


286
287
288
# File 'lib/dry/schema/dsl.rb', line 286

def type_schema
  strict_type_schema.lax
end

#typesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This DSL’s type map merged with any parent type maps



49
# File 'lib/dry/schema/dsl.rb', line 49

option :types, default: -> { EMPTY_HASH.dup }