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

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 (DSL)

    An instance of the parent DSL (optional)

  • :config (Config)

    A configuration object (optional)

See Also:



89
90
91
92
93
# File 'lib/dry/schema/dsl.rb', line 89

def self.new(**options, &block)
  dsl = super
  dsl.instance_eval(&block) if block
  dsl
end

Instance Method Details

#[](name) ⇒ Macros::Core

Return a macro with the provided name



121
122
123
# File 'lib/dry/schema/dsl.rb', line 121

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

#arrayDry::Types::Array::Member

A shortcut for defining an array type with a member

Examples:

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


214
215
216
# File 'lib/dry/schema/dsl.rb', line 214

def array
  -> member_type { type_registry['array'].of(resolve_type(member_type)) }
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



191
192
193
194
195
196
197
# File 'lib/dry/schema/dsl.rb', line 191

def call
  steps = [key_coercer]
  steps << filter_schema.rule_applier if filter_rules?
  steps << value_coercer << rule_applier

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

#compilerCompiler

Returns The rule compiler object.



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

option :compiler, default: -> { Compiler.new }

#configConfig

Returns Configuration object exposed via ‘#configure` method.



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

option :config, optional: true, default: proc { parent ? parent.config.dup : Config.new }

#configure(&block) ⇒ DSL

Provide customized configuration for your schema

Examples:

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

See Also:



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

def configure(&block)
  config.configure(&block)
  self
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



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

def filter_rules?
  (instance_variable_defined?('@filter_schema_dsl') && !filter_schema_dsl.macros.empty?) || parent&.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.



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

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


278
279
280
# File 'lib/dry/schema/dsl.rb', line 278

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

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

A generic method for defining keys

Raises:

  • (ArgumentError)


169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/dry/schema/dsl.rb', line 169

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_dsl: filter_schema_dsl
  )

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

#macrosArray

Returns An array with macros defined within the DSL.



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

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

#new(options = EMPTY_HASH, &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



233
234
235
# File 'lib/dry/schema/dsl.rb', line 233

def new(options = EMPTY_HASH, &block)
  self.class.new(options.merge(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

See Also:



157
158
159
# File 'lib/dry/schema/dsl.rb', line 157

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

#parentDSL

Returns An optional parent DSL object that will be used to merge keys and rules.



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

option :parent, optional: true

#processor_typeCompiler

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



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

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? }


141
142
143
# File 'lib/dry/schema/dsl.rb', line 141

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



259
260
261
262
263
264
265
266
# File 'lib/dry/schema/dsl.rb', line 259

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



245
246
247
248
249
250
# File 'lib/dry/schema/dsl.rb', line 245

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

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

#to_ruleRuleApplier

Cast this DSL into a rule object



202
203
204
# File 'lib/dry/schema/dsl.rb', line 202

def to_rule
  call.to_rule
end

#type_schemaDry::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 type schema used by the value coercer



223
224
225
226
# File 'lib/dry/schema/dsl.rb', line 223

def type_schema
  schema = type_registry['hash'].schema(types).lax
  parent ? parent.type_schema.schema(schema.to_a) : schema
end

#typesCompiler

Returns A key=>type map defined within the DSL.



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

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