From 9bbe85d044ea5761753da84b0118cb4bc25cdc46 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 16 Jul 2013 21:14:21 -0400 Subject: [PATCH 1/3] first crack at a best prefix algorithm. Works for information and other kinds of units, but also changes the unit as well --- lib/ruby_units/unit.rb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index e059d5ae..0af488f6 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -71,7 +71,7 @@ class Unit < Numeric :substance, :luminosity, :currency, - :memory, + :information, :angle ] @@KINDS = { @@ -120,7 +120,7 @@ class Unit < Numeric 63999998 => :illuminance, 64000000 => :luminous_power, 1280000000 => :currency, - 25600000000 => :memory, + 25600000000 => :information, 511999999980 => :angular_velocity, 512000000000 => :angle } @@ -1264,6 +1264,16 @@ def coerce(other) end end + def best_prefix + best_prefix = if (self.kind == :information) + @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10)) + else + @@PREFIX_VALUES.key(10**((Math.log(self.base_scalar,10) / 3.0).floor * 3)) + end + puts @@PREFIX_MAP.key(best_prefix)+self.base.units + self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(best_prefix)+self.base.units)) + end + # Protected and Private Functions that should only be called from this class protected @@ -1300,6 +1310,7 @@ def unit_signature_vector return vector end + private # used by #dup to duplicate a Unit @@ -1516,8 +1527,6 @@ def self.base_units return @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) } end - private - # parse a string consisting of a number and a unit string # @param [String] string # @return [Array] consisting of [Numeric, "unit"] From 29c9466e348a2c9f54206ff4fab9295f4888795a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 16 Jul 2013 21:44:22 -0400 Subject: [PATCH 2/3] simple implementation of natural unit. Preserves original unit --- lib/ruby_units/unit.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 0af488f6..d296e6ec 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1048,9 +1048,8 @@ def as_json(*args) # returns the 'unit' part of the Unit object without the scalar # @return [String] - def units + def units(with_prefix = true) return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY - return @unit_name unless @unit_name.nil? output_numerator = [] output_denominator = [] num = @numerator.clone.compact @@ -1061,7 +1060,9 @@ def units else while defn = RubyUnits::Unit.definition(num.shift) do if defn && defn.prefix? - output_numerator << defn.display_name + RubyUnits::Unit.definition(num.shift).display_name + if with_prefix + output_numerator << (defn.display_name + RubyUnits::Unit.definition(num.shift).display_name) + end else output_numerator << defn.display_name end @@ -1073,7 +1074,9 @@ def units else while defn = RubyUnits::Unit.definition(den.shift) do if defn && defn.prefix? - output_denominator << defn.display_name + RubyUnits::Unit.definition(den.shift).display_name + if with_prefix + output_denominator << (defn.display_name + RubyUnits::Unit.definition(den.shift).display_name) + end else output_denominator << defn.display_name end @@ -1087,7 +1090,6 @@ def units map { |x| [x, output_denominator.count(x)] }. map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } out = "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip - @unit_name = out unless self.kind == :temperature return out end @@ -1264,14 +1266,14 @@ def coerce(other) end end - def best_prefix + # returns a new unit that has been + def natural best_prefix = if (self.kind == :information) @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10)) else @@PREFIX_VALUES.key(10**((Math.log(self.base_scalar,10) / 3.0).floor * 3)) end - puts @@PREFIX_MAP.key(best_prefix)+self.base.units - self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(best_prefix)+self.base.units)) + self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(best_prefix)+self.units(false))) end # Protected and Private Functions that should only be called from this class From 088eb2850e8288b7835a68415200388e966c304a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 18 Jul 2013 11:26:28 -0400 Subject: [PATCH 3/3] add specs and tweak #best_prefix method --- lib/ruby_units/unit.rb | 8 ++++---- lib/ruby_units/unit_definitions/base.rb | 2 +- spec/ruby-units/unit_spec.rb | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index d296e6ec..350fe358 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1267,13 +1267,13 @@ def coerce(other) end # returns a new unit that has been - def natural - best_prefix = if (self.kind == :information) + def best_prefix + _best_prefix = if (self.kind == :information) @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10)) else - @@PREFIX_VALUES.key(10**((Math.log(self.base_scalar,10) / 3.0).floor * 3)) + @@PREFIX_VALUES.key(10**((Math.log10(self.base_scalar) / 3.0).floor * 3)) end - self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(best_prefix)+self.units(false))) + self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(_best_prefix)+self.units(false))) end # Protected and Private Functions that should only be called from this class diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index 952cc238..36a1eff7 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -61,7 +61,7 @@ unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{B byte bytes} - unit.kind = :memory + unit.kind = :information end RubyUnits::Unit.define("dollar") do |unit| diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index e0501b0c..8cd39ce2 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1306,6 +1306,11 @@ specify { Unit('23 m').div(Unit('2 m')).should == 11 } end + context '#best_prefix' do + specify { Unit('1024 KiB').best_prefix.should == Unit('1 MiB')} + specify { Unit('1000 m').best_prefix.should == Unit('1 km')} + end + context "Time helper functions" do before do Time.stub!(:now).and_return(Time.utc(2011,10,16))