Class: CMDx::Coercions

Inherits:
Object
  • Object
show all
Defined in:
lib/cmdx/coercions.rb,
lib/cmdx/coercions/date.rb,
lib/cmdx/coercions/hash.rb,
lib/cmdx/coercions/time.rb,
lib/cmdx/coercions/array.rb,
lib/cmdx/coercions/float.rb,
lib/cmdx/coercions/coerce.rb,
lib/cmdx/coercions/string.rb,
lib/cmdx/coercions/symbol.rb,
lib/cmdx/coercions/boolean.rb,
lib/cmdx/coercions/complex.rb,
lib/cmdx/coercions/integer.rb,
lib/cmdx/coercions/rational.rb,
lib/cmdx/coercions/date_time.rb,
lib/cmdx/coercions/big_decimal.rb

Overview

Registry of named type coercions applied to input/output values. Ships with built-ins for ‘:array`, `:big_decimal`, `:boolean`, `:complex`, `:date`, `:date_time`, `:float`, `:hash`, `:integer`, `:rational`, `:string`, `:symbol`, `:time`. Coercion handlers return the coerced value on success, or a Failure carrying an i18n message on failure.

Defined Under Namespace

Modules: Array, BigDecimal, Boolean, Coerce, Complex, Date, DateTime, Float, Hash, Integer, Rational, String, Symbol, Time Classes: Failure

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCoercions

Returns a new instance of Coercions.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/cmdx/coercions.rb', line 17

def initialize
  @registry = {
    array: Coercions::Array,
    big_decimal: Coercions::BigDecimal,
    boolean: Coercions::Boolean,
    complex: Coercions::Complex,
    date: Coercions::Date,
    date_time: Coercions::DateTime,
    float: Coercions::Float,
    hash: Coercions::Hash,
    integer: Coercions::Integer,
    rational: Coercions::Rational,
    string: Coercions::String,
    symbol: Coercions::Symbol,
    time: Coercions::Time
  }
end

Instance Attribute Details

#registryObject (readonly)

Returns the value of attribute registry.



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

def registry
  @registry
end

Instance Method Details

#coerce(task, name, value, rules) ⇒ Object, Failure

Applies each coercion rule to ‘value`. Returns the first successful coercion. When every rule fails and more than one was declared (and none were inline callables), the aggregated “into_any” message is recorded; otherwise the last individual failure is used.

Parameters:

  • task (Task)

    used for inline ‘Symbol`/`Proc` handlers and error recording

  • name (Symbol)

    attribute name for error reporting

  • value (Object)

    raw input before coercion rules run

  • rules (Array<Array(Object, Hash)>)

    from #extract

Returns:

  • (Object, Failure)

    coerced value, or ‘Failure` when every rule failed



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/cmdx/coercions.rb', line 128

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

  last_failure = nil
  any_inline = false

  rules.each do |handler, opts|
    result =
      if handler.is_a?(::Symbol) && registry.key?(handler)
        lookup(handler).call(value, **opts)
      else
        any_inline = true
        Coercions::Coerce.call(task, value, handler)
      end

    return result unless result.is_a?(Failure)

    last_failure = result
  end

  if rules.size > 1 && !any_inline
    type_names   = rules.map { |h, _| I18nProxy.t("cmdx.types.#{h}") }.join(", ")
    last_failure = Failure.new(I18nProxy.t("cmdx.coercions.into_any", types: type_names))
  end

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

#deregister(name) ⇒ Coercions

Returns self for chaining.

Parameters:

Returns:



66
67
68
69
# File 'lib/cmdx/coercions.rb', line 66

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

#empty?Boolean

Returns:



109
110
111
# File 'lib/cmdx/coercions.rb', line 109

def empty?
  registry.empty?
end

#extract(options) ⇒ Array<Array(Object, Hash)>

Normalizes the ‘:coerce` declaration on an input/output into a list of `[handler, opts]` pairs. Accepts a Symbol, Array, Hash, or any callable.

Parameters:

  • options (Hash{Symbol => Object})

    declaration options

Options Hash (options):

  • :coerce (Object)

    coercion rule(s): Symbol, Array, Hash, or ‘#call`-able

Returns:

  • (Array<Array(Object, Hash)>)

    pairs of handler + per-handler options

Raises:

  • (ArgumentError)

    when ‘:coerce` is an unsupported format



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/cmdx/coercions.rb', line 88

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

  raw = options[:coerce]
  return EMPTY_ARRAY if raw.nil? || raw == EMPTY_ARRAY

  case raw
  when ::Symbol
    [[raw, EMPTY_HASH]]
  when ::Array
    raw.map { |t| normalize_entry(t) }
  when ::Hash
    raw.map { |k, v| [k, v == true ? EMPTY_HASH : v] }
  else
    return [[raw, EMPTY_HASH]] if raw.respond_to?(:call)

    raise ArgumentError, "unsupported type format: #{raw.inspect}"
  end
end

#initialize_copy(source) ⇒ void

This method returns an undefined value.

Parameters:

  • source (Coercions)

    registry to duplicate



37
38
39
# File 'lib/cmdx/coercions.rb', line 37

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

#lookup(name) ⇒ #call

Returns the registered coercion.

Parameters:

Returns:

  • (#call)

    the registered coercion

Raises:

  • (ArgumentError)

    when ‘name` isn’t registered



74
75
76
77
78
# File 'lib/cmdx/coercions.rb', line 74

def lookup(name)
  registry[name] || begin
    raise ArgumentError, "unknown coercion: #{name}"
  end
end

#register(name, callable = nil, &block) {|see built-in coercion signatures — `call(value, options = {})`| ... } ⇒ Coercions

Registers a named coercion, overwriting any existing entry with the same name.

Parameters:

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

    pass either this or a block

  • block (#call, nil)

    coercion implementation when ‘callable` is omitted

Yields:

  • (see built-in coercion signatures — `call(value, options = {})`)

Returns:

Raises:

  • (ArgumentError)

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



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cmdx/coercions.rb', line 51

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

  if callable && block
    raise ArgumentError, "provide either a callable or a block, not both"
  elsif !coercion.respond_to?(:call)
    raise ArgumentError, "coercion must respond to #call"
  end

  registry[name.to_sym] = coercion
  self
end

#sizeInteger

Returns:



114
115
116
# File 'lib/cmdx/coercions.rb', line 114

def size
  registry.size
end