Class: UnitMeasurements::Measurement Abstract

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, ConversionMethods, NumericMethods
Includes:
Arithmetic, Comparison, Conversion, Formatter, Math
Defined in:
lib/unit_measurements/measurement.rb

Overview

This class is abstract.

The UnitMeasurements::Measurement is the abstract class and serves as superclass for all the unit groups. It includes several modules that provide mathematical operations, comparison, conversion, formatting, and other functionalities.

This class provides a comprehensive set of methods and functionality for working with measurements in different units. It includes robust error handling and supports conversion between units. Additionally, it ensures that measurements are consistently represented.

You should not directly initialize a Measurement instance. Instead, create specialized measurement types by subclassing Measurement and providing specific units and conversions through the build method defined in the UnitMeasurements module.

Constant Summary collapse

CONVERSION_STRING_REGEXP =

Regular expression to match conversion strings.

Author:

Since:

  • 1.0.0

/(.+?)\s?(?:\s+(?:in|to|as)\s+(.+)|\z)/i.freeze

Constants included from Formatter

Formatter::DEFAULT_FORMAT

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NumericMethods

define_numeric_method_for, define_numeric_methods

Methods included from ConversionMethods

define_conversion_method_for, define_conversion_methods

Methods included from Math

#abs, #cbrt, #ceil, #floor, #round, #sqrt

Methods included from Formatter

#format, #to_fs

Methods included from Conversion

#to_c, #to_d, #to_f, #to_i, #to_r

Methods included from Comparison

#<=>

Methods included from Arithmetic

#*, #**, #+, #-, #-@, #/, #arithmetic_operation, #coerce, #nonzero?

Constructor Details

#initialize(quantity, unit) ⇒ Measurement

Initializes a new instance of Measurement with a specified quantity and unit.

This method is intended to be overridden by subclasses and serves as a placeholder for common initialization logic. It raises an error if called directly on the abstract Measurement class.

Examples:

Initializing the measurement with scientific number and unit:

UnitMeasurements::Length.new(BigDecimal(2), "km")
=> 2.0 km

UnitMeasurements::Length.new("2e+2", "km")
=> 200.0 km

UnitMeasurements::Length.new("2e²", "km")
=> 200.0 km

UnitMeasurements::Length.new("2e⁻²", "km")
=> 0.02 km

Initializing the measurement with complex number and unit:

UnitMeasurements::Length.new(Complex(2, 3), "km")
=> 2+3i km

UnitMeasurements::Length.new("2+3i", "km")
=> 2.0+3.0i km

Initializing the measurement with rational or mixed rational number and unit:

UnitMeasurements::Length.new(Rational(2, 3), "km")
=> 0.6666666666666666 km

UnitMeasurements::Length.new(2/3r, "km")
=> 2/3 km

UnitMeasurements::Length.new("2/3", "km")
=> 0.6666666666666666 km

UnitMeasurements::Length.new("½", "km")
=> 0.5 km

UnitMeasurements::Length.new("2 ½", "km")
=> 2.5 km

Initializing the measurement with ratio and unit:

UnitMeasurements::Length.new("1:2", "km")
=> 0.5 km

Parameters:

  • quantity (Numeric|String)

    The quantity of the measurement.

  • unit (String|Unit)

    The unit of the measurement.

Raises:

See Also:

Author:

Since:

  • 1.0.0



118
119
120
121
122
123
124
# File 'lib/unit_measurements/measurement.rb', line 118

def initialize(quantity, unit)
  raise BlankQuantityError if quantity.blank?
  raise BlankUnitError if unit.blank?

  @quantity = convert_quantity(quantity)
  @unit = unit_from_unit_or_name!(unit)
end

Instance Attribute Details

#quantityNumeric (readonly)

Returns the quantity of the measurement.

Returns:

  • (Numeric)

    Quantity of the measurement.

Author:

Since:

  • 1.5.0



51
52
53
# File 'lib/unit_measurements/measurement.rb', line 51

def quantity
  @quantity
end

#unitUnit (readonly)

The unit associated with the measurement.

Returns:

  • (Unit)

    The unit instance associated with the measurement.

Author:

Since:

  • 1.0.0



59
60
61
# File 'lib/unit_measurements/measurement.rb', line 59

def unit
  @unit
end

Class Method Details

._parse(string) ⇒ Measurement (private)

Parses the normalized string to return the Measurement instance.

Parameters:

  • string (String)

    String to be parsed.

Returns:

See Also:

Author:

Since:

  • 1.0.0



459
460
461
462
463
# File 'lib/unit_measurements/measurement.rb', line 459

def _parse(string)
  quantity, unit = Parser.parse(string)

  new(quantity, unit)
end

.cachedCache

Returns the Cache instance for the unit group to store and retrieve conversion factors.

Examples:

UnitMeasurements::Length.cached
=> #<UnitMeasurements::Cache:0x00007fe407249750>

Returns:

  • (Cache)

    The Cache instance.

See Also:

Author:

Since:

  • 5.2.0



379
380
381
# File 'lib/unit_measurements/measurement.rb', line 379

def cached
  @cached ||= Cache.new(self)
end

.clear_cachevoid

This method returns an undefined value.

Clears the cached conversion factors of the unit group.

Examples:

UnitMeasurements::Length.clear_cache

See Also:

Author:

Since:

  • 5.2.0



394
395
396
# File 'lib/unit_measurements/measurement.rb', line 394

def clear_cache
  cached.clear_cache
end

.parse(input, use_cache: false) ⇒ Measurement

Parses an input string and returns a Measurement instance depending on the input string. This method first normalizes the input internally, using the Normalizer before parsing it using the Parser.

You can separate source and target units from each other in input using to, in, or as.

If only the source unit is provided, it returns a new Measurement instance with the quantity in the source unit. If both source and target units are provided in the input string, it returns a new Measurement instance with the quantity converted to the target unit.

Examples:

Parsing string representing a complex number and source unit:

UnitMeasurements::Length.parse("2+3i km")
=> 2.0+3.0i km

Parsing string representing a complex number, source, and target units:

UnitMeasurements::Length.parse("2+3i km in m")
=> 2000.0+3000.0i m

Parsing string representing a rational or mixed rational number and source unit:

UnitMeasurements::Length.parse("½ km")
=> 0.5 km

UnitMeasurements::Length.parse("2/3 km")
=> 0.666666666666667 km

UnitMeasurements::Length.parse("2 ½ km")
=> 2.5 km

UnitMeasurements::Length.parse("2 1/2 km")
=> 2.5 km

Parsing string representing a rational or mixed rational number, source, and target units:

UnitMeasurements::Length.parse("½ km to m")
=> 500.0 km

UnitMeasurements::Length.parse("2/3 km to m")
=> 666.666666666667 m

UnitMeasurements::Length.parse("2 ½ km in m")
=> 2500.0 m

UnitMeasurements::Length.parse("2 1/2 km as m")
=> 2500.0 m

Parsing string representing a scientific number and source unit:

UnitMeasurements::Length.parse("2e² km")
=> 200.0 km

UnitMeasurements::Length.parse("2e+2 km")
=> 200.0 km

UnitMeasurements::Length.parse("2e⁻² km")
=> 0.02 km

Parsing string representing a scientific number, source, and target units:


UnitMeasurements::Length.parse("2e+2 km to m")
=> 200000.0 m

UnitMeasurements::Length.parse("2e⁻² km as m")
=> 20.0 m

Parsing string representing a ratio and source unit:

UnitMeasurements::Length.parse("1:2 km")
=> 0.5 km

Parsing string representing a ratio, source, and target units:

UnitMeasurements::Length.parse("1:2 km in m")
=> 500.0 m

Parameters:

  • input (String)

    The input string to be parsed.

  • use_cache (TrueClass|FalseClass) (defaults to: false)

    Indicates whether to use cached conversion factors.

Returns:

See Also:

Author:

Since:

  • 1.0.0



360
361
362
363
364
365
# File 'lib/unit_measurements/measurement.rb', line 360

def parse(input, use_cache: false)
  input = Normalizer.normalize(input)
  source, target = input.match(CONVERSION_STRING_REGEXP)&.captures

  target ? _parse(source).convert_to(target, use_cache: use_cache) : _parse(source)
end

.ratio(source_unit, target_unit) ⇒ String

Calculates the ratio between two units.

This method takes a source unit and a target unit, and returns the ratio between them as a string representation.

Examples:

Calculating the ratio between ‘in’ and ‘ft’:

UnitMeasurements::Length.ratio("in", "ft")
=> "12.0 in/ft"

UnitMeasurements::Length.ratio(UnitMeasurements::Length.unit_for("in"), "ft")
=> "12.0 in/ft"

Parameters:

  • source_unit (Unit|String|Symbol)

    The source unit for the ratio calculation.

  • target_unit (Unit|String|Symbol)

    The target unit for the ratio calculation.

Returns:

  • (String)

    The ratio between the source and target units.

Raises:

  • (UnitError)

    If either the source unit or the target unit is not found in the unit group.

Author:

Since:

  • 5.11.0



422
423
424
425
426
427
428
429
430
# File 'lib/unit_measurements/measurement.rb', line 422

def ratio(source_unit, target_unit)
  source_unit = source_unit.is_a?(Unit) ? source_unit : unit_for!(source_unit)
  target_unit = target_unit.is_a?(Unit) ? target_unit : unit_for!(target_unit)

  source_quantity = 1
  target_quantity = new(source_quantity, target_unit).convert_to(source_unit).quantity

  "#{target_quantity} #{source_unit}/#{target_unit}"
end

.unit_groupUnitGroup (private)

The class attribute representing an instance of UnitGroup.

Returns:

Raises:

  • (BaseError)

    If directly invoked on Measurement rather than its subclasses.

See Also:

Author:

Since:

  • 1.0.0



445
446
447
# File 'lib/unit_measurements/measurement.rb', line 445

def unit_group
  raise BaseError, "`Measurement` does not have a `unit_group` instance. You cannot directly use `Measurement`. Instead, build a new unit group by calling `UnitMeasurements.build`."
end

Instance Method Details

#calculate_conversion_factor(target_unit, use_cache) ⇒ Numeric (private)

Note:

If caching is enabled, the calculated conversion factor will be stored in the cache.

Calculates the conversion factor between the current unit and the target unit.

If caching is enabled and a cached factor is available, it will be used. Otherwise, the conversion factor will be computed and, if caching is enabled, stored in the cache.

Parameters:

  • target_unit (Unit)

    The target unit for conversion.

  • use_cache (TrueClass|FalseClass)

    Indicates whether caching should be used.

Returns:

  • (Numeric)

    The conversion factor.

See Also:

Author:

Since:

  • 5.2.0



527
528
529
530
531
532
533
534
535
536
537
# File 'lib/unit_measurements/measurement.rb', line 527

def calculate_conversion_factor(target_unit, use_cache)
  use_cache = (UnitMeasurements.configuration.use_cache || use_cache)

  if use_cache && (cached_factor = self.class.cached.get(unit.name, target_unit.name))
    cached_factor
  else
    factor = unit.conversion_factor / target_unit.conversion_factor
    self.class.cached.set(unit.name, target_unit.name, factor) if use_cache
    factor
  end
end

#convert_quantity(quantity) ⇒ Numeric (private)

Converts the measurement quantity to a suitable format for internal use.

Parameters:

  • quantity (Numeric|String)

    The quantity of the measurement.

Returns:

  • (Numeric)

    The converted quantity.

Author:

Since:

  • 1.0.0



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
# File 'lib/unit_measurements/measurement.rb', line 477

def convert_quantity(quantity)
  case quantity
  when Float
    BigDecimal(quantity, Float::DIG)
  when Integer
    Rational(quantity)
  when String
    quantity = Normalizer.normalize(quantity)
    quantity, _ = Parser.parse(quantity)

    quantity
  else
    quantity
  end
end

#convert_to(target_unit, use_cache: false) ⇒ Measurement Also known as: to, in, as

Converts the measurement to a target_unit and returns new instance of the measurement.

When use_cache value is true, conversion factor between units are checked in cache file of the unit group. If cached conversion factor is present in the cache file, it is used for conversion otherwise conversion factor is stored in the cache before converting the measurement to the target_unit.

Examples:

UnitMeasurements::Length.new(1, "m").convert_to("cm")
=> 100.0 cm

UnitMeasurements::Length.new(1, "m").convert_to("mm", use_cache: true)
=> 1000.0 cm

Parameters:

  • target_unit (String|Symbol)

    The target unit for conversion.

  • use_cache (TrueClass|FalseClass) (defaults to: false)

    Indicates whether to use cached conversion factors.

Returns:

  • (Measurement)

    A new Measurement instance with the converted quantity and target unit.

Author:

Since:

  • 1.0.0



152
153
154
155
156
157
158
159
# File 'lib/unit_measurements/measurement.rb', line 152

def convert_to(target_unit, use_cache: false)
  target_unit = unit_from_unit_or_name!(target_unit)
  return self if target_unit == unit

  conversion_factor = calculate_conversion_factor(target_unit, use_cache)

  self.class.new((quantity * conversion_factor), target_unit)
end

#convert_to!(target_unit, use_cache: false) ⇒ Measurement Also known as: to!, in!, as!

Converts the measurement to a target_unit and updates the current instance.

Examples:

UnitMeasurements::Length.new(1, "m").convert_to!("cm")
=> 100.0 cm

UnitMeasurements::Length.new(1, "m").convert_to!("mm", use_cache: true)
=> 1000.0 mm

Parameters:

  • target_unit (String|Symbol)

    The target unit for conversion.

  • use_cache (TrueClass|FalseClass) (defaults to: false)

    Indicates whether to use cached conversion factors.

Returns:

  • (Measurement)

    The current Measurement instance with updated quantity and unit.

See Also:

Author:

Since:

  • 1.0.0



184
185
186
187
188
189
# File 'lib/unit_measurements/measurement.rb', line 184

def convert_to!(target_unit, use_cache: false)
  measurement = convert_to(target_unit, use_cache: use_cache)
  @quantity, @unit = measurement.quantity, measurement.unit

  self
end

#inspect(dump: false) ⇒ Object

Returns an object representation of the Measurement.

Parameters:

  • dump (TrueClass|FalseClass) (defaults to: false)

    If true, returns the dump representation.

Returns:

  • (Object)

    An object representation of the Measurement.

Author:

Since:

  • 1.0.0



237
238
239
# File 'lib/unit_measurements/measurement.rb', line 237

def inspect(dump: false)
  dump ? super() : to_s
end

#to_primitive(use_cache: false) ⇒ Measurement Also known as: in_primitive, as_primitive

Converts the measurement to its primitive unit and returns a new instance of the Measurement.

The method first retrieves the primitive unit of the unit group associated with the measurement. If the primitive unit is not set, it raises a MissingPrimitiveUnitError.

Examples:

UnitMeasurements::Length.new(1, "m").to_primitive
=> 1 m

UnitMeasurements::Length.new(1, "cm").to_primitive
=> 0.01 m

Parameters:

  • use_cache (TrueClass|FalseClass) (defaults to: false)

    Indicates whether to use cached conversion factors.

Returns:

  • (Measurement)

    A new Measurement instance representing the measurement in its primitive unit.

Raises:

Author:

Since:

  • 5.13.0



220
221
222
223
224
225
# File 'lib/unit_measurements/measurement.rb', line 220

def to_primitive(use_cache: false)
  primitive_unit = self.class.primitive
  raise MissingPrimitiveUnitError if primitive_unit.nil?

  convert_to(primitive_unit, use_cache: use_cache)
end

#to_sString

Returns a string representation of the Measurement.

Returns:

  • (String)

    A string representation of the Measurement.

Author:

Since:

  • 1.0.0



247
248
249
# File 'lib/unit_measurements/measurement.rb', line 247

def to_s
  "#{quantity} #{unit}"
end

#unit_from_unit_or_name!(value) ⇒ Unit (private)

Returns the Unit instance associated with the value provided.

Parameters:

  • value (String|Unit)

    The value representing a unit name or Unit instance.

Returns:

  • (Unit)

    The Unit instance associated with value.

Author:

Since:

  • 1.0.0



503
504
505
# File 'lib/unit_measurements/measurement.rb', line 503

def unit_from_unit_or_name!(value)
  value.is_a?(Unit) ? value : self.class.unit_for!(value)
end