diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 1eaad1d4..1c1b732d 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -779,9 +779,16 @@ def *(other) case other when Unit raise ArgumentError, "Cannot multiply by temperatures" if [other, self].any? { |x| x.is_temperature? } - opts = RubyUnits::Unit.eliminate_terms(@scalar*other.scalar, @numerator + other.numerator, @denominator + other.denominator) - opts.merge!(:signature => @signature + other.signature) - return RubyUnits::Unit.new(opts) + if other.numerator == [''] + return RubyUnits::Unit.new(:scalar => @scalar*other.to_base.scalar, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + elsif @numerator == [''] + #return other * self + return RubyUnits::Unit.new(:scalar => self.to_base.scalar*other.scalar, :numerator => other.numerator, :denominator => other.denominator, :signature => other.signature) + else + opts = RubyUnits::Unit.eliminate_terms(@scalar*other.scalar, @numerator + other.numerator, @denominator + other.denominator) + opts.merge!(:signature => @signature + other.signature) + return RubyUnits::Unit.new(opts) + end when Numeric return RubyUnits::Unit.new(:scalar => @scalar*other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) else @@ -801,9 +808,17 @@ def /(other) when Unit raise ZeroDivisionError if other.zero? raise ArgumentError, "Cannot divide with temperatures" if [other, self].any? { |x| x.is_temperature? } - opts = RubyUnits::Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator, @denominator + other.numerator) - opts.merge!(:signature => @signature - other.signature) - return RubyUnits::Unit.new(opts) + self_pct = @numerator == [''] + other_pct = other.numerator == [''] + if other_pct && ! self_pct + return RubyUnits::Unit.new(:scalar => @scalar/other.to_base.scalar, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + elsif self_pct && ! other_pct + return RubyUnits::Unit.new(:scalar => self.to_base.scalar/other.scalar, :numerator => other.numerator, :denominator => other.denominator, :signature => other.signature) + else + opts = RubyUnits::Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator, @denominator + other.numerator) + opts.merge!(:signature => @signature - other.signature) + return RubyUnits::Unit.new(opts) + end when Numeric raise ZeroDivisionError if other.zero? return RubyUnits::Unit.new(:scalar => @scalar/other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) @@ -819,11 +834,38 @@ def /(other) # @param [Object] other # @return [Array] def divmod(other) - raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" 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) + case other + when Unit + raise ZeroDivisionError if other.zero? + self_pct = @numerator == [''] + other_pct = other.numerator == [''] + if other_pct && ! self_pct + return @scalar.divmod(other.to_base.scalar).map {|part| + RubyUnits::Unit.new(:scalar => part, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + } + elsif self_pct && ! other_pct + return self.base.scalar.divmod(other).map {|part| + RubyUnits::Unit.new(:scalar => part, :numerator => other.denominator, :denominator => other.numerator, :signature => other.signature) + } + else + raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" unless self =~ other + if self.units == other.units + return @scalar.divmod(other.scalar) + else + opts = RubyUnits::Unit.eliminate_terms(0, @numerator + other.denominator, @denominator + other.numerator) + opts.merge!(:signature => @signature - other.signature) + return self.to_base.scalar.divmod(other.to_base.scalar).map {|part| + RubyUnits::Unit.new(opts.merge(:scalar => part)) + } + end + end + when Numeric + return self.scalar.divmod(other).map {|part| + RubyUnits::Unit.new(:scalar => part, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + } + else + x, y = coerce(other) + return y.divmod x end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 1789601a..9bca5e6c 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1353,7 +1353,7 @@ context '#divmod' do specify { Unit("5 mm").divmod(Unit("2 mm")).should == [2, 1] } - specify { Unit("1 km").divmod(Unit("2 m")).should == [500, 0] } + specify { Unit("1 km").divmod(Unit("2 m")).should == [Unit('500 km/m'), Unit('0 km/m')] } specify { expect { Unit('1 m').divmod(Unit('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end