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)



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/tins/unit.rb', line 128

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



167
168
169
# File 'lib/tins/unit.rb', line 167

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)


220
221
222
# File 'lib/tins/unit.rb', line 220

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



178
179
180
181
# File 'lib/tins/unit.rb', line 178

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



212
213
214
# File 'lib/tins/unit.rb', line 212

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.



185
186
187
188
# File 'lib/tins/unit.rb', line 185

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



193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/tins/unit.rb', line 193

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



152
153
154
155
156
157
158
159
160
# File 'lib/tins/unit.rb', line 152

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