ruby-units 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,6 @@ require 'date'
22
22
  #
23
23
  module RubyUnits
24
24
  class Unit < Numeric
25
- VERSION = Unit::Version::STRING
26
25
  @@definitions = {}
27
26
  @@prefix_values = {}
28
27
  @@prefix_map = {}
@@ -32,30 +31,41 @@ module RubyUnits
32
31
  @@unit_match_regex = nil
33
32
  UNITY = '<1>'.freeze
34
33
  UNITY_ARRAY = [UNITY].freeze
35
- # ideally we would like to generate this regex from the alias for a 'feet' and 'inches', but they aren't
36
- # defined at the point in the code where we need this regex.
37
- FEET_INCH_UNITS_REGEX = /(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inch(?:es)?)/
38
- FEET_INCH_REGEX = /(\d+)\s*#{FEET_INCH_UNITS_REGEX}/
39
- # ideally we would like to generate this regex from the alias for a 'pound' and 'ounce', but they aren't
40
- # defined at the point in the code where we need this regex.
41
- LBS_OZ_UNIT_REGEX = /(?:#|lbs?|pounds?|pound-mass)+[\s,]*(\d+)\s*(?:ozs?|ounces?)/
42
- LBS_OZ_REGEX = /(\d+)\s*#{LBS_OZ_UNIT_REGEX}/
43
- # ideally we would like to generate this regex from the alias for a 'stone' and 'pound', but they aren't
44
- # defined at the point in the code where we need this regex.
45
- # also note that the plural of 'stone' is still 'stone', but we accept 'stones' anyway.
46
- STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/
47
- STONE_LB_REGEX = /(\d+)\s*#{STONE_LB_UNIT_REGEX}/
48
- TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/
49
- SCI_NUMBER = /([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)/
50
- RATIONAL_NUMBER = %r{\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?}
51
- COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/
52
- NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/
53
- UNIT_STRING_REGEX = %r{#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*}
54
- TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/
55
- BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/
56
- NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/
57
- COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/
58
- RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/
34
+ # ideally we would like to generate this regex from the alias for a 'feet'
35
+ # and 'inches', but they aren't defined at the point in the code where we
36
+ # need this regex.
37
+ FEET_INCH_UNITS_REGEX = /(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inch(?:es)?)/.freeze
38
+ FEET_INCH_REGEX = /(\d+)\s*#{FEET_INCH_UNITS_REGEX}/.freeze
39
+ # ideally we would like to generate this regex from the alias for a 'pound'
40
+ # and 'ounce', but they aren't defined at the point in the code where we
41
+ # need this regex.
42
+ LBS_OZ_UNIT_REGEX = /(?:#|lbs?|pounds?|pound-mass)+[\s,]*(\d+)\s*(?:ozs?|ounces?)/.freeze
43
+ LBS_OZ_REGEX = /(\d+)\s*#{LBS_OZ_UNIT_REGEX}/.freeze
44
+ # ideally we would like to generate this regex from the alias for a 'stone'
45
+ # and 'pound', but they aren't defined at the point in the code where we
46
+ # need this regex. also note that the plural of 'stone' is still 'stone',
47
+ # but we accept 'stones' anyway.
48
+ STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/.freeze
49
+ STONE_LB_REGEX = /(\d+)\s*#{STONE_LB_UNIT_REGEX}/.freeze
50
+ # Time formats: 12:34:56,78, (hh:mm:ss,msec) etc.
51
+ TIME_REGEX = /(?<hour>\d+):(?<min>\d+):(?:(?<sec>\d+))?(?:,(?<msec>\d+))?/.freeze
52
+ # Scientific notation: 1, -1, +1, 1.2, +1.2, -1.2, 123.4E5, +123.4e5,
53
+ # -123.4E+5, -123.4e-5, etc.
54
+ SCI_NUMBER = /([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)/.freeze
55
+ # Rational number, including improper fractions: 1 2/3, -1 2/3, 5/3, etc.
56
+ RATIONAL_NUMBER = %r{\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?}.freeze
57
+ # Complex numbers: 1+2i, 1.0+2.0i, -1-1i, etc.
58
+ COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/.freeze
59
+ # Any Complex, Rational, or scientific number
60
+ ANY_NUMBER = /(#{COMPLEX_NUMBER}|#{RATIONAL_NUMBER}|#{SCI_NUMBER})/.freeze
61
+ ANY_NUMBER_REGEX = /(?:#{ANY_NUMBER})?\s?([^-\d.].*)?/.freeze
62
+ NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/.freeze
63
+ UNIT_STRING_REGEX = %r{#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*}.freeze
64
+ TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/.freeze
65
+ BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/.freeze
66
+ NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/.freeze
67
+ COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/.freeze
68
+ RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/.freeze
59
69
  KELVIN = ['<kelvin>'].freeze
60
70
  FAHRENHEIT = ['<fahrenheit>'].freeze
61
71
  RANKINE = ['<rankine>'].freeze
@@ -140,11 +150,11 @@ module RubyUnits
140
150
  @@unit_match_regex = nil
141
151
  @@prefix_regex = nil
142
152
 
143
- @@definitions.each do |_name, definition|
153
+ @@definitions.each_value do |definition|
144
154
  use_definition(definition)
145
155
  end
146
156
 
147
- RubyUnits::Unit.new(1)
157
+ new(1)
148
158
  true
149
159
  end
150
160
 
@@ -156,7 +166,7 @@ module RubyUnits
156
166
  end
157
167
 
158
168
  # return the unit definition for a unit
159
- # @param [String] unit
169
+ # @param unit_name [String]
160
170
  # @return [RubyUnits::Unit::Definition, nil]
161
171
  def self.definition(unit_name)
162
172
  unit = unit_name =~ /^<.+>$/ ? unit_name : "<#{unit_name}>"
@@ -164,12 +174,12 @@ module RubyUnits
164
174
  end
165
175
 
166
176
  # return a list of all defined units
167
- # @return [Array]
177
+ # @return [Array<RubyUnits::Units::Definition>]
168
178
  def self.definitions
169
179
  @@definitions
170
180
  end
171
181
 
172
- # @param [RubyUnits::Unit::Definition|String] unit_definition
182
+ # @param [RubyUnits::Unit::Definition, String] unit_definition
173
183
  # @param [Block] block
174
184
  # @return [RubyUnits::Unit::Definition]
175
185
  # @raise [ArgumentError] when passed a non-string if using the block form
@@ -188,33 +198,38 @@ module RubyUnits
188
198
  raise ArgumentError, 'When using the block form of RubyUnits::Unit.define, pass the name of the unit' unless unit_definition.instance_of?(String)
189
199
  unit_definition = RubyUnits::Unit::Definition.new(unit_definition, &block)
190
200
  end
191
- RubyUnits::Unit.definitions[unit_definition.name] = unit_definition
192
- RubyUnits::Unit.use_definition(unit_definition)
201
+ definitions[unit_definition.name] = unit_definition
202
+ use_definition(unit_definition)
193
203
  unit_definition
194
204
  end
195
205
 
206
+ # Get the definition for a unit and allow it to be redefined
207
+ #
196
208
  # @param [String] name Name of unit to redefine
197
- # @param [Block] block
209
+ # @param [Block] _block
198
210
  # @raise [ArgumentError] if a block is not given
199
- # @yield [RubyUnits::Unit::Definition]
211
+ # @yieldparam [RubyUnits::Unit::Definition] the definition of the unit being
212
+ # redefined
200
213
  # @return (see RubyUnits::Unit.define)
201
- # Get the definition for a unit and allow it to be redefined
202
- def self.redefine!(name)
214
+ def self.redefine!(name, &_block)
203
215
  raise ArgumentError, 'A block is required to redefine a unit' unless block_given?
216
+
204
217
  unit_definition = definition(name)
205
218
  raise(ArgumentError, "'#{name}' Unit not recognized") unless unit_definition
219
+
206
220
  yield unit_definition
207
221
  @@definitions.delete("<#{name}>")
208
222
  define(unit_definition)
209
- RubyUnits::Unit.setup
223
+ setup
210
224
  end
211
225
 
212
- # @param [String] name of unit to undefine
213
- # @return (see RubyUnits::Unit.setup)
214
226
  # Undefine a unit. Will not raise an exception for unknown units.
227
+ #
228
+ # @param unit [String] name of unit to undefine
229
+ # @return (see RubyUnits::Unit.setup)
215
230
  def self.undefine!(unit)
216
231
  @@definitions.delete("<#{unit}>")
217
- RubyUnits::Unit.setup
232
+ setup
218
233
  end
219
234
 
220
235
  # @return [Hash]
@@ -226,7 +241,7 @@ module RubyUnits
226
241
  def self.clear_cache
227
242
  @@cached_units = {}
228
243
  @@base_unit_cache = {}
229
- RubyUnits::Unit.new(1)
244
+ new(1)
230
245
  true
231
246
  end
232
247
 
@@ -241,104 +256,74 @@ module RubyUnits
241
256
  # @return [Unit]
242
257
  def self.parse(input)
243
258
  first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first
244
- second.nil? ? RubyUnits::Unit.new(first) : RubyUnits::Unit.new(first).convert_to(second)
259
+ second.nil? ? new(first) : new(first).convert_to(second)
245
260
  end
246
261
 
247
- # @param [Numeric] q quantity
248
- # @param [Array] n numerator
249
- # @param [Array] d denominator
262
+ # @param q [Numeric] quantity
263
+ # @param n [Array] numerator
264
+ # @param d [Array] denominator
250
265
  # @return [Hash]
251
266
  def self.eliminate_terms(q, n, d)
252
267
  num = n.dup
253
268
  den = d.dup
269
+ num.delete(UNITY)
270
+ den.delete(UNITY)
254
271
 
255
- num.delete_if { |v| v == UNITY }
256
- den.delete_if { |v| v == UNITY }
257
272
  combined = Hash.new(0)
258
273
 
259
- i = 0
260
- loop do
261
- break if i > num.size
262
- if @@prefix_values.key? num[i]
263
- k = [num[i], num[i + 1]]
264
- i += 2
265
- else
266
- k = num[i]
267
- i += 1
268
- end
269
- combined[k] += 1 unless k.nil? || k == UNITY
270
- end
271
-
272
- j = 0
273
- loop do
274
- break if j > den.size
275
- if @@prefix_values.key? den[j]
276
- k = [den[j], den[j + 1]]
277
- j += 2
278
- else
279
- k = den[j]
280
- j += 1
281
- end
282
- combined[k] -= 1 unless k.nil? || k == UNITY
274
+ [[num, 1], [den, -1]].each do |array, increment|
275
+ array.chunk_while { |elt_before, _| definition(elt_before).prefix? }
276
+ .to_a
277
+ .each { |unit| combined[unit] += increment }
283
278
  end
284
279
 
285
280
  num = []
286
281
  den = []
287
282
  combined.each do |key, value|
288
- if value >= 0
283
+ if value.positive?
289
284
  value.times { num << key }
290
- elsif value < 0
285
+ elsif value.negative?
291
286
  value.abs.times { den << key }
292
287
  end
293
288
  end
294
289
  num = UNITY_ARRAY if num.empty?
295
290
  den = UNITY_ARRAY if den.empty?
296
- { scalar: q, numerator: num.flatten.compact, denominator: den.flatten.compact }
291
+ { scalar: q, numerator: num.flatten, denominator: den.flatten }
292
+ end
293
+
294
+ # Creates a new unit from the current one with all common terms eliminated.
295
+ #
296
+ # @return [RubyUnits::Unit]
297
+ def eliminate_terms
298
+ self.class.new(self.class.eliminate_terms(@scalar, @numerator, @denominator))
297
299
  end
298
300
 
299
301
  # return an array of base units
300
302
  # @return [Array]
301
303
  def self.base_units
302
- @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) }
304
+ @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| new(u) }
303
305
  end
304
306
 
305
307
  # parse a string consisting of a number and a unit string
306
308
  # NOTE: This does not properly handle units formatted like '12mg/6ml'
307
309
  # @param [String] string
308
- # @return [Array] consisting of [Numeric, "unit"]
310
+ # @return [Array(Numeric, String)] consisting of [number, "unit"]
309
311
  def self.parse_into_numbers_and_units(string)
310
- # scientific notation.... 123.234E22, -123.456e-10
311
- sci = /[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*/
312
- # rational numbers.... -1/3, 1/5, 20/100, -6 1/2, -6-1/2
313
- rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?}
314
- # complex numbers... -1.2+3i, +1.2-3.3i
315
- complex = /#{sci}{2,2}i/
316
- anynumber = /(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?/
317
-
318
- num, unit = string.scan(anynumber).first
312
+ num, unit = string.scan(ANY_NUMBER_REGEX).first
319
313
 
320
314
  [
321
315
  case num
322
- when NilClass
316
+ when nil # This happens when no number is passed and we are parsing a pure unit string
323
317
  1
324
- when complex
325
- if num.respond_to?(:to_c)
326
- num.to_c
327
- else
328
- #:nocov_19:
329
- Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map(&:to_i))
330
- #:nocov_19:
331
- end
332
- when rational
333
- # if it has whitespace, it will be of the form '6 1/2'
334
- if num =~ RATIONAL_NUMBER
335
- sign = Regexp.last_match(1) == '-' ? -1 : 1
336
- n = Regexp.last_match(2).to_i
337
- f = Rational(Regexp.last_match(3).to_i, Regexp.last_match(4).to_i)
338
- sign * (n + f)
339
- else
340
- Rational(*num.split('/').map(&:to_i))
341
- end
318
+ when COMPLEX_NUMBER
319
+ num.to_c
320
+ when RATIONAL_NUMBER
321
+ # We use this method instead of relying on `to_r` because it does not
322
+ # handle improper fractions correctly.
323
+ sign = Regexp.last_match(1) == '-' ? -1 : 1
324
+ n = Regexp.last_match(2).to_i
325
+ f = Rational(Regexp.last_match(3).to_i, Regexp.last_match(4).to_i)
326
+ sign * (n + f)
342
327
  else
343
328
  num.to_f
344
329
  end,
@@ -356,7 +341,7 @@ module RubyUnits
356
341
  # return a regex used to match units
357
342
  # @return [RegExp]
358
343
  def self.unit_match_regex
359
- @@unit_match_regex ||= /(#{RubyUnits::Unit.prefix_regex})??(#{RubyUnits::Unit.unit_regex})\b/
344
+ @@unit_match_regex ||= /(#{prefix_regex})??(#{unit_regex})\b/
360
345
  end
361
346
 
362
347
  # return a regexp fragment used to match prefixes
@@ -366,11 +351,14 @@ module RubyUnits
366
351
  @@prefix_regex ||= @@prefix_map.keys.sort_by { |prefix| [prefix.length, prefix] }.reverse.join('|')
367
352
  end
368
353
 
354
+ # Generates (and memoizes) a regexp matching any of the temperature units or their aliases.
355
+ #
356
+ # @return [RegExp]
369
357
  def self.temp_regex
370
358
  @@temp_regex ||= begin
371
359
  temp_units = %w[tempK tempC tempF tempR degK degC degF degR]
372
360
  aliases = temp_units.map do |unit|
373
- d = RubyUnits::Unit.definition(unit)
361
+ d = definition(unit)
374
362
  d && d.aliases
375
363
  end.flatten.compact
376
364
  regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|')
@@ -379,6 +367,8 @@ module RubyUnits
379
367
  end
380
368
 
381
369
  # inject a definition into the internal array and set it up for use
370
+ #
371
+ # @param definition [RubyUnits::Unit::Definition]
382
372
  def self.use_definition(definition)
383
373
  @@unit_match_regex = nil # invalidate the unit match regex
384
374
  @@temp_regex = nil # invalidate the temp regex
@@ -470,6 +460,7 @@ module RubyUnits
470
460
  @signature = nil
471
461
  @output = {}
472
462
  raise ArgumentError, 'Invalid Unit Format' if options[0].nil?
463
+
473
464
  if options.size == 2
474
465
  # options[0] is the scalar
475
466
  # options[1] is a unit string
@@ -529,16 +520,17 @@ module RubyUnits
529
520
  end
530
521
  update_base_scalar
531
522
  raise ArgumentError, 'Temperatures must not be less than absolute zero' if temperature? && base_scalar < 0
523
+
532
524
  unary_unit = units || ''
533
525
  if options.first.instance_of?(String)
534
- _opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0])
526
+ _opt_scalar, opt_units = self.class.parse_into_numbers_and_units(options[0])
535
527
  unless @@cached_units.keys.include?(opt_units) ||
536
- (opt_units =~ %r{\D/[\d+\.]+}) ||
537
- (opt_units =~ %r{(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-})
528
+ (opt_units =~ %r{\D/[\d+.]+}) ||
529
+ (opt_units =~ %r{(#{self.class.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|&plusmn;|\+\/-})
538
530
  @@cached_units[opt_units] = (scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty?
539
531
  end
540
532
  end
541
- unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/)
533
+ unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{self.class.temp_regex}/)
542
534
  @@cached_units[unary_unit] = (scalar == 1 ? self : unary_unit.to_unit)
543
535
  end
544
536
  [@scalar, @numerator, @denominator, @base_scalar, @signature, @base].each(&:freeze)
@@ -566,7 +558,7 @@ module RubyUnits
566
558
  @base = (@numerator + @denominator)
567
559
  .compact
568
560
  .uniq
569
- .map { |unit| RubyUnits::Unit.definition(unit) }
561
+ .map { |unit| self.class.definition(unit) }
570
562
  .all? { |element| element.unity? || element.base? }
571
563
  @base
572
564
  end
@@ -621,7 +613,7 @@ module RubyUnits
621
613
  num = num.flatten.compact
622
614
  den = den.flatten.compact
623
615
  num = UNITY_ARRAY if num.empty?
624
- base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den))
616
+ base = self.class.new(self.class.eliminate_terms(q, num, den))
625
617
  @@base_unit_cache[units] = base
626
618
  base * @scalar
627
619
  end
@@ -842,12 +834,12 @@ module RubyUnits
842
834
  raise ArgumentError, 'Cannot add two temperatures' if [self, other].all?(&:temperature?)
843
835
  if [self, other].any?(&:temperature?)
844
836
  if temperature?
845
- RubyUnits::Unit.new(scalar: (scalar + other.convert_to(temperature_scale).scalar), numerator: @numerator, denominator: @denominator, signature: @signature)
837
+ self.class.new(scalar: (scalar + other.convert_to(temperature_scale).scalar), numerator: @numerator, denominator: @denominator, signature: @signature)
846
838
  else
847
- RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature)
839
+ self.class.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature)
848
840
  end
849
841
  else
850
- RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units)
842
+ self.class.new(scalar: (base_scalar + other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).convert_to(self)
851
843
  end
852
844
  else
853
845
  raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')"
@@ -877,13 +869,13 @@ module RubyUnits
877
869
  end
878
870
  elsif self =~ other
879
871
  if [self, other].all?(&:temperature?)
880
- RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: KELVIN, denominator: UNITY_ARRAY, signature: @signature).convert_to(temperature_scale)
872
+ self.class.new(scalar: (base_scalar - other.base_scalar), numerator: KELVIN, denominator: UNITY_ARRAY, signature: @signature).convert_to(temperature_scale)
881
873
  elsif temperature?
882
- RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: ['<tempK>'], denominator: UNITY_ARRAY, signature: @signature).convert_to(self)
874
+ self.class.new(scalar: (base_scalar - other.base_scalar), numerator: ['<tempK>'], denominator: UNITY_ARRAY, signature: @signature).convert_to(self)
883
875
  elsif other.temperature?
884
876
  raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit'
885
877
  else
886
- RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units)
878
+ self.class.new(scalar: (base_scalar - other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).convert_to(self)
887
879
  end
888
880
  else
889
881
  raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')"
@@ -904,11 +896,11 @@ module RubyUnits
904
896
  case other
905
897
  when Unit
906
898
  raise ArgumentError, 'Cannot multiply by temperatures' if [other, self].any?(&:temperature?)
907
- opts = RubyUnits::Unit.eliminate_terms(@scalar * other.scalar, @numerator + other.numerator, @denominator + other.denominator)
899
+ opts = self.class.eliminate_terms(@scalar * other.scalar, @numerator + other.numerator, @denominator + other.denominator)
908
900
  opts[:signature] = @signature + other.signature
909
- RubyUnits::Unit.new(opts)
901
+ self.class.new(opts)
910
902
  when Numeric
911
- RubyUnits::Unit.new(scalar: @scalar * other, numerator: @numerator, denominator: @denominator, signature: @signature)
903
+ self.class.new(scalar: @scalar * other, numerator: @numerator, denominator: @denominator, signature: @signature)
912
904
  else
913
905
  x, y = coerce(other)
914
906
  x * y
@@ -928,14 +920,14 @@ module RubyUnits
928
920
  raise ArgumentError, 'Cannot divide with temperatures' if [other, self].any?(&:temperature?)
929
921
  sc = Rational(@scalar, other.scalar)
930
922
  sc = sc.numerator if sc.denominator == 1
931
- opts = RubyUnits::Unit.eliminate_terms(sc, @numerator + other.denominator, @denominator + other.numerator)
923
+ opts = self.class.eliminate_terms(sc, @numerator + other.denominator, @denominator + other.numerator)
932
924
  opts[:signature] = @signature - other.signature
933
- RubyUnits::Unit.new(opts)
925
+ self.class.new(opts)
934
926
  when Numeric
935
927
  raise ZeroDivisionError if other.zero?
936
928
  sc = Rational(@scalar, other)
937
929
  sc = sc.numerator if sc.denominator == 1
938
- RubyUnits::Unit.new(scalar: sc, numerator: @numerator, denominator: @denominator, signature: @signature)
930
+ self.class.new(scalar: sc, numerator: @numerator, denominator: @denominator, signature: @signature)
939
931
  else
940
932
  x, y = coerce(other)
941
933
  y / x
@@ -1044,13 +1036,13 @@ module RubyUnits
1044
1036
  r = ((x / n) * (n - 1)).to_int
1045
1037
  r.times { den.delete_at(den.index(item)) }
1046
1038
  end
1047
- RubyUnits::Unit.new(scalar: @scalar**Rational(1, n), numerator: num, denominator: den)
1039
+ self.class.new(scalar: @scalar**Rational(1, n), numerator: num, denominator: den)
1048
1040
  end
1049
1041
 
1050
1042
  # returns inverse of Unit (1/unit)
1051
1043
  # @return [Unit]
1052
1044
  def inverse
1053
- RubyUnits::Unit.new('1') / self
1045
+ self.class.new('1') / self
1054
1046
  end
1055
1047
 
1056
1048
  # convert to a specified unit string or to the same units as another Unit
@@ -1061,13 +1053,17 @@ module RubyUnits
1061
1053
  # To convert a Unit object to match another Unit object, use:
1062
1054
  # unit1 >>= unit2
1063
1055
  #
1064
- # Special handling for temperature conversions is supported. If the Unit object is converted
1065
- # from one temperature unit to another, the proper temperature offsets will be used.
1066
- # Supports Kelvin, Celsius, Fahrenheit, and Rankine scales.
1056
+ # Special handling for temperature conversions is supported. If the Unit
1057
+ # object is converted from one temperature unit to another, the proper
1058
+ # temperature offsets will be used. Supports Kelvin, Celsius, Fahrenheit,
1059
+ # and Rankine scales.
1067
1060
  #
1068
- # @note If temperature is part of a compound unit, the temperature will be treated as a differential
1069
- # and the units will be scaled appropriately.
1070
- # @param [Object] other
1061
+ # @note If temperature is part of a compound unit, the temperature will be
1062
+ # treated as a differential and the units will be scaled appropriately.
1063
+ # @note When converting units with Integer scalars, the scalar will be
1064
+ # converted to a Rational to avoid unexpected behavior caused by Integer
1065
+ # division.
1066
+ # @param other [Unit, String]
1071
1067
  # @return [Unit]
1072
1068
  # @raise [ArgumentError] when attempting to convert a degree to a temperature
1073
1069
  # @raise [ArgumentError] when target unit is unknown
@@ -1076,14 +1072,23 @@ module RubyUnits
1076
1072
  return self if other.nil?
1077
1073
  return self if TrueClass === other
1078
1074
  return self if FalseClass === other
1079
- if (Unit === other && other.temperature?) || (String === other && other =~ /temp[CFRK]/)
1075
+
1076
+ if (other.is_a?(Unit) && other.temperature?) || (other.is_a?(String) && other =~ self.class.temp_regex)
1080
1077
  raise ArgumentError, 'Receiver is not a temperature unit' unless degree?
1078
+
1081
1079
  start_unit = units
1082
- target_unit = begin
1080
+ # @type [String]
1081
+ target_unit = case other
1082
+ when Unit
1083
1083
  other.units
1084
- rescue
1084
+ when String
1085
1085
  other
1086
+ else
1087
+ raise ArgumentError, 'Unknown target units'
1086
1088
  end
1089
+ return self if target_unit == start_unit
1090
+
1091
+ # @type [Numeric]
1087
1092
  @base_scalar ||= case @@unit_map[start_unit]
1088
1093
  when '<tempC>'
1089
1094
  @scalar + 273.15
@@ -1094,36 +1099,48 @@ module RubyUnits
1094
1099
  when '<tempR>'
1095
1100
  @scalar.to_r * Rational(5, 9)
1096
1101
  end
1102
+ # @type [Numeric]
1097
1103
  q = case @@unit_map[target_unit]
1098
1104
  when '<tempC>'
1099
- @base_scalar - 273.15r
1105
+ @base_scalar - 273.15
1100
1106
  when '<tempK>'
1101
1107
  @base_scalar
1102
1108
  when '<tempF>'
1103
- @base_scalar.to_r * Rational(9, 5) - 459.67r
1109
+ (@base_scalar.to_r * Rational(9, 5)) - 459.67r
1104
1110
  when '<tempR>'
1105
1111
  @base_scalar.to_r * Rational(9, 5)
1106
1112
  end
1107
- return RubyUnits::Unit.new("#{q} #{target_unit}")
1113
+ return self.class.new("#{q} #{target_unit}")
1108
1114
  else
1109
- case other
1110
- when Unit
1111
- return self if other.units == units
1112
- target = other
1113
- when String
1114
- target = RubyUnits::Unit.new(other)
1115
- else
1116
- raise ArgumentError, 'Unknown target units'
1117
- end
1115
+ # @type [Unit]
1116
+ target = case other
1117
+ when Unit
1118
+ other
1119
+ when String
1120
+ self.class.new(other)
1121
+ else
1122
+ raise ArgumentError, 'Unknown target units'
1123
+ end
1124
+ return self if target.units == units
1125
+
1118
1126
  raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" unless self =~ target
1119
- numerator1 = @numerator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact
1120
- denominator1 = @denominator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact
1121
- numerator2 = target.numerator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact
1122
- denominator2 = target.denominator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact
1123
-
1124
- q = @scalar * ((numerator1 + denominator2).inject(1) { |acc, elem| acc * elem }) /
1125
- ((numerator2 + denominator1).inject(1) { |acc, elem| acc * elem })
1126
- return RubyUnits::Unit.new(scalar: q, numerator: target.numerator, denominator: target.denominator, signature: target.signature)
1127
+
1128
+ numerator1 = @numerator.map { |x| @@prefix_values[x] || x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact
1129
+ denominator1 = @denominator.map { |x| @@prefix_values[x] || x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact
1130
+ numerator2 = target.numerator.map { |x| @@prefix_values[x] || x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact
1131
+ denominator2 = target.denominator.map { |x| @@prefix_values[x] || x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact
1132
+
1133
+ # If the scalar is an Integer, convert it to a Rational number so that
1134
+ # if the value is scaled during conversion, resolution is not lost due
1135
+ # to integer math
1136
+ # @type [Rational, Numeric]
1137
+ conversion_scalar = @scalar.is_a?(Integer) ? @scalar.to_r : @scalar
1138
+ q = conversion_scalar * (numerator1 + denominator2).reduce(1, :*) / (numerator2 + denominator1).reduce(1, :*)
1139
+ # Convert the scalar to an Integer if the result is equivalent to an
1140
+ # integer
1141
+
1142
+ q = q.to_i if @scalar.is_a?(Integer) && q.to_i == q
1143
+ self.class.new(scalar: q, numerator: target.numerator, denominator: target.denominator, signature: target.signature)
1127
1144
  end
1128
1145
  end
1129
1146
 
@@ -1170,52 +1187,29 @@ module RubyUnits
1170
1187
  to_s
1171
1188
  end
1172
1189
 
1173
- # returns the 'unit' part of the Unit object without the scalar
1190
+ # Returns the 'unit' part of the Unit object without the scalar
1191
+ #
1192
+ # @param with_prefix [Boolean] include prefixes in output
1174
1193
  # @return [String]
1175
1194
  def units(with_prefix: true)
1176
1195
  return '' if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY
1196
+
1177
1197
  output_numerator = ['1']
1178
1198
  output_denominator = []
1179
1199
  num = @numerator.clone.compact
1180
1200
  den = @denominator.clone.compact
1181
1201
 
1182
1202
  unless num == UNITY_ARRAY
1183
- definitions = num.map { |element| RubyUnits::Unit.definition(element) }
1203
+ definitions = num.map { |element| self.class.definition(element) }
1184
1204
  definitions.reject!(&:prefix?) unless with_prefix
1185
- # there is a bug in jruby 9.1.6.0's implementation of chunk_while
1186
- # see https://github.com/jruby/jruby/issues/4410
1187
- # TODO: fix this after jruby fixes their bug.
1188
- definitions = if definitions.respond_to?(:chunk_while) && RUBY_ENGINE != 'jruby'
1189
- definitions.chunk_while { |defn, _| defn.prefix? }.to_a
1190
- else # chunk_while is new to ruby 2.3+, so fallback to less efficient methods for older ruby
1191
- result = []
1192
- enumerator = definitions.to_enum
1193
- loop do
1194
- first = enumerator.next
1195
- result << (first.prefix? ? [first, enumerator.next] : [first])
1196
- end
1197
- result
1198
- end
1205
+ definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a
1199
1206
  output_numerator = definitions.map { |element| element.map(&:display_name).join }
1200
1207
  end
1201
1208
 
1202
1209
  unless den == UNITY_ARRAY
1203
- definitions = den.map { |element| RubyUnits::Unit.definition(element) }
1210
+ definitions = den.map { |element| self.class.definition(element) }
1204
1211
  definitions.reject!(&:prefix?) unless with_prefix
1205
- # there is a bug in jruby 9.1.6.0's implementation of chunk_while
1206
- # see https://github.com/jruby/jruby/issues/4410
1207
- # TODO: fix this after jruby fixes their bug.
1208
- definitions = if definitions.respond_to?(:chunk_while) && RUBY_ENGINE != 'jruby'
1209
- definitions.chunk_while { |defn, _| defn.prefix? }.to_a
1210
- else # chunk_while is new to ruby 2.3+, so fallback to less efficient methods for older ruby
1211
- result = []
1212
- enumerator = definitions.to_enum
1213
- loop do
1214
- first = enumerator.next
1215
- result << (first.prefix? ? [first, enumerator.next] : [first])
1216
- end
1217
- result
1218
- end
1212
+ definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a
1219
1213
  output_denominator = definitions.map { |element| element.map(&:display_name).join }
1220
1214
  end
1221
1215
 
@@ -1227,7 +1221,7 @@ module RubyUnits
1227
1221
  .uniq
1228
1222
  .map { |x| [x, output_denominator.count(x)] }
1229
1223
  .map { |element, power| (element.to_s.strip + (power > 1 ? "^#{power}" : '')) }
1230
- "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip
1224
+ "#{on.join('*')}#{od.empty? ? '' : "/#{od.join('*')}"}".strip
1231
1225
  end
1232
1226
 
1233
1227
  # negates the scalar of the Unit
@@ -1241,32 +1235,45 @@ module RubyUnits
1241
1235
  # @return [Numeric,Unit]
1242
1236
  def abs
1243
1237
  return @scalar.abs if unitless?
1244
- RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator)
1238
+ self.class.new(@scalar.abs, @numerator, @denominator)
1245
1239
  end
1246
1240
 
1247
1241
  # ceil of a unit
1248
1242
  # @return [Numeric,Unit]
1249
- def ceil
1250
- return @scalar.ceil if unitless?
1251
- RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator)
1243
+ def ceil(*args)
1244
+ return @scalar.ceil(*args) if unitless?
1245
+
1246
+ self.class.new(@scalar.ceil(*args), @numerator, @denominator)
1252
1247
  end
1253
1248
 
1254
1249
  # @return [Numeric,Unit]
1255
- def floor
1256
- return @scalar.floor if unitless?
1257
- RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator)
1250
+ def floor(*args)
1251
+ return @scalar.floor(*args) if unitless?
1252
+
1253
+ self.class.new(@scalar.floor(*args), @numerator, @denominator)
1258
1254
  end
1259
1255
 
1256
+ # Round the unit according to the rules of the scalar's class. Call this
1257
+ # with the arguments appropriate for the scalar's class (e.g., Integer,
1258
+ # Rational, etc..). Because unit conversions can often result in Rational
1259
+ # scalars (to preserve precision), it may be advisable to use +to_s+ to
1260
+ # format output instead of using +round+.
1261
+ # @example
1262
+ # RubyUnits::Unit.new('21870 mm/min').convert_to('m/min').round(1) #=> 2187/100 m/min
1263
+ # RubyUnits::Unit.new('21870 mm/min').convert_to('m/min').to_s('%0.1f') #=> 21.9 m/min
1264
+ #
1260
1265
  # @return [Numeric,Unit]
1261
- def round(ndigits = 0)
1262
- return @scalar.round(ndigits) if unitless?
1263
- RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator)
1266
+ def round(*args, **kwargs)
1267
+ return @scalar.round(*args, **kwargs) if unitless?
1268
+
1269
+ self.class.new(@scalar.round(*args, **kwargs), @numerator, @denominator)
1264
1270
  end
1265
1271
 
1266
1272
  # @return [Numeric, Unit]
1267
- def truncate
1268
- return @scalar.truncate if unitless?
1269
- RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator)
1273
+ def truncate(*args)
1274
+ return @scalar.truncate(*args) if unitless?
1275
+
1276
+ self.class.new(@scalar.truncate(*args), @numerator, @denominator)
1270
1277
  end
1271
1278
 
1272
1279
  # returns next unit in a range. '1 mm'.to_unit.succ #=> '2 mm'.to_unit
@@ -1275,7 +1282,7 @@ module RubyUnits
1275
1282
  # @raise [ArgumentError] when scalar is not equal to an integer
1276
1283
  def succ
1277
1284
  raise ArgumentError, 'Non Integer Scalar' unless @scalar == @scalar.to_i
1278
- RubyUnits::Unit.new(@scalar.to_i.succ, @numerator, @denominator)
1285
+ self.class.new(@scalar.to_i.succ, @numerator, @denominator)
1279
1286
  end
1280
1287
 
1281
1288
  alias next succ
@@ -1286,7 +1293,7 @@ module RubyUnits
1286
1293
  # @raise [ArgumentError] when scalar is not equal to an integer
1287
1294
  def pred
1288
1295
  raise ArgumentError, 'Non Integer Scalar' unless @scalar == @scalar.to_i
1289
- RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator)
1296
+ self.class.new(@scalar.to_i.pred, @numerator, @denominator)
1290
1297
  end
1291
1298
 
1292
1299
  # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch.
@@ -1389,7 +1396,7 @@ module RubyUnits
1389
1396
 
1390
1397
  # automatically coerce objects to units when possible
1391
1398
  # if an object defines a 'to_unit' method, it will be coerced using that method
1392
- # @param [Object, #to_unit]
1399
+ # @param other [Object, #to_unit]
1393
1400
  # @return [Array]
1394
1401
  def coerce(other)
1395
1402
  return [other.to_unit, self] if other.respond_to? :to_unit
@@ -1397,7 +1404,7 @@ module RubyUnits
1397
1404
  when Unit
1398
1405
  [other, self]
1399
1406
  else
1400
- [RubyUnits::Unit.new(other), self]
1407
+ [self.class.new(other), self]
1401
1408
  end
1402
1409
  end
1403
1410
 
@@ -1409,7 +1416,7 @@ module RubyUnits
1409
1416
  else
1410
1417
  @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3))
1411
1418
  end
1412
- to(RubyUnits::Unit.new(@@prefix_map.key(best_prefix) + units(with_prefix: false)))
1419
+ to(self.class.new(@@prefix_map.key(best_prefix) + units(with_prefix: false)))
1413
1420
  end
1414
1421
 
1415
1422
  # override hash method so objects with same values are considered equal
@@ -1449,11 +1456,11 @@ module RubyUnits
1449
1456
  vector = Array.new(SIGNATURE_VECTOR.size, 0)
1450
1457
  # it's possible to have a kind that misses the array... kinds like :counting
1451
1458
  # are more like prefixes, so don't use them to calculate the vector
1452
- @numerator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition|
1459
+ @numerator.map { |element| self.class.definition(element) }.each do |definition|
1453
1460
  index = SIGNATURE_VECTOR.index(definition.kind)
1454
1461
  vector[index] += 1 if index
1455
1462
  end
1456
- @denominator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition|
1463
+ @denominator.map { |element| self.class.definition(element) }.each do |definition|
1457
1464
  index = SIGNATURE_VECTOR.index(definition.kind)
1458
1465
  vector[index] -= 1 if index
1459
1466
  end
@@ -1507,7 +1514,7 @@ module RubyUnits
1507
1514
 
1508
1515
  if defined?(Complex) && unit_string =~ COMPLEX_NUMBER
1509
1516
  real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0]
1510
- result = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f)
1517
+ result = self.class.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f)
1511
1518
  copy(result)
1512
1519
  return
1513
1520
  end
@@ -1516,7 +1523,7 @@ module RubyUnits
1516
1523
  sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0]
1517
1524
  sign = sign == '-' ? -1 : 1
1518
1525
  rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i))
1519
- result = RubyUnits::Unit.new(unit_s || '1') * rational
1526
+ result = self.class.new(unit_s || '1') * rational
1520
1527
  copy(result)
1521
1528
  return
1522
1529
  end
@@ -1542,13 +1549,14 @@ module RubyUnits
1542
1549
  # ... and then strip the remaining brackets for x*y*z
1543
1550
  unit_string.gsub!(/[<>]/, '')
1544
1551
 
1545
- if unit_string =~ /:/
1552
+ if unit_string =~ TIME_REGEX
1546
1553
  hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0]
1547
- raise ArgumentError, 'Invalid Duration' if [hours, minutes, seconds, microseconds].all?(&:nil?)
1548
- result = RubyUnits::Unit.new("#{hours || 0} h") +
1549
- RubyUnits::Unit.new("#{minutes || 0} minutes") +
1550
- RubyUnits::Unit.new("#{seconds || 0} seconds") +
1551
- RubyUnits::Unit.new("#{microseconds || 0} usec")
1554
+ raise ArgumentError,'Invalid Duration' if [hours, minutes, seconds, microseconds].all?(&:nil?)
1555
+
1556
+ result = self.class.new("#{hours || 0} h") +
1557
+ self.class.new("#{minutes || 0} minutes") +
1558
+ self.class.new("#{seconds || 0} seconds") +
1559
+ self.class.new("#{microseconds || 0} usec")
1552
1560
  copy(result)
1553
1561
  return
1554
1562
  end
@@ -1557,7 +1565,7 @@ module RubyUnits
1557
1565
  # feet -- 6'5"
1558
1566
  feet, inches = unit_string.scan(FEET_INCH_REGEX)[0]
1559
1567
  if feet && inches
1560
- result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches")
1568
+ result = self.class.new("#{feet} ft") + self.class.new("#{inches} inches")
1561
1569
  copy(result)
1562
1570
  return
1563
1571
  end
@@ -1565,7 +1573,7 @@ module RubyUnits
1565
1573
  # weight -- 8 lbs 12 oz
1566
1574
  pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0]
1567
1575
  if pounds && oz
1568
- result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz")
1576
+ result = self.class.new("#{pounds} lbs") + self.class.new("#{oz} oz")
1569
1577
  copy(result)
1570
1578
  return
1571
1579
  end
@@ -1573,7 +1581,7 @@ module RubyUnits
1573
1581
  # stone -- 3 stone 5, 2 stone, 14 stone 3 pounds, etc.
1574
1582
  stone, pounds = unit_string.scan(STONE_LB_REGEX)[0]
1575
1583
  if stone && pounds
1576
- result = RubyUnits::Unit.new("#{stone} stone") + RubyUnits::Unit.new("#{pounds} lbs")
1584
+ result = self.class.new("#{stone} stone") + self.class.new("#{pounds} lbs")
1577
1585
  copy(result)
1578
1586
  return
1579
1587
  end
@@ -1581,6 +1589,7 @@ module RubyUnits
1581
1589
  # more than one per. I.e., "1 m/s/s"
1582
1590
  raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1
1583
1591
  raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string =~ /\s[02-9]/
1592
+
1584
1593
  @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] # parse the string into parts
1585
1594
  top.scan(TOP_REGEX).each do |item|
1586
1595
  n = item[1].to_i
@@ -1613,12 +1622,12 @@ module RubyUnits
1613
1622
 
1614
1623
  @numerator ||= UNITY_ARRAY
1615
1624
  @denominator ||= UNITY_ARRAY
1616
- @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if top
1617
- @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if bottom
1625
+ @numerator = top.scan(self.class.unit_match_regex).delete_if(&:empty?).compact if top
1626
+ @denominator = bottom.scan(self.class.unit_match_regex).delete_if(&:empty?).compact if bottom
1618
1627
 
1619
1628
  # eliminate all known terms from this string. This is a quick check to see if the passed unit
1620
1629
  # contains terms that are not defined.
1621
- used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(%r{[\d\*, "'_^\/\$]}, '')
1630
+ used = "#{top} #{bottom}".to_s.gsub(self.class.unit_match_regex, '').gsub(%r{[\d\*, "'_^\/\$]}, '')
1622
1631
  raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty?
1623
1632
 
1624
1633
  @numerator = @numerator.map do |item|