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