class Dry::Schema::Macros::DSL

Macro specialization used within the DSL

@api public

Public Instance Methods

array(...) click to toggle source

Like `each` but sets `array?` type-check

@example a list of strings

required(:tags).array(:str?)

@example a list of hashes

required(:tags).array(:hash) do
  required(:name).filled(:string)
end

@return [Macros::Core]

@api public

# File lib/dry/schema/macros/dsl.rb, line 179
def array(...)
  append_macro(Macros::Array) do |macro|
    macro.value(...)
  end
end
custom_type?() click to toggle source

@api private

# File lib/dry/schema/macros/dsl.rb, line 202
def custom_type?
  schema_dsl.custom_type?(name)
end
each(...) click to toggle source

Specify predicates that should be applied to each element of an array

This is a simpler building block than `array` macro, use it when you want to provide `array?` type-check with other rules manually.

@example a list of strings

required(:tags).value(:array, min_size?: 2).each(:str?)

@example a list of hashes

required(:tags).value(:array, min_size?: 2).each(:hash) do
  required(:name).filled(:string)
end

@return [Macros::Core]

@api public

# File lib/dry/schema/macros/dsl.rb, line 159
def each(...)
  append_macro(Macros::Each) do |macro|
    macro.value(...)
  end
end
filled(*args, **opts, &block) click to toggle source

Prepends `:filled?` predicate

@example with a type spec

required(:name).filled(:string)

@example with a type spec and a predicate

required(:name).filled(:string, format?: /\w+/)

@return [Macros::Core]

@api public

# File lib/dry/schema/macros/dsl.rb, line 80
def filled(*args, **opts, &block)
  extract_type_spec(args) do |*predicates, type_spec:, type_rule:|
    append_macro(Macros::Filled) do |macro|
      macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
    end
  end
end
hash(...) click to toggle source

Specify a nested hash with enforced `hash?` type-check

@example

required(:tags).hash do
  required(:name).value(:string)
end

@api public

# File lib/dry/schema/macros/dsl.rb, line 135
def hash(...)
  append_macro(Macros::Hash) do |macro|
    macro.call(...)
  end
end
maybe(*args, **opts, &block) click to toggle source

Set type specification and predicates for a maybe value

@example

required(:name).maybe(:string)

@see Macros::Key#value

@return [Macros::Key]

@api public

# File lib/dry/schema/macros/dsl.rb, line 98
def maybe(*args, **opts, &block)
  extract_type_spec(args, nullable: true) do |*predicates, type_spec:, type_rule:|
    append_macro(Macros::Maybe) do |macro|
      macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
    end
  end
end
schema(...) click to toggle source

Specify a nested hash without enforced `hash?` type-check

This is a simpler building block than `hash` macro, use it when you want to provide `hash?` type-check with other rules manually.

@example

required(:tags).value(:hash, min_size?: 1).schema do
  required(:name).value(:string)
end

@return [Macros::Core]

@api public

# File lib/dry/schema/macros/dsl.rb, line 120
def schema(...)
  append_macro(Macros::Schema) do |macro|
    macro.call(...)
  end
end
type(spec) click to toggle source

Set type spec

@example

required(:name).type(:string).value(min_size?: 2)

@param [Symbol, Array, Dry::Types::Type] spec

@return [Macros::Key]

@api public

# File lib/dry/schema/macros/dsl.rb, line 196
def type(spec)
  schema_dsl.set_type(name, spec)
  self
end
value(*args, **opts, &block) click to toggle source

@overload value(*predicates, **predicate_opts)

Set predicates without and with arguments

@param [Array<Symbol>] predicates
@param [Hash] predicate_opts

@example with a predicate
  required(:name).value(:filled?)

@example with a predicate with arguments
  required(:name).value(min_size?: 2)

@example with a predicate with and without arguments
  required(:name).value(:filled?, min_size?: 2)

@example with a block
  required(:name).value { filled? & min_size?(2) }

@return [Macros::Core]

@api public

# File lib/dry/schema/macros/dsl.rb, line 61
def value(*args, **opts, &block)
  extract_type_spec(args) do |*predicates, type_spec:, type_rule:|
    append_macro(Macros::Value) do |macro|
      macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
    end
  end
end

Private Instance Methods

append_macro(macro_type) { |macro| ... } click to toggle source

@api private

# File lib/dry/schema/macros/dsl.rb, line 209
def append_macro(macro_type)
  macro = macro_type.new(schema_dsl: schema_dsl, name: name)

  yield(macro)

  if chain
    trace << macro
    self
  else
    macro
  end
end
extract_type_spec(args, nullable: false, set_type: true) { |*predicates, type_spec: nil, type_rule: type_rule| ... } click to toggle source

@api private rubocop: disable Metrics/PerceivedComplexity

# File lib/dry/schema/macros/dsl.rb, line 224
def extract_type_spec(args, nullable: false, set_type: true)
  type_spec = args[0] unless schema_or_predicate?(args[0])

  predicates = Array(type_spec ? args[1..] : args)
  type_rule = nil

  if type_spec
    resolved_type = resolve_type(type_spec, nullable)

    if type_spec.is_a?(::Array)
      type_rule = type_spec.map { |ts| new(chain: false).value(ts) }.reduce(:|)
    else
      type_predicates = predicate_inferrer[resolved_type]

      predicates.replace(type_predicates + predicates) unless type_predicates.empty?

      return self if predicates.empty?
    end
  end

  type(resolved_type) if set_type && resolved_type

  if type_rule
    yield(*predicates, type_spec: nil, type_rule: type_rule)
  else
    yield(*predicates, type_spec: type_spec, type_rule: nil)
  end
end
resolve_type(type_spec, nullable) click to toggle source

@api private

# File lib/dry/schema/macros/dsl.rb, line 255
def resolve_type(type_spec, nullable)
  resolved = schema_dsl.resolve_type(type_spec)

  if type_spec.is_a?(::Array) || !nullable || resolved.optional?
    resolved
  else
    schema_dsl.resolve_type([:nil, resolved])
  end
end
schema_or_predicate?(arg) click to toggle source

@api private

# File lib/dry/schema/macros/dsl.rb, line 266
def schema_or_predicate?(arg)
  arg.is_a?(Dry::Schema::Processor) ||
    (arg.is_a?(Symbol) &&
      arg.to_s.end_with?(QUESTION_MARK))
end