Class: CMDx::Validators

Inherits:
Object
  • Object
show all
Defined in:
lib/cmdx/validators.rb,
lib/cmdx/validators/format.rb,
lib/cmdx/validators/length.rb,
lib/cmdx/validators/absence.rb,
lib/cmdx/validators/numeric.rb,
lib/cmdx/validators/presence.rb,
lib/cmdx/validators/validate.rb,
lib/cmdx/validators/exclusion.rb,
lib/cmdx/validators/inclusion.rb

Overview

Registry of named validators applied to resolved input/output values. Ships with built-ins for ‘:absence`, `:exclusion`, `:format`, `:inclusion`, `:length`, `:numeric`, `:presence`. Validators return a Failure on invalid input (recorded on `task.errors`) or `nil` on success. The `:validate` key supports inline callables.

Defined Under Namespace

Modules: Absence, Exclusion, Format, Inclusion, Length, Numeric, Presence, Validate Classes: Failure

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeValidators

Returns a new instance of Validators.



17
18
19
20
21
22
23
24
25
26
27
# File 'lib/cmdx/validators.rb', line 17

def initialize
  @registry = {
    absence: Validators::Absence,
    exclusion: Validators::Exclusion,
    format: Validators::Format,
    inclusion: Validators::Inclusion,
    length: Validators::Length,
    numeric: Validators::Numeric,
    presence: Validators::Presence
  }
end

Instance Attribute Details

#registryObject (readonly)

Returns the value of attribute registry.



15
16
17
# File 'lib/cmdx/validators.rb', line 15

def registry
  @registry
end

Instance Method Details

#deregister(name) ⇒ Validators

Returns self for chaining.

Parameters:

  • name (Symbol)

Returns:



62
63
64
65
# File 'lib/cmdx/validators.rb', line 62

def deregister(name)
  registry.delete(name)
  self
end

#empty?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/cmdx/validators.rb', line 107

def empty?
  registry.empty?
end

#extract(options) ⇒ Hash{Symbol => Object}

Picks registered-validator keys out of a declaration’s options and appends ‘:validate` (inline callable(s)) when present.

Parameters:

  • options (Hash{Symbol => Object})

    declaration options

Options Hash (options):

  • :presence (Object)

    payload for the presence validator (‘call`)

  • :absence (Object)

    payload for the absence validator (‘call`)

  • :format (Object)

    payload for the format validator (‘call`)

  • :inclusion (Object)

    payload for the inclusion validator (‘call`)

  • :exclusion (Object)

    payload for the exclusion validator (‘call`)

  • :length (Object)

    payload for the length validator (‘call`)

  • :numeric (Object)

    payload for the numeric validator (‘call`)

  • :validate (Object, Array<Object>)

    inline callable(s) (‘Validators::Validate`)

Returns:

  • (Hash{Symbol => Object})

    validator rules to run



98
99
100
101
102
103
104
# File 'lib/cmdx/validators.rb', line 98

def extract(options)
  return EMPTY_HASH if options.empty?

  rules = options.slice(*registry.keys)
  rules = rules.merge(validate: options[:validate]) if options.key?(:validate)
  rules
end

#initialize_copy(source) ⇒ void

This method returns an undefined value.

Parameters:



31
32
33
# File 'lib/cmdx/validators.rb', line 31

def initialize_copy(source)
  @registry = source.registry.dup
end

#key?(name) ⇒ Boolean

Returns whether a validator is registered under ‘name`.

Parameters:

  • name (Symbol)

Returns:

  • (Boolean)

    whether a validator is registered under ‘name`



69
70
71
# File 'lib/cmdx/validators.rb', line 69

def key?(name)
  registry.key?(name)
end

#lookup(name) ⇒ #call

Parameters:

  • name (Symbol)

Returns:

  • (#call)

Raises:



76
77
78
79
80
81
82
83
# File 'lib/cmdx/validators.rb', line 76

def lookup(name)
  registry[name] || begin
    raise UnknownEntryError, <<~MSG.chomp
      unknown validator #{name.inspect}; registered: #{registry.keys.inspect}.
      See https://drexed.github.io/cmdx/inputs/validations/#built-in-validators
    MSG
  end
end

#register(name, callable = nil, &block) { ... } ⇒ Validators

Registers a named validator, overwriting any existing entry.

Parameters:

  • name (Symbol)
  • callable (#call, nil) (defaults to: nil)

    pass either this or a block

  • block (#call, nil)

    validator callable when ‘callable` is omitted

Yields:

  • validator body — ‘call(value, options = {})`

Returns:

Raises:

  • (ArgumentError)

    when both ‘callable` and a block are given, or when the resolved validator isn’t callable



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/cmdx/validators.rb', line 44

def register(name, callable = nil, &block)
  validator = callable || block

  if callable && block
    raise ArgumentError, "validator: provide either a callable or a block, not both"
  elsif !validator.respond_to?(:call)
    raise ArgumentError, <<~MSG.chomp
      validator must respond to #call (got #{validator.class}).
      See https://drexed.github.io/cmdx/inputs/validations/#declarations
    MSG
  end

  registry[name.to_sym] = validator
  self
end

#sizeInteger

Returns:

  • (Integer)


112
113
114
# File 'lib/cmdx/validators.rb', line 112

def size
  registry.size
end

#validate(task, name, value, rules) ⇒ void

This method returns an undefined value.

Runs every rule against ‘value`, recording a failure message on `task.errors` under `name` for each failure. Respects `:allow_nil` and `:if`/`:unless` per-rule.

Parameters:

  • task (Task)
  • name (Symbol)

    attribute name for error reporting

  • value (Object)

    value being validated

  • rules (Hash{Symbol => Object})

    from #extract



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/cmdx/validators.rb', line 125

def validate(task, name, value, rules)
  return if rules.empty?

  rules.each do |type, raw_options|
    if type == :validate
      Array(raw_options).each do |handler|
        result = Validators::Validate.call(task, value, handler)
        task.errors.add(name, result.message) if result.is_a?(Failure)
      end
      next
    end

    options = normalize_options(raw_options)
    next if options.nil?

    next if options[:allow_nil] && value.nil?
    next unless Util.satisfied?(options[:if], options[:unless], task, value)

    result = lookup(type).call(value, options)
    next unless result.is_a?(Failure)

    task.errors.add(name, result.message)
  end
end