lib/quantify/unit/base_unit.rb in quantify-3.0.0 vs lib/quantify/unit/base_unit.rb in quantify-3.1.0

- old
+ new

@@ -15,10 +15,18 @@ end def self.construct_and_load(unit,&block) self.construct(unit, &block).load end + + def self.initialize_prefixed_version(prefix,unit) + prefix, unit = Prefix.for(prefix), Unit.for(unit) + raise Exceptions::InvalidArgumentError, "Prefix is not known" if prefix.nil? + raise Exceptions::InvalidArgumentError, "Unit is not known" if unit.nil? + raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{unit.prefix.name}" if unit.prefix + self.new &self.block_for_prefixed_version(prefix,unit) + end # Mass load prefixed units. First argument is a single or array of units. # Second argument is a single or array of prefixes. All specfied units will # be loaded with all specified prefixes. # @@ -34,13 +42,13 @@ # Define a new unit in terms of an already instantiated compound unit. This # unit becomes a representation of the compound - without explicitly holding # the base units, e.g. # - # Unit::Base.define(Unit.m**2).name #=> "square metre" + # Unit::Base.construct(Unit.m**2).name #=> "square metre" # - # Unit::Base.define(Unit**3) do |unit| + # Unit::Base.construct(Unit.m**3) do |unit| # unit.name = "metres cubed" # end.name #=> "metres cubed" # def self.construct(unit,&block) new_unit = self.new unit.to_hash @@ -63,10 +71,11 @@ class_eval(&block) if block end attr_reader :name, :symbol, :label, :factor, :dimensions attr_reader :acts_as_alternative_unit, :acts_as_equivalent_unit + attr_accessor :base_unit, :prefix # Create a new Unit::Base instance. # # Valid options are: :name => The unit name, e.g. :kilometre # @@ -102,14 +111,17 @@ @acts_as_alternative_unit = true @acts_as_equivalent_unit = false self.factor = 1.0 self.symbol = nil self.label = nil + self.name = nil + self.base_unit = nil + self.prefix = nil if options.is_a? Hash - self.dimensions = options[:dimensions] || options[:physical_quantity] - self.name = options[:name] + self.dimensions = options[:dimensions] || options[:physical_quantity] if options[:dimensions] || options[:physical_quantity] self.factor = options[:factor] if options[:factor] + self.name = options[:name] if options[:name] self.symbol = options[:symbol] if options[:symbol] self.label = options[:label] if options[:label] end block.call(self) if block_given? valid? @@ -301,13 +313,11 @@ !is_base_unit? end # Determine if the unit is a prefixed unit def is_prefixed_unit? - return true if valid_prefixes.size > 0 && - self.name =~ /\A(#{valid_prefixes.map {|p| p.name}.join("|")})/ - return false + self.prefix ? true : false end # Determine if the unit is one of the units against which all other units # of the same physical quantity are defined. These units are almost entirely # equivalent to the non-prefixed, SI units, but the one exception is the @@ -426,35 +436,10 @@ def valid_dimensions? @dimensions.is_a? Dimensions end - # Returns an array representing the valid prefixes for the unit described - # by self - # - # If no argument is given, the array holds instances of Prefix::Base (or - # subclasses; SI, NonSI...). Alternatively only the names or symbols of each - # prefix can be returned by providing the appropriate prefix attribute as a - # symbolized argument, e.g. - # - # Unit.m.valid_prefixes #=> [ #<Quantify::Prefix: .. >, - # #<Quantify::Prefix: .. >, - # ... ] - # - # Unit.m.valid_prefixes :name #=> [ "deca", "hecto", "kilo", - # "mega", "giga", "tera" - # ... ] - # - # Unit.m.valid_prefixes :symbol #=> [ "da", "h", "k", "M", "G", - # "T", "P" ... ] - # - def valid_prefixes(by=nil) - return [] if is_compound_unit? && has_multiple_base_units? - return Unit::Prefix.si_prefixes.map(&by).to_a if is_si_unit? - return Unit::Prefix.non_si_prefixes.map(&by).to_a if is_non_si_unit? - end - # Multiply two units together. This results in the generation of a compound # unit. # def multiply(other) options = [] @@ -511,19 +496,11 @@ # Apply a prefix to self. Returns new unit according to the prefixed version # of self, complete with modified name, symbol, factor, etc.. # def with_prefix(name_or_symbol) - raise Exceptions::InvalidArgumentError, "No valid prefixes exist for unit: #{self.name}" if valid_prefixes.empty? - raise Exceptions::InvalidArgumentError, "Cannot add prefix where one already exists: #{self.name}" if @name =~ /\A(#{valid_prefixes(:name).join("|")})/ - - prefix = Unit::Prefix.for(name_or_symbol,valid_prefixes) - if !prefix.nil? - self.class.new(options_for_prefixed_version(prefix)) - else - raise Exceptions::InvalidArgumentError, "Prefix unit is not known: #{prefix}" - end + self.class.initialize_prefixed_version(name_or_symbol,self) end # Return an array of new unit instances based upon self, together with the # prefixes specified by <tt>prefixes</tt> # @@ -556,20 +533,10 @@ raise Exceptions::InvalidArgumentError, "Cannot coerce #{self.class} into #{object.class}" end end private - - def options_for_prefixed_version(prefix) - options = {} - options[:name] = "#{prefix.name}#{@name}" - options[:symbol] = "#{prefix.symbol}#{@symbol}" - options[:label] = "#{prefix.symbol}#{@label}" - options[:factor] = prefix.factor * @factor - options[:physical_quantity] = @dimensions - return options - end # Clone self and explicitly clone the associated Dimensions object located # at @dimensions. # # This enables full or 'deep' copies of the already initialized units to be @@ -579,10 +546,22 @@ # def initialize_copy(source) super instance_variable_set("@dimensions", @dimensions.clone) end + + def self.block_for_prefixed_version(prefix,unit) + return Proc.new do |new_unit| + new_unit.base_unit = unit.clone + new_unit.prefix = prefix + new_unit.dimensions = unit.dimensions.clone + new_unit.name = "#{prefix.name}#{unit.name}" + new_unit.factor = prefix.factor * unit.factor + new_unit.symbol = "#{prefix.symbol}#{unit.symbol}" + new_unit.label = "#{prefix.symbol}#{unit.label}" + end + end # Provides syntactic sugar for several methods. E.g. # # Unit.metre.to_kilo # @@ -595,11 +574,9 @@ def method_missing(method, *args, &block) if method.to_s =~ /(to_)(.*)/ && prefix = Prefix.for($2.to_sym) return self.with_prefix(prefix) elsif method.to_s =~ /(alternatives_by_)(.*)/ && self.respond_to?($2.to_sym) return self.alternatives($2.to_sym) - elsif method.to_s =~ /(valid_prefixes_by_)(.*)/ && Prefix::Base.instance_methods.include?($2.to_s) - return self.valid_prefixes($2.to_sym) end super end end