Module: AnyVali::Coercion

Defined in:
lib/anyvali/parse/coercion.rb

Class Method Summary collapse

Class Method Details

.apply(value, config, kind) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/anyvali/parse/coercion.rb', line 7

def apply(value, config, kind)
  configs = config.is_a?(Array) ? config : [config]
  current = value

  configs.each do |c|
    result = apply_single(current, c, kind)
    return result unless result[:success]
    current = result[:value]
  end

  { success: true, value: current }
end

.apply_single(value, config, kind) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/anyvali/parse/coercion.rb', line 20

def apply_single(value, config, kind)
  case config
  when "string->int"
    coerce_string_to_int(value)
  when "string->number"
    coerce_string_to_number(value)
  when "string->bool"
    coerce_string_to_bool(value)
  when "trim"
    coerce_trim(value)
  when "lower"
    coerce_lower(value)
  when "upper"
    coerce_upper(value)
  else
    { success: false, value: value }
  end
end

.coerce_lower(value) ⇒ Object



88
89
90
91
# File 'lib/anyvali/parse/coercion.rb', line 88

def coerce_lower(value)
  return { success: true, value: value } unless value.is_a?(String)
  { success: true, value: value.downcase }
end

.coerce_string_to_bool(value) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/anyvali/parse/coercion.rb', line 69

def coerce_string_to_bool(value)
  return { success: true, value: value } if value.is_a?(TrueClass) || value.is_a?(FalseClass)
  return { success: false, value: value } unless value.is_a?(String)

  case value.strip.downcase
  when "true", "1"
    { success: true, value: true }
  when "false", "0"
    { success: true, value: false }
  else
    { success: false, value: value }
  end
end

.coerce_string_to_int(value) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/anyvali/parse/coercion.rb', line 39

def coerce_string_to_int(value)
  return { success: true, value: value } if value.is_a?(Integer)
  return { success: false, value: value } unless value.is_a?(String)

  stripped = value.strip
  if stripped.match?(/\A-?\d+\z/)
    { success: true, value: stripped.to_i }
  else
    { success: false, value: value }
  end
end

.coerce_string_to_number(value) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/anyvali/parse/coercion.rb', line 51

def coerce_string_to_number(value)
  return { success: true, value: value } if value.is_a?(Numeric)
  return { success: false, value: value } unless value.is_a?(String)

  stripped = value.strip
  # Spec 5.1: parse DECIMAL floating-point only. Ruby's Float() also accepts
  # digit-group underscores ("1_000.5") and hex floats ("0x1.8p3"), which
  # diverge from the JS reference and let non-decimal strings slip through.
  return { success: false, value: value } unless stripped.match?(/\A[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?\z/)

  begin
    f = Float(stripped)
    { success: true, value: f }
  rescue ArgumentError
    { success: false, value: value }
  end
end

.coerce_trim(value) ⇒ Object



83
84
85
86
# File 'lib/anyvali/parse/coercion.rb', line 83

def coerce_trim(value)
  return { success: true, value: value } unless value.is_a?(String)
  { success: true, value: value.strip }
end

.coerce_upper(value) ⇒ Object



93
94
95
96
# File 'lib/anyvali/parse/coercion.rb', line 93

def coerce_upper(value)
  return { success: true, value: value } unless value.is_a?(String)
  { success: true, value: value.upcase }
end