ruby-units 2.3.0 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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|