Class: Tins::Unit::UnitParser

Inherits:
StringScanner
  • Object
show all
Defined in:
lib/tins/unit.rb

Overview

A parser for unit specifications that extends StringScanner

This class is responsible for parsing strings that contain numerical values followed by unit specifications, supporting various prefix types and unit formats for flexible unit parsing.

Constant Summary collapse

NUMBER =

A regular expression matching a number.

/([+-]?
 (?:0|[1-9]\d*)
 (?:
  \.\d+(?i:e[+-]?\d+) |
 \.\d+ |
 (?i:e[+-]?\d+)
 )?
)/x

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, unit, prefixes = nil) ⇒ UnitParser

The initialize method sets up a new UnitParser instance with the given source string, unit identifier, and optional prefixes configuration.

Parameters:

  • source (String)

    the input string to parse for units

  • unit (String, Symbol)

    the unit identifier to look for in the source

  • prefixes (Object, nil) (defaults to: nil)

    optional prefixes configuration (can be array or symbol)



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/tins/unit.rb', line 112

def initialize(source, unit, prefixes = nil)
  super source
  if prefixes
    @unit_re    = unit_re(Tins::Unit.prefixes(prefixes), unit)
    @unit_lc_re = @unit_uc_re = nil
  else
    @unit_lc_re = unit_re(Tins::Unit.prefixes(:lc), unit)
    @unit_uc_re = unit_re(Tins::Unit.prefixes(:uc), unit)
    @unit_re    = nil
  end
  @number       = 1.0
end

Instance Attribute Details

#numberObject (readonly)

The number reader method returns the value of the number attribute.

Returns:

  • (Object)

    the current value of the number attribute



151
152
153
# File 'lib/tins/unit.rb', line 151

def number
  @number
end

Instance Method Details

#parseObject

The parse method is intended to be overridden by subclasses to provide specific parsing functionality.

Returns:

  • (Object)

    the parsed result

Raises:

  • (NotImplementedError)


204
205
206
# File 'lib/tins/unit.rb', line 204

def parse
  raise NotImplementedError
end

#scan(re) ⇒ String?

The scan method scans a regular expression against the current string scanner state.

This method delegates to the parent StringScanner’s scan method, but includes a guard clause to return early if the provided regular expression is nil.

Parameters:

  • re (Regexp, nil)

    the regular expression to scan for

Returns:

  • (String, nil)

    the matched string if found, or nil if no match



162
163
164
165
# File 'lib/tins/unit.rb', line 162

def scan(re)
  re.nil? and return
  super
end

#scan_char(char) ⇒ String?

The scan_char method attempts to match a character pattern against the current string scanner state.

Parameters:

  • char (String)

    the character to scan for

Returns:

  • (String, nil)

    the matched string if found, or nil if no match



196
197
198
# File 'lib/tins/unit.rb', line 196

def scan_char(char)
  scan(/#{char}/) or return
end

#scan_numberObject

The scan_number method parses a number from the current string scanner state and multiplies the internal number value by it.



169
170
171
172
# File 'lib/tins/unit.rb', line 169

def scan_number
  scan(NUMBER) or return
  @number *= BigDecimal(self[1])
end

#scan_unitObject

The scan_unit method attempts to match unit patterns against the current string and updates the internal number value by multiplying it with the corresponding prefix multiplier



177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/tins/unit.rb', line 177

def scan_unit
  case
  when scan(@unit_re)
    prefix = @unit_re.prefixes.find { |pre| pre.name == self[1] } or return
    @number *= prefix.multiplier
  when scan(@unit_lc_re)
    prefix = @unit_lc_re.prefixes.find { |pre| pre.name == self[1] } or return
    @number *= prefix.multiplier
  when scan(@unit_uc_re)
    prefix = @unit_uc_re.prefixes.find { |pre| pre.name == self[1] } or return
    @number *= prefix.multiplier
  end
end

#unit_re(prefixes, unit) ⇒ Regexp (private)

The unit_re method creates a regular expression for matching units with prefixes

This method constructs a regular expression pattern that can match unit strings including their associated prefixes, which is useful for parsing formatted unit specifications in text.

Parameters:

  • prefixes (Array)

    an array of prefix objects with name attributes

  • unit (String)

    the base unit string to match against

Returns:

  • (Regexp)

    a regular expression object that can match prefixed units



136
137
138
139
140
141
142
143
144
# File 'lib/tins/unit.rb', line 136

def unit_re(prefixes, unit)
  re = Regexp.new(
    "(#{prefixes.reverse.map { |pre| Regexp.quote(pre.name) } * ?|})(#{unit})"
  )
  re.singleton_class.class_eval do
    define_method(:prefixes) { prefixes }
  end
  re
end