Module: Dentaku::NumericParser

Defined in:
lib/dentaku/numeric_parser.rb

Constant Summary collapse

NUMERIC_PATTERN =
'((?:\d+(\.\d+)?|\.\d+)(?:(e|E)(\+|-)?\d+)?)\b'.freeze
HEXADECIMAL_PATTERN =

e.g: [2, 1.2, .5, 1e10, 1.5E-10]

'(0x[0-9a-f]+)\b'.freeze

Class Method Summary collapse

Class Method Details

.ensure_numeric(value) ⇒ Object



61
62
63
64
65
# File 'lib/dentaku/numeric_parser.rb', line 61

def ensure_numeric(value)
  ensure_numeric!(value)
rescue Dentaku::ArgumentError
  nil
end

.ensure_numeric!(value) ⇒ Numeric

An Exception will be raised if a value is passed that cannot be cast to a Number.

Returns:

  • (Numeric)

    where possible it returns an Integer otherwise a BigDecimal.

Raises:



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/dentaku/numeric_parser.rb', line 49

def ensure_numeric!(value)
  return value if value.is_a?(::Numeric)

  if value.is_a?(::String)
    number = parse_string(value)
    return number if number
  end

  raise Dentaku::ArgumentError.for(:incompatible_type, actual: value, expected: Numeric),
    "'#{value || value.class}' is not coercible to numeric"
end

.match(string) ⇒ Object



9
10
11
12
# File 'lib/dentaku/numeric_parser.rb', line 9

def match(string)
  regex = %r{\A(-?(#{ NUMERIC_PATTERN }|#{ HEXADECIMAL_PATTERN }))\z}i
  string.match(regex)
end

.match_hexadecimal(string) ⇒ Object



19
20
21
22
# File 'lib/dentaku/numeric_parser.rb', line 19

def match_hexadecimal(string)
  regex = %r{\A(#{ HEXADECIMAL_PATTERN })\z}i
  string.match(regex)
end

.match_numeric(string) ⇒ Object



14
15
16
17
# File 'lib/dentaku/numeric_parser.rb', line 14

def match_numeric(string)
  regex = %r{\A(#{ NUMERIC_PATTERN })\z}i
  string.match(regex)
end

.parse_hexadecimal_string(raw) ⇒ Object



28
29
30
# File 'lib/dentaku/numeric_parser.rb', line 28

def parse_hexadecimal_string(raw)
  raw[2..-1].to_i(16)
end

.parse_numeric_string(raw) ⇒ Object



24
25
26
# File 'lib/dentaku/numeric_parser.rb', line 24

def parse_numeric_string(raw)
  raw =~ /(\.|e|E)/ ? BigDecimal(raw, Float::DIG + 1) : raw.to_i
end

.parse_string(raw) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/dentaku/numeric_parser.rb', line 32

def parse_string(raw)
  return nil unless !!match(raw)

  is_negative = raw.start_with?('-')
  number_part = is_negative ? raw[1..-1] : raw

  value = if number_part =~ /\A0x/i
    parse_hexadecimal_string(number_part)
  else
    parse_numeric_string(number_part)
  end

  is_negative ? -value : value
end