lib/ruby_units/ruby-units.rb in ruby-units-1.1.5 vs lib/ruby_units/ruby-units.rb in ruby-units-1.2.0.a
- old
+ new
@@ -1,13 +1,13 @@
-require 'mathn'
-require 'rational'
require 'date'
-require 'parsedate'
-
+if RUBY_VERSION < "1.9"
+ require 'parsedate'
+ require 'rational'
+end
# = Ruby Units
#
-# Copyright 2006 by Kevin C. Olbrich, Ph.D.
+# Copyright 2006-2010 by Kevin C. Olbrich, Ph.D.
#
# See http://rubyforge.org/ruby-units/
#
# http://www.sciwerks.org
#
@@ -38,11 +38,11 @@
# }
# end
# Unit.setup
class Unit < Numeric
# pre-generate hashes from unit definitions for performance.
- VERSION = '1.1.5'
+ VERSION = '1.2.0.a'
@@USER_DEFINITIONS = {}
@@PREFIX_VALUES = {}
@@PREFIX_MAP = {}
@@UNIT_MAP = {}
@@UNIT_VALUES = {}
@@ -131,16 +131,15 @@
end
end
@@OUTPUT_MAP[key]=value[0][0]
end
@@PREFIX_REGEX = @@PREFIX_MAP.keys.sort_by {|prefix| [prefix.length, prefix]}.reverse.join('|')
- @@UNIT_REGEX = @@UNIT_MAP.keys.sort_by {|unit| [unit.length, unit]}.reverse.join('|')
+ @@UNIT_REGEX = @@UNIT_MAP.keys.sort_by {|unit_name| [unit_name.length, unit]}.reverse.join('|')
@@UNIT_MATCH_REGEX = /(#{@@PREFIX_REGEX})*?(#{@@UNIT_REGEX})\b/
Unit.new(1)
end
-
include Comparable
attr_accessor :scalar, :numerator, :denominator, :signature, :base_scalar, :base_numerator, :base_denominator, :output, :unit_name
def to_yaml_properties
%w{@scalar @numerator @denominator @signature @base_scalar}
@@ -162,15 +161,17 @@
@unit_name = from.unit_name rescue nil
end
# basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string
# before YAML'izing it.
- def to_yaml( opts = {} )
- YAML::quick_emit( object_id, opts ) do |out|
- out.map( taguri, to_yaml_style ) do |map|
- for m in to_yaml_properties do
- map.add( m[1..-1], instance_variable_get( m ) )
+ if RUBY_VERSION < "1.9"
+ def to_yaml( opts = {} )
+ YAML::quick_emit( object_id, opts ) do |out|
+ out.map( taguri, to_yaml_style ) do |map|
+ for m in to_yaml_properties do
+ map.add( m[1..-1], instance_variable_get( m ) )
+ end
end
end
end
end
@@ -200,42 +201,44 @@
initialize("#{options[0]} #{(options[1].units rescue options[1])}")
end
return
end
if options.size == 3
+ options[1] = options[1].join if options[1].kind_of?(Array)
+ options[2] = options[2].join if options[2].kind_of?(Array)
begin
cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0]
copy(cached)
rescue
initialize("#{options[0]} #{options[1]}/#{options[2]}")
end
return
end
case options[0]
- when Hash:
+ when Hash
@scalar = options[0][:scalar] || 1
@numerator = options[0][:numerator] || UNITY_ARRAY
@denominator = options[0][:denominator] || UNITY_ARRAY
@signature = options[0][:signature]
- when Array:
+ when Array
initialize(*options[0])
return
- when Numeric:
+ when Numeric
@scalar = options[0]
@numerator = @denominator = UNITY_ARRAY
- when Time:
+ when Time
@scalar = options[0].to_f
@numerator = ['<second>']
@denominator = UNITY_ARRAY
- when DateTime:
+ when DateTime
@scalar = options[0].ajd
@numerator = ['<day>']
@denominator = UNITY_ARRAY
- when "":
+ when ""
raise ArgumentError, "No Unit Specified"
- when String:
+ when String
parse(options[0])
else
raise ArgumentError, "Invalid Unit Format"
end
self.update_base_scalar
@@ -282,11 +285,11 @@
alias :unit :to_unit
# Returns 'true' if the Unit is represented in base units
def is_base?
return @is_base if defined? @is_base
- return @is_base=true if @signature == 400 && self.numerator.size == 1 && self.denominator == UNITY_ARRAY && self.units =~ /(deg|temp)K/
+ return @is_base=true if self.degree? && self.numerator.size == 1 && self.denominator == UNITY_ARRAY && self.units =~ /(deg|temp)K/
n = @numerator + @denominator
for x in n.compact do
return @is_base=false unless x == UNITY || (@@BASE_UNITS.include?((x)))
end
return @is_base = true
@@ -294,44 +297,46 @@
# convert to base SI units
# results of the conversion are cached so subsequent calls to this will be fast
def to_base
return self if self.is_base?
- if self.units =~ /\A(deg|temp)(C|F|K|C)\Z/
+ if self.units =~ /\A(deg|temp)(C|F|K|C)\Z/
@signature = 400
base = case self.units
- when /temp/ : self.to('tempK')
- when /deg/ : self.to('degK')
+ when /temp/
+ self.to('tempK')
+ when /deg/
+ self.to('degK')
end
return base
end
cached = ((@@base_unit_cache[self.units] * self.scalar) rescue nil)
return cached if cached
-
+
num = []
den = []
q = 1
for unit in @numerator.compact do
- if @@PREFIX_VALUES[unit]
- q *= @@PREFIX_VALUES[unit]
- else
- q *= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit]
- num << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator]
- den << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator]
- end
+ if @@PREFIX_VALUES[unit]
+ q *= @@PREFIX_VALUES[unit]
+ else
+ q *= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit]
+ num << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator]
+ den << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator]
+ end
end
for unit in @denominator.compact do
- if @@PREFIX_VALUES[unit]
- q /= @@PREFIX_VALUES[unit]
- else
- q /= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit]
- den << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator]
- num << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator]
- end
+ if @@PREFIX_VALUES[unit]
+ q /= @@PREFIX_VALUES[unit]
+ else
+ q /= @@UNIT_VALUES[unit][:scalar] if @@UNIT_VALUES[unit]
+ den << @@UNIT_VALUES[unit][:numerator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:numerator]
+ num << @@UNIT_VALUES[unit][:denominator] if @@UNIT_VALUES[unit] && @@UNIT_VALUES[unit][:denominator]
+ end
end
-
+
num = num.flatten.compact
den = den.flatten.compact
num = UNITY_ARRAY if num.empty?
base= Unit.new(Unit.eliminate_terms(q,num,den))
@@base_unit_cache[self.units]=base
@@ -354,19 +359,19 @@
out = @output[target_units]
if out
return out
else
case target_units
- when :ft :
+ when :ft
inches = self.to("in").scalar.to_int
out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\""
- when :lbs :
+ when :lbs
ounces = self.to("oz").scalar.to_int
out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz"
when String
out = case target_units
- when /(%[-+\.\w\d#]+)\s*(.+)*/ #format string like '%0.2f in'
+ when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in'
begin
if $2 #unit specified, need to convert
self.to($2).to_s($1)
else
"#{$1 % @scalar} #{$2 || self.units}".strip
@@ -379,11 +384,11 @@
else
raise "unhandled case"
end
else
out = case @scalar
- when Rational :
+ when Rational
"#{@scalar} #{self.units}"
else
"#{'%g' % @scalar} #{self.units}"
end.strip
end
@@ -398,13 +403,20 @@
self.to_s
end
# true if unit is a 'temperature', false if a 'degree' or anything else
def is_temperature?
- return true if self.signature == 400 && self.units =~ /temp/
+ self.is_degree? && self.units =~ /temp/
end
+ alias :temperature? :is_temperature?
+ # true if a degree unit or equivalent.
+ def is_degree?
+ self.kind == :temperature
+ end
+ alias :degree? :is_degree?
+
# returns the 'degree' unit associated with a temperature unit
# '100 tempC'.unit.temperature_scale #=> 'degC'
def temperature_scale
return nil unless self.is_temperature?
self.units =~ /temp(C|F|R|K)/
@@ -418,18 +430,19 @@
end
# Compare two Unit objects. Throws an exception if they are not of compatible types.
# Comparisons are done based on the value of the unit in base SI units.
def <=>(other)
- case other
- when 0: self.base_scalar <=> 0
- when Unit:
+ case
+ when other.zero? && !self.is_temperature?
+ return self.base_scalar <=> 0
+ when Unit === other
raise ArgumentError, "Incompatible Units" unless self =~ other
- self.base_scalar <=> other.base_scalar
+ return self.base_scalar <=> other.base_scalar
else
x,y = coerce(other)
- x <=> y
+ return x <=> y
end
end
# check to see if units are compatible, but not the scalar part
# this check is done by comparing signatures for performance reasons
@@ -439,11 +452,12 @@
# if you want to do a regexp on the unit string do this ...
# unit.units =~ /regexp/
def =~(other)
return true if self == 0 || other == 0
case other
- when Unit : self.signature == other.signature
+ when Unit
+ self.signature == other.signature
else
x,y = coerce(other)
x =~ y
end
end
@@ -455,11 +469,12 @@
#
# Unit("100 cm") === Unit("100 cm") # => true
# Unit("100 cm") === Unit("1 m") # => false
def ===(other)
case other
- when Unit: (self.scalar == other.scalar) && (self.units == other.units)
+ when Unit
+ (self.scalar == other.scalar) && (self.units == other.units)
else
x,y = coerce(other)
x === y
end
end
@@ -471,48 +486,49 @@
# throws an exception if the units are not compatible.
# It is possible to add Time objects to units of time
def +(other)
if Unit === other
case
- when self.zero? : other.dup
- when self =~ other :
+ when self.zero?
+ other.dup
+ when self =~ other
raise ArgumentError, "Cannot add two temperatures" if ([self, other].all? {|x| x.is_temperature?})
if [self, other].any? {|x| x.is_temperature?}
- case self.is_temperature?
- when true:
+ if self.is_temperature?
Unit.new(:scalar => (self.scalar + other.to(self.temperature_scale).scalar), :numerator => @numerator, :denominator=>@denominator, :signature => @signature)
else
Unit.new(:scalar => (other.scalar + self.to(other.temperature_scale).scalar), :numerator => other.numerator, :denominator=>other.denominator, :signature => other.signature)
end
else
@q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.to_base.scalar))
Unit.new(:scalar=>(self.base_scalar + other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature)
end
else
- raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')"
+ raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')"
end
elsif Time === other
other + self
else
- x,y = coerce(other)
- y + x
+ x,y = coerce(other)
+ y + x
end
end
# Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately
# throws an exception if the units are not compatible.
def -(other)
if Unit === other
- case
- when self.zero? : -other.dup
- when self =~ other :
+ case
+ when self.zero?
+ -other.dup
+ when self =~ other
case
- when [self, other].all? {|x| x.is_temperature?} :
+ when [self, other].all? {|x| x.is_temperature?}
Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => KELVIN, :denominator => UNITY_ARRAY, :signature => @signature).to(self.temperature_scale)
- when self.is_temperature? :
+ when self.is_temperature?
Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => ['<temp-K>'], :denominator => UNITY_ARRAY, :signature => @signature).to(self)
- when other.is_temperature? :
+ when other.is_temperature?
raise ArgumentError, "Cannot subtract a temperature from a differential degree unit"
else
@q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.unit.scalar/self.units.unit.to_base.scalar))
Unit.new(:scalar=>(self.base_scalar - other.base_scalar)*@q, :numerator=>@numerator, :denominator=>@denominator, :signature=>@signature)
end
@@ -559,10 +575,22 @@
else
x,y = coerce(other)
y / x
end
end
+
+ # divide two units and return quotient and remainder
+ # when both units are in the same units we just use divmod on the raw scalars
+ # otherwise we use the scalar of the base unit which will be a float
+ def divmod(other)
+ raise ArgumentError, "Incompatible Units" unless self =~ other
+ if self.units == other.units
+ return self.scalar.divmod(other.scalar)
+ else
+ return self.to_base.scalar.divmod(other.to_base.scalar)
+ end
+ end
# Exponentiate. Only takes integer powers.
# Note that anything raised to the power of 0 results in a Unit object with a scalar of 1, and no units.
# Throws an exception if exponent is not an integer.
# Ideally this routine should accept a float for the exponent
@@ -576,15 +604,15 @@
return Unit("1") if other.zero?
return self if other == 1
return self.inverse if other == -1
end
case other
- when Rational:
+ when Rational
self.power(other.numerator).root(other.denominator)
- when Integer:
+ when Integer
self.power(other)
- when Float:
+ when Float
return self**(other.to_i) if other == other.to_i
valid = (1..9).map {|x| 1/x}
raise ArgumentError, "Not a n-th root (1..9), use 1/n" unless valid.include? other.abs
self.root((1/other).to_int)
else
@@ -622,17 +650,17 @@
den = @denominator.dup
for item in @numerator.uniq do
x = num.find_all {|i| i==item}.size
r = ((x/n)*(n-1)).to_int
- r.times {|x| num.delete_at(num.index(item))}
+ r.times {|y| num.delete_at(num.index(item))}
end
for item in @denominator.uniq do
x = den.find_all {|i| i==item}.size
r = ((x/n)*(n-1)).to_int
- r.times {|x| den.delete_at(den.index(item))}
+ r.times {|y| den.delete_at(den.index(item))}
end
q = @scalar < 0 ? (-1)**Rational(1,n) * (@scalar.abs)**Rational(1,n) : @scalar**Rational(1,n)
Unit.new(:scalar=>q,:numerator=>num,:denominator=>den)
end
@@ -650,47 +678,56 @@
# unit1 >>= unit2
# Throws an exception if the requested target units are incompatible with current Unit.
#
# Special handling for temperature conversions is supported. If the Unit object is converted
# from one temperature unit to another, the proper temperature offsets will be used.
- # Supports Kelvin, Celcius, fahrenheit, and Rankine scales.
+ # Supports Kelvin, Celsius, fahrenheit, and Rankine scales.
#
# Note that if temperature is part of a compound unit, the temperature will be treated as a differential
# and the units will be scaled appropriately.
def to(other)
return self if other.nil?
return self if TrueClass === other
return self if FalseClass === other
if (Unit === other && other.is_temperature?) || (String === other && other =~ /temp(K|C|R|F)/)
- raise ArgumentError, "Receiver is not a temperature unit" unless self.signature == 400
+ raise ArgumentError, "Receiver is not a temperature unit" unless self.degree?
start_unit = self.units
target_unit = other.units rescue other
unless @base_scalar
@base_scalar = case start_unit
- when 'tempC' : @scalar + 273.15
- when 'tempK' : @scalar
- when 'tempF' : (@scalar+459.67)*(5.0/9.0)
- when 'tempR' : @scalar*(5.0/9.0)
+ when 'tempC'
+ @scalar + 273.15
+ when 'tempK'
+ @scalar
+ when 'tempF'
+ (@scalar+459.67)*(5.0/9.0)
+ when 'tempR'
+ @scalar*(5.0/9.0)
end
end
q= case target_unit
- when 'tempC' : @base_scalar - 273.15
- when 'tempK' : @base_scalar
- when 'tempF' : @base_scalar * (9.0/5.0) - 459.67
- when 'tempR' : @base_scalar * (9.0/5.0)
- end
-
+ when 'tempC'
+ @base_scalar - 273.15
+ when 'tempK'
+ @base_scalar
+ when 'tempF'
+ @base_scalar * (9.0/5.0) - 459.67
+ when 'tempR'
+ @base_scalar * (9.0/5.0)
+ end
+
Unit.new("#{q} #{target_unit}")
else
- case other
- when Unit:
- return self if other.units == self.units
- target = other
- when String: target = Unit.new(other)
- else
- raise ArgumentError, "Unknown target units"
- end
+ case other
+ when Unit
+ return self if other.units == self.units
+ target = other
+ when String
+ target = Unit.new(other)
+ else
+ raise ArgumentError, "Unknown target units"
+ end
raise ArgumentError, "Incompatible Units" unless self =~ target
one = @numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact
two = @denominator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact
v = one.inject(1) {|product,n| product*n} / two.inject(1) {|product,n| product*n}
one = target.numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact
@@ -704,11 +741,11 @@
alias :convert_to :to
# converts the unit back to a float if it is unitless. Otherwise raises an exception
def to_f
return @scalar.to_f if self.unitless?
- raise RuntimeError, "Can't convert to Float unless unitless. Use Unit#scalar"
+ raise RuntimeError, "Can't convert to Float unless unitless (#{self.to_s}). Use Unit#scalar"
end
# converts the unit back to a complex if it is unitless. Otherwise raises an exception
def to_c
@@ -738,17 +775,17 @@
end
if @denominator == UNITY_ARRAY
output_d = ['1']
else
den.each_with_index do |token,index|
- if token && @@PREFIX_VALUES[token] then
- output_d << "#{@@OUTPUT_MAP[token]}#{@@OUTPUT_MAP[den[index+1]]}"
- den[index+1]=nil
- else
- output_d << "#{@@OUTPUT_MAP[token]}" if token
- end
+ if token && @@PREFIX_VALUES[token] then
+ output_d << "#{@@OUTPUT_MAP[token]}#{@@OUTPUT_MAP[den[index+1]]}"
+ den[index+1]=nil
+ else
+ output_d << "#{@@OUTPUT_MAP[token]}" if token
end
+ end
end
on = output_n.reject {|x| x.empty?}.map {|x| [x, output_n.find_all {|z| z==x}.size]}.uniq.map {|x| ("#{x[0]}".strip+ (x[1] > 1 ? "^#{x[1]}" : ''))}
od = output_d.reject {|x| x.empty?}.map {|x| [x, output_d.find_all {|z| z==x}.size]}.uniq.map {|x| ("#{x[0]}".strip+ (x[1] > 1 ? "^#{x[1]}" : ''))}
out = "#{on.join('*')}#{od == ['1'] ? '': '/'+od.join('*')}".strip
@unit_name = out unless self.kind == :temperature
@@ -809,11 +846,11 @@
Unit.new(@scalar.round, @numerator, @denominator)
end
# true if scalar is zero
def zero?
- return @scalar.zero?
+ return self.to_base.scalar.zero?
end
# '5 min'.unit.ago
def ago
self.before
@@ -831,27 +868,30 @@
alias :before_now :before
# 'min'.since(time)
def since(time_point = ::Time.now)
case time_point
- when Time: (Time.now - time_point).unit('s').to(self)
- when DateTime, Date: (DateTime.now - time_point).unit('d').to(self)
- when String:
- (DateTime.now - time_point.time(:context=>:past)).unit('d').to(self)
+ when Time
+ (Time.now - time_point).unit('s').to(self)
+ when DateTime, Date
+ (DateTime.now - time_point).unit('d').to(self)
+ when String
+ (DateTime.now - time_point.to_datetime(:context=>:past)).unit('d').to(self)
else
raise ArgumentError, "Must specify a Time, DateTime, or String"
end
end
# 'min'.until(time)
def until(time_point = ::Time.now)
case time_point
- when Time: (time_point - Time.now).unit('s').to(self)
- when DateTime, Date: (time_point - DateTime.now).unit('d').to(self)
- when String:
- r = (time_point.time(:context=>:future) - DateTime.now)
- Time === time_point.time ? r.unit('s').to(self) : r.unit('d').to(self)
+ when Time
+ (time_point - Time.now).unit('s').to(self)
+ when DateTime, Date
+ (time_point - DateTime.now).unit('d').to(self)
+ when String
+ (time_point.to_datetime(:context=>:future) - DateTime.now).unit('d').to(self)
else
raise ArgumentError, "Must specify a Time, DateTime, or String"
end
end
@@ -880,11 +920,12 @@
def coerce(other)
if other.respond_to? :to_unit
return [other.to_unit, self]
end
case other
- when Unit : [other, self]
+ when Unit
+ [other, self]
else
[Unit.new(other), self]
end
end
@@ -904,26 +945,25 @@
end
end
# calculates the unit signature vector used by unit_signature
def unit_signature_vector
- return self.to_base.unit_signature_vector unless self.is_base?
- result = self
- vector = Array.new(SIGNATURE_VECTOR.size,0)
- for element in @numerator
- if r=@@ALL_UNIT_DEFINITIONS[element]
- n = SIGNATURE_VECTOR.index(r[2])
- vector[n] = vector[n] + 1 if n
- end
+ return self.to_base.unit_signature_vector unless self.is_base?
+ vector = Array.new(SIGNATURE_VECTOR.size,0)
+ for element in @numerator
+ if r=@@ALL_UNIT_DEFINITIONS[element]
+ n = SIGNATURE_VECTOR.index(r[2])
+ vector[n] = vector[n] + 1 if n
end
- for element in @denominator
- if r=@@ALL_UNIT_DEFINITIONS[element]
- n = SIGNATURE_VECTOR.index(r[2])
- vector[n] = vector[n] - 1 if n
- end
+ end
+ for element in @denominator
+ if r=@@ALL_UNIT_DEFINITIONS[element]
+ n = SIGNATURE_VECTOR.index(r[2])
+ vector[n] = vector[n] - 1 if n
end
- vector
+ end
+ vector
end
private
def initialize_copy(other)
@@ -982,12 +1022,14 @@
num = []
den = []
for key, value in combined do
case
- when value > 0 : value.times {num << key}
- when value < 0 : value.abs.times {den << key}
+ when value > 0
+ value.times {num << key}
+ when value < 0
+ value.abs.times {den << key}
end
end
num = UNITY_ARRAY if num.empty?
den = UNITY_ARRAY if den.empty?
{:scalar=>q, :numerator=>num.flatten.compact, :denominator=>den.flatten.compact}
@@ -1081,11 +1123,13 @@
@scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts
top.scan(TOP_REGEX).each do |item|
n = item[1].to_i
x = "#{item[0]} "
case
- when n>=0 : top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) {|s| x * n}
- when n<0 : bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/,"")
+ when n>=0
+ top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) {|s| x * n}
+ when n<0
+ bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/,"")
end
end
bottom.gsub!(BOTTOM_REGEX) {|s| "#{$1} " * $2.to_i} if bottom
@scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty?
@scalar = 1 unless @scalar.kind_of? Numeric