Class: Unit
- Includes:
- Comparable
- Defined in:
- lib/rails_units/unit.rb,
lib/rails_units/cache.rb,
lib/rails_units/version.rb,
lib/rails_units/unit_definitions.rb
Overview
Unit.setup
Defined Under Namespace
Modules: Version Classes: Cache
Constant Summary collapse
- VERSION =
pre-generate hashes from unit definitions for performance.
Unit::Version::STRING
- UNITY =
'<1>'
- UNITY_ARRAY =
[UNITY]
- FEET_INCH_REGEX =
/(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/
- TIME_REGEX =
/(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/
- LBS_OZ_REGEX =
/(\d+)\s*(?:#|lbs|pounds|pound-mass)+[\s,]*(\d+)\s*(?:oz|ounces)/
- SCI_NUMBER =
%r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)}
- RATIONAL_NUMBER =
/([+-]?\d+)\/(\d+)/
- COMPLEX_NUMBER =
/#{SCI_NUMBER}?#{SCI_NUMBER}i\b/
- NUMBER_REGEX =
/#{SCI_NUMBER}*\s*(.+)?/
- UNIT_STRING_REGEX =
/#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/
- TOP_REGEX =
/([^ \*]+)(?:\^|\*\*)([\d-]+)/
- BOTTOM_REGEX =
/([^* ]+)(?:\^|\*\*)(\d+)/
- UNCERTAIN_REGEX =
/#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/
- COMPLEX_REGEX =
/#{COMPLEX_NUMBER}\s?(.+)?/
- RATIONAL_REGEX =
/#{RATIONAL_NUMBER}\s?(.+)?/
- KELVIN =
['<kelvin>']
- FAHRENHEIT =
['<fahrenheit>']
- RANKINE =
['<rankine>']
- CELSIUS =
['<celsius>']
- TEMP_REGEX =
/(?:temp|deg)[CFRK]/
- SIGNATURE_VECTOR =
[:length, :time, :temperature, :mass, :current, :substance, :luminosity, :currency, :memory, :angle, :capacitance]
- UNIT_DEFINITIONS =
{ # prefixes '<googol>' => [%w{googol}, 1e100, :prefix], '<kibi>' => [%w{Ki Kibi kibi}, 2**10, :prefix], '<mebi>' => [%w{Mi Mebi mebi}, 2**20, :prefix], '<gibi>' => [%w{Gi Gibi gibi}, 2**30, :prefix], '<tebi>' => [%w{Ti Tebi tebi}, 2**40, :prefix], '<pebi>' => [%w{Pi Pebi pebi}, 2**50, :prefix], '<exi>' => [%w{Ei Exi exi}, 2**60, :prefix], '<zebi>' => [%w{Zi Zebi zebi}, 2**70, :prefix], '<yebi>' => [%w{Yi Yebi yebi}, 2**80, :prefix], '<yotta>' => [%w{Y Yotta yotta}, 1e24, :prefix], '<zetta>' => [%w{Z Zetta zetta}, 1e21, :prefix], '<exa>' => [%w{E Exa exa}, 1e18, :prefix], '<peta>' => [%w{P Peta peta}, 1e15, :prefix], '<tera>' => [%w{T Tera tera}, 1e12, :prefix], '<giga>' => [%w{G Giga giga}, 1e9, :prefix], '<mega>' => [%w{M Mega mega}, 1e6, :prefix], '<kilo>' => [%w{k kilo}, 1e3, :prefix], '<hecto>' => [%w{h Hecto hecto}, 1e2, :prefix], '<deca>' => [%w{da Deca deca deka}, 1e1, :prefix], '<deci>' => [%w{d Deci deci}, Rational(1,1e1), :prefix], '<centi>' => [%w{c Centi centi}, Rational(1,1e2), :prefix], '<milli>' => [%w{m Milli milli}, Rational(1,1e3), :prefix], '<micro>' => [%w{u Micro micro}, Rational(1,1e6), :prefix], '<nano>' => [%w{n Nano nano}, Rational(1,1e9), :prefix], '<pico>' => [%w{p Pico pico}, Rational(1,1e12), :prefix], '<femto>' => [%w{f Femto femto}, Rational(1,1e15), :prefix], '<atto>' => [%w{a Atto atto}, Rational(1,1e18), :prefix], '<zepto>' => [%w{z Zepto zepto}, Rational(1,1e21), :prefix], '<yocto>' => [%w{y Yocto yocto}, Rational(1,1e24), :prefix], '<1>' => [%w{1},1,:prefix], # length units '<meter>' => [%w{m meter meters metre metres}, 1, :length, %w{<meter>} ], '<inch>' => [%w{in inch inches "}, Rational(254,10_000), :length, %w{<meter>}], '<foot>' => [%w{ft foot feet '}, Rational(3048,10_000), :length, %w{<meter>}], '<yard>' => [%w{yd yard yards}, 0.9144, :length, %w{<meter>}], '<mile>' => [%w{mi mile miles}, 1609.344, :length, %w{<meter>}], '<naut-mile>' => [%w{nmi}, 1852, :length, %w{<meter>}], '<league>'=> [%w{league leagues}, 4828, :length, %w{<meter>}], '<furlong>'=> [%w{furlong furlongs}, 201.2, :length, %w{<meter>}], '<rod>' => [%w{rd rod rods}, 5.029, :length, %w{<meter>}], '<mil>' => [%w{mil mils}, 0.0000254, :length, %w{<meter>}], '<angstrom>' =>[%w{ang angstrom angstroms}, Rational(1,1e10), :length, %w{<meter>}], '<fathom>' => [%w{fathom fathoms}, 1.829, :length, %w{<meter>}], '<redshift>' => [%w{z red-shift}, 1.302773e26, :length, %w{<meter>}], '<AU>' => [%w{AU astronomical-unit}, 149597900000, :length, %w{<meter>}], '<light-second>'=>[%w{ls light-second}, 299792500, :length, %w{<meter>}], '<light-minute>'=>[%w{lmin light-minute}, 17987550000, :length, %w{<meter>}], '<light-year>' => [%w{ly light-year}, 9460528000000000, :length, %w{<meter>}], '<parsec>' => [%w{pc parsec parsecs}, 30856780000000000, :length, %w{<meter>}], #mass '<kilogram>' => [%w{kg kilogram kilograms}, 1, :mass, %w{<kilogram>}], '<AMU>' => [%w{u AMU amu}, 6.0221415e26, :mass, %w{<kilogram>}], '<dalton>' => [%w{Da Dalton Daltons dalton daltons}, 6.0221415e26, :mass, %w{<kilogram>}], '<slug>' => [%w{slug slugs}, 14.5939029, :mass, %w{<kilogram>}], '<short-ton>' => [%w{tn ton}, 907.18474, :mass, %w{<kilogram>}], '<metric-ton>'=>[%w{tonne}, 1000, :mass, %w{<kilogram>}], '<carat>' => [%w{ct carat carats}, 0.0002, :mass, %w{<kilogram>}], '<pound>' => [%w{lbs lb pound pounds #}, Rational(8171193714040401,18014398509481984), :mass, %w{<kilogram>}], '<ounce>' => [%w{oz ounce ounces}, Rational(8171193714040401,288230376151711744), :mass, %w{<kilogram>}], '<gram>' => [%w{g gram grams gramme grammes},Rational(1,1e3),:mass, %w{<kilogram>}], #area '<hectare>'=>[%w{hectare}, 10000, :area, %w{<meter> <meter>}], '<acre>'=>[%w(acre acres), 4046.85642, :area, %w{<meter> <meter>}], '<sqft>'=>[%w(sqft), 1, :area, %w{<feet> <feet>}], #volume '<liter>' => [%w{l L liter liters litre litres}, Rational(1,1e3), :volume, %w{<meter> <meter> <meter>}], '<gallon>'=> [%w{gal gallon gallons}, 0.0037854118, :volume, %w{<meter> <meter> <meter>}], '<quart>'=> [%w{qt quart quarts}, 0.00094635295, :volume, %w{<meter> <meter> <meter>}], '<pint>'=> [%w{pt pint pints}, 0.000473176475, :volume, %w{<meter> <meter> <meter>}], '<cup>'=> [%w{cu cup cups}, 0.000236588238, :volume, %w{<meter> <meter> <meter>}], '<fluid-ounce>'=> [%w{floz fluid-ounce}, 2.95735297e-5, :volume, %w{<meter> <meter> <meter>}], '<tablespoon>'=> [%w{tbs tablespoon tablespoons}, 1.47867648e-5, :volume, %w{<meter> <meter> <meter>}], '<teaspoon>'=> [%w{tsp teaspoon teaspoons}, 4.92892161e-6, :volume, %w{<meter> <meter> <meter>}], #speed '<kph>' => [%w{kph}, 0.277777778, :speed, %w{<meter>}, %w{<second>}], '<mph>' => [%w{mph}, 0.44704, :speed, %w{<meter>}, %w{<second>}], '<knot>' => [%w{kt kn kts knot knots}, 0.514444444, :speed, %w{<meter>}, %w{<second>}], '<fps>' => [%w{fps}, 0.3048, :speed, %w{<meter>}, %w{<second>}], #acceleration '<gee>' => [%w{gee}, 9.80655, :acceleration, %w{<meter>}, %w{<second> <second>}], #temperature_difference '<kelvin>' => [%w{degK kelvin}, 1, :temperature, %w{<kelvin>}], '<celsius>' => [%w{degC celsius celsius centigrade}, 1, :temperature, %w{<kelvin>}], '<fahrenheit>' => [%w{degF fahrenheit}, Rational(1,1.8), :temperature, %w{<kelvin>}], '<rankine>' => [%w{degR rankine}, Rational(1,1.8), :temperature, %w{<kelvin>}], '<temp-K>' => [%w{tempK}, 1, :temperature, %w{<temp-K>}], '<temp-C>' => [%w{tempC}, 1, :temperature, %w{<temp-K>}], '<temp-F>' => [%w{tempF}, Rational(1,1.8), :temperature, %w{<temp-K>}], '<temp-R>' => [%w{tempR}, Rational(1,1.8), :temperature, %w{<temp-K>}], #time '<second>'=> [%w{s sec second seconds}, 1, :time, %w{<second>}], '<minute>'=> [%w{min minute minutes}, 60, :time, %w{<second>}], '<hour>'=> [%w{h hr hrs hour hours}, 3600, :time, %w{<second>}], '<day>'=> [%w{d day days}, 3600*24, :time, %w{<second>}], '<week>'=> [%w{wk week weeks}, 7*3600*24, :time, %w{<second>}], '<fortnight>'=> [%w{fortnight fortnights}, 1209600, :time, %W{<second>}], '<year>'=> [%w{y yr year years annum}, 31556926, :time, %w{<second>}], '<decade>'=>[%w{decade decades}, 315569260, :time, %w{<second>}], '<century>'=>[%w{century centuries}, 3155692600, :time, %w{<second>}], #pressure '<pascal>' => [%w{Pa pascal Pascal}, 1, :pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<mmHg>' => [%w{mmHg}, 133.322368,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<inHg>' => [%w{inHg}, 3386.3881472,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<torr>' => [%w{torr}, 133.322368,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<bar>' => [%w{bar}, 100000,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<atm>' => [%w{atm ATM atmosphere atmospheres}, 101325,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<psi>' => [%w{psi}, 6894.76,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<cmh2o>' => [%w{cmH2O}, 98.0638,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], '<inh2o>' => [%w{inH2O}, 249.082052,:pressure, %w{<kilogram>},%w{<meter> <second> <second>}], #viscosity '<poise>' => [%w{P poise}, Rational(1,10), :viscosity, %w{<kilogram>},%w{<meter> <second>} ], '<stokes>' => [%w{St stokes}, Rational(1,1e4), :viscosity, %w{<meter> <meter>}, %w{<second>}], #substance '<mole>' => [%w{mol mole}, 1, :substance, %w{<mole>}], #concentration '<molar>' => [%w{M molar}, 1000, :concentration, %w{<mole>}, %w{<meter> <meter> <meter>}], '<wtpercent>' => [%w{wt% wtpercent}, 10, :concentration, %w{<kilogram>}, %w{<meter> <meter> <meter>}], #activity '<katal>' => [%w{kat katal Katal}, 1, :activity, %w{<mole>}, %w{<second>}], '<unit>' => [%w{U enzUnit}, 16.667e-16, :activity, %w{<mole>}, %w{<second>}], #capacitance '<farad>' => [%w{F farad Farad}, 1, :capacitance, %w{<farad>}], #charge '<coulomb>' => [%w{C coulomb Coulomb}, 1, :charge, %w{<ampere> <second>}], #current '<ampere>' => [%w{A Ampere ampere amp amps}, 1, :current, %w{<ampere>}], #conductance '<siemens>' => [%w{S Siemens siemens}, 1, :resistance, %w{<second> <second> <second> <ampere> <ampere>}, %w{<kilogram> <meter> <meter>}], #inductance '<henry>' => [%w{H Henry henry}, 1, :inductance, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere> <ampere>}], #potential '<volt>' => [%w{V Volt volt volts}, 1, :potential, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <second> <ampere>}], #resistance '<ohm>' => [%w{Ohm ohm}, 1, :resistance, %w{<meter> <meter> <kilogram>},%w{<second> <second> <second> <ampere> <ampere>}], #magnetism '<weber>' => [%w{Wb weber webers}, 1, :magnetism, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere>}], '<tesla>' => [%w{T tesla teslas}, 1, :magnetism, %w{<kilogram>}, %w{<second> <second> <ampere>}], '<gauss>' => [%w{G gauss}, Rational(1,1e4), :magnetism, %w{<kilogram>}, %w{<second> <second> <ampere>}], '<maxwell>' => [%w{Mx maxwell maxwells}, Rational(1,1e8), :magnetism, %w{<meter> <meter> <kilogram>}, %w{<second> <second> <ampere>}], '<oersted>' => [%w{Oe oersted oersteds}, 250.0/Math::PI, :magnetism, %w{<ampere>}, %w{<meter>}], #energy '<joule>' => [%w{J joule Joule joules}, 1, :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}], '<erg>' => [%w{erg ergs}, Rational(1,1e7), :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}], '<btu>' => [%w{BTU btu BTUs}, 1055.056, :energy, %w{<meter> <meter> <kilogram>}, %w{<second> <second>}], '<calorie>' => [%w{cal calorie calories}, 4.18400, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}], '<Calorie>' => [%w{Cal Calorie Calories}, 4184.00, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}], '<therm-US>' => [%w{th therm therms Therm}, 105480400, :energy,%w{<meter> <meter> <kilogram>}, %w{<second> <second>}], #force '<newton>' => [%w{N Newton newton}, 1, :force, %w{<kilogram> <meter>}, %w{<second> <second>}], '<dyne>' => [%w{dyn dyne}, Rational(1,1e5), :force, %w{<kilogram> <meter>}, %w{<second> <second>}], '<pound-force>' => [%w{lbf pound-force}, 4.448222, :force, %w{<kilogram> <meter>}, %w{<second> <second>}], #frequency '<hertz>' => [%w{Hz hertz Hertz}, 1, :frequency, %w{<1>}, %{<second>}], #angle '<radian>' =>[%w{rad radian radian radians}, 1, :angle, %w{<radian>}], '<degree>' =>[%w{deg degree degrees}, Math::PI / 180.0, :angle, %w{<radian>}], '<grad>' =>[%w{grad gradian grads}, Math::PI / 200.0, :angle, %w{<radian>}], '<steradian>' => [%w{sr steradian steradians}, 1, :solid_angle, %w{<steradian>}], #rotation '<rotation>' => [%w{rotation}, 2.0*Math::PI, :angle, %w{<radian>}], '<rpm>' =>[%w{rpm}, 2.0*Math::PI / 60.0, :angular_velocity, %w{<radian>}, %w{<second>}], #memory '<byte>' =>[%w{B byte}, 1, :memory, %w{<byte>}], '<bit>' =>[%w{b bit}, 0.125, :memory, %w{<byte>}], #currency '<dollar>'=>[%w{USD dollar}, 1, :currency, %w{<dollar>}], '<cents>' =>[%w{cents}, Rational(1,100), :currency, %w{<dollar>}], #luminosity '<candela>' => [%w{cd candela}, 1, :luminosity, %w{<candela>}], '<lumen>' => [%w{lm lumen}, 1, :luminous_power, %w{<candela> <steradian>}], '<lux>' =>[%w{lux}, 1, :illuminance, %w{<candela> <steradian>}, %w{<meter> <meter>}], #power '<watt>' => [%w{W watt watts}, 1, :power, %w{<kilogram> <meter> <meter>}, %w{<second> <second> <second>}], '<horsepower>' => [%w{hp horsepower}, 745.699872, :power, %w{<kilogram> <meter> <meter>}, %w{<second> <second> <second>}], #radiation '<gray>' => [%w{Gy gray grays}, 1, :radiation, %w{<meter> <meter>}, %w{<second> <second>}], '<roentgen>' => [%w{R roentgen}, 0.009330, :radiation, %w{<meter> <meter>}, %w{<second> <second>}], '<sievert>' => [%w{Sv sievert sieverts}, 1, :radiation, %w{<meter> <meter>}, %w{<second> <second>}], '<becquerel>' => [%w{Bq bequerel bequerels}, 1, :radiation, %w{<1>},%w{<second>}], '<curie>' => [%w{Ci curie curies}, 3.7e10, :radiation, %w{<1>},%w{<second>}], # rate '<cpm>' => [%w{cpm}, Rational(1,60), :rate, %w{<count>},%w{<second>}], '<dpm>' => [%w{dpm}, Rational(1,60), :rate, %w{<count>},%w{<second>}], '<bpm>' => [%w{bpm}, Rational(1,60), :rate, %w{<count>},%w{<second>}], #resolution / typography '<dot>' => [%w{dot dots}, 1, :resolution, %w{<each>}], '<pixel>' => [%w{pixel px}, 1, :resolution, %w{<each>}], '<ppi>' => [%w{ppi}, 1, :resolution, %w{<pixel>}, %w{<inch>}], '<dpi>' => [%w{dpi}, 1, :typography, %w{<dot>}, %w{<inch>}], '<pica>' => [%w{pica}, 0.00423333333 , :typography, %w{<meter>}], '<point>' => [%w{point pt}, 0.000352777778, :typography, %w{<meter>}], #other '<cell>' => [%w{cells cell}, 1, :counting, %w{<each>}], '<each>' => [%w{each}, 1, :counting, %w{<each>}], '<count>' => [%w{count}, 1, :counting, %w{<each>}], '<base-pair>' => [%w{bp}, 1, :counting, %w{<each>}], '<nucleotide>' => [%w{nt}, 1, :counting, %w{<each>}], '<molecule>' => [%w{molecule molecules}, 1, :counting, %w{<1>}], '<dozen>' => [%w{doz dz dozen},12,:prefix_only, %w{<each>}], '<percent>'=> [%w{% percent}, Rational(1,100), :prefix_only, %w{<1>}], '<ppm>' => [%w{ppm},Rational(1,1e6),:prefix_only, %w{<1>}], '<ppt>' => [%w{ppt},Rational(1,1e9),:prefix_only, %w{<1>}], '<gross>' => [%w{gr gross},144, :prefix_only, %w{<dozen> <dozen>}], '<decibel>' => [%w{dB decibel decibels}, 1, :logarithmic, %w{<decibel>}] }
- @@USER_DEFINITIONS =
{}
- @@PREFIX_VALUES =
{}
- @@PREFIX_MAP =
{}
- @@UNIT_MAP =
{}
- @@UNIT_VALUES =
{}
- @@OUTPUT_MAP =
{}
- @@BASE_UNITS =
['<meter>','<kilogram>','<second>','<mole>', '<farad>', '<ampere>','<radian>','<kelvin>','<temp-K>','<byte>','<dollar>','<candela>','<each>','<steradian>','<decibel>']
- @@KINDS =
{ -312058=>:resistance, -312038=>:inductance, -152040=>:magnetism, -152038=>:magnetism, -152058=>:potential, -39=>:acceleration, -38=>:radiation, -20=>:frequency, -19=>:speed, -18=>:viscosity, 0=>:unitless, 1=>:length, 2=>:area, 3=>:volume, 20=>:time, 400=>:temperature, 7942=>:power, 7959=>:pressure, 7962=>:energy, 7979=>:viscosity, 7961=>:force, 7997=>:mass_concentration, 8000=>:mass, 159999=>:magnetism, 160000=>:current, 160020=>:charge, 312058=>:resistance, 3199980=>:activity, 3199997=>:molar_concentration, 3200000=>:substance, 63999998=>:illuminance, 64000000=>:luminous_power, 1280000000=>:currency, 25600000000=>:memory, 511999999980=>:angular_velocity, 512000000000=>:angle, 10240000000000=>:capacitance, }
- @@cached_units =
{}
- @@base_unit_cache =
{}
Instance Attribute Summary collapse
-
#base_denominator ⇒ Object
Returns the value of attribute base_denominator.
-
#base_numerator ⇒ Object
Returns the value of attribute base_numerator.
-
#base_scalar ⇒ Object
Returns the value of attribute base_scalar.
-
#denominator ⇒ Object
Returns the value of attribute denominator.
-
#numerator ⇒ Object
Returns the value of attribute numerator.
-
#output ⇒ Object
Returns the value of attribute output.
-
#scalar ⇒ Object
Returns the value of attribute scalar.
-
#signature ⇒ Object
Returns the value of attribute signature.
-
#unit_name ⇒ Object
Returns the value of attribute unit_name.
Class Method Summary collapse
- .base_unit_cache ⇒ Object
- .cached ⇒ Object
- .clear_cache ⇒ Object
-
.parse(input) ⇒ Object
parse strings like “1 minute in seconds”.
- .setup ⇒ Object
Instance Method Summary collapse
-
#%(other) ⇒ Object
perform a modulo on a unit, will raise an exception if the units are not compatible.
-
#*(other) ⇒ Object
Multiply two units.
-
#**(other) ⇒ Object
Exponentiate.
-
#+(other) ⇒ Object
Add two units together.
-
#-(other) ⇒ Object
Subtract two units.
-
#-@ ⇒ Object
negates the scalar of the Unit.
-
#/(other) ⇒ Object
Divide two units.
-
#<=>(other) ⇒ Object
Compare two Unit objects.
-
#==(other) ⇒ Object
Compare Units for equality this is necessary mostly for Complex units.
-
#===(other) ⇒ Object
(also: #same?, #same_as?)
Compare two units.
-
#=~(other) ⇒ Object
(also: #compatible?, #compatible_with?)
check to see if units are compatible, but not the scalar part this check is done by comparing signatures for performance reasons if passed a string, it will create a unit object with the string and then do the comparison this permits a syntax like: unit =~ “mm” if you want to do a regexp on the unit string do this …
- #abs ⇒ Object
-
#ago ⇒ Object
‘5 min’.unit.ago.
-
#before(time_point = ::Time.now) ⇒ Object
(also: #before_now)
‘5 min’.before(time).
- #ceil ⇒ Object
-
#coerce(other) ⇒ Object
automatically coerce objects to units when possible if an object defines a ‘to_unit’ method, it will be coerced using that method.
- #copy(from) ⇒ Object
-
#divmod(other) ⇒ Object
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.
- #floor ⇒ Object
-
#from(time_point = ::Time.now) ⇒ Object
(also: #after, #from_now)
‘5 min’.from(time).
-
#initialize(*options) ⇒ Unit
constructor
Create a new Unit object.
-
#inspect(option = nil) ⇒ Object
Normally pretty prints the unit, but if you really want to see the guts of it, pass ‘:dump’.
-
#inverse ⇒ Object
returns inverse of Unit (1/unit).
-
#is_base? ⇒ Boolean
(also: #base?)
Returns ‘true’ if the Unit is represented in base units.
-
#is_degree? ⇒ Boolean
(also: #degree?)
true if a degree unit or equivalent.
-
#is_temperature? ⇒ Boolean
(also: #temperature?)
true if unit is a ‘temperature’, false if a ‘degree’ or anything else.
- #kind ⇒ Object
-
#kind_of?(klass) ⇒ Boolean
needed to make complex units play nice – otherwise not detected as a complex_generic.
-
#power(n) ⇒ Object
returns the unit raised to the n-th power.
-
#pred ⇒ Object
returns next unit in a range.
-
#root(n) ⇒ Object
Calculates the n-th root of a unit, where n = (1..9) if n < 0, returns 1/unit^(1/n).
- #round ⇒ Object
-
#since(time_point = ::Time.now) ⇒ Object
‘min’.since(time).
-
#succ ⇒ Object
(also: #next)
returns next unit in a range.
-
#temperature_scale ⇒ Object
returns the ‘degree’ unit associated with a temperature unit ‘100 tempC’.unit.temperature_scale #=> ‘degC’.
-
#to(other) ⇒ Object
(also: #>>, #convert_to)
convert to a specified unit string or to the same units as another Unit.
-
#to_base ⇒ Object
(also: #base)
convert to base SI units results of the conversion are cached so subsequent calls to this will be fast.
-
#to_c ⇒ Object
converts the unit back to a complex if it is unitless.
- #to_date ⇒ Object
-
#to_datetime ⇒ Object
convert a duration to a DateTime.
-
#to_f ⇒ Object
converts the unit back to a float if it is unitless.
-
#to_i ⇒ Object
(also: #to_int)
if unitless, returns an int, otherwise raises an error.
-
#to_r ⇒ Object
if unitless, returns a Rational, otherwise raises an error.
-
#to_s(target_units = nil) ⇒ Object
Generate human readable output.
-
#to_time ⇒ Object
(also: #time)
Tries to make a Time object from current unit.
- #to_unit ⇒ Object (also: #unit)
- #to_yaml(opts = {}) ⇒ Object
- #to_yaml_properties ⇒ Object
- #truncate ⇒ Object
-
#unitless? ⇒ Boolean
returns true if no associated units false, even if the units are “unitless” like ‘radians, each, etc’.
-
#units ⇒ Object
returns the ‘unit’ part of the Unit object without the scalar.
-
#until(time_point = ::Time.now) ⇒ Object
‘min’.until(time).
-
#zero? ⇒ Boolean
true if scalar is zero.
Constructor Details
#initialize(*options) ⇒ Unit
Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime Valid formats include:
"5.6 kg*m/s^2"
"5.6 kg*m*s^-2"
"5.6 kilogram*meter*second^-2"
"2.2 kPa"
"37 degC"
"1" -- creates a unitless constant with value 1
"GPa" -- creates a unit with scalar 1 with units 'GPa'
6'4" -- recognized as 6 feet + 4 inches
8 lbs 8 oz -- recognized as 8 lbs + 8 ounces
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/rails_units/unit.rb', line 191 def initialize(*) @scalar = nil @base_scalar = nil @unit_name = nil @signature = nil @output = {} if .size == 2 # options[0] is the scalar # options[1] is a unit string begin cached = @@cached_units[[1]] * [0] copy(cached) rescue initialize("#{[0]} #{([1].units rescue [1])}") end return end if .size == 3 [1] = [1].join if [1].kind_of?(Array) [2] = [2].join if [2].kind_of?(Array) begin cached = @@cached_units["#{[1]}/#{[2]}"] * [0] copy(cached) rescue initialize("#{[0]} #{[1]}/#{[2]}") end return end case [0] when Hash @scalar = [0][:scalar] || 1 @numerator = [0][:numerator] || UNITY_ARRAY @denominator = [0][:denominator] || UNITY_ARRAY @signature = [0][:signature] when Array initialize(*[0]) return when Numeric @scalar = [0] @numerator = @denominator = UNITY_ARRAY when Time @scalar = [0].to_f @numerator = ['<second>'] @denominator = UNITY_ARRAY when DateTime, Date @scalar = [0].ajd @numerator = ['<day>'] @denominator = UNITY_ARRAY when /^\s*$/ raise ArgumentError, "No Unit Specified" when String parse([0]) else raise ArgumentError, "Invalid Unit Format" end self.update_base_scalar raise ArgumentError, "Temperatures must not be less than absolute zero" if self.is_temperature? && self.base_scalar < 0 unary_unit = self.units || "" if .first.instance_of?(String) opt_scalar, opt_units = Unit.parse_into_numbers_and_units([0]) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{TEMP_REGEX})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.unit) if opt_units && !opt_units.empty? end end unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{TEMP_REGEX}/) then @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit) end [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each {|x| x.freeze} self end |
Instance Attribute Details
#base_denominator ⇒ Object
Returns the value of attribute base_denominator.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def base_denominator @base_denominator end |
#base_numerator ⇒ Object
Returns the value of attribute base_numerator.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def base_numerator @base_numerator end |
#base_scalar ⇒ Object
Returns the value of attribute base_scalar.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def base_scalar @base_scalar end |
#denominator ⇒ Object
Returns the value of attribute denominator.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def denominator @denominator end |
#numerator ⇒ Object
Returns the value of attribute numerator.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def numerator @numerator end |
#output ⇒ Object
Returns the value of attribute output.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def output @output end |
#scalar ⇒ Object
Returns the value of attribute scalar.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def scalar @scalar end |
#signature ⇒ Object
Returns the value of attribute signature.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def signature @signature end |
#unit_name ⇒ Object
Returns the value of attribute unit_name.
143 144 145 |
# File 'lib/rails_units/unit.rb', line 143 def unit_name @unit_name end |
Class Method Details
.base_unit_cache ⇒ Object
280 281 282 |
# File 'lib/rails_units/unit.rb', line 280 def self.base_unit_cache return @@base_unit_cache end |
.cached ⇒ Object
270 271 272 |
# File 'lib/rails_units/unit.rb', line 270 def self.cached return @@cached_units end |
.clear_cache ⇒ Object
274 275 276 277 278 |
# File 'lib/rails_units/unit.rb', line 274 def self.clear_cache @@cached_units = {} @@base_unit_cache = {} Unit.new(1) end |
.parse(input) ⇒ Object
parse strings like “1 minute in seconds”
287 288 289 290 |
# File 'lib/rails_units/unit.rb', line 287 def self.parse(input) first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first second.nil? ? first.unit : first.unit.to(second) end |
.setup ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/rails_units/unit.rb', line 116 def self.setup @@ALL_UNIT_DEFINITIONS = UNIT_DEFINITIONS.merge!(@@USER_DEFINITIONS) for unit in (@@ALL_UNIT_DEFINITIONS) do key, value = unit if value[2] == :prefix then @@PREFIX_VALUES[key]=value[1] for name in value[0] do @@PREFIX_MAP[name]=key end else @@UNIT_VALUES[key]={} @@UNIT_VALUES[key][:scalar]=value[1] @@UNIT_VALUES[key][:numerator]=value[3] if value[3] @@UNIT_VALUES[key][:denominator]=value[4] if value[4] for name in value[0] do @@UNIT_MAP[name]=key 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_name| [unit_name.length, unit]}.reverse.join('|') @@UNIT_MATCH_REGEX = /(#{@@PREFIX_REGEX})*?(#{@@UNIT_REGEX})\b/ Unit.new(1) end |
Instance Method Details
#%(other) ⇒ Object
perform a modulo on a unit, will raise an exception if the units are not compatible
634 635 636 |
# File 'lib/rails_units/unit.rb', line 634 def %(other) self.divmod(other).last end |
#*(other) ⇒ Object
Multiply two units.
587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
# File 'lib/rails_units/unit.rb', line 587 def *(other) case other when Unit raise ArgumentError, "Cannot multiply by temperatures" if [other,self].any? {|x| x.is_temperature?} opts = Unit.eliminate_terms(@scalar*other.scalar, @numerator + other.numerator ,@denominator + other.denominator) opts.merge!(:signature => @signature + other.signature) Unit.new(opts) when Numeric Unit.new(:scalar=>@scalar*other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) else x,y = coerce(other) x * y end end |
#**(other) ⇒ Object
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 It should then convert the float to a rational and raise the unit by the numerator and root it by the denominator but, sadly, floats can’t be converted to rationals.
For now, if a rational is passed in, it will be used, otherwise we are stuck with integers and certain floats < 1
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
# File 'lib/rails_units/unit.rb', line 646 def **(other) raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? if other.kind_of?(Numeric) return self.inverse if other == -1 return self if other == 1 return 1 if other.zero? end case other when Rational self.power(other.numerator).root(other.denominator) when Integer self.power(other) 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) when Complex raise ArgumentError, "exponentiation of complex numbers is not yet supported." else raise ArgumentError, "Invalid Exponent" end end |
#+(other) ⇒ Object
Add two units together. Result is same units as receiver and scalar and base_scalar are updated appropriately throws an exception if the units are not compatible. It is possible to add Time objects to units of time
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
# File 'lib/rails_units/unit.rb', line 526 def +(other) case other when Unit case 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?} 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}')" end when Date, Time raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be added to a Unit" else x,y = coerce(other) y + x end end |
#-(other) ⇒ Object
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.
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
# File 'lib/rails_units/unit.rb', line 557 def -(other) case other when Unit case when self.zero? -other.dup when self =~ other case 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? Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => ['<temp-K>'], :denominator => UNITY_ARRAY, :signature => @signature).to(self) 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 else raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" end when Time raise ArgumentError, "Date and Time objects represent fixed points in time and cannot be subtracted from to a Unit, which can only represent time spans" else x,y = coerce(other) y-x end end |
#-@ ⇒ Object
negates the scalar of the Unit
868 869 870 871 |
# File 'lib/rails_units/unit.rb', line 868 def -@ return -@scalar if self.unitless? self.dup * -1 end |
#/(other) ⇒ Object
Divide two units. Throws an exception if divisor is 0
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
# File 'lib/rails_units/unit.rb', line 604 def /(other) case other when Unit raise ZeroDivisionError if other.zero? raise ArgumentError, "Cannot divide with temperatures" if [other,self].any? {|x| x.is_temperature?} opts = Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator ,@denominator + other.numerator) opts.merge!(:signature=> @signature - other.signature) Unit.new(opts) when Numeric raise ZeroDivisionError if other.zero? Unit.new(:scalar=>@scalar/other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) else x,y = coerce(other) y / x end end |
#<=>(other) ⇒ Object
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.
452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/rails_units/unit.rb', line 452 def <=>(other) case when !self.base_scalar.respond_to?(:<=>) raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" when !self.is_temperature? && other.zero? return self.base_scalar <=> 0 when other.instance_of?(Unit) raise ArgumentError, "Incompatible Units (#{self.units} !~ #{other.units})" unless self =~ other return self.base_scalar <=> other.base_scalar else x,y = coerce(other) return x <=> y end end |
#==(other) ⇒ Object
Compare Units for equality this is necessary mostly for Complex units. Complex units do not have a <=> operator so we define this one here so that we can properly check complex units for equality. Units of incompatible types are not equal, except when they are both zero and neither is a temperature Equality checks can be tricky since round off errors may make essentially equivalent units appear to be different.
473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/rails_units/unit.rb', line 473 def ==(other) case when other.respond_to?(:zero?) && other.zero? return self.zero? when other.instance_of?(Unit) return false unless self =~ other return self.base_scalar == other.base_scalar else x,y = coerce(other) return x == y end end |
#===(other) ⇒ Object Also known as: same?, same_as?
Compare two units. Returns true if quantities and units match
Unit(“100 cm”) === Unit(“100 cm”) # => true Unit(“100 cm”) === Unit(“1 m”) # => false
510 511 512 513 514 515 516 517 518 |
# File 'lib/rails_units/unit.rb', line 510 def ===(other) case other when Unit (self.scalar == other.scalar) && (self.units == other.units) else x,y = coerce(other) x === y end end |
#=~(other) ⇒ Object Also known as: compatible?, compatible_with?
check to see if units are compatible, but not the scalar part this check is done by comparing signatures for performance reasons if passed a string, it will create a unit object with the string and then do the comparison this permits a syntax like:
unit =~ "mm"
if you want to do a regexp on the unit string do this …
unit.units =~ /regexp/
493 494 495 496 497 498 499 500 501 |
# File 'lib/rails_units/unit.rb', line 493 def =~(other) case other when Unit self.signature == other.signature else x,y = coerce(other) x =~ y end end |
#abs ⇒ Object
873 874 875 876 |
# File 'lib/rails_units/unit.rb', line 873 def abs return @scalar.abs if self.unitless? Unit.new(@scalar.abs, @numerator, @denominator) end |
#ago ⇒ Object
‘5 min’.unit.ago
938 939 940 |
# File 'lib/rails_units/unit.rb', line 938 def ago self.before end |
#before(time_point = ::Time.now) ⇒ Object Also known as: before_now
‘5 min’.before(time)
943 944 945 946 947 948 949 950 |
# File 'lib/rails_units/unit.rb', line 943 def before(time_point = ::Time.now) raise ArgumentError, "Must specify a Time" unless time_point if String === time_point time_point.time - self rescue time_point.datetime - self else time_point - self rescue time_point.to_datetime - self end end |
#ceil ⇒ Object
878 879 880 881 |
# File 'lib/rails_units/unit.rb', line 878 def ceil return @scalar.ceil if self.unitless? Unit.new(@scalar.ceil, @numerator, @denominator) end |
#coerce(other) ⇒ Object
automatically coerce objects to units when possible if an object defines a ‘to_unit’ method, it will be coerced using that method
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
# File 'lib/rails_units/unit.rb', line 997 def coerce(other) if other.respond_to? :to_unit return [other.to_unit, self] end case other when Unit [other, self] else [Unit.new(other), self] end end |
#copy(from) ⇒ Object
155 156 157 158 159 160 161 162 163 |
# File 'lib/rails_units/unit.rb', line 155 def copy(from) @scalar = from.scalar @numerator = from.numerator @denominator = from.denominator @is_base = from.is_base? @signature = from.signature @base_scalar = from.base_scalar @unit_name = from.unit_name rescue nil end |
#divmod(other) ⇒ Object
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
624 625 626 627 628 629 630 631 |
# File 'lib/rails_units/unit.rb', line 624 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 |
#floor ⇒ Object
883 884 885 886 |
# File 'lib/rails_units/unit.rb', line 883 def floor return @scalar.floor if self.unitless? Unit.new(@scalar.floor, @numerator, @denominator) end |
#from(time_point = ::Time.now) ⇒ Object Also known as: after, from_now
‘5 min’.from(time)
982 983 984 985 986 987 988 989 |
# File 'lib/rails_units/unit.rb', line 982 def from(time_point = ::Time.now) raise ArgumentError, "Must specify a Time" unless time_point if String === time_point time_point.time + self rescue time_point.datetime + self else time_point + self rescue time_point.to_datetime + self end end |
#inspect(option = nil) ⇒ Object
Normally pretty prints the unit, but if you really want to see the guts of it, pass ‘:dump’
419 420 421 422 |
# File 'lib/rails_units/unit.rb', line 419 def inspect(option=nil) return super() if option == :dump self.to_s end |
#inverse ⇒ Object
returns inverse of Unit (1/unit)
715 716 717 |
# File 'lib/rails_units/unit.rb', line 715 def inverse Unit("1") / self end |
#is_base? ⇒ Boolean Also known as: base?
Returns ‘true’ if the Unit is represented in base units
298 299 300 301 302 303 304 305 306 |
# File 'lib/rails_units/unit.rb', line 298 def is_base? return @is_base if defined? @is_base 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 end |
#is_degree? ⇒ Boolean Also known as: degree?
true if a degree unit or equivalent.
431 432 433 |
# File 'lib/rails_units/unit.rb', line 431 def is_degree? self.kind == :temperature end |
#is_temperature? ⇒ Boolean Also known as: temperature?
true if unit is a ‘temperature’, false if a ‘degree’ or anything else
425 426 427 |
# File 'lib/rails_units/unit.rb', line 425 def is_temperature? self.is_degree? && (!(self.units =~ /temp[CFRK]/).nil?) end |
#kind ⇒ Object
266 267 268 |
# File 'lib/rails_units/unit.rb', line 266 def kind return @@KINDS[self.signature] end |
#kind_of?(klass) ⇒ Boolean
needed to make complex units play nice – otherwise not detected as a complex_generic
151 152 153 |
# File 'lib/rails_units/unit.rb', line 151 def kind_of?(klass) self.scalar.kind_of?(klass) end |
#power(n) ⇒ Object
returns the unit raised to the n-th power. Integers only
671 672 673 674 675 676 677 678 679 680 681 682 |
# File 'lib/rails_units/unit.rb', line 671 def power(n) raise ArgumentError, "Cannot raise a temperature to a power" if self.is_temperature? raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) return self.inverse if n == -1 return 1 if n.zero? return self if n == 1 if n > 0 then (1..(n-1).to_i).inject(self) {|product, x| product * self} else (1..-(n-1).to_i).inject(self) {|product, x| product / self} end end |
#pred ⇒ Object
returns next unit in a range. ‘1 mm’.unit.succ #=> ‘2 mm’.unit only works when the scalar is an integer
908 909 910 911 |
# File 'lib/rails_units/unit.rb', line 908 def pred raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i Unit.new(@scalar.to_i.pred, @numerator, @denominator) end |
#root(n) ⇒ Object
Calculates the n-th root of a unit, where n = (1..9) if n < 0, returns 1/unit^(1/n)
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'lib/rails_units/unit.rb', line 686 def root(n) raise ArgumentError, "Cannot take the root of a temperature" if self.is_temperature? raise ArgumentError, "Exponent must an Integer" unless n.kind_of?(Integer) raise ArgumentError, "0th root undefined" if n.zero? return self if n == 1 return self.root(n.abs).inverse if n < 0 vec = self.unit_signature_vector vec=vec.map {|x| x % n} raise ArgumentError, "Illegal root" unless vec.max == 0 num = @numerator.dup 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 {|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 {|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 |
#round ⇒ Object
888 889 890 891 |
# File 'lib/rails_units/unit.rb', line 888 def round return @scalar.round if self.unitless? Unit.new(@scalar.round, @numerator, @denominator) end |
#since(time_point = ::Time.now) ⇒ Object
‘min’.since(time)
954 955 956 957 958 959 960 961 962 963 964 965 |
# File 'lib/rails_units/unit.rb', line 954 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.to_datetime(:context=>:past)).unit('d').to(self) else raise ArgumentError, "Must specify a Time, DateTime, or String" end end |
#succ ⇒ Object Also known as: next
returns next unit in a range. ‘1 mm’.unit.succ #=> ‘2 mm’.unit only works when the scalar is an integer
900 901 902 903 |
# File 'lib/rails_units/unit.rb', line 900 def succ raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i Unit.new(@scalar.to_i.succ, @numerator, @denominator) end |
#temperature_scale ⇒ Object
returns the ‘degree’ unit associated with a temperature unit ‘100 tempC’.unit.temperature_scale #=> ‘degC’
438 439 440 441 442 |
# File 'lib/rails_units/unit.rb', line 438 def temperature_scale return nil unless self.is_temperature? self.units =~ /temp([CFRK])/ "deg#{$1}" end |
#to(other) ⇒ Object Also known as: >>, convert_to
convert to a specified unit string or to the same units as another Unit
unit >> "kg" will covert to kilograms
unit1 >> unit2 converts to same units as unit2 object
To convert a Unit object to match another Unit object, use:
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, 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.
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/rails_units/unit.rb', line 734 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[CFRK]/) 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)*Rational(5,9) when 'tempR' @scalar*Rational(5,9) end end q= case target_unit when 'tempC' @base_scalar - 273.15 when 'tempK' @base_scalar when 'tempF' @base_scalar * Rational(9,5) - 459.67 when 'tempR' @base_scalar * Rational(9,5) 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 raise ArgumentError, "Incompatible Units" unless self =~ target _numerator1 = @numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact _denominator1 = @denominator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|i| i.kind_of?(Numeric) ? i : @@UNIT_VALUES[i][:scalar] }.compact _numerator2 = target.numerator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact _denominator2 = target.denominator.map {|x| @@PREFIX_VALUES[x] ? @@PREFIX_VALUES[x] : x}.map {|x| x.kind_of?(Numeric) ? x : @@UNIT_VALUES[x][:scalar] }.compact # eliminate common terms (_numerator1 & _denominator2).each do |common| _numerator1.delete(common) _denominator2.delete(common) end (_numerator2 & _denominator1).each do |common| _numerator1.delete(common) _denominator2.delete(common) end q = @scalar * ( (_numerator1 + _denominator2).inject(1) {|product,n| product*n} ) / ( (_numerator2 + _denominator1).inject(1) {|product,n| product*n} ) Unit.new(:scalar=>q, :numerator=>target.numerator, :denominator=>target.denominator, :signature => target.signature) end end |
#to_base ⇒ Object Also known as: base
convert to base SI units results of the conversion are cached so subsequent calls to this will be fast
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/rails_units/unit.rb', line 311 def to_base return self if self.is_base? if self.units =~ /\A(?:temp|deg)[CRF]\Z/ if RUBY_VERSION < "1.9" @signature = @@KINDS.index(:temperature) else #:nocov: @signature = @@KINDS.key(:temperature) #:nocov: end base = case when self.is_temperature? self.to('tempK') when self.is_degree? 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 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 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 return base * @scalar end |
#to_c ⇒ Object
converts the unit back to a complex if it is unitless. Otherwise raises an exception
810 811 812 813 |
# File 'lib/rails_units/unit.rb', line 810 def to_c return Complex(@scalar) if self.unitless? raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" end |
#to_date ⇒ Object
927 928 929 |
# File 'lib/rails_units/unit.rb', line 927 def to_date Date.new0(self.to('d').scalar) end |
#to_datetime ⇒ Object
convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date defined by DateTime
923 924 925 |
# File 'lib/rails_units/unit.rb', line 923 def to_datetime DateTime.new!(self.to('d').scalar) end |
#to_f ⇒ Object
converts the unit back to a float if it is unitless. Otherwise raises an exception
804 805 806 807 |
# File 'lib/rails_units/unit.rb', line 804 def to_f return @scalar.to_f if self.unitless? raise RuntimeError, "Cannot convert '#{self.to_s}' to Float unless unitless. Use Unit#scalar" end |
#to_i ⇒ Object Also known as: to_int
if unitless, returns an int, otherwise raises an error
816 817 818 819 |
# File 'lib/rails_units/unit.rb', line 816 def to_i return @scalar.to_int if self.unitless? raise RuntimeError, "Cannot convert '#{self.to_s}' to Integer unless unitless. Use Unit#scalar" end |
#to_r ⇒ Object
if unitless, returns a Rational, otherwise raises an error
823 824 825 826 |
# File 'lib/rails_units/unit.rb', line 823 def to_r return @scalar.to_r if self.unitless? raise RuntimeError, "Cannot convert '#{self.to_s}' to Rational unless unitless. Use Unit#scalar" end |
#to_s(target_units = nil) ⇒ Object
Generate human readable output. If the name of a unit is passed, the unit will first be converted to the target unit before output. some named conversions are available
:ft - outputs in feet and inches (e.g., 6'4")
:lbs - outputs in pounds and ounces (e.g, 8 lbs, 8 oz)
You can also pass a standard format string (i.e., ‘%0.2f’) or a strftime format string.
output is cached so subsequent calls for the same format will be fast
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/rails_units/unit.rb', line 376 def to_s(target_units=nil) out = @output[target_units] if out return out else case target_units when :ft inches = self.to("in").scalar.to_int out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" 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#]+)\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 end rescue (DateTime.new(0) + self).strftime(target_units) end when /(\S+)/ #unit only 'mm' or '1/mm' "#{self.to($1).to_s}" else raise "unhandled case" end else out = case @scalar when Rational "#{@scalar} #{self.units}" else "#{'%g' % @scalar} #{self.units}" end.strip end @output[target_units] = out return out end end |
#to_time ⇒ Object Also known as: time
Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch.
915 916 917 |
# File 'lib/rails_units/unit.rb', line 915 def to_time Time.at(self) end |
#to_unit ⇒ Object Also known as: unit
292 293 294 |
# File 'lib/rails_units/unit.rb', line 292 def to_unit self end |
#to_yaml(opts = {}) ⇒ Object
168 169 170 171 172 173 174 175 176 |
# File 'lib/rails_units/unit.rb', line 168 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 |
#to_yaml_properties ⇒ Object
145 146 147 |
# File 'lib/rails_units/unit.rb', line 145 def to_yaml_properties %w{@scalar @numerator @denominator @signature @base_scalar} end |
#truncate ⇒ Object
893 894 895 896 |
# File 'lib/rails_units/unit.rb', line 893 def truncate return @scalar.truncate if self.unitless? Unit.new(@scalar.truncate, @numerator, @denominator) end |
#unitless? ⇒ Boolean
returns true if no associated units false, even if the units are “unitless” like ‘radians, each, etc’
446 447 448 |
# File 'lib/rails_units/unit.rb', line 446 def unitless? (@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) end |
#units ⇒ Object
returns the ‘unit’ part of the Unit object without the scalar
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 |
# File 'lib/rails_units/unit.rb', line 829 def units return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY return @unit_name unless @unit_name.nil? output_n = [] output_d =[] num = @numerator.clone.compact den = @denominator.clone.compact if @numerator == UNITY_ARRAY output_n << "1" else num.each_with_index do |token,index| if token && @@PREFIX_VALUES[token] then output_n << "#{@@OUTPUT_MAP[token]}#{@@OUTPUT_MAP[num[index+1]]}" num[index+1]=nil else output_n << "#{@@OUTPUT_MAP[token]}" if token end end 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 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 return out end |
#until(time_point = ::Time.now) ⇒ Object
‘min’.until(time)
968 969 970 971 972 973 974 975 976 977 978 979 |
# File 'lib/rails_units/unit.rb', line 968 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 (time_point.to_datetime(:context=>:future) - DateTime.now).unit('d').to(self) else raise ArgumentError, "Must specify a Time, DateTime, or String" end end |
#zero? ⇒ Boolean
true if scalar is zero
933 934 935 |
# File 'lib/rails_units/unit.rb', line 933 def zero? return self.base_scalar.zero? end |