From 4afece5b3d010675606fad0579cd1a82bb80a8d8 Mon Sep 17 00:00:00 2001 From: Aaron Graves Date: Fri, 17 May 2013 15:02:48 -0400 Subject: [PATCH 001/150] Fix YAML test failure --- spec/ruby-units/unit_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index dc08adb0..408d7698 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1,4 +1,5 @@ require File.dirname(__FILE__) + '/../spec_helper' +require 'yaml' describe Unit.base_units do it {should be_a Array} From c26a41678edeef2764bbb97edba4e81235e00990 Mon Sep 17 00:00:00 2001 From: Aaron Graves Date: Fri, 17 May 2013 15:06:44 -0400 Subject: [PATCH 002/150] Remove non-existent RakeFile from gemspec --- ruby-units.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 01a25952..2da76b54 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| "CHANGELOG.txt", "LICENSE.txt", "README.md", - "RakeFile", + "Rakefile.rb", "TODO", "VERSION", "lib/ruby-units.rb", From 52d9e0502079a8a5cb1800c885ad246cbf62368c Mon Sep 17 00:00:00 2001 From: Aaron Graves Date: Fri, 17 May 2013 14:26:24 -0400 Subject: [PATCH 003/150] Support passing Time objects to Time.at --- lib/ruby_units/time.rb | 2 ++ spec/ruby-units/time_spec.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index 9ac59f5d..f3100078 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -16,6 +16,8 @@ class << self # @return [Unit, Time] def self.at(arg,ms=0) case arg + when Time + unit_time_at(arg) when Unit unit_time_at(arg.convert_to("s").scalar, ms) else diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby-units/time_spec.rb index 019cd993..96492874 100644 --- a/spec/ruby-units/time_spec.rb +++ b/spec/ruby-units/time_spec.rb @@ -8,6 +8,7 @@ context ".at" do subject { Date.new(2011,4,1).to_unit } + specify { Time.at(Time.at(0)).utc.strftime("%D %T").should == "01/01/70 00:00:00" } specify { Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T").should == "04/01/11 00:00:00"} specify { Time.at(subject - Date.new(1970,1,1), 500).usec.should == 500} end From 633e434971d80887bdb8c3e332e488b7094f02f7 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 12 Jun 2013 03:29:59 +0000 Subject: [PATCH 004/150] Version bump to 1.4.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c9929e36..3c80e4f0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.2 \ No newline at end of file +1.4.3 \ No newline at end of file From 26b9e3e728a84732cae4885c3dfcf90a1d64989f Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 12 Jun 2013 03:30:19 +0000 Subject: [PATCH 005/150] update changelog and bump version --- CHANGELOG.txt | 7 +++++++ Gemfile | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e868ebc7..436143b9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,12 @@ Change Log for Ruby-units ========================= +2013-06-11 1.4.3 * Fix issue #70 -- Support passing Time objects to Time.at + * Fix issue #72 -- Remove non-existent RakeFile from gemspec + * Fix issue #71 -- Fix YAML test failure + * Fix issue #49 -- Unit instances constructed using other Unit instances are incompatible within the framework + * Fix issue #61 -- Fix failing case of subtraction losing Units class + * Fix issue #63 -- fixes an issue with to_date on 1.8.7 + * Fix issue #64 -- Aliases aren't considered in Unit.defined? method 2012-09-16 1.4.2 * Fix issue #54 -- pluralization of fluid-ounces * Fix issue #53, 51 -- incorrect definition for gee * Fix issue #52 -- add support for degree symbol diff --git a/Gemfile b/Gemfile index a5f30db9..6d48215f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" group :development do gem 'bundler', '~> 1.0' From 23824cbb5ebcf322b21dfa3dbda19fd3f514f45d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 12 Jun 2013 03:33:25 +0000 Subject: [PATCH 006/150] Regenerate gemspec for version 1.4.3 --- ruby-units.gemspec | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 2da76b54..507958f5 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -1,15 +1,15 @@ # Generated by jeweler # DO NOT EDIT THIS FILE DIRECTLY -# Instead, edit Jeweler::Tasks in RakeFile, and run 'rake gemspec' +# Instead, edit Jeweler::Tasks in Rakefile.rb, and run 'rake gemspec' # -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = "ruby-units" - s.version = "1.4.2" + s.version = "1.4.3" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2012-09-16" + s.date = "2013-06-12" s.description = "Provides classes and methods to perform unit math and conversions" s.email = ["kevin.olbrich+ruby_units@gmail.com"] s.extra_rdoc_files = [ @@ -56,29 +56,14 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, ["~> 1.0"]) - s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, ["~> 2.5"]) - s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, ["~> 1.0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, ["~> 2.5"]) - s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, ["~> 1.0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, ["~> 2.5"]) - s.add_dependency(%q, [">= 0"]) end end From 12b6139362c87d71a0405b79f37f58ef58ce981d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 12 Jun 2013 03:34:34 +0000 Subject: [PATCH 007/150] Regenerate gemspec for version 1.4.3 --- ruby-units.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 507958f5..3db13b84 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -48,7 +48,7 @@ Gem::Specification.new do |s| s.licenses = ["MIT"] s.post_install_message = "====================\nDeprecation Warning\n====================\n\nSeveral convenience methods that ruby-units added to the string class have\nbeen deprecated in this release. These methods include String#to, String#from, String#ago, String#before and others.\nIf your code relies on these functions, they can be added back by adding this line to your code.\n\nrequire 'ruby-units/string/extras'\n# note that these methods do not play well with Rails, which is one of the reasons they are being removed.\n\nThe extra functions mostly work the same, but will no longer properly handle cases when they are called with strings..\n\n'min'.from(\"4-1-2011\") # => Exception\n\nPass in a Date, Time, or DateTime object to get the expected result.\n\nThey will go away completely in the next release, so it would be a good idea to refactor your code\nto avoid using them. They will also throw deprecation warnings when they are used.\n" s.require_paths = ["lib"] - s.rubygems_version = "1.8.24" + s.rubygems_version = "1.8.25" s.summary = "A class that performs unit conversions and unit math" if s.respond_to? :specification_version then From 2cbdd3759e45749b4e744156dfafaa8d7a9eaf14 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 11:00:47 -0400 Subject: [PATCH 008/150] add RubyUnits namespace to Unit --- lib/ruby-units.rb | 18 +- lib/ruby_units/array.rb | 8 +- lib/ruby_units/cache.rb | 4 +- lib/ruby_units/definition.rb | 12 +- lib/ruby_units/fixnum.rb | 4 +- lib/ruby_units/math.rb | 24 +- lib/ruby_units/namespaced.rb | 14 + lib/ruby_units/numeric.rb | 6 +- lib/ruby_units/string.rb | 10 +- lib/ruby_units/time.rb | 16 +- lib/ruby_units/unit.rb | 2780 ++++++++++--------- lib/ruby_units/unit_definitions/base.rb | 30 +- lib/ruby_units/unit_definitions/prefix.rb | 4 +- lib/ruby_units/unit_definitions/standard.rb | 536 ++-- lib/ruby_units/version.rb | 12 +- spec/ruby-units/unit_spec.rb | 4 +- 16 files changed, 1751 insertions(+), 1731 deletions(-) create mode 100644 lib/ruby_units/namespaced.rb diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index b6e8b020..820e4f30 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -1,14 +1,6 @@ + $LOAD_PATH << File.dirname(__FILE__) -require "ruby_units/version" -require "ruby_units/definition" -require "ruby_units/cache" -require 'ruby_units/array' -require 'ruby_units/date' -require 'ruby_units/time' -require 'ruby_units/math' -require 'ruby_units/numeric' -require 'ruby_units/object' -require 'ruby_units/string' -require 'ruby_units/unit' -require 'ruby_units/fixnum' -require 'ruby_units/unit_definitions' + +require 'ruby_units/namespaced' + +Unit = RubyUnits::Unit diff --git a/lib/ruby_units/array.rb b/lib/ruby_units/array.rb index a3a7ee6c..413d0ddd 100644 --- a/lib/ruby_units/array.rb +++ b/lib/ruby_units/array.rb @@ -1,11 +1,11 @@ class Array # Construct a unit from an array - # @example [1, 'mm'].to_unit => Unit("1 mm") - # @return (see Unit#initialize) + # @example [1, 'mm'].to_unit => RubyUnits::Unit("1 mm") + # @return (see RubyUnits::Unit#initialize) # @param [Object] other convert to same units as passed def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit -end \ No newline at end of file +end diff --git a/lib/ruby_units/cache.rb b/lib/ruby_units/cache.rb index 6a65379c..6eaaccaa 100644 --- a/lib/ruby_units/cache.rb +++ b/lib/ruby_units/cache.rb @@ -1,4 +1,4 @@ -class Unit < Numeric +class RubyUnits::Unit < Numeric @@cached_units = {} class Cache @@ -17,4 +17,4 @@ def self.clear end end -end \ No newline at end of file +end diff --git a/lib/ruby_units/definition.rb b/lib/ruby_units/definition.rb index 7fd0b406..2db7df80 100644 --- a/lib/ruby_units/definition.rb +++ b/lib/ruby_units/definition.rb @@ -1,4 +1,4 @@ -class Unit < Numeric +class RubyUnits::Unit < Numeric # Handle the definition of units class Definition @@ -36,8 +36,8 @@ def initialize(_name, _definition = [], &block) @aliases ||= (_definition[0] || [_name]) @scalar ||= _definition[1] @kind ||= _definition[2] - @numerator ||= _definition[3] || Unit::UNITY_ARRAY - @denominator ||= _definition[4] || Unit::UNITY_ARRAY + @numerator ||= _definition[3] || RubyUnits::Unit::UNITY_ARRAY + @denominator ||= _definition[4] || RubyUnits::Unit::UNITY_ARRAY @display_name ||= @aliases.first end @@ -90,11 +90,11 @@ def unity? # units are base units if the scalar is one, and the unit is defined in terms of itself. # @return [Boolean] def base? - (self.denominator == Unit::UNITY_ARRAY) && - (self.numerator != Unit::UNITY_ARRAY) && + (self.denominator == RubyUnits::Unit::UNITY_ARRAY) && + (self.numerator != RubyUnits::Unit::UNITY_ARRAY) && (self.numerator.size == 1) && (self.scalar == 1) && (self.numerator.first == self.name) end end -end \ No newline at end of file +end diff --git a/lib/ruby_units/fixnum.rb b/lib/ruby_units/fixnum.rb index 3101bca9..376f36c8 100644 --- a/lib/ruby_units/fixnum.rb +++ b/lib/ruby_units/fixnum.rb @@ -8,7 +8,7 @@ class Fixnum # @return [Unit, Integer] def quo_with_units(other) case other - when Unit + when RubyUnits::Unit self * other.inverse else quo_without_units(other) @@ -19,4 +19,4 @@ def quo_with_units(other) alias / quo_with_units end # :nocov_19: -end \ No newline at end of file +end diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index 5b2bf1b5..5eea1838 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -7,7 +7,7 @@ module Math alias :unit_sqrt :sqrt # @return [Numeric] def sqrt(n) - if Unit === n + if RubyUnits::Unit === n (n**(Rational(1,2))).to_unit else unit_sqrt(n) @@ -23,7 +23,7 @@ def sqrt(n) alias :unit_cbrt :cbrt # @return [Numeric] def cbrt(n) - if Unit === n + if RubyUnits::Unit === n (n**(Rational(1,3))).to_unit else unit_cbrt(n) @@ -39,7 +39,7 @@ def cbrt(n) alias :unit_sin :sin # @return [Numeric] def sin(n) - Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) + RubyUnits::Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) end # @return [Numeric] module_function :unit_sin @@ -49,7 +49,7 @@ def sin(n) alias :unit_cos :cos # @return [Numeric] def cos(n) - Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n) + RubyUnits::Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n) end # @return [Numeric] module_function :unit_cos @@ -59,7 +59,7 @@ def cos(n) alias :unit_sinh :sinh # @return [Numeric] def sinh(n) - Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n) + RubyUnits::Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n) end # @return [Numeric] module_function :unit_sinh @@ -69,7 +69,7 @@ def sinh(n) alias :unit_cosh :cosh # @return [Numeric] def cosh(n) - Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n) + RubyUnits::Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n) end # @return [Numeric] module_function :unit_cosh @@ -79,7 +79,7 @@ def cosh(n) alias :unit_tan :tan # @return [Numeric] def tan(n) - Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) + RubyUnits::Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) end # @return [Numeric] module_function :tan @@ -89,7 +89,7 @@ def tan(n) alias :unit_tanh :tanh # @return [Numeric] def tanh(n) - Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n) + RubyUnits::Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n) end # @return [Numeric] module_function :unit_tanh @@ -100,7 +100,7 @@ def tanh(n) # Convert parameters to consistent units and perform the function # @return [Numeric] def hypot(x,y) - if Unit === x && Unit === y + if RubyUnits::Unit === x && RubyUnits::Unit === y (x**2 + y**2)**(1/2) else unit_hypot(x,y) @@ -115,9 +115,9 @@ def hypot(x,y) # @return [Numeric] def atan2(x,y) case - when (x.is_a?(Unit) && y.is_a?(Unit)) && (x !~ y) - raise ArgumentError, "Incompatible Units" - when (x.is_a?(Unit) && y.is_a?(Unit)) && (x =~ y) + when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x !~ y) + raise ArgumentError, "Incompatible RubyUnits::Units" + when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x =~ y) Math::unit_atan2(x.base_scalar, y.base_scalar) else Math::unit_atan2(x,y) diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb new file mode 100644 index 00000000..2efc61e1 --- /dev/null +++ b/lib/ruby_units/namespaced.rb @@ -0,0 +1,14 @@ +# require this file to avoid creating an class alias from Unit to RubyUnits::Unit +require "ruby_units/version" +require "ruby_units/definition" +require "ruby_units/cache" +require 'ruby_units/array' +require 'ruby_units/date' +require 'ruby_units/time' +require 'ruby_units/math' +require 'ruby_units/numeric' +require 'ruby_units/object' +require 'ruby_units/string' +require 'ruby_units/unit' +require 'ruby_units/fixnum' +require 'ruby_units/unit_definitions' diff --git a/lib/ruby_units/numeric.rb b/lib/ruby_units/numeric.rb index 136787cd..75190b2b 100644 --- a/lib/ruby_units/numeric.rb +++ b/lib/ruby_units/numeric.rb @@ -1,9 +1,9 @@ class Numeric # make a unitless unit with a given scalar - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self, other) : Unit.new(self) + other ? RubyUnits::Unit.new(self, other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit -end \ No newline at end of file +end diff --git a/lib/ruby_units/string.rb b/lib/ruby_units/string.rb index fd820f34..61c0edda 100644 --- a/lib/ruby_units/string.rb +++ b/lib/ruby_units/string.rb @@ -1,9 +1,9 @@ require 'time' class String # make a string into a unit - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit @@ -16,7 +16,7 @@ def to_unit(other = nil) def %(*args) return "" if self.empty? case - when args.first.is_a?(Unit) + when args.first.is_a?(RubyUnits::Unit) args.first.to_s(self) when (!defined?(Uncertain).nil? && args.first.is_a?(Uncertain)) args.first.to_s(self) @@ -27,8 +27,8 @@ def %(*args) end end - # @param (see Unit#convert_to) - # @return (see Unit#convert_to) + # @param (see RubyUnits::Unit#convert_to) + # @return (see RubyUnits::Unit#convert_to) def convert_to(other) self.unit.convert_to(other) end diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index f3100078..020c602e 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -13,21 +13,21 @@ class << self # epoch # @param [Time] arg # @param [Integer] ms - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def self.at(arg,ms=0) case arg when Time unit_time_at(arg) - when Unit + when RubyUnits::Unit unit_time_at(arg.convert_to("s").scalar, ms) else unit_time_at(arg, ms) end end - # @return (see Unit#initialize) + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit alias :u :to_unit @@ -39,10 +39,10 @@ def to_unit(other = nil) end alias :unit_add :+ - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def +(other) case other - when Unit + when RubyUnits::Unit other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_add(other.convert_to('s').scalar) @@ -63,10 +63,10 @@ def self.in(duration) alias :unit_sub :- - # @return [Unit, Time] + # @return [RubyUnits::Unit, Time] def -(other) case other - when Unit + when RubyUnits::Unit other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_sub(other.convert_to('s').scalar) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 2bbac52e..200be03b 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -23,7 +23,7 @@ # # To add or override a unit definition, add a code block like this.. # @example Define a new unit -# Unit.define("foobar") do |unit| +# RubyUnits::Unit.define("foobar") do |unit| # unit.aliases = %w{foo fb foo-bar} # unit.definition = Unit("1 baz") # end @@ -32,1560 +32,1572 @@ # @todo pull caching out into its own class # @todo refactor internal representation of units # @todo method to determine best natural prefix -class Unit < Numeric - VERSION = Unit::Version::STRING - @@definitions = {} - @@PREFIX_VALUES = {} - @@PREFIX_MAP = {} - @@UNIT_MAP = {} - @@UNIT_VALUES = {} - @@UNIT_REGEX = nil - @@UNIT_MATCH_REGEX = nil - 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 = [''] - FAHRENHEIT = [''] - RANKINE = [''] - CELSIUS = [''] - @@TEMP_REGEX = nil - SIGNATURE_VECTOR = [ - :length, - :time, - :temperature, - :mass, - :current, - :substance, - :luminosity, - :currency, - :memory, - :angle - ] - @@KINDS = { - -312078 => :elastance, - -312058 => :resistance, - -312038 => :inductance, - -152040 => :magnetism, - -152038 => :magnetism, - -152058 => :potential, - -7997 => :specific_volume, - -79 => :snap, - -59 => :jolt, - -39 => :acceleration, - -38 => :radiation, - -20 => :frequency, - -19 => :speed, - -18 => :viscosity, - -17 => :volumetric_flow, - -1 => :wavenumber, - 0 => :unitless, - 1 => :length, - 2 => :area, - 3 => :volume, - 20 => :time, - 400 => :temperature, - 7941 => :yank, - 7942 => :power, - 7959 => :pressure, - 7962 => :energy, - 7979 => :viscosity, - 7961 => :force, - 7981 => :momentum, - 7982 => :angular_momentum, - 7997 => :density, - 7998 => :area_density, - 8000 => :mass, - 152020 => :radiation_exposure, - 159999 => :magnetism, - 160000 => :current, - 160020 => :charge, - 312058 => :resistance, - 312078 => :capacitance, - 3199980 => :activity, - 3199997 => :molar_concentration, - 3200000 => :substance, - 63999998 => :illuminance, - 64000000 => :luminous_power, - 1280000000 => :currency, - 25600000000 => :memory, - 511999999980 => :angular_velocity, - 512000000000 => :angle - } - @@cached_units = {} - @@base_unit_cache = {} - - # setup internal arrays and hashes - # @return [true] - def self.setup - self.clear_cache +module RubyUnits + class Unit < Numeric + VERSION = Unit::Version::STRING + @@definitions = {} @@PREFIX_VALUES = {} @@PREFIX_MAP = {} - @@UNIT_VALUES = {} @@UNIT_MAP = {} + @@UNIT_VALUES = {} @@UNIT_REGEX = nil @@UNIT_MATCH_REGEX = nil - @@PREFIX_REGEX = nil + 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 = [''] + FAHRENHEIT = [''] + RANKINE = [''] + CELSIUS = [''] + @@TEMP_REGEX = nil + SIGNATURE_VECTOR = [ + :length, + :time, + :temperature, + :mass, + :current, + :substance, + :luminosity, + :currency, + :memory, + :angle + ] + @@KINDS = { + -312078 => :elastance, + -312058 => :resistance, + -312038 => :inductance, + -152040 => :magnetism, + -152038 => :magnetism, + -152058 => :potential, + -7997 => :specific_volume, + -79 => :snap, + -59 => :jolt, + -39 => :acceleration, + -38 => :radiation, + -20 => :frequency, + -19 => :speed, + -18 => :viscosity, + -17 => :volumetric_flow, + -1 => :wavenumber, + 0 => :unitless, + 1 => :length, + 2 => :area, + 3 => :volume, + 20 => :time, + 400 => :temperature, + 7941 => :yank, + 7942 => :power, + 7959 => :pressure, + 7962 => :energy, + 7979 => :viscosity, + 7961 => :force, + 7981 => :momentum, + 7982 => :angular_momentum, + 7997 => :density, + 7998 => :area_density, + 8000 => :mass, + 152020 => :radiation_exposure, + 159999 => :magnetism, + 160000 => :current, + 160020 => :charge, + 312058 => :resistance, + 312078 => :capacitance, + 3199980 => :activity, + 3199997 => :molar_concentration, + 3200000 => :substance, + 63999998 => :illuminance, + 64000000 => :luminous_power, + 1280000000 => :currency, + 25600000000 => :memory, + 511999999980 => :angular_velocity, + 512000000000 => :angle + } + @@cached_units = {} + @@base_unit_cache = {} + + # setup internal arrays and hashes + # @return [true] + def self.setup + self.clear_cache + @@PREFIX_VALUES = {} + @@PREFIX_MAP = {} + @@UNIT_VALUES = {} + @@UNIT_MAP = {} + @@UNIT_REGEX = nil + @@UNIT_MATCH_REGEX = nil + @@PREFIX_REGEX = nil + + @@definitions.each do |name, definition| + self.use_definition(definition) + end - @@definitions.each do |name, definition| - self.use_definition(definition) + RubyUnits::Unit.new(1) + return true end - Unit.new(1) - return true - end - - # determine if a unit is already defined - # @param [String] unit - # @return [Boolean] - def self.defined?(unit) - self.definitions.values.any? {|d| d.aliases.include?(unit)} - end + # determine if a unit is already defined + # @param [String] unit + # @return [Boolean] + def self.defined?(unit) + self.definitions.values.any? { |d| d.aliases.include?(unit) } + end - # return the unit definition for a unit - # @param [String] unit - # @return [Unit::Definition, nil] - def self.definition(_unit) - unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>" - return @@definitions[unit] - end + # return the unit definition for a unit + # @param [String] unit + # @return [RubyUnits::Unit::Definition, nil] + def self.definition(_unit) + unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>" + return @@definitions[unit] + end - # return a list of all defined units - # @return [Array] - def self.definitions - return @@definitions - end + # return a list of all defined units + # @return [Array] + def self.definitions + return @@definitions + end - # @param [Unit::Definition|String] unit_definition - # @param [Block] block - # @return [Unit::Definition] - # @raise [ArgumentError] when passed a non-string if using the block form - # Unpack a unit definition and add it to the array of defined units - # - # @example Block form - # Unit.define('foobar') do |foobar| - # foobar.definition = Unit("1 baz") - # end - # - # @example Unit::Definition form - # unit_definition = Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} - # Unit.define(unit_definition) - def self.define(unit_definition, &block) - if block_given? - raise ArgumentError, "When using the block form of Unit.define, pass the name of the unit" unless unit_definition.instance_of?(String) - unit_definition = Unit::Definition.new(unit_definition, &block) - end - Unit.definitions[unit_definition.name] = unit_definition - Unit.use_definition(unit_definition) - return unit_definition - end + # @param [RubyUnits::Unit::Definition|String] unit_definition + # @param [Block] block + # @return [RubyUnits::Unit::Definition] + # @raise [ArgumentError] when passed a non-string if using the block form + # Unpack a unit definition and add it to the array of defined units + # + # @example Block form + # RubyUnits::Unit.define('foobar') do |foobar| + # foobar.definition = Unit("1 baz") + # end + # + # @example RubyUnits::Unit::Definition form + # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} + # RubyUnits::Unit.define(unit_definition) + def self.define(unit_definition, &block) + if block_given? + raise ArgumentError, "When using the block form of RubyUnits::Unit.define, pass the name of the unit" unless unit_definition.instance_of?(String) + unit_definition = RubyUnits::Unit::Definition.new(unit_definition, &block) + end + RubyUnits::Unit.definitions[unit_definition.name] = unit_definition + RubyUnits::Unit.use_definition(unit_definition) + return unit_definition + end - # @param [String] name Name of unit to redefine - # @param [Block] block - # @raise [ArgumentError] if a block is not given - # @yield [Unit::Definition] - # @return (see Unit.define) - # Get the definition for a unit and allow it to be redefined - def self.redefine!(name, &block) - raise ArgumentError, "A block is required to redefine a unit" unless block_given? - unit_definition = self.definition(name) - yield unit_definition - self.define(unit_definition) - end + # @param [String] name Name of unit to redefine + # @param [Block] block + # @raise [ArgumentError] if a block is not given + # @yield [RubyUnits::Unit::Definition] + # @return (see RubyUnits::Unit.define) + # Get the definition for a unit and allow it to be redefined + def self.redefine!(name, &block) + raise ArgumentError, "A block is required to redefine a unit" unless block_given? + unit_definition = self.definition(name) + yield unit_definition + self.define(unit_definition) + end - # @param [String] name of unit to undefine - # @return (see Unit.setup) - # Undefine a unit. Will not raise an exception for unknown units. - def self.undefine!(unit) - @@definitions.delete("<#{unit}>") - Unit.setup - end + # @param [String] name of unit to undefine + # @return (see RubyUnits::Unit.setup) + # Undefine a unit. Will not raise an exception for unknown units. + def self.undefine!(unit) + @@definitions.delete("<#{unit}>") + RubyUnits::Unit.setup + end - include Comparable + include Comparable - # @return [Numeric] - attr_accessor :scalar + # @return [Numeric] + attr_accessor :scalar - # @return [Array] - attr_accessor :numerator + # @return [Array] + attr_accessor :numerator - # @return [Array] - attr_accessor :denominator + # @return [Array] + attr_accessor :denominator - # @return [Integer] - attr_accessor :signature + # @return [Integer] + attr_accessor :signature - # @return [Numeric] - attr_accessor :base_scalar + # @return [Numeric] + attr_accessor :base_scalar - # @return [Array] - attr_accessor :base_numerator + # @return [Array] + attr_accessor :base_numerator - # @return [Array] - attr_accessor :base_denominator + # @return [Array] + attr_accessor :base_denominator - # @return [String] - attr_accessor :output + # @return [String] + attr_accessor :output - # @return [String] - attr_accessor :unit_name + # @return [String] + attr_accessor :unit_name - # needed to make complex units play nice -- otherwise not detected as a complex_generic - # @param [Class] - # @return [Boolean] - def kind_of?(klass) - self.scalar.kind_of?(klass) - end + # needed to make complex units play nice -- otherwise not detected as a complex_generic + # @param [Class] + # @return [Boolean] + def kind_of?(klass) + self.scalar.kind_of?(klass) + end - # Used to copy one unit to another - # @param [Unit] from Unit to copy definition from - # @return [Unit] - 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 - return self - end + # Used to copy one unit to another + # @param [Unit] from Unit to copy definition from + # @return [Unit] + 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 + return self + end - if RUBY_VERSION < "1.9" - # :nocov_19: + if RUBY_VERSION < "1.9" + # :nocov_19: - # a list of properties to emit to yaml - # @return [Array] - def to_yaml_properties - %w{@scalar @numerator @denominator @signature @base_scalar} - end + # a list of properties to emit to yaml + # @return [Array] + def to_yaml_properties + %w{@scalar @numerator @denominator @signature @base_scalar} + end - # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string - # before YAML'izing it. - # @param [Hash] opts - # @return [String] - 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 ) ) + # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string + # before YAML'izing it. + # @param [Hash] opts + # @return [String] + 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 + # :nocov_19: end - # :nocov_19: - end - # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime - # - # @example Valid options 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 - # [1, 'kg'] - # {:scalar => 1, :numerator=>'kg'} - # - # @param [Unit,String,Hash,Array,Date,Time,DateTime] options - # @return [Unit] - # @raise [ArgumentError] if absolute value of a temperature is less than absolute zero - # @raise [ArgumentError] if no unit is specified - # @raise [ArgumentError] if an invalid unit is specified - def initialize(*options) - @scalar = nil - @base_scalar = nil - @unit_name = nil - @signature = nil - @output = { } - raise ArgumentError, "Invalid Unit Format" if options[0].nil? - if options.size == 2 - # options[0] is the scalar - # options[1] is a unit string - begin - cached = @@cached_units[options[1]] * options[0] - copy(cached) - rescue - initialize("#{options[0]} #{(options[1].units rescue options[1])}") + # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime + # + # @example Valid options 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 + # [1, 'kg'] + # {:scalar => 1, :numerator=>'kg'} + # + # @param [Unit,String,Hash,Array,Date,Time,DateTime] options + # @return [Unit] + # @raise [ArgumentError] if absolute value of a temperature is less than absolute zero + # @raise [ArgumentError] if no unit is specified + # @raise [ArgumentError] if an invalid unit is specified + def initialize(*options) + @scalar = nil + @base_scalar = nil + @unit_name = nil + @signature = nil + @output = {} + raise ArgumentError, "Invalid Unit Format" if options[0].nil? + if options.size == 2 + # options[0] is the scalar + # options[1] is a unit string + begin + cached = @@cached_units[options[1]] * options[0] + copy(cached) + rescue + initialize("#{options[0]} #{(options[1].units rescue options[1])}") + end + return end - return - end - if options.size == 3 - options[1] = options[1].join if options[1].kind_of?(Array) - options[2] = options[2].join if options[2].kind_of?(Array) - begin - cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0] - copy(cached) - rescue - initialize("#{options[0]} #{options[1]}/#{options[2]}") + if options.size == 3 + options[1] = options[1].join if options[1].kind_of?(Array) + options[2] = options[2].join if options[2].kind_of?(Array) + begin + cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0] + copy(cached) + rescue + initialize("#{options[0]} #{options[1]}/#{options[2]}") + end + return end - return - end - case options[0] - when Unit - copy(options[0]) - return - when Hash - @scalar = options[0][:scalar] || 1 - @numerator = options[0][:numerator] || UNITY_ARRAY - @denominator = options[0][:denominator] || UNITY_ARRAY - @signature = options[0][:signature] - when Array - initialize(*options[0]) - return - when Numeric - @scalar = options[0] - @numerator = @denominator = UNITY_ARRAY - when Time - @scalar = options[0].to_f - @numerator = [''] - @denominator = UNITY_ARRAY - when DateTime, Date - @scalar = options[0].ajd - @numerator = [''] - @denominator = UNITY_ARRAY - when /^\s*$/ - raise ArgumentError, "No Unit Specified" - when String - parse(options[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 options.first.instance_of?(String) - opt_scalar, opt_units = Unit.parse_into_numbers_and_units(options[0]) - unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{Unit.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? + case options[0] + when Unit + copy(options[0]) + return + when Hash + @scalar = options[0][:scalar] || 1 + @numerator = options[0][:numerator] || UNITY_ARRAY + @denominator = options[0][:denominator] || UNITY_ARRAY + @signature = options[0][:signature] + when Array + initialize(*options[0]) + return + when Numeric + @scalar = options[0] + @numerator = @denominator = UNITY_ARRAY + when Time + @scalar = options[0].to_f + @numerator = [''] + @denominator = UNITY_ARRAY + when DateTime, Date + @scalar = options[0].ajd + @numerator = [''] + @denominator = UNITY_ARRAY + when /^\s*$/ + raise ArgumentError, "No Unit Specified" + when String + parse(options[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 options.first.instance_of?(String) + opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) + unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{RubyUnits::Unit.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 =~ /#{RubyUnits::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 } + return self end - unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{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} - return self - end - # @todo: figure out how to handle :counting units. This method should probably return :counting instead of :unitless for 'each' - # return the kind of the unit (:mass, :length, etc...) - # @return [Symbol] - def kind - return @@KINDS[self.signature] - end + # @todo: figure out how to handle :counting units. This method should probably return :counting instead of :unitless for 'each' + # return the kind of the unit (:mass, :length, etc...) + # @return [Symbol] + def kind + return @@KINDS[self.signature] + end - # @private - # @return [Hash] - def self.cached - return @@cached_units - end + # @private + # @return [Hash] + def self.cached + return @@cached_units + end - # @private - # @return [true] - def self.clear_cache - @@cached_units = {} - @@base_unit_cache = {} - Unit.new(1) - return true - end + # @private + # @return [true] + def self.clear_cache + @@cached_units = {} + @@base_unit_cache = {} + RubyUnits::Unit.new(1) + return true + end - # @private - # @return [Hash] - def self.base_unit_cache - return @@base_unit_cache - end + # @private + # @return [Hash] + def self.base_unit_cache + return @@base_unit_cache + end - # @example parse strings - # "1 minute in seconds" - # @param [String] input - # @return [Unit] - def self.parse(input) - first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first - return second.nil? ? first.unit : first.unit.convert_to(second) - end + # @example parse strings + # "1 minute in seconds" + # @param [String] input + # @return [Unit] + def self.parse(input) + first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first + return second.nil? ? first.unit : first.unit.convert_to(second) + end - # @return [Unit] - def to_unit - self - end - alias :unit :to_unit - - # Is this unit in base form? - # @return [Boolean] - def is_base? - return @is_base if defined? @is_base - @is_base = (@numerator + @denominator).compact.uniq. - map {|unit| Unit.definition(unit)}. - all? {|element| element.unity? || element.base? } - return @is_base - end - alias :base? :is_base? - - # convert to base SI units - # results of the conversion are cached so subsequent calls to this will be fast - # @return [Unit] - # @todo this is brittle as it depends on the display_name of a unit, which can be changed - def to_base - return self if self.is_base? - if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ - if RUBY_VERSION < "1.9" - # :nocov_19: - @signature = @@KINDS.index(:temperature) - # :nocov_19: - else - #:nocov: - @signature = @@KINDS.key(:temperature) - #:nocov: - end - base = case - when self.is_temperature? - self.convert_to('tempK') - when self.is_degree? - self.convert_to('degK') - end - return base + # @return [Unit] + def to_unit + self end - cached = ((@@base_unit_cache[self.units] * self.scalar) rescue nil) - return cached if cached + alias :unit :to_unit - 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 + # Is this unit in base form? + # @return [Boolean] + def is_base? + return @is_base if defined? @is_base + @is_base = (@numerator + @denominator).compact.uniq. + map { |unit| RubyUnits::Unit.definition(unit) }. + all? { |element| element.unity? || element.base? } + return @is_base 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] + + alias :base? :is_base? + + # convert to base SI units + # results of the conversion are cached so subsequent calls to this will be fast + # @return [Unit] + # @todo this is brittle as it depends on the display_name of a unit, which can be changed + def to_base + return self if self.is_base? + if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ + if RUBY_VERSION < "1.9" + # :nocov_19: + @signature = @@KINDS.index(:temperature) + # :nocov_19: + else + #:nocov: + @signature = @@KINDS.key(:temperature) + #:nocov: + end + base = case + when self.is_temperature? + self.convert_to('tempK') + when self.is_degree? + self.convert_to('degK') + end + return base 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 - alias :base :to_base - - # 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 - # - # @example - # unit.to_s(:ft) - outputs in feet and inches (e.g., 6'4") - # unit.to_s(: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 - # - # @param [Symbol] target_units - # @return [String] - def to_s(target_units=nil) - out = @output[target_units] - if out - return out - else - case target_units - when :ft - inches = self.convert_to("in").scalar.to_int - out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" - when :lbs - ounces = self.convert_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.convert_to($2).to_s($1) - else - "#{$1 % @scalar} #{$2 || self.units}".strip - end - rescue # parse it like a strftime format string - (DateTime.new(0) + self).strftime(target_units) - end - when /(\S+)/ #unit only 'mm' or '1/mm' - self.convert_to($1).to_s + 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 - raise "unhandled case" + 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 - else - out = case @scalar - when Rational - "#{@scalar} #{self.units}" + end + for unit in @denominator.compact do + if @@PREFIX_VALUES[unit] + q /= @@PREFIX_VALUES[unit] else - "#{'%g' % @scalar} #{self.units}" - end.strip + 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 - @output[target_units] = out - return out + + num = num.flatten.compact + den = den.flatten.compact + num = UNITY_ARRAY if num.empty? + base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den)) + @@base_unit_cache[self.units]=base + return base * @scalar end - end - # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' - # @deprecated - # @return [String] - def inspect(option=nil) - return super() if option == :dump - return self.to_s - end + alias :base :to_base + + # 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 + # + # @example + # unit.to_s(:ft) - outputs in feet and inches (e.g., 6'4") + # unit.to_s(: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 + # + # @param [Symbol] target_units + # @return [String] + def to_s(target_units=nil) + out = @output[target_units] + if out + return out + else + case target_units + when :ft + inches = self.convert_to("in").scalar.to_int + out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" + when :lbs + ounces = self.convert_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.convert_to($2).to_s($1) + else + "#{$1 % @scalar} #{$2 || self.units}".strip + end + rescue # parse it like a strftime format string + (DateTime.new(0) + self).strftime(target_units) + end + when /(\S+)/ #unit only 'mm' or '1/mm' + self.convert_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 - # true if unit is a 'temperature', false if a 'degree' or anything else - # @return [Boolean] - # @todo use unit definition to determine if it's a temperature instead of a regex - def is_temperature? - return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?) - end - alias :temperature? :is_temperature? + # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' + # @deprecated + # @return [String] + def inspect(option=nil) + return super() if option == :dump + return self.to_s + end - # true if a degree unit or equivalent. - # @return [Boolean] - def is_degree? - return self.kind == :temperature - end - alias :degree? :is_degree? - - # returns the 'degree' unit associated with a temperature unit - # @example '100 tempC'.unit.temperature_scale #=> 'degC' - # @return [String] possible values: degC, degF, degR, or degK - def temperature_scale - return nil unless self.is_temperature? - return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/,1]}" - end + # true if unit is a 'temperature', false if a 'degree' or anything else + # @return [Boolean] + # @todo use unit definition to determine if it's a temperature instead of a regex + def is_temperature? + return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?) + end - # returns true if no associated units - # false, even if the units are "unitless" like 'radians, each, etc' - # @return [Boolean] - def unitless? - return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) - end + alias :temperature? :is_temperature? - # 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. - # @param [Object] other - # @return [-1|0|1|nil] - # @raise [NoMethodError] when other does not define <=> - # @raise [ArgumentError] when units are not compatible - def <=>(other) - case - when !self.base_scalar.respond_to?(:<=>) - raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" - when other.nil? - return self.base_scalar <=> nil - 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 + # true if a degree unit or equivalent. + # @return [Boolean] + def is_degree? + return self.kind == :temperature end - end - # 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. - # @param [Object] other - # @return [Boolean] - 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 - begin - x,y = coerce(other) - return x == y - rescue ArgumentError # return false when object cannot be coerced - return false - end + alias :degree? :is_degree? + + # returns the 'degree' unit associated with a temperature unit + # @example '100 tempC'.unit.temperature_scale #=> 'degC' + # @return [String] possible values: degC, degF, degR, or degK + def temperature_scale + return nil unless self.is_temperature? + return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/, 1]}" end - end - # 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 - # @example this permits a syntax like: - # unit =~ "mm" - # @note if you want to do a regexp comparison of the unit string do this ... - # unit.units =~ /regexp/ - # @param [Object] other - # @return [Boolean] - def =~(other) - case other - when Unit - self.signature == other.signature - else - begin - x,y = coerce(other) - return x =~ y - rescue ArgumentError - return false - end + # returns true if no associated units + # false, even if the units are "unitless" like 'radians, each, etc' + # @return [Boolean] + def unitless? + return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) end - end - alias :compatible? :=~ - alias :compatible_with? :=~ - - # Compare two units. Returns true if quantities and units match - # @example - # Unit("100 cm") === Unit("100 cm") # => true - # Unit("100 cm") === Unit("1 m") # => false - # @param [Object] other - # @return [Boolean] - def ===(other) - case other - when Unit - (self.scalar == other.scalar) && (self.units == other.units) - else - begin - x,y = coerce(other) - return x === y - rescue ArgumentError - return false + # 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. + # @param [Object] other + # @return [-1|0|1|nil] + # @raise [NoMethodError] when other does not define <=> + # @raise [ArgumentError] when units are not compatible + def <=>(other) + case + when !self.base_scalar.respond_to?(:<=>) + raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" + when other.nil? + return self.base_scalar <=> nil + 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 - end - alias :same? :=== - alias :same_as? :=== - - # 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 - # @param [Object] other - # @return [Unit] - # @raise [ArgumentError] when two temperatures are added - # @raise [ArgumentError] when units are not compatible - # @raise [ArgumentError] when adding a fixed time or date to a time span - def +(other) - case other - when Unit + # 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. + # @param [Object] other + # @return [Boolean] + def ==(other) 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.convert_to(self.temperature_scale).scalar), :numerator => @numerator, :denominator=>@denominator, :signature => @signature) - else - Unit.new(:scalar => (other.scalar + self.convert_to(other.temperature_scale).scalar), :numerator => other.numerator, :denominator=>other.denominator, :signature => other.signature) + 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 + begin + x, y = coerce(other) + return x == y + rescue ArgumentError # return false when object cannot be coerced + return false end + end + end + + # 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 + # @example this permits a syntax like: + # unit =~ "mm" + # @note if you want to do a regexp comparison of the unit string do this ... + # unit.units =~ /regexp/ + # @param [Object] other + # @return [Boolean] + def =~(other) + case other + when Unit + self.signature == other.signature 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}')" + begin + x, y = coerce(other) + return x =~ y + rescue ArgumentError + return false + end 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 - # Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when subtracting a temperature from a degree - # @raise [ArgumentError] when units are not compatible - # @raise [ArgumentError] when subtracting a fixed time from a time span - def -(other) - case other - when Unit - case - when self.zero? - if other.zero? - other.dup * -1 # preserve Units class - else - -other.dup + alias :compatible? :=~ + alias :compatible_with? :=~ + + # Compare two units. Returns true if quantities and units match + # @example + # Unit("100 cm") === Unit("100 cm") # => true + # Unit("100 cm") === Unit("1 m") # => false + # @param [Object] other + # @return [Boolean] + def ===(other) + case other + when Unit + (self.scalar == other.scalar) && (self.units == other.units) + else + begin + x, y = coerce(other) + return x === y + rescue ArgumentError + return false end - when self =~ other + end + end + + alias :same? :=== + alias :same_as? :=== + + # 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 + # @param [Object] other + # @return [Unit] + # @raise [ArgumentError] when two temperatures are added + # @raise [ArgumentError] when units are not compatible + # @raise [ArgumentError] when adding a fixed time or date to a time span + def +(other) + case other + when Unit 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).convert_to(self.temperature_scale) - when self.is_temperature? - Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => [''], :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self) - when other.is_temperature? - raise ArgumentError, "Cannot subtract a temperature from a differential degree unit" + 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? + RubyUnits::Unit.new(:scalar => (self.scalar + other.convert_to(self.temperature_scale).scalar), :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + RubyUnits::Unit.new(:scalar => (other.scalar + self.convert_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)) + RubyUnits::Unit.new(:scalar => (self.base_scalar + other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + end 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) + 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 - 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) - return y-x + x, y = coerce(other) + y + x + end end - end - # Multiply two units. - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when attempting to multiply two temperatures - 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) - return Unit.new(opts) - when Numeric - return Unit.new(:scalar=>@scalar*other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) - else - x,y = coerce(other) - return x * y + # Subtract two units. Result is same units as receiver and scalar and base_scalar are updated appropriately + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when subtracting a temperature from a degree + # @raise [ArgumentError] when units are not compatible + # @raise [ArgumentError] when subtracting a fixed time from a time span + def -(other) + case other + when Unit + case + when self.zero? + if other.zero? + other.dup * -1 # preserve Units class + else + -other.dup + end + when self =~ other + case + when [self, other].all? { |x| x.is_temperature? } + RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => KELVIN, :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self.temperature_scale) + when self.is_temperature? + RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => [''], :denominator => UNITY_ARRAY, :signature => @signature).convert_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)) + RubyUnits::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) + return y-x + end end - end - # Divide two units. - # Throws an exception if divisor is 0 - # @param [Numeric] other - # @return [Unit] - # @raise [ZeroDivisionError] if divisor is zero - # @raise [ArgumentError] if attempting to divide a temperature by another temperature - 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) - return Unit.new(opts) - when Numeric - raise ZeroDivisionError if other.zero? - return Unit.new(:scalar=>@scalar/other, :numerator=>@numerator, :denominator=>@denominator, :signature => @signature) - else - x,y = coerce(other) - return y / x + # Multiply two units. + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when attempting to multiply two temperatures + 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) + when Numeric + return RubyUnits::Unit.new(:scalar => @scalar*other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + x, y = coerce(other) + return x * y + end end - end - # 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 - # @param [Object] other - # @return [Array] - 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) + # Divide two units. + # Throws an exception if divisor is 0 + # @param [Numeric] other + # @return [Unit] + # @raise [ZeroDivisionError] if divisor is zero + # @raise [ArgumentError] if attempting to divide a temperature by another temperature + 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 = RubyUnits::Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator, @denominator + other.numerator) + opts.merge!(:signature => @signature - other.signature) + return RubyUnits::Unit.new(opts) + when Numeric + raise ZeroDivisionError if other.zero? + return RubyUnits::Unit.new(:scalar => @scalar/other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) + else + x, y = coerce(other) + return y / x + end end - end - # perform a modulo on a unit, will raise an exception if the units are not compatible - # @param [Object] other - # @return [Integer] - def %(other) - return self.divmod(other).last - end - - # 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 - # @param [Numeric] other - # @return [Unit] - # @raise [ArgumentError] when raising a temperature to a power - # @raise [ArgumentError] when n not in the set integers from (1..9) - # @raise [ArgumentError] when attempting to raise to a complex number - # @raise [ArgumentError] when an invalid exponent is passed - 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 - return self.power(other.numerator).root(other.denominator) - when Integer - return 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 - return self.root((1/other).to_int) - when Complex - raise ArgumentError, "exponentiation of complex numbers is not yet supported." - else - raise ArgumentError, "Invalid Exponent" + # 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 + # @param [Object] other + # @return [Array] + 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 - end - # returns the unit raised to the n-th power - # @param [Integer] n - # @return [Unit] - # @raise [ArgumentError] when attempting to raise a temperature to a power - # @raise [ArgumentError] when n is not an integer - 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 - return (1..(n-1).to_i).inject(self) {|product, x| product * self} - else - return (1..-(n-1).to_i).inject(self) {|product, x| product / self} + # perform a modulo on a unit, will raise an exception if the units are not compatible + # @param [Object] other + # @return [Integer] + def %(other) + return self.divmod(other).last end - end - # Calculates the n-th root of a unit - # if n < 0, returns 1/unit^(1/n) - # @param [Integer] n - # @return [Unit] - # @raise [ArgumentError] when attemptint to take the root of a temperature - # @raise [ArgumentError] when n is not an integer - # @raise [ArgumentError] when n is 0 - 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) - return Unit.new(:scalar=>q,:numerator=>num,:denominator=>den) - end + # 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 + # @param [Numeric] other + # @return [Unit] + # @raise [ArgumentError] when raising a temperature to a power + # @raise [ArgumentError] when n not in the set integers from (1..9) + # @raise [ArgumentError] when attempting to raise to a complex number + # @raise [ArgumentError] when an invalid exponent is passed + 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 + return self.power(other.numerator).root(other.denominator) + when Integer + return 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 + return 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 - # returns inverse of Unit (1/unit) - # @return [Unit] - def inverse - return Unit("1") / self - end + # returns the unit raised to the n-th power + # @param [Integer] n + # @return [Unit] + # @raise [ArgumentError] when attempting to raise a temperature to a power + # @raise [ArgumentError] when n is not an integer + 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 + return (1..(n-1).to_i).inject(self) { |product, x| product * self } + else + return (1..-(n-1).to_i).inject(self) { |product, x| product / self } + end + end - # convert to a specified unit string or to the same units as another Unit - # - # unit.convert_to "kg" will covert to kilograms - # unit1.convert_to unit2 converts to same units as unit2 object - # - # To convert a Unit object to match another Unit object, use: - # unit1 >>= unit2 - # - # 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 If temperature is part of a compound unit, the temperature will be treated as a differential - # and the units will be scaled appropriately. - # @param [Object] other - # @return [Unit] - # @raise [ArgumentError] when attempting to convert a degree to a temperature - # @raise [ArgumentError] when target unit is unknown - # @raise [ArgumentError] when target unit is incompatible - def convert_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 @@UNIT_MAP[start_unit] - when '' - @scalar + 273.15 - when '' - @scalar - when '' - (@scalar+459.67)*Rational(5,9) - when '' - @scalar*Rational(5,9) - end + # Calculates the n-th root of a unit + # if n < 0, returns 1/unit^(1/n) + # @param [Integer] n + # @return [Unit] + # @raise [ArgumentError] when attemptint to take the root of a temperature + # @raise [ArgumentError] when n is not an integer + # @raise [ArgumentError] when n is 0 + 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 - q= case @@UNIT_MAP[target_unit] - when '' - @base_scalar - 273.15 - when '' - @base_scalar - when '' - @base_scalar * Rational(9,5) - 459.67 - when '' - @base_scalar * Rational(9,5) + + 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 - return 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) + q = @scalar < 0 ? (-1)**Rational(1, n) * (@scalar.abs)**Rational(1, n) : @scalar**Rational(1, n) + return RubyUnits::Unit.new(:scalar => q, :numerator => num, :denominator => den) + end + + # returns inverse of Unit (1/unit) + # @return [Unit] + def inverse + return Unit("1") / self + end + + # convert to a specified unit string or to the same units as another Unit + # + # unit.convert_to "kg" will covert to kilograms + # unit1.convert_to unit2 converts to same units as unit2 object + # + # To convert a Unit object to match another Unit object, use: + # unit1 >>= unit2 + # + # 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 If temperature is part of a compound unit, the temperature will be treated as a differential + # and the units will be scaled appropriately. + # @param [Object] other + # @return [Unit] + # @raise [ArgumentError] when attempting to convert a degree to a temperature + # @raise [ArgumentError] when target unit is unknown + # @raise [ArgumentError] when target unit is incompatible + def convert_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 @@UNIT_MAP[start_unit] + when '' + @scalar + 273.15 + when '' + @scalar + when '' + (@scalar+459.67)*Rational(5, 9) + when '' + @scalar*Rational(5, 9) + end + end + q= case @@UNIT_MAP[target_unit] + when '' + @base_scalar - 273.15 + when '' + @base_scalar + when '' + @base_scalar * Rational(9, 5) - 459.67 + when '' + @base_scalar * Rational(9, 5) + end + return RubyUnits::Unit.new("#{q} #{target_unit}") else - raise ArgumentError, "Unknown target units" + case other + when Unit + return self if other.units == self.units + target = other + when String + target = RubyUnits::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 + + q = @scalar * ((_numerator1 + _denominator2).inject(1) { |product, n| product*n }) / + ((_numerator2 + _denominator1).inject(1) { |product, n| product*n }) + return RubyUnits::Unit.new(:scalar => q, :numerator => target.numerator, :denominator => target.denominator, :signature => target.signature) 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 + end - q = @scalar * ( (_numerator1 + _denominator2).inject(1) {|product,n| product*n} ) / - ( (_numerator2 + _denominator1).inject(1) {|product,n| product*n} ) - return Unit.new(:scalar=>q, :numerator=>target.numerator, :denominator=>target.denominator, :signature => target.signature) + alias :>> :convert_to + alias :to :convert_to + + # converts the unit back to a float if it is unitless. Otherwise raises an exception + # @return [Float] + # @raise [RuntimeError] when not unitless + 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 - end - alias :>> :convert_to - alias :to :convert_to - - # converts the unit back to a float if it is unitless. Otherwise raises an exception - # @return [Float] - # @raise [RuntimeError] when not unitless - 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 - # converts the unit back to a complex if it is unitless. Otherwise raises an exception - # @return [Complex] - # @raise [RuntimeError] when not unitless - def to_c - return Complex(@scalar) if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" - end + # converts the unit back to a complex if it is unitless. Otherwise raises an exception + # @return [Complex] + # @raise [RuntimeError] when not unitless + def to_c + return Complex(@scalar) if self.unitless? + raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" + end - # if unitless, returns an int, otherwise raises an error - # @return [Integer] - # @raise [RuntimeError] when not unitless - 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 - alias :to_int :to_i - - # if unitless, returns a Rational, otherwise raises an error - # @return [Rational] - # @raise [RuntimeError] when not unitless - 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 + # if unitless, returns an int, otherwise raises an error + # @return [Integer] + # @raise [RuntimeError] when not unitless + 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 - # Returns string formatted for json - # @return [String] - def as_json(*args) - to_s - end + alias :to_int :to_i - # returns the 'unit' part of the Unit object without the scalar - # @return [String] - def units - return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY - return @unit_name unless @unit_name.nil? - output_numerator = [] - output_denominator = [] - num = @numerator.clone.compact - den = @denominator.clone.compact - - if @numerator == UNITY_ARRAY - output_numerator << "1" - else - while defn = Unit.definition(num.shift) do - if defn && defn.prefix? - output_numerator << defn.display_name + Unit.definition(num.shift).display_name - else - output_numerator << defn.display_name - end - end + # if unitless, returns a Rational, otherwise raises an error + # @return [Rational] + # @raise [RuntimeError] when not unitless + 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 + + # Returns string formatted for json + # @return [String] + def as_json(*args) + to_s end - if @denominator == UNITY_ARRAY + # returns the 'unit' part of the Unit object without the scalar + # @return [String] + def units + return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY + return @unit_name unless @unit_name.nil? + output_numerator = [] output_denominator = [] - else - while defn = Unit.definition(den.shift) do - if defn && defn.prefix? - output_denominator << defn.display_name + Unit.definition(den.shift).display_name - else - output_denominator << defn.display_name + num = @numerator.clone.compact + den = @denominator.clone.compact + + if @numerator == UNITY_ARRAY + output_numerator << "1" + 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 + else + output_numerator << defn.display_name + end end end - end - on = output_numerator.uniq. - map {|x| [x, output_numerator.count(x)]}. - map {|element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : ''))} - od = output_denominator.uniq. - 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 - - # negates the scalar of the Unit - # @return [Numeric,Unit] - def -@ - return -@scalar if self.unitless? - return (self.dup * -1) - end + if @denominator == UNITY_ARRAY + output_denominator = [] + 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 + else + output_denominator << defn.display_name + end + end + end - # absolute value of a unit - # @return [Numeric,Unit] - def abs - return @scalar.abs if self.unitless? - return Unit.new(@scalar.abs, @numerator, @denominator) - end + on = output_numerator.uniq. + map { |x| [x, output_numerator.count(x)] }. + map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + od = output_denominator.uniq. + 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 - # ceil of a unit - # @return [Numeric,Unit] - def ceil - return @scalar.ceil if self.unitless? - return Unit.new(@scalar.ceil, @numerator, @denominator) - end + # negates the scalar of the Unit + # @return [Numeric,Unit] + def -@ + return -@scalar if self.unitless? + return (self.dup * -1) + end - # @return [Numeric,Unit] - def floor - return @scalar.floor if self.unitless? - return Unit.new(@scalar.floor, @numerator, @denominator) - end + # absolute value of a unit + # @return [Numeric,Unit] + def abs + return @scalar.abs if self.unitless? + return RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator) + end - if RUBY_VERSION < '1.9' + # ceil of a unit # @return [Numeric,Unit] - def round - return @scalar.round if self.unitless? - return Unit.new(@scalar.round, @numerator, @denominator) + def ceil + return @scalar.ceil if self.unitless? + return RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator) end - else + # @return [Numeric,Unit] - def round(ndigits = 0) - return @scalar.round(ndigits) if self.unitless? - return Unit.new(@scalar.round(ndigits), @numerator, @denominator) + def floor + return @scalar.floor if self.unitless? + return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator) end - end - # @return [Numeric, Unit] - def truncate - return @scalar.truncate if self.unitless? - return Unit.new(@scalar.truncate, @numerator, @denominator) - end + if RUBY_VERSION < '1.9' + # @return [Numeric,Unit] + def round + return @scalar.round if self.unitless? + return RubyUnits::Unit.new(@scalar.round, @numerator, @denominator) + end + else + # @return [Numeric,Unit] + def round(ndigits = 0) + return @scalar.round(ndigits) if self.unitless? + return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) + end + end - # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit - # only works when the scalar is an integer - # @return [Unit] - # @raise [ArgumentError] when scalar is not equal to an integer - def succ - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return Unit.new(@scalar.to_i.succ, @numerator, @denominator) - end - alias :next :succ - - # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit - # only works when the scalar is an integer - # @return [Unit] - # @raise [ArgumentError] when scalar is not equal to an integer - def pred - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return Unit.new(@scalar.to_i.pred, @numerator, @denominator) - end + # @return [Numeric, Unit] + def truncate + return @scalar.truncate if self.unitless? + return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator) + end - # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. - # @return [Time] - def to_time - return Time.at(self) - end - alias :time :to_time + # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit + # only works when the scalar is an integer + # @return [Unit] + # @raise [ArgumentError] when scalar is not equal to an integer + def succ + raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i + return RubyUnits::Unit.new(@scalar.to_i.succ, @numerator, @denominator) + end - # convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date - # defined by DateTime - # @return [DateTime] - def to_datetime - return DateTime.new!(self.convert_to('d').scalar) - end + alias :next :succ - # @return [Date] - def to_date - return Date.new0(self.convert_to('d').scalar) - end + # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit + # only works when the scalar is an integer + # @return [Unit] + # @raise [ArgumentError] when scalar is not equal to an integer + def pred + raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i + return RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator) + end - # true if scalar is zero - # @return [Boolean] - def zero? - return self.base_scalar.zero? - end + # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. + # @return [Time] + def to_time + return Time.at(self) + end - # @example '5 min'.unit.ago - # @return [Unit] - def ago - return self.before - end + alias :time :to_time - # @example '5 min'.before(time) - # @return [Unit] - def before(time_point = ::Time.now) - case time_point - when Time, Date, DateTime - return (time_point - self rescue time_point.to_datetime - self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date + # defined by DateTime + # @return [DateTime] + def to_datetime + return DateTime.new!(self.convert_to('d').scalar) end - end - alias :before_now :before - - # @example 'min'.since(time) - # @param [Time, Date, DateTime] time_point - # @return [Unit] - # @raise [ArgumentError] when time point is not a Time, Date, or DateTime - def since(time_point) - case time_point - when Time - return (Time.now - time_point).unit('s').convert_to(self) - when DateTime, Date - return (DateTime.now - time_point).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + + # @return [Date] + def to_date + return Date.new0(self.convert_to('d').scalar) end - end - # @example 'min'.until(time) - # @param [Time, Date, DateTime] time_point - # @return [Unit] - def until(time_point) - case time_point - when Time - return (time_point - Time.now).unit('s').convert_to(self) - when DateTime, Date - return (time_point - DateTime.now).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # true if scalar is zero + # @return [Boolean] + def zero? + return self.base_scalar.zero? end - end - # @example '5 min'.from(time) - # @param [Time, Date, DateTime] time_point - # @return [Time, Date, DateTime] - # @raise [ArgumentError] when passed argument is not a Time, Date, or DateTime - def from(time_point) - case time_point - when Time, DateTime, Date - return (time_point + self rescue time_point.to_datetime + self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + # @example '5 min'.unit.ago + # @return [Unit] + def ago + return self.before end - end - alias :after :from - alias :from_now :from - - # automatically coerce objects to units when possible - # if an object defines a 'to_unit' method, it will be coerced using that method - # @param [Object, #to_unit] - # @return [Array] - def coerce(other) - if other.respond_to? :to_unit - return [other.to_unit, self] - end - case other - when Unit - return [other, self] - else - return [Unit.new(other), self] + + # @example '5 min'.before(time) + # @return [Unit] + def before(time_point = ::Time.now) + case time_point + when Time, Date, DateTime + return (time_point - self rescue time_point.to_datetime - self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end end - end - # Protected and Private Functions that should only be called from this class - protected + alias :before_now :before + + # @example 'min'.since(time) + # @param [Time, Date, DateTime] time_point + # @return [Unit] + # @raise [ArgumentError] when time point is not a Time, Date, or DateTime + def since(time_point) + case time_point + when Time + return (Time.now - time_point).unit('s').convert_to(self) + when DateTime, Date + return (DateTime.now - time_point).unit('d').convert_to(self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end + end - # figure out what the scalar part of the base unit for this unit is - # @return [nil] - def update_base_scalar - if self.is_base? - @base_scalar = @scalar - @signature = unit_signature - else - base = self.to_base - @base_scalar = base.scalar - @signature = base.signature + # @example 'min'.until(time) + # @param [Time, Date, DateTime] time_point + # @return [Unit] + def until(time_point) + case time_point + when Time + return (time_point - Time.now).unit('s').convert_to(self) + when DateTime, Date + return (time_point - DateTime.now).unit('d').convert_to(self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end end - end - # calculates the unit signature vector used by unit_signature - # @return [Array] - # @raise [ArgumentError] when exponent associated with a unit is > 20 or < -20 - def unit_signature_vector - return self.to_base.unit_signature_vector unless self.is_base? - vector = Array.new(SIGNATURE_VECTOR.size,0) - # it's possible to have a kind that misses the array... kinds like :counting - # are more like prefixes, so don't use them to calculate the vector - @numerator.map {|element| Unit.definition(element)}.each do |definition| - index = SIGNATURE_VECTOR.index(definition.kind) - vector[index] += 1 if index - end - @denominator.map {|element| Unit.definition(element)}.each do |definition| - index = SIGNATURE_VECTOR.index(definition.kind) - vector[index] -= 1 if index - end - raise ArgumentError, "Power out of range (-20 < net power of a unit < 20)" if vector.any? {|x| x.abs >=20} - return vector - end + # @example '5 min'.from(time) + # @param [Time, Date, DateTime] time_point + # @return [Time, Date, DateTime] + # @raise [ArgumentError] when passed argument is not a Time, Date, or DateTime + def from(time_point) + case time_point + when Time, DateTime, Date + return (time_point + self rescue time_point.to_datetime + self) + else + raise ArgumentError, "Must specify a Time, Date, or DateTime" + end + end - private + alias :after :from + alias :from_now :from - # used by #dup to duplicate a Unit - # @param [Unit] other - # @private - def initialize_copy(other) - @numerator = other.numerator.dup - @denominator = other.denominator.dup - end + # automatically coerce objects to units when possible + # if an object defines a 'to_unit' method, it will be coerced using that method + # @param [Object, #to_unit] + # @return [Array] + def coerce(other) + if other.respond_to? :to_unit + return [other.to_unit, self] + end + case other + when Unit + return [other, self] + else + return [RubyUnits::Unit.new(other), self] + end + end - # calculates the unit signature id for use in comparing compatible units and simplification - # the signature is based on a simple classification of units and is based on the following publication - # - # Novak, G.S., Jr. "Conversion of units of measurement", IEEE Transactions on Software Engineering, 21(8), Aug 1995, pp.651-661 - # @see http://doi.ieeecomputersociety.org/10.1109/32.403789 - # @return [Array] - def unit_signature - return @signature unless @signature.nil? - vector = unit_signature_vector - vector.each_with_index {|item,index| vector[index] = item * 20**index} - @signature=vector.inject(0) {|sum,n| sum+n} - return @signature - end + # Protected and Private Functions that should only be called from this class + protected - # @param [Numeric] q quantity - # @param [Array] n numerator - # @param [Array] d denominator - # @return [Hash] - def self.eliminate_terms(q, n, d) - num = n.dup - den = d.dup - - num.delete_if {|v| v == UNITY} - den.delete_if {|v| v == UNITY} - combined = Hash.new(0) - - i = 0 - loop do - break if i > num.size - if @@PREFIX_VALUES.has_key? num[i] - k = [num[i],num[i+1]] - i += 2 + # figure out what the scalar part of the base unit for this unit is + # @return [nil] + def update_base_scalar + if self.is_base? + @base_scalar = @scalar + @signature = unit_signature else - k = num[i] - i += 1 + base = self.to_base + @base_scalar = base.scalar + @signature = base.signature + end + end + + # calculates the unit signature vector used by unit_signature + # @return [Array] + # @raise [ArgumentError] when exponent associated with a unit is > 20 or < -20 + def unit_signature_vector + return self.to_base.unit_signature_vector unless self.is_base? + vector = Array.new(SIGNATURE_VECTOR.size, 0) + # it's possible to have a kind that misses the array... kinds like :counting + # are more like prefixes, so don't use them to calculate the vector + @numerator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition| + index = SIGNATURE_VECTOR.index(definition.kind) + vector[index] += 1 if index end - combined[k] += 1 unless k.nil? || k == UNITY + @denominator.map { |element| RubyUnits::Unit.definition(element) }.each do |definition| + index = SIGNATURE_VECTOR.index(definition.kind) + vector[index] -= 1 if index + end + raise ArgumentError, "Power out of range (-20 < net power of a unit < 20)" if vector.any? { |x| x.abs >=20 } + return vector end - j = 0 - loop do - break if j > den.size + private + + # used by #dup to duplicate a Unit + # @param [Unit] other + # @private + def initialize_copy(other) + @numerator = other.numerator.dup + @denominator = other.denominator.dup + end + + # calculates the unit signature id for use in comparing compatible units and simplification + # the signature is based on a simple classification of units and is based on the following publication + # + # Novak, G.S., Jr. "Conversion of units of measurement", IEEE Transactions on Software Engineering, 21(8), Aug 1995, pp.651-661 + # @see http://doi.ieeecomputersociety.org/10.1109/32.403789 + # @return [Array] + def unit_signature + return @signature unless @signature.nil? + vector = unit_signature_vector + vector.each_with_index { |item, index| vector[index] = item * 20**index } + @signature=vector.inject(0) { |sum, n| sum+n } + return @signature + end + + # @param [Numeric] q quantity + # @param [Array] n numerator + # @param [Array] d denominator + # @return [Hash] + def self.eliminate_terms(q, n, d) + num = n.dup + den = d.dup + + num.delete_if { |v| v == UNITY } + den.delete_if { |v| v == UNITY } + combined = Hash.new(0) + + i = 0 + loop do + break if i > num.size + if @@PREFIX_VALUES.has_key? num[i] + k = [num[i], num[i+1]] + i += 2 + else + k = num[i] + i += 1 + end + combined[k] += 1 unless k.nil? || k == UNITY + end + + j = 0 + loop do + break if j > den.size if @@PREFIX_VALUES.has_key? den[j] - k = [den[j],den[j+1]] + k = [den[j], den[j+1]] j += 2 else k = den[j] j += 1 end - combined[k] -= 1 unless k.nil? || k == UNITY - end - - num = [] - den = [] - for key, value in combined do - case - when value > 0 - value.times {num << key} - when value < 0 - value.abs.times {den << key} + combined[k] -= 1 unless k.nil? || k == UNITY end - end - num = UNITY_ARRAY if num.empty? - den = UNITY_ARRAY if den.empty? - return {:scalar=>q, :numerator=>num.flatten.compact, :denominator=>den.flatten.compact} - end - # parse a string into a unit object. - # Typical formats like : - # "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 - # @return [nil | Unit] - # @todo This should either be a separate class or at least a class method - def parse(passed_unit_string="0") - unit_string = passed_unit_string.dup - if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ - unit_string = "#{$1} USD" - end - unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8 - - unit_string.gsub!(/%/,'percent') - unit_string.gsub!(/'/,'feet') - unit_string.gsub!(/"/,'inch') - unit_string.gsub!(/#/,'pound') - - #:nocov: - #:nocov_19: - if defined?(Uncertain) && unit_string =~ /(\+\/-|±)/ - value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0] - result = unit_s.unit * Uncertain.new(value.to_f,uncertainty.to_f) - copy(result) - return - end - #:nocov: - #:nocov_19: - - if defined?(Complex) && unit_string =~ COMPLEX_NUMBER - real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] - result = Unit(unit_s || '1') * Complex(real.to_f,imaginary.to_f) - copy(result) - return - end - - if defined?(Rational) && unit_string =~ RATIONAL_NUMBER - numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - result = Unit(unit_s || '1') * Rational(numerator.to_i,denominator.to_i) - copy(result) - return - end - - unit_string =~ NUMBER_REGEX - unit = @@cached_units[$2] - mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 - mult = mult.to_int if (mult.to_int == mult) - if unit - copy(unit) - @scalar *= mult - @base_scalar *= mult - return self - end - unit_string.gsub!(/<(#{@@UNIT_REGEX})><(#{@@UNIT_REGEX})>/, '\1*\2') - unit_string.gsub!(/[<>]/,"") - - if unit_string =~ /:/ - hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] - raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? {|x| x.nil?} - result = "#{hours || 0} h".unit + - "#{minutes || 0} minutes".unit + - "#{seconds || 0} seconds".unit + - "#{microseconds || 0} usec".unit - copy(result) - return - end - - # Special processing for unusual unit strings - # feet -- 6'5" - feet, inches = unit_string.scan(FEET_INCH_REGEX)[0] - if (feet && inches) - result = Unit.new("#{feet} ft") + Unit.new("#{inches} inches") - copy(result) - return - end - - # weight -- 8 lbs 12 oz - pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0] - if (pounds && oz) - result = Unit.new("#{pounds} lbs") + Unit.new("#{oz} oz") - copy(result) - return - end - - # more than one per. I.e., "1 m/s/s" - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 - @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts - top.scan(TOP_REGEX).each do |item| - n = item[1].to_i - x = "#{item[0]} " - case - when n>=0 - top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) {|s| x * n} - when n<0 - bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/,"") + num = [] + den = [] + for key, value in combined do + case + when value > 0 + value.times { num << key } + when value < 0 + value.abs.times { den << key } + end end + num = UNITY_ARRAY if num.empty? + den = UNITY_ARRAY if den.empty? + return { :scalar => q, :numerator => num.flatten.compact, :denominator => den.flatten.compact } end - bottom.gsub!(BOTTOM_REGEX) {|s| "#{$1} " * $2.to_i} if bottom - @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? - @scalar = 1 unless @scalar.kind_of? Numeric - @scalar = @scalar.to_int if (@scalar.to_int == @scalar) - @numerator ||= UNITY_ARRAY - @denominator ||= UNITY_ARRAY - @numerator = top.scan(Unit.unit_match_regex).delete_if {|x| x.empty?}.compact if top - @denominator = bottom.scan(Unit.unit_match_regex).delete_if {|x| x.empty?}.compact if bottom + # parse a string into a unit object. + # Typical formats like : + # "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 + # @return [nil | Unit] + # @todo This should either be a separate class or at least a class method + def parse(passed_unit_string="0") + unit_string = passed_unit_string.dup + if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ + unit_string = "#{$1} USD" + end + unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8 + + unit_string.gsub!(/%/, 'percent') + unit_string.gsub!(/'/, 'feet') + unit_string.gsub!(/"/, 'inch') + unit_string.gsub!(/#/, 'pound') + + #:nocov: + #:nocov_19: + if defined?(Uncertain) && unit_string =~ /(\+\/-|±)/ + value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0] + result = unit_s.unit * Uncertain.new(value.to_f, uncertainty.to_f) + copy(result) + return + end + #:nocov: + #:nocov_19: - # eliminate all known terms from this string. This is a quick check to see if the passed unit - # contains terms that are not defined. - used = "#{top} #{bottom}".to_s.gsub(Unit.unit_match_regex,'').gsub(/[\d\*, "'_^\/\$]/,'') - raise( ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty? + if defined?(Complex) && unit_string =~ COMPLEX_NUMBER + real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] + result = Unit(unit_s || '1') * Complex(real.to_f, imaginary.to_f) + copy(result) + return + end - @numerator = @numerator.map do |item| - @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] - end.flatten.compact.delete_if {|x| x.empty?} + if defined?(Rational) && unit_string =~ RATIONAL_NUMBER + numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] + result = Unit(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) + copy(result) + return + end - @denominator = @denominator.map do |item| - @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] - end.flatten.compact.delete_if {|x| x.empty?} + unit_string =~ NUMBER_REGEX + unit = @@cached_units[$2] + mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 + mult = mult.to_int if (mult.to_int == mult) + if unit + copy(unit) + @scalar *= mult + @base_scalar *= mult + return self + end + unit_string.gsub!(/<(#{@@UNIT_REGEX})><(#{@@UNIT_REGEX})>/, '\1*\2') + unit_string.gsub!(/[<>]/, "") + + if unit_string =~ /:/ + hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] + raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? { |x| x.nil? } + result = "#{hours || 0} h".unit + + "#{minutes || 0} minutes".unit + + "#{seconds || 0} seconds".unit + + "#{microseconds || 0} usec".unit + copy(result) + return + end - @numerator = UNITY_ARRAY if @numerator.empty? - @denominator = UNITY_ARRAY if @denominator.empty? - return self - end + # Special processing for unusual unit strings + # feet -- 6'5" + feet, inches = unit_string.scan(FEET_INCH_REGEX)[0] + if (feet && inches) + result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches") + copy(result) + return + end - # return an array of base units - # @return [Array] - def self.base_units - return @@base_units ||= @@definitions.dup.delete_if {|_, defn| !defn.base?}.keys.map {|u| Unit.new(u)} - end + # weight -- 8 lbs 12 oz + pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0] + if (pounds && oz) + result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz") + copy(result) + return + end - private - - # parse a string consisting of a number and a unit string - # @param [String] string - # @return [Array] consisting of [Numeric, "unit"] - # @private - def self.parse_into_numbers_and_units(string) - # scientific notation.... 123.234E22, -123.456e-10 - sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} - # rational numbers.... -1/3, 1/5, 20/100 - rational = %r{[+-]?\d+\/\d+} - # complex numbers... -1.2+3i, +1.2-3.3i - complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([\D].*)?} - num, unit = string.scan(anynumber).first - - return [case num - when NilClass - 1 - when complex - if num.respond_to?(:to_c) - num.to_c - else - #:nocov_19: - Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map {|n| n.to_i}) - #:nocov_19: + # more than one per. I.e., "1 m/s/s" + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 + @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts + top.scan(TOP_REGEX).each do |item| + n = item[1].to_i + x = "#{item[0]} " + case + when n>=0 + top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { |s| x * n } + when n<0 + bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, "") end - when rational - Rational(*num.split("/").map {|x| x.to_i}) - else - num.to_f - end, unit.to_s.strip] - end + end + bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } if bottom + @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? + @scalar = 1 unless @scalar.kind_of? Numeric + @scalar = @scalar.to_int if (@scalar.to_int == @scalar) + + @numerator ||= UNITY_ARRAY + @denominator ||= UNITY_ARRAY + @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if top + @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if bottom + + # eliminate all known terms from this string. This is a quick check to see if the passed unit + # contains terms that are not defined. + used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(/[\d\*, "'_^\/\$]/, '') + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty? + + @numerator = @numerator.map do |item| + @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] + end.flatten.compact.delete_if { |x| x.empty? } + + @denominator = @denominator.map do |item| + @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] + end.flatten.compact.delete_if { |x| x.empty? } + + @numerator = UNITY_ARRAY if @numerator.empty? + @denominator = UNITY_ARRAY if @denominator.empty? + return self + end - # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. - # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names - # @return [String] - # @private - def self.unit_regex - @@UNIT_REGEX ||= @@UNIT_MAP.keys.sort_by {|unit_name| [unit_name.length, unit_name]}.reverse.join('|') - end + # return an array of base units + # @return [Array] + def self.base_units + return @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) } + end - # return a regex used to match units - # @return [RegExp] - # @private - def self.unit_match_regex - @@UNIT_MATCH_REGEX ||= /(#{Unit.prefix_regex})*?(#{Unit.unit_regex})\b/ - end + private + + # parse a string consisting of a number and a unit string + # @param [String] string + # @return [Array] consisting of [Numeric, "unit"] + # @private + def self.parse_into_numbers_and_units(string) + # scientific notation.... 123.234E22, -123.456e-10 + sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} + # rational numbers.... -1/3, 1/5, 20/100 + rational = %r{[+-]?\d+\/\d+} + # complex numbers... -1.2+3i, +1.2-3.3i + complex = %r{#{sci}{2,2}i} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([\D].*)?} + num, unit = string.scan(anynumber).first + + return [case num + when NilClass + 1 + when complex + if num.respond_to?(:to_c) + num.to_c + else + #:nocov_19: + Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map { |n| n.to_i }) + #:nocov_19: + end + when rational + Rational(*num.split("/").map { |x| x.to_i }) + else + num.to_f + end, unit.to_s.strip] + end - # return a regexp fragment used to match prefixes - # @return [String] - # @private - def self.prefix_regex - return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by {|prefix| [prefix.length, prefix]}.reverse.join('|') - end + # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. + # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names + # @return [String] + # @private + def self.unit_regex + @@UNIT_REGEX ||= @@UNIT_MAP.keys.sort_by { |unit_name| [unit_name.length, unit_name] }.reverse.join('|') + end - def self.temp_regex - @@TEMP_REGEX ||= Regexp.new "(?:#{ + # return a regex used to match units + # @return [RegExp] + # @private + def self.unit_match_regex + @@UNIT_MATCH_REGEX ||= /(#{RubyUnits::Unit.prefix_regex})*?(#{RubyUnits::Unit.unit_regex})\b/ + end + + # return a regexp fragment used to match prefixes + # @return [String] + # @private + def self.prefix_regex + return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by { |prefix| [prefix.length, prefix] }.reverse.join('|') + end + + def self.temp_regex + @@TEMP_REGEX ||= Regexp.new "(?:#{ temp_units=%w(tempK tempC tempF tempR degK degC degF degR) - aliases=temp_units.map{|unit| d=Unit.definition(unit); d && d.aliases}.flatten.compact - regex_str= aliases.empty? ? '(?!x)x' : aliases.join('|') + aliases =temp_units.map { |unit| d=RubyUnits::Unit.definition(unit); d && d.aliases }.flatten.compact + regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') regex_str - })" - end + })" + end - # inject a definition into the internal array and set it up for use - # @private - def self.use_definition(definition) - @@UNIT_MATCH_REGEX = nil #invalidate the unit match regex - @@TEMP_REGEX = nil #invalidate the temp regex - if definition.prefix? - @@PREFIX_VALUES[definition.name] = definition.scalar - definition.aliases.each {|_alias| @@PREFIX_MAP[_alias] = definition.name } - @@PREFIX_REGEX = nil #invalidate the prefix regex - else - @@UNIT_VALUES[definition.name] = {} - @@UNIT_VALUES[definition.name][:scalar] = definition.scalar - @@UNIT_VALUES[definition.name][:numerator] = definition.numerator if definition.numerator - @@UNIT_VALUES[definition.name][:denominator] = definition.denominator if definition.denominator - definition.aliases.each {|_alias| @@UNIT_MAP[_alias] = definition.name} - @@UNIT_REGEX = nil #invalidate the unit regex + # inject a definition into the internal array and set it up for use + # @private + def self.use_definition(definition) + @@UNIT_MATCH_REGEX = nil #invalidate the unit match regex + @@TEMP_REGEX = nil #invalidate the temp regex + if definition.prefix? + @@PREFIX_VALUES[definition.name] = definition.scalar + definition.aliases.each { |_alias| @@PREFIX_MAP[_alias] = definition.name } + @@PREFIX_REGEX = nil #invalidate the prefix regex + else + @@UNIT_VALUES[definition.name] = {} + @@UNIT_VALUES[definition.name][:scalar] = definition.scalar + @@UNIT_VALUES[definition.name][:numerator] = definition.numerator if definition.numerator + @@UNIT_VALUES[definition.name][:denominator] = definition.denominator if definition.denominator + definition.aliases.each { |_alias| @@UNIT_MAP[_alias] = definition.name } + @@UNIT_REGEX = nil #invalidate the unit regex + end end end - end diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index 6795cf32..a18c67bc 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -1,98 +1,98 @@ # seed the cache -Unit('1') +RubyUnits::Unit('1') -Unit.define("meter") do |unit| +RubyUnits::Unit.define("meter") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{m meter meters metre metres} unit.kind = :length end -Unit.define("kilogram") do |unit| +RubyUnits::Unit.define("kilogram") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{kg kilogram kilograms} unit.kind = :mass end -Unit.define("second") do |unit| +RubyUnits::Unit.define("second") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{s sec second seconds} unit.kind = :time end -Unit.define("mole") do |unit| +RubyUnits::Unit.define("mole") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{mol mole} unit.kind = :substance end -Unit.define("ampere") do |unit| +RubyUnits::Unit.define("ampere") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{A ampere amperes amp amps} unit.kind = :current end -Unit.define("radian") do |unit| +RubyUnits::Unit.define("radian") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{rad radian radians} unit.kind = :angle end -Unit.define("kelvin") do |unit| +RubyUnits::Unit.define("kelvin") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{degK kelvin} unit.kind = :temperature end -Unit.define("tempK") do |unit| +RubyUnits::Unit.define("tempK") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{tempK} unit.kind = :temperature end -Unit.define("byte") do |unit| +RubyUnits::Unit.define("byte") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{B byte bytes} unit.kind = :memory end -Unit.define("dollar") do |unit| +RubyUnits::Unit.define("dollar") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{USD dollar} unit.kind = :currency end -Unit.define("candela") do |unit| +RubyUnits::Unit.define("candela") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{cd candela} unit.kind = :luminosity end -Unit.define("each") do |unit| +RubyUnits::Unit.define("each") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{each} unit.kind = :counting end -Unit.define("steradian") do |unit| +RubyUnits::Unit.define("steradian") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{sr steradian steradians} unit.kind = :solid_angle end -Unit.define("decibel") do |unit| +RubyUnits::Unit.define("decibel") do |unit| unit.scalar = 1 unit.numerator = %w{} unit.aliases = %w{dB decibel decibels} diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 3b3e9da1..041ea5aa 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -31,10 +31,10 @@ 'zepto' => [%w{z Zepto zepto}, Rational(1,1e21)], 'yocto' => [%w{y Yocto yocto}, Rational(1,1e24)] }.each do |name, definition| - Unit.define(name) do |unit| + RubyUnits::Unit.define(name) do |unit| aliases, scalar = definition unit.aliases = aliases unit.scalar = scalar unit.kind = :prefix end -end \ No newline at end of file +end diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index a1987f4c..0a40d1f2 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -1,705 +1,705 @@ # length units -Unit.define('inch') do |inch| - inch.definition = Unit('254/10000 meter') +RubyUnits::Unit.define('inch') do |inch| + inch.definition = RubyUnits::Unit('254/10000 meter') inch.aliases = %w{in inch inches "} end -Unit.define('foot') do |foot| - foot.definition = Unit('12 inches') +RubyUnits::Unit.define('foot') do |foot| + foot.definition = RubyUnits::Unit('12 inches') foot.aliases = %w{ft foot feet '} end -Unit.define('survey-foot') do |sft| - sft.definition = Unit('1200/3937 meter') +RubyUnits::Unit.define('survey-foot') do |sft| + sft.definition = RubyUnits::Unit('1200/3937 meter') sft.aliases = %w{sft sfoot sfeet} end -Unit.define('yard') do |yard| - yard.definition = Unit('3 ft') +RubyUnits::Unit.define('yard') do |yard| + yard.definition = RubyUnits::Unit('3 ft') yard.aliases = %w{yd yard yards} end -Unit.define('mile') do |mile| - mile.definition = Unit('5280 ft') +RubyUnits::Unit.define('mile') do |mile| + mile.definition = RubyUnits::Unit('5280 ft') mile.aliases = %w{mi mile miles} end -Unit.define('naut-mile') do |naut| - naut.definition = Unit('1852 m') +RubyUnits::Unit.define('naut-mile') do |naut| + naut.definition = RubyUnits::Unit('1852 m') naut.aliases = %w{nmi M NM} end # on land -Unit.define('league') do |league| - league.definition = Unit('3 miles') +RubyUnits::Unit.define('league') do |league| + league.definition = RubyUnits::Unit('3 miles') league.aliases = %w{league leagues} end # at sea -Unit.define('naut-league') do |naut_league| - naut_league.definition = Unit('3 nmi') +RubyUnits::Unit.define('naut-league') do |naut_league| + naut_league.definition = RubyUnits::Unit('3 nmi') naut_league.aliases = %w{nleague nleagues} end -Unit.define('furlong') do |furlong| - furlong.definition = Unit('1/8 mile') +RubyUnits::Unit.define('furlong') do |furlong| + furlong.definition = RubyUnits::Unit('1/8 mile') furlong.aliases = %w{fur furlong furlongs} end -Unit.define('rod') do |rod| - rod.definition = Unit('33/2 feet') +RubyUnits::Unit.define('rod') do |rod| + rod.definition = RubyUnits::Unit('33/2 feet') rod.aliases = %w{rd rod rods} end -Unit.define('fathom') do |fathom| - fathom.definition = Unit('6 ft') +RubyUnits::Unit.define('fathom') do |fathom| + fathom.definition = RubyUnits::Unit('6 ft') fathom.aliases = %w{fathom fathoms} end -Unit.define('mil') do |mil| - mil.definition = Unit('1/1000 inch') +RubyUnits::Unit.define('mil') do |mil| + mil.definition = RubyUnits::Unit('1/1000 inch') mil.aliases = %w{mil mils} end -Unit.define('angstrom') do |ang| - ang.definition = Unit('1/10 nm') +RubyUnits::Unit.define('angstrom') do |ang| + ang.definition = RubyUnits::Unit('1/10 nm') ang.aliases = %w{ang angstrom angstroms} end # typesetting -Unit.define('point') do |point| - point.definition = Unit('1/72 ft') +RubyUnits::Unit.define('point') do |point| + point.definition = RubyUnits::Unit('1/72 ft') point.aliases = %w{point points} end -Unit.define('pica') do |pica| - pica.definition = Unit('12 point') +RubyUnits::Unit.define('pica') do |pica| + pica.definition = RubyUnits::Unit('12 point') pica.aliases = %w{P pica picas} end -Unit.define('dot') do |dot| - dot.definition = Unit('1 each') +RubyUnits::Unit.define('dot') do |dot| + dot.definition = RubyUnits::Unit('1 each') dot.aliases = %w{dot dots} dot.kind = :counting end -Unit.define('pixel') do |pixel| - pixel.definition = Unit('1 each') +RubyUnits::Unit.define('pixel') do |pixel| + pixel.definition = RubyUnits::Unit('1 each') pixel.aliases = %w{px pixel pixels} pixel.kind = :counting end -Unit.define('ppi') do |ppi| - ppi.definition = Unit('1 pixel/inch') +RubyUnits::Unit.define('ppi') do |ppi| + ppi.definition = RubyUnits::Unit('1 pixel/inch') end -Unit.define('dpi') do |dpi| - dpi.definition = Unit('1 dot/inch') +RubyUnits::Unit.define('dpi') do |dpi| + dpi.definition = RubyUnits::Unit('1 dot/inch') end # Mass -avagadro_constant = Unit('6.02214129e23 1/mol') +avagadro_constant = RubyUnits::Unit('6.02214129e23 1/mol') -Unit.define('AMU') do |amu| - amu.definition = Unit('12 kg/mol') / (12 * avagadro_constant) +RubyUnits::Unit.define('AMU') do |amu| + amu.definition = RubyUnits::Unit('12 kg/mol') / (12 * avagadro_constant) amu.aliases = %w{u AMU amu} end -Unit.define('dalton') do |dalton| - dalton.definition = Unit('1 amu') +RubyUnits::Unit.define('dalton') do |dalton| + dalton.definition = RubyUnits::Unit('1 amu') dalton.aliases = %w{Da dalton daltons} end -standard_gravitation = Unit('9.80665 m/s^2') +standard_gravitation = RubyUnits::Unit('9.80665 m/s^2') -Unit.define('metric-ton') do |mton| - mton.definition = Unit('1000 kg') +RubyUnits::Unit.define('metric-ton') do |mton| + mton.definition = RubyUnits::Unit('1000 kg') mton.aliases = %w{tonne} end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations -Unit.define('pound') do |pound| - pound.definition = Unit(Rational(45359237,1e8), 'kg') +RubyUnits::Unit.define('pound') do |pound| + pound.definition = RubyUnits::Unit(Rational(45359237,1e8), 'kg') pound.aliases = %w{lbs lb lbm pound-mass pound pounds #} end -Unit.define('ounce') do |ounce| - ounce.definition = Unit('1/16 lbs') +RubyUnits::Unit.define('ounce') do |ounce| + ounce.definition = RubyUnits::Unit('1/16 lbs') ounce.aliases = %w{oz ounce ounces} end -Unit.define('gram') do |gram| - gram.definition = Unit('1/1000 kg') +RubyUnits::Unit.define('gram') do |gram| + gram.definition = RubyUnits::Unit('1/1000 kg') gram.aliases = %w{g gram grams gramme grammes} end -Unit.define('short-ton') do |ton| - ton.definition = Unit('2000 lbs') +RubyUnits::Unit.define('short-ton') do |ton| + ton.definition = RubyUnits::Unit('2000 lbs') ton.aliases = %w{ton tn} end -Unit.define('carat') do |carat| - carat.definition = Unit('1/5000 kg') +RubyUnits::Unit.define('carat') do |carat| + carat.definition = RubyUnits::Unit('1/5000 kg') carat.aliases = %w{ct carat carats} end # time -Unit.define('minute') do |min| - min.definition = Unit('60 seconds') +RubyUnits::Unit.define('minute') do |min| + min.definition = RubyUnits::Unit('60 seconds') min.aliases = %w{min minute minutes} end -Unit.define('hour') do |hour| - hour.definition = Unit('60 minutes') +RubyUnits::Unit.define('hour') do |hour| + hour.definition = RubyUnits::Unit('60 minutes') hour.aliases = %w{h hr hrs hour hours} end -Unit.define('day') do |day| - day.definition = Unit('24 hours') +RubyUnits::Unit.define('day') do |day| + day.definition = RubyUnits::Unit('24 hours') day.aliases = %w{d day days} end -Unit.define('week') do |week| - week.definition = Unit('7 days') +RubyUnits::Unit.define('week') do |week| + week.definition = RubyUnits::Unit('7 days') week.aliases = %w{wk week weeks} end -Unit.define('fortnight') do |fortnight| - fortnight.definition = Unit('2 weeks') +RubyUnits::Unit.define('fortnight') do |fortnight| + fortnight.definition = RubyUnits::Unit('2 weeks') fortnight.aliases = %w{fortnight fortnights} end -Unit.define('year') do |year| - year.definition = Unit('31556926 seconds') # works out to 365.24219907407405 days +RubyUnits::Unit.define('year') do |year| + year.definition = RubyUnits::Unit('31556926 seconds') # works out to 365.24219907407405 days year.aliases = %w{y yr year years annum} end -Unit.define('decade') do |decade| - decade.definition = Unit('10 years') +RubyUnits::Unit.define('decade') do |decade| + decade.definition = RubyUnits::Unit('10 years') decade.aliases = %w{decade decades} end -Unit.define('century') do |century| - century.definition = Unit('100 years') +RubyUnits::Unit.define('century') do |century| + century.definition = RubyUnits::Unit('100 years') century.aliases = %w{century centuries} end # area -Unit.define('hectare') do |hectare| - hectare.definition = Unit('10000 m^2') +RubyUnits::Unit.define('hectare') do |hectare| + hectare.definition = RubyUnits::Unit('10000 m^2') end -Unit.define('acre') do |acre| - acre.definition = Unit('1 mi')**2 / 640 +RubyUnits::Unit.define('acre') do |acre| + acre.definition = RubyUnits::Unit('1 mi')**2 / 640 acre.aliases = %w{acre acres} end -Unit.define('sqft') do |sqft| - sqft.definition = Unit('1 ft^2') +RubyUnits::Unit.define('sqft') do |sqft| + sqft.definition = RubyUnits::Unit('1 ft^2') end -Unit.define('sqin') do |sqin| - sqin.definition = Unit('1 in^2') +RubyUnits::Unit.define('sqin') do |sqin| + sqin.definition = RubyUnits::Unit('1 in^2') end # volume -Unit.define('liter') do |liter| - liter.definition = Unit('1/1000 m^3') +RubyUnits::Unit.define('liter') do |liter| + liter.definition = RubyUnits::Unit('1/1000 m^3') liter.aliases = %w{l L liter liters litre litres} end -Unit.define('gallon') do |gallon| - gallon.definition = Unit('231 in^3') +RubyUnits::Unit.define('gallon') do |gallon| + gallon.definition = RubyUnits::Unit('231 in^3') gallon.aliases = %w{gal gallon gallons} end -Unit.define('quart') do |quart| - quart.definition = Unit('1/4 gal') +RubyUnits::Unit.define('quart') do |quart| + quart.definition = RubyUnits::Unit('1/4 gal') quart.aliases = %w{qt quart quarts} end -Unit.define('pint') do |pint| - pint.definition = Unit('1/8 gal') +RubyUnits::Unit.define('pint') do |pint| + pint.definition = RubyUnits::Unit('1/8 gal') pint.aliases = %w{pt pint pints} end -Unit.define('cup') do |cup| - cup.definition = Unit('1/16 gal') +RubyUnits::Unit.define('cup') do |cup| + cup.definition = RubyUnits::Unit('1/16 gal') cup.aliases = %w{cu cup cups} end -Unit.define('fluid-ounce') do |floz| - floz.definition = Unit('1/128 gal') +RubyUnits::Unit.define('fluid-ounce') do |floz| + floz.definition = RubyUnits::Unit('1/128 gal') floz.aliases = %w{floz fluid-ounce fluid-ounces} end -Unit.define('tablespoon') do |tbsp| - tbsp.definition = Unit('1/2 floz') +RubyUnits::Unit.define('tablespoon') do |tbsp| + tbsp.definition = RubyUnits::Unit('1/2 floz') tbsp.aliases = %w{tbs tbsp tablespoon tablespoons} end -Unit.define('teaspoon') do |tsp| - tsp.definition = Unit('1/3 tablespoon') +RubyUnits::Unit.define('teaspoon') do |tsp| + tsp.definition = RubyUnits::Unit('1/3 tablespoon') tsp.aliases = %w{tsp teaspoon teaspoons} end # volumetric flow -Unit.define('cfm') do |cfm| - cfm.definition = Unit('1 ft^3/minute') +RubyUnits::Unit.define('cfm') do |cfm| + cfm.definition = RubyUnits::Unit('1 ft^3/minute') cfm.aliases = %w{cfm CFM CFPM} end # speed -Unit.define('kph') do |kph| - kph.definition = Unit('1 kilometer/hour') +RubyUnits::Unit.define('kph') do |kph| + kph.definition = RubyUnits::Unit('1 kilometer/hour') end -Unit.define('mph') do |mph| - mph.definition = Unit('1 mile/hour') +RubyUnits::Unit.define('mph') do |mph| + mph.definition = RubyUnits::Unit('1 mile/hour') end -Unit.define('fps') do |fps| - fps.definition = Unit('1 foot/second') +RubyUnits::Unit.define('fps') do |fps| + fps.definition = RubyUnits::Unit('1 foot/second') end -Unit.define('knot') do |knot| - knot.definition = Unit('1 nmi/hour') +RubyUnits::Unit.define('knot') do |knot| + knot.definition = RubyUnits::Unit('1 nmi/hour') knot.aliases = %w{kt kn kts knot knots} end -Unit.define('gee') do |gee| +RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors - gee.definition = Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 + gee.definition = RubyUnits::Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 gee.aliases = %w{gee standard-gravitation} end # temperature differences -Unit.define('newton') do |newton| - newton.definition = Unit('1 kg*m/s^2') +RubyUnits::Unit.define('newton') do |newton| + newton.definition = RubyUnits::Unit('1 kg*m/s^2') newton.aliases = %w{N newton newtons} end -Unit.define('dyne') do |dyne| - dyne.definition = Unit('1/100000 N') +RubyUnits::Unit.define('dyne') do |dyne| + dyne.definition = RubyUnits::Unit('1/100000 N') dyne.aliases = %w{dyn dyne} end -Unit.define('pound-force') do |lbf| - lbf.definition = Unit('1 lb') * Unit('1 gee') +RubyUnits::Unit.define('pound-force') do |lbf| + lbf.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 gee') lbf.aliases = %w{lbf pound-force} end -Unit.define('poundal') do |poundal| - poundal.definition = Unit('1 lb') * Unit('1 ft/s^2') +RubyUnits::Unit.define('poundal') do |poundal| + poundal.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 ft/s^2') poundal.aliases = %w{pdl poundal poundals} end temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 -Unit.define('celsius') do |celsius| - celsius.definition = Unit('1 degK') +RubyUnits::Unit.define('celsius') do |celsius| + celsius.definition = RubyUnits::Unit('1 degK') celsius.aliases = %w{degC celsius centigrade} end -Unit.define('fahrenheit') do |fahrenheit| - fahrenheit.definition = Unit(temp_convert_factor, 'degK') +RubyUnits::Unit.define('fahrenheit') do |fahrenheit| + fahrenheit.definition = RubyUnits::Unit(temp_convert_factor, 'degK') fahrenheit.aliases = %w{degF fahrenheit} end -Unit.define('rankine') do |rankine| - rankine.definition = Unit('1 degF') +RubyUnits::Unit.define('rankine') do |rankine| + rankine.definition = RubyUnits::Unit('1 degF') rankine.aliases = %w{degR rankine} end -Unit.define('tempC') do |tempC| - tempC.definition = Unit('1 tempK') +RubyUnits::Unit.define('tempC') do |tempC| + tempC.definition = RubyUnits::Unit('1 tempK') end -Unit.define('tempF') do |tempF| - tempF.definition = Unit(temp_convert_factor, 'tempK') +RubyUnits::Unit.define('tempF') do |tempF| + tempF.definition = RubyUnits::Unit(temp_convert_factor, 'tempK') end -Unit.define('tempR') do |tempR| - tempR.definition = Unit('1 tempF') +RubyUnits::Unit.define('tempR') do |tempR| + tempR.definition = RubyUnits::Unit('1 tempF') end # astronomy -speed_of_light = Unit('299792458 m/s') +speed_of_light = RubyUnits::Unit('299792458 m/s') -Unit.define('light-second') do |ls| - ls.definition = Unit('1 s') * speed_of_light +RubyUnits::Unit.define('light-second') do |ls| + ls.definition = RubyUnits::Unit('1 s') * speed_of_light ls.aliases = %w{ls lsec light-second} end -Unit.define('light-minute') do |lmin| - lmin.definition = Unit('1 min') * speed_of_light +RubyUnits::Unit.define('light-minute') do |lmin| + lmin.definition = RubyUnits::Unit('1 min') * speed_of_light lmin.aliases = %w{lmin light-minute} end -Unit.define('light-year') do |ly| - ly.definition = Unit('1 y') * speed_of_light +RubyUnits::Unit.define('light-year') do |ly| + ly.definition = RubyUnits::Unit('1 y') * speed_of_light ly.aliases = %w{ly light-year} end -Unit.define('parsec') do |parsec| - parsec.definition = Unit('3.26163626 ly') +RubyUnits::Unit.define('parsec') do |parsec| + parsec.definition = RubyUnits::Unit('3.26163626 ly') parsec.aliases = %w{pc parsec parsecs} end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit -Unit.define('AU') do |au| - au.definition = Unit('149597870700 m') +RubyUnits::Unit.define('AU') do |au| + au.definition = RubyUnits::Unit('149597870700 m') au.aliases = %w{AU astronomical-unit} end -Unit.define('redshift') do |red| - red.definition = Unit('1.302773e26 m') +RubyUnits::Unit.define('redshift') do |red| + red.definition = RubyUnits::Unit('1.302773e26 m') red.aliases = %w{z red-shift} end # mass -Unit.define('slug') do |slug| - slug.definition = Unit('1 lbf*s^2/ft') +RubyUnits::Unit.define('slug') do |slug| + slug.definition = RubyUnits::Unit('1 lbf*s^2/ft') slug.aliases = %w{slug slugs} end # pressure -Unit.define('pascal') do |pascal| - pascal.definition = Unit('1 kg/m*s^2') +RubyUnits::Unit.define('pascal') do |pascal| + pascal.definition = RubyUnits::Unit('1 kg/m*s^2') pascal.aliases = %w{Pa pascal pascals} end -Unit.define('bar') do |bar| - bar.definition = Unit('100 kPa') +RubyUnits::Unit.define('bar') do |bar| + bar.definition = RubyUnits::Unit('100 kPa') bar.aliases = %w{bar bars} end -Unit.define('atm') do |atm| - atm.definition = Unit('101325 Pa') +RubyUnits::Unit.define('atm') do |atm| + atm.definition = RubyUnits::Unit('101325 Pa') atm.aliases = %w{atm ATM atmosphere atmospheres} end -Unit.define('mmHg') do |mmhg| - density_of_mercury = Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - mmhg.definition = Unit('1 mm') * Unit('1 gee') * density_of_mercury +RubyUnits::Unit.define('mmHg') do |mmhg| + density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + mmhg.definition = RubyUnits::Unit('1 mm') * RubyUnits::Unit('1 gee') * density_of_mercury end -Unit.define('inHg') do |inhg| - density_of_mercury = Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - inhg.definition = Unit('1 in') * Unit('1 gee') * density_of_mercury +RubyUnits::Unit.define('inHg') do |inhg| + density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + inhg.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_mercury end -Unit.define('torr') do |torr| - torr.definition = Unit('1/760 atm') +RubyUnits::Unit.define('torr') do |torr| + torr.definition = RubyUnits::Unit('1/760 atm') torr.aliases = %w{Torr torr} end -Unit.define('psi') do |psi| - psi.definition = Unit('1 lbf/in^2') +RubyUnits::Unit.define('psi') do |psi| + psi.definition = RubyUnits::Unit('1 lbf/in^2') end -Unit.define('cmh2o') do |cmh2o| - density_of_water = Unit('1 g/cm^3') # at 4 tempC - cmh2o.definition = Unit('1 cm') * Unit('1 gee') * density_of_water +RubyUnits::Unit.define('cmh2o') do |cmh2o| + density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC + cmh2o.definition = RubyUnits::Unit('1 cm') * RubyUnits::Unit('1 gee') * density_of_water cmh2o.aliases = %w{cmH2O cmh2o cmAq} end -Unit.define('inh2o') do |inh2o| - density_of_water = Unit('1 g/cm^3') # at 4 tempC - inh2o.definition = Unit('1 in') * Unit('1 gee') * density_of_water +RubyUnits::Unit.define('inh2o') do |inh2o| + density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC + inh2o.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_water inh2o.aliases = %w{inH2O inh2o inAq} end #viscosity -Unit.define('poise') do |poise| - poise.definition = Unit('dPa*s') +RubyUnits::Unit.define('poise') do |poise| + poise.definition = RubyUnits::Unit('dPa*s') poise.aliases = %w{P poise} end -Unit.define('stokes') do |stokes| - stokes.definition = Unit('1 cm^2/s') +RubyUnits::Unit.define('stokes') do |stokes| + stokes.definition = RubyUnits::Unit('1 cm^2/s') stokes.aliases = %w{St stokes} end # #energy -Unit.define('joule') do |joule| - joule.definition = Unit('1 N*m') +RubyUnits::Unit.define('joule') do |joule| + joule.definition = RubyUnits::Unit('1 N*m') joule.aliases = %w{J joule joules} end -Unit.define('erg') do |erg| - erg.definition = Unit('1 g*cm^2/s^2') +RubyUnits::Unit.define('erg') do |erg| + erg.definition = RubyUnits::Unit('1 g*cm^2/s^2') erg.aliases = %w{erg ergs} end #power -Unit.define('watt') do |watt| - watt.definition = Unit('1 N*m/s') +RubyUnits::Unit.define('watt') do |watt| + watt.definition = RubyUnits::Unit('1 N*m/s') watt.aliases = %w{W Watt watt watts} end -Unit.define('horsepower') do |hp| - hp.definition = Unit('33000 ft*lbf/min') +RubyUnits::Unit.define('horsepower') do |hp| + hp.definition = RubyUnits::Unit('33000 ft*lbf/min') hp.aliases = %w{hp horsepower} end # energy -Unit.define('btu') do |btu| - btu.definition = Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard +RubyUnits::Unit.define('btu') do |btu| + btu.definition = RubyUnits::Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard btu.aliases = %w{Btu btu Btus btus} end -Unit.define('therm') do |therm| - therm.definition = Unit('100 kBtu') +RubyUnits::Unit.define('therm') do |therm| + therm.definition = RubyUnits::Unit('100 kBtu') therm.aliases = %w{thm therm therms Therm} end # "small" calorie -Unit.define('calorie') do |calorie| - calorie.definition = Unit('4.184 J') +RubyUnits::Unit.define('calorie') do |calorie| + calorie.definition = RubyUnits::Unit('4.184 J') calorie.aliases = %w{cal calorie calories} end # "big" calorie -Unit.define('Calorie') do |calorie| - calorie.definition = Unit('1 kcal') +RubyUnits::Unit.define('Calorie') do |calorie| + calorie.definition = RubyUnits::Unit('1 kcal') calorie.aliases = %w{Cal Calorie Calories} end -Unit.define('molar') do |molar| - molar.definition = Unit('1 mole/l') +RubyUnits::Unit.define('molar') do |molar| + molar.definition = RubyUnits::Unit('1 mole/l') molar.aliases = %w{M molar} end # potential -Unit.define('volt') do |volt| - volt.definition = Unit('1 W/A') +RubyUnits::Unit.define('volt') do |volt| + volt.definition = RubyUnits::Unit('1 W/A') volt.aliases = %w{V volt volts} end # capacitance -Unit.define('farad') do |farad| - farad.definition = Unit('1 A*s/V') +RubyUnits::Unit.define('farad') do |farad| + farad.definition = RubyUnits::Unit('1 A*s/V') farad.aliases = %w{F farad farads} end # charge -Unit.define('coulomb') do |coulomb| - coulomb.definition = Unit('1 A*s') +RubyUnits::Unit.define('coulomb') do |coulomb| + coulomb.definition = RubyUnits::Unit('1 A*s') coulomb.aliases = %w{C coulomb coulombs} end # conductance -Unit.define('siemens') do |siemens| - siemens.definition = Unit('1 A/V') +RubyUnits::Unit.define('siemens') do |siemens| + siemens.definition = RubyUnits::Unit('1 A/V') siemens.aliases = %w{S siemens} end # inductance -Unit.define('henry') do |henry| - henry.definition = Unit('1 J/A^2') +RubyUnits::Unit.define('henry') do |henry| + henry.definition = RubyUnits::Unit('1 J/A^2') henry.aliases = %w{H henry henries} end # resistance -Unit.define('ohm') do |ohm| - ohm.definition = Unit('1 V/A') +RubyUnits::Unit.define('ohm') do |ohm| + ohm.definition = RubyUnits::Unit('1 V/A') ohm.aliases = %w{Ohm ohm ohms} end # magnetism -Unit.define('weber') do |weber| - weber.definition = Unit('1 V*s') +RubyUnits::Unit.define('weber') do |weber| + weber.definition = RubyUnits::Unit('1 V*s') weber.aliases = %w{Wb weber webers} end -Unit.define('tesla') do |tesla| - tesla.definition = Unit('1 V*s/m^2') +RubyUnits::Unit.define('tesla') do |tesla| + tesla.definition = RubyUnits::Unit('1 V*s/m^2') tesla.aliases = %w{T tesla teslas} end -Unit.define('gauss') do |gauss| - gauss.definition = Unit('100 microT') +RubyUnits::Unit.define('gauss') do |gauss| + gauss.definition = RubyUnits::Unit('100 microT') gauss.aliases = %w{G gauss} end -Unit.define('maxwell') do |maxwell| - maxwell.definition = Unit('1 gauss*cm^2') +RubyUnits::Unit.define('maxwell') do |maxwell| + maxwell.definition = RubyUnits::Unit('1 gauss*cm^2') maxwell.aliases = %w{Mx maxwell maxwells} end -Unit.define('oersted') do |oersted| - oersted.definition = Unit(250.0/Math::PI, 'A/m') +RubyUnits::Unit.define('oersted') do |oersted| + oersted.definition = RubyUnits::Unit(250.0/Math::PI, 'A/m') oersted.aliases = %w{Oe oersted oersteds} end #activity -Unit.define('katal') do |katal| - katal.definition = Unit('1 mole/sec') +RubyUnits::Unit.define('katal') do |katal| + katal.definition = RubyUnits::Unit('1 mole/sec') katal.aliases = %w{kat katal} end -Unit.define('unit') do |unit| - unit.definition = Unit('1/60 microkatal') - unit.aliases = %w{U enzUnit} +RubyUnits::Unit.define('unit') do |unit| + unit.definition = RubyUnits::Unit('1/60 microkatal') + unit.aliases = %w{U enzRubyUnits::Unit} end #frequency -Unit.define('hertz') do |hz| - hz.definition = Unit('1 1/s') +RubyUnits::Unit.define('hertz') do |hz| + hz.definition = RubyUnits::Unit('1 1/s') hz.aliases = %w{Hz hertz} end #angle -Unit.define('degree') do |deg| - deg.definition = Unit(Math::PI / 180.0, 'radian') +RubyUnits::Unit.define('degree') do |deg| + deg.definition = RubyUnits::Unit(Math::PI / 180.0, 'radian') deg.aliases = %w{deg degree degrees} end -Unit.define('grad') do |grad| - grad.definition = Unit(Math::PI / 200.0, 'radian') +RubyUnits::Unit.define('grad') do |grad| + grad.definition = RubyUnits::Unit(Math::PI / 200.0, 'radian') grad.aliases = %w{grad gradian grads} end #rotation -Unit.define('rotation') do |rotation| - rotation.definition = Unit(2.0*Math::PI, 'radian') +RubyUnits::Unit.define('rotation') do |rotation| + rotation.definition = RubyUnits::Unit(2.0*Math::PI, 'radian') end -Unit.define('rpm') do |rpm| - rpm.definition = Unit('1 rotation/min') +RubyUnits::Unit.define('rpm') do |rpm| + rpm.definition = RubyUnits::Unit('1 rotation/min') end #memory -Unit.define('bit') do |bit| - bit.definition = Unit('1/8 byte') +RubyUnits::Unit.define('bit') do |bit| + bit.definition = RubyUnits::Unit('1/8 byte') bit.aliases = %w{b bit} end #currency -Unit.define('cents') do |cents| - cents.definition = Unit('1/100 dollar') +RubyUnits::Unit.define('cents') do |cents| + cents.definition = RubyUnits::Unit('1/100 dollar') end #luminosity -Unit.define('lumen') do |lumen| - lumen.definition = Unit('1 cd*steradian') +RubyUnits::Unit.define('lumen') do |lumen| + lumen.definition = RubyUnits::Unit('1 cd*steradian') lumen.aliases = %w{lm lumen} end -Unit.define('lux') do |lux| - lux.definition = Unit('1 lumen/m^2') +RubyUnits::Unit.define('lux') do |lux| + lux.definition = RubyUnits::Unit('1 lumen/m^2') end #radiation -Unit.define('gray') do |gray| - gray.definition = Unit('1 J/kg') +RubyUnits::Unit.define('gray') do |gray| + gray.definition = RubyUnits::Unit('1 J/kg') gray.aliases = %w{Gy gray grays} end -Unit.define('roentgen') do |roentgen| - roentgen.definition = Unit('2.58e-4 C/kg') +RubyUnits::Unit.define('roentgen') do |roentgen| + roentgen.definition = RubyUnits::Unit('2.58e-4 C/kg') roentgen.aliases = %w{R roentgen} end -Unit.define('sievert') do |sievert| - sievert.definition = Unit('1 J/kg') +RubyUnits::Unit.define('sievert') do |sievert| + sievert.definition = RubyUnits::Unit('1 J/kg') sievert.aliases = %w{Sv sievert sieverts} end -Unit.define('becquerel') do |becquerel| - becquerel.definition = Unit('1 1/s') +RubyUnits::Unit.define('becquerel') do |becquerel| + becquerel.definition = RubyUnits::Unit('1 1/s') becquerel.aliases = %w{Bq becquerel becquerels} end -Unit.define('curie') do |curie| - curie.definition = Unit('37 GBq') +RubyUnits::Unit.define('curie') do |curie| + curie.definition = RubyUnits::Unit('37 GBq') curie.aliases = %w{Ci curie curies} end -Unit.define('count') do |count| - count.definition = Unit('1 each') +RubyUnits::Unit.define('count') do |count| + count.definition = RubyUnits::Unit('1 each') count.kind = :counting end # rate -Unit.define('cpm') do |cpm| - cpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('cpm') do |cpm| + cpm.definition = RubyUnits::Unit('1 count/min') end -Unit.define('dpm') do |dpm| - dpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('dpm') do |dpm| + dpm.definition = RubyUnits::Unit('1 count/min') end -Unit.define('bpm') do |bpm| - bpm.definition = Unit('1 count/min') +RubyUnits::Unit.define('bpm') do |bpm| + bpm.definition = RubyUnits::Unit('1 count/min') end # misc -Unit.define('dozen') do |dozen| - dozen.definition = Unit('12 each') +RubyUnits::Unit.define('dozen') do |dozen| + dozen.definition = RubyUnits::Unit('12 each') dozen.aliases = %w{doz dz dozen} dozen.kind = :counting end -Unit.define('gross') do |gross| - gross.definition = Unit('12 dozen') +RubyUnits::Unit.define('gross') do |gross| + gross.definition = RubyUnits::Unit('12 dozen') gross.aliases = %w{gr gross} gross.kind = :counting end -Unit.define('cell') do |cell| - cell.definition = Unit('1 each') +RubyUnits::Unit.define('cell') do |cell| + cell.definition = RubyUnits::Unit('1 each') cell.aliases = %w{cells cell} cell.kind = :counting end -Unit.define('base-pair') do |bp| - bp.definition = Unit('1 each') +RubyUnits::Unit.define('base-pair') do |bp| + bp.definition = RubyUnits::Unit('1 each') bp.aliases = %w{bp base-pair} bp.kind = :counting end -Unit.define('nucleotide') do |nt| - nt.definition = Unit('1 each') +RubyUnits::Unit.define('nucleotide') do |nt| + nt.definition = RubyUnits::Unit('1 each') nt.aliases = %w{nt} nt.kind = :counting end -Unit.define('molecule') do |molecule| - molecule.definition = Unit('1 each') +RubyUnits::Unit.define('molecule') do |molecule| + molecule.definition = RubyUnits::Unit('1 each') molecule.aliases = %w{molecule molecules} molecule.kind = :counting end -Unit.define('percent') do |percent| - percent.definition = Unit('1/100') +RubyUnits::Unit.define('percent') do |percent| + percent.definition = RubyUnits::Unit('1/100') percent.aliases = %w{% percent} end -Unit.define('ppm') do |ppm| - ppm.definition = Unit(1) / 1_000_000 +RubyUnits::Unit.define('ppm') do |ppm| + ppm.definition = RubyUnits::Unit(1) / 1_000_000 end -Unit.define('ppb') do |ppb| - ppb.definition = Unit(1) / 1_000_000_000 +RubyUnits::Unit.define('ppb') do |ppb| + ppb.definition = RubyUnits::Unit(1) / 1_000_000_000 end diff --git a/lib/ruby_units/version.rb b/lib/ruby_units/version.rb index 1d6dee39..059e2ca3 100644 --- a/lib/ruby_units/version.rb +++ b/lib/ruby_units/version.rb @@ -1,6 +1,8 @@ -class Unit < Numeric - # Pull the version number from the VERSION file - module Version - STRING = File.read(File.dirname(__FILE__) + "/../../VERSION") +module RubyUnits + class Unit < Numeric + # Pull the version number from the VERSION file + module Version + STRING = File.read(File.dirname(__FILE__) + "/../../VERSION") + end end -end \ No newline at end of file +end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 408d7698..e0501b0c 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -603,7 +603,7 @@ describe '#to_yaml' do subject { Unit('1 mm') } - its(:to_yaml) {should =~ /--- !ruby\/object:Unit/ } + its(:to_yaml) {should =~ /--- !ruby\/object:RubyUnits::Unit/ } end describe "#definition" do @@ -834,7 +834,7 @@ specify { Unit("2 m").should > Unit("1 ft")} specify { Unit("70 tempF").should > Unit("10 degC")} specify { Unit("1 m").should > 0 } - specify { expect { Unit("1 m").should_not > nil}.to raise_error(ArgumentError, /comparison of Unit with (nil failed|NilClass)/) } + specify { expect { Unit("1 m").should_not > nil}.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do From 5aacc00b09eb7f2ef9e18110ff01df915824a21e Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 11:59:09 -0400 Subject: [PATCH 009/150] Don't load 'Unit()' helper if only loading namespaced code. Add travis config for 2.0.0 --- .travis.yml | 3 +- README.md | 6 +- lib/ruby-units | 1 + lib/ruby-units.rb | 7 +- lib/ruby_units/namespaced.rb | 30 ++- lib/ruby_units/time.rb | 1 + lib/ruby_units/unit.rb | 16 +- lib/ruby_units/unit_definitions.rb | 6 +- lib/ruby_units/unit_definitions/base.rb | 2 +- lib/ruby_units/unit_definitions/standard.rb | 274 ++++++++++---------- 10 files changed, 176 insertions(+), 170 deletions(-) create mode 120000 lib/ruby-units diff --git a/.travis.yml b/.travis.yml index 4b6f75d1..07bf44b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: ruby rvm: - 1.9.3 - jruby-19mode # JRuby in 1.9 mode + - 2.0.0 jdk: - openjdk6 - openjdk7 @@ -9,4 +10,4 @@ matrix: exclude: - rvm: 1.9.3 jdk: openjdk7 -script: bundle exec rake --trace \ No newline at end of file +script: bundle exec rake --trace diff --git a/README.md b/README.md index 7d61e19f..45e2d86a 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ [![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) -Kevin C. Olbrich, Ph.D. - -[Sciwerks.com](http://www.sciwerks.com) +Kevin C. Olbrich, Ph.D. Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) @@ -36,7 +34,7 @@ This package may be installed using: `gem install ruby-units` 2. use SI notation when possible 3. avoid using spaces in unit names -## Unit compatability: +## Unit compatibility: Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. unit1 =~ unit2 #=> true if units are compatible diff --git a/lib/ruby-units b/lib/ruby-units new file mode 120000 index 00000000..661dac0c --- /dev/null +++ b/lib/ruby-units @@ -0,0 +1 @@ +./ruby_units \ No newline at end of file diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index 820e4f30..36b5cb09 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -1,6 +1,9 @@ - $LOAD_PATH << File.dirname(__FILE__) -require 'ruby_units/namespaced' +require_relative 'ruby_units/namespaced' + +# only include the Unit('unit') helper if we aren't fully namespaced +require_relative 'ruby_units/object' + Unit = RubyUnits::Unit diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb index 2efc61e1..229fdd00 100644 --- a/lib/ruby_units/namespaced.rb +++ b/lib/ruby_units/namespaced.rb @@ -1,14 +1,16 @@ -# require this file to avoid creating an class alias from Unit to RubyUnits::Unit -require "ruby_units/version" -require "ruby_units/definition" -require "ruby_units/cache" -require 'ruby_units/array' -require 'ruby_units/date' -require 'ruby_units/time' -require 'ruby_units/math' -require 'ruby_units/numeric' -require 'ruby_units/object' -require 'ruby_units/string' -require 'ruby_units/unit' -require 'ruby_units/fixnum' -require 'ruby_units/unit_definitions' + +$LOAD_PATH << File.dirname(__FILE__) + +# require_relative this file to avoid creating an class alias from Unit to RubyUnits::Unit +require_relative 'version' +require_relative 'definition' +require_relative 'cache' +require_relative 'array' +require_relative 'date' +require_relative 'time' +require_relative 'math' +require_relative 'numeric' +require_relative 'string' +require_relative 'unit' +require_relative 'fixnum' +require_relative 'unit_definitions' diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index 020c602e..78488546 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -1,3 +1,4 @@ +require 'time' # # Time math is handled slightly differently. The difference is considered to be an exact duration if # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 200be03b..694735e7 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -25,7 +25,7 @@ # @example Define a new unit # RubyUnits::Unit.define("foobar") do |unit| # unit.aliases = %w{foo fb foo-bar} -# unit.definition = Unit("1 baz") +# unit.definition = RubyUnits::Unit.new("1 baz") # end # # @todo fix class variables so they conform to standard naming conventions and refactor away as many of them as possible @@ -177,11 +177,11 @@ def self.definitions # # @example Block form # RubyUnits::Unit.define('foobar') do |foobar| - # foobar.definition = Unit("1 baz") + # foobar.definition = RubyUnits::Unit.new("1 baz") # end # # @example RubyUnits::Unit::Definition form - # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = Unit("1 baz")} + # unit_definition = RubyUnits::Unit::Definition.new("foobar") {|foobar| foobar.definition = RubyUnits::Unit.new("1 baz")} # RubyUnits::Unit.define(unit_definition) def self.define(unit_definition, &block) if block_given? @@ -674,8 +674,8 @@ def =~(other) # Compare two units. Returns true if quantities and units match # @example - # Unit("100 cm") === Unit("100 cm") # => true - # Unit("100 cm") === Unit("1 m") # => false + # RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("100 cm") # => true + # RubyUnits::Unit.new("100 cm") === RubyUnits::Unit.new("1 m") # => false # @param [Object] other # @return [Boolean] def ===(other) @@ -928,7 +928,7 @@ def root(n) # returns inverse of Unit (1/unit) # @return [Unit] def inverse - return Unit("1") / self + return RubyUnits::Unit.new("1") / self end # convert to a specified unit string or to the same units as another Unit @@ -1415,14 +1415,14 @@ def parse(passed_unit_string="0") if defined?(Complex) && unit_string =~ COMPLEX_NUMBER real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] - result = Unit(unit_s || '1') * Complex(real.to_f, imaginary.to_f) + result = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f) copy(result) return end if defined?(Rational) && unit_string =~ RATIONAL_NUMBER numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - result = Unit(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) + result = RubyUnits::Unit.new(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) copy(result) return end diff --git a/lib/ruby_units/unit_definitions.rb b/lib/ruby_units/unit_definitions.rb index 4f6b0ea6..0aa0331f 100644 --- a/lib/ruby_units/unit_definitions.rb +++ b/lib/ruby_units/unit_definitions.rb @@ -1,3 +1,3 @@ -require 'ruby_units/unit_definitions/prefix' -require 'ruby_units/unit_definitions/base' -require 'ruby_units/unit_definitions/standard' +require_relative 'unit_definitions/prefix' +require_relative 'unit_definitions/base' +require_relative 'unit_definitions/standard' diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index a18c67bc..952cc238 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -1,5 +1,5 @@ # seed the cache -RubyUnits::Unit('1') +RubyUnits::Unit.new('1') RubyUnits::Unit.define("meter") do |unit| unit.scalar = 1 diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 0a40d1f2..17ec11bd 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -1,705 +1,705 @@ # length units RubyUnits::Unit.define('inch') do |inch| - inch.definition = RubyUnits::Unit('254/10000 meter') + inch.definition = RubyUnits::Unit.new('254/10000 meter') inch.aliases = %w{in inch inches "} end RubyUnits::Unit.define('foot') do |foot| - foot.definition = RubyUnits::Unit('12 inches') + foot.definition = RubyUnits::Unit.new('12 inches') foot.aliases = %w{ft foot feet '} end RubyUnits::Unit.define('survey-foot') do |sft| - sft.definition = RubyUnits::Unit('1200/3937 meter') + sft.definition = RubyUnits::Unit.new('1200/3937 meter') sft.aliases = %w{sft sfoot sfeet} end RubyUnits::Unit.define('yard') do |yard| - yard.definition = RubyUnits::Unit('3 ft') + yard.definition = RubyUnits::Unit.new('3 ft') yard.aliases = %w{yd yard yards} end RubyUnits::Unit.define('mile') do |mile| - mile.definition = RubyUnits::Unit('5280 ft') + mile.definition = RubyUnits::Unit.new('5280 ft') mile.aliases = %w{mi mile miles} end RubyUnits::Unit.define('naut-mile') do |naut| - naut.definition = RubyUnits::Unit('1852 m') + naut.definition = RubyUnits::Unit.new('1852 m') naut.aliases = %w{nmi M NM} end # on land RubyUnits::Unit.define('league') do |league| - league.definition = RubyUnits::Unit('3 miles') + league.definition = RubyUnits::Unit.new('3 miles') league.aliases = %w{league leagues} end # at sea RubyUnits::Unit.define('naut-league') do |naut_league| - naut_league.definition = RubyUnits::Unit('3 nmi') + naut_league.definition = RubyUnits::Unit.new('3 nmi') naut_league.aliases = %w{nleague nleagues} end RubyUnits::Unit.define('furlong') do |furlong| - furlong.definition = RubyUnits::Unit('1/8 mile') + furlong.definition = RubyUnits::Unit.new('1/8 mile') furlong.aliases = %w{fur furlong furlongs} end RubyUnits::Unit.define('rod') do |rod| - rod.definition = RubyUnits::Unit('33/2 feet') + rod.definition = RubyUnits::Unit.new('33/2 feet') rod.aliases = %w{rd rod rods} end RubyUnits::Unit.define('fathom') do |fathom| - fathom.definition = RubyUnits::Unit('6 ft') + fathom.definition = RubyUnits::Unit.new('6 ft') fathom.aliases = %w{fathom fathoms} end RubyUnits::Unit.define('mil') do |mil| - mil.definition = RubyUnits::Unit('1/1000 inch') + mil.definition = RubyUnits::Unit.new('1/1000 inch') mil.aliases = %w{mil mils} end RubyUnits::Unit.define('angstrom') do |ang| - ang.definition = RubyUnits::Unit('1/10 nm') + ang.definition = RubyUnits::Unit.new('1/10 nm') ang.aliases = %w{ang angstrom angstroms} end # typesetting RubyUnits::Unit.define('point') do |point| - point.definition = RubyUnits::Unit('1/72 ft') + point.definition = RubyUnits::Unit.new('1/72 ft') point.aliases = %w{point points} end RubyUnits::Unit.define('pica') do |pica| - pica.definition = RubyUnits::Unit('12 point') + pica.definition = RubyUnits::Unit.new('12 point') pica.aliases = %w{P pica picas} end RubyUnits::Unit.define('dot') do |dot| - dot.definition = RubyUnits::Unit('1 each') + dot.definition = RubyUnits::Unit.new('1 each') dot.aliases = %w{dot dots} dot.kind = :counting end RubyUnits::Unit.define('pixel') do |pixel| - pixel.definition = RubyUnits::Unit('1 each') + pixel.definition = RubyUnits::Unit.new('1 each') pixel.aliases = %w{px pixel pixels} pixel.kind = :counting end RubyUnits::Unit.define('ppi') do |ppi| - ppi.definition = RubyUnits::Unit('1 pixel/inch') + ppi.definition = RubyUnits::Unit.new('1 pixel/inch') end RubyUnits::Unit.define('dpi') do |dpi| - dpi.definition = RubyUnits::Unit('1 dot/inch') + dpi.definition = RubyUnits::Unit.new('1 dot/inch') end # Mass -avagadro_constant = RubyUnits::Unit('6.02214129e23 1/mol') +avagadro_constant = RubyUnits::Unit.new('6.02214129e23 1/mol') RubyUnits::Unit.define('AMU') do |amu| - amu.definition = RubyUnits::Unit('12 kg/mol') / (12 * avagadro_constant) + amu.definition = RubyUnits::Unit.new('12 kg/mol') / (12 * avagadro_constant) amu.aliases = %w{u AMU amu} end RubyUnits::Unit.define('dalton') do |dalton| - dalton.definition = RubyUnits::Unit('1 amu') + dalton.definition = RubyUnits::Unit.new('1 amu') dalton.aliases = %w{Da dalton daltons} end -standard_gravitation = RubyUnits::Unit('9.80665 m/s^2') +standard_gravitation = RubyUnits::Unit.new('9.80665 m/s^2') RubyUnits::Unit.define('metric-ton') do |mton| - mton.definition = RubyUnits::Unit('1000 kg') + mton.definition = RubyUnits::Unit.new('1000 kg') mton.aliases = %w{tonne} end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations RubyUnits::Unit.define('pound') do |pound| - pound.definition = RubyUnits::Unit(Rational(45359237,1e8), 'kg') + pound.definition = RubyUnits::Unit.new(Rational(45359237,1e8), 'kg') pound.aliases = %w{lbs lb lbm pound-mass pound pounds #} end RubyUnits::Unit.define('ounce') do |ounce| - ounce.definition = RubyUnits::Unit('1/16 lbs') + ounce.definition = RubyUnits::Unit.new('1/16 lbs') ounce.aliases = %w{oz ounce ounces} end RubyUnits::Unit.define('gram') do |gram| - gram.definition = RubyUnits::Unit('1/1000 kg') + gram.definition = RubyUnits::Unit.new('1/1000 kg') gram.aliases = %w{g gram grams gramme grammes} end RubyUnits::Unit.define('short-ton') do |ton| - ton.definition = RubyUnits::Unit('2000 lbs') + ton.definition = RubyUnits::Unit.new('2000 lbs') ton.aliases = %w{ton tn} end RubyUnits::Unit.define('carat') do |carat| - carat.definition = RubyUnits::Unit('1/5000 kg') + carat.definition = RubyUnits::Unit.new('1/5000 kg') carat.aliases = %w{ct carat carats} end # time RubyUnits::Unit.define('minute') do |min| - min.definition = RubyUnits::Unit('60 seconds') + min.definition = RubyUnits::Unit.new('60 seconds') min.aliases = %w{min minute minutes} end RubyUnits::Unit.define('hour') do |hour| - hour.definition = RubyUnits::Unit('60 minutes') + hour.definition = RubyUnits::Unit.new('60 minutes') hour.aliases = %w{h hr hrs hour hours} end RubyUnits::Unit.define('day') do |day| - day.definition = RubyUnits::Unit('24 hours') + day.definition = RubyUnits::Unit.new('24 hours') day.aliases = %w{d day days} end RubyUnits::Unit.define('week') do |week| - week.definition = RubyUnits::Unit('7 days') + week.definition = RubyUnits::Unit.new('7 days') week.aliases = %w{wk week weeks} end RubyUnits::Unit.define('fortnight') do |fortnight| - fortnight.definition = RubyUnits::Unit('2 weeks') + fortnight.definition = RubyUnits::Unit.new('2 weeks') fortnight.aliases = %w{fortnight fortnights} end RubyUnits::Unit.define('year') do |year| - year.definition = RubyUnits::Unit('31556926 seconds') # works out to 365.24219907407405 days + year.definition = RubyUnits::Unit.new('31556926 seconds') # works out to 365.24219907407405 days year.aliases = %w{y yr year years annum} end RubyUnits::Unit.define('decade') do |decade| - decade.definition = RubyUnits::Unit('10 years') + decade.definition = RubyUnits::Unit.new('10 years') decade.aliases = %w{decade decades} end RubyUnits::Unit.define('century') do |century| - century.definition = RubyUnits::Unit('100 years') + century.definition = RubyUnits::Unit.new('100 years') century.aliases = %w{century centuries} end # area RubyUnits::Unit.define('hectare') do |hectare| - hectare.definition = RubyUnits::Unit('10000 m^2') + hectare.definition = RubyUnits::Unit.new('10000 m^2') end RubyUnits::Unit.define('acre') do |acre| - acre.definition = RubyUnits::Unit('1 mi')**2 / 640 + acre.definition = RubyUnits::Unit.new('1 mi')**2 / 640 acre.aliases = %w{acre acres} end RubyUnits::Unit.define('sqft') do |sqft| - sqft.definition = RubyUnits::Unit('1 ft^2') + sqft.definition = RubyUnits::Unit.new('1 ft^2') end RubyUnits::Unit.define('sqin') do |sqin| - sqin.definition = RubyUnits::Unit('1 in^2') + sqin.definition = RubyUnits::Unit.new('1 in^2') end # volume RubyUnits::Unit.define('liter') do |liter| - liter.definition = RubyUnits::Unit('1/1000 m^3') + liter.definition = RubyUnits::Unit.new('1/1000 m^3') liter.aliases = %w{l L liter liters litre litres} end RubyUnits::Unit.define('gallon') do |gallon| - gallon.definition = RubyUnits::Unit('231 in^3') + gallon.definition = RubyUnits::Unit.new('231 in^3') gallon.aliases = %w{gal gallon gallons} end RubyUnits::Unit.define('quart') do |quart| - quart.definition = RubyUnits::Unit('1/4 gal') + quart.definition = RubyUnits::Unit.new('1/4 gal') quart.aliases = %w{qt quart quarts} end RubyUnits::Unit.define('pint') do |pint| - pint.definition = RubyUnits::Unit('1/8 gal') + pint.definition = RubyUnits::Unit.new('1/8 gal') pint.aliases = %w{pt pint pints} end RubyUnits::Unit.define('cup') do |cup| - cup.definition = RubyUnits::Unit('1/16 gal') + cup.definition = RubyUnits::Unit.new('1/16 gal') cup.aliases = %w{cu cup cups} end RubyUnits::Unit.define('fluid-ounce') do |floz| - floz.definition = RubyUnits::Unit('1/128 gal') + floz.definition = RubyUnits::Unit.new('1/128 gal') floz.aliases = %w{floz fluid-ounce fluid-ounces} end RubyUnits::Unit.define('tablespoon') do |tbsp| - tbsp.definition = RubyUnits::Unit('1/2 floz') + tbsp.definition = RubyUnits::Unit.new('1/2 floz') tbsp.aliases = %w{tbs tbsp tablespoon tablespoons} end RubyUnits::Unit.define('teaspoon') do |tsp| - tsp.definition = RubyUnits::Unit('1/3 tablespoon') + tsp.definition = RubyUnits::Unit.new('1/3 tablespoon') tsp.aliases = %w{tsp teaspoon teaspoons} end # volumetric flow RubyUnits::Unit.define('cfm') do |cfm| - cfm.definition = RubyUnits::Unit('1 ft^3/minute') + cfm.definition = RubyUnits::Unit.new('1 ft^3/minute') cfm.aliases = %w{cfm CFM CFPM} end # speed RubyUnits::Unit.define('kph') do |kph| - kph.definition = RubyUnits::Unit('1 kilometer/hour') + kph.definition = RubyUnits::Unit.new('1 kilometer/hour') end RubyUnits::Unit.define('mph') do |mph| - mph.definition = RubyUnits::Unit('1 mile/hour') + mph.definition = RubyUnits::Unit.new('1 mile/hour') end RubyUnits::Unit.define('fps') do |fps| - fps.definition = RubyUnits::Unit('1 foot/second') + fps.definition = RubyUnits::Unit.new('1 foot/second') end RubyUnits::Unit.define('knot') do |knot| - knot.definition = RubyUnits::Unit('1 nmi/hour') + knot.definition = RubyUnits::Unit.new('1 nmi/hour') knot.aliases = %w{kt kn kts knot knots} end RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors - gee.definition = RubyUnits::Unit(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 + gee.definition = RubyUnits::Unit.new(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 gee.aliases = %w{gee standard-gravitation} end # temperature differences RubyUnits::Unit.define('newton') do |newton| - newton.definition = RubyUnits::Unit('1 kg*m/s^2') + newton.definition = RubyUnits::Unit.new('1 kg*m/s^2') newton.aliases = %w{N newton newtons} end RubyUnits::Unit.define('dyne') do |dyne| - dyne.definition = RubyUnits::Unit('1/100000 N') + dyne.definition = RubyUnits::Unit.new('1/100000 N') dyne.aliases = %w{dyn dyne} end RubyUnits::Unit.define('pound-force') do |lbf| - lbf.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 gee') + lbf.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 gee') lbf.aliases = %w{lbf pound-force} end RubyUnits::Unit.define('poundal') do |poundal| - poundal.definition = RubyUnits::Unit('1 lb') * RubyUnits::Unit('1 ft/s^2') + poundal.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 ft/s^2') poundal.aliases = %w{pdl poundal poundals} end temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 RubyUnits::Unit.define('celsius') do |celsius| - celsius.definition = RubyUnits::Unit('1 degK') + celsius.definition = RubyUnits::Unit.new('1 degK') celsius.aliases = %w{degC celsius centigrade} end RubyUnits::Unit.define('fahrenheit') do |fahrenheit| - fahrenheit.definition = RubyUnits::Unit(temp_convert_factor, 'degK') + fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') fahrenheit.aliases = %w{degF fahrenheit} end RubyUnits::Unit.define('rankine') do |rankine| - rankine.definition = RubyUnits::Unit('1 degF') + rankine.definition = RubyUnits::Unit.new('1 degF') rankine.aliases = %w{degR rankine} end RubyUnits::Unit.define('tempC') do |tempC| - tempC.definition = RubyUnits::Unit('1 tempK') + tempC.definition = RubyUnits::Unit.new('1 tempK') end RubyUnits::Unit.define('tempF') do |tempF| - tempF.definition = RubyUnits::Unit(temp_convert_factor, 'tempK') + tempF.definition = RubyUnits::Unit.new(temp_convert_factor, 'tempK') end RubyUnits::Unit.define('tempR') do |tempR| - tempR.definition = RubyUnits::Unit('1 tempF') + tempR.definition = RubyUnits::Unit.new('1 tempF') end # astronomy -speed_of_light = RubyUnits::Unit('299792458 m/s') +speed_of_light = RubyUnits::Unit.new('299792458 m/s') RubyUnits::Unit.define('light-second') do |ls| - ls.definition = RubyUnits::Unit('1 s') * speed_of_light + ls.definition = RubyUnits::Unit.new('1 s') * speed_of_light ls.aliases = %w{ls lsec light-second} end RubyUnits::Unit.define('light-minute') do |lmin| - lmin.definition = RubyUnits::Unit('1 min') * speed_of_light + lmin.definition = RubyUnits::Unit.new('1 min') * speed_of_light lmin.aliases = %w{lmin light-minute} end RubyUnits::Unit.define('light-year') do |ly| - ly.definition = RubyUnits::Unit('1 y') * speed_of_light + ly.definition = RubyUnits::Unit.new('1 y') * speed_of_light ly.aliases = %w{ly light-year} end RubyUnits::Unit.define('parsec') do |parsec| - parsec.definition = RubyUnits::Unit('3.26163626 ly') + parsec.definition = RubyUnits::Unit.new('3.26163626 ly') parsec.aliases = %w{pc parsec parsecs} end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit RubyUnits::Unit.define('AU') do |au| - au.definition = RubyUnits::Unit('149597870700 m') + au.definition = RubyUnits::Unit.new('149597870700 m') au.aliases = %w{AU astronomical-unit} end RubyUnits::Unit.define('redshift') do |red| - red.definition = RubyUnits::Unit('1.302773e26 m') + red.definition = RubyUnits::Unit.new('1.302773e26 m') red.aliases = %w{z red-shift} end # mass RubyUnits::Unit.define('slug') do |slug| - slug.definition = RubyUnits::Unit('1 lbf*s^2/ft') + slug.definition = RubyUnits::Unit.new('1 lbf*s^2/ft') slug.aliases = %w{slug slugs} end # pressure RubyUnits::Unit.define('pascal') do |pascal| - pascal.definition = RubyUnits::Unit('1 kg/m*s^2') + pascal.definition = RubyUnits::Unit.new('1 kg/m*s^2') pascal.aliases = %w{Pa pascal pascals} end RubyUnits::Unit.define('bar') do |bar| - bar.definition = RubyUnits::Unit('100 kPa') + bar.definition = RubyUnits::Unit.new('100 kPa') bar.aliases = %w{bar bars} end RubyUnits::Unit.define('atm') do |atm| - atm.definition = RubyUnits::Unit('101325 Pa') + atm.definition = RubyUnits::Unit.new('101325 Pa') atm.aliases = %w{atm ATM atmosphere atmospheres} end RubyUnits::Unit.define('mmHg') do |mmhg| - density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - mmhg.definition = RubyUnits::Unit('1 mm') * RubyUnits::Unit('1 gee') * density_of_mercury + density_of_mercury = RubyUnits::Unit.new('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + mmhg.definition = RubyUnits::Unit.new('1 mm') * RubyUnits::Unit.new('1 gee') * density_of_mercury end RubyUnits::Unit.define('inHg') do |inhg| - density_of_mercury = RubyUnits::Unit('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC - inhg.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_mercury + density_of_mercury = RubyUnits::Unit.new('7653360911758079/562949953421312 g/cm^3') # 13.5951 g/cm^3 at 0 tempC + inhg.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_mercury end RubyUnits::Unit.define('torr') do |torr| - torr.definition = RubyUnits::Unit('1/760 atm') + torr.definition = RubyUnits::Unit.new('1/760 atm') torr.aliases = %w{Torr torr} end RubyUnits::Unit.define('psi') do |psi| - psi.definition = RubyUnits::Unit('1 lbf/in^2') + psi.definition = RubyUnits::Unit.new('1 lbf/in^2') end RubyUnits::Unit.define('cmh2o') do |cmh2o| - density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC - cmh2o.definition = RubyUnits::Unit('1 cm') * RubyUnits::Unit('1 gee') * density_of_water + density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC + cmh2o.definition = RubyUnits::Unit.new('1 cm') * RubyUnits::Unit.new('1 gee') * density_of_water cmh2o.aliases = %w{cmH2O cmh2o cmAq} end RubyUnits::Unit.define('inh2o') do |inh2o| - density_of_water = RubyUnits::Unit('1 g/cm^3') # at 4 tempC - inh2o.definition = RubyUnits::Unit('1 in') * RubyUnits::Unit('1 gee') * density_of_water + density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC + inh2o.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_water inh2o.aliases = %w{inH2O inh2o inAq} end #viscosity RubyUnits::Unit.define('poise') do |poise| - poise.definition = RubyUnits::Unit('dPa*s') + poise.definition = RubyUnits::Unit.new('dPa*s') poise.aliases = %w{P poise} end RubyUnits::Unit.define('stokes') do |stokes| - stokes.definition = RubyUnits::Unit('1 cm^2/s') + stokes.definition = RubyUnits::Unit.new('1 cm^2/s') stokes.aliases = %w{St stokes} end # #energy RubyUnits::Unit.define('joule') do |joule| - joule.definition = RubyUnits::Unit('1 N*m') + joule.definition = RubyUnits::Unit.new('1 N*m') joule.aliases = %w{J joule joules} end RubyUnits::Unit.define('erg') do |erg| - erg.definition = RubyUnits::Unit('1 g*cm^2/s^2') + erg.definition = RubyUnits::Unit.new('1 g*cm^2/s^2') erg.aliases = %w{erg ergs} end #power RubyUnits::Unit.define('watt') do |watt| - watt.definition = RubyUnits::Unit('1 N*m/s') + watt.definition = RubyUnits::Unit.new('1 N*m/s') watt.aliases = %w{W Watt watt watts} end RubyUnits::Unit.define('horsepower') do |hp| - hp.definition = RubyUnits::Unit('33000 ft*lbf/min') + hp.definition = RubyUnits::Unit.new('33000 ft*lbf/min') hp.aliases = %w{hp horsepower} end # energy RubyUnits::Unit.define('btu') do |btu| - btu.definition = RubyUnits::Unit('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard + btu.definition = RubyUnits::Unit.new('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard btu.aliases = %w{Btu btu Btus btus} end RubyUnits::Unit.define('therm') do |therm| - therm.definition = RubyUnits::Unit('100 kBtu') + therm.definition = RubyUnits::Unit.new('100 kBtu') therm.aliases = %w{thm therm therms Therm} end # "small" calorie RubyUnits::Unit.define('calorie') do |calorie| - calorie.definition = RubyUnits::Unit('4.184 J') + calorie.definition = RubyUnits::Unit.new('4.184 J') calorie.aliases = %w{cal calorie calories} end # "big" calorie RubyUnits::Unit.define('Calorie') do |calorie| - calorie.definition = RubyUnits::Unit('1 kcal') + calorie.definition = RubyUnits::Unit.new('1 kcal') calorie.aliases = %w{Cal Calorie Calories} end RubyUnits::Unit.define('molar') do |molar| - molar.definition = RubyUnits::Unit('1 mole/l') + molar.definition = RubyUnits::Unit.new('1 mole/l') molar.aliases = %w{M molar} end # potential RubyUnits::Unit.define('volt') do |volt| - volt.definition = RubyUnits::Unit('1 W/A') + volt.definition = RubyUnits::Unit.new('1 W/A') volt.aliases = %w{V volt volts} end # capacitance RubyUnits::Unit.define('farad') do |farad| - farad.definition = RubyUnits::Unit('1 A*s/V') + farad.definition = RubyUnits::Unit.new('1 A*s/V') farad.aliases = %w{F farad farads} end # charge RubyUnits::Unit.define('coulomb') do |coulomb| - coulomb.definition = RubyUnits::Unit('1 A*s') + coulomb.definition = RubyUnits::Unit.new('1 A*s') coulomb.aliases = %w{C coulomb coulombs} end # conductance RubyUnits::Unit.define('siemens') do |siemens| - siemens.definition = RubyUnits::Unit('1 A/V') + siemens.definition = RubyUnits::Unit.new('1 A/V') siemens.aliases = %w{S siemens} end # inductance RubyUnits::Unit.define('henry') do |henry| - henry.definition = RubyUnits::Unit('1 J/A^2') + henry.definition = RubyUnits::Unit.new('1 J/A^2') henry.aliases = %w{H henry henries} end # resistance RubyUnits::Unit.define('ohm') do |ohm| - ohm.definition = RubyUnits::Unit('1 V/A') + ohm.definition = RubyUnits::Unit.new('1 V/A') ohm.aliases = %w{Ohm ohm ohms} end # magnetism RubyUnits::Unit.define('weber') do |weber| - weber.definition = RubyUnits::Unit('1 V*s') + weber.definition = RubyUnits::Unit.new('1 V*s') weber.aliases = %w{Wb weber webers} end RubyUnits::Unit.define('tesla') do |tesla| - tesla.definition = RubyUnits::Unit('1 V*s/m^2') + tesla.definition = RubyUnits::Unit.new('1 V*s/m^2') tesla.aliases = %w{T tesla teslas} end RubyUnits::Unit.define('gauss') do |gauss| - gauss.definition = RubyUnits::Unit('100 microT') + gauss.definition = RubyUnits::Unit.new('100 microT') gauss.aliases = %w{G gauss} end RubyUnits::Unit.define('maxwell') do |maxwell| - maxwell.definition = RubyUnits::Unit('1 gauss*cm^2') + maxwell.definition = RubyUnits::Unit.new('1 gauss*cm^2') maxwell.aliases = %w{Mx maxwell maxwells} end RubyUnits::Unit.define('oersted') do |oersted| - oersted.definition = RubyUnits::Unit(250.0/Math::PI, 'A/m') + oersted.definition = RubyUnits::Unit.new(250.0/Math::PI, 'A/m') oersted.aliases = %w{Oe oersted oersteds} end #activity RubyUnits::Unit.define('katal') do |katal| - katal.definition = RubyUnits::Unit('1 mole/sec') + katal.definition = RubyUnits::Unit.new('1 mole/sec') katal.aliases = %w{kat katal} end RubyUnits::Unit.define('unit') do |unit| - unit.definition = RubyUnits::Unit('1/60 microkatal') + unit.definition = RubyUnits::Unit.new('1/60 microkatal') unit.aliases = %w{U enzRubyUnits::Unit} end #frequency RubyUnits::Unit.define('hertz') do |hz| - hz.definition = RubyUnits::Unit('1 1/s') + hz.definition = RubyUnits::Unit.new('1 1/s') hz.aliases = %w{Hz hertz} end #angle RubyUnits::Unit.define('degree') do |deg| - deg.definition = RubyUnits::Unit(Math::PI / 180.0, 'radian') + deg.definition = RubyUnits::Unit.new(Math::PI / 180.0, 'radian') deg.aliases = %w{deg degree degrees} end RubyUnits::Unit.define('grad') do |grad| - grad.definition = RubyUnits::Unit(Math::PI / 200.0, 'radian') + grad.definition = RubyUnits::Unit.new(Math::PI / 200.0, 'radian') grad.aliases = %w{grad gradian grads} end #rotation RubyUnits::Unit.define('rotation') do |rotation| - rotation.definition = RubyUnits::Unit(2.0*Math::PI, 'radian') + rotation.definition = RubyUnits::Unit.new(2.0*Math::PI, 'radian') end RubyUnits::Unit.define('rpm') do |rpm| - rpm.definition = RubyUnits::Unit('1 rotation/min') + rpm.definition = RubyUnits::Unit.new('1 rotation/min') end #memory RubyUnits::Unit.define('bit') do |bit| - bit.definition = RubyUnits::Unit('1/8 byte') + bit.definition = RubyUnits::Unit.new('1/8 byte') bit.aliases = %w{b bit} end #currency RubyUnits::Unit.define('cents') do |cents| - cents.definition = RubyUnits::Unit('1/100 dollar') + cents.definition = RubyUnits::Unit.new('1/100 dollar') end #luminosity RubyUnits::Unit.define('lumen') do |lumen| - lumen.definition = RubyUnits::Unit('1 cd*steradian') + lumen.definition = RubyUnits::Unit.new('1 cd*steradian') lumen.aliases = %w{lm lumen} end RubyUnits::Unit.define('lux') do |lux| - lux.definition = RubyUnits::Unit('1 lumen/m^2') + lux.definition = RubyUnits::Unit.new('1 lumen/m^2') end #radiation RubyUnits::Unit.define('gray') do |gray| - gray.definition = RubyUnits::Unit('1 J/kg') + gray.definition = RubyUnits::Unit.new('1 J/kg') gray.aliases = %w{Gy gray grays} end RubyUnits::Unit.define('roentgen') do |roentgen| - roentgen.definition = RubyUnits::Unit('2.58e-4 C/kg') + roentgen.definition = RubyUnits::Unit.new('2.58e-4 C/kg') roentgen.aliases = %w{R roentgen} end RubyUnits::Unit.define('sievert') do |sievert| - sievert.definition = RubyUnits::Unit('1 J/kg') + sievert.definition = RubyUnits::Unit.new('1 J/kg') sievert.aliases = %w{Sv sievert sieverts} end RubyUnits::Unit.define('becquerel') do |becquerel| - becquerel.definition = RubyUnits::Unit('1 1/s') + becquerel.definition = RubyUnits::Unit.new('1 1/s') becquerel.aliases = %w{Bq becquerel becquerels} end RubyUnits::Unit.define('curie') do |curie| - curie.definition = RubyUnits::Unit('37 GBq') + curie.definition = RubyUnits::Unit.new('37 GBq') curie.aliases = %w{Ci curie curies} end RubyUnits::Unit.define('count') do |count| - count.definition = RubyUnits::Unit('1 each') + count.definition = RubyUnits::Unit.new('1 each') count.kind = :counting end # rate RubyUnits::Unit.define('cpm') do |cpm| - cpm.definition = RubyUnits::Unit('1 count/min') + cpm.definition = RubyUnits::Unit.new('1 count/min') end RubyUnits::Unit.define('dpm') do |dpm| - dpm.definition = RubyUnits::Unit('1 count/min') + dpm.definition = RubyUnits::Unit.new('1 count/min') end RubyUnits::Unit.define('bpm') do |bpm| - bpm.definition = RubyUnits::Unit('1 count/min') + bpm.definition = RubyUnits::Unit.new('1 count/min') end # misc RubyUnits::Unit.define('dozen') do |dozen| - dozen.definition = RubyUnits::Unit('12 each') + dozen.definition = RubyUnits::Unit.new('12 each') dozen.aliases = %w{doz dz dozen} dozen.kind = :counting end RubyUnits::Unit.define('gross') do |gross| - gross.definition = RubyUnits::Unit('12 dozen') + gross.definition = RubyUnits::Unit.new('12 dozen') gross.aliases = %w{gr gross} gross.kind = :counting end RubyUnits::Unit.define('cell') do |cell| - cell.definition = RubyUnits::Unit('1 each') + cell.definition = RubyUnits::Unit.new('1 each') cell.aliases = %w{cells cell} cell.kind = :counting end RubyUnits::Unit.define('base-pair') do |bp| - bp.definition = RubyUnits::Unit('1 each') + bp.definition = RubyUnits::Unit.new('1 each') bp.aliases = %w{bp base-pair} bp.kind = :counting end RubyUnits::Unit.define('nucleotide') do |nt| - nt.definition = RubyUnits::Unit('1 each') + nt.definition = RubyUnits::Unit.new('1 each') nt.aliases = %w{nt} nt.kind = :counting end RubyUnits::Unit.define('molecule') do |molecule| - molecule.definition = RubyUnits::Unit('1 each') + molecule.definition = RubyUnits::Unit.new('1 each') molecule.aliases = %w{molecule molecules} molecule.kind = :counting end RubyUnits::Unit.define('percent') do |percent| - percent.definition = RubyUnits::Unit('1/100') + percent.definition = RubyUnits::Unit.new('1/100') percent.aliases = %w{% percent} end RubyUnits::Unit.define('ppm') do |ppm| - ppm.definition = RubyUnits::Unit(1) / 1_000_000 + ppm.definition = RubyUnits::Unit.new(1) / 1_000_000 end RubyUnits::Unit.define('ppb') do |ppb| - ppb.definition = RubyUnits::Unit(1) / 1_000_000_000 + ppb.definition = RubyUnits::Unit.new(1) / 1_000_000_000 end From f89f5b4aeadace6b4320621f81a84b9ee286eb5c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:10:22 -0400 Subject: [PATCH 010/150] Version bump to 1.4.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3c80e4f0..e1df5de7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.4.4 \ No newline at end of file From 031eb8e1701ba994432e970fbf5724fc52ced389 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:15:31 -0400 Subject: [PATCH 011/150] update readme with information about namespaced classes and how to use them. See #60 --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45e2d86a..51405b8a 100644 --- a/README.md +++ b/README.md @@ -168,4 +168,17 @@ This is useful for changing display names, adding aliases, etc. Unit.redefine!("cup") do |cup| cup.display_name = "cup" end - + + +### Namespaced Class + +Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. +The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatiblity, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. + +To load ruby-units without this alias... + + require 'ruby-units/namespaced' + +When using bundler... + + gem 'ruby-units', require: 'namespaced' From 26eb120b47ecb5b69b184866a7b0a146de97c8e3 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 6 Jul 2013 12:17:14 -0400 Subject: [PATCH 012/150] add another caveat about the Unit helper --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 51405b8a..198438f9 100644 --- a/README.md +++ b/README.md @@ -182,3 +182,5 @@ To load ruby-units without this alias... When using bundler... gem 'ruby-units', require: 'namespaced' + +Note: when using the namespaced version, the Unit('unit string') helper will not be defined. From c5c4336d82dde90b26c48fd5e380ba09eb282c15 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 16 Jul 2013 20:17:04 -0400 Subject: [PATCH 013/150] fix kind for conductance, fixes #75 --- lib/ruby_units/unit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 694735e7..e059d5ae 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -112,7 +112,7 @@ class Unit < Numeric 159999 => :magnetism, 160000 => :current, 160020 => :charge, - 312058 => :resistance, + 312058 => :conductance, 312078 => :capacitance, 3199980 => :activity, 3199997 => :molar_concentration, From 9bbe85d044ea5761753da84b0118cb4bc25cdc46 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 16 Jul 2013 21:14:21 -0400 Subject: [PATCH 014/150] 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 015/150] 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 016/150] 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)) From 9ad14a5da92b9932f47496b845136203e43b7e7d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 19 Jul 2013 09:25:00 -0400 Subject: [PATCH 017/150] add specs --- spec/ruby-units/unit_spec.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 8cd39ce2..d91cdc16 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -508,7 +508,16 @@ its(:kind) {should == :speed} its(:units) {should == "m/s"} end - + + # without spaces + describe Unit('1g') do + specify { subject == Unit('1 g')} + end + + describe Unit('11/s') do + specify { subject == Unit('1 1/s')} + end + end describe "Unit handles attempts to create bad units" do From 1f90ce5439cbfb901d9de3aa8936dcace0b1f36f Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 19 Jul 2013 09:34:13 -0400 Subject: [PATCH 018/150] update documentation --- CHANGELOG.txt | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 436143b9..f5e5e186 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,8 @@ Change Log for Ruby-units ========================= +2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method + * Fix issue #60 -- Consider placing Unit in a module + * Fix issue #75 -- Siemens is kind of conductance not resistance 2013-06-11 1.4.3 * Fix issue #70 -- Support passing Time objects to Time.at * Fix issue #72 -- Remove non-existent RakeFile from gemspec * Fix issue #71 -- Fix YAML test failure diff --git a/README.md b/README.md index 198438f9..401b1e45 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This package may be installed using: `gem install ruby-units` ## Rules: 1. only 1 quantity per unit (with 2 exceptions... 6'5" and '8 lbs 8 oz') 2. use SI notation when possible -3. avoid using spaces in unit names +3. spaces in units are allowed, but ones like '11/m' will be recognized as '11 1/m'. ## Unit compatibility: Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. From f8e886ff0a41f8b35acd5d9d803b097ae97da90d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 19 Jul 2013 09:43:57 -0400 Subject: [PATCH 019/150] allow creation of units without spaces in them. Fixes #68, #16, #36 --- lib/ruby_units/unit.rb | 2 +- spec/ruby-units/unit_spec.rb | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 350fe358..5d1420d0 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1540,7 +1540,7 @@ def self.parse_into_numbers_and_units(string) rational = %r{[+-]?\d+\/\d+} # complex numbers... -1.2+3i, +1.2-3.3i complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([\D].*)?} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^\d\.].*)?} num, unit = string.scan(anynumber).first return [case num diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index d91cdc16..3df03152 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -518,6 +518,9 @@ specify { subject == Unit('1 1/s')} end + describe Unit.new("63.5029318kg") do + specify { subject == Unit.new("63.5029318 kg")} + end end describe "Unit handles attempts to create bad units" do From 4b4d98cbcf1bce32abf5e2c2292cd4cb91b10624 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 19 Jul 2013 09:46:46 -0400 Subject: [PATCH 020/150] update changelog --- CHANGELOG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f5e5e186..450f1975 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -3,6 +3,9 @@ Change Log for Ruby-units 2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method * Fix issue #60 -- Consider placing Unit in a module * Fix issue #75 -- Siemens is kind of conductance not resistance + * Fix issue #36 -- Don't require spaces in units + * Fix issue #68 -- ditto + * Fix issue #16 -- ditto 2013-06-11 1.4.3 * Fix issue #70 -- Support passing Time objects to Time.at * Fix issue #72 -- Remove non-existent RakeFile from gemspec * Fix issue #71 -- Fix YAML test failure From ecc231ad87cc343172739363f6eaac8a07329943 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 19 Jul 2013 09:57:11 -0400 Subject: [PATCH 021/150] Regenerate gemspec for version 1.4.4 --- ruby-units.gemspec | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 3db13b84..fa16b4e4 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "ruby-units" - s.version = "1.4.3" + s.version = "1.4.4" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2013-06-12" + s.date = "2013-07-19" s.description = "Provides classes and methods to perform unit math and conversions" s.email = ["kevin.olbrich+ruby_units@gmail.com"] s.extra_rdoc_files = [ @@ -32,6 +32,7 @@ Gem::Specification.new do |s| "lib/ruby_units/definition.rb", "lib/ruby_units/fixnum.rb", "lib/ruby_units/math.rb", + "lib/ruby_units/namespaced.rb", "lib/ruby_units/numeric.rb", "lib/ruby_units/object.rb", "lib/ruby_units/string.rb", From c9f2aeac2a2745b4d84df521349fabc02c13c36c Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 13 Aug 2013 10:29:06 -0600 Subject: [PATCH 022/150] Allow for Float and milliseconds with Time#at --- lib/ruby_units/time.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index 78488546..d430241e 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -15,14 +15,14 @@ class << self # @param [Time] arg # @param [Integer] ms # @return [RubyUnits::Unit, Time] - def self.at(arg,ms=0) + def self.at(arg,ms=nil) case arg when Time unit_time_at(arg) when RubyUnits::Unit unit_time_at(arg.convert_to("s").scalar, ms) else - unit_time_at(arg, ms) + ms.nil? ? unit_time_at(arg) : unit_time_at(arg, ms) end end From e0572902521b3fad6e0a942751be3d2ef1cad0d5 Mon Sep 17 00:00:00 2001 From: Eric Badger Date: Sun, 1 Sep 2013 13:50:06 -0500 Subject: [PATCH 023/150] Return base unit from #best_prefix if scalar is 0 Without this, #best_prefix will raise FloatDomainError while trying to call #floor on '-Infinity' if the scalar is 0. --- lib/ruby_units/unit.rb | 3 ++- spec/ruby-units/unit_spec.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 5d1420d0..7cfa18bc 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1266,8 +1266,9 @@ def coerce(other) end end - # returns a new unit that has been + # returns a new unit that has been scaled to be more in line with typical usage. def best_prefix + return self.to_base if self.scalar == 0 _best_prefix = if (self.kind == :information) @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10)) else diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 3df03152..856af8c6 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1321,6 +1321,7 @@ context '#best_prefix' do specify { Unit('1024 KiB').best_prefix.should == Unit('1 MiB')} specify { Unit('1000 m').best_prefix.should == Unit('1 km')} + specify { expect { Unit('0 m').best_prefix }.to_not raise_error } end context "Time helper functions" do From 260a2a0d75231e97b76e08c11d1d4098543f9dfb Mon Sep 17 00:00:00 2001 From: Julien Sanchez Date: Thu, 12 Sep 2013 15:15:54 +0200 Subject: [PATCH 024/150] Fix negative units without spaces --- lib/ruby_units/unit.rb | 2 +- spec/ruby-units/unit_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 7cfa18bc..0a44ff35 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1541,7 +1541,7 @@ def self.parse_into_numbers_and_units(string) rational = %r{[+-]?\d+\/\d+} # complex numbers... -1.2+3i, +1.2-3.3i complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^\d\.].*)?} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^-\d\.].*)?} num, unit = string.scan(anynumber).first return [case num diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 856af8c6..502f9c7c 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -514,6 +514,10 @@ specify { subject == Unit('1 g')} end + describe Unit('-1g') do + specify { subject == Unit('-1 g')} + end + describe Unit('11/s') do specify { subject == Unit('1 1/s')} end From ef8acd950e87724ca058526c3ef8076e2b57f962 Mon Sep 17 00:00:00 2001 From: Ralph Jennings Date: Fri, 22 Nov 2013 13:00:04 -0800 Subject: [PATCH 025/150] Fixed point and pica definitions --- lib/ruby_units/unit_definitions/standard.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 17ec11bd..e7d8e83b 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -70,12 +70,12 @@ # typesetting RubyUnits::Unit.define('point') do |point| - point.definition = RubyUnits::Unit.new('1/72 ft') + point.definition = RubyUnits::Unit.new('1/12 pica') point.aliases = %w{point points} end RubyUnits::Unit.define('pica') do |pica| - pica.definition = RubyUnits::Unit.new('12 point') + pica.definition = RubyUnits::Unit.new('1/72 ft') pica.aliases = %w{P pica picas} end From 10370aea7491b84b04fa484bff48d5aab1439b97 Mon Sep 17 00:00:00 2001 From: Jeremy Mack Date: Mon, 25 Nov 2013 16:23:31 -0500 Subject: [PATCH 026/150] Update Namespaced Required Examples The previous example did not work. Tested with Ruby 1.9.3-p448 and Ruby 2.0.0-p247 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 401b1e45..ae96060d 100644 --- a/README.md +++ b/README.md @@ -177,10 +177,10 @@ The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards To load ruby-units without this alias... - require 'ruby-units/namespaced' + require 'ruby_units/namespaced' When using bundler... - gem 'ruby-units', require: 'namespaced' + gem 'ruby-units', require: 'ruby_units/namespaced' Note: when using the namespaced version, the Unit('unit string') helper will not be defined. From a244e6b4a500340551ac0ee41110ce67841fe9bf Mon Sep 17 00:00:00 2001 From: Ralph Jennings Date: Mon, 25 Nov 2013 18:13:30 -0800 Subject: [PATCH 027/150] Swapped pica and point into correct init order --- lib/ruby_units/unit_definitions/standard.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index e7d8e83b..bb07713b 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -69,16 +69,16 @@ # typesetting -RubyUnits::Unit.define('point') do |point| - point.definition = RubyUnits::Unit.new('1/12 pica') - point.aliases = %w{point points} -end - RubyUnits::Unit.define('pica') do |pica| pica.definition = RubyUnits::Unit.new('1/72 ft') pica.aliases = %w{P pica picas} end +RubyUnits::Unit.define('point') do |point| + point.definition = RubyUnits::Unit.new('1/12 pica') + point.aliases = %w{point points} +end + RubyUnits::Unit.define('dot') do |dot| dot.definition = RubyUnits::Unit.new('1 each') dot.aliases = %w{dot dots} From 5665da5407634a2db37554985264071d565673c7 Mon Sep 17 00:00:00 2001 From: Joe Stanton Date: Tue, 26 Nov 2013 22:40:02 +0000 Subject: [PATCH 028/150] Replace deprecated #stub! -> #stub --- spec/ruby-units/unit_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 502f9c7c..a0d8fff9 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1330,9 +1330,9 @@ context "Time helper functions" do before do - Time.stub!(:now).and_return(Time.utc(2011,10,16)) - DateTime.stub!(:now).and_return(DateTime.civil(2011,10,16)) - Date.stub!(:today).and_return(Date.civil(2011,10,16)) + Time.stub(:now).and_return(Time.utc(2011,10,16)) + DateTime.stub(:now).and_return(DateTime.civil(2011,10,16)) + Date.stub(:today).and_return(Date.civil(2011,10,16)) end context '#since' do From 3611d6241f9741c848cdad98b077c3e64efa6d55 Mon Sep 17 00:00:00 2001 From: Joe Stanton Date: Wed, 27 Nov 2013 00:26:32 +0000 Subject: [PATCH 029/150] Test for zero? before using to fix Unit <=> string comparisons --- lib/ruby_units/unit.rb | 2 +- spec/ruby-units/unit_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 0a44ff35..bc2505fd 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -610,7 +610,7 @@ def <=>(other) raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" when other.nil? return self.base_scalar <=> nil - when !self.is_temperature? && other.zero? + when !self.is_temperature? && other.respond_to?(:zero?) && other.zero? return self.base_scalar <=> 0 when other.instance_of?(Unit) raise ArgumentError, "Incompatible Units (#{self.units} !~ #{other.units})" unless self =~ other diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 502f9c7c..4fbc4484 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -857,6 +857,11 @@ specify { expect { Unit("1 m") < Unit("1 liter")}.to raise_error(ArgumentError,"Incompatible Units (m !~ l)")} specify { expect { Unit("1 kg") > Unit("60 mph")}.to raise_error(ArgumentError,"Incompatible Units (kg !~ mph)")} end + + context "with coercions should be valid" do + specify { Unit("1GB") > "500MB" } + specify { Unit("0.5GB") < "900MB" } + end end end From dc7a08d330c29e7f9480b22bb4f0cb5246b77dfc Mon Sep 17 00:00:00 2001 From: Joe Stanton Date: Wed, 27 Nov 2013 19:34:34 +0000 Subject: [PATCH 030/150] Fix for the wrong x,y order, not picked up by tests as there was no assertion --- lib/ruby_units/unit.rb | 2 +- spec/ruby-units/unit_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index bc2505fd..0d738431 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -617,7 +617,7 @@ def <=>(other) return self.base_scalar <=> other.base_scalar else x, y = coerce(other) - return x <=> y + return y <=> x end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 4fbc4484..10f04bd7 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -859,8 +859,8 @@ end context "with coercions should be valid" do - specify { Unit("1GB") > "500MB" } - specify { Unit("0.5GB") < "900MB" } + specify { expect(Unit("1GB") > "500MB").to eq(true) } + specify { expect(Unit("0.5GB") < "900MB").to eq(true) } end end From 25fd10b3a7ad019dcdb8812af43cae60002fe71a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 27 Nov 2013 15:15:57 -0500 Subject: [PATCH 031/150] allow passing optional ms parameter to Time.at. Fixes #79 and #80 --- lib/ruby_units/time.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index d430241e..c9cd5f6d 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -15,17 +15,21 @@ class << self # @param [Time] arg # @param [Integer] ms # @return [RubyUnits::Unit, Time] - def self.at(arg,ms=nil) + def self.at(arg, ms=nil) case arg when Time unit_time_at(arg) when RubyUnits::Unit - unit_time_at(arg.convert_to("s").scalar, ms) + if ms + unit_time_at(arg.convert_to("s").scalar, ms) + else + unit_time_at(arg.convert_to("s").scalar) + end else ms.nil? ? unit_time_at(arg) : unit_time_at(arg, ms) end end - + # @return (see RubyUnits::Unit#initialize) def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) From d5ed4230b0ee75f3c2631221e57d885b9d64826e Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 27 Nov 2013 15:45:27 -0500 Subject: [PATCH 032/150] make some exception messages more consistent and provide more information. Fixes #65 --- lib/ruby_units/unit.rb | 6 +++--- spec/ruby-units/unit_spec.rb | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 0d738431..32faf522 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -613,7 +613,7 @@ def <=>(other) when !self.is_temperature? && other.respond_to?(:zero?) && other.zero? return self.base_scalar <=> 0 when other.instance_of?(Unit) - raise ArgumentError, "Incompatible Units (#{self.units} !~ #{other.units})" unless self =~ other + raise ArgumentError, "Incompatible Units ('#{self.units}' not compatible with '#{other.units}')" unless self =~ other return self.base_scalar <=> other.base_scalar else x, y = coerce(other) @@ -819,7 +819,7 @@ def /(other) # @param [Object] other # @return [Array] def divmod(other) - raise ArgumentError, "Incompatible Units" unless self =~ 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 @@ -991,7 +991,7 @@ def convert_to(other) else raise ArgumentError, "Unknown target units" end - raise ArgumentError, "Incompatible Units" unless self =~ target + raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" 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 diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 5b6d7a81..caf00c9a 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -854,8 +854,8 @@ end context "incompatible units cannot be compared" do - specify { expect { Unit("1 m") < Unit("1 liter")}.to raise_error(ArgumentError,"Incompatible Units (m !~ l)")} - specify { expect { Unit("1 kg") > Unit("60 mph")}.to raise_error(ArgumentError,"Incompatible Units (kg !~ mph)")} + specify { expect { Unit("1 m") < Unit("1 liter")}.to raise_error(ArgumentError,"Incompatible Units ('m' not compatible with 'l')")} + specify { expect { Unit("1 kg") > Unit("60 mph")}.to raise_error(ArgumentError,"Incompatible Units ('kg' not compatible with 'mph')")} end context "with coercions should be valid" do @@ -877,7 +877,7 @@ end context "between incompatible units" do - specify { expect { Unit("1 s").convert_to("m")}.to raise_error(ArgumentError,"Incompatible Units")} + specify { expect { Unit("1 s").convert_to("m")}.to raise_error(ArgumentError,"Incompatible Units ('1 s' not compatible with 'm')")} end context "given bad input" do @@ -1140,7 +1140,7 @@ end specify "incompatible units raises an exception" do - expect { Unit("1 m") % Unit("1 kg")}.to raise_error(ArgumentError,"Incompatible Units") + expect { Unit("1 m") % Unit("1 kg")}.to raise_error(ArgumentError,"Incompatible Units ('1 m' not compatible with '1 kg')") end end @@ -1320,7 +1320,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 { expect {Unit('1 m').divmod(Unit('2 kg'))}.to raise_error(ArgumentError,"Incompatible Units")} + specify { expect {Unit('1 m').divmod(Unit('2 kg'))}.to raise_error(ArgumentError,"Incompatible Units ('1 m' not compatible with '2 kg')")} end context '#div' do From 816d284f5df08f36fb5ed36660bed818bad92335 Mon Sep 17 00:00:00 2001 From: Erik Ostrom Date: Sat, 28 Dec 2013 16:25:26 -0600 Subject: [PATCH 033/150] Fixed round/ceil/floor for units with >2 factors. E.g., m^3 or kg*m^2. Fixes #91. --- lib/ruby_units/unit.rb | 6 +++++- spec/ruby-units/unit_spec.rb | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 32faf522..d43c80a7 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1451,7 +1451,11 @@ def parse(passed_unit_string="0") @base_scalar *= mult return self end - unit_string.gsub!(/<(#{@@UNIT_REGEX})><(#{@@UNIT_REGEX})>/, '\1*\2') + + while unit_string.gsub! /(<#{@@UNIT_REGEX})><(#{@@UNIT_REGEX}>)/, '\1*\2' + # collapse into ... + end + # ... and then strip the remaining brackets for x*y*z unit_string.gsub!(/[<>]/, "") if unit_string =~ /:/ diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index caf00c9a..ebfe6505 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -509,6 +509,11 @@ its(:units) {should == "m/s"} end + describe Unit("1 /") do + its(:kind) {should == :yank} + its(:units) {should == "kg*m/s^3"} + end + # without spaces describe Unit('1g') do specify { subject == Unit('1 g')} @@ -1286,6 +1291,12 @@ Unit("10.5 m").truncate.should == Unit("10 m") end end + + context "of a complex unit" do + specify "returns a unit with the truncate of the scalar" do + Unit("10.5 kg*m/s^3").truncate.should == Unit("10 kg*m/s^3") + end + end end context '#zero?' do From 99c7b383059fd48383268b91d81a39705799788c Mon Sep 17 00:00:00 2001 From: Erik Ostrom Date: Sat, 28 Dec 2013 22:27:20 -0600 Subject: [PATCH 034/150] Added plural aliases to short-ton unit. Also reordered the existing aliases abbreviation-first, because that's the kind of guy I am. --- lib/ruby_units/unit_definitions/standard.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index bb07713b..ccbb680c 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -139,7 +139,7 @@ RubyUnits::Unit.define('short-ton') do |ton| ton.definition = RubyUnits::Unit.new('2000 lbs') - ton.aliases = %w{ton tn} + ton.aliases = %w{tn ton tons short-tons} end RubyUnits::Unit.define('carat') do |carat| From 3dbde9f32c51eadf79299bedb8ac5f1a59f491c1 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 1 Jan 2014 15:43:12 -0500 Subject: [PATCH 035/150] add pry --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index 6d48215f..ad40c588 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,7 @@ source "https://rubygems.org" group :development do gem 'bundler', '~> 1.0' gem 'jeweler' + gem 'pry' end group :test do From 69117b32c0468da78cfe5be78a25a8d615d2b780 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 1 Jan 2014 15:44:14 -0500 Subject: [PATCH 036/150] add better parsing for rationals. Now allows for rationals to be expressed as '-6 1/2' --- lib/ruby_units/unit.rb | 20 +- spec/ruby-units/unit_spec.rb | 1523 +++++++++++++++++----------------- 2 files changed, 779 insertions(+), 764 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index d43c80a7..61cfb482 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -48,7 +48,7 @@ class Unit < Numeric 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+)\)?/ + RATIONAL_NUMBER = /\(?([+-])?(\d+ )?(\d+)\/(\d+)\)?/ COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/ UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ @@ -1435,8 +1435,10 @@ def parse(passed_unit_string="0") end if defined?(Rational) && unit_string =~ RATIONAL_NUMBER - numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - result = RubyUnits::Unit.new(unit_s || '1') * Rational(numerator.to_i, denominator.to_i) + sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] + sign = (sign == '-') ? -1 : 1 + rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i)) + result = RubyUnits::Unit.new(unit_s || '1') * rational copy(result) return end @@ -1542,7 +1544,7 @@ def self.parse_into_numbers_and_units(string) # scientific notation.... 123.234E22, -123.456e-10 sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} # rational numbers.... -1/3, 1/5, 20/100 - rational = %r{[+-]?\d+\/\d+} + rational = %r{[+-]?(?:\d+ )?\d+\/\d+} # complex numbers... -1.2+3i, +1.2-3.3i complex = %r{#{sci}{2,2}i} anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^-\d\.].*)?} @@ -1560,7 +1562,15 @@ def self.parse_into_numbers_and_units(string) #:nocov_19: end when rational - Rational(*num.split("/").map { |x| x.to_i }) + # if it has whitespace, it will be of the form '6 1/2' + if num =~ /([+-]?)(\d+ )?(\d+)\/(\d+)/ + sign = ($1 == '-') ? -1 : 1 + n = $2.to_i + f = Rational($3.to_i,$4.to_i) + sign * (n + f) + else + Rational(*num.split("/").map { |x| x.to_i }) + end else num.to_f end, unit.to_s.strip] diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index ebfe6505..11001598 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -2,10 +2,10 @@ require 'yaml' describe Unit.base_units do - it {should be_a Array} - it {should have(14).elements} + it { should be_a Array } + it { should have(14).elements } %w{kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte}.each do |u| - it {should include(Unit(u))} + it { should include(Unit(u)) } end end @@ -14,600 +14,605 @@ # zero string describe Unit("0") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === 0} - its(:scalar) {should be_an Integer} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should be_zero} - its(:base) {should == subject} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === 0 } + its(:scalar) { should be_an Integer } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should be_zero } + its(:base) { should == subject } end # non-zero string describe Unit("1") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === 1} - its(:scalar) {should be_an Integer} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == subject} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === 1 } + its(:scalar) { should be_an Integer } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == subject } end # numeric describe Unit(1) do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === 1} - its(:scalar) {should be_an Integer} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == subject} - end - + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === 1 } + its(:scalar) { should be_an Integer } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == subject } + end + # rational - describe Unit(Rational(1,2)) do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === Rational(1,2)} - its(:scalar) {should be_a Rational} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == subject} + describe Unit(Rational(1, 2)) do + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === Rational(1, 2) } + its(:scalar) { should be_a Rational } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == subject } end # float describe Unit(0.5) do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === 0.5} - its(:scalar) {should be_a Float} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == subject} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === 0.5 } + its(:scalar) { should be_a Float } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == subject } end # complex - describe Unit(Complex(1,1)) do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === Complex(1,1)} - its(:scalar) {should be_a Complex} - its(:units) {should be_empty} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == subject} + describe Unit(Complex(1, 1)) do + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === Complex(1, 1) } + its(:scalar) { should be_a Complex } + its(:units) { should be_empty } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == subject } end describe Unit("1+1i m") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should === Complex(1,1)} - its(:scalar) {should be_a Complex} - its(:units) {should == "m"} - its(:kind) {should == :length} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == subject} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should === Complex(1, 1) } + its(:scalar) { should be_a Complex } + its(:units) { should == "m" } + its(:kind) { should == :length } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == subject } end # scalar and unit describe Unit("1 mm") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1} - its(:scalar) {should be_an Integer} - its(:units) {should == "mm"} - its(:kind) {should == :length} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("0.001 m")} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1 } + its(:scalar) { should be_an Integer } + its(:units) { should == "mm" } + its(:kind) { should == :length } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("0.001 m") } end # with a zero power describe Unit("1 m^0") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1} - its(:scalar) {should be_an Integer} - its(:units) {should == ""} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("1")} - end - + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1 } + its(:scalar) { should be_an Integer } + its(:units) { should == "" } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("1") } + end + # unit only describe Unit("mm") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1} - its(:scalar) {should be_an Integer} - its(:units) {should == "mm"} - its(:kind) {should == :length} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("0.001 m")} - end - + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1 } + its(:scalar) { should be_an Integer } + its(:units) { should == "mm" } + its(:kind) { should == :length } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("0.001 m") } + end + # Compound unit describe Unit("1 N*m") do - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1} - its(:scalar) {should be_an Integer} - its(:units) {should == "N*m"} - its(:kind) {should == :energy} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("1 kg*m^2/s^2")} + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1 } + its(:scalar) { should be_an Integer } + its(:units) { should == "N*m" } + its(:kind) { should == :energy } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("1 kg*m^2/s^2") } end # scalar and unit with powers describe Unit("10 m/s^2") do - it {should be_an_instance_of Unit} - its(:scalar) {should == 10} - its(:scalar) {should be_an Integer} - its(:units) {should == "m/s^2"} - its(:kind) {should == :acceleration} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("10 m/s^2")} + it { should be_an_instance_of Unit } + its(:scalar) { should == 10 } + its(:scalar) { should be_an Integer } + its(:units) { should == "m/s^2" } + its(:kind) { should == :acceleration } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("10 m/s^2") } end # feet/in form describe Unit("5ft 6in") do - it {should be_an_instance_of Unit} - its(:scalar) {should == 5.5} - its(:units) {should == "ft"} - its(:kind) {should == :length} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_within(Unit("0.01 m")).of Unit("1.6764 m")} + it { should be_an_instance_of Unit } + its(:scalar) { should == 5.5 } + its(:units) { should == "ft" } + its(:kind) { should == :length } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_within(Unit("0.01 m")).of Unit("1.6764 m") } specify { subject.to_s(:ft).should == %{5'6"} } end # pound/ounces form describe Unit("6lbs 5oz") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_within(0.001).of 6.312} - its(:units) {should == "lbs"} - its(:kind) {should == :mass} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_within(Unit("0.01 kg")).of Unit("2.8633 kg")} + it { should be_an_instance_of Unit } + its(:scalar) { should be_within(0.001).of 6.312 } + its(:units) { should == "lbs" } + its(:kind) { should == :mass } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } specify { subject.to_s(:lbs).should == "6 lbs, 5 oz" } end # temperature describe Unit("100 tempC") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_within(0.001).of 100} - its(:units) {should == "tempC"} - its(:kind) {should == :temperature} - it {should be_temperature} - it {should be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} - its(:temperature_scale) {should == "degC"} + it { should be_an_instance_of Unit } + its(:scalar) { should be_within(0.001).of 100 } + its(:units) { should == "tempC" } + its(:kind) { should == :temperature } + it { should be_temperature } + it { should be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } + its(:temperature_scale) { should == "degC" } end # Time describe Unit(Time.now) do - it {should be_an_instance_of Unit} - its(:scalar) {should be_a(Numeric)} - its(:units) {should == "s"} - its(:kind) {should == :time} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a(Numeric)} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_a(Numeric) } + its(:units) { should == "s" } + its(:kind) { should == :time } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a(Numeric) } + its(:temperature_scale) { should be_nil } end # degrees describe Unit("100 degC") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_within(0.001).of 100} - its(:units) {should == "degC"} - its(:kind) {should == :temperature} - it {should_not be_temperature} - it {should be_degree} - it {should_not be_base} - it {should_not be_unitless} - its(:base) {should be_within(Unit("0.01 degK")).of Unit("100 degK")} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_within(0.001).of 100 } + its(:units) { should == "degC" } + its(:kind) { should == :temperature } + it { should_not be_temperature } + it { should be_degree } + it { should_not be_base } + it { should_not be_unitless } + its(:base) { should be_within(Unit("0.01 degK")).of Unit("100 degK") } + end + # percent describe Unit("75%") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "%"} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a(Numeric)} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "%" } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a(Numeric) } + its(:temperature_scale) { should be_nil } end # angle describe Unit("180 deg") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_a Numeric} - its(:units) {should == "deg"} - its(:kind) {should == :angle} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a(Numeric)} - its(:temperature_scale) {should be_nil} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_a Numeric } + its(:units) { should == "deg" } + its(:kind) { should == :angle } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a(Numeric) } + its(:temperature_scale) { should be_nil } + end + # radians describe Unit("1 radian") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_a Numeric} - its(:units) {should == "rad"} - its(:kind) {should == :angle} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_a Numeric } + its(:units) { should == "rad" } + its(:kind) { should == :angle } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end # counting describe Unit("12 dozen") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "doz"} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "doz" } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end # rational scalar with unit describe Unit("1/2 kg") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Rational} - its(:units) {should == "kg"} - its(:kind) {should == :mass} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Rational } + its(:units) { should == "kg" } + its(:kind) { should == :mass } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end # rational scalar with compound unit describe Unit("1/2 kg/m") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Rational} - its(:units) {should == "kg/m"} - its(:kind) {should be_nil} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Rational } + its(:units) { should == "kg/m" } + its(:kind) { should be_nil } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + end + # time string describe Unit("1:23:45,200") do - it {should be_an_instance_of Unit} - it {should == Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec")} - its(:scalar) {should be_an Rational} - its(:units) {should == "h"} - its(:kind) {should == :time} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + it { should == Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec") } + its(:scalar) { should be_an Rational } + its(:units) { should == "h" } + its(:kind) { should == :time } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end # also '1 hours as minutes' # '1 hour to minutes' describe Unit.parse("1 hour in minutes") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "min"} - its(:kind) {should == :time} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "min" } + its(:kind) { should == :time } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end # funky unit describe Unit("1 attoparsec/microfortnight") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "apc/ufortnight"} - its(:kind) {should == :speed} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} - it { subject.convert_to("in/s").should be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s"))} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "apc/ufortnight" } + its(:kind) { should == :speed } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + it { subject.convert_to("in/s").should be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } + end + # Farads describe Unit("1 F") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "F"} - its(:kind) {should == :capacitance} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "F" } + its(:kind) { should == :capacitance } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } end describe Unit("1 m^2 s^-2") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "m^2/s^2"} - its(:kind) {should == :radiation} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} - end - - describe Unit(1,"m^2","s^2") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:units) {should == "m^2/s^2"} - its(:kind) {should == :radiation} - it {should_not be_temperature} - it {should_not be_degree} - it {should be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "m^2/s^2" } + its(:kind) { should == :radiation } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + end + + describe Unit(1, "m^2", "s^2") do + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:units) { should == "m^2/s^2" } + its(:kind) { should == :radiation } + it { should_not be_temperature } + it { should_not be_degree } + it { should be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + end + #scientific notation describe Unit("1e6 cells") do - it {should be_an_instance_of Unit} - its(:scalar) {should be_an Integer} - its(:scalar) {should == 1e6 } - its(:units) {should == "cells"} - its(:kind) {should == :unitless} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_a Numeric} - its(:temperature_scale) {should be_nil} - end - + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Integer } + its(:scalar) { should == 1e6 } + its(:units) { should == "cells" } + its(:kind) { should == :unitless } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + end + #could be m*m describe Unit("1 mm") do - its(:kind) {should == :length} + its(:kind) { should == :length } end - + #could be centi-day describe Unit("1 cd") do - its(:kind) {should == :luminous_power} + its(:kind) { should == :luminous_power } end # could be milli-inch describe Unit("1 min") do - its(:kind) {should == :time} + its(:kind) { should == :time } end - + #could be femto-tons describe Unit("1 ft") do - its(:kind) {should == :length} + its(:kind) { should == :length } end - + #could be deci-ounce describe Unit("1 doz") do - its(:kind) {should == :unitless} + its(:kind) { should == :unitless } end - + # create with another unit describe 10.unit(Unit("1 mm")) do - its(:units) {should == "mm"} - its(:scalar) {should == 10} + its(:units) { should == "mm" } + its(:scalar) { should == 10 } end - + #explicit create describe Unit("1 /") do - its(:kind) {should == :speed} - its(:units) {should == "m/s"} + its(:kind) { should == :speed } + its(:units) { should == "m/s" } end describe Unit("1 /") do - its(:kind) {should == :yank} - its(:units) {should == "kg*m/s^3"} + its(:kind) { should == :yank } + its(:units) { should == "kg*m/s^3" } end # without spaces describe Unit('1g') do - specify { subject == Unit('1 g')} + specify { subject.should eq(Unit('1 g')) } end describe Unit('-1g') do - specify { subject == Unit('-1 g')} + specify { subject.should eq(Unit('-1 g')) } end describe Unit('11/s') do - specify { subject == Unit('1 1/s')} + specify { subject.should eq(Unit('11 1/s')) } end describe Unit.new("63.5029318kg") do - specify { subject == Unit.new("63.5029318 kg")} + specify { subject.should eq(Unit.new("63.5029318 kg")) } + end + + # mixed fraction + describe Unit.new('6 1/2 cups') do + specify { subject.should eq(Unit.new('13/2 cu')) } end end describe "Unit handles attempts to create bad units" do specify "no empty strings" do - expect {Unit("")}.to raise_error(ArgumentError,"No Unit Specified") + expect { Unit("") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no blank strings" do - expect {Unit(" ")}.to raise_error(ArgumentError,"No Unit Specified") + expect { Unit(" ") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no strings with tabs" do - expect {Unit("\t")}.to raise_error(ArgumentError,"No Unit Specified") + expect { Unit("\t") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no strings with newlines" do - expect {Unit("\n")}.to raise_error(ArgumentError,"No Unit Specified") + expect { Unit("\n") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no double slashes" do - expect {Unit("3 s/s/ft")}.to raise_error(ArgumentError,/Unit not recognized/) + expect { Unit("3 s/s/ft") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no pipes or commas" do - expect {Unit("3 s**2|,s**2")}.to raise_error(ArgumentError,/Unit not recognized/) + expect { Unit("3 s**2|,s**2") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no multiple spaces" do - expect {Unit("3 s**2 4s s**2")}.to raise_error(ArgumentError,/Unit not recognized/) + expect { Unit("3 s**2 4s s**2") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no exponentiation of numbers" do - expect {Unit("3 s 5^6")}.to raise_error(ArgumentError,/Unit not recognized/) + expect { Unit("3 s 5^6") }.to raise_error(ArgumentError, /Unit not recognized/) end - + specify "no strings that don't specify a valid unit" do - expect {Unit("random string")}.to raise_error(ArgumentError,"'random string' Unit not recognized") + expect { Unit("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") end - + specify "no unhandled classes" do - expect {Unit(STDIN)}.to raise_error(ArgumentError,"Invalid Unit Format") + expect { Unit(STDIN) }.to raise_error(ArgumentError, "Invalid Unit Format") end specify "no undefined units" do - expect {Unit("1 mFoo")}.to raise_error(ArgumentError,"'1 mFoo' Unit not recognized") - expect {Unit("1 second/mFoo")}.to raise_error(ArgumentError,"'1 second/mFoo' Unit not recognized") + expect { Unit("1 mFoo") }.to raise_error(ArgumentError, "'1 mFoo' Unit not recognized") + expect { Unit("1 second/mFoo") }.to raise_error(ArgumentError, "'1 second/mFoo' Unit not recognized") end specify "no units with powers greater than 19" do - expect {Unit("1 m^20")}.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + expect { Unit("1 m^20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") end specify "no units with powers less than 19" do - expect {Unit("1 m^-20")}.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + expect { Unit("1 m^-20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") end specify "no temperatures less than absolute zero" do - expect {Unit("-100 tempK")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero") - expect {Unit("-100 tempR")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero") - expect {Unit("-500/9 tempR")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero") + expect { Unit("-100 tempK") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + expect { Unit("-100 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + expect { Unit("-500/9 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") end - + specify "no nil scalar" do - expect {Unit(nil, "feet")}.to raise_error(ArgumentError, "Invalid Unit Format") - expect {Unit(nil, "feet", "min")}.to raise_error(ArgumentError, "Invalid Unit Format") + expect { Unit(nil, "feet") }.to raise_error(ArgumentError, "Invalid Unit Format") + expect { Unit(nil, "feet", "min") }.to raise_error(ArgumentError, "Invalid Unit Format") end end describe Unit do it "is a subclass of Numeric" do - described_class.should < Numeric + described_class.should < Numeric end - - it "is Comparable" do + + it "is Comparable" do described_class.should < Comparable end - + describe "#defined?" do it "should return true when asked about a defined unit" do Unit.defined?("meter").should be_true @@ -621,37 +626,37 @@ Unit.defined?("doohickey").should be_false end end - + describe '#to_yaml' do subject { Unit('1 mm') } - its(:to_yaml) {should =~ /--- !ruby\/object:RubyUnits::Unit/ } + its(:to_yaml) { should =~ /--- !ruby\/object:RubyUnits::Unit/ } end - describe "#definition" do + describe "#definition" do context "The requested unit is defined" do before(:each) do @definition = Unit.definition('mph') end - + it "should return a Unit::Definition" do @definition.should be_instance_of(Unit::Definition) end - - specify { @definition.name.should == ""} - specify { @definition.aliases.should == %w{mph}} + + specify { @definition.name.should == "" } + specify { @definition.aliases.should == %w{mph} } specify { @definition.numerator.should == [''] } specify { @definition.denominator.should == [''] } specify { @definition.kind.should == :speed } - specify { @definition.scalar.should === 0.44704} + specify { @definition.scalar.should === 0.44704 } end - + context "The requested unit is not defined" do it "should return nil" do Unit.definition("doohickey").should be_nil end - end + end end - + describe "#define" do describe "a new unit" do before(:each) do @@ -662,34 +667,34 @@ jiffy.kind = :time end end - + after(:each) do Unit.undefine!('jiffy') end - + describe "Unit('1e6 jiffy')" do # do this because the unit is not defined at the time this file is parsed, so it fails - subject {Unit("1e6 jiffy")} - - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1e6} - its(:scalar) {should be_an Integer} - its(:units) {should == "jif"} - its(:kind) {should == :time} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should == Unit("10000 s")} + subject { Unit("1e6 jiffy") } + + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1e6 } + its(:scalar) { should be_an Integer } + its(:units) { should == "jif" } + its(:kind) { should == :time } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should == Unit("10000 s") } end - + it "should register the new unit" do Unit.defined?('jiffy').should be_true end end - + describe "an existing unit again" do before(:each) do @cups = Unit.definition('cup') @@ -697,32 +702,32 @@ @cups.display_name = "cupz" Unit.define(@cups) end - + after(:each) do Unit.redefine!("cup") do |cup| cup.display_name = @original_display_name end end - + describe "Unit('1 cup')" do # do this because the unit is going to be redefined - subject {Unit("1 cup")} - - it {should be_a Numeric} - it {should be_an_instance_of Unit} - its(:scalar) {should == 1} - its(:scalar) {should be_an Integer} - its(:units) {should == "cupz"} - its(:kind) {should == :volume} - it {should_not be_temperature} - it {should_not be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} + subject { Unit("1 cup") } + + it { should be_a Numeric } + it { should be_an_instance_of Unit } + its(:scalar) { should == 1 } + its(:scalar) { should be_an Integer } + its(:units) { should == "cupz" } + its(:kind) { should == :volume } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } end - + end - + end describe '#redefine!' do @@ -738,14 +743,14 @@ jiffy.scalar = (1/1000) end end - + after(:each) do Unit.undefine!("jiffy") end - + specify { Unit('1 jiffy').to_base.scalar.should == (1/1000) } end - + describe '#undefine!' do before(:each) do @jiffy = Unit.define("jiffy") do |jiffy| @@ -756,111 +761,111 @@ end Unit.undefine!("jiffy") end - + specify "the unit should be undefined" do Unit.defined?('jiffy').should be_false end - + specify "attempting to use an undefined unit fails" do expect { Unit("1 jiffy") }.to raise_exception(ArgumentError) end - + it "should return true when undefining an unknown unit" do Unit.defined?("unknown").should be_false Unit.undefine!("unknown").should be_true end - + end describe '#clone' do subject { Unit('1 mm') } - its(:clone) {should === subject} + its(:clone) { should === subject } end end describe "Unit Comparisons" do context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do - specify { Unit("1 ft").should =~ Unit('1 m')} - specify { Unit("1 ft").should =~ "m"} - specify { Unit("1 ft").should be_compatible_with Unit('1 m')} - specify { Unit("1 ft").should be_compatible_with "m"} - specify { Unit("1 m").should be_compatible_with Unit('1 kg*m/kg')} - specify { Unit("1 ft").should_not =~ Unit('1 kg')} - specify { Unit("1 ft").should_not be_compatible_with Unit('1 kg')} - specify { Unit("1 ft").should_not be_compatible_with nil} - end - + specify { Unit("1 ft").should =~ Unit('1 m') } + specify { Unit("1 ft").should =~ "m" } + specify { Unit("1 ft").should be_compatible_with Unit('1 m') } + specify { Unit("1 ft").should be_compatible_with "m" } + specify { Unit("1 m").should be_compatible_with Unit('1 kg*m/kg') } + specify { Unit("1 ft").should_not =~ Unit('1 kg') } + specify { Unit("1 ft").should_not be_compatible_with Unit('1 kg') } + specify { Unit("1 ft").should_not be_compatible_with nil } + end + context "Equality" do - + context "with uncoercable objects" do specify { Unit("1 mm").should_not == nil } end - + context "units of same kind" do - specify { Unit("1000 m").should == Unit('1 km')} - specify { Unit("100 m").should_not == Unit('1 km')} - specify { Unit("1 m").should == Unit('100 cm')} + specify { Unit("1000 m").should == Unit('1 km') } + specify { Unit("100 m").should_not == Unit('1 km') } + specify { Unit("1 m").should == Unit('100 cm') } end - + context "units of incompatible types" do - specify { Unit("1 m").should_not == Unit("1 kg")} + specify { Unit("1 m").should_not == Unit("1 kg") } end - + context "units with a zero scalar are equal" do - specify {Unit("0 m").should == Unit("0 s")} - specify {Unit("0 m").should == Unit("0 kg")} - + specify { Unit("0 m").should == Unit("0 s") } + specify { Unit("0 m").should == Unit("0 kg") } + context "except for temperature units" do - specify {Unit("0 tempK").should == Unit("0 m")} - specify {Unit("0 tempR").should == Unit("0 m")} - specify {Unit("0 tempC").should_not == Unit("0 m")} - specify {Unit("0 tempF").should_not == Unit("0 m")} + specify { Unit("0 tempK").should == Unit("0 m") } + specify { Unit("0 tempR").should == Unit("0 m") } + specify { Unit("0 tempC").should_not == Unit("0 m") } + specify { Unit("0 tempF").should_not == Unit("0 m") } end end end - + context "Equivalence" do context "units and scalars are the exactly the same" do - specify { Unit("1 m").should === Unit("1 m")} - specify { Unit("1 m").should be_same Unit("1 m")} - specify { Unit("1 m").should be_same_as Unit("1 m")} + specify { Unit("1 m").should === Unit("1 m") } + specify { Unit("1 m").should be_same Unit("1 m") } + specify { Unit("1 m").should be_same_as Unit("1 m") } end - + context "units are compatible but not identical" do - specify { Unit("1000 m").should_not === Unit("1 km")} - specify { Unit("1000 m").should_not be_same Unit("1 km")} - specify { Unit("1000 m").should_not be_same_as Unit("1 km")} + specify { Unit("1000 m").should_not === Unit("1 km") } + specify { Unit("1000 m").should_not be_same Unit("1 km") } + specify { Unit("1000 m").should_not be_same_as Unit("1 km") } end - + context "units are not compatible" do - specify { Unit("1000 m").should_not === Unit("1 hour")} - specify { Unit("1000 m").should_not be_same Unit("1 hour")} - specify { Unit("1000 m").should_not be_same_as Unit("1 hour")} + specify { Unit("1000 m").should_not === Unit("1 hour") } + specify { Unit("1000 m").should_not be_same Unit("1 hour") } + specify { Unit("1000 m").should_not be_same_as Unit("1 hour") } end - + context "scalars are different" do - specify { Unit("1 m").should_not === Unit("2 m")} - specify { Unit("1 m").should_not be_same Unit("2 m")} - specify { Unit("1 m").should_not be_same_as Unit("2 m")} + specify { Unit("1 m").should_not === Unit("2 m") } + specify { Unit("1 m").should_not be_same Unit("2 m") } + specify { Unit("1 m").should_not be_same_as Unit("2 m") } end - - specify { Unit("1 m").should_not === nil} + + specify { Unit("1 m").should_not === nil } end - + context "Comparisons" do context "compatible units can be compared" do - specify { Unit("1 m").should < Unit("2 m")} - specify { Unit("2 m").should > Unit("1 m")} - specify { Unit("1 m").should < Unit("1 mi")} - specify { Unit("2 m").should > Unit("1 ft")} - specify { Unit("70 tempF").should > Unit("10 degC")} + specify { Unit("1 m").should < Unit("2 m") } + specify { Unit("2 m").should > Unit("1 m") } + specify { Unit("1 m").should < Unit("1 mi") } + specify { Unit("2 m").should > Unit("1 ft") } + specify { Unit("70 tempF").should > Unit("10 degC") } specify { Unit("1 m").should > 0 } - specify { expect { Unit("1 m").should_not > nil}.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + specify { expect { Unit("1 m").should_not > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end - + context "incompatible units cannot be compared" do - specify { expect { Unit("1 m") < Unit("1 liter")}.to raise_error(ArgumentError,"Incompatible Units ('m' not compatible with 'l')")} - specify { expect { Unit("1 kg") > Unit("60 mph")}.to raise_error(ArgumentError,"Incompatible Units ('kg' not compatible with 'mph')")} + specify { expect { Unit("1 m") < Unit("1 liter") }.to raise_error(ArgumentError, "Incompatible Units ('m' not compatible with 'l')") } + specify { expect { Unit("1 kg") > Unit("60 mph") }.to raise_error(ArgumentError, "Incompatible Units ('kg' not compatible with 'mph')") } end context "with coercions should be valid" do @@ -868,92 +873,92 @@ specify { expect(Unit("0.5GB") < "900MB").to eq(true) } end end - + end describe "Unit Conversions" do - + context "between compatible units" do - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns")} - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns")} - specify { (Unit("1 s") >> "ns").should == Unit("1e9 ns")} + specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } + specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } + specify { (Unit("1 s") >> "ns").should == Unit("1e9 ns") } - specify { Unit("1 m").convert_to(Unit("ft")).should be_within(Unit("0.001 ft")).of(Unit("3.28084 ft"))} + specify { Unit("1 m").convert_to(Unit("ft")).should be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } end - + context "between incompatible units" do - specify { expect { Unit("1 s").convert_to("m")}.to raise_error(ArgumentError,"Incompatible Units ('1 s' not compatible with 'm')")} + specify { expect { Unit("1 s").convert_to("m") }.to raise_error(ArgumentError, "Incompatible Units ('1 s' not compatible with 'm')") } end - + context "given bad input" do - specify { expect { Unit("1 m").convert_to("random string")}.to raise_error(ArgumentError,"'random string' Unit not recognized")} - specify { expect { Unit("1 m").convert_to(STDOUT)}.to raise_error(ArgumentError,"Unknown target units")} + specify { expect { Unit("1 m").convert_to("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") } + specify { expect { Unit("1 m").convert_to(STDOUT) }.to raise_error(ArgumentError, "Unknown target units") } end - + context "between temperature scales" do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - + specify { Unit("100 tempC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } specify { Unit("0 tempC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("37 tempC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { Unit("37 tempC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } specify { Unit("-273.15 tempC").should == Unit("0 tempK") } - + specify { Unit("212 tempF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } specify { Unit("32 tempF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("98.6 tempF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { Unit("98.6 tempF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } specify { Unit("-459.67 tempF").should == Unit("0 tempK") } specify { Unit("671.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } specify { Unit("491.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("558.27 tempR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { Unit("558.27 tempR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } specify { Unit("0 tempR").should == Unit("0 tempK") } - - specify { Unit("100 tempK").convert_to("tempC").should be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} - specify { Unit("100 tempK").convert_to("tempF").should be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} - specify { Unit("100 tempK").convert_to("tempR").should be_within(U"0.01 degR").of(Unit("180 tempR"))} - - specify { Unit("1 degC").should == Unit("1 degK")} - specify { Unit("1 degF").should == Unit("1 degR")} - specify { Unit("1 degC").should == Unit("1.8 degR")} - specify { Unit("1 degF").should be_within(Unit("0.001 degK")).of(Unit("0.5555 degK"))} - end - + + specify { Unit("100 tempK").convert_to("tempC").should be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } + specify { Unit("100 tempK").convert_to("tempF").should be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } + specify { Unit("100 tempK").convert_to("tempR").should be_within(U "0.01 degR").of(Unit("180 tempR")) } + + specify { Unit("1 degC").should == Unit("1 degK") } + specify { Unit("1 degF").should == Unit("1 degR") } + specify { Unit("1 degC").should == Unit("1.8 degR") } + specify { Unit("1 degF").should be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } + end + context "reported bugs" do specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).should == Unit("224721 tonne") } specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne").should == Unit("224721 tonne") } end - + describe "Foot-inch conversions" do [ - ["76 in", %Q{6'4"}], - ["77 in", %Q{6'5"}], - ["78 in", %Q{6'6"}], - ["79 in", %Q{6'7"}], - ["80 in", %Q{6'8"}], - ["87 in", %Q{7'3"}], - ["88 in", %Q{7'4"}], - ["89 in", %Q{7'5"}] - ].each do |inches, feet| - specify { Unit(inches).convert_to("ft").should == Unit(feet)} - specify { Unit(inches).to_s(:ft).should == feet} + ["76 in", %Q{6'4"}], + ["77 in", %Q{6'5"}], + ["78 in", %Q{6'6"}], + ["79 in", %Q{6'7"}], + ["80 in", %Q{6'8"}], + ["87 in", %Q{7'3"}], + ["88 in", %Q{7'4"}], + ["89 in", %Q{7'5"}] + ].each do |inches, feet| + specify { Unit(inches).convert_to("ft").should == Unit(feet) } + specify { Unit(inches).to_s(:ft).should == feet } end end describe "pound-ounce conversions" do [ - ["76 oz", "4 lbs, 12 oz"], - ["77 oz", "4 lbs, 13 oz"], - ["78 oz", "4 lbs, 14 oz"], - ["79 oz", "4 lbs, 15 oz"], - ["80 oz", "5 lbs, 0 oz"], - ["87 oz", "5 lbs, 7 oz"], - ["88 oz", "5 lbs, 8 oz"], - ["89 oz", "5 lbs, 9 oz"] - ].each do |ounces, pounds| - specify { Unit(ounces).convert_to("lbs").should == Unit(pounds)} - specify { Unit(ounces).to_s(:lbs).should == pounds} - end + ["76 oz", "4 lbs, 12 oz"], + ["77 oz", "4 lbs, 13 oz"], + ["78 oz", "4 lbs, 14 oz"], + ["79 oz", "4 lbs, 15 oz"], + ["80 oz", "5 lbs, 0 oz"], + ["87 oz", "5 lbs, 7 oz"], + ["88 oz", "5 lbs, 8 oz"], + ["89 oz", "5 lbs, 9 oz"] + ].each do |ounces, pounds| + specify { Unit(ounces).convert_to("lbs").should == Unit(pounds) } + specify { Unit(ounces).to_s(:lbs).should == pounds } + end end end @@ -961,35 +966,35 @@ context "operators:" do context "addition (+)" do context "between compatible units" do - specify { (Unit("0 m") + Unit("10 m")).should == Unit("10 m")} - specify { (Unit("5 kg") + Unit("10 kg")).should == Unit("15 kg")} + specify { (Unit("0 m") + Unit("10 m")).should == Unit("10 m") } + specify { (Unit("5 kg") + Unit("10 kg")).should == Unit("15 kg") } end - + context "between a zero unit and another unit" do - specify { (Unit("0 kg") + Unit("10 m")).should == Unit("10 m")} - specify { (Unit("0 m") + Unit("10 kg")).should == Unit("10 kg")} + specify { (Unit("0 kg") + Unit("10 m")).should == Unit("10 m") } + specify { (Unit("0 m") + Unit("10 kg")).should == Unit("10 kg") } end - + context "between incompatible units" do - specify { expect {Unit("10 kg") + Unit("10 m")}.to raise_error(ArgumentError)} - specify { expect {Unit("10 m") + Unit("10 kg")}.to raise_error(ArgumentError)} - specify { expect {Unit("10 m") + nil}.to raise_error(ArgumentError)} + specify { expect { Unit("10 kg") + Unit("10 m") }.to raise_error(ArgumentError) } + specify { expect { Unit("10 m") + Unit("10 kg") }.to raise_error(ArgumentError) } + specify { expect { Unit("10 m") + nil }.to raise_error(ArgumentError) } end context "a number from a unit" do - specify { expect { Unit("10 kg") + 1 }.to raise_error(ArgumentError)} - specify { expect { 10 + Unit("10 kg") }.to raise_error(ArgumentError)} + specify { expect { Unit("10 kg") + 1 }.to raise_error(ArgumentError) } + specify { expect { 10 + Unit("10 kg") }.to raise_error(ArgumentError) } end - + context "between a unit and coerceable types" do specify { (Unit('10 kg') + %w{1 kg}).should == Unit('11 kg') } specify { (Unit('10 kg') + "1 kg").should == Unit('11 kg') } end - + context "between two temperatures" do - specify { expect {(Unit("100 tempK") + Unit("100 tempK"))}.to raise_error(ArgumentError,"Cannot add two temperatures") } + specify { expect { (Unit("100 tempK") + Unit("100 tempK")) }.to raise_error(ArgumentError, "Cannot add two temperatures") } end - + context "between a temperature and a degree" do specify { (Unit("100 tempK") + Unit("100 degK")).should == Unit("200 tempK") } end @@ -997,120 +1002,120 @@ context "between a degree and a temperature" do specify { (Unit("100 degK") + Unit("100 tempK")).should == Unit("200 tempK") } end - - end - + + end + context "subtracting (-)" do context "compatible units" do - specify { (Unit("0 m") - Unit("10 m")).should == Unit("-10 m")} - specify { (Unit("5 kg") - Unit("10 kg")).should == Unit("-5 kg")} + specify { (Unit("0 m") - Unit("10 m")).should == Unit("-10 m") } + specify { (Unit("5 kg") - Unit("10 kg")).should == Unit("-5 kg") } end - + context "a unit from a zero unit" do - specify { (Unit("0 kg") - Unit("10 m")).should == Unit("-10 m")} - specify { (Unit("0 m") - Unit("10 kg")).should == Unit("-10 kg")} + specify { (Unit("0 kg") - Unit("10 m")).should == Unit("-10 m") } + specify { (Unit("0 m") - Unit("10 kg")).should == Unit("-10 kg") } end - + context "incompatible units" do - specify { expect {Unit("10 kg") - Unit("10 m")}.to raise_error(ArgumentError)} - specify { expect {Unit("10 m") - Unit("10 kg")}.to raise_error(ArgumentError)} - specify { expect {Unit("10 m") - nil}.to raise_error(ArgumentError)} + specify { expect { Unit("10 kg") - Unit("10 m") }.to raise_error(ArgumentError) } + specify { expect { Unit("10 m") - Unit("10 kg") }.to raise_error(ArgumentError) } + specify { expect { Unit("10 m") - nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do specify { (Unit('10 kg') - %w{1 kg}).should == Unit('9 kg') } specify { (Unit('10 kg') - "1 kg").should == Unit('9 kg') } end - + context "a number from a unit" do - specify { expect { Unit("10 kg") - 1 }.to raise_error(ArgumentError)} - specify { expect { 10 - Unit("10 kg") }.to raise_error(ArgumentError)} + specify { expect { Unit("10 kg") - 1 }.to raise_error(ArgumentError) } + specify { expect { 10 - Unit("10 kg") }.to raise_error(ArgumentError) } end context "between two temperatures" do specify { (Unit("100 tempK") - Unit("100 tempK")).should == Unit("0 degK") } end - + context "between a temperature and a degree" do specify { (Unit("100 tempK") - Unit("100 degK")).should == Unit("0 tempK") } end context "between a degree and a temperature" do - specify { expect {(Unit("100 degK") - Unit("100 tempK"))}.to raise_error(ArgumentError,"Cannot subtract a temperature from a differential degree unit")} + specify { expect { (Unit("100 degK") - Unit("100 tempK")) }.to raise_error(ArgumentError, "Cannot subtract a temperature from a differential degree unit") } end - + end - + context "multiplying (*)" do context "between compatible units" do - specify { (Unit("0 m") * Unit("10 m")).should == Unit("0 m^2")} - specify { (Unit("5 kg") * Unit("10 kg")).should == Unit("50 kg^2")} + specify { (Unit("0 m") * Unit("10 m")).should == Unit("0 m^2") } + specify { (Unit("5 kg") * Unit("10 kg")).should == Unit("50 kg^2") } end - + context "between incompatible units" do - specify { (Unit("0 m") * Unit("10 kg")).should == Unit("0 kg*m")} - specify { (Unit("5 m") * Unit("10 kg")).should == Unit("50 kg*m")} - specify { expect {Unit("10 m") * nil}.to raise_error(ArgumentError)} + specify { (Unit("0 m") * Unit("10 kg")).should == Unit("0 kg*m") } + specify { (Unit("5 m") * Unit("10 kg")).should == Unit("50 kg*m") } + specify { expect { Unit("10 m") * nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do specify { (Unit('10 kg') * %w{1 kg}).should == Unit('10 kg^2') } specify { (Unit('10 kg') * "1 kg").should == Unit('10 kg^2') } end - + context "by a temperature" do - specify { expect { Unit("5 kg") * Unit("100 tempF")}.to raise_exception(ArgumentError) } + specify { expect { Unit("5 kg") * Unit("100 tempF") }.to raise_exception(ArgumentError) } end context "by a number" do - specify { (10 * Unit("5 kg")).should == Unit("50 kg")} + specify { (10 * Unit("5 kg")).should == Unit("50 kg") } end - + end - + context "dividing (/)" do context "compatible units" do - specify { (Unit("0 m") / Unit("10 m")).should == Unit(0)} - specify { (Unit("5 kg") / Unit("10 kg")).should == Rational(1,2)} - specify { (Unit("5 kg") / Unit("5 kg")).should == 1} + specify { (Unit("0 m") / Unit("10 m")).should == Unit(0) } + specify { (Unit("5 kg") / Unit("10 kg")).should == Rational(1, 2) } + specify { (Unit("5 kg") / Unit("5 kg")).should == 1 } end - + context "incompatible units" do - specify { (Unit("0 m") / Unit("10 kg")).should == Unit("0 m/kg")} - specify { (Unit("5 m") / Unit("10 kg")).should == Unit("1/2 m/kg")} - specify { expect {Unit("10 m") / nil}.to raise_error(ArgumentError)} + specify { (Unit("0 m") / Unit("10 kg")).should == Unit("0 m/kg") } + specify { (Unit("5 m") / Unit("10 kg")).should == Unit("1/2 m/kg") } + specify { expect { Unit("10 m") / nil }.to raise_error(ArgumentError) } end - + context "between a unit and coerceable types" do specify { (Unit('10 kg^2') / %w{1 kg}).should == Unit('10 kg') } specify { (Unit('10 kg^2') / "1 kg").should == Unit('10 kg') } end - + context "by a temperature" do - specify { expect { Unit("5 kg") / Unit("100 tempF")}.to raise_exception(ArgumentError) } + specify { expect { Unit("5 kg") / Unit("100 tempF") }.to raise_exception(ArgumentError) } end context "a number by a unit" do - specify { (10 / Unit("5 kg")).should == Unit("2 1/kg")} + specify { (10 / Unit("5 kg")).should == Unit("2 1/kg") } end context "a unit by a number" do - specify { (Unit("5 kg") / 2).should == Unit("2.5 kg")} + specify { (Unit("5 kg") / 2).should == Unit("2.5 kg") } end - + context "by zero" do - specify { expect { Unit("10 m") / 0}.to raise_error(ZeroDivisionError)} - specify { expect { Unit("10 m") / Unit("0 m")}.to raise_error(ZeroDivisionError)} - specify { expect { Unit("10 m") / Unit("0 kg")}.to raise_error(ZeroDivisionError)} + specify { expect { Unit("10 m") / 0 }.to raise_error(ZeroDivisionError) } + specify { expect { Unit("10 m") / Unit("0 m") }.to raise_error(ZeroDivisionError) } + specify { expect { Unit("10 m") / Unit("0 kg") }.to raise_error(ZeroDivisionError) } end end - + context "exponentiating (**)" do - + specify "a temperature raises an execption" do - expect { Unit("100 tempK")**2 }.to raise_error(ArgumentError,"Cannot raise a temperature to a power") + expect { Unit("100 tempK")**2 }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - + context Unit("0 m") do it { (subject**1).should == subject } it { (subject**2).should == subject } @@ -1120,130 +1125,130 @@ it { (subject**0).should == 1 } it { (subject**1).should == subject } it { (subject**(-1)).should == 1/subject } - it { (subject**(2)).should == Unit("1 m^2")} - it { (subject**(-2)).should == Unit("1 1/m^2")} - specify { expect { subject**(1/2)}.to raise_error(ArgumentError, "Illegal root")} - # because 1 m^(1/2) doesn't make any sense - specify { expect { subject**(Complex(1,1))}.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.")} - specify { expect { subject**(Unit("1 m"))}.to raise_error(ArgumentError, "Invalid Exponent")} + it { (subject**(2)).should == Unit("1 m^2") } + it { (subject**(-2)).should == Unit("1 1/m^2") } + specify { expect { subject**(1/2) }.to raise_error(ArgumentError, "Illegal root") } + # because 1 m^(1/2) doesn't make any sense + specify { expect { subject**(Complex(1, 1)) }.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.") } + specify { expect { subject**(Unit("1 m")) }.to raise_error(ArgumentError, "Invalid Exponent") } end - + context Unit("1 m^2") do - it { (subject**(Rational(1,2))).should == Unit("1 m")} - it { (subject**(0.5)).should == Unit("1 m")} - - specify { expect { subject**(0.12345) }.to raise_error(ArgumentError,"Not a n-th root (1..9), use 1/n")} - specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError,"Invalid Exponent")} + it { (subject**(Rational(1, 2))).should == Unit("1 m") } + it { (subject**(0.5)).should == Unit("1 m") } + + specify { expect { subject**(0.12345) }.to raise_error(ArgumentError, "Not a n-th root (1..9), use 1/n") } + specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError, "Invalid Exponent") } end - + end - + context "modulo (%)" do context "compatible units" do specify { (Unit("2 m") % Unit("1 m")).should == 0 } specify { (Unit("5 m") % Unit("2 m")).should == 1 } end - - specify "incompatible units raises an exception" do - expect { Unit("1 m") % Unit("1 kg")}.to raise_error(ArgumentError,"Incompatible Units ('1 m' not compatible with '1 kg')") + + specify "incompatible units raises an exception" do + expect { Unit("1 m") % Unit("1 kg") }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '1 kg')") end end - + context "unary negation (-)" do - specify { (-Unit("1 mm")).should == Unit("-1 mm")} + specify { (-Unit("1 mm")).should == Unit("-1 mm") } end - + context "unary plus (+)" do - specify { (+Unit('1 mm')).should == Unit('1 mm')} + specify { (+Unit('1 mm')).should == Unit('1 mm') } end end - + context "#power" do subject { Unit("1 m") } it "raises an exception when passed a Float argument" do - expect {subject.power(1.5)}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.power(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when passed a Rational argument" do - expect {subject.power(Rational(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.power(Rational(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when passed a Complex argument" do - expect {subject.power(Complex(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.power(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when called on a temperature unit" do - expect { Unit("100 tempC").power(2)}.to raise_error(ArgumentError,"Cannot raise a temperature to a power") + expect { Unit("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - - specify { (subject.power(-1)).should == Unit("1 1/m") } + + specify { (subject.power(-1)).should == Unit("1 1/m") } specify { (subject.power(0)).should == 1 } specify { (subject.power(1)).should == subject } specify { (subject.power(2)).should == Unit("1 m^2") } - + end - + context "#root" do subject { Unit("1 m") } it "raises an exception when passed a Float argument" do - expect {subject.root(1.5)}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.root(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when passed a Rational argument" do - expect {subject.root(Rational(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.root(Rational(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when passed a Complex argument" do - expect {subject.root(Complex(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer") + expect { subject.root(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when called on a temperature unit" do - expect { Unit("100 tempC").root(2)}.to raise_error(ArgumentError,"Cannot take the root of a temperature") + expect { Unit("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") end - + specify { (Unit("1 m^2").root(-2)).should == Unit("1 1/m") } - specify { (subject.root(-1)).should == Unit("1 1/m") } - specify { expect {(subject.root(0))}.to raise_error(ArgumentError, "0th root undefined")} + specify { (subject.root(-1)).should == Unit("1 1/m") } + specify { expect { (subject.root(0)) }.to raise_error(ArgumentError, "0th root undefined") } specify { (subject.root(1)).should == subject } specify { (Unit("1 m^2").root(2)).should == Unit("1 m") } - + end - + context "#inverse" do specify { Unit("1 m").inverse.should == Unit("1 1/m") } - specify { expect {Unit("100 tempK").inverse}.to raise_error(ArgumentError,"Cannot divide with temperatures") } + specify { expect { Unit("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } end - + context "convert to scalars" do - specify {Unit("10").to_i.should be_kind_of(Integer)} - specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError,"Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } + specify { Unit("10").to_i.should be_kind_of(Integer) } + specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } + + specify { Unit("10.0").to_f.should be_kind_of(Float) } + specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } - specify {Unit("10.0").to_f.should be_kind_of(Float)} - specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError,"Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } + specify { Unit("1+1i").to_c.should be_kind_of(Complex) } + specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } - specify {Unit("1+1i").to_c.should be_kind_of(Complex)} - specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError,"Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } + specify { Unit("3/7").to_r.should be_kind_of(Rational) } + specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } - specify {Unit("3/7").to_r.should be_kind_of(Rational)} - specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError,"Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } - end - + context "absolute value (#abs)" do context "of a unitless unit" do specify "returns the absolute value of the scalar" do Unit("-10").abs.should == 10 end end - + context "of a unit" do specify "returns a unit with the absolute value of the scalar" do Unit("-10 m").abs.should == Unit("10 m") end end end - + context "#ceil" do context "of a unitless unit" do specify "returns the ceil of the scalar" do Unit("10.1").ceil.should == 11 end end - + context "of a unit" do specify "returns a unit with the ceil of the scalar" do Unit("10.1 m").ceil.should == Unit("11 m") @@ -1257,7 +1262,7 @@ Unit("10.1").floor.should == 10 end end - + context "of a unit" do specify "returns a unit with the floor of the scalar" do Unit("10.1 m").floor.should == Unit("10 m") @@ -1271,21 +1276,21 @@ Unit("10.5").round.should == 11 end end - + context "of a unit" do specify "returns a unit with the round of the scalar" do Unit("10.5 m").round.should == Unit("11 m") end end end - + context "#truncate" do context "of a unitless unit" do specify "returns the truncate of the scalar" do Unit("10.5").truncate.should == 10 end end - + context "of a unit" do specify "returns a unit with the truncate of the scalar" do Unit("10.5 m").truncate.should == Unit("10 m") @@ -1298,7 +1303,7 @@ end end end - + context '#zero?' do it "is true when the scalar is zero on the base scale" do Unit("0").should be_zero @@ -1312,83 +1317,83 @@ Unit("0 tempC").should_not be_zero end end - + context '#succ' do - specify { Unit("1").succ.should == Unit("2")} - specify { Unit("1 mm").succ.should == Unit("2 mm")} - specify { Unit("1 mm").next.should == Unit("2 mm")} - specify { Unit("-1 mm").succ.should == Unit("0 mm")} - specify { expect {Unit("1.5 mm").succ}.to raise_error(ArgumentError,"Non Integer Scalar")} + specify { Unit("1").succ.should == Unit("2") } + specify { Unit("1 mm").succ.should == Unit("2 mm") } + specify { Unit("1 mm").next.should == Unit("2 mm") } + specify { Unit("-1 mm").succ.should == Unit("0 mm") } + specify { expect { Unit("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } end context '#pred' do - specify { Unit("1").pred.should == Unit("0")} - specify { Unit("1 mm").pred.should == Unit("0 mm")} - specify { Unit("-1 mm").pred.should == Unit("-2 mm")} - specify { expect {Unit("1.5 mm").pred}.to raise_error(ArgumentError,"Non Integer Scalar")} + specify { Unit("1").pred.should == Unit("0") } + specify { Unit("1 mm").pred.should == Unit("0 mm") } + specify { Unit("-1 mm").pred.should == Unit("-2 mm") } + specify { expect { Unit("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } end 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 { expect {Unit('1 m').divmod(Unit('2 kg'))}.to raise_error(ArgumentError,"Incompatible Units ('1 m' not compatible with '2 kg')")} + specify { Unit("5 mm").divmod(Unit("2 mm")).should == [2, 1] } + specify { Unit("1 km").divmod(Unit("2 m")).should == [500, 0] } + specify { expect { Unit('1 m').divmod(Unit('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end - + context '#div' do 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')} + specify { Unit('1024 KiB').best_prefix.should == Unit('1 MiB') } + specify { Unit('1000 m').best_prefix.should == Unit('1 km') } specify { expect { Unit('0 m').best_prefix }.to_not raise_error } end context "Time helper functions" do before do - Time.stub(:now).and_return(Time.utc(2011,10,16)) - DateTime.stub(:now).and_return(DateTime.civil(2011,10,16)) - Date.stub(:today).and_return(Date.civil(2011,10,16)) + Time.stub(:now).and_return(Time.utc(2011, 10, 16)) + DateTime.stub(:now).and_return(DateTime.civil(2011, 10, 16)) + Date.stub(:today).and_return(Date.civil(2011, 10, 16)) end - + context '#since' do - specify { Unit("min").since(Time.utc(2001,4,1,0,0,0)).should == Unit("5544000 min")} - specify { Unit("min").since(DateTime.civil(2001,4,1,0,0,0)).should == Unit("5544000 min")} - specify { Unit("min").since(Date.civil(2001,4,1)).should == Unit("5544000 min")} - specify { expect {Unit("min").since("4-1-2001")}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect {Unit("min").since(nil)}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } + specify { Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } + specify { Unit("min").since(Date.civil(2001, 4, 1)).should == Unit("5544000 min") } + specify { expect { Unit("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { Unit("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end - + context '#before' do - specify { Unit("5 min").before(Time.now).should == Time.utc(2011,10,15,23,55)} - specify { Unit("5 min").before(DateTime.now).should == DateTime.civil(2011,10,15,23,55)} - specify { Unit("5 min").before(Date.today).should == DateTime.civil(2011,10,15,23,55)} - specify { expect {Unit('5 min').before(nil)}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} - specify { expect {Unit('5 min').before("12:00")}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} + specify { Unit("5 min").before(Time.now).should == Time.utc(2011, 10, 15, 23, 55) } + specify { Unit("5 min").before(DateTime.now).should == DateTime.civil(2011, 10, 15, 23, 55) } + specify { Unit("5 min").before(Date.today).should == DateTime.civil(2011, 10, 15, 23, 55) } + specify { expect { Unit('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { Unit('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end - + context '#ago' do - specify { Unit("5 min").ago.should be_kind_of Time} - specify { Unit("10000 y").ago.should be_kind_of Time} - specify { Unit("1 year").ago.should == Time.utc(2010,10,16)} + specify { Unit("5 min").ago.should be_kind_of Time } + specify { Unit("10000 y").ago.should be_kind_of Time } + specify { Unit("1 year").ago.should == Time.utc(2010, 10, 16) } end - + context '#until' do - specify { Unit("min").until(Date.civil(2011,10,17)).should == Unit("1440 min")} - specify { Unit("min").until(DateTime.civil(2011,10,21)).should == Unit("7200 min")} - specify { Unit("min").until(Time.utc(2011,10,21)).should == Unit("7200 min")} - specify { expect {Unit('5 min').until(nil)}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} - specify { expect {Unit('5 min').until("12:00")}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} + specify { Unit("min").until(Date.civil(2011, 10, 17)).should == Unit("1440 min") } + specify { Unit("min").until(DateTime.civil(2011, 10, 21)).should == Unit("7200 min") } + specify { Unit("min").until(Time.utc(2011, 10, 21)).should == Unit("7200 min") } + specify { expect { Unit('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { Unit('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end - + context '#from' do - specify { Unit("1 day").from(Date.civil(2011,10,17)).should == Date.civil(2011,10,18)} - specify { Unit("5 min").from(DateTime.civil(2011,10,21)).should == DateTime.civil(2011,10,21,00,05)} - specify { Unit("5 min").from(Time.utc(2011,10,21)).should == Time.utc(2011,10,21,00,05)} - specify { expect {Unit('5 min').from(nil)}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} - specify { expect {Unit('5 min').from("12:00")}.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime")} + specify { Unit("1 day").from(Date.civil(2011, 10, 17)).should == Date.civil(2011, 10, 18) } + specify { Unit("5 min").from(DateTime.civil(2011, 10, 21)).should == DateTime.civil(2011, 10, 21, 00, 05) } + specify { Unit("5 min").from(Time.utc(2011, 10, 21)).should == Time.utc(2011, 10, 21, 00, 05) } + specify { expect { Unit('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { Unit('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end - + end end @@ -1396,40 +1401,40 @@ describe "Unit Output formatting" do context Unit("10.5 m/s^2") do specify { subject.to_s.should == "10.5 m/s^2" } - specify { subject.to_s("%0.2f").should == "10.50 m/s^2"} - specify { subject.to_s("%0.2e km/s^2").should == "1.05e-02 km/s^2"} - specify { subject.to_s("km/s^2").should == "0.0105 km/s^2"} + specify { subject.to_s("%0.2f").should == "10.50 m/s^2" } + specify { subject.to_s("%0.2e km/s^2").should == "1.05e-02 km/s^2" } + specify { subject.to_s("km/s^2").should == "0.0105 km/s^2" } specify { subject.to_s(STDOUT).should == "10.5 m/s^2" } - specify { expect {subject.to_s("random string")}.to raise_error(ArgumentError,"'random' Unit not recognized")} + specify { expect { subject.to_s("random string") }.to raise_error(ArgumentError, "'random' Unit not recognized") } end - + context "for a unit with a custom display_name" do before(:each) do Unit.redefine!("cup") do |cup| cup.display_name = "cupz" end end - + after(:each) do Unit.redefine!("cup") do |cup| cup.display_name = cup.aliases.first end end - - subject { Unit("8 cups")} - + + subject { Unit("8 cups") } + specify { subject.to_s.should == "8 cupz" } - + end - + end describe "Equations with Units" do context "Ideal Gas Law" do - let(:p) { Unit('100 kPa') } - let(:v) { Unit('1 m^3') } - let(:n) { Unit("1 mole") } - let(:r) { Unit("8.31451 J/mol*degK") } - specify { ((p*v)/(n*r)).convert_to('tempK').should be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } + let(:p) { Unit('100 kPa') } + let(:v) { Unit('1 m^3') } + let(:n) { Unit("1 mole") } + let(:r) { Unit("8.31451 J/mol*degK") } + specify { ((p*v)/(n*r)).convert_to('tempK').should be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } end end From ef0e05f86f13a4603f549b024d17fd4c5bedf006 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 2 Jan 2014 20:17:32 +0000 Subject: [PATCH 037/150] allow for fractions formatted like -6-1/2 --- lib/ruby_units/unit.rb | 10 +++++----- spec/ruby-units/unit_spec.rb | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 61cfb482..faad9669 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -48,7 +48,7 @@ class Unit < Numeric 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+)\/(\d+)\)?/ + RATIONAL_NUMBER = /\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?/ COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/ UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ @@ -1488,7 +1488,7 @@ def parse(passed_unit_string="0") return end - # more than one per. I.e., "1 m/s/s" + # more than one per. I.e., "1 m/s/s" raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts @@ -1543,8 +1543,8 @@ def self.base_units def self.parse_into_numbers_and_units(string) # scientific notation.... 123.234E22, -123.456e-10 sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} - # rational numbers.... -1/3, 1/5, 20/100 - rational = %r{[+-]?(?:\d+ )?\d+\/\d+} + # rational numbers.... -1/3, 1/5, 20/100, -6 1/2, -6-1/2 + rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?} # complex numbers... -1.2+3i, +1.2-3.3i complex = %r{#{sci}{2,2}i} anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^-\d\.].*)?} @@ -1563,7 +1563,7 @@ def self.parse_into_numbers_and_units(string) end when rational # if it has whitespace, it will be of the form '6 1/2' - if num =~ /([+-]?)(\d+ )?(\d+)\/(\d+)/ + if num =~ RATIONAL_NUMBER sign = ($1 == '-') ? -1 : 1 n = $2.to_i f = Rational($3.to_i,$4.to_i) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 11001598..9da80161 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -535,6 +535,12 @@ describe Unit.new('6 1/2 cups') do specify { subject.should eq(Unit.new('13/2 cu')) } end + + # mixed fraction + describe Unit.new('-6-1/2 cups') do + specify { subject.should eq(Unit.new('-13/2 cu')) } + end + end describe "Unit handles attempts to create bad units" do From ee2d561d949c866beee521cb3dd1726e27a20dbf Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 12 Jan 2014 15:51:27 +0000 Subject: [PATCH 038/150] add 2.1.0 to travis configs so we can test against it too --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 07bf44b8..de254c3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ rvm: - 1.9.3 - jruby-19mode # JRuby in 1.9 mode - 2.0.0 + - 2.1.0 jdk: - openjdk6 - openjdk7 From d973e0ff09130ef9306e6d60841f3202387fc18b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 12 Jan 2014 15:58:37 +0000 Subject: [PATCH 039/150] exclude some jdk's so we don't run the tests against mri ruby multiple times --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index de254c3b..04c4938b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,9 @@ jdk: matrix: exclude: - rvm: 1.9.3 - jdk: openjdk7 + jdk: openjdk6 + - rvm: 2.0.0 + jdk: openjdk6 + - rvm: 2.1.0 + jdk: openjdk6 script: bundle exec rake --trace From 07680c39704a7be158db8c27847e2fa869fff92a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 28 Jan 2014 20:48:32 +0000 Subject: [PATCH 040/150] catch cases where units defined with multiple prefixes actually parsed when they should not have (i.e., '1 mmm' would be parsed as '1 mm' or '1 mcg' would be parsed as '1 cg'). --- lib/ruby_units/unit.rb | 2 +- spec/ruby-units/unit_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index faad9669..1eaad1d4 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1588,7 +1588,7 @@ def self.unit_regex # @return [RegExp] # @private def self.unit_match_regex - @@UNIT_MATCH_REGEX ||= /(#{RubyUnits::Unit.prefix_regex})*?(#{RubyUnits::Unit.unit_regex})\b/ + @@UNIT_MATCH_REGEX ||= /(#{RubyUnits::Unit.prefix_regex})??(#{RubyUnits::Unit.unit_regex})\b/ end # return a regexp fragment used to match prefixes diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 9da80161..e2c7aca0 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -608,6 +608,10 @@ expect { Unit(nil, "feet", "min") }.to raise_error(ArgumentError, "Invalid Unit Format") end + specify 'no double prefixes' do + expect { Unit.new('1 mmm') }.to raise_error(ArgumentError, /Unit not recognized/) + end + end describe Unit do From f983da75c50a3521363f5d7f422b769dd447a840 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 28 Jan 2014 20:49:23 +0000 Subject: [PATCH 041/150] add definitions for 'mc' as a prefix alias for 'micro', useful since u and mu can occasionally be confusing. --- lib/ruby_units/unit_definitions/prefix.rb | 2 +- spec/ruby-units/unit_spec.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 041ea5aa..bcdc817d 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -23,7 +23,7 @@ 'deci' => [%w{d Deci deci}, Rational(1,1e1)], 'centi' => [%w{c Centi centi}, Rational(1,1e2)], 'milli' => [%w{m Milli milli}, Rational(1,1e3)], - 'micro' => [%w{u Micro micro}, Rational(1,1e6)], + 'micro' => [%w{u Micro micro mc}, Rational(1,1e6)], 'nano' => [%w{n Nano nano}, Rational(1,1e9)], 'pico' => [%w{p Pico pico}, Rational(1,1e12)], 'femto' => [%w{f Femto femto}, Rational(1,1e15)], diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index e2c7aca0..1789601a 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -541,6 +541,14 @@ specify { subject.should eq(Unit.new('-13/2 cu')) } end + describe Unit.new('100 mcg') do + specify { expect(subject).to eq(Unit.new('100 ug'))} + end + + describe Unit.new('100 mcL') do + specify { expect(subject).to eq(Unit.new('100 uL'))} + end + end describe "Unit handles attempts to create bad units" do From ba5c3bee4b6c0057317c6e83eaa8ea1a970de9cf Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 28 Jan 2014 20:50:38 +0000 Subject: [PATCH 042/150] Fix search and replace error that botched enzyme activity units, also add plural for this. --- lib/ruby_units/unit_definitions/standard.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index ccbb680c..f2ffbdb8 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -559,7 +559,7 @@ RubyUnits::Unit.define('unit') do |unit| unit.definition = RubyUnits::Unit.new('1/60 microkatal') - unit.aliases = %w{U enzRubyUnits::Unit} + unit.aliases = %w{U enzUnit units} end #frequency From e1b99414b2e6130854b3ea6dd129b846ffed914b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 4 Feb 2014 12:56:40 -0500 Subject: [PATCH 043/150] Update README.md Thanks @alexgandy. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae96060d..a2328f80 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/r Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors. ## Solution -The 'Ruby units' gem is designed so simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result. +The 'Ruby units' gem is designed to simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result. ## Installation: This package may be installed using: `gem install ruby-units` From c7b67f29d875cf3e4fe00360b542e1bcb30ba15c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 21 Feb 2014 10:41:21 -0500 Subject: [PATCH 044/150] Version bump to 1.5.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e1df5de7..3e1ad720 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.4 \ No newline at end of file +1.5.0 \ No newline at end of file From 501402188803504ee9fbb0df2b88801e7ad12a7b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 21 Feb 2014 10:41:57 -0500 Subject: [PATCH 045/150] Version bump to 1.5.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3e1ad720..8e03717d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.0 \ No newline at end of file +1.5.1 \ No newline at end of file From b3cce80b80c4ee46e6dfab3e6cf7f2b6ef6c0c3a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 21 Feb 2014 10:42:47 -0500 Subject: [PATCH 046/150] adjust changelog and release version --- CHANGELOG.txt | 1 + VERSION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 450f1975..d6d79f21 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,6 @@ Change Log for Ruby-units ========================= +2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit 2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method * Fix issue #60 -- Consider placing Unit in a module * Fix issue #75 -- Siemens is kind of conductance not resistance diff --git a/VERSION b/VERSION index 8e03717d..e516bb9d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.1 \ No newline at end of file +1.4.5 From 1252f22d068fe9288caa205fddab4179b339e089 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 21 Feb 2014 10:45:11 -0500 Subject: [PATCH 047/150] update gemspec --- ruby-units.gemspec | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index fa16b4e4..513ed200 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,14 +2,16 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile.rb, and run 'rake gemspec' # -*- encoding: utf-8 -*- +# stub: ruby-units 1.4.5 ruby lib Gem::Specification.new do |s| s.name = "ruby-units" - s.version = "1.4.4" + s.version = "1.4.5" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib"] s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2013-07-19" + s.date = "2014-02-21" s.description = "Provides classes and methods to perform unit math and conversions" s.email = ["kevin.olbrich+ruby_units@gmail.com"] s.extra_rdoc_files = [ @@ -48,23 +50,25 @@ Gem::Specification.new do |s| s.homepage = "https://github.com/olbrich/ruby-units" s.licenses = ["MIT"] s.post_install_message = "====================\nDeprecation Warning\n====================\n\nSeveral convenience methods that ruby-units added to the string class have\nbeen deprecated in this release. These methods include String#to, String#from, String#ago, String#before and others.\nIf your code relies on these functions, they can be added back by adding this line to your code.\n\nrequire 'ruby-units/string/extras'\n# note that these methods do not play well with Rails, which is one of the reasons they are being removed.\n\nThe extra functions mostly work the same, but will no longer properly handle cases when they are called with strings..\n\n'min'.from(\"4-1-2011\") # => Exception\n\nPass in a Date, Time, or DateTime object to get the expected result.\n\nThey will go away completely in the next release, so it would be a good idea to refactor your code\nto avoid using them. They will also throw deprecation warnings when they are used.\n" - s.require_paths = ["lib"] - s.rubygems_version = "1.8.25" + s.rubygems_version = "2.2.2" s.summary = "A class that performs unit conversions and unit math" if s.respond_to? :specification_version then - s.specification_version = 3 + s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, ["~> 1.0"]) s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end end From 89d5c785216d3dedaa0035ce614d50a210dff7b7 Mon Sep 17 00:00:00 2001 From: deployable Date: Wed, 28 May 2014 20:38:20 +0100 Subject: [PATCH 048/150] Correct exi prefix to exbi and yebi prefix to yobi (http://en.wikipedia.org/wiki/Binary_prefix) --- lib/ruby_units/unit_definitions/prefix.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index bcdc817d..b6233605 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,9 +1,9 @@ { 'googol' => [%w{googol}, 1e100], - 'yebi' => [%w{Yi Yebi yebi}, 2**80], + 'yobi' => [%w{Yi Yobi yobi}, 2**80], 'zebi' => [%w{Zi Zebi zebi}, 2**70], - 'exi' => [%w{Ei Exi exi}, 2**60], + 'exbi' => [%w{Ei Exbi exbi}, 2**60], 'pebi' => [%w{Pi Pebi pebi}, 2**50], 'tebi' => [%w{Ti Tebi tebi}, 2**40], 'gibi' => [%w{Gi Gibi gibi}, 2**30], From ddeb63695d065bafa1b44c727f87bc70fefb230f Mon Sep 17 00:00:00 2001 From: Russell Osborne Date: Thu, 29 May 2014 14:51:31 -0400 Subject: [PATCH 049/150] Adding Support for Board Feet. --- lib/ruby_units/unit_definitions/standard.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index f2ffbdb8..abafc9a8 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -250,6 +250,11 @@ tsp.aliases = %w{tsp teaspoon teaspoons} end +RubyUnits::Unit.define('bdft') do |bdft| + bdft.definition = RubyUnits::Unit.new('1/12 ft^3') + bdft.aliases = %w{boardfoot boardfeet} +end + # volumetric flow RubyUnits::Unit.define('cfm') do |cfm| From 0b96e438b76d4bf8f5ab2182fa441793ec5d16c6 Mon Sep 17 00:00:00 2001 From: Russell Osborne Date: Wed, 18 Jun 2014 10:40:12 -0400 Subject: [PATCH 050/150] Adding abbreviations and description of unit --- lib/ruby_units/unit_definitions/standard.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index abafc9a8..c02893fc 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -250,9 +250,14 @@ tsp.aliases = %w{tsp teaspoon teaspoons} end +## +# The board-foot is a specialized unit of measure for the volume of lumber in +# the United States and Canada. It is the volume of a one-foot length of a board +# one foot wide and one inch thick. +# http://en.wikipedia.org/wiki/Board_foot RubyUnits::Unit.define('bdft') do |bdft| bdft.definition = RubyUnits::Unit.new('1/12 ft^3') - bdft.aliases = %w{boardfoot boardfeet} + bdft.aliases = %w{fbm boardfoot boardfeet bf} end # volumetric flow From 186fd4f631c7265988823ff7052b7bce6a1b9ee4 Mon Sep 17 00:00:00 2001 From: saki7 Date: Fri, 23 Jan 2015 01:52:44 +0900 Subject: [PATCH 051/150] Load RubyUnits::Unit instead of Date::Unit when overriding --- lib/ruby_units/date.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ruby_units/date.rb b/lib/ruby_units/date.rb index 70b75770..ca2f5944 100644 --- a/lib/ruby_units/date.rb +++ b/lib/ruby_units/date.rb @@ -8,7 +8,7 @@ class Date # @return [Unit] def +(unit) case unit - when Unit + when RubyUnits::Unit unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units unit_date_add(unit.convert_to('day').scalar) else @@ -21,7 +21,7 @@ def +(unit) # @return [Unit] def -(unit) case unit - when Unit + when RubyUnits::Unit unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units unit_date_sub(unit.convert_to('day').scalar) else @@ -34,7 +34,7 @@ def -(unit) # @return (see Unit#initialize) # @param [Object] other convert to same units as passed def to_unit(other = nil) - other ? Unit.new(self).convert_to(other) : Unit.new(self) + other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end alias :unit :to_unit @@ -63,4 +63,4 @@ def to_date # :nocov_19: end -end \ No newline at end of file +end From f1d988d1bbf13e8a175054e2fe489531d92d67f7 Mon Sep 17 00:00:00 2001 From: Julien Sanchez Date: Tue, 17 Feb 2015 22:27:25 +0100 Subject: [PATCH 052/150] Fix 'amu' definition 'amu' is defined as 0.012 kg/mol / (12 * Avogadro) --- lib/ruby_units/unit_definitions/standard.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index c02893fc..08b8bd75 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -104,7 +104,7 @@ avagadro_constant = RubyUnits::Unit.new('6.02214129e23 1/mol') RubyUnits::Unit.define('AMU') do |amu| - amu.definition = RubyUnits::Unit.new('12 kg/mol') / (12 * avagadro_constant) + amu.definition = RubyUnits::Unit.new('0.012 kg/mol') / (12 * avagadro_constant) amu.aliases = %w{u AMU amu} end From 3b3c9eba2baa768bc6758d51543de5b917a65075 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:08:15 -0400 Subject: [PATCH 053/150] use transpec to convert from spec 2 style to rspec 3 style --- Gemfile | 1 + Guardfile | 32 + spec/ruby-units/array_spec.rb | 10 +- spec/ruby-units/bugs_spec.rb | 2 +- spec/ruby-units/cache_spec.rb | 6 +- spec/ruby-units/complex_spec.rb | 14 +- spec/ruby-units/date_spec.rb | 46 +- spec/ruby-units/definition_spec.rb | 35 +- spec/ruby-units/math_spec.rb | 58 +- spec/ruby-units/numeric_spec.rb | 12 +- spec/ruby-units/object_spec.rb | 10 +- spec/ruby-units/range_spec.rb | 10 +- spec/ruby-units/string_spec.rb | 18 +- spec/ruby-units/temperature_spec.rb | 70 +- spec/ruby-units/time_spec.rb | 45 +- spec/ruby-units/unit_spec.rb | 1844 ++++++++++++++++++--------- spec/ruby-units/utf-8/unit_spec.rb | 6 +- 17 files changed, 1498 insertions(+), 721 deletions(-) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index ad40c588..fb868299 100644 --- a/Gemfile +++ b/Gemfile @@ -12,5 +12,6 @@ group :test do gem 'simplecov', :require => false, :platforms => :mri_19 gem 'simplecov-html', :platforms => :mri_19 gem 'rspec', '~>2.5' + gem 'guard-rspec' end diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..0469987f --- /dev/null +++ b/Guardfile @@ -0,0 +1,32 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +directories %w(lib spec) + +## Uncomment to clear the screen before every task +clearing :on + +# Note: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: "bundle exec rspec" do + require "ostruct" + + # Generic Ruby apps + rspec = OpenStruct.new + rspec.spec = ->(m) { "spec/#{m}_spec.rb" } + rspec.spec_dir = "spec" + rspec.spec_helper = "spec/spec_helper.rb" + + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.("lib/#{m[1]}") } + watch(rspec.spec_helper) { rspec.spec_dir } + +end diff --git a/spec/ruby-units/array_spec.rb b/spec/ruby-units/array_spec.rb index 2a3b7424..aca122c6 100644 --- a/spec/ruby-units/array_spec.rb +++ b/spec/ruby-units/array_spec.rb @@ -4,11 +4,11 @@ subject { [1, 'cm'] } - it {should be_kind_of Array} - it {should respond_to :to_unit} + it {is_expected.to be_kind_of Array} + it {is_expected.to respond_to :to_unit} - specify { subject.to_unit.should be_instance_of Unit} - specify { subject.to_unit.should == "1 cm".to_unit } - specify { subject.to_unit('mm').should == "10 mm".to_unit} + specify { expect(subject.to_unit).to be_instance_of Unit} + specify { expect(subject.to_unit).to eq("1 cm".to_unit) } + specify { expect(subject.to_unit('mm')).to eq("10 mm".to_unit)} end \ No newline at end of file diff --git a/spec/ruby-units/bugs_spec.rb b/spec/ruby-units/bugs_spec.rb index 8b0709b9..25b6ca37 100644 --- a/spec/ruby-units/bugs_spec.rb +++ b/spec/ruby-units/bugs_spec.rb @@ -5,6 +5,6 @@ let(:b) { Unit.new(a)} it "should subtract a unit properly from one initialized with a unit" do - (b - Unit("1.5 cm^3")).should == Unit("1.5 cm^3") + expect(b - Unit("1.5 cm^3")).to eq(Unit("1.5 cm^3")) end end \ No newline at end of file diff --git a/spec/ruby-units/cache_spec.rb b/spec/ruby-units/cache_spec.rb index e7048601..f6a07602 100644 --- a/spec/ruby-units/cache_spec.rb +++ b/spec/ruby-units/cache_spec.rb @@ -12,20 +12,20 @@ context ".clear" do it "should clear the cache" do subject.clear - subject.get('m').should be_nil + expect(subject.get('m')).to be_nil end end context ".get" do it "should retrieve values already in the cache" do - subject.get['m'].should == unit + expect(subject.get['m']).to eq(unit) end end context ".set" do it "should put a unit into the cache" do subject.set('kg', Unit('1 kg')) - subject.get['kg'].should == Unit('1 kg') + expect(subject.get['kg']).to eq(Unit('1 kg')) end end end \ No newline at end of file diff --git a/spec/ruby-units/complex_spec.rb b/spec/ruby-units/complex_spec.rb index 1077de1c..404951ff 100644 --- a/spec/ruby-units/complex_spec.rb +++ b/spec/ruby-units/complex_spec.rb @@ -6,23 +6,23 @@ describe Complex do subject { Complex(1,1) } - it { should respond_to :to_unit } + it { is_expected.to respond_to :to_unit } end describe "Complex Unit" do subject { Complex(1.0, -1.0).to_unit } - it { should be_instance_of Unit} - it(:scalar) { should be_kind_of Complex } + it { is_expected.to be_instance_of Unit} + it(:scalar) { is_expected.to be_kind_of Complex } - it { should == "1-1i".to_unit } - it { should === "1-1i".to_unit } + it { is_expected.to eq("1-1i".to_unit) } + it { is_expected.to be === "1-1i".to_unit } if RUBY_VERSION < "1.9" context "in Ruby < 1.9" do it "is comparable" do - subject.should > "1+0.5i".to_unit - subject.should < "2+1i".to_unit + expect(subject).to be > "1+0.5i".to_unit + expect(subject).to be < "2+1i".to_unit end end else diff --git a/spec/ruby-units/date_spec.rb b/spec/ruby-units/date_spec.rb index 77a11371..e9507e42 100644 --- a/spec/ruby-units/date_spec.rb +++ b/spec/ruby-units/date_spec.rb @@ -3,36 +3,48 @@ describe Date do subject { Date.new(2011,4,1) } - it {should be_instance_of Date} - it {should respond_to :to_unit} - it {should respond_to :to_time} - it {should respond_to :to_date} + it {is_expected.to be_instance_of Date} + it {is_expected.to respond_to :to_unit} + it {is_expected.to respond_to :to_time} + it {is_expected.to respond_to :to_date} - specify { (subject + "5 days".unit).should == Date.new(2011,4,6) } - specify { (subject - "5 days".unit).should == Date.new(2011,3,27) } + specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } + specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } # 2012 is a leap year... - specify { (subject + "1 year".unit).should == Date.new(2012,3,31) } - specify { (subject - "1 year".unit).should == Date.new(2010,4,1) } + specify { expect(subject + "1 year".unit).to eq(Date.new(2012,3,31)) } + specify { expect(subject - "1 year".unit).to eq(Date.new(2010,4,1)) } end describe "Date Unit" do subject { Date.new(2011,4,1).to_unit } - it { should be_instance_of Unit } - its(:scalar) { should be_kind_of Rational } - its(:units) { should == "d" } - its(:kind) { should == :time } + it { is_expected.to be_instance_of Unit } - specify { (subject + "5 days".unit).should == Date.new(2011,4,6) } - specify { (subject - "5 days".unit).should == Date.new(2011,3,27) } + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_kind_of Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("d") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + + specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } + specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } specify { expect { subject + Date.new(2011,4,1) }.to raise_error(ArgumentError) } specify { expect { subject + DateTime.new(2011,4,1,12,00,00) }.to raise_error(ArgumentError) } specify { expect { subject + Time.parse("2011-04-01 12:00:00") }.to raise_error(ArgumentError) } - specify { (subject - Date.new(2011,4,1)).should be_zero } - specify { (subject - DateTime.new(2011,4,1,00,00,00)).should be_zero } + specify { expect(subject - Date.new(2011,4,1)).to be_zero } + specify { expect(subject - DateTime.new(2011,4,1,00,00,00)).to be_zero } specify { expect {(subject - Time.parse("2011-04-01 00:00"))}.to raise_error(ArgumentError) } - specify { (Date.new(2011,4,1) + 1).should == Date.new(2011,4,2)} + specify { expect(Date.new(2011,4,1) + 1).to eq(Date.new(2011,4,2))} end \ No newline at end of file diff --git a/spec/ruby-units/definition_spec.rb b/spec/ruby-units/definition_spec.rb index 1e0c53df..0f83e261 100644 --- a/spec/ruby-units/definition_spec.rb +++ b/spec/ruby-units/definition_spec.rb @@ -9,10 +9,33 @@ end } - its(:name) {should == ""} - its(:aliases) {should == %w{eV electron-volt}} - its(:scalar) {should == 1.602E-19} - its(:numerator) {should include("", "", "")} - its(:denominator) {should include("", "")} - its(:display_name) {should == "electron-volt"} + describe '#name' do + subject { super().name } + it {is_expected.to eq("")} + end + + describe '#aliases' do + subject { super().aliases } + it {is_expected.to eq(%w{eV electron-volt})} + end + + describe '#scalar' do + subject { super().scalar } + it {is_expected.to eq(1.602E-19)} + end + + describe '#numerator' do + subject { super().numerator } + it {is_expected.to include("", "", "")} + end + + describe '#denominator' do + subject { super().denominator } + it {is_expected.to include("", "")} + end + + describe '#display_name' do + subject { super().display_name } + it {is_expected.to eq("electron-volt")} + end end diff --git a/spec/ruby-units/math_spec.rb b/spec/ruby-units/math_spec.rb index 4ad5b4f8..3d355c57 100644 --- a/spec/ruby-units/math_spec.rb +++ b/spec/ruby-units/math_spec.rb @@ -3,16 +3,16 @@ describe Math do describe "#sqrt" do - specify { Math.sqrt(Unit('1 mm^6')).should == Unit('1 mm^3') } - specify { Math.sqrt(4).should == 2 } - specify { Math.sqrt(Unit("-9 mm^2")).should be_kind_of(Complex) } + specify { expect(Math.sqrt(Unit('1 mm^6'))).to eq(Unit('1 mm^3')) } + specify { expect(Math.sqrt(4)).to eq(2) } + specify { expect(Math.sqrt(Unit("-9 mm^2"))).to be_kind_of(Complex) } end if RUBY_VERSION > "1.9" # cbrt is only defined in Ruby > 1.9 describe '#cbrt' do - specify { Math.cbrt(Unit('1 mm^6')).should == Unit('1 mm^2') } - specify { Math.cbrt(8).should == 2 } + specify { expect(Math.cbrt(Unit('1 mm^6'))).to eq(Unit('1 mm^2')) } + specify { expect(Math.cbrt(8)).to eq(2) } end end @@ -20,42 +20,42 @@ context "with '45 deg' unit" do subject { Unit("45 deg") } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end context "with 'PI/4 radians' unit" do subject { Unit((Math::PI/4),'radians') } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end context "with 'PI/4' continues to work" do subject { (Math::PI/4) } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end - specify { Math.hypot(Unit("1 m"), Unit("2 m")).should be_within(Unit("0.01 m")).of(Unit("2.23607 m")) } - specify { Math.hypot(Unit("1 m"), Unit("2 ft")).should be_within(Unit("0.01 m")).of(Unit("1.17116 m")) } - specify { Math.hypot(3,4).should == 5} + specify { expect(Math.hypot(Unit("1 m"), Unit("2 m"))).to be_within(Unit("0.01 m")).of(Unit("2.23607 m")) } + specify { expect(Math.hypot(Unit("1 m"), Unit("2 ft"))).to be_within(Unit("0.01 m")).of(Unit("1.17116 m")) } + specify { expect(Math.hypot(3,4)).to eq(5)} specify { expect {Math.hypot(Unit("1 m"), Unit("2 lbs")) }.to raise_error(ArgumentError) } - specify { Math.atan2(Unit("1 m"), Unit("2 m")).should be_within(0.01).of(0.4636476090008061) } - specify { Math.atan2(Unit("1 m"), Unit("2 ft")).should be_within(0.01).of(1.0233478888629426) } - specify { Math.atan2(1,1).should be_within(0.01).of(0.785398163397448)} + specify { expect(Math.atan2(Unit("1 m"), Unit("2 m"))).to be_within(0.01).of(0.4636476090008061) } + specify { expect(Math.atan2(Unit("1 m"), Unit("2 ft"))).to be_within(0.01).of(1.0233478888629426) } + specify { expect(Math.atan2(1,1)).to be_within(0.01).of(0.785398163397448)} specify { expect {Math.atan2(Unit("1 m"), Unit("2 lbs"))}.to raise_error(ArgumentError) } end end \ No newline at end of file diff --git a/spec/ruby-units/numeric_spec.rb b/spec/ruby-units/numeric_spec.rb index b0721852..f26afb72 100644 --- a/spec/ruby-units/numeric_spec.rb +++ b/spec/ruby-units/numeric_spec.rb @@ -3,10 +3,10 @@ # some rubies return an array of strings for .instance_methods and others return an array of symbols # so let's stringify them before we compare describe Numeric do - specify { Float.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Integer.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Fixnum.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Complex.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Bignum.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Rational.instance_methods.map {|m| m.to_s}.should include("to_unit") } + specify { expect(Float.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Integer.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Fixnum.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Complex.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Bignum.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Rational.instance_methods.map {|m| m.to_s}).to include("to_unit") } end \ No newline at end of file diff --git a/spec/ruby-units/object_spec.rb b/spec/ruby-units/object_spec.rb index f4ac0953..1050a25a 100644 --- a/spec/ruby-units/object_spec.rb +++ b/spec/ruby-units/object_spec.rb @@ -1,9 +1,9 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Object do - specify { Unit('1 mm').should be_instance_of Unit} - specify { U('1 mm').should be_instance_of Unit} - specify { u('1 mm').should be_instance_of Unit} - specify { (Unit(0) + Unit(0)).should be_instance_of Unit} - specify { (Unit(0) - Unit(0)).should be_instance_of Unit} + specify { expect(Unit('1 mm')).to be_instance_of Unit} + specify { expect(U('1 mm')).to be_instance_of Unit} + specify { expect(u('1 mm')).to be_instance_of Unit} + specify { expect(Unit(0) + Unit(0)).to be_instance_of Unit} + specify { expect(Unit(0) - Unit(0)).to be_instance_of Unit} end \ No newline at end of file diff --git a/spec/ruby-units/range_spec.rb b/spec/ruby-units/range_spec.rb index bd486b41..245d98e5 100644 --- a/spec/ruby-units/range_spec.rb +++ b/spec/ruby-units/range_spec.rb @@ -4,13 +4,17 @@ context "of integer units" do subject { (Unit('1 mm')..Unit('3 mm')) } - it { should include(Unit('2 mm')) } - its(:to_a) { should == [ Unit('1 mm'), Unit('2 mm'), Unit('3 mm') ] } + it { is_expected.to include(Unit('2 mm')) } + + describe '#to_a' do + subject { super().to_a } + it { is_expected.to eq([ Unit('1 mm'), Unit('2 mm'), Unit('3 mm') ]) } + end end context "of floating point units" do subject { (Unit('1.5 mm')..Unit('3.5 mm')) } - it { should include(Unit('2.0 mm')) } + it { is_expected.to include(Unit('2.0 mm')) } specify { expect { subject.to_a }.to raise_exception(ArgumentError)} end end \ No newline at end of file diff --git a/spec/ruby-units/string_spec.rb b/spec/ruby-units/string_spec.rb index bb893445..da8a9131 100644 --- a/spec/ruby-units/string_spec.rb +++ b/spec/ruby-units/string_spec.rb @@ -2,19 +2,19 @@ describe String do context "Unit creation from strings" do - specify { "1 mm".to_unit.should be_instance_of Unit } - specify { "1 mm".unit.should be_instance_of Unit } - specify { "1 mm".u.should be_instance_of Unit } - specify { "1 m".convert_to("ft").should be_within(Unit("0.01 ft")).of Unit("3.28084 ft") } + specify { expect("1 mm".to_unit).to be_instance_of Unit } + specify { expect("1 mm".unit).to be_instance_of Unit } + specify { expect("1 mm".u).to be_instance_of Unit } + specify { expect("1 m".convert_to("ft")).to be_within(Unit("0.01 ft")).of Unit("3.28084 ft") } end context "output format" do subject { Unit("1.23456 m/s^2") } - specify { ("" % subject).should == ""} - specify { ("%0.2f" % subject).should == "1.23 m/s^2"} - specify { ("%0.2f km/h^2" % subject).should == "15999.90 km/h^2"} - specify { ("km/h^2" % subject).should == "15999.9 km/h^2"} - specify { ("%H:%M:%S" % Unit("1.5 h")).should == "01:30:00"} + specify { expect("" % subject).to eq("")} + specify { expect("%0.2f" % subject).to eq("1.23 m/s^2")} + specify { expect("%0.2f km/h^2" % subject).to eq("15999.90 km/h^2")} + specify { expect("km/h^2" % subject).to eq("15999.9 km/h^2")} + specify { expect("%H:%M:%S" % Unit("1.5 h")).to eq("01:30:00")} end end \ No newline at end of file diff --git a/spec/ruby-units/temperature_spec.rb b/spec/ruby-units/temperature_spec.rb index 4836f96b..e11328cf 100644 --- a/spec/ruby-units/temperature_spec.rb +++ b/spec/ruby-units/temperature_spec.rb @@ -50,40 +50,60 @@ describe "Unit('100 tC')" do subject {Unit("100 tC")} - its(:scalar) {should be_within(0.001).of 100} - its(:units) {should == "tC"} - its(:kind) {should == :temperature} - it {should be_temperature} - it {should be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} - its(:temperature_scale) {should == "degC"} + + describe '#scalar' do + subject { super().scalar } + it {is_expected.to be_within(0.001).of 100} + end + + describe '#units' do + subject { super().units } + it {is_expected.to eq("tC")} + end + + describe '#kind' do + subject { super().kind } + it {is_expected.to eq(:temperature)} + end + it {is_expected.to be_temperature} + it {is_expected.to be_degree} + it {is_expected.not_to be_base} + it {is_expected.not_to be_unitless} + it {is_expected.not_to be_zero} + + describe '#base' do + subject { super().base } + it {is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it {is_expected.to eq("degC")} + end end context "between temperature scales" do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - specify { Unit("100 tC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("0 tC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("37 tC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("-273.15 tC").should == Unit("0 tempK") } + specify { expect(Unit("100 tC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("0 tC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("37 tC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("-273.15 tC")).to eq(Unit("0 tempK")) } - specify { Unit("212 tF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("32 tF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("98.6 tF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("-459.67 tF").should == Unit("0 tempK") } + specify { expect(Unit("212 tF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("32 tF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("98.6 tF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("-459.67 tF")).to eq(Unit("0 tempK")) } - specify { Unit("671.67 tR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("491.67 tR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("558.27 tR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("0 tR").should == Unit("0 tempK") } + specify { expect(Unit("671.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("491.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("558.27 tR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("0 tR")).to eq(Unit("0 tempK")) } - specify { Unit("100 tK").convert_to("tempC").should be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} - specify { Unit("100 tK").convert_to("tempF").should be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} - specify { Unit("100 tK").convert_to("tempR").should be_within(U"0.01 degR").of(Unit("180 tempR"))} + specify { expect(Unit("100 tK").convert_to("tempC")).to be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} + specify { expect(Unit("100 tK").convert_to("tempF")).to be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} + specify { expect(Unit("100 tK").convert_to("tempR")).to be_within(U"0.01 degR").of(Unit("180 tempR"))} end diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby-units/time_spec.rb index 96492874..d60fbf8d 100644 --- a/spec/ruby-units/time_spec.rb +++ b/spec/ruby-units/time_spec.rb @@ -3,44 +3,55 @@ describe Time do let(:now) { Time.at(1303656390) } before(:each) do - Time.stub(:now).and_return(now) + allow(Time).to receive(:now).and_return(now) end context ".at" do subject { Date.new(2011,4,1).to_unit } - specify { Time.at(Time.at(0)).utc.strftime("%D %T").should == "01/01/70 00:00:00" } - specify { Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T").should == "04/01/11 00:00:00"} - specify { Time.at(subject - Date.new(1970,1,1), 500).usec.should == 500} + specify { expect(Time.at(Time.at(0)).utc.strftime("%D %T")).to eq("01/01/70 00:00:00") } + specify { expect(Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T")).to eq("04/01/11 00:00:00")} + specify { expect(Time.at(subject - Date.new(1970,1,1), 500).usec).to eq(500)} end context ".in" do - specify { Time.in("5 min").should be_a Time} - specify { Time.in("5 min").should > Time.now} + specify { expect(Time.in("5 min")).to be_a Time} + specify { expect(Time.in("5 min")).to be > Time.now} end context '#to_date' do subject { Time.parse("2012-01-31 11:59:59") } - specify { subject.to_date.to_s.should == "2012-01-31" } - specify { (subject+1).to_date.to_s.should == "2012-01-31" } + specify { expect(subject.to_date.to_s).to eq("2012-01-31") } + specify { expect((subject+1).to_date.to_s).to eq("2012-01-31") } end context '#to_unit' do subject { now } - its(:to_unit) { should be_an_instance_of(Unit) } - its('to_unit.units') { should == "s" } - specify { subject.to_unit('h').kind.should == :time} - specify { subject.to_unit('h').units.should == 'h'} + + describe '#to_unit' do + subject { super().to_unit } + it { is_expected.to be_an_instance_of(Unit) } + end + + describe '#to_unit' do + subject { super().to_unit } + describe '#units' do + subject { super().units } + it { is_expected.to eq("s") } + end + end + specify { expect(subject.to_unit('h').kind).to eq(:time)} + specify { expect(subject.to_unit('h').units).to eq('h')} end context 'addition (+)' do - specify { (Time.now + 1).should == Time.at(1303656390 + 1)} - specify { (Time.now + Unit("10 min")).should == Time.at(1303656390 + 600)} + specify { expect(Time.now + 1).to eq(Time.at(1303656390 + 1))} + specify { expect(Time.now + Unit("10 min")).to eq(Time.at(1303656390 + 600))} end context 'subtraction (-)' do - specify { (Time.now - 1).should == Time.at(1303656390 - 1)} - specify { (Time.now - Unit("10 min")).should == Time.at(1303656390 - 600)} - specify { (Time.now - Unit("150 years")).should == Time.parse("1861-04-24 09:46:30 -0500")} + specify { expect(Time.now - 1).to eq(Time.at(1303656390 - 1))} + specify { expect(Time.now - Unit("10 min")).to eq(Time.at(1303656390 - 600))} + specify { expect(Time.now - Unit("150 years")).to eq(Time.parse("1861-04-24 09:46:30 -0500"))} end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 1789601a..b1283069 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -2,10 +2,12 @@ require 'yaml' describe Unit.base_units do - it { should be_a Array } - it { should have(14).elements } + it { is_expected.to be_a Array } + it 'has 14 elements' do + expect(subject.size).to eq(14) + end %w{kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte}.each do |u| - it { should include(Unit(u)) } + it { is_expected.to include(Unit(u)) } end end @@ -14,531 +16,1159 @@ # zero string describe Unit("0") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 0 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 0 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # non-zero string describe Unit("1") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 1 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 1 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # numeric describe Unit(1) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 1 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 1 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # rational describe Unit(Rational(1, 2)) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Rational(1, 2) } - its(:scalar) { should be_a Rational } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Rational(1, 2) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # float describe Unit(0.5) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 0.5 } - its(:scalar) { should be_a Float } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 0.5 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Float } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # complex describe Unit(Complex(1, 1)) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Complex(1, 1) } - its(:scalar) { should be_a Complex } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Complex(1, 1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Complex } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end describe Unit("1+1i m") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Complex(1, 1) } - its(:scalar) { should be_a Complex } - its(:units) { should == "m" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Complex(1, 1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Complex } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # scalar and unit describe Unit("1 mm") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "mm" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("0.001 m") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("0.001 m")) } + end end # with a zero power describe Unit("1 m^0") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("1") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("1")) } + end end # unit only describe Unit("mm") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "mm" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("0.001 m") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("0.001 m")) } + end end # Compound unit describe Unit("1 N*m") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "N*m" } - its(:kind) { should == :energy } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("1 kg*m^2/s^2") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("N*m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:energy) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("1 kg*m^2/s^2")) } + end end # scalar and unit with powers describe Unit("10 m/s^2") do - it { should be_an_instance_of Unit } - its(:scalar) { should == 10 } - its(:scalar) { should be_an Integer } - its(:units) { should == "m/s^2" } - its(:kind) { should == :acceleration } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("10 m/s^2") } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(10) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:acceleration) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("10 m/s^2")) } + end end # feet/in form describe Unit("5ft 6in") do - it { should be_an_instance_of Unit } - its(:scalar) { should == 5.5 } - its(:units) { should == "ft" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 m")).of Unit("1.6764 m") } - specify { subject.to_s(:ft).should == %{5'6"} } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(5.5) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("ft") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 m")).of Unit("1.6764 m") } + end + specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } end # pound/ounces form describe Unit("6lbs 5oz") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 6.312 } - its(:units) { should == "lbs" } - its(:kind) { should == :mass } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } - specify { subject.to_s(:lbs).should == "6 lbs, 5 oz" } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 6.312 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("lbs") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:mass) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } + end + specify { expect(subject.to_s(:lbs)).to eq("6 lbs, 5 oz") } end # temperature describe Unit("100 tempC") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 100 } - its(:units) { should == "tempC" } - its(:kind) { should == :temperature } - it { should be_temperature } - it { should be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } - its(:temperature_scale) { should == "degC" } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 100 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("tempC") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:temperature) } + end + it { is_expected.to be_temperature } + it { is_expected.to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to eq("degC") } + end end # Time describe Unit(Time.now) do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a(Numeric) } - its(:units) { should == "s" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a(Numeric) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("s") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # degrees describe Unit("100 degC") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 100 } - its(:units) { should == "degC" } - its(:kind) { should == :temperature } - it { should_not be_temperature } - it { should be_degree } - it { should_not be_base } - it { should_not be_unitless } - its(:base) { should be_within(Unit("0.01 degK")).of Unit("100 degK") } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 100 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("degC") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:temperature) } + end + it { is_expected.not_to be_temperature } + it { is_expected.to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 degK")).of Unit("100 degK") } + end end # percent describe Unit("75%") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "%" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("%") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # angle describe Unit("180 deg") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a Numeric } - its(:units) { should == "deg" } - its(:kind) { should == :angle } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Numeric } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("deg") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:angle) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # radians describe Unit("1 radian") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a Numeric } - its(:units) { should == "rad" } - its(:kind) { should == :angle } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Numeric } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("rad") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:angle) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # counting describe Unit("12 dozen") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "doz" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("doz") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # rational scalar with unit describe Unit("1/2 kg") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Rational } - its(:units) { should == "kg" } - its(:kind) { should == :mass } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:mass) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # rational scalar with compound unit describe Unit("1/2 kg/m") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Rational } - its(:units) { should == "kg/m" } - its(:kind) { should be_nil } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg/m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to be_nil } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # time string describe Unit("1:23:45,200") do - it { should be_an_instance_of Unit } - it { should == Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec") } - its(:scalar) { should be_an Rational } - its(:units) { should == "h" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + it { is_expected.to eq(Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec")) } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("h") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # also '1 hours as minutes' # '1 hour to minutes' describe Unit.parse("1 hour in minutes") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "min" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("min") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # funky unit describe Unit("1 attoparsec/microfortnight") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "apc/ufortnight" } - its(:kind) { should == :speed } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } - it { subject.convert_to("in/s").should be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("apc/ufortnight") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:speed) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end + it { expect(subject.convert_to("in/s")).to be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } end # Farads describe Unit("1 F") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "F" } - its(:kind) { should == :capacitance } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("F") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:capacitance) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end describe Unit("1 m^2 s^-2") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "m^2/s^2" } - its(:kind) { should == :radiation } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m^2/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:radiation) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end describe Unit(1, "m^2", "s^2") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "m^2/s^2" } - its(:kind) { should == :radiation } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m^2/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:radiation) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end #scientific notation describe Unit("1e6 cells") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:scalar) { should == 1e6 } - its(:units) { should == "cells" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1e6) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("cells") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end #could be m*m describe Unit("1 mm") do - its(:kind) { should == :length } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end end #could be centi-day describe Unit("1 cd") do - its(:kind) { should == :luminous_power } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:luminous_power) } + end end # could be milli-inch describe Unit("1 min") do - its(:kind) { should == :time } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end end #could be femto-tons describe Unit("1 ft") do - its(:kind) { should == :length } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end end #could be deci-ounce describe Unit("1 doz") do - its(:kind) { should == :unitless } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end end # create with another unit describe 10.unit(Unit("1 mm")) do - its(:units) { should == "mm" } - its(:scalar) { should == 10 } + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(10) } + end end #explicit create describe Unit("1 /") do - its(:kind) { should == :speed } - its(:units) { should == "m/s" } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:speed) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m/s") } + end end describe Unit("1 /") do - its(:kind) { should == :yank } - its(:units) { should == "kg*m/s^3" } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:yank) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg*m/s^3") } + end end # without spaces describe Unit('1g') do - specify { subject.should eq(Unit('1 g')) } + specify { expect(subject).to eq(Unit('1 g')) } end describe Unit('-1g') do - specify { subject.should eq(Unit('-1 g')) } + specify { expect(subject).to eq(Unit('-1 g')) } end describe Unit('11/s') do - specify { subject.should eq(Unit('11 1/s')) } + specify { expect(subject).to eq(Unit('11 1/s')) } end describe Unit.new("63.5029318kg") do - specify { subject.should eq(Unit.new("63.5029318 kg")) } + specify { expect(subject).to eq(Unit.new("63.5029318 kg")) } end # mixed fraction describe Unit.new('6 1/2 cups') do - specify { subject.should eq(Unit.new('13/2 cu')) } + specify { expect(subject).to eq(Unit.new('13/2 cu')) } end # mixed fraction describe Unit.new('-6-1/2 cups') do - specify { subject.should eq(Unit.new('-13/2 cu')) } + specify { expect(subject).to eq(Unit.new('-13/2 cu')) } end describe Unit.new('100 mcg') do @@ -624,30 +1254,34 @@ describe Unit do it "is a subclass of Numeric" do - described_class.should < Numeric + expect(described_class).to be < Numeric end it "is Comparable" do - described_class.should < Comparable + expect(described_class).to be < Comparable end describe "#defined?" do it "should return true when asked about a defined unit" do - Unit.defined?("meter").should be_true + expect(Unit.defined?("meter")).to be_truthy end it "should return true when asked about an alias for a unit" do - Unit.defined?("m").should be_true + expect(Unit.defined?("m")).to be_truthy end it "should return false when asked about a unit that is not defined" do - Unit.defined?("doohickey").should be_false + expect(Unit.defined?("doohickey")).to be_falsey end end describe '#to_yaml' do subject { Unit('1 mm') } - its(:to_yaml) { should =~ /--- !ruby\/object:RubyUnits::Unit/ } + + describe '#to_yaml' do + subject { super().to_yaml } + it { is_expected.to match(/--- !ruby\/object:RubyUnits::Unit/) } + end end describe "#definition" do @@ -657,20 +1291,20 @@ end it "should return a Unit::Definition" do - @definition.should be_instance_of(Unit::Definition) + expect(@definition).to be_instance_of(Unit::Definition) end - specify { @definition.name.should == "" } - specify { @definition.aliases.should == %w{mph} } - specify { @definition.numerator.should == [''] } - specify { @definition.denominator.should == [''] } - specify { @definition.kind.should == :speed } - specify { @definition.scalar.should === 0.44704 } + specify { expect(@definition.name).to eq("") } + specify { expect(@definition.aliases).to eq(%w{mph}) } + specify { expect(@definition.numerator).to eq(['']) } + specify { expect(@definition.denominator).to eq(['']) } + specify { expect(@definition.kind).to eq(:speed) } + specify { expect(@definition.scalar).to be === 0.44704 } end context "The requested unit is not defined" do it "should return nil" do - Unit.definition("doohickey").should be_nil + expect(Unit.definition("doohickey")).to be_nil end end end @@ -694,22 +1328,42 @@ # do this because the unit is not defined at the time this file is parsed, so it fails subject { Unit("1e6 jiffy") } - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1e6 } - its(:scalar) { should be_an Integer } - its(:units) { should == "jif" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("10000 s") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1e6) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("jif") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("10000 s")) } + end end it "should register the new unit" do - Unit.defined?('jiffy').should be_true + expect(Unit.defined?('jiffy')).to be_truthy end end @@ -731,17 +1385,33 @@ # do this because the unit is going to be redefined subject { Unit("1 cup") } - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "cupz" } - its(:kind) { should == :volume } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("cupz") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:volume) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } end end @@ -766,7 +1436,7 @@ Unit.undefine!("jiffy") end - specify { Unit('1 jiffy').to_base.scalar.should == (1/1000) } + specify { expect(Unit('1 jiffy').to_base.scalar).to eq(1/1000) } end describe '#undefine!' do @@ -781,7 +1451,7 @@ end specify "the unit should be undefined" do - Unit.defined?('jiffy').should be_false + expect(Unit.defined?('jiffy')).to be_falsey end specify "attempting to use an undefined unit fails" do @@ -789,96 +1459,100 @@ end it "should return true when undefining an unknown unit" do - Unit.defined?("unknown").should be_false - Unit.undefine!("unknown").should be_true + expect(Unit.defined?("unknown")).to be_falsey + expect(Unit.undefine!("unknown")).to be_truthy end end describe '#clone' do subject { Unit('1 mm') } - its(:clone) { should === subject } + + describe '#clone' do + subject { super().clone } + it { is_expected.to be === subject } + end end end describe "Unit Comparisons" do context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do - specify { Unit("1 ft").should =~ Unit('1 m') } - specify { Unit("1 ft").should =~ "m" } - specify { Unit("1 ft").should be_compatible_with Unit('1 m') } - specify { Unit("1 ft").should be_compatible_with "m" } - specify { Unit("1 m").should be_compatible_with Unit('1 kg*m/kg') } - specify { Unit("1 ft").should_not =~ Unit('1 kg') } - specify { Unit("1 ft").should_not be_compatible_with Unit('1 kg') } - specify { Unit("1 ft").should_not be_compatible_with nil } + specify { expect(Unit("1 ft") =~ Unit('1 m')).to be true } + specify { expect(Unit("1 ft") =~ "m").to be true } + specify { expect(Unit("1 ft")).to be_compatible_with Unit('1 m') } + specify { expect(Unit("1 ft")).to be_compatible_with "m" } + specify { expect(Unit("1 m")).to be_compatible_with Unit('1 kg*m/kg') } + specify { expect(Unit("1 ft") =~ Unit('1 kg')).to be false } + specify { expect(Unit("1 ft")).not_to be_compatible_with Unit('1 kg') } + specify { expect(Unit("1 ft")).not_to be_compatible_with nil } end context "Equality" do context "with uncoercable objects" do - specify { Unit("1 mm").should_not == nil } + specify { expect(Unit("1 mm")).not_to eq(nil) } end context "units of same kind" do - specify { Unit("1000 m").should == Unit('1 km') } - specify { Unit("100 m").should_not == Unit('1 km') } - specify { Unit("1 m").should == Unit('100 cm') } + specify { expect(Unit("1000 m")).to eq(Unit('1 km')) } + specify { expect(Unit("100 m")).not_to eq(Unit('1 km')) } + specify { expect(Unit("1 m")).to eq(Unit('100 cm')) } end context "units of incompatible types" do - specify { Unit("1 m").should_not == Unit("1 kg") } + specify { expect(Unit("1 m")).not_to eq(Unit("1 kg")) } end context "units with a zero scalar are equal" do - specify { Unit("0 m").should == Unit("0 s") } - specify { Unit("0 m").should == Unit("0 kg") } + specify { expect(Unit("0 m")).to eq(Unit("0 s")) } + specify { expect(Unit("0 m")).to eq(Unit("0 kg")) } context "except for temperature units" do - specify { Unit("0 tempK").should == Unit("0 m") } - specify { Unit("0 tempR").should == Unit("0 m") } - specify { Unit("0 tempC").should_not == Unit("0 m") } - specify { Unit("0 tempF").should_not == Unit("0 m") } + specify { expect(Unit("0 tempK")).to eq(Unit("0 m")) } + specify { expect(Unit("0 tempR")).to eq(Unit("0 m")) } + specify { expect(Unit("0 tempC")).not_to eq(Unit("0 m")) } + specify { expect(Unit("0 tempF")).not_to eq(Unit("0 m")) } end end end context "Equivalence" do context "units and scalars are the exactly the same" do - specify { Unit("1 m").should === Unit("1 m") } - specify { Unit("1 m").should be_same Unit("1 m") } - specify { Unit("1 m").should be_same_as Unit("1 m") } + specify { expect(Unit("1 m")).to be === Unit("1 m") } + specify { expect(Unit("1 m")).to be_same Unit("1 m") } + specify { expect(Unit("1 m")).to be_same_as Unit("1 m") } end context "units are compatible but not identical" do - specify { Unit("1000 m").should_not === Unit("1 km") } - specify { Unit("1000 m").should_not be_same Unit("1 km") } - specify { Unit("1000 m").should_not be_same_as Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be === Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be_same Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 km") } end context "units are not compatible" do - specify { Unit("1000 m").should_not === Unit("1 hour") } - specify { Unit("1000 m").should_not be_same Unit("1 hour") } - specify { Unit("1000 m").should_not be_same_as Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be === Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be_same Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 hour") } end context "scalars are different" do - specify { Unit("1 m").should_not === Unit("2 m") } - specify { Unit("1 m").should_not be_same Unit("2 m") } - specify { Unit("1 m").should_not be_same_as Unit("2 m") } + specify { expect(Unit("1 m")).not_to be === Unit("2 m") } + specify { expect(Unit("1 m")).not_to be_same Unit("2 m") } + specify { expect(Unit("1 m")).not_to be_same_as Unit("2 m") } end - specify { Unit("1 m").should_not === nil } + specify { expect(Unit("1 m")).not_to be === nil } end context "Comparisons" do context "compatible units can be compared" do - specify { Unit("1 m").should < Unit("2 m") } - specify { Unit("2 m").should > Unit("1 m") } - specify { Unit("1 m").should < Unit("1 mi") } - specify { Unit("2 m").should > Unit("1 ft") } - specify { Unit("70 tempF").should > Unit("10 degC") } - specify { Unit("1 m").should > 0 } - specify { expect { Unit("1 m").should_not > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + specify { expect(Unit("1 m")).to be < Unit("2 m") } + specify { expect(Unit("2 m")).to be > Unit("1 m") } + specify { expect(Unit("1 m")).to be < Unit("1 mi") } + specify { expect(Unit("2 m")).to be > Unit("1 ft") } + specify { expect(Unit("70 tempF")).to be > Unit("10 degC") } + specify { expect(Unit("1 m")).to be > 0 } + specify { expect { expect(Unit("1 m")).not_to be > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do @@ -897,11 +1571,11 @@ describe "Unit Conversions" do context "between compatible units" do - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } - specify { (Unit("1 s") >> "ns").should == Unit("1e9 ns") } + specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } + specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } + specify { expect(Unit("1 s") >> "ns").to eq(Unit("1e9 ns")) } - specify { Unit("1 m").convert_to(Unit("ft")).should be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } + specify { expect(Unit("1 m").convert_to(Unit("ft"))).to be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } end context "between incompatible units" do @@ -917,34 +1591,34 @@ # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - specify { Unit("100 tempC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("0 tempC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("37 tempC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("-273.15 tempC").should == Unit("0 tempK") } + specify { expect(Unit("100 tempC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("0 tempC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("37 tempC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("-273.15 tempC")).to eq(Unit("0 tempK")) } - specify { Unit("212 tempF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("32 tempF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("98.6 tempF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("-459.67 tempF").should == Unit("0 tempK") } + specify { expect(Unit("212 tempF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("32 tempF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("98.6 tempF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("-459.67 tempF")).to eq(Unit("0 tempK")) } - specify { Unit("671.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("491.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("558.27 tempR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("0 tempR").should == Unit("0 tempK") } + specify { expect(Unit("671.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("491.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("558.27 tempR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("0 tempR")).to eq(Unit("0 tempK")) } - specify { Unit("100 tempK").convert_to("tempC").should be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } - specify { Unit("100 tempK").convert_to("tempF").should be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } - specify { Unit("100 tempK").convert_to("tempR").should be_within(U "0.01 degR").of(Unit("180 tempR")) } + specify { expect(Unit("100 tempK").convert_to("tempC")).to be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } + specify { expect(Unit("100 tempK").convert_to("tempF")).to be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } + specify { expect(Unit("100 tempK").convert_to("tempR")).to be_within(U "0.01 degR").of(Unit("180 tempR")) } - specify { Unit("1 degC").should == Unit("1 degK") } - specify { Unit("1 degF").should == Unit("1 degR") } - specify { Unit("1 degC").should == Unit("1.8 degR") } - specify { Unit("1 degF").should be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } + specify { expect(Unit("1 degC")).to eq(Unit("1 degK")) } + specify { expect(Unit("1 degF")).to eq(Unit("1 degR")) } + specify { expect(Unit("1 degC")).to eq(Unit("1.8 degR")) } + specify { expect(Unit("1 degF")).to be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } end context "reported bugs" do - specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).should == Unit("224721 tonne") } - specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne").should == Unit("224721 tonne") } + specify { expect(Unit("189 Mtonne") * Unit("1189 g/tonne")).to eq(Unit("224721 tonne")) } + specify { expect((Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne")).to eq(Unit("224721 tonne")) } end describe "Foot-inch conversions" do @@ -958,8 +1632,8 @@ ["88 in", %Q{7'4"}], ["89 in", %Q{7'5"}] ].each do |inches, feet| - specify { Unit(inches).convert_to("ft").should == Unit(feet) } - specify { Unit(inches).to_s(:ft).should == feet } + specify { expect(Unit(inches).convert_to("ft")).to eq(Unit(feet)) } + specify { expect(Unit(inches).to_s(:ft)).to eq(feet) } end end @@ -974,8 +1648,8 @@ ["88 oz", "5 lbs, 8 oz"], ["89 oz", "5 lbs, 9 oz"] ].each do |ounces, pounds| - specify { Unit(ounces).convert_to("lbs").should == Unit(pounds) } - specify { Unit(ounces).to_s(:lbs).should == pounds } + specify { expect(Unit(ounces).convert_to("lbs")).to eq(Unit(pounds)) } + specify { expect(Unit(ounces).to_s(:lbs)).to eq(pounds) } end end end @@ -984,13 +1658,13 @@ context "operators:" do context "addition (+)" do context "between compatible units" do - specify { (Unit("0 m") + Unit("10 m")).should == Unit("10 m") } - specify { (Unit("5 kg") + Unit("10 kg")).should == Unit("15 kg") } + specify { expect(Unit("0 m") + Unit("10 m")).to eq(Unit("10 m")) } + specify { expect(Unit("5 kg") + Unit("10 kg")).to eq(Unit("15 kg")) } end context "between a zero unit and another unit" do - specify { (Unit("0 kg") + Unit("10 m")).should == Unit("10 m") } - specify { (Unit("0 m") + Unit("10 kg")).should == Unit("10 kg") } + specify { expect(Unit("0 kg") + Unit("10 m")).to eq(Unit("10 m")) } + specify { expect(Unit("0 m") + Unit("10 kg")).to eq(Unit("10 kg")) } end context "between incompatible units" do @@ -1005,8 +1679,8 @@ end context "between a unit and coerceable types" do - specify { (Unit('10 kg') + %w{1 kg}).should == Unit('11 kg') } - specify { (Unit('10 kg') + "1 kg").should == Unit('11 kg') } + specify { expect(Unit('10 kg') + %w{1 kg}).to eq(Unit('11 kg')) } + specify { expect(Unit('10 kg') + "1 kg").to eq(Unit('11 kg')) } end context "between two temperatures" do @@ -1014,24 +1688,24 @@ end context "between a temperature and a degree" do - specify { (Unit("100 tempK") + Unit("100 degK")).should == Unit("200 tempK") } + specify { expect(Unit("100 tempK") + Unit("100 degK")).to eq(Unit("200 tempK")) } end context "between a degree and a temperature" do - specify { (Unit("100 degK") + Unit("100 tempK")).should == Unit("200 tempK") } + specify { expect(Unit("100 degK") + Unit("100 tempK")).to eq(Unit("200 tempK")) } end end context "subtracting (-)" do context "compatible units" do - specify { (Unit("0 m") - Unit("10 m")).should == Unit("-10 m") } - specify { (Unit("5 kg") - Unit("10 kg")).should == Unit("-5 kg") } + specify { expect(Unit("0 m") - Unit("10 m")).to eq(Unit("-10 m")) } + specify { expect(Unit("5 kg") - Unit("10 kg")).to eq(Unit("-5 kg")) } end context "a unit from a zero unit" do - specify { (Unit("0 kg") - Unit("10 m")).should == Unit("-10 m") } - specify { (Unit("0 m") - Unit("10 kg")).should == Unit("-10 kg") } + specify { expect(Unit("0 kg") - Unit("10 m")).to eq(Unit("-10 m")) } + specify { expect(Unit("0 m") - Unit("10 kg")).to eq(Unit("-10 kg")) } end context "incompatible units" do @@ -1041,8 +1715,8 @@ end context "between a unit and coerceable types" do - specify { (Unit('10 kg') - %w{1 kg}).should == Unit('9 kg') } - specify { (Unit('10 kg') - "1 kg").should == Unit('9 kg') } + specify { expect(Unit('10 kg') - %w{1 kg}).to eq(Unit('9 kg')) } + specify { expect(Unit('10 kg') - "1 kg").to eq(Unit('9 kg')) } end context "a number from a unit" do @@ -1051,11 +1725,11 @@ end context "between two temperatures" do - specify { (Unit("100 tempK") - Unit("100 tempK")).should == Unit("0 degK") } + specify { expect(Unit("100 tempK") - Unit("100 tempK")).to eq(Unit("0 degK")) } end context "between a temperature and a degree" do - specify { (Unit("100 tempK") - Unit("100 degK")).should == Unit("0 tempK") } + specify { expect(Unit("100 tempK") - Unit("100 degK")).to eq(Unit("0 tempK")) } end context "between a degree and a temperature" do @@ -1066,19 +1740,19 @@ context "multiplying (*)" do context "between compatible units" do - specify { (Unit("0 m") * Unit("10 m")).should == Unit("0 m^2") } - specify { (Unit("5 kg") * Unit("10 kg")).should == Unit("50 kg^2") } + specify { expect(Unit("0 m") * Unit("10 m")).to eq(Unit("0 m^2")) } + specify { expect(Unit("5 kg") * Unit("10 kg")).to eq(Unit("50 kg^2")) } end context "between incompatible units" do - specify { (Unit("0 m") * Unit("10 kg")).should == Unit("0 kg*m") } - specify { (Unit("5 m") * Unit("10 kg")).should == Unit("50 kg*m") } + specify { expect(Unit("0 m") * Unit("10 kg")).to eq(Unit("0 kg*m")) } + specify { expect(Unit("5 m") * Unit("10 kg")).to eq(Unit("50 kg*m")) } specify { expect { Unit("10 m") * nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { (Unit('10 kg') * %w{1 kg}).should == Unit('10 kg^2') } - specify { (Unit('10 kg') * "1 kg").should == Unit('10 kg^2') } + specify { expect(Unit('10 kg') * %w{1 kg}).to eq(Unit('10 kg^2')) } + specify { expect(Unit('10 kg') * "1 kg").to eq(Unit('10 kg^2')) } end context "by a temperature" do @@ -1086,27 +1760,27 @@ end context "by a number" do - specify { (10 * Unit("5 kg")).should == Unit("50 kg") } + specify { expect(10 * Unit("5 kg")).to eq(Unit("50 kg")) } end end context "dividing (/)" do context "compatible units" do - specify { (Unit("0 m") / Unit("10 m")).should == Unit(0) } - specify { (Unit("5 kg") / Unit("10 kg")).should == Rational(1, 2) } - specify { (Unit("5 kg") / Unit("5 kg")).should == 1 } + specify { expect(Unit("0 m") / Unit("10 m")).to eq(Unit(0)) } + specify { expect(Unit("5 kg") / Unit("10 kg")).to eq(Rational(1, 2)) } + specify { expect(Unit("5 kg") / Unit("5 kg")).to eq(1) } end context "incompatible units" do - specify { (Unit("0 m") / Unit("10 kg")).should == Unit("0 m/kg") } - specify { (Unit("5 m") / Unit("10 kg")).should == Unit("1/2 m/kg") } + specify { expect(Unit("0 m") / Unit("10 kg")).to eq(Unit("0 m/kg")) } + specify { expect(Unit("5 m") / Unit("10 kg")).to eq(Unit("1/2 m/kg")) } specify { expect { Unit("10 m") / nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { (Unit('10 kg^2') / %w{1 kg}).should == Unit('10 kg') } - specify { (Unit('10 kg^2') / "1 kg").should == Unit('10 kg') } + specify { expect(Unit('10 kg^2') / %w{1 kg}).to eq(Unit('10 kg')) } + specify { expect(Unit('10 kg^2') / "1 kg").to eq(Unit('10 kg')) } end context "by a temperature" do @@ -1114,11 +1788,11 @@ end context "a number by a unit" do - specify { (10 / Unit("5 kg")).should == Unit("2 1/kg") } + specify { expect(10 / Unit("5 kg")).to eq(Unit("2 1/kg")) } end context "a unit by a number" do - specify { (Unit("5 kg") / 2).should == Unit("2.5 kg") } + specify { expect(Unit("5 kg") / 2).to eq(Unit("2.5 kg")) } end context "by zero" do @@ -1135,16 +1809,16 @@ end context Unit("0 m") do - it { (subject**1).should == subject } - it { (subject**2).should == subject } + it { expect(subject**1).to eq(subject) } + it { expect(subject**2).to eq(subject) } end context Unit("1 m") do - it { (subject**0).should == 1 } - it { (subject**1).should == subject } - it { (subject**(-1)).should == 1/subject } - it { (subject**(2)).should == Unit("1 m^2") } - it { (subject**(-2)).should == Unit("1 1/m^2") } + it { expect(subject**0).to eq(1) } + it { expect(subject**1).to eq(subject) } + it { expect(subject**(-1)).to eq(1/subject) } + it { expect(subject**(2)).to eq(Unit("1 m^2")) } + it { expect(subject**(-2)).to eq(Unit("1 1/m^2")) } specify { expect { subject**(1/2) }.to raise_error(ArgumentError, "Illegal root") } # because 1 m^(1/2) doesn't make any sense specify { expect { subject**(Complex(1, 1)) }.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.") } @@ -1152,8 +1826,8 @@ end context Unit("1 m^2") do - it { (subject**(Rational(1, 2))).should == Unit("1 m") } - it { (subject**(0.5)).should == Unit("1 m") } + it { expect(subject**(Rational(1, 2))).to eq(Unit("1 m")) } + it { expect(subject**(0.5)).to eq(Unit("1 m")) } specify { expect { subject**(0.12345) }.to raise_error(ArgumentError, "Not a n-th root (1..9), use 1/n") } specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError, "Invalid Exponent") } @@ -1163,8 +1837,8 @@ context "modulo (%)" do context "compatible units" do - specify { (Unit("2 m") % Unit("1 m")).should == 0 } - specify { (Unit("5 m") % Unit("2 m")).should == 1 } + specify { expect(Unit("2 m") % Unit("1 m")).to eq(0) } + specify { expect(Unit("5 m") % Unit("2 m")).to eq(1) } end specify "incompatible units raises an exception" do @@ -1173,11 +1847,11 @@ end context "unary negation (-)" do - specify { (-Unit("1 mm")).should == Unit("-1 mm") } + specify { expect(-Unit("1 mm")).to eq(Unit("-1 mm")) } end context "unary plus (+)" do - specify { (+Unit('1 mm')).should == Unit('1 mm') } + specify { expect(+Unit('1 mm')).to eq(Unit('1 mm')) } end end @@ -1196,10 +1870,10 @@ expect { Unit("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - specify { (subject.power(-1)).should == Unit("1 1/m") } - specify { (subject.power(0)).should == 1 } - specify { (subject.power(1)).should == subject } - specify { (subject.power(2)).should == Unit("1 m^2") } + specify { expect(subject.power(-1)).to eq(Unit("1 1/m")) } + specify { expect(subject.power(0)).to eq(1) } + specify { expect(subject.power(1)).to eq(subject) } + specify { expect(subject.power(2)).to eq(Unit("1 m^2")) } end @@ -1218,30 +1892,30 @@ expect { Unit("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") end - specify { (Unit("1 m^2").root(-2)).should == Unit("1 1/m") } - specify { (subject.root(-1)).should == Unit("1 1/m") } + specify { expect(Unit("1 m^2").root(-2)).to eq(Unit("1 1/m")) } + specify { expect(subject.root(-1)).to eq(Unit("1 1/m")) } specify { expect { (subject.root(0)) }.to raise_error(ArgumentError, "0th root undefined") } - specify { (subject.root(1)).should == subject } - specify { (Unit("1 m^2").root(2)).should == Unit("1 m") } + specify { expect(subject.root(1)).to eq(subject) } + specify { expect(Unit("1 m^2").root(2)).to eq(Unit("1 m")) } end context "#inverse" do - specify { Unit("1 m").inverse.should == Unit("1 1/m") } + specify { expect(Unit("1 m").inverse).to eq(Unit("1 1/m")) } specify { expect { Unit("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } end context "convert to scalars" do - specify { Unit("10").to_i.should be_kind_of(Integer) } + specify { expect(Unit("10").to_i).to be_kind_of(Integer) } specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } - specify { Unit("10.0").to_f.should be_kind_of(Float) } + specify { expect(Unit("10.0").to_f).to be_kind_of(Float) } specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } - specify { Unit("1+1i").to_c.should be_kind_of(Complex) } + specify { expect(Unit("1+1i").to_c).to be_kind_of(Complex) } specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } - specify { Unit("3/7").to_r.should be_kind_of(Rational) } + specify { expect(Unit("3/7").to_r).to be_kind_of(Rational) } specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } end @@ -1249,13 +1923,13 @@ context "absolute value (#abs)" do context "of a unitless unit" do specify "returns the absolute value of the scalar" do - Unit("-10").abs.should == 10 + expect(Unit("-10").abs).to eq(10) end end context "of a unit" do specify "returns a unit with the absolute value of the scalar" do - Unit("-10 m").abs.should == Unit("10 m") + expect(Unit("-10 m").abs).to eq(Unit("10 m")) end end end @@ -1263,13 +1937,13 @@ context "#ceil" do context "of a unitless unit" do specify "returns the ceil of the scalar" do - Unit("10.1").ceil.should == 11 + expect(Unit("10.1").ceil).to eq(11) end end context "of a unit" do specify "returns a unit with the ceil of the scalar" do - Unit("10.1 m").ceil.should == Unit("11 m") + expect(Unit("10.1 m").ceil).to eq(Unit("11 m")) end end end @@ -1277,13 +1951,13 @@ context "#floor" do context "of a unitless unit" do specify "returns the floor of the scalar" do - Unit("10.1").floor.should == 10 + expect(Unit("10.1").floor).to eq(10) end end context "of a unit" do specify "returns a unit with the floor of the scalar" do - Unit("10.1 m").floor.should == Unit("10 m") + expect(Unit("10.1 m").floor).to eq(Unit("10 m")) end end end @@ -1291,13 +1965,13 @@ context "#round" do context "of a unitless unit" do specify "returns the round of the scalar" do - Unit("10.5").round.should == 11 + expect(Unit("10.5").round).to eq(11) end end context "of a unit" do specify "returns a unit with the round of the scalar" do - Unit("10.5 m").round.should == Unit("11 m") + expect(Unit("10.5 m").round).to eq(Unit("11 m")) end end end @@ -1305,109 +1979,109 @@ context "#truncate" do context "of a unitless unit" do specify "returns the truncate of the scalar" do - Unit("10.5").truncate.should == 10 + expect(Unit("10.5").truncate).to eq(10) end end context "of a unit" do specify "returns a unit with the truncate of the scalar" do - Unit("10.5 m").truncate.should == Unit("10 m") + expect(Unit("10.5 m").truncate).to eq(Unit("10 m")) end end context "of a complex unit" do specify "returns a unit with the truncate of the scalar" do - Unit("10.5 kg*m/s^3").truncate.should == Unit("10 kg*m/s^3") + expect(Unit("10.5 kg*m/s^3").truncate).to eq(Unit("10 kg*m/s^3")) end end end context '#zero?' do it "is true when the scalar is zero on the base scale" do - Unit("0").should be_zero - Unit("0 mm").should be_zero - Unit("-273.15 tempC").should be_zero + expect(Unit("0")).to be_zero + expect(Unit("0 mm")).to be_zero + expect(Unit("-273.15 tempC")).to be_zero end it "is false when the scalar is not zero" do - Unit("1").should_not be_zero - Unit("1 mm").should_not be_zero - Unit("0 tempC").should_not be_zero + expect(Unit("1")).not_to be_zero + expect(Unit("1 mm")).not_to be_zero + expect(Unit("0 tempC")).not_to be_zero end end context '#succ' do - specify { Unit("1").succ.should == Unit("2") } - specify { Unit("1 mm").succ.should == Unit("2 mm") } - specify { Unit("1 mm").next.should == Unit("2 mm") } - specify { Unit("-1 mm").succ.should == Unit("0 mm") } + specify { expect(Unit("1").succ).to eq(Unit("2")) } + specify { expect(Unit("1 mm").succ).to eq(Unit("2 mm")) } + specify { expect(Unit("1 mm").next).to eq(Unit("2 mm")) } + specify { expect(Unit("-1 mm").succ).to eq(Unit("0 mm")) } specify { expect { Unit("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } end context '#pred' do - specify { Unit("1").pred.should == Unit("0") } - specify { Unit("1 mm").pred.should == Unit("0 mm") } - specify { Unit("-1 mm").pred.should == Unit("-2 mm") } + specify { expect(Unit("1").pred).to eq(Unit("0")) } + specify { expect(Unit("1 mm").pred).to eq(Unit("0 mm")) } + specify { expect(Unit("-1 mm").pred).to eq(Unit("-2 mm")) } specify { expect { Unit("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } end 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 { expect(Unit("5 mm").divmod(Unit("2 mm"))).to eq([2, 1]) } + specify { expect(Unit("1 km").divmod(Unit("2 m"))).to eq([500, 0]) } specify { expect { Unit('1 m').divmod(Unit('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end context '#div' do - specify { Unit('23 m').div(Unit('2 m')).should == 11 } + specify { expect(Unit('23 m').div(Unit('2 m'))).to eq(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') } + specify { expect(Unit('1024 KiB').best_prefix).to eq(Unit('1 MiB')) } + specify { expect(Unit('1000 m').best_prefix).to eq(Unit('1 km')) } specify { expect { Unit('0 m').best_prefix }.to_not raise_error } end context "Time helper functions" do before do - Time.stub(:now).and_return(Time.utc(2011, 10, 16)) - DateTime.stub(:now).and_return(DateTime.civil(2011, 10, 16)) - Date.stub(:today).and_return(Date.civil(2011, 10, 16)) + allow(Time).to receive(:now).and_return(Time.utc(2011, 10, 16)) + allow(DateTime).to receive(:now).and_return(DateTime.civil(2011, 10, 16)) + allow(Date).to receive(:today).and_return(Date.civil(2011, 10, 16)) end context '#since' do - specify { Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } - specify { Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } - specify { Unit("min").since(Date.civil(2001, 4, 1)).should == Unit("5544000 min") } + specify { expect(Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } + specify { expect(Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } + specify { expect(Unit("min").since(Date.civil(2001, 4, 1))).to eq(Unit("5544000 min")) } specify { expect { Unit("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#before' do - specify { Unit("5 min").before(Time.now).should == Time.utc(2011, 10, 15, 23, 55) } - specify { Unit("5 min").before(DateTime.now).should == DateTime.civil(2011, 10, 15, 23, 55) } - specify { Unit("5 min").before(Date.today).should == DateTime.civil(2011, 10, 15, 23, 55) } + specify { expect(Unit("5 min").before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } + specify { expect(Unit("5 min").before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect(Unit("5 min").before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } specify { expect { Unit('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#ago' do - specify { Unit("5 min").ago.should be_kind_of Time } - specify { Unit("10000 y").ago.should be_kind_of Time } - specify { Unit("1 year").ago.should == Time.utc(2010, 10, 16) } + specify { expect(Unit("5 min").ago).to be_kind_of Time } + specify { expect(Unit("10000 y").ago).to be_kind_of Time } + specify { expect(Unit("1 year").ago).to eq(Time.utc(2010, 10, 16)) } end context '#until' do - specify { Unit("min").until(Date.civil(2011, 10, 17)).should == Unit("1440 min") } - specify { Unit("min").until(DateTime.civil(2011, 10, 21)).should == Unit("7200 min") } - specify { Unit("min").until(Time.utc(2011, 10, 21)).should == Unit("7200 min") } + specify { expect(Unit("min").until(Date.civil(2011, 10, 17))).to eq(Unit("1440 min")) } + specify { expect(Unit("min").until(DateTime.civil(2011, 10, 21))).to eq(Unit("7200 min")) } + specify { expect(Unit("min").until(Time.utc(2011, 10, 21))).to eq(Unit("7200 min")) } specify { expect { Unit('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#from' do - specify { Unit("1 day").from(Date.civil(2011, 10, 17)).should == Date.civil(2011, 10, 18) } - specify { Unit("5 min").from(DateTime.civil(2011, 10, 21)).should == DateTime.civil(2011, 10, 21, 00, 05) } - specify { Unit("5 min").from(Time.utc(2011, 10, 21)).should == Time.utc(2011, 10, 21, 00, 05) } + specify { expect(Unit("1 day").from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } + specify { expect(Unit("5 min").from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 00, 05)) } + specify { expect(Unit("5 min").from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 00, 05)) } specify { expect { Unit('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end @@ -1418,11 +2092,11 @@ describe "Unit Output formatting" do context Unit("10.5 m/s^2") do - specify { subject.to_s.should == "10.5 m/s^2" } - specify { subject.to_s("%0.2f").should == "10.50 m/s^2" } - specify { subject.to_s("%0.2e km/s^2").should == "1.05e-02 km/s^2" } - specify { subject.to_s("km/s^2").should == "0.0105 km/s^2" } - specify { subject.to_s(STDOUT).should == "10.5 m/s^2" } + specify { expect(subject.to_s).to eq("10.5 m/s^2") } + specify { expect(subject.to_s("%0.2f")).to eq("10.50 m/s^2") } + specify { expect(subject.to_s("%0.2e km/s^2")).to eq("1.05e-02 km/s^2") } + specify { expect(subject.to_s("km/s^2")).to eq("0.0105 km/s^2") } + specify { expect(subject.to_s(STDOUT)).to eq("10.5 m/s^2") } specify { expect { subject.to_s("random string") }.to raise_error(ArgumentError, "'random' Unit not recognized") } end @@ -1441,7 +2115,7 @@ subject { Unit("8 cups") } - specify { subject.to_s.should == "8 cupz" } + specify { expect(subject.to_s).to eq("8 cupz") } end @@ -1453,6 +2127,6 @@ let(:v) { Unit('1 m^3') } let(:n) { Unit("1 mole") } let(:r) { Unit("8.31451 J/mol*degK") } - specify { ((p*v)/(n*r)).convert_to('tempK').should be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } + specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } end end diff --git a/spec/ruby-units/utf-8/unit_spec.rb b/spec/ruby-units/utf-8/unit_spec.rb index 045fafed..eb9cf654 100644 --- a/spec/ruby-units/utf-8/unit_spec.rb +++ b/spec/ruby-units/utf-8/unit_spec.rb @@ -7,17 +7,17 @@ context 'when the UTF-8 symbol is used' do context 'Angles' do it 'should be a degree' do - Unit("180\u00B0").units.should == 'deg' + expect(Unit("180\u00B0").units).to eq('deg') end end context 'Temperature' do it 'should be a degree Celcius' do - Unit("180\u00B0C").units.should == 'degC' + expect(Unit("180\u00B0C").units).to eq('degC') end it 'should be a degree Fahrenheit' do - Unit("180\u00B0F").units.should == 'degF' + expect(Unit("180\u00B0F").units).to eq('degF') end end end From 4333e5d2096dda1df0a001695f6c9ba42b3fe13b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:10:26 -0400 Subject: [PATCH 054/150] remove rspec restriction --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index fb868299..90155cc9 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ group :test do gem 'rcov', :platforms => :mri_18 gem 'simplecov', :require => false, :platforms => :mri_19 gem 'simplecov-html', :platforms => :mri_19 - gem 'rspec', '~>2.5' + gem 'rspec' gem 'guard-rspec' end From 67e856a6f2e36ca9b89dc82f3e37135acc84d356 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:08 -0400 Subject: [PATCH 055/150] remove autotest --- .autotest | 41 ----------------------------------------- autotest/discover.rb | 1 - 2 files changed, 42 deletions(-) delete mode 100644 .autotest delete mode 100644 autotest/discover.rb diff --git a/.autotest b/.autotest deleted file mode 100644 index b32fba98..00000000 --- a/.autotest +++ /dev/null @@ -1,41 +0,0 @@ -# -*- ruby -*- - -require 'autotest/growl' -require 'autotest/fsevent' -require 'autotest/bundler' - -module AutoGrowl - def self.growl title, msg, pri=0 - system "growlnotify -n autotest --image /Applications/Mail.app/Contents/Resources/Caution.tiff -p #{pri} -m #{msg.inspect} #{title}" - end - - Autotest.add_hook :run do |at| - growl "Run", "Run" unless $TESTING - end - - Autotest.add_hook :red do |at| - growl "Tests Failed", "#{at.files_to_test.size} tests failed", 2 - end - - Autotest.add_hook :green do |at| - growl "Tests Passed", "All tests passed", -2 if at.tainted - end - - Autotest.add_hook :init do |at| - growl "autotest", "autotest was started" unless $TESTING - end - - Autotest.add_hook :interrupt do |at| - growl "autotest", "autotest was reset" unless $TESTING - nil - end - - Autotest.add_hook :quit do |at| - growl "autotest", "autotest is exiting" unless $TESTING - end - - Autotest.add_hook :all do |at|_hook - growl "autotest", "Tests have fully passed", -2 unless $TESTING - end -end - diff --git a/autotest/discover.rb b/autotest/discover.rb deleted file mode 100644 index 24dd9b7b..00000000 --- a/autotest/discover.rb +++ /dev/null @@ -1 +0,0 @@ -Autotest.add_discovery { "rspec2" } \ No newline at end of file From b5101b57cf1260fdf486bc0b5fa49bd121c386ce Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:45 -0400 Subject: [PATCH 056/150] changelog & whitespace in rakefile --- CHANGELOG.txt | 75 ++++++++++++++++++++++++++------------------------- Rakefile.rb | 2 +- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d6d79f21..4caf0a6e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,7 @@ Change Log for Ruby-units ========================= -2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit +2015-05-09 * update test harness to use rspec 3 +2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit 2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method * Fix issue #60 -- Consider placing Unit in a module * Fix issue #75 -- Siemens is kind of conductance not resistance @@ -25,7 +26,7 @@ Change Log for Ruby-units 2012-01-02 1.4.0 * Fix some definitions that were just wrong (amu, dalton) * Definition uses name of unit if no aliases provided * Refactor definition process. New units are immediately available -2011-12-31 * Define standard units in terms of base and other standard units -- more internally consistent +2011-12-31 * Define standard units in terms of base and other standard units -- more internally consistent and less prone to round-off errors. * add 'poundal' * remove 'wtpercent' @@ -33,7 +34,7 @@ Change Log for Ruby-units * Define compound units with base units for consistency * distinguish between a league and a nautical league * NOTE: the new unit definition DSL is not backwardly compatible with the old method - (which is now deprecated). + (which is now deprecated). * Fix issue #27 2011-12-18 * Can define a display_name for units (fixes #26) 2011-12-04 * Documentation improvements @@ -61,17 +62,17 @@ Change Log for Ruby-units 2007-12-13 1.1.3 * fixed a minor bug with string % 2007-12-12 1.1.2 * fixed a bug with format strings * detect if ruby 1.8.6 is installed and use its' to_date function - + 2007-07-14 1.1.1 * fixed bug that would prevent creating '' units, which prevented rounding from working * tests do not fail if Uncertain gem is not installed, you just get an annoying warning message - + 2007-01-28 1.1.0 * completely revamped the temperature handling system (see README) * fixed some spelling errors in some units * fixed to_datetime and to_date to convert durations to datetimes and dates' -2007-01-24 1.0.2 * Minor changes in the way powers are calculated to support Uncertain +2007-01-24 1.0.2 * Minor changes in the way powers are calculated to support Uncertain numbers better. * Fixed parsing bug with Uncertain Numbers * added resolution / typography units (pixels, points, pica) @@ -87,17 +88,17 @@ Change Log for Ruby-units '1+1i mm'.unit to get a complex unit. * Taking the root of a negative unit will give you a complex unit * fixed unary minus to work again - * Math.hypot now takes units. Both parameters must be the compatible - units or it will assert. Units will be converted to a common base + * Math.hypot now takes units. Both parameters must be the compatible + units or it will assert. Units will be converted to a common base before use. - * Can now specify units in rational numbers, i.e., '1/4 cup'.unit + * Can now specify units in rational numbers, i.e., '1/4 cup'.unit * Seems like a good time to move to 1.0 status - + 2006-12-15 0.3.9 * forgot to increment the version in the gem file..ooops. -2006-12-15 0.3.8 * Any object that supports a 'to_unit' method will now be +2006-12-15 0.3.8 * Any object that supports a 'to_unit' method will now be automatically coerced to a unit during math operations. - + 2006-12-14 0.3.7 * improved handling of percents and added a 'wt%' unit equivalent to 1 g/dl. * Improved handling for units with non-alphanumeric names @@ -111,21 +112,21 @@ Change Log for Ruby-units * to_int now coerces the result to an actual Integer, but only works properly for unitless Units. -2006-10-27 0.3.4 * Fixed a few more parsing bugs so that it will properly +2006-10-27 0.3.4 * Fixed a few more parsing bugs so that it will properly complain about malformed units. * Fixed a bug that prevents proper use of percents - * several minor tweaks + * several minor tweaks * some improved Date and DateTime handling * can convert between Date, DateTime, and Time objects * Time math will now return a DateTime if it goes out of range. -2006-10-03 0.3.3 * Apparently I can't do math late at night. +2006-10-03 0.3.3 * Apparently I can't do math late at night. Fixed a bug that would cause problems when adding - or subtracting units to a unit with a zero scalar. + or subtracting units to a unit with a zero scalar. * Date and DateTime objects can be converted to 'units' -2006-10-03 0.3.2 * More minor bug fixes +2006-10-03 0.3.2 * More minor bug fixes (now fixes a minor name collision with rails) 2006-10-02 0.3.1 * minor bug fixes @@ -133,10 +134,10 @@ Change Log for Ruby-units 2006-10-02 0.3.0 * Performance enhanced by caching results of many functions (Thanks to Kurt Stephens for pushing this.) * Throws an exception if the unit is not recognized - * units can now identify what 'kind' they are + * units can now identify what 'kind' they are (:length, :mass, etc..) - * New constructors: - Unit(1,"mm") + * New constructors: + Unit(1,"mm") Unit(1,"mm/s") Unit(1,"mm","s") @@ -149,8 +150,8 @@ Change Log for Ruby-units * 'string'.time returns a Time object or a DateTime if the Time object fails * 'string'.datetime returns a DateTime or a Time if the - DateTime fails - + DateTime fails + 2006-09-19 0.2.2 * tweaked temperature handling a bit. Now enter temperatures like this: '0 tempC'.unit #=> 273.15 degK @@ -158,7 +159,7 @@ Change Log for Ruby-units problems when temperatures are used in equations. * added Time.in("5 min") * added Unit.to_unit to simplify some calls - + 2006-09-18 0.2.1 * Trig math functions (sin, cos, tan, sinh, cosh, tanh) accept units that can be converted to radians Math.sin("90 deg".unit) => 1.0 @@ -170,14 +171,14 @@ Change Log for Ruby-units Time.now + "1 hr".unit => Mon Sep 18 11:51:29 EDT 2006 * can output time in 'hh:mm:ss' format by using 'unit.to_s(:time)' - * added time helper methods - ago, - since(Time/DateTime), - until(Time/DateTime), - from(Time/DateTime), + * added time helper methods + ago, + since(Time/DateTime), + until(Time/DateTime), + from(Time/DateTime), before(Time/DateTime), and after(Time/DateTime) - * Time helpers also work on strings. In this case they + * Time helpers also work on strings. In this case they are first converted to units '5 min'.from_now '1 week'.ago @@ -191,19 +192,19 @@ Change Log for Ruby-units output * can use U'1 mm' or '1 mm'.u to specify units now -2006-09-17 * can now use the '%' format specifier like +2006-09-17 * can now use the '%' format specifier like '%0.2f' % '1 mm'.unit #=> '1.00 mm' * works nicely with time now. '1 week'.unit + Time.now => 1.159e+09 s - Time.at('1.159e+09 s'.unit) + Time.at('1.159e+09 s'.unit) => Sat Sep 23 04:26:40 EDT 2006 - "1.159e9 s".unit.time + "1.159e9 s".unit.time => Sat Sep 23 04:26:40 EDT 2006 * Time.now.unit => 1.159e9 s * works well with 'Uncertain' numerics (www.rubyforge.org/projects/uncertain) * Improved parsing - + 2006-08-28 0.2.0 * Added 'ruby_unit.rb' file so that requires will still work if the wrong name is used * Added 'to' as an alias to '>>' so conversions can be @@ -226,13 +227,13 @@ Change Log for Ruby-units from forcing the conversion. To get the scalar, just use 'unit.scalar' * 'inspect' returns string representation - * better edge-case detection with math functions. + * better edge-case detection with math functions. "0 mm".unit**-1 now throws a ZeroDivisionError exception - * Ranges can make a series of units, so long as the end + * Ranges can make a series of units, so long as the end points have integer scalars. * Fixed a parsing bug with feet/pounds and scientific numbers - + 2006-08-22 0.1.1 * Added new format option "1 mm".to_unit("in") now converts the result to the indicated units * Fixed some naming issues so that the gem name matches @@ -249,7 +250,7 @@ Change Log for Ruby-units [1,'mm','s'].unit === "1 mm/s".unit 2.5.unit === "2.5".unit * Added instructions on how to add custom units - + 2006-08-22 0.1.0 * Initial Release diff --git a/Rakefile.rb b/Rakefile.rb index d41e377a..de0c9fd1 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -60,7 +60,7 @@ # puts %x{rvm current} puts end - + desc "Run all specs with rcov" RSpec::Core::RakeTask.new("spec:rcov") do |t| t.rcov = true From 56451f0ff259cbdb544fa9d7070e0f909a7aaf20 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:52 -0400 Subject: [PATCH 057/150] travis config --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 04c4938b..cd28a68b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ rvm: - jruby-19mode # JRuby in 1.9 mode - 2.0.0 - 2.1.0 + - 2.2.0 + - ruby-head + - jruby-head jdk: - openjdk6 - openjdk7 @@ -15,4 +18,10 @@ matrix: jdk: openjdk6 - rvm: 2.1.0 jdk: openjdk6 + - rvm: 2.2.0 + jdk: openjdk6 + - rvm: jruby-head + jdk: openjdk6 + - rvm: ruby-head + jdk: openjdk6 script: bundle exec rake --trace From 6a379a27da7f22987c98cf0d337905749a0dcc5c Mon Sep 17 00:00:00 2001 From: dlanphear9 Date: Fri, 10 Jul 2015 12:17:17 -0400 Subject: [PATCH 058/150] Separate leading decimal number from denominator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to prevent “Unit not recognized” --- lib/ruby_units/unit.rb | 8 +++++++- spec/ruby-units/unit_spec.rb | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 1eaad1d4..e8e00453 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -54,6 +54,7 @@ class Unit < Numeric UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/ BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/ + NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/ UNCERTAIN_REGEX = /#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/ COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/ RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/ @@ -1502,7 +1503,12 @@ def parse(passed_unit_string="0") bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, "") end end - bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } if bottom + if bottom + bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } + # Separate leading decimal from denominator, if any + bottom_scalar,bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] + end + @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? @scalar = 1 unless @scalar.kind_of? Numeric @scalar = @scalar.to_int if (@scalar.to_int == @scalar) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 1789601a..a4e3f34d 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -365,6 +365,21 @@ its(:temperature_scale) { should be_nil } end + # rational scalar with numeric modified unit + describe Unit("12.1 mg/0.6mL") do + it { should be_an_instance_of Unit } + its(:scalar) { should be_an Numeric} + its(:units) { should == "mg/ml" } + its(:kind) { should == :density } + it { should_not be_temperature } + it { should_not be_degree } + it { should_not be_base } + it { should_not be_unitless } + it { should_not be_zero } + its(:base) { should be_a Numeric } + its(:temperature_scale) { should be_nil } + end + # time string describe Unit("1:23:45,200") do it { should be_an_instance_of Unit } From afbbe2d5e694b7c0dab790687ba47f20927ee3d6 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:08:15 -0400 Subject: [PATCH 059/150] use transpec to convert from spec 2 style to rspec 3 style --- Gemfile | 1 + Guardfile | 32 + spec/ruby-units/array_spec.rb | 10 +- spec/ruby-units/bugs_spec.rb | 2 +- spec/ruby-units/cache_spec.rb | 6 +- spec/ruby-units/complex_spec.rb | 14 +- spec/ruby-units/date_spec.rb | 46 +- spec/ruby-units/definition_spec.rb | 35 +- spec/ruby-units/math_spec.rb | 58 +- spec/ruby-units/numeric_spec.rb | 12 +- spec/ruby-units/object_spec.rb | 10 +- spec/ruby-units/range_spec.rb | 10 +- spec/ruby-units/string_spec.rb | 18 +- spec/ruby-units/temperature_spec.rb | 70 +- spec/ruby-units/time_spec.rb | 45 +- spec/ruby-units/unit_spec.rb | 1844 ++++++++++++++++++--------- spec/ruby-units/utf-8/unit_spec.rb | 6 +- 17 files changed, 1498 insertions(+), 721 deletions(-) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index ad40c588..fb868299 100644 --- a/Gemfile +++ b/Gemfile @@ -12,5 +12,6 @@ group :test do gem 'simplecov', :require => false, :platforms => :mri_19 gem 'simplecov-html', :platforms => :mri_19 gem 'rspec', '~>2.5' + gem 'guard-rspec' end diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..0469987f --- /dev/null +++ b/Guardfile @@ -0,0 +1,32 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +directories %w(lib spec) + +## Uncomment to clear the screen before every task +clearing :on + +# Note: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: "bundle exec rspec" do + require "ostruct" + + # Generic Ruby apps + rspec = OpenStruct.new + rspec.spec = ->(m) { "spec/#{m}_spec.rb" } + rspec.spec_dir = "spec" + rspec.spec_helper = "spec/spec_helper.rb" + + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.("lib/#{m[1]}") } + watch(rspec.spec_helper) { rspec.spec_dir } + +end diff --git a/spec/ruby-units/array_spec.rb b/spec/ruby-units/array_spec.rb index 2a3b7424..aca122c6 100644 --- a/spec/ruby-units/array_spec.rb +++ b/spec/ruby-units/array_spec.rb @@ -4,11 +4,11 @@ subject { [1, 'cm'] } - it {should be_kind_of Array} - it {should respond_to :to_unit} + it {is_expected.to be_kind_of Array} + it {is_expected.to respond_to :to_unit} - specify { subject.to_unit.should be_instance_of Unit} - specify { subject.to_unit.should == "1 cm".to_unit } - specify { subject.to_unit('mm').should == "10 mm".to_unit} + specify { expect(subject.to_unit).to be_instance_of Unit} + specify { expect(subject.to_unit).to eq("1 cm".to_unit) } + specify { expect(subject.to_unit('mm')).to eq("10 mm".to_unit)} end \ No newline at end of file diff --git a/spec/ruby-units/bugs_spec.rb b/spec/ruby-units/bugs_spec.rb index 8b0709b9..25b6ca37 100644 --- a/spec/ruby-units/bugs_spec.rb +++ b/spec/ruby-units/bugs_spec.rb @@ -5,6 +5,6 @@ let(:b) { Unit.new(a)} it "should subtract a unit properly from one initialized with a unit" do - (b - Unit("1.5 cm^3")).should == Unit("1.5 cm^3") + expect(b - Unit("1.5 cm^3")).to eq(Unit("1.5 cm^3")) end end \ No newline at end of file diff --git a/spec/ruby-units/cache_spec.rb b/spec/ruby-units/cache_spec.rb index e7048601..f6a07602 100644 --- a/spec/ruby-units/cache_spec.rb +++ b/spec/ruby-units/cache_spec.rb @@ -12,20 +12,20 @@ context ".clear" do it "should clear the cache" do subject.clear - subject.get('m').should be_nil + expect(subject.get('m')).to be_nil end end context ".get" do it "should retrieve values already in the cache" do - subject.get['m'].should == unit + expect(subject.get['m']).to eq(unit) end end context ".set" do it "should put a unit into the cache" do subject.set('kg', Unit('1 kg')) - subject.get['kg'].should == Unit('1 kg') + expect(subject.get['kg']).to eq(Unit('1 kg')) end end end \ No newline at end of file diff --git a/spec/ruby-units/complex_spec.rb b/spec/ruby-units/complex_spec.rb index 1077de1c..404951ff 100644 --- a/spec/ruby-units/complex_spec.rb +++ b/spec/ruby-units/complex_spec.rb @@ -6,23 +6,23 @@ describe Complex do subject { Complex(1,1) } - it { should respond_to :to_unit } + it { is_expected.to respond_to :to_unit } end describe "Complex Unit" do subject { Complex(1.0, -1.0).to_unit } - it { should be_instance_of Unit} - it(:scalar) { should be_kind_of Complex } + it { is_expected.to be_instance_of Unit} + it(:scalar) { is_expected.to be_kind_of Complex } - it { should == "1-1i".to_unit } - it { should === "1-1i".to_unit } + it { is_expected.to eq("1-1i".to_unit) } + it { is_expected.to be === "1-1i".to_unit } if RUBY_VERSION < "1.9" context "in Ruby < 1.9" do it "is comparable" do - subject.should > "1+0.5i".to_unit - subject.should < "2+1i".to_unit + expect(subject).to be > "1+0.5i".to_unit + expect(subject).to be < "2+1i".to_unit end end else diff --git a/spec/ruby-units/date_spec.rb b/spec/ruby-units/date_spec.rb index 77a11371..e9507e42 100644 --- a/spec/ruby-units/date_spec.rb +++ b/spec/ruby-units/date_spec.rb @@ -3,36 +3,48 @@ describe Date do subject { Date.new(2011,4,1) } - it {should be_instance_of Date} - it {should respond_to :to_unit} - it {should respond_to :to_time} - it {should respond_to :to_date} + it {is_expected.to be_instance_of Date} + it {is_expected.to respond_to :to_unit} + it {is_expected.to respond_to :to_time} + it {is_expected.to respond_to :to_date} - specify { (subject + "5 days".unit).should == Date.new(2011,4,6) } - specify { (subject - "5 days".unit).should == Date.new(2011,3,27) } + specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } + specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } # 2012 is a leap year... - specify { (subject + "1 year".unit).should == Date.new(2012,3,31) } - specify { (subject - "1 year".unit).should == Date.new(2010,4,1) } + specify { expect(subject + "1 year".unit).to eq(Date.new(2012,3,31)) } + specify { expect(subject - "1 year".unit).to eq(Date.new(2010,4,1)) } end describe "Date Unit" do subject { Date.new(2011,4,1).to_unit } - it { should be_instance_of Unit } - its(:scalar) { should be_kind_of Rational } - its(:units) { should == "d" } - its(:kind) { should == :time } + it { is_expected.to be_instance_of Unit } - specify { (subject + "5 days".unit).should == Date.new(2011,4,6) } - specify { (subject - "5 days".unit).should == Date.new(2011,3,27) } + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_kind_of Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("d") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + + specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } + specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } specify { expect { subject + Date.new(2011,4,1) }.to raise_error(ArgumentError) } specify { expect { subject + DateTime.new(2011,4,1,12,00,00) }.to raise_error(ArgumentError) } specify { expect { subject + Time.parse("2011-04-01 12:00:00") }.to raise_error(ArgumentError) } - specify { (subject - Date.new(2011,4,1)).should be_zero } - specify { (subject - DateTime.new(2011,4,1,00,00,00)).should be_zero } + specify { expect(subject - Date.new(2011,4,1)).to be_zero } + specify { expect(subject - DateTime.new(2011,4,1,00,00,00)).to be_zero } specify { expect {(subject - Time.parse("2011-04-01 00:00"))}.to raise_error(ArgumentError) } - specify { (Date.new(2011,4,1) + 1).should == Date.new(2011,4,2)} + specify { expect(Date.new(2011,4,1) + 1).to eq(Date.new(2011,4,2))} end \ No newline at end of file diff --git a/spec/ruby-units/definition_spec.rb b/spec/ruby-units/definition_spec.rb index 1e0c53df..0f83e261 100644 --- a/spec/ruby-units/definition_spec.rb +++ b/spec/ruby-units/definition_spec.rb @@ -9,10 +9,33 @@ end } - its(:name) {should == ""} - its(:aliases) {should == %w{eV electron-volt}} - its(:scalar) {should == 1.602E-19} - its(:numerator) {should include("", "", "")} - its(:denominator) {should include("", "")} - its(:display_name) {should == "electron-volt"} + describe '#name' do + subject { super().name } + it {is_expected.to eq("")} + end + + describe '#aliases' do + subject { super().aliases } + it {is_expected.to eq(%w{eV electron-volt})} + end + + describe '#scalar' do + subject { super().scalar } + it {is_expected.to eq(1.602E-19)} + end + + describe '#numerator' do + subject { super().numerator } + it {is_expected.to include("", "", "")} + end + + describe '#denominator' do + subject { super().denominator } + it {is_expected.to include("", "")} + end + + describe '#display_name' do + subject { super().display_name } + it {is_expected.to eq("electron-volt")} + end end diff --git a/spec/ruby-units/math_spec.rb b/spec/ruby-units/math_spec.rb index 4ad5b4f8..3d355c57 100644 --- a/spec/ruby-units/math_spec.rb +++ b/spec/ruby-units/math_spec.rb @@ -3,16 +3,16 @@ describe Math do describe "#sqrt" do - specify { Math.sqrt(Unit('1 mm^6')).should == Unit('1 mm^3') } - specify { Math.sqrt(4).should == 2 } - specify { Math.sqrt(Unit("-9 mm^2")).should be_kind_of(Complex) } + specify { expect(Math.sqrt(Unit('1 mm^6'))).to eq(Unit('1 mm^3')) } + specify { expect(Math.sqrt(4)).to eq(2) } + specify { expect(Math.sqrt(Unit("-9 mm^2"))).to be_kind_of(Complex) } end if RUBY_VERSION > "1.9" # cbrt is only defined in Ruby > 1.9 describe '#cbrt' do - specify { Math.cbrt(Unit('1 mm^6')).should == Unit('1 mm^2') } - specify { Math.cbrt(8).should == 2 } + specify { expect(Math.cbrt(Unit('1 mm^6'))).to eq(Unit('1 mm^2')) } + specify { expect(Math.cbrt(8)).to eq(2) } end end @@ -20,42 +20,42 @@ context "with '45 deg' unit" do subject { Unit("45 deg") } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end context "with 'PI/4 radians' unit" do subject { Unit((Math::PI/4),'radians') } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end context "with 'PI/4' continues to work" do subject { (Math::PI/4) } - specify { Math.sin(subject).should be_within(0.01).of(0.70710678) } - specify { Math.cos(subject).should be_within(0.01).of(0.70710678) } - specify { Math.tan(subject).should be_within(0.01).of(1) } - specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) } - specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) } - specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) } + specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } + specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } + specify { expect(Math.sinh(subject)).to be_within(0.01).of(0.8686709614860095) } + specify { expect(Math.cosh(subject)).to be_within(0.01).of(1.3246090892520057) } + specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end - specify { Math.hypot(Unit("1 m"), Unit("2 m")).should be_within(Unit("0.01 m")).of(Unit("2.23607 m")) } - specify { Math.hypot(Unit("1 m"), Unit("2 ft")).should be_within(Unit("0.01 m")).of(Unit("1.17116 m")) } - specify { Math.hypot(3,4).should == 5} + specify { expect(Math.hypot(Unit("1 m"), Unit("2 m"))).to be_within(Unit("0.01 m")).of(Unit("2.23607 m")) } + specify { expect(Math.hypot(Unit("1 m"), Unit("2 ft"))).to be_within(Unit("0.01 m")).of(Unit("1.17116 m")) } + specify { expect(Math.hypot(3,4)).to eq(5)} specify { expect {Math.hypot(Unit("1 m"), Unit("2 lbs")) }.to raise_error(ArgumentError) } - specify { Math.atan2(Unit("1 m"), Unit("2 m")).should be_within(0.01).of(0.4636476090008061) } - specify { Math.atan2(Unit("1 m"), Unit("2 ft")).should be_within(0.01).of(1.0233478888629426) } - specify { Math.atan2(1,1).should be_within(0.01).of(0.785398163397448)} + specify { expect(Math.atan2(Unit("1 m"), Unit("2 m"))).to be_within(0.01).of(0.4636476090008061) } + specify { expect(Math.atan2(Unit("1 m"), Unit("2 ft"))).to be_within(0.01).of(1.0233478888629426) } + specify { expect(Math.atan2(1,1)).to be_within(0.01).of(0.785398163397448)} specify { expect {Math.atan2(Unit("1 m"), Unit("2 lbs"))}.to raise_error(ArgumentError) } end end \ No newline at end of file diff --git a/spec/ruby-units/numeric_spec.rb b/spec/ruby-units/numeric_spec.rb index b0721852..f26afb72 100644 --- a/spec/ruby-units/numeric_spec.rb +++ b/spec/ruby-units/numeric_spec.rb @@ -3,10 +3,10 @@ # some rubies return an array of strings for .instance_methods and others return an array of symbols # so let's stringify them before we compare describe Numeric do - specify { Float.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Integer.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Fixnum.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Complex.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Bignum.instance_methods.map {|m| m.to_s}.should include("to_unit") } - specify { Rational.instance_methods.map {|m| m.to_s}.should include("to_unit") } + specify { expect(Float.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Integer.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Fixnum.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Complex.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Bignum.instance_methods.map {|m| m.to_s}).to include("to_unit") } + specify { expect(Rational.instance_methods.map {|m| m.to_s}).to include("to_unit") } end \ No newline at end of file diff --git a/spec/ruby-units/object_spec.rb b/spec/ruby-units/object_spec.rb index f4ac0953..1050a25a 100644 --- a/spec/ruby-units/object_spec.rb +++ b/spec/ruby-units/object_spec.rb @@ -1,9 +1,9 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Object do - specify { Unit('1 mm').should be_instance_of Unit} - specify { U('1 mm').should be_instance_of Unit} - specify { u('1 mm').should be_instance_of Unit} - specify { (Unit(0) + Unit(0)).should be_instance_of Unit} - specify { (Unit(0) - Unit(0)).should be_instance_of Unit} + specify { expect(Unit('1 mm')).to be_instance_of Unit} + specify { expect(U('1 mm')).to be_instance_of Unit} + specify { expect(u('1 mm')).to be_instance_of Unit} + specify { expect(Unit(0) + Unit(0)).to be_instance_of Unit} + specify { expect(Unit(0) - Unit(0)).to be_instance_of Unit} end \ No newline at end of file diff --git a/spec/ruby-units/range_spec.rb b/spec/ruby-units/range_spec.rb index bd486b41..245d98e5 100644 --- a/spec/ruby-units/range_spec.rb +++ b/spec/ruby-units/range_spec.rb @@ -4,13 +4,17 @@ context "of integer units" do subject { (Unit('1 mm')..Unit('3 mm')) } - it { should include(Unit('2 mm')) } - its(:to_a) { should == [ Unit('1 mm'), Unit('2 mm'), Unit('3 mm') ] } + it { is_expected.to include(Unit('2 mm')) } + + describe '#to_a' do + subject { super().to_a } + it { is_expected.to eq([ Unit('1 mm'), Unit('2 mm'), Unit('3 mm') ]) } + end end context "of floating point units" do subject { (Unit('1.5 mm')..Unit('3.5 mm')) } - it { should include(Unit('2.0 mm')) } + it { is_expected.to include(Unit('2.0 mm')) } specify { expect { subject.to_a }.to raise_exception(ArgumentError)} end end \ No newline at end of file diff --git a/spec/ruby-units/string_spec.rb b/spec/ruby-units/string_spec.rb index bb893445..da8a9131 100644 --- a/spec/ruby-units/string_spec.rb +++ b/spec/ruby-units/string_spec.rb @@ -2,19 +2,19 @@ describe String do context "Unit creation from strings" do - specify { "1 mm".to_unit.should be_instance_of Unit } - specify { "1 mm".unit.should be_instance_of Unit } - specify { "1 mm".u.should be_instance_of Unit } - specify { "1 m".convert_to("ft").should be_within(Unit("0.01 ft")).of Unit("3.28084 ft") } + specify { expect("1 mm".to_unit).to be_instance_of Unit } + specify { expect("1 mm".unit).to be_instance_of Unit } + specify { expect("1 mm".u).to be_instance_of Unit } + specify { expect("1 m".convert_to("ft")).to be_within(Unit("0.01 ft")).of Unit("3.28084 ft") } end context "output format" do subject { Unit("1.23456 m/s^2") } - specify { ("" % subject).should == ""} - specify { ("%0.2f" % subject).should == "1.23 m/s^2"} - specify { ("%0.2f km/h^2" % subject).should == "15999.90 km/h^2"} - specify { ("km/h^2" % subject).should == "15999.9 km/h^2"} - specify { ("%H:%M:%S" % Unit("1.5 h")).should == "01:30:00"} + specify { expect("" % subject).to eq("")} + specify { expect("%0.2f" % subject).to eq("1.23 m/s^2")} + specify { expect("%0.2f km/h^2" % subject).to eq("15999.90 km/h^2")} + specify { expect("km/h^2" % subject).to eq("15999.9 km/h^2")} + specify { expect("%H:%M:%S" % Unit("1.5 h")).to eq("01:30:00")} end end \ No newline at end of file diff --git a/spec/ruby-units/temperature_spec.rb b/spec/ruby-units/temperature_spec.rb index 4836f96b..e11328cf 100644 --- a/spec/ruby-units/temperature_spec.rb +++ b/spec/ruby-units/temperature_spec.rb @@ -50,40 +50,60 @@ describe "Unit('100 tC')" do subject {Unit("100 tC")} - its(:scalar) {should be_within(0.001).of 100} - its(:units) {should == "tC"} - its(:kind) {should == :temperature} - it {should be_temperature} - it {should be_degree} - it {should_not be_base} - it {should_not be_unitless} - it {should_not be_zero} - its(:base) {should be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} - its(:temperature_scale) {should == "degC"} + + describe '#scalar' do + subject { super().scalar } + it {is_expected.to be_within(0.001).of 100} + end + + describe '#units' do + subject { super().units } + it {is_expected.to eq("tC")} + end + + describe '#kind' do + subject { super().kind } + it {is_expected.to eq(:temperature)} + end + it {is_expected.to be_temperature} + it {is_expected.to be_degree} + it {is_expected.not_to be_base} + it {is_expected.not_to be_unitless} + it {is_expected.not_to be_zero} + + describe '#base' do + subject { super().base } + it {is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it {is_expected.to eq("degC")} + end end context "between temperature scales" do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - specify { Unit("100 tC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("0 tC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("37 tC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("-273.15 tC").should == Unit("0 tempK") } + specify { expect(Unit("100 tC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("0 tC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("37 tC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("-273.15 tC")).to eq(Unit("0 tempK")) } - specify { Unit("212 tF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("32 tF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("98.6 tF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("-459.67 tF").should == Unit("0 tempK") } + specify { expect(Unit("212 tF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("32 tF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("98.6 tF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("-459.67 tF")).to eq(Unit("0 tempK")) } - specify { Unit("671.67 tR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("491.67 tR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("558.27 tR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { Unit("0 tR").should == Unit("0 tempK") } + specify { expect(Unit("671.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("491.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("558.27 tR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} + specify { expect(Unit("0 tR")).to eq(Unit("0 tempK")) } - specify { Unit("100 tK").convert_to("tempC").should be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} - specify { Unit("100 tK").convert_to("tempF").should be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} - specify { Unit("100 tK").convert_to("tempR").should be_within(U"0.01 degR").of(Unit("180 tempR"))} + specify { expect(Unit("100 tK").convert_to("tempC")).to be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} + specify { expect(Unit("100 tK").convert_to("tempF")).to be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} + specify { expect(Unit("100 tK").convert_to("tempR")).to be_within(U"0.01 degR").of(Unit("180 tempR"))} end diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby-units/time_spec.rb index 96492874..d60fbf8d 100644 --- a/spec/ruby-units/time_spec.rb +++ b/spec/ruby-units/time_spec.rb @@ -3,44 +3,55 @@ describe Time do let(:now) { Time.at(1303656390) } before(:each) do - Time.stub(:now).and_return(now) + allow(Time).to receive(:now).and_return(now) end context ".at" do subject { Date.new(2011,4,1).to_unit } - specify { Time.at(Time.at(0)).utc.strftime("%D %T").should == "01/01/70 00:00:00" } - specify { Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T").should == "04/01/11 00:00:00"} - specify { Time.at(subject - Date.new(1970,1,1), 500).usec.should == 500} + specify { expect(Time.at(Time.at(0)).utc.strftime("%D %T")).to eq("01/01/70 00:00:00") } + specify { expect(Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T")).to eq("04/01/11 00:00:00")} + specify { expect(Time.at(subject - Date.new(1970,1,1), 500).usec).to eq(500)} end context ".in" do - specify { Time.in("5 min").should be_a Time} - specify { Time.in("5 min").should > Time.now} + specify { expect(Time.in("5 min")).to be_a Time} + specify { expect(Time.in("5 min")).to be > Time.now} end context '#to_date' do subject { Time.parse("2012-01-31 11:59:59") } - specify { subject.to_date.to_s.should == "2012-01-31" } - specify { (subject+1).to_date.to_s.should == "2012-01-31" } + specify { expect(subject.to_date.to_s).to eq("2012-01-31") } + specify { expect((subject+1).to_date.to_s).to eq("2012-01-31") } end context '#to_unit' do subject { now } - its(:to_unit) { should be_an_instance_of(Unit) } - its('to_unit.units') { should == "s" } - specify { subject.to_unit('h').kind.should == :time} - specify { subject.to_unit('h').units.should == 'h'} + + describe '#to_unit' do + subject { super().to_unit } + it { is_expected.to be_an_instance_of(Unit) } + end + + describe '#to_unit' do + subject { super().to_unit } + describe '#units' do + subject { super().units } + it { is_expected.to eq("s") } + end + end + specify { expect(subject.to_unit('h').kind).to eq(:time)} + specify { expect(subject.to_unit('h').units).to eq('h')} end context 'addition (+)' do - specify { (Time.now + 1).should == Time.at(1303656390 + 1)} - specify { (Time.now + Unit("10 min")).should == Time.at(1303656390 + 600)} + specify { expect(Time.now + 1).to eq(Time.at(1303656390 + 1))} + specify { expect(Time.now + Unit("10 min")).to eq(Time.at(1303656390 + 600))} end context 'subtraction (-)' do - specify { (Time.now - 1).should == Time.at(1303656390 - 1)} - specify { (Time.now - Unit("10 min")).should == Time.at(1303656390 - 600)} - specify { (Time.now - Unit("150 years")).should == Time.parse("1861-04-24 09:46:30 -0500")} + specify { expect(Time.now - 1).to eq(Time.at(1303656390 - 1))} + specify { expect(Time.now - Unit("10 min")).to eq(Time.at(1303656390 - 600))} + specify { expect(Time.now - Unit("150 years")).to eq(Time.parse("1861-04-24 09:46:30 -0500"))} end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index a4e3f34d..ca30afad 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -2,10 +2,12 @@ require 'yaml' describe Unit.base_units do - it { should be_a Array } - it { should have(14).elements } + it { is_expected.to be_a Array } + it 'has 14 elements' do + expect(subject.size).to eq(14) + end %w{kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte}.each do |u| - it { should include(Unit(u)) } + it { is_expected.to include(Unit(u)) } end end @@ -14,355 +16,803 @@ # zero string describe Unit("0") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 0 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 0 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # non-zero string describe Unit("1") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 1 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 1 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # numeric describe Unit(1) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 1 } - its(:scalar) { should be_an Integer } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 1 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # rational describe Unit(Rational(1, 2)) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Rational(1, 2) } - its(:scalar) { should be_a Rational } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Rational(1, 2) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # float describe Unit(0.5) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === 0.5 } - its(:scalar) { should be_a Float } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === 0.5 } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Float } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # complex describe Unit(Complex(1, 1)) do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Complex(1, 1) } - its(:scalar) { should be_a Complex } - its(:units) { should be_empty } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Complex(1, 1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Complex } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_empty } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end describe Unit("1+1i m") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should === Complex(1, 1) } - its(:scalar) { should be_a Complex } - its(:units) { should == "m" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == subject } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be === Complex(1, 1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Complex } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(subject) } + end end # scalar and unit describe Unit("1 mm") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "mm" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("0.001 m") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("0.001 m")) } + end end # with a zero power describe Unit("1 m^0") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("1") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("1")) } + end end # unit only describe Unit("mm") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "mm" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("0.001 m") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("0.001 m")) } + end end # Compound unit describe Unit("1 N*m") do - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "N*m" } - its(:kind) { should == :energy } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("1 kg*m^2/s^2") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("N*m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:energy) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("1 kg*m^2/s^2")) } + end end # scalar and unit with powers describe Unit("10 m/s^2") do - it { should be_an_instance_of Unit } - its(:scalar) { should == 10 } - its(:scalar) { should be_an Integer } - its(:units) { should == "m/s^2" } - its(:kind) { should == :acceleration } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("10 m/s^2") } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(10) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:acceleration) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("10 m/s^2")) } + end end # feet/in form describe Unit("5ft 6in") do - it { should be_an_instance_of Unit } - its(:scalar) { should == 5.5 } - its(:units) { should == "ft" } - its(:kind) { should == :length } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 m")).of Unit("1.6764 m") } - specify { subject.to_s(:ft).should == %{5'6"} } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(5.5) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("ft") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 m")).of Unit("1.6764 m") } + end + specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } end # pound/ounces form describe Unit("6lbs 5oz") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 6.312 } - its(:units) { should == "lbs" } - its(:kind) { should == :mass } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } - specify { subject.to_s(:lbs).should == "6 lbs, 5 oz" } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 6.312 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("lbs") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:mass) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } + end + specify { expect(subject.to_s(:lbs)).to eq("6 lbs, 5 oz") } end # temperature describe Unit("100 tempC") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 100 } - its(:units) { should == "tempC" } - its(:kind) { should == :temperature } - it { should be_temperature } - it { should be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } - its(:temperature_scale) { should == "degC" } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 100 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("tempC") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:temperature) } + end + it { is_expected.to be_temperature } + it { is_expected.to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to eq("degC") } + end end # Time describe Unit(Time.now) do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a(Numeric) } - its(:units) { should == "s" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a(Numeric) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("s") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # degrees describe Unit("100 degC") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_within(0.001).of 100 } - its(:units) { should == "degC" } - its(:kind) { should == :temperature } - it { should_not be_temperature } - it { should be_degree } - it { should_not be_base } - it { should_not be_unitless } - its(:base) { should be_within(Unit("0.01 degK")).of Unit("100 degK") } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_within(0.001).of 100 } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("degC") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:temperature) } + end + it { is_expected.not_to be_temperature } + it { is_expected.to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(Unit("0.01 degK")).of Unit("100 degK") } + end end # percent describe Unit("75%") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "%" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("%") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # angle describe Unit("180 deg") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a Numeric } - its(:units) { should == "deg" } - its(:kind) { should == :angle } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a(Numeric) } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Numeric } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("deg") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:angle) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a(Numeric) } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # radians describe Unit("1 radian") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_a Numeric } - its(:units) { should == "rad" } - its(:kind) { should == :angle } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_a Numeric } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("rad") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:angle) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # counting describe Unit("12 dozen") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "doz" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("doz") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # rational scalar with unit describe Unit("1/2 kg") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Rational } - its(:units) { should == "kg" } - its(:kind) { should == :mass } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:mass) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # rational scalar with compound unit describe Unit("1/2 kg/m") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Rational } - its(:units) { should == "kg/m" } - its(:kind) { should be_nil } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg/m") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to be_nil } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # rational scalar with numeric modified unit @@ -382,178 +832,358 @@ # time string describe Unit("1:23:45,200") do - it { should be_an_instance_of Unit } - it { should == Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec") } - its(:scalar) { should be_an Rational } - its(:units) { should == "h" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + it { is_expected.to eq(Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec")) } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Rational } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("h") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # also '1 hours as minutes' # '1 hour to minutes' describe Unit.parse("1 hour in minutes") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "min" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("min") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # funky unit describe Unit("1 attoparsec/microfortnight") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "apc/ufortnight" } - its(:kind) { should == :speed } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } - it { subject.convert_to("in/s").should be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("apc/ufortnight") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:speed) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end + it { expect(subject.convert_to("in/s")).to be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } end # Farads describe Unit("1 F") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "F" } - its(:kind) { should == :capacitance } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("F") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:capacitance) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end describe Unit("1 m^2 s^-2") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "m^2/s^2" } - its(:kind) { should == :radiation } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m^2/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:radiation) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end describe Unit(1, "m^2", "s^2") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:units) { should == "m^2/s^2" } - its(:kind) { should == :radiation } - it { should_not be_temperature } - it { should_not be_degree } - it { should be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m^2/s^2") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:radiation) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end #scientific notation describe Unit("1e6 cells") do - it { should be_an_instance_of Unit } - its(:scalar) { should be_an Integer } - its(:scalar) { should == 1e6 } - its(:units) { should == "cells" } - its(:kind) { should == :unitless } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1e6) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("cells") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end #could be m*m describe Unit("1 mm") do - its(:kind) { should == :length } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end end #could be centi-day describe Unit("1 cd") do - its(:kind) { should == :luminous_power } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:luminous_power) } + end end # could be milli-inch describe Unit("1 min") do - its(:kind) { should == :time } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end end #could be femto-tons describe Unit("1 ft") do - its(:kind) { should == :length } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end end #could be deci-ounce describe Unit("1 doz") do - its(:kind) { should == :unitless } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:unitless) } + end end # create with another unit describe 10.unit(Unit("1 mm")) do - its(:units) { should == "mm" } - its(:scalar) { should == 10 } + describe '#units' do + subject { super().units } + it { is_expected.to eq("mm") } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(10) } + end end #explicit create describe Unit("1 /") do - its(:kind) { should == :speed } - its(:units) { should == "m/s" } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:speed) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("m/s") } + end end describe Unit("1 /") do - its(:kind) { should == :yank } - its(:units) { should == "kg*m/s^3" } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:yank) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("kg*m/s^3") } + end end # without spaces describe Unit('1g') do - specify { subject.should eq(Unit('1 g')) } + specify { expect(subject).to eq(Unit('1 g')) } end describe Unit('-1g') do - specify { subject.should eq(Unit('-1 g')) } + specify { expect(subject).to eq(Unit('-1 g')) } end describe Unit('11/s') do - specify { subject.should eq(Unit('11 1/s')) } + specify { expect(subject).to eq(Unit('11 1/s')) } end describe Unit.new("63.5029318kg") do - specify { subject.should eq(Unit.new("63.5029318 kg")) } + specify { expect(subject).to eq(Unit.new("63.5029318 kg")) } end # mixed fraction describe Unit.new('6 1/2 cups') do - specify { subject.should eq(Unit.new('13/2 cu')) } + specify { expect(subject).to eq(Unit.new('13/2 cu')) } end # mixed fraction describe Unit.new('-6-1/2 cups') do - specify { subject.should eq(Unit.new('-13/2 cu')) } + specify { expect(subject).to eq(Unit.new('-13/2 cu')) } end describe Unit.new('100 mcg') do @@ -639,30 +1269,34 @@ describe Unit do it "is a subclass of Numeric" do - described_class.should < Numeric + expect(described_class).to be < Numeric end it "is Comparable" do - described_class.should < Comparable + expect(described_class).to be < Comparable end describe "#defined?" do it "should return true when asked about a defined unit" do - Unit.defined?("meter").should be_true + expect(Unit.defined?("meter")).to be_truthy end it "should return true when asked about an alias for a unit" do - Unit.defined?("m").should be_true + expect(Unit.defined?("m")).to be_truthy end it "should return false when asked about a unit that is not defined" do - Unit.defined?("doohickey").should be_false + expect(Unit.defined?("doohickey")).to be_falsey end end describe '#to_yaml' do subject { Unit('1 mm') } - its(:to_yaml) { should =~ /--- !ruby\/object:RubyUnits::Unit/ } + + describe '#to_yaml' do + subject { super().to_yaml } + it { is_expected.to match(/--- !ruby\/object:RubyUnits::Unit/) } + end end describe "#definition" do @@ -672,20 +1306,20 @@ end it "should return a Unit::Definition" do - @definition.should be_instance_of(Unit::Definition) + expect(@definition).to be_instance_of(Unit::Definition) end - specify { @definition.name.should == "" } - specify { @definition.aliases.should == %w{mph} } - specify { @definition.numerator.should == [''] } - specify { @definition.denominator.should == [''] } - specify { @definition.kind.should == :speed } - specify { @definition.scalar.should === 0.44704 } + specify { expect(@definition.name).to eq("") } + specify { expect(@definition.aliases).to eq(%w{mph}) } + specify { expect(@definition.numerator).to eq(['']) } + specify { expect(@definition.denominator).to eq(['']) } + specify { expect(@definition.kind).to eq(:speed) } + specify { expect(@definition.scalar).to be === 0.44704 } end context "The requested unit is not defined" do it "should return nil" do - Unit.definition("doohickey").should be_nil + expect(Unit.definition("doohickey")).to be_nil end end end @@ -709,22 +1343,42 @@ # do this because the unit is not defined at the time this file is parsed, so it fails subject { Unit("1e6 jiffy") } - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1e6 } - its(:scalar) { should be_an Integer } - its(:units) { should == "jif" } - its(:kind) { should == :time } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should == Unit("10000 s") } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1e6) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("jif") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:time) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to eq(Unit("10000 s")) } + end end it "should register the new unit" do - Unit.defined?('jiffy').should be_true + expect(Unit.defined?('jiffy')).to be_truthy end end @@ -746,17 +1400,33 @@ # do this because the unit is going to be redefined subject { Unit("1 cup") } - it { should be_a Numeric } - it { should be_an_instance_of Unit } - its(:scalar) { should == 1 } - its(:scalar) { should be_an Integer } - its(:units) { should == "cupz" } - its(:kind) { should == :volume } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } + it { is_expected.to be_a Numeric } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(1) } + end + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Integer } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq("cupz") } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:volume) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } end end @@ -781,7 +1451,7 @@ Unit.undefine!("jiffy") end - specify { Unit('1 jiffy').to_base.scalar.should == (1/1000) } + specify { expect(Unit('1 jiffy').to_base.scalar).to eq(1/1000) } end describe '#undefine!' do @@ -796,7 +1466,7 @@ end specify "the unit should be undefined" do - Unit.defined?('jiffy').should be_false + expect(Unit.defined?('jiffy')).to be_falsey end specify "attempting to use an undefined unit fails" do @@ -804,96 +1474,100 @@ end it "should return true when undefining an unknown unit" do - Unit.defined?("unknown").should be_false - Unit.undefine!("unknown").should be_true + expect(Unit.defined?("unknown")).to be_falsey + expect(Unit.undefine!("unknown")).to be_truthy end end describe '#clone' do subject { Unit('1 mm') } - its(:clone) { should === subject } + + describe '#clone' do + subject { super().clone } + it { is_expected.to be === subject } + end end end describe "Unit Comparisons" do context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do - specify { Unit("1 ft").should =~ Unit('1 m') } - specify { Unit("1 ft").should =~ "m" } - specify { Unit("1 ft").should be_compatible_with Unit('1 m') } - specify { Unit("1 ft").should be_compatible_with "m" } - specify { Unit("1 m").should be_compatible_with Unit('1 kg*m/kg') } - specify { Unit("1 ft").should_not =~ Unit('1 kg') } - specify { Unit("1 ft").should_not be_compatible_with Unit('1 kg') } - specify { Unit("1 ft").should_not be_compatible_with nil } + specify { expect(Unit("1 ft") =~ Unit('1 m')).to be true } + specify { expect(Unit("1 ft") =~ "m").to be true } + specify { expect(Unit("1 ft")).to be_compatible_with Unit('1 m') } + specify { expect(Unit("1 ft")).to be_compatible_with "m" } + specify { expect(Unit("1 m")).to be_compatible_with Unit('1 kg*m/kg') } + specify { expect(Unit("1 ft") =~ Unit('1 kg')).to be false } + specify { expect(Unit("1 ft")).not_to be_compatible_with Unit('1 kg') } + specify { expect(Unit("1 ft")).not_to be_compatible_with nil } end context "Equality" do context "with uncoercable objects" do - specify { Unit("1 mm").should_not == nil } + specify { expect(Unit("1 mm")).not_to eq(nil) } end context "units of same kind" do - specify { Unit("1000 m").should == Unit('1 km') } - specify { Unit("100 m").should_not == Unit('1 km') } - specify { Unit("1 m").should == Unit('100 cm') } + specify { expect(Unit("1000 m")).to eq(Unit('1 km')) } + specify { expect(Unit("100 m")).not_to eq(Unit('1 km')) } + specify { expect(Unit("1 m")).to eq(Unit('100 cm')) } end context "units of incompatible types" do - specify { Unit("1 m").should_not == Unit("1 kg") } + specify { expect(Unit("1 m")).not_to eq(Unit("1 kg")) } end context "units with a zero scalar are equal" do - specify { Unit("0 m").should == Unit("0 s") } - specify { Unit("0 m").should == Unit("0 kg") } + specify { expect(Unit("0 m")).to eq(Unit("0 s")) } + specify { expect(Unit("0 m")).to eq(Unit("0 kg")) } context "except for temperature units" do - specify { Unit("0 tempK").should == Unit("0 m") } - specify { Unit("0 tempR").should == Unit("0 m") } - specify { Unit("0 tempC").should_not == Unit("0 m") } - specify { Unit("0 tempF").should_not == Unit("0 m") } + specify { expect(Unit("0 tempK")).to eq(Unit("0 m")) } + specify { expect(Unit("0 tempR")).to eq(Unit("0 m")) } + specify { expect(Unit("0 tempC")).not_to eq(Unit("0 m")) } + specify { expect(Unit("0 tempF")).not_to eq(Unit("0 m")) } end end end context "Equivalence" do context "units and scalars are the exactly the same" do - specify { Unit("1 m").should === Unit("1 m") } - specify { Unit("1 m").should be_same Unit("1 m") } - specify { Unit("1 m").should be_same_as Unit("1 m") } + specify { expect(Unit("1 m")).to be === Unit("1 m") } + specify { expect(Unit("1 m")).to be_same Unit("1 m") } + specify { expect(Unit("1 m")).to be_same_as Unit("1 m") } end context "units are compatible but not identical" do - specify { Unit("1000 m").should_not === Unit("1 km") } - specify { Unit("1000 m").should_not be_same Unit("1 km") } - specify { Unit("1000 m").should_not be_same_as Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be === Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be_same Unit("1 km") } + specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 km") } end context "units are not compatible" do - specify { Unit("1000 m").should_not === Unit("1 hour") } - specify { Unit("1000 m").should_not be_same Unit("1 hour") } - specify { Unit("1000 m").should_not be_same_as Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be === Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be_same Unit("1 hour") } + specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 hour") } end context "scalars are different" do - specify { Unit("1 m").should_not === Unit("2 m") } - specify { Unit("1 m").should_not be_same Unit("2 m") } - specify { Unit("1 m").should_not be_same_as Unit("2 m") } + specify { expect(Unit("1 m")).not_to be === Unit("2 m") } + specify { expect(Unit("1 m")).not_to be_same Unit("2 m") } + specify { expect(Unit("1 m")).not_to be_same_as Unit("2 m") } end - specify { Unit("1 m").should_not === nil } + specify { expect(Unit("1 m")).not_to be === nil } end context "Comparisons" do context "compatible units can be compared" do - specify { Unit("1 m").should < Unit("2 m") } - specify { Unit("2 m").should > Unit("1 m") } - specify { Unit("1 m").should < Unit("1 mi") } - specify { Unit("2 m").should > Unit("1 ft") } - specify { Unit("70 tempF").should > Unit("10 degC") } - specify { Unit("1 m").should > 0 } - specify { expect { Unit("1 m").should_not > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + specify { expect(Unit("1 m")).to be < Unit("2 m") } + specify { expect(Unit("2 m")).to be > Unit("1 m") } + specify { expect(Unit("1 m")).to be < Unit("1 mi") } + specify { expect(Unit("2 m")).to be > Unit("1 ft") } + specify { expect(Unit("70 tempF")).to be > Unit("10 degC") } + specify { expect(Unit("1 m")).to be > 0 } + specify { expect { expect(Unit("1 m")).not_to be > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do @@ -912,11 +1586,11 @@ describe "Unit Conversions" do context "between compatible units" do - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } - specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns") } - specify { (Unit("1 s") >> "ns").should == Unit("1e9 ns") } + specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } + specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } + specify { expect(Unit("1 s") >> "ns").to eq(Unit("1e9 ns")) } - specify { Unit("1 m").convert_to(Unit("ft")).should be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } + specify { expect(Unit("1 m").convert_to(Unit("ft"))).to be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } end context "between incompatible units" do @@ -932,34 +1606,34 @@ # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - specify { Unit("100 tempC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("0 tempC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("37 tempC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("-273.15 tempC").should == Unit("0 tempK") } + specify { expect(Unit("100 tempC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("0 tempC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("37 tempC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("-273.15 tempC")).to eq(Unit("0 tempK")) } - specify { Unit("212 tempF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("32 tempF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("98.6 tempF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("-459.67 tempF").should == Unit("0 tempK") } + specify { expect(Unit("212 tempF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("32 tempF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("98.6 tempF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("-459.67 tempF")).to eq(Unit("0 tempK")) } - specify { Unit("671.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { Unit("491.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { Unit("558.27 tempR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { Unit("0 tempR").should == Unit("0 tempK") } + specify { expect(Unit("671.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } + specify { expect(Unit("491.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } + specify { expect(Unit("558.27 tempR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } + specify { expect(Unit("0 tempR")).to eq(Unit("0 tempK")) } - specify { Unit("100 tempK").convert_to("tempC").should be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } - specify { Unit("100 tempK").convert_to("tempF").should be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } - specify { Unit("100 tempK").convert_to("tempR").should be_within(U "0.01 degR").of(Unit("180 tempR")) } + specify { expect(Unit("100 tempK").convert_to("tempC")).to be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } + specify { expect(Unit("100 tempK").convert_to("tempF")).to be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } + specify { expect(Unit("100 tempK").convert_to("tempR")).to be_within(U "0.01 degR").of(Unit("180 tempR")) } - specify { Unit("1 degC").should == Unit("1 degK") } - specify { Unit("1 degF").should == Unit("1 degR") } - specify { Unit("1 degC").should == Unit("1.8 degR") } - specify { Unit("1 degF").should be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } + specify { expect(Unit("1 degC")).to eq(Unit("1 degK")) } + specify { expect(Unit("1 degF")).to eq(Unit("1 degR")) } + specify { expect(Unit("1 degC")).to eq(Unit("1.8 degR")) } + specify { expect(Unit("1 degF")).to be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } end context "reported bugs" do - specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).should == Unit("224721 tonne") } - specify { (Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne").should == Unit("224721 tonne") } + specify { expect(Unit("189 Mtonne") * Unit("1189 g/tonne")).to eq(Unit("224721 tonne")) } + specify { expect((Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne")).to eq(Unit("224721 tonne")) } end describe "Foot-inch conversions" do @@ -973,8 +1647,8 @@ ["88 in", %Q{7'4"}], ["89 in", %Q{7'5"}] ].each do |inches, feet| - specify { Unit(inches).convert_to("ft").should == Unit(feet) } - specify { Unit(inches).to_s(:ft).should == feet } + specify { expect(Unit(inches).convert_to("ft")).to eq(Unit(feet)) } + specify { expect(Unit(inches).to_s(:ft)).to eq(feet) } end end @@ -989,8 +1663,8 @@ ["88 oz", "5 lbs, 8 oz"], ["89 oz", "5 lbs, 9 oz"] ].each do |ounces, pounds| - specify { Unit(ounces).convert_to("lbs").should == Unit(pounds) } - specify { Unit(ounces).to_s(:lbs).should == pounds } + specify { expect(Unit(ounces).convert_to("lbs")).to eq(Unit(pounds)) } + specify { expect(Unit(ounces).to_s(:lbs)).to eq(pounds) } end end end @@ -999,13 +1673,13 @@ context "operators:" do context "addition (+)" do context "between compatible units" do - specify { (Unit("0 m") + Unit("10 m")).should == Unit("10 m") } - specify { (Unit("5 kg") + Unit("10 kg")).should == Unit("15 kg") } + specify { expect(Unit("0 m") + Unit("10 m")).to eq(Unit("10 m")) } + specify { expect(Unit("5 kg") + Unit("10 kg")).to eq(Unit("15 kg")) } end context "between a zero unit and another unit" do - specify { (Unit("0 kg") + Unit("10 m")).should == Unit("10 m") } - specify { (Unit("0 m") + Unit("10 kg")).should == Unit("10 kg") } + specify { expect(Unit("0 kg") + Unit("10 m")).to eq(Unit("10 m")) } + specify { expect(Unit("0 m") + Unit("10 kg")).to eq(Unit("10 kg")) } end context "between incompatible units" do @@ -1020,8 +1694,8 @@ end context "between a unit and coerceable types" do - specify { (Unit('10 kg') + %w{1 kg}).should == Unit('11 kg') } - specify { (Unit('10 kg') + "1 kg").should == Unit('11 kg') } + specify { expect(Unit('10 kg') + %w{1 kg}).to eq(Unit('11 kg')) } + specify { expect(Unit('10 kg') + "1 kg").to eq(Unit('11 kg')) } end context "between two temperatures" do @@ -1029,24 +1703,24 @@ end context "between a temperature and a degree" do - specify { (Unit("100 tempK") + Unit("100 degK")).should == Unit("200 tempK") } + specify { expect(Unit("100 tempK") + Unit("100 degK")).to eq(Unit("200 tempK")) } end context "between a degree and a temperature" do - specify { (Unit("100 degK") + Unit("100 tempK")).should == Unit("200 tempK") } + specify { expect(Unit("100 degK") + Unit("100 tempK")).to eq(Unit("200 tempK")) } end end context "subtracting (-)" do context "compatible units" do - specify { (Unit("0 m") - Unit("10 m")).should == Unit("-10 m") } - specify { (Unit("5 kg") - Unit("10 kg")).should == Unit("-5 kg") } + specify { expect(Unit("0 m") - Unit("10 m")).to eq(Unit("-10 m")) } + specify { expect(Unit("5 kg") - Unit("10 kg")).to eq(Unit("-5 kg")) } end context "a unit from a zero unit" do - specify { (Unit("0 kg") - Unit("10 m")).should == Unit("-10 m") } - specify { (Unit("0 m") - Unit("10 kg")).should == Unit("-10 kg") } + specify { expect(Unit("0 kg") - Unit("10 m")).to eq(Unit("-10 m")) } + specify { expect(Unit("0 m") - Unit("10 kg")).to eq(Unit("-10 kg")) } end context "incompatible units" do @@ -1056,8 +1730,8 @@ end context "between a unit and coerceable types" do - specify { (Unit('10 kg') - %w{1 kg}).should == Unit('9 kg') } - specify { (Unit('10 kg') - "1 kg").should == Unit('9 kg') } + specify { expect(Unit('10 kg') - %w{1 kg}).to eq(Unit('9 kg')) } + specify { expect(Unit('10 kg') - "1 kg").to eq(Unit('9 kg')) } end context "a number from a unit" do @@ -1066,11 +1740,11 @@ end context "between two temperatures" do - specify { (Unit("100 tempK") - Unit("100 tempK")).should == Unit("0 degK") } + specify { expect(Unit("100 tempK") - Unit("100 tempK")).to eq(Unit("0 degK")) } end context "between a temperature and a degree" do - specify { (Unit("100 tempK") - Unit("100 degK")).should == Unit("0 tempK") } + specify { expect(Unit("100 tempK") - Unit("100 degK")).to eq(Unit("0 tempK")) } end context "between a degree and a temperature" do @@ -1081,19 +1755,19 @@ context "multiplying (*)" do context "between compatible units" do - specify { (Unit("0 m") * Unit("10 m")).should == Unit("0 m^2") } - specify { (Unit("5 kg") * Unit("10 kg")).should == Unit("50 kg^2") } + specify { expect(Unit("0 m") * Unit("10 m")).to eq(Unit("0 m^2")) } + specify { expect(Unit("5 kg") * Unit("10 kg")).to eq(Unit("50 kg^2")) } end context "between incompatible units" do - specify { (Unit("0 m") * Unit("10 kg")).should == Unit("0 kg*m") } - specify { (Unit("5 m") * Unit("10 kg")).should == Unit("50 kg*m") } + specify { expect(Unit("0 m") * Unit("10 kg")).to eq(Unit("0 kg*m")) } + specify { expect(Unit("5 m") * Unit("10 kg")).to eq(Unit("50 kg*m")) } specify { expect { Unit("10 m") * nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { (Unit('10 kg') * %w{1 kg}).should == Unit('10 kg^2') } - specify { (Unit('10 kg') * "1 kg").should == Unit('10 kg^2') } + specify { expect(Unit('10 kg') * %w{1 kg}).to eq(Unit('10 kg^2')) } + specify { expect(Unit('10 kg') * "1 kg").to eq(Unit('10 kg^2')) } end context "by a temperature" do @@ -1101,27 +1775,27 @@ end context "by a number" do - specify { (10 * Unit("5 kg")).should == Unit("50 kg") } + specify { expect(10 * Unit("5 kg")).to eq(Unit("50 kg")) } end end context "dividing (/)" do context "compatible units" do - specify { (Unit("0 m") / Unit("10 m")).should == Unit(0) } - specify { (Unit("5 kg") / Unit("10 kg")).should == Rational(1, 2) } - specify { (Unit("5 kg") / Unit("5 kg")).should == 1 } + specify { expect(Unit("0 m") / Unit("10 m")).to eq(Unit(0)) } + specify { expect(Unit("5 kg") / Unit("10 kg")).to eq(Rational(1, 2)) } + specify { expect(Unit("5 kg") / Unit("5 kg")).to eq(1) } end context "incompatible units" do - specify { (Unit("0 m") / Unit("10 kg")).should == Unit("0 m/kg") } - specify { (Unit("5 m") / Unit("10 kg")).should == Unit("1/2 m/kg") } + specify { expect(Unit("0 m") / Unit("10 kg")).to eq(Unit("0 m/kg")) } + specify { expect(Unit("5 m") / Unit("10 kg")).to eq(Unit("1/2 m/kg")) } specify { expect { Unit("10 m") / nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { (Unit('10 kg^2') / %w{1 kg}).should == Unit('10 kg') } - specify { (Unit('10 kg^2') / "1 kg").should == Unit('10 kg') } + specify { expect(Unit('10 kg^2') / %w{1 kg}).to eq(Unit('10 kg')) } + specify { expect(Unit('10 kg^2') / "1 kg").to eq(Unit('10 kg')) } end context "by a temperature" do @@ -1129,11 +1803,11 @@ end context "a number by a unit" do - specify { (10 / Unit("5 kg")).should == Unit("2 1/kg") } + specify { expect(10 / Unit("5 kg")).to eq(Unit("2 1/kg")) } end context "a unit by a number" do - specify { (Unit("5 kg") / 2).should == Unit("2.5 kg") } + specify { expect(Unit("5 kg") / 2).to eq(Unit("2.5 kg")) } end context "by zero" do @@ -1150,16 +1824,16 @@ end context Unit("0 m") do - it { (subject**1).should == subject } - it { (subject**2).should == subject } + it { expect(subject**1).to eq(subject) } + it { expect(subject**2).to eq(subject) } end context Unit("1 m") do - it { (subject**0).should == 1 } - it { (subject**1).should == subject } - it { (subject**(-1)).should == 1/subject } - it { (subject**(2)).should == Unit("1 m^2") } - it { (subject**(-2)).should == Unit("1 1/m^2") } + it { expect(subject**0).to eq(1) } + it { expect(subject**1).to eq(subject) } + it { expect(subject**(-1)).to eq(1/subject) } + it { expect(subject**(2)).to eq(Unit("1 m^2")) } + it { expect(subject**(-2)).to eq(Unit("1 1/m^2")) } specify { expect { subject**(1/2) }.to raise_error(ArgumentError, "Illegal root") } # because 1 m^(1/2) doesn't make any sense specify { expect { subject**(Complex(1, 1)) }.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.") } @@ -1167,8 +1841,8 @@ end context Unit("1 m^2") do - it { (subject**(Rational(1, 2))).should == Unit("1 m") } - it { (subject**(0.5)).should == Unit("1 m") } + it { expect(subject**(Rational(1, 2))).to eq(Unit("1 m")) } + it { expect(subject**(0.5)).to eq(Unit("1 m")) } specify { expect { subject**(0.12345) }.to raise_error(ArgumentError, "Not a n-th root (1..9), use 1/n") } specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError, "Invalid Exponent") } @@ -1178,8 +1852,8 @@ context "modulo (%)" do context "compatible units" do - specify { (Unit("2 m") % Unit("1 m")).should == 0 } - specify { (Unit("5 m") % Unit("2 m")).should == 1 } + specify { expect(Unit("2 m") % Unit("1 m")).to eq(0) } + specify { expect(Unit("5 m") % Unit("2 m")).to eq(1) } end specify "incompatible units raises an exception" do @@ -1188,11 +1862,11 @@ end context "unary negation (-)" do - specify { (-Unit("1 mm")).should == Unit("-1 mm") } + specify { expect(-Unit("1 mm")).to eq(Unit("-1 mm")) } end context "unary plus (+)" do - specify { (+Unit('1 mm')).should == Unit('1 mm') } + specify { expect(+Unit('1 mm')).to eq(Unit('1 mm')) } end end @@ -1211,10 +1885,10 @@ expect { Unit("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - specify { (subject.power(-1)).should == Unit("1 1/m") } - specify { (subject.power(0)).should == 1 } - specify { (subject.power(1)).should == subject } - specify { (subject.power(2)).should == Unit("1 m^2") } + specify { expect(subject.power(-1)).to eq(Unit("1 1/m")) } + specify { expect(subject.power(0)).to eq(1) } + specify { expect(subject.power(1)).to eq(subject) } + specify { expect(subject.power(2)).to eq(Unit("1 m^2")) } end @@ -1233,30 +1907,30 @@ expect { Unit("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") end - specify { (Unit("1 m^2").root(-2)).should == Unit("1 1/m") } - specify { (subject.root(-1)).should == Unit("1 1/m") } + specify { expect(Unit("1 m^2").root(-2)).to eq(Unit("1 1/m")) } + specify { expect(subject.root(-1)).to eq(Unit("1 1/m")) } specify { expect { (subject.root(0)) }.to raise_error(ArgumentError, "0th root undefined") } - specify { (subject.root(1)).should == subject } - specify { (Unit("1 m^2").root(2)).should == Unit("1 m") } + specify { expect(subject.root(1)).to eq(subject) } + specify { expect(Unit("1 m^2").root(2)).to eq(Unit("1 m")) } end context "#inverse" do - specify { Unit("1 m").inverse.should == Unit("1 1/m") } + specify { expect(Unit("1 m").inverse).to eq(Unit("1 1/m")) } specify { expect { Unit("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } end context "convert to scalars" do - specify { Unit("10").to_i.should be_kind_of(Integer) } + specify { expect(Unit("10").to_i).to be_kind_of(Integer) } specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } - specify { Unit("10.0").to_f.should be_kind_of(Float) } + specify { expect(Unit("10.0").to_f).to be_kind_of(Float) } specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } - specify { Unit("1+1i").to_c.should be_kind_of(Complex) } + specify { expect(Unit("1+1i").to_c).to be_kind_of(Complex) } specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } - specify { Unit("3/7").to_r.should be_kind_of(Rational) } + specify { expect(Unit("3/7").to_r).to be_kind_of(Rational) } specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } end @@ -1264,13 +1938,13 @@ context "absolute value (#abs)" do context "of a unitless unit" do specify "returns the absolute value of the scalar" do - Unit("-10").abs.should == 10 + expect(Unit("-10").abs).to eq(10) end end context "of a unit" do specify "returns a unit with the absolute value of the scalar" do - Unit("-10 m").abs.should == Unit("10 m") + expect(Unit("-10 m").abs).to eq(Unit("10 m")) end end end @@ -1278,13 +1952,13 @@ context "#ceil" do context "of a unitless unit" do specify "returns the ceil of the scalar" do - Unit("10.1").ceil.should == 11 + expect(Unit("10.1").ceil).to eq(11) end end context "of a unit" do specify "returns a unit with the ceil of the scalar" do - Unit("10.1 m").ceil.should == Unit("11 m") + expect(Unit("10.1 m").ceil).to eq(Unit("11 m")) end end end @@ -1292,13 +1966,13 @@ context "#floor" do context "of a unitless unit" do specify "returns the floor of the scalar" do - Unit("10.1").floor.should == 10 + expect(Unit("10.1").floor).to eq(10) end end context "of a unit" do specify "returns a unit with the floor of the scalar" do - Unit("10.1 m").floor.should == Unit("10 m") + expect(Unit("10.1 m").floor).to eq(Unit("10 m")) end end end @@ -1306,13 +1980,13 @@ context "#round" do context "of a unitless unit" do specify "returns the round of the scalar" do - Unit("10.5").round.should == 11 + expect(Unit("10.5").round).to eq(11) end end context "of a unit" do specify "returns a unit with the round of the scalar" do - Unit("10.5 m").round.should == Unit("11 m") + expect(Unit("10.5 m").round).to eq(Unit("11 m")) end end end @@ -1320,109 +1994,109 @@ context "#truncate" do context "of a unitless unit" do specify "returns the truncate of the scalar" do - Unit("10.5").truncate.should == 10 + expect(Unit("10.5").truncate).to eq(10) end end context "of a unit" do specify "returns a unit with the truncate of the scalar" do - Unit("10.5 m").truncate.should == Unit("10 m") + expect(Unit("10.5 m").truncate).to eq(Unit("10 m")) end end context "of a complex unit" do specify "returns a unit with the truncate of the scalar" do - Unit("10.5 kg*m/s^3").truncate.should == Unit("10 kg*m/s^3") + expect(Unit("10.5 kg*m/s^3").truncate).to eq(Unit("10 kg*m/s^3")) end end end context '#zero?' do it "is true when the scalar is zero on the base scale" do - Unit("0").should be_zero - Unit("0 mm").should be_zero - Unit("-273.15 tempC").should be_zero + expect(Unit("0")).to be_zero + expect(Unit("0 mm")).to be_zero + expect(Unit("-273.15 tempC")).to be_zero end it "is false when the scalar is not zero" do - Unit("1").should_not be_zero - Unit("1 mm").should_not be_zero - Unit("0 tempC").should_not be_zero + expect(Unit("1")).not_to be_zero + expect(Unit("1 mm")).not_to be_zero + expect(Unit("0 tempC")).not_to be_zero end end context '#succ' do - specify { Unit("1").succ.should == Unit("2") } - specify { Unit("1 mm").succ.should == Unit("2 mm") } - specify { Unit("1 mm").next.should == Unit("2 mm") } - specify { Unit("-1 mm").succ.should == Unit("0 mm") } + specify { expect(Unit("1").succ).to eq(Unit("2")) } + specify { expect(Unit("1 mm").succ).to eq(Unit("2 mm")) } + specify { expect(Unit("1 mm").next).to eq(Unit("2 mm")) } + specify { expect(Unit("-1 mm").succ).to eq(Unit("0 mm")) } specify { expect { Unit("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } end context '#pred' do - specify { Unit("1").pred.should == Unit("0") } - specify { Unit("1 mm").pred.should == Unit("0 mm") } - specify { Unit("-1 mm").pred.should == Unit("-2 mm") } + specify { expect(Unit("1").pred).to eq(Unit("0")) } + specify { expect(Unit("1 mm").pred).to eq(Unit("0 mm")) } + specify { expect(Unit("-1 mm").pred).to eq(Unit("-2 mm")) } specify { expect { Unit("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } end 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 { expect(Unit("5 mm").divmod(Unit("2 mm"))).to eq([2, 1]) } + specify { expect(Unit("1 km").divmod(Unit("2 m"))).to eq([500, 0]) } specify { expect { Unit('1 m').divmod(Unit('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end context '#div' do - specify { Unit('23 m').div(Unit('2 m')).should == 11 } + specify { expect(Unit('23 m').div(Unit('2 m'))).to eq(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') } + specify { expect(Unit('1024 KiB').best_prefix).to eq(Unit('1 MiB')) } + specify { expect(Unit('1000 m').best_prefix).to eq(Unit('1 km')) } specify { expect { Unit('0 m').best_prefix }.to_not raise_error } end context "Time helper functions" do before do - Time.stub(:now).and_return(Time.utc(2011, 10, 16)) - DateTime.stub(:now).and_return(DateTime.civil(2011, 10, 16)) - Date.stub(:today).and_return(Date.civil(2011, 10, 16)) + allow(Time).to receive(:now).and_return(Time.utc(2011, 10, 16)) + allow(DateTime).to receive(:now).and_return(DateTime.civil(2011, 10, 16)) + allow(Date).to receive(:today).and_return(Date.civil(2011, 10, 16)) end context '#since' do - specify { Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } - specify { Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0)).should == Unit("5544000 min") } - specify { Unit("min").since(Date.civil(2001, 4, 1)).should == Unit("5544000 min") } + specify { expect(Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } + specify { expect(Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } + specify { expect(Unit("min").since(Date.civil(2001, 4, 1))).to eq(Unit("5544000 min")) } specify { expect { Unit("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#before' do - specify { Unit("5 min").before(Time.now).should == Time.utc(2011, 10, 15, 23, 55) } - specify { Unit("5 min").before(DateTime.now).should == DateTime.civil(2011, 10, 15, 23, 55) } - specify { Unit("5 min").before(Date.today).should == DateTime.civil(2011, 10, 15, 23, 55) } + specify { expect(Unit("5 min").before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } + specify { expect(Unit("5 min").before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect(Unit("5 min").before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } specify { expect { Unit('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#ago' do - specify { Unit("5 min").ago.should be_kind_of Time } - specify { Unit("10000 y").ago.should be_kind_of Time } - specify { Unit("1 year").ago.should == Time.utc(2010, 10, 16) } + specify { expect(Unit("5 min").ago).to be_kind_of Time } + specify { expect(Unit("10000 y").ago).to be_kind_of Time } + specify { expect(Unit("1 year").ago).to eq(Time.utc(2010, 10, 16)) } end context '#until' do - specify { Unit("min").until(Date.civil(2011, 10, 17)).should == Unit("1440 min") } - specify { Unit("min").until(DateTime.civil(2011, 10, 21)).should == Unit("7200 min") } - specify { Unit("min").until(Time.utc(2011, 10, 21)).should == Unit("7200 min") } + specify { expect(Unit("min").until(Date.civil(2011, 10, 17))).to eq(Unit("1440 min")) } + specify { expect(Unit("min").until(DateTime.civil(2011, 10, 21))).to eq(Unit("7200 min")) } + specify { expect(Unit("min").until(Time.utc(2011, 10, 21))).to eq(Unit("7200 min")) } specify { expect { Unit('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#from' do - specify { Unit("1 day").from(Date.civil(2011, 10, 17)).should == Date.civil(2011, 10, 18) } - specify { Unit("5 min").from(DateTime.civil(2011, 10, 21)).should == DateTime.civil(2011, 10, 21, 00, 05) } - specify { Unit("5 min").from(Time.utc(2011, 10, 21)).should == Time.utc(2011, 10, 21, 00, 05) } + specify { expect(Unit("1 day").from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } + specify { expect(Unit("5 min").from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 00, 05)) } + specify { expect(Unit("5 min").from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 00, 05)) } specify { expect { Unit('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } specify { expect { Unit('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end @@ -1433,11 +2107,11 @@ describe "Unit Output formatting" do context Unit("10.5 m/s^2") do - specify { subject.to_s.should == "10.5 m/s^2" } - specify { subject.to_s("%0.2f").should == "10.50 m/s^2" } - specify { subject.to_s("%0.2e km/s^2").should == "1.05e-02 km/s^2" } - specify { subject.to_s("km/s^2").should == "0.0105 km/s^2" } - specify { subject.to_s(STDOUT).should == "10.5 m/s^2" } + specify { expect(subject.to_s).to eq("10.5 m/s^2") } + specify { expect(subject.to_s("%0.2f")).to eq("10.50 m/s^2") } + specify { expect(subject.to_s("%0.2e km/s^2")).to eq("1.05e-02 km/s^2") } + specify { expect(subject.to_s("km/s^2")).to eq("0.0105 km/s^2") } + specify { expect(subject.to_s(STDOUT)).to eq("10.5 m/s^2") } specify { expect { subject.to_s("random string") }.to raise_error(ArgumentError, "'random' Unit not recognized") } end @@ -1456,7 +2130,7 @@ subject { Unit("8 cups") } - specify { subject.to_s.should == "8 cupz" } + specify { expect(subject.to_s).to eq("8 cupz") } end @@ -1468,6 +2142,6 @@ let(:v) { Unit('1 m^3') } let(:n) { Unit("1 mole") } let(:r) { Unit("8.31451 J/mol*degK") } - specify { ((p*v)/(n*r)).convert_to('tempK').should be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } + specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } end end diff --git a/spec/ruby-units/utf-8/unit_spec.rb b/spec/ruby-units/utf-8/unit_spec.rb index 045fafed..eb9cf654 100644 --- a/spec/ruby-units/utf-8/unit_spec.rb +++ b/spec/ruby-units/utf-8/unit_spec.rb @@ -7,17 +7,17 @@ context 'when the UTF-8 symbol is used' do context 'Angles' do it 'should be a degree' do - Unit("180\u00B0").units.should == 'deg' + expect(Unit("180\u00B0").units).to eq('deg') end end context 'Temperature' do it 'should be a degree Celcius' do - Unit("180\u00B0C").units.should == 'degC' + expect(Unit("180\u00B0C").units).to eq('degC') end it 'should be a degree Fahrenheit' do - Unit("180\u00B0F").units.should == 'degF' + expect(Unit("180\u00B0F").units).to eq('degF') end end end From 6f70dc6d848b0278a7af0f7b651a04569aff68ef Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:10:26 -0400 Subject: [PATCH 060/150] remove rspec restriction --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index fb868299..90155cc9 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ group :test do gem 'rcov', :platforms => :mri_18 gem 'simplecov', :require => false, :platforms => :mri_19 gem 'simplecov-html', :platforms => :mri_19 - gem 'rspec', '~>2.5' + gem 'rspec' gem 'guard-rspec' end From b38309466861119af9155d7ba25ba31747909c0b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:08 -0400 Subject: [PATCH 061/150] remove autotest --- .autotest | 41 ----------------------------------------- autotest/discover.rb | 1 - 2 files changed, 42 deletions(-) delete mode 100644 .autotest delete mode 100644 autotest/discover.rb diff --git a/.autotest b/.autotest deleted file mode 100644 index b32fba98..00000000 --- a/.autotest +++ /dev/null @@ -1,41 +0,0 @@ -# -*- ruby -*- - -require 'autotest/growl' -require 'autotest/fsevent' -require 'autotest/bundler' - -module AutoGrowl - def self.growl title, msg, pri=0 - system "growlnotify -n autotest --image /Applications/Mail.app/Contents/Resources/Caution.tiff -p #{pri} -m #{msg.inspect} #{title}" - end - - Autotest.add_hook :run do |at| - growl "Run", "Run" unless $TESTING - end - - Autotest.add_hook :red do |at| - growl "Tests Failed", "#{at.files_to_test.size} tests failed", 2 - end - - Autotest.add_hook :green do |at| - growl "Tests Passed", "All tests passed", -2 if at.tainted - end - - Autotest.add_hook :init do |at| - growl "autotest", "autotest was started" unless $TESTING - end - - Autotest.add_hook :interrupt do |at| - growl "autotest", "autotest was reset" unless $TESTING - nil - end - - Autotest.add_hook :quit do |at| - growl "autotest", "autotest is exiting" unless $TESTING - end - - Autotest.add_hook :all do |at|_hook - growl "autotest", "Tests have fully passed", -2 unless $TESTING - end -end - diff --git a/autotest/discover.rb b/autotest/discover.rb deleted file mode 100644 index 24dd9b7b..00000000 --- a/autotest/discover.rb +++ /dev/null @@ -1 +0,0 @@ -Autotest.add_discovery { "rspec2" } \ No newline at end of file From 8343c28ccb987875acb079d042c7bbbd58807897 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:45 -0400 Subject: [PATCH 062/150] changelog & whitespace in rakefile --- CHANGELOG.txt | 75 ++++++++++++++++++++++++++------------------------- Rakefile.rb | 2 +- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d6d79f21..4caf0a6e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,7 @@ Change Log for Ruby-units ========================= -2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit +2015-05-09 * update test harness to use rspec 3 +2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit 2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method * Fix issue #60 -- Consider placing Unit in a module * Fix issue #75 -- Siemens is kind of conductance not resistance @@ -25,7 +26,7 @@ Change Log for Ruby-units 2012-01-02 1.4.0 * Fix some definitions that were just wrong (amu, dalton) * Definition uses name of unit if no aliases provided * Refactor definition process. New units are immediately available -2011-12-31 * Define standard units in terms of base and other standard units -- more internally consistent +2011-12-31 * Define standard units in terms of base and other standard units -- more internally consistent and less prone to round-off errors. * add 'poundal' * remove 'wtpercent' @@ -33,7 +34,7 @@ Change Log for Ruby-units * Define compound units with base units for consistency * distinguish between a league and a nautical league * NOTE: the new unit definition DSL is not backwardly compatible with the old method - (which is now deprecated). + (which is now deprecated). * Fix issue #27 2011-12-18 * Can define a display_name for units (fixes #26) 2011-12-04 * Documentation improvements @@ -61,17 +62,17 @@ Change Log for Ruby-units 2007-12-13 1.1.3 * fixed a minor bug with string % 2007-12-12 1.1.2 * fixed a bug with format strings * detect if ruby 1.8.6 is installed and use its' to_date function - + 2007-07-14 1.1.1 * fixed bug that would prevent creating '' units, which prevented rounding from working * tests do not fail if Uncertain gem is not installed, you just get an annoying warning message - + 2007-01-28 1.1.0 * completely revamped the temperature handling system (see README) * fixed some spelling errors in some units * fixed to_datetime and to_date to convert durations to datetimes and dates' -2007-01-24 1.0.2 * Minor changes in the way powers are calculated to support Uncertain +2007-01-24 1.0.2 * Minor changes in the way powers are calculated to support Uncertain numbers better. * Fixed parsing bug with Uncertain Numbers * added resolution / typography units (pixels, points, pica) @@ -87,17 +88,17 @@ Change Log for Ruby-units '1+1i mm'.unit to get a complex unit. * Taking the root of a negative unit will give you a complex unit * fixed unary minus to work again - * Math.hypot now takes units. Both parameters must be the compatible - units or it will assert. Units will be converted to a common base + * Math.hypot now takes units. Both parameters must be the compatible + units or it will assert. Units will be converted to a common base before use. - * Can now specify units in rational numbers, i.e., '1/4 cup'.unit + * Can now specify units in rational numbers, i.e., '1/4 cup'.unit * Seems like a good time to move to 1.0 status - + 2006-12-15 0.3.9 * forgot to increment the version in the gem file..ooops. -2006-12-15 0.3.8 * Any object that supports a 'to_unit' method will now be +2006-12-15 0.3.8 * Any object that supports a 'to_unit' method will now be automatically coerced to a unit during math operations. - + 2006-12-14 0.3.7 * improved handling of percents and added a 'wt%' unit equivalent to 1 g/dl. * Improved handling for units with non-alphanumeric names @@ -111,21 +112,21 @@ Change Log for Ruby-units * to_int now coerces the result to an actual Integer, but only works properly for unitless Units. -2006-10-27 0.3.4 * Fixed a few more parsing bugs so that it will properly +2006-10-27 0.3.4 * Fixed a few more parsing bugs so that it will properly complain about malformed units. * Fixed a bug that prevents proper use of percents - * several minor tweaks + * several minor tweaks * some improved Date and DateTime handling * can convert between Date, DateTime, and Time objects * Time math will now return a DateTime if it goes out of range. -2006-10-03 0.3.3 * Apparently I can't do math late at night. +2006-10-03 0.3.3 * Apparently I can't do math late at night. Fixed a bug that would cause problems when adding - or subtracting units to a unit with a zero scalar. + or subtracting units to a unit with a zero scalar. * Date and DateTime objects can be converted to 'units' -2006-10-03 0.3.2 * More minor bug fixes +2006-10-03 0.3.2 * More minor bug fixes (now fixes a minor name collision with rails) 2006-10-02 0.3.1 * minor bug fixes @@ -133,10 +134,10 @@ Change Log for Ruby-units 2006-10-02 0.3.0 * Performance enhanced by caching results of many functions (Thanks to Kurt Stephens for pushing this.) * Throws an exception if the unit is not recognized - * units can now identify what 'kind' they are + * units can now identify what 'kind' they are (:length, :mass, etc..) - * New constructors: - Unit(1,"mm") + * New constructors: + Unit(1,"mm") Unit(1,"mm/s") Unit(1,"mm","s") @@ -149,8 +150,8 @@ Change Log for Ruby-units * 'string'.time returns a Time object or a DateTime if the Time object fails * 'string'.datetime returns a DateTime or a Time if the - DateTime fails - + DateTime fails + 2006-09-19 0.2.2 * tweaked temperature handling a bit. Now enter temperatures like this: '0 tempC'.unit #=> 273.15 degK @@ -158,7 +159,7 @@ Change Log for Ruby-units problems when temperatures are used in equations. * added Time.in("5 min") * added Unit.to_unit to simplify some calls - + 2006-09-18 0.2.1 * Trig math functions (sin, cos, tan, sinh, cosh, tanh) accept units that can be converted to radians Math.sin("90 deg".unit) => 1.0 @@ -170,14 +171,14 @@ Change Log for Ruby-units Time.now + "1 hr".unit => Mon Sep 18 11:51:29 EDT 2006 * can output time in 'hh:mm:ss' format by using 'unit.to_s(:time)' - * added time helper methods - ago, - since(Time/DateTime), - until(Time/DateTime), - from(Time/DateTime), + * added time helper methods + ago, + since(Time/DateTime), + until(Time/DateTime), + from(Time/DateTime), before(Time/DateTime), and after(Time/DateTime) - * Time helpers also work on strings. In this case they + * Time helpers also work on strings. In this case they are first converted to units '5 min'.from_now '1 week'.ago @@ -191,19 +192,19 @@ Change Log for Ruby-units output * can use U'1 mm' or '1 mm'.u to specify units now -2006-09-17 * can now use the '%' format specifier like +2006-09-17 * can now use the '%' format specifier like '%0.2f' % '1 mm'.unit #=> '1.00 mm' * works nicely with time now. '1 week'.unit + Time.now => 1.159e+09 s - Time.at('1.159e+09 s'.unit) + Time.at('1.159e+09 s'.unit) => Sat Sep 23 04:26:40 EDT 2006 - "1.159e9 s".unit.time + "1.159e9 s".unit.time => Sat Sep 23 04:26:40 EDT 2006 * Time.now.unit => 1.159e9 s * works well with 'Uncertain' numerics (www.rubyforge.org/projects/uncertain) * Improved parsing - + 2006-08-28 0.2.0 * Added 'ruby_unit.rb' file so that requires will still work if the wrong name is used * Added 'to' as an alias to '>>' so conversions can be @@ -226,13 +227,13 @@ Change Log for Ruby-units from forcing the conversion. To get the scalar, just use 'unit.scalar' * 'inspect' returns string representation - * better edge-case detection with math functions. + * better edge-case detection with math functions. "0 mm".unit**-1 now throws a ZeroDivisionError exception - * Ranges can make a series of units, so long as the end + * Ranges can make a series of units, so long as the end points have integer scalars. * Fixed a parsing bug with feet/pounds and scientific numbers - + 2006-08-22 0.1.1 * Added new format option "1 mm".to_unit("in") now converts the result to the indicated units * Fixed some naming issues so that the gem name matches @@ -249,7 +250,7 @@ Change Log for Ruby-units [1,'mm','s'].unit === "1 mm/s".unit 2.5.unit === "2.5".unit * Added instructions on how to add custom units - + 2006-08-22 0.1.0 * Initial Release diff --git a/Rakefile.rb b/Rakefile.rb index d41e377a..de0c9fd1 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -60,7 +60,7 @@ # puts %x{rvm current} puts end - + desc "Run all specs with rcov" RSpec::Core::RakeTask.new("spec:rcov") do |t| t.rcov = true From 271d91a4e36827b1e889740b3e92e936cb67e683 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 9 May 2015 13:28:52 -0400 Subject: [PATCH 063/150] travis config --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 04c4938b..cd28a68b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ rvm: - jruby-19mode # JRuby in 1.9 mode - 2.0.0 - 2.1.0 + - 2.2.0 + - ruby-head + - jruby-head jdk: - openjdk6 - openjdk7 @@ -15,4 +18,10 @@ matrix: jdk: openjdk6 - rvm: 2.1.0 jdk: openjdk6 + - rvm: 2.2.0 + jdk: openjdk6 + - rvm: jruby-head + jdk: openjdk6 + - rvm: ruby-head + jdk: openjdk6 script: bundle exec rake --trace From 5f9c300c36e201cb155c59669d33bfad955ee195 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 13 Jul 2015 11:52:19 -0400 Subject: [PATCH 064/150] =?UTF-8?q?add=20=E2=80=98pry-byebug=E2=80=99=20fo?= =?UTF-8?q?r=20debugging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 90155cc9..cbe2d177 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" group :development do gem 'bundler', '~> 1.0' gem 'jeweler' - gem 'pry' + gem 'pry-byebug' end group :test do From 5d5ec64d430f2108bb686b5cdc9d67c3051df39d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 13 Jul 2015 11:53:14 -0400 Subject: [PATCH 065/150] =?UTF-8?q?don=E2=80=99t=20cache=20units=20formatt?= =?UTF-8?q?ed=20like=20=E2=80=9912mg/6ml=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ruby_units/unit.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index e8e00453..94dc30ef 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -375,7 +375,9 @@ def initialize(*options) unary_unit = self.units || "" if options.first.instance_of?(String) opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) - unless @@cached_units.keys.include?(opt_units) || (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) + unless @@cached_units.keys.include?(opt_units) || + (opt_units =~ %r{\D/[\d+\.]+}) || + (opt_units =~ /(#{RubyUnits::Unit.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 From 717d1abeee8d828a3905fd4189eca58728101aa3 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 13 Jul 2015 11:53:45 -0400 Subject: [PATCH 066/150] =?UTF-8?q?actually=20use=20the=20denominator=20sp?= =?UTF-8?q?ecified=20in=20units=20like=20=E2=80=9912mg/6ml=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ruby_units/unit.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 94dc30ef..4058b69b 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1508,13 +1508,22 @@ def parse(passed_unit_string="0") if bottom bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } # Separate leading decimal from denominator, if any - bottom_scalar,bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] + bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] end @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? @scalar = 1 unless @scalar.kind_of? Numeric @scalar = @scalar.to_int if (@scalar.to_int == @scalar) + case + when bottom_scalar.nil? || bottom_scalar.empty? + when bottom_scalar.to_i == bottom_scalar + @scalar /= bottom_scalar.to_i + else + @scalar /= bottom_scalar.to_f + end + + @numerator ||= UNITY_ARRAY @denominator ||= UNITY_ARRAY @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if top @@ -1545,6 +1554,7 @@ def self.base_units end # parse a string consisting of a number and a unit string + # NOTE: This does not properly handle units formatted like '12mg/6ml' # @param [String] string # @return [Array] consisting of [Numeric, "unit"] # @private @@ -1555,7 +1565,8 @@ def self.parse_into_numbers_and_units(string) rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?} # complex numbers... -1.2+3i, +1.2-3.3i complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci})\b)?\s?([^-\d\.].*)?} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?} + num, unit = string.scan(anynumber).first return [case num From b37a9a62d64de73d0cd95468b63842d63628cbe3 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 13 Jul 2015 11:54:11 -0400 Subject: [PATCH 067/150] redo specs to be rspec 3 compliant --- spec/ruby-units/unit_spec.rb | 44 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index ca30afad..bc05e23e 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -816,18 +816,40 @@ end # rational scalar with numeric modified unit - describe Unit("12.1 mg/0.6mL") do + describe Unit.new('12.0mg/6.0mL') do it { should be_an_instance_of Unit } - its(:scalar) { should be_an Numeric} - its(:units) { should == "mg/ml" } - its(:kind) { should == :density } - it { should_not be_temperature } - it { should_not be_degree } - it { should_not be_base } - it { should_not be_unitless } - it { should_not be_zero } - its(:base) { should be_a Numeric } - its(:temperature_scale) { should be_nil } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Numeric } + it { is_expected.to eq (12.0/6.0) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq 'mg/ml' } + end + + describe '#kind' do + subject { super().kind } + it { is_expected.to eq :density } + end + + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_a Numeric } + end + + describe '#temperature_scale' do + subject { super().temperature_scale } + it { is_expected.to be_nil } + end end # time string From cd9114563aabfd98e462b7fadc9ed22e16944979 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 13 Jul 2015 11:54:24 -0400 Subject: [PATCH 068/150] allow filtering of tests --- spec/spec_helper.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a76dcf53..ddd4ed42 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,4 +14,11 @@ rescue LoadError end +RSpec.configure do |config| + #config.order = :random + config.filter_run_including focus: true + config.run_all_when_everything_filtered = true +end + require File.dirname(__FILE__) + "/../lib/ruby-units" + From 6c33706e40b3005687859122e58f247b1e8fb76a Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 16 Jul 2015 16:05:53 -0400 Subject: [PATCH 069/150] update changelog --- CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4caf0a6e..551121fc 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,6 @@ Change Log for Ruby-units ========================= +2015-07-16 * Fix issue #129 -- doesn't handle number in the denominator 2015-05-09 * update test harness to use rspec 3 2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit 2013-07-19 1.4.4 * Fix issue #4 -- .best_prefix method From ab9f4ef181724d37719aa7a896788c8b656ce8d3 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 16 Jul 2015 16:19:39 -0400 Subject: [PATCH 070/150] restrict pry-byebug to ruby 2.0 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index cbe2d177..d5bc7830 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" group :development do gem 'bundler', '~> 1.0' gem 'jeweler' - gem 'pry-byebug' + gem 'pry-byebug', :platforms => :ruby_20 end group :test do From 2818291f85f9013cc280809ad66398738c3f47f2 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 16 Jul 2015 21:38:26 -0400 Subject: [PATCH 071/150] update .travis.yml so it will use containers --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cd28a68b..ae319dca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: ruby rvm: - 1.9.3 From 8c56568e6e61607fca7b4f70a419f1fde5008730 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 17 Jul 2015 12:04:49 -0400 Subject: [PATCH 072/150] fix broken spec --- spec/ruby-units/unit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index bc05e23e..83cc8220 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1589,7 +1589,7 @@ specify { expect(Unit("2 m")).to be > Unit("1 ft") } specify { expect(Unit("70 tempF")).to be > Unit("10 degC") } specify { expect(Unit("1 m")).to be > 0 } - specify { expect { expect(Unit("1 m")).not_to be > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + specify { expect { Unit("1 m") > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do From c5d9ca1627127fc5283940392486752b4119785d Mon Sep 17 00:00:00 2001 From: Christian Nelson Date: Tue, 13 Oct 2015 16:36:43 -0700 Subject: [PATCH 073/150] =?UTF-8?q?Include=20greek=20=C2=B5=20as=20an=20al?= =?UTF-8?q?ias=20for=20micro.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ruby_units/unit_definitions/prefix.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index b6233605..62911e66 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -23,7 +23,7 @@ 'deci' => [%w{d Deci deci}, Rational(1,1e1)], 'centi' => [%w{c Centi centi}, Rational(1,1e2)], 'milli' => [%w{m Milli milli}, Rational(1,1e3)], - 'micro' => [%w{u Micro micro mc}, Rational(1,1e6)], + 'micro' => [%w{u µ Micro micro mc}, Rational(1,1e6)], 'nano' => [%w{n Nano nano}, Rational(1,1e9)], 'pico' => [%w{p Pico pico}, Rational(1,1e12)], 'femto' => [%w{f Femto femto}, Rational(1,1e15)], From acdfea8c505f6e43583b9bd57e253275faaf0a89 Mon Sep 17 00:00:00 2001 From: Christian Nelson Date: Tue, 13 Oct 2015 16:37:14 -0700 Subject: [PATCH 074/150] Reformat code. --- lib/ruby_units/unit_definitions/prefix.rb | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 62911e66..3901cd92 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,35 +1,35 @@ { - 'googol' => [%w{googol}, 1e100], - 'yobi' => [%w{Yi Yobi yobi}, 2**80], - 'zebi' => [%w{Zi Zebi zebi}, 2**70], - 'exbi' => [%w{Ei Exbi exbi}, 2**60], - 'pebi' => [%w{Pi Pebi pebi}, 2**50], - 'tebi' => [%w{Ti Tebi tebi}, 2**40], - 'gibi' => [%w{Gi Gibi gibi}, 2**30], - 'mebi' => [%w{Mi Mebi mebi}, 2**20], - 'kibi' => [%w{Ki Kibi kibi}, 2**10], - 'yotta' => [%w{Y Yotta yotta}, 1e24], - 'zetta' => [%w{Z Zetta zetta}, 1e21], - 'exa' => [%w{E Exa exa}, 1e18], - 'peta' => [%w{P Peta peta}, 1e15], - 'tera' => [%w{T Tera tera}, 1e12], - 'giga' => [%w{G Giga giga}, 1e9], - 'mega' => [%w{M Mega mega}, 1e6], - 'kilo' => [%w{k kilo}, 1e3], - 'hecto' => [%w{h Hecto hecto}, 1e2], - 'deca' => [%w{da Deca deca deka}, 1e1], - '1' => [%w{1}, 1], - 'deci' => [%w{d Deci deci}, Rational(1,1e1)], - 'centi' => [%w{c Centi centi}, Rational(1,1e2)], - 'milli' => [%w{m Milli milli}, Rational(1,1e3)], + 'googol' => [%w{googol}, 1e100], + 'yobi' => [%w{Yi Yobi yobi}, 2**80], + 'zebi' => [%w{Zi Zebi zebi}, 2**70], + 'exbi' => [%w{Ei Exbi exbi}, 2**60], + 'pebi' => [%w{Pi Pebi pebi}, 2**50], + 'tebi' => [%w{Ti Tebi tebi}, 2**40], + 'gibi' => [%w{Gi Gibi gibi}, 2**30], + 'mebi' => [%w{Mi Mebi mebi}, 2**20], + 'kibi' => [%w{Ki Kibi kibi}, 2**10], + 'yotta' => [%w{Y Yotta yotta}, 1e24], + 'zetta' => [%w{Z Zetta zetta}, 1e21], + 'exa' => [%w{E Exa exa}, 1e18], + 'peta' => [%w{P Peta peta}, 1e15], + 'tera' => [%w{T Tera tera}, 1e12], + 'giga' => [%w{G Giga giga}, 1e9], + 'mega' => [%w{M Mega mega}, 1e6], + 'kilo' => [%w{k kilo}, 1e3], + 'hecto' => [%w{h Hecto hecto}, 1e2], + 'deca' => [%w{da Deca deca deka}, 1e1], + '1' => [%w{1}, 1], + 'deci' => [%w{d Deci deci}, Rational(1,1e1)], + 'centi' => [%w{c Centi centi}, Rational(1,1e2)], + 'milli' => [%w{m Milli milli}, Rational(1,1e3)], 'micro' => [%w{u µ Micro micro mc}, Rational(1,1e6)], - 'nano' => [%w{n Nano nano}, Rational(1,1e9)], - 'pico' => [%w{p Pico pico}, Rational(1,1e12)], - 'femto' => [%w{f Femto femto}, Rational(1,1e15)], - 'atto' => [%w{a Atto atto}, Rational(1,1e18)], - 'zepto' => [%w{z Zepto zepto}, Rational(1,1e21)], - 'yocto' => [%w{y Yocto yocto}, Rational(1,1e24)] + 'nano' => [%w{n Nano nano}, Rational(1,1e9)], + 'pico' => [%w{p Pico pico}, Rational(1,1e12)], + 'femto' => [%w{f Femto femto}, Rational(1,1e15)], + 'atto' => [%w{a Atto atto}, Rational(1,1e18)], + 'zepto' => [%w{z Zepto zepto}, Rational(1,1e21)], + 'yocto' => [%w{y Yocto yocto}, Rational(1,1e24)] }.each do |name, definition| RubyUnits::Unit.define(name) do |unit| aliases, scalar = definition From 5a118ec976127c6684326375b5d81f82a9abc9fb Mon Sep 17 00:00:00 2001 From: Christian Nelson Date: Wed, 14 Oct 2015 07:52:11 -0700 Subject: [PATCH 075/150] Convert specs to RSpec 3.3.2 syntax with Transpec This conversion is done by Transpec 3.1.1 with the following command: transpec * 1 conversion from: it { should ... } to: it { is_expected.to ... } For more details: https://github.com/yujinakayama/transpec#supported-conversions --- spec/ruby-units/unit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 83cc8220..5851e3b9 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -817,7 +817,7 @@ # rational scalar with numeric modified unit describe Unit.new('12.0mg/6.0mL') do - it { should be_an_instance_of Unit } + it { is_expected.to be_an_instance_of Unit } describe '#scalar' do subject { super().scalar } From f4c3e560d30518c635ae296b0ad31d760a2d90c8 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 20:02:10 -0500 Subject: [PATCH 076/150] get rid of symlink --- lib/ruby_units.rb | 1 - 1 file changed, 1 deletion(-) delete mode 120000 lib/ruby_units.rb diff --git a/lib/ruby_units.rb b/lib/ruby_units.rb deleted file mode 120000 index ef999766..00000000 --- a/lib/ruby_units.rb +++ /dev/null @@ -1 +0,0 @@ -ruby-units.rb \ No newline at end of file From fa15cfdd71ef5823fadd465f43704fe1ed5ebf3b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 20:03:28 -0500 Subject: [PATCH 077/150] remove code used to support ruby < 2.0 --- .travis.yml | 4 -- Rakefile.rb | 2 - lib/ruby-units.rb | 1 - lib/ruby_units/fixnum.rb | 22 ---------- lib/ruby_units/namespaced.rb | 1 - lib/ruby_units/unit.rb | 66 ++++-------------------------- spec/ruby-units/complex_spec.rb | 23 +++-------- spec/ruby-units/math_spec.rb | 11 ++--- spec/ruby-units/utf-8/unit_spec.rb | 28 ++++++------- 9 files changed, 30 insertions(+), 128 deletions(-) delete mode 100644 lib/ruby_units/fixnum.rb diff --git a/.travis.yml b/.travis.yml index ae319dca..6df71900 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ sudo: false language: ruby rvm: - - 1.9.3 - - jruby-19mode # JRuby in 1.9 mode - 2.0.0 - 2.1.0 - 2.2.0 @@ -13,8 +11,6 @@ jdk: - openjdk7 matrix: exclude: - - rvm: 1.9.3 - jdk: openjdk6 - rvm: 2.0.0 jdk: openjdk6 - rvm: 2.1.0 diff --git a/Rakefile.rb b/Rakefile.rb index de0c9fd1..7de37758 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -72,8 +72,6 @@ task :specs => :spec rubies = { - "ruby-1.8.7" => %w{ruby-1.8.7-p357@ruby-units ruby-1.8.7-p357@ruby-units-with-chronic}, - "ruby-1.9.2" => %w{ruby-1.9.2-p290@ruby-units ruby-1.9.2-p290@ruby-units-with-chronic}, "rbx" => %w{rbx-head@ruby-units}, "jruby" => %w{jruby-1.6.7@ruby-units} } diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index 36b5cb09..17643349 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -5,5 +5,4 @@ # only include the Unit('unit') helper if we aren't fully namespaced require_relative 'ruby_units/object' - Unit = RubyUnits::Unit diff --git a/lib/ruby_units/fixnum.rb b/lib/ruby_units/fixnum.rb deleted file mode 100644 index 376f36c8..00000000 --- a/lib/ruby_units/fixnum.rb +++ /dev/null @@ -1,22 +0,0 @@ -if RUBY_VERSION < "1.9" - # :nocov_19: - class Fixnum - alias quo_without_units quo - - # @note this patch is necessary for ruby 1.8 because cases where Integers are divided by Units don't work quite right - # @param [Numeric] - # @return [Unit, Integer] - def quo_with_units(other) - case other - when RubyUnits::Unit - self * other.inverse - else - quo_without_units(other) - end - end - - alias quo quo_with_units - alias / quo_with_units - end - # :nocov_19: -end diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb index 229fdd00..34b75412 100644 --- a/lib/ruby_units/namespaced.rb +++ b/lib/ruby_units/namespaced.rb @@ -12,5 +12,4 @@ require_relative 'numeric' require_relative 'string' require_relative 'unit' -require_relative 'fixnum' require_relative 'unit_definitions' diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 4058b69b..c174c7c4 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1,13 +1,6 @@ # encoding: utf-8 require 'date' -if RUBY_VERSION < "1.9" - # :nocov_19: - require 'parsedate' - require 'rational' - # :nocov_19: -end -# Copyright 2006-2012 -# +# Copyright 2006-2015 # @author Kevin C. Olbrich, Ph.D. # @see https://github.com/olbrich/ruby-units # @@ -28,10 +21,6 @@ # unit.definition = RubyUnits::Unit.new("1 baz") # end # -# @todo fix class variables so they conform to standard naming conventions and refactor away as many of them as possible -# @todo pull caching out into its own class -# @todo refactor internal representation of units -# @todo method to determine best natural prefix module RubyUnits class Unit < Numeric VERSION = Unit::Version::STRING @@ -265,31 +254,6 @@ def copy(from) return self end - if RUBY_VERSION < "1.9" - # :nocov_19: - - # a list of properties to emit to yaml - # @return [Array] - def to_yaml_properties - %w{@scalar @numerator @denominator @signature @base_scalar} - end - - # basically a copy of the basic to_yaml. Needed because otherwise it ends up coercing the object to a string - # before YAML'izing it. - # @param [Hash] opts - # @return [String] - 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 - # :nocov_19: - end - # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime # # @example Valid options include: @@ -451,15 +415,7 @@ def is_base? def to_base return self if self.is_base? if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ - if RUBY_VERSION < "1.9" - # :nocov_19: - @signature = @@KINDS.index(:temperature) - # :nocov_19: - else - #:nocov: - @signature = @@KINDS.key(:temperature) - #:nocov: - end + @signature = @@KINDS.key(:temperature) base = case when self.is_temperature? self.convert_to('tempK') @@ -1123,18 +1079,10 @@ def floor return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator) end - if RUBY_VERSION < '1.9' - # @return [Numeric,Unit] - def round - return @scalar.round if self.unitless? - return RubyUnits::Unit.new(@scalar.round, @numerator, @denominator) - end - else - # @return [Numeric,Unit] - def round(ndigits = 0) - return @scalar.round(ndigits) if self.unitless? - return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) - end + # @return [Numeric,Unit] + def round(ndigits = 0) + return @scalar.round(ndigits) if self.unitless? + return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) end # @return [Numeric, Unit] @@ -1412,7 +1360,7 @@ def parse(passed_unit_string="0") if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ unit_string = "#{$1} USD" end - unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if RUBY_VERSION >= '1.9' && unit_string.encoding == Encoding::UTF_8 + unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8 unit_string.gsub!(/%/, 'percent') unit_string.gsub!(/'/, 'feet') diff --git a/spec/ruby-units/complex_spec.rb b/spec/ruby-units/complex_spec.rb index 404951ff..c6e96731 100644 --- a/spec/ruby-units/complex_spec.rb +++ b/spec/ruby-units/complex_spec.rb @@ -11,27 +11,16 @@ describe "Complex Unit" do subject { Complex(1.0, -1.0).to_unit } - + it { is_expected.to be_instance_of Unit} it(:scalar) { is_expected.to be_kind_of Complex } it { is_expected.to eq("1-1i".to_unit) } it { is_expected.to be === "1-1i".to_unit } - if RUBY_VERSION < "1.9" - context "in Ruby < 1.9" do - it "is comparable" do - expect(subject).to be > "1+0.5i".to_unit - expect(subject).to be < "2+1i".to_unit - end - end - else - context "in Ruby >= 1.9" do - it "is not comparable" do - expect { subject > "1+1i".to_unit }.to raise_error(NoMethodError) - expect { subject < "1+1i".to_unit }.to raise_error(NoMethodError) - end - end + it "is not comparable" do + expect { subject > "1+1i".to_unit }.to raise_error(NoMethodError) + expect { subject < "1+1i".to_unit }.to raise_error(NoMethodError) end - -end \ No newline at end of file + +end diff --git a/spec/ruby-units/math_spec.rb b/spec/ruby-units/math_spec.rb index 3d355c57..64e3b874 100644 --- a/spec/ruby-units/math_spec.rb +++ b/spec/ruby-units/math_spec.rb @@ -8,12 +8,9 @@ specify { expect(Math.sqrt(Unit("-9 mm^2"))).to be_kind_of(Complex) } end - if RUBY_VERSION > "1.9" - # cbrt is only defined in Ruby > 1.9 - describe '#cbrt' do - specify { expect(Math.cbrt(Unit('1 mm^6'))).to eq(Unit('1 mm^2')) } - specify { expect(Math.cbrt(8)).to eq(2) } - end + describe '#cbrt' do + specify { expect(Math.cbrt(Unit('1 mm^6'))).to eq(Unit('1 mm^2')) } + specify { expect(Math.cbrt(8)).to eq(2) } end context "Trigonometry functions" do @@ -58,4 +55,4 @@ specify { expect(Math.atan2(1,1)).to be_within(0.01).of(0.785398163397448)} specify { expect {Math.atan2(Unit("1 m"), Unit("2 lbs"))}.to raise_error(ArgumentError) } end -end \ No newline at end of file +end diff --git a/spec/ruby-units/utf-8/unit_spec.rb b/spec/ruby-units/utf-8/unit_spec.rb index eb9cf654..39975792 100644 --- a/spec/ruby-units/utf-8/unit_spec.rb +++ b/spec/ruby-units/utf-8/unit_spec.rb @@ -1,24 +1,22 @@ # encoding: utf-8 require File.dirname(__FILE__) + '/../../spec_helper' - -if RUBY_VERSION.include?('1.9') - describe Unit, 'Degrees' do - context 'when the UTF-8 symbol is used' do - context 'Angles' do - it 'should be a degree' do - expect(Unit("180\u00B0").units).to eq('deg') - end + +describe Unit, 'Degrees' do + context 'when the UTF-8 symbol is used' do + context 'Angles' do + it 'should be a degree' do + expect(Unit("180\u00B0").units).to eq('deg') end + end - context 'Temperature' do - it 'should be a degree Celcius' do - expect(Unit("180\u00B0C").units).to eq('degC') - end + context 'Temperature' do + it 'should be a degree Celcius' do + expect(Unit("180\u00B0C").units).to eq('degC') + end - it 'should be a degree Fahrenheit' do - expect(Unit("180\u00B0F").units).to eq('degF') - end + it 'should be a degree Fahrenheit' do + expect(Unit("180\u00B0F").units).to eq('degF') end end end From 5e4cc030f2cf2bf88a76792d9368e24554b37d81 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 20:03:39 -0500 Subject: [PATCH 078/150] add ruby-version file --- .ruby-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..58594069 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.2.3 From 2ff4e255c30a98fc528d58303e58b6c2187cf419 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 20:32:21 -0500 Subject: [PATCH 079/150] Version bump to 2.0.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e516bb9d..359a5b95 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5 +2.0.0 \ No newline at end of file From ffb6dfa729c8d53c825c0f4ebb788d2cdda3624b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 22:21:21 -0500 Subject: [PATCH 080/150] kill off symlink --- lib/ruby-units | 1 - 1 file changed, 1 deletion(-) delete mode 120000 lib/ruby-units diff --git a/lib/ruby-units b/lib/ruby-units deleted file mode 120000 index 661dac0c..00000000 --- a/lib/ruby-units +++ /dev/null @@ -1 +0,0 @@ -./ruby_units \ No newline at end of file From c1406d354c3f0e50954d203b8e87003de67d8f78 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 22:21:57 -0500 Subject: [PATCH 081/150] housekeeping --- Gemfile | 10 +++--- Rakefile.rb | 88 +++++++-------------------------------------- spec/spec_helper.rb | 21 +++++------ 3 files changed, 25 insertions(+), 94 deletions(-) diff --git a/Gemfile b/Gemfile index d5bc7830..f58f9677 100644 --- a/Gemfile +++ b/Gemfile @@ -1,17 +1,15 @@ -source "https://rubygems.org" +source 'https://rubygems.org' group :development do gem 'bundler', '~> 1.0' gem 'jeweler' - gem 'pry-byebug', :platforms => :ruby_20 + gem 'pry-byebug' end group :test do gem 'rake' - gem 'rcov', :platforms => :mri_18 - gem 'simplecov', :require => false, :platforms => :mri_19 - gem 'simplecov-html', :platforms => :mri_19 + gem 'simplecov' + gem 'simplecov-html' gem 'rspec' gem 'guard-rspec' end - diff --git a/Rakefile.rb b/Rakefile.rb index 7de37758..a5a13062 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -6,84 +6,22 @@ begin require 'jeweler' Jeweler::Tasks.new do |gem| - gem.name = "ruby-units" - gem.summary = %Q{A class that performs unit conversions and unit math} - gem.description = %Q{Provides classes and methods to perform unit math and conversions} - gem.authors = ["Kevin Olbrich, Ph.D."] - gem.email = ["kevin.olbrich+ruby_units@gmail.com"] - gem.homepage = "https://github.com/olbrich/ruby-units" - gem.files.exclude(".*","test/**/*","spec/**/*","autotest/**/*", "Gemfile") - gem.license = "MIT" - gem.post_install_message = <<-EOS -==================== -Deprecation Warning -==================== - -Several convenience methods that ruby-units added to the string class have -been deprecated in this release. These methods include String#to, String#from, String#ago, String#before and others. -If your code relies on these functions, they can be added back by adding this line to your code. - -require 'ruby-units/string/extras' -# note that these methods do not play well with Rails, which is one of the reasons they are being removed. - -The extra functions mostly work the same, but will no longer properly handle cases when they are called with strings.. - -'min'.from("4-1-2011") # => Exception - -Pass in a Date, Time, or DateTime object to get the expected result. - -They will go away completely in the next release, so it would be a good idea to refactor your code -to avoid using them. They will also throw deprecation warnings when they are used. -EOS + gem.name = 'ruby-units' + gem.summary = 'A class that performs unit conversions and unit math' + gem.description = 'Provides classes and methods to perform unit math and conversions' + gem.authors = ['Kevin Olbrich, Ph.D.'] + gem.email = ['kevin.olbrich+ruby_units@gmail.com'] + gem.homepage = 'https://github.com/olbrich/ruby-units' + gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile') + gem.license = 'MIT' end Jeweler::GemcutterTasks.new rescue LoadError - puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" -end - -begin - require 'simplecov' - desc "code coverage report using simplecov (ruby 1.9+)" - task :simplecov do - ENV['COVERAGE']='true' - Rake::Task['spec'].invoke - end -rescue LoadError -end - -begin - require 'rspec/core/rake_task' - - desc "Run specs" - RSpec::Core::RakeTask.new do |spec| - puts - # puts %x{rvm current} - puts - end - - desc "Run all specs with rcov" - RSpec::Core::RakeTask.new("spec:rcov") do |t| - t.rcov = true - t.rcov_opts = %w{--exclude osx\/objc,gems\/,spec\/,features\/} - end -rescue LoadError -end - -task :specs => :spec - -rubies = { - "rbx" => %w{rbx-head@ruby-units}, - "jruby" => %w{jruby-1.6.7@ruby-units} - } - -rubies.each do |name, ruby| - desc "Run Spec against #{name}" - task "spec:#{name}" do - sh "rvm #{ruby.join(',')} do rake spec" - end + puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler' end -desc "Run specs against several ruby versions, requires rvm" -task "spec:all" => rubies.keys.map {|name| "spec:#{name}"} +require 'rspec/core/rake_task' +desc 'Run specs' +RSpec::Core::RakeTask.new -task :default => :spec +task default: :spec diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ddd4ed42..787d1f92 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,24 +1,19 @@ require 'rubygems' -require 'bundler' -Bundler.setup(:development) +require 'bundler/setup' +Bundler.require(:development, :test) require 'rspec/core' -# Initiate code coverage generation when needed -begin - require 'simplecov' - SimpleCov.start do - add_filter "/spec/" - add_filter "/test/" - skip_token "nocov_19" - end if ENV['COVERAGE'] -rescue LoadError +require 'simplecov' +SimpleCov.start do + add_filter '/spec/' + add_filter '/test/' + skip_token 'nocov_19' end RSpec.configure do |config| - #config.order = :random + config.order = :random config.filter_run_including focus: true config.run_all_when_everything_filtered = true end require File.dirname(__FILE__) + "/../lib/ruby-units" - From 299ba0a9afe9de352f19bca1c2cd992a546413a4 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 22:27:26 -0500 Subject: [PATCH 082/150] get rid of 'unit' and 'u' methods on String and Date --- lib/ruby_units/date.rb | 56 ++++++++++----------- lib/ruby_units/string.rb | 27 ++++------ lib/ruby_units/unit.rb | 90 ++++++++++++++++++---------------- spec/ruby-units/date_spec.rb | 49 +++++++++--------- spec/ruby-units/string_spec.rb | 27 +++++----- spec/ruby-units/unit_spec.rb | 12 ++--- 6 files changed, 126 insertions(+), 135 deletions(-) diff --git a/lib/ruby_units/date.rb b/lib/ruby_units/date.rb index ca2f5944..b08a6705 100644 --- a/lib/ruby_units/date.rb +++ b/lib/ruby_units/date.rb @@ -1,34 +1,34 @@ require 'date' # Allow date objects to do offsets by a time unit -# Date.today + U"1 week" => gives today+1 week +# Date.today + Unit.new("1 week") => gives today+1 week class Date - alias :unit_date_add :+ - # @param [Object] unit + alias_method :unit_date_add, :+ + # @param [Object] other # @return [Unit] - def +(unit) - case unit + def +(other) + case other when RubyUnits::Unit - unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units - unit_date_add(unit.convert_to('day').scalar) + other = other.convert_to('d').round if %w(y decade century).include? other.units + unit_date_add(other.convert_to('day').scalar) else - unit_date_add(unit) + unit_date_add(other) end end - - alias :unit_date_sub :- - # @param [Object] unit + + alias_method :unit_date_sub, :- + # @param [Object] other # @return [Unit] - def -(unit) - case unit - when RubyUnits::Unit - unit = unit.convert_to('d').round if ['y', 'decade', 'century'].include? unit.units - unit_date_sub(unit.convert_to('day').scalar) + def -(other) + case other + when RubyUnits::Unit + other = other.convert_to('d').round if %w(y decade century).include? other.units + unit_date_sub(other.convert_to('day').scalar) else - unit_date_sub(unit) + unit_date_sub(other) end end - + # Construct a unit from a Date # @example Date.today.to_unit => Unit # @return (see Unit#initialize) @@ -36,31 +36,29 @@ def -(unit) def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end - alias :unit :to_unit - + # :nocov_19: unless Date.instance_methods.include?(:to_time) # @return [Time] def to_time - Time.local(*ParseDate.parsedate(self.to_s)) + Time.local(*ParseDate.parsedate(to_s)) end end # :nocov_19: - - alias :units_datetime_inspect :inspect + + alias_method :units_datetime_inspect, :inspect # @deprecated - def inspect(raw = false) - return self.units_datetime_inspect if raw - self.to_s + def inspect(dump = false) + return units_datetime_inspect if dump + to_s end - + unless Date.instance_methods.include?(:to_date) # :nocov_19: # @return [Date] def to_date - Date.civil(self.year, self.month, self.day) + Date.civil(year, month, day) end # :nocov_19: end - end diff --git a/lib/ruby_units/string.rb b/lib/ruby_units/string.rb index 61c0edda..9cfbfcb9 100644 --- a/lib/ruby_units/string.rb +++ b/lib/ruby_units/string.rb @@ -5,31 +5,24 @@ class String def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end - alias :unit :to_unit - alias :u :to_unit - - alias :unit_format :% - # format unit output using formating codes + alias_method :original_format, :% + # format unit output using formating codes # @example '%0.2f' % '1 mm'.unit => '1.00 mm' # @return [String] - def %(*args) - return "" if self.empty? - case - when args.first.is_a?(RubyUnits::Unit) - args.first.to_s(self) - when (!defined?(Uncertain).nil? && args.first.is_a?(Uncertain)) - args.first.to_s(self) - when args.first.is_a?(Complex) - args.first.to_s + def format_with_unit(*other) + case + when other.first.is_a?(RubyUnits::Unit) + other.first.to_s(self) else - unit_format(*args) + original_format(*other) end end - + alias_method :%, :format_with_unit + # @param (see RubyUnits::Unit#convert_to) # @return (see RubyUnits::Unit#convert_to) def convert_to(other) - self.unit.convert_to(other) + to_unit.convert_to(other) end end diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index c174c7c4..cfda5a1e 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -189,11 +189,13 @@ def self.define(unit_definition, &block) # @yield [RubyUnits::Unit::Definition] # @return (see RubyUnits::Unit.define) # Get the definition for a unit and allow it to be redefined - def self.redefine!(name, &block) - raise ArgumentError, "A block is required to redefine a unit" unless block_given? - unit_definition = self.definition(name) + def self.redefine!(name) + fail ArgumentError, 'A block is required to redefine a unit' unless block_given? + unit_definition = definition(name) yield unit_definition - self.define(unit_definition) + @@definitions.delete("<#{name}>") + define(unit_definition) + RubyUnits::Unit.setup end # @param [String] name of unit to undefine @@ -342,11 +344,11 @@ def initialize(*options) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ %r{\D/[\d+\.]+}) || (opt_units =~ /(#{RubyUnits::Unit.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? + @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? end end unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) then - @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.unit) + @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.to_unit) end [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each { |x| x.freeze } return self @@ -386,7 +388,7 @@ def self.base_unit_cache # @return [Unit] def self.parse(input) first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first - return second.nil? ? first.unit : first.unit.convert_to(second) + second.nil? ? RubyUnits::Unit.new(first) : RubyUnits::Unit.new(first).convert_to(second) end # @return [Unit] @@ -453,7 +455,7 @@ def to_base num = num.flatten.compact den = den.flatten.compact num = UNITY_ARRAY if num.empty? - base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den)) + base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den)) @@base_unit_cache[self.units]=base return base * @scalar end @@ -481,36 +483,38 @@ def to_s(target_units=nil) return out else case target_units - when :ft - inches = self.convert_to("in").scalar.to_int - out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" - when :lbs - ounces = self.convert_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.convert_to($2).to_s($1) - else - "#{$1 % @scalar} #{$2 || self.units}".strip - end - rescue # parse it like a strftime format string - (DateTime.new(0) + self).strftime(target_units) - end - when /(\S+)/ #unit only 'mm' or '1/mm' - self.convert_to($1).to_s + when :ft + inches = self.convert_to("in").scalar.to_int + out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" + when :lbs + ounces = self.convert_to("oz").scalar.to_int + out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" + when String + out = case target_units.strip + when /\A\s*\Z/ # whitespace only + '' + when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in' + begin + if $2 #unit specified, need to convert + self.convert_to($2).to_s($1) else - raise "unhandled case" + "#{$1 % @scalar} #{$2 || self.units}".strip + end + rescue # parse it like a strftime format string + (DateTime.new(0) + self).strftime(target_units) end - else - out = case @scalar - when Rational - "#{@scalar} #{self.units}" - else - "#{'%g' % @scalar} #{self.units}" - end.strip + when /(\S+)/ #unit only 'mm' or '1/mm' + self.convert_to($1).to_s + else + raise "unhandled case" + end + else + out = case @scalar + when Rational, Complex + "#{@scalar} #{self.units}" + else + "#{'%g' % @scalar} #{self.units}" + end.strip end @output[target_units] = out return out @@ -520,9 +524,9 @@ def to_s(target_units=nil) # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' # @deprecated # @return [String] - def inspect(option=nil) - return super() if option == :dump - return self.to_s + def inspect(dump = nil) + return super() if dump + to_s end # true if unit is a 'temperature', false if a 'degree' or anything else @@ -1414,10 +1418,10 @@ def parse(passed_unit_string="0") if unit_string =~ /:/ hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? { |x| x.nil? } - result = "#{hours || 0} h".unit + - "#{minutes || 0} minutes".unit + - "#{seconds || 0} seconds".unit + - "#{microseconds || 0} usec".unit + result = RubyUnits::Unit.new("#{hours || 0} h") + + RubyUnits::Unit.new("#{minutes || 0} minutes") + + RubyUnits::Unit.new("#{seconds || 0} seconds") + + RubyUnits::Unit.new("#{microseconds || 0} usec") copy(result) return end diff --git a/spec/ruby-units/date_spec.rb b/spec/ruby-units/date_spec.rb index e9507e42..998713b2 100644 --- a/spec/ruby-units/date_spec.rb +++ b/spec/ruby-units/date_spec.rb @@ -1,23 +1,22 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Date do - subject { Date.new(2011,4,1) } - - it {is_expected.to be_instance_of Date} - it {is_expected.to respond_to :to_unit} - it {is_expected.to respond_to :to_time} - it {is_expected.to respond_to :to_date} - - specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } - specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } + subject { Date.new(2011, 4, 1) } + + it { is_expected.to be_instance_of Date } + it { is_expected.to respond_to :to_unit } + it { is_expected.to respond_to :to_time } + it { is_expected.to respond_to :to_date } + + specify { expect(subject + '5 days'.to_unit).to eq(Date.new(2011, 4, 6)) } + specify { expect(subject - '5 days'.to_unit).to eq(Date.new(2011, 3, 27)) } # 2012 is a leap year... - specify { expect(subject + "1 year".unit).to eq(Date.new(2012,3,31)) } - specify { expect(subject - "1 year".unit).to eq(Date.new(2010,4,1)) } + specify { expect(subject + '1 year'.to_unit).to eq(Date.new(2012, 3, 31)) } + specify { expect(subject - '1 year'.to_unit).to eq(Date.new(2010, 4, 1)) } end -describe "Date Unit" do - - subject { Date.new(2011,4,1).to_unit } +describe 'Date Unit' do + subject { Date.new(2011, 4, 1).to_unit } it { is_expected.to be_instance_of Unit } @@ -28,7 +27,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("d") } + it { is_expected.to eq('d') } end describe '#kind' do @@ -36,15 +35,15 @@ it { is_expected.to eq(:time) } end - specify { expect(subject + "5 days".unit).to eq(Date.new(2011,4,6)) } - specify { expect(subject - "5 days".unit).to eq(Date.new(2011,3,27)) } + specify { expect(subject + '5 days'.to_unit).to eq(Date.new(2011, 4, 6)) } + specify { expect(subject - '5 days'.to_unit).to eq(Date.new(2011, 3, 27)) } - specify { expect { subject + Date.new(2011,4,1) }.to raise_error(ArgumentError) } - specify { expect { subject + DateTime.new(2011,4,1,12,00,00) }.to raise_error(ArgumentError) } - specify { expect { subject + Time.parse("2011-04-01 12:00:00") }.to raise_error(ArgumentError) } + specify { expect { subject + Date.new(2011, 4, 1) }.to raise_error(ArgumentError) } + specify { expect { subject + DateTime.new(2011, 4, 1, 12, 00, 00) }.to raise_error(ArgumentError) } + specify { expect { subject + Time.parse('2011-04-01 12:00:00') }.to raise_error(ArgumentError) } - specify { expect(subject - Date.new(2011,4,1)).to be_zero } - specify { expect(subject - DateTime.new(2011,4,1,00,00,00)).to be_zero } - specify { expect {(subject - Time.parse("2011-04-01 00:00"))}.to raise_error(ArgumentError) } - specify { expect(Date.new(2011,4,1) + 1).to eq(Date.new(2011,4,2))} -end \ No newline at end of file + specify { expect(subject - Date.new(2011, 4, 1)).to be_zero } + specify { expect(subject - DateTime.new(2011, 4, 1, 00, 00, 00)).to be_zero } + specify { expect { (subject - Time.parse('2011-04-01 00:00')) }.to raise_error(ArgumentError) } + specify { expect(Date.new(2011, 4, 1) + 1).to eq(Date.new(2011, 4, 2)) } +end diff --git a/spec/ruby-units/string_spec.rb b/spec/ruby-units/string_spec.rb index da8a9131..a23fcdc1 100644 --- a/spec/ruby-units/string_spec.rb +++ b/spec/ruby-units/string_spec.rb @@ -1,20 +1,17 @@ require File.dirname(__FILE__) + '/../spec_helper' describe String do - context "Unit creation from strings" do - specify { expect("1 mm".to_unit).to be_instance_of Unit } - specify { expect("1 mm".unit).to be_instance_of Unit } - specify { expect("1 mm".u).to be_instance_of Unit } - specify { expect("1 m".convert_to("ft")).to be_within(Unit("0.01 ft")).of Unit("3.28084 ft") } + context 'Unit creation from strings' do + specify { expect('1 mm'.to_unit).to be_instance_of Unit } + specify { expect('1 m'.convert_to('ft')).to be_within(Unit.new('0.01 ft')).of Unit.new('3.28084 ft') } end - - context "output format" do - subject { Unit("1.23456 m/s^2") } - specify { expect("" % subject).to eq("")} - specify { expect("%0.2f" % subject).to eq("1.23 m/s^2")} - specify { expect("%0.2f km/h^2" % subject).to eq("15999.90 km/h^2")} - specify { expect("km/h^2" % subject).to eq("15999.9 km/h^2")} - specify { expect("%H:%M:%S" % Unit("1.5 h")).to eq("01:30:00")} + + context 'output format' do + subject { Unit('1.23456 m/s^2') } + specify { expect('' % subject).to eq('') } + specify { expect('%0.2f' % subject).to eq('1.23 m/s^2') } + specify { expect('%0.2f km/h^2' % subject).to eq('15999.90 km/h^2') } + specify { expect('km/h^2' % subject).to eq('15999.9 km/h^2') } + specify { expect('%H:%M:%S' % Unit('1.5 h')).to eq('01:30:00') } end - -end \ No newline at end of file +end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 5851e3b9..b29de8db 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -2137,22 +2137,22 @@ specify { expect { subject.to_s("random string") }.to raise_error(ArgumentError, "'random' Unit not recognized") } end - context "for a unit with a custom display_name" do + context 'for a unit with a custom display_name' do before(:each) do - Unit.redefine!("cup") do |cup| - cup.display_name = "cupz" + Unit.redefine!('cup') do |cup| + cup.display_name = 'cupz' end end after(:each) do - Unit.redefine!("cup") do |cup| + Unit.redefine!('cup') do |cup| cup.display_name = cup.aliases.first end end - subject { Unit("8 cups") } + subject { Unit.new('8 cups') } - specify { expect(subject.to_s).to eq("8 cupz") } + specify { expect(subject.to_s).to eq('8 cupz') } end From 82cf4d78c6f6520abe9a4ddf270956bfc8b13462 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 22:36:32 -0500 Subject: [PATCH 083/150] Don't load bye bug unless on MRI because Jruby will complain about installing it. Usually only an issue on Travis, where we don't need it anyway. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index f58f9677..5626b398 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' group :development do gem 'bundler', '~> 1.0' gem 'jeweler' - gem 'pry-byebug' + gem 'pry-byebug', platforms: :mri end group :test do From 71833cb1de4be77958f92e9f2c24e26bb6808e7f Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 23:33:18 -0500 Subject: [PATCH 084/150] remove the Unit('1 mm'), and U('1 mm') style of instantiation --- CHANGELOG.txt | 12 +- lib/ruby-units.rb | 5 - lib/ruby_units/array.rb | 4 +- lib/ruby_units/definition.rb | 26 +- lib/ruby_units/numeric.rb | 2 - lib/ruby_units/object.rb | 15 - lib/ruby_units/time.rb | 22 +- lib/ruby_units/unit.rb | 24 +- spec/ruby-units/bugs_spec.rb | 12 +- spec/ruby-units/cache_spec.rb | 22 +- spec/ruby-units/definition_spec.rb | 28 +- spec/ruby-units/math_spec.rb | 53 ++- spec/ruby-units/object_spec.rb | 9 - spec/ruby-units/range_spec.rb | 23 +- spec/ruby-units/string_spec.rb | 6 +- spec/ruby-units/temperature_spec.rb | 127 +++--- spec/ruby-units/time_spec.rb | 6 +- spec/ruby-units/unit_spec.rb | 618 ++++++++++++++-------------- spec/ruby-units/utf-8/unit_spec.rb | 6 +- 19 files changed, 496 insertions(+), 524 deletions(-) delete mode 100644 lib/ruby_units/object.rb delete mode 100644 spec/ruby-units/object_spec.rb diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 551121fc..c421b1ff 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,10 @@ Change Log for Ruby-units ========================= +2015-11-07 2.0.0 * remove support for ruby versions less than 2.0 + * remove `.unit` and `.u` from String + * remove `.unit` from Date + * Fix an issue with redefining units that have already been cached + * remove 'U()' and 'u()' constructors 2015-07-16 * Fix issue #129 -- doesn't handle number in the denominator 2015-05-09 * update test harness to use rspec 3 2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit @@ -253,10 +258,3 @@ Change Log for Ruby-units * Added instructions on how to add custom units 2006-08-22 0.1.0 * Initial Release - - - - - - - diff --git a/lib/ruby-units.rb b/lib/ruby-units.rb index 17643349..20794030 100755 --- a/lib/ruby-units.rb +++ b/lib/ruby-units.rb @@ -1,8 +1,3 @@ $LOAD_PATH << File.dirname(__FILE__) - require_relative 'ruby_units/namespaced' - -# only include the Unit('unit') helper if we aren't fully namespaced -require_relative 'ruby_units/object' - Unit = RubyUnits::Unit diff --git a/lib/ruby_units/array.rb b/lib/ruby_units/array.rb index 413d0ddd..1f95a634 100644 --- a/lib/ruby_units/array.rb +++ b/lib/ruby_units/array.rb @@ -1,11 +1,9 @@ class Array # Construct a unit from an array - # @example [1, 'mm'].to_unit => RubyUnits::Unit("1 mm") + # @example [1, 'mm'].to_unit => RubyUnits::Unit.new("1 mm") # @return (see RubyUnits::Unit#initialize) # @param [Object] other convert to same units as passed def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end - alias :unit :to_unit - alias :u :to_unit end diff --git a/lib/ruby_units/definition.rb b/lib/ruby_units/definition.rb index 2db7df80..bdd7826b 100644 --- a/lib/ruby_units/definition.rb +++ b/lib/ruby_units/definition.rb @@ -2,32 +2,32 @@ class RubyUnits::Unit < Numeric # Handle the definition of units class Definition - + # @return [Array] attr_writer :aliases - + # @return [Symbol] attr_accessor :kind - + # @return [Numeric] attr_accessor :scalar - + # @return [Array] attr_accessor :numerator # @return [Array] attr_accessor :denominator - + # @return [String] attr_accessor :display_name - + # @example Raw definition from a hash # Unit::Definition.new("rack-unit",[%w{U rack-U}, (6405920109971793/144115188075855872), :length, %w{} ]) - # + # # @example Block form # Unit::Definition.new("rack-unit") do |unit| # unit.aliases = %w{U rack-U} - # unit.definition = Unit("7/4 inches") + # unit.definition = RubyUnits::Unit.new("7/4 inches") # end # def initialize(_name, _definition = [], &block) @@ -40,7 +40,7 @@ def initialize(_name, _definition = [], &block) @denominator ||= _definition[4] || RubyUnits::Unit::UNITY_ARRAY @display_name ||= @aliases.first end - + # name of the unit # nil if name is not set, adds '<' and '>' around the name # @return [String, nil] @@ -48,14 +48,14 @@ def initialize(_name, _definition = [], &block) def name "<#{@name}>" if (defined?(@name) && @name) end - + # set the name, strip off '<' and '>' # @param [String] # @return [String] def name=(_name) @name = _name.gsub(/[<>]/,'') end - + # alias array must contain the name of the unit and entries must be unique # @return [Array] def aliases @@ -79,13 +79,13 @@ def definition=(unit) def prefix? self.kind == :prefix end - + # Is this definition the unity definition? # @return [Boolean] def unity? self.prefix? && self.scalar == 1 end - + # is this a base unit? # units are base units if the scalar is one, and the unit is defined in terms of itself. # @return [Boolean] diff --git a/lib/ruby_units/numeric.rb b/lib/ruby_units/numeric.rb index 75190b2b..1b0879ac 100644 --- a/lib/ruby_units/numeric.rb +++ b/lib/ruby_units/numeric.rb @@ -4,6 +4,4 @@ class Numeric def to_unit(other = nil) other ? RubyUnits::Unit.new(self, other) : RubyUnits::Unit.new(self) end - alias :unit :to_unit - alias :u :to_unit end diff --git a/lib/ruby_units/object.rb b/lib/ruby_units/object.rb deleted file mode 100644 index c82d880a..00000000 --- a/lib/ruby_units/object.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Object - - # Shortcut for creating Unit object - # @example - # Unit("1 mm") - # U("1 mm") - # @return [Unit] - def Unit(*other) - other.to_unit - end - alias :U :Unit - - # @deprecated - alias :u :Unit -end diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index c9cd5f6d..a76a3fda 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -2,15 +2,15 @@ # # Time math is handled slightly differently. The difference is considered to be an exact duration if # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset -# is in years, decades, or centuries. This leads to less precise values, but ones that match the +# is in years, decades, or centuries. This leads to less precise values, but ones that match the # calendar better. class Time - + class << self alias unit_time_at at end - - # Convert a duration to a Time value by considering the duration to be the number of seconds since the + + # Convert a duration to a Time value by considering the duration to be the number of seconds since the # epoch # @param [Time] arg # @param [Integer] ms @@ -34,21 +34,19 @@ def self.at(arg, ms=nil) def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end - alias :unit :to_unit - alias :u :to_unit unless Time.public_method_defined?(:to_date) # :nocov_19: public :to_date # :nocov_19: end - + alias :unit_add :+ # @return [RubyUnits::Unit, Time] def +(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units + other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_add(other.convert_to('s').scalar) rescue RangeError @@ -58,21 +56,21 @@ def +(other) unit_add(other) end end - + # @example # Time.in '5 min' # @return (see Time#+) def self.in(duration) Time.now + duration.to_unit end - + alias :unit_sub :- - + # @return [RubyUnits::Unit, Time] def -(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units + other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units begin unit_sub(other.convert_to('s').scalar) rescue RangeError diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index cfda5a1e..5b50611e 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1166,12 +1166,12 @@ def before(time_point = ::Time.now) # @raise [ArgumentError] when time point is not a Time, Date, or DateTime def since(time_point) case time_point - when Time - return (Time.now - time_point).unit('s').convert_to(self) - when DateTime, Date - return (DateTime.now - time_point).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + when Time + return (Time.now - time_point).to_unit('s').convert_to(self) + when DateTime, Date + return (DateTime.now - time_point).to_unit('d').convert_to(self) + else + fail ArgumentError, 'Must specify a Time, Date, or DateTime' end end @@ -1180,12 +1180,12 @@ def since(time_point) # @return [Unit] def until(time_point) case time_point - when Time - return (time_point - Time.now).unit('s').convert_to(self) - when DateTime, Date - return (time_point - DateTime.now).unit('d').convert_to(self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + when Time + return (time_point - Time.now).to_unit('s').convert_to(self) + when DateTime, Date + return (time_point - DateTime.now).to_unit('d').convert_to(self) + else + fail ArgumentError, 'Must specify a Time, Date, or DateTime' end end diff --git a/spec/ruby-units/bugs_spec.rb b/spec/ruby-units/bugs_spec.rb index 25b6ca37..d90338f0 100644 --- a/spec/ruby-units/bugs_spec.rb +++ b/spec/ruby-units/bugs_spec.rb @@ -1,10 +1,10 @@ require File.dirname(__FILE__) + '/../spec_helper' -describe "Github issue #49" do - let(:a) { Unit("3 cm^3")} - let(:b) { Unit.new(a)} +describe 'Github issue #49' do + let(:a) { RubyUnits::Unit.new('3 cm^3') } + let(:b) { RubyUnits::Unit.new(a) } - it "should subtract a unit properly from one initialized with a unit" do - expect(b - Unit("1.5 cm^3")).to eq(Unit("1.5 cm^3")) + it 'should subtract a unit properly from one initialized with a unit' do + expect(b - RubyUnits::Unit.new('1.5 cm^3')).to eq(RubyUnits::Unit.new('1.5 cm^3')) end -end \ No newline at end of file +end diff --git a/spec/ruby-units/cache_spec.rb b/spec/ruby-units/cache_spec.rb index f6a07602..5856570a 100644 --- a/spec/ruby-units/cache_spec.rb +++ b/spec/ruby-units/cache_spec.rb @@ -2,30 +2,30 @@ describe Unit::Cache do subject { Unit::Cache } - let(:unit) { Unit('1 m') } + let(:unit) { RubyUnits::Unit.new('1 m') } before(:each) do subject.clear - subject.set("m", unit) + subject.set('m', unit) end - context ".clear" do - it "should clear the cache" do + context '.clear' do + it 'should clear the cache' do subject.clear expect(subject.get('m')).to be_nil end end - context ".get" do - it "should retrieve values already in the cache" do + context '.get' do + it 'should retrieve values already in the cache' do expect(subject.get['m']).to eq(unit) end end - context ".set" do - it "should put a unit into the cache" do - subject.set('kg', Unit('1 kg')) - expect(subject.get['kg']).to eq(Unit('1 kg')) + context '.set' do + it 'should put a unit into the cache' do + subject.set('kg', RubyUnits::Unit.new('1 kg')) + expect(subject.get['kg']).to eq(RubyUnits::Unit.new('1 kg')) end end -end \ No newline at end of file +end diff --git a/spec/ruby-units/definition_spec.rb b/spec/ruby-units/definition_spec.rb index 0f83e261..9014ce8e 100644 --- a/spec/ruby-units/definition_spec.rb +++ b/spec/ruby-units/definition_spec.rb @@ -1,41 +1,41 @@ require File.dirname(__FILE__) + '/../spec_helper' describe "Unit::Definition('eV')" do - subject { - Unit::Definition.new("eV") do |ev| - ev.aliases = ["eV", "electron-volt"] - ev.definition = Unit("1.602E-19 joule") - ev.display_name = "electron-volt" - end - } - + subject do + Unit::Definition.new('eV') do |ev| + ev.aliases = ['eV', 'electron-volt'] + ev.definition = RubyUnits::Unit.new('1.602E-19 joule') + ev.display_name = 'electron-volt' + end + end + describe '#name' do subject { super().name } - it {is_expected.to eq("")} + it { is_expected.to eq('') } end describe '#aliases' do subject { super().aliases } - it {is_expected.to eq(%w{eV electron-volt})} + it { is_expected.to eq(%w(eV electron-volt)) } end describe '#scalar' do subject { super().scalar } - it {is_expected.to eq(1.602E-19)} + it { is_expected.to eq(1.602E-19) } end describe '#numerator' do subject { super().numerator } - it {is_expected.to include("", "", "")} + it { is_expected.to include('', '', '') } end describe '#denominator' do subject { super().denominator } - it {is_expected.to include("", "")} + it { is_expected.to include('', '') } end describe '#display_name' do subject { super().display_name } - it {is_expected.to eq("electron-volt")} + it { is_expected.to eq('electron-volt') } end end diff --git a/spec/ruby-units/math_spec.rb b/spec/ruby-units/math_spec.rb index 64e3b874..69e0c6d8 100644 --- a/spec/ruby-units/math_spec.rb +++ b/spec/ruby-units/math_spec.rb @@ -1,22 +1,20 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Math do - - describe "#sqrt" do - specify { expect(Math.sqrt(Unit('1 mm^6'))).to eq(Unit('1 mm^3')) } + describe '#sqrt' do + specify { expect(Math.sqrt(RubyUnits::Unit.new('1 mm^6'))).to eq(RubyUnits::Unit.new('1 mm^3')) } specify { expect(Math.sqrt(4)).to eq(2) } - specify { expect(Math.sqrt(Unit("-9 mm^2"))).to be_kind_of(Complex) } + specify { expect(Math.sqrt(RubyUnits::Unit.new('-9 mm^2'))).to be_kind_of(Complex) } end describe '#cbrt' do - specify { expect(Math.cbrt(Unit('1 mm^6'))).to eq(Unit('1 mm^2')) } + specify { expect(Math.cbrt(RubyUnits::Unit.new('1 mm^6'))).to eq(RubyUnits::Unit.new('1 mm^2')) } specify { expect(Math.cbrt(8)).to eq(2) } end - context "Trigonometry functions" do - + context 'Trigonometry functions' do context "with '45 deg' unit" do - subject { Unit("45 deg") } + subject { RubyUnits::Unit.new('45 deg') } specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } @@ -26,7 +24,7 @@ end context "with 'PI/4 radians' unit" do - subject { Unit((Math::PI/4),'radians') } + subject { RubyUnits::Unit.new((Math::PI / 4), 'radians') } specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } @@ -36,7 +34,7 @@ end context "with 'PI/4' continues to work" do - subject { (Math::PI/4) } + subject { (Math::PI / 4) } specify { expect(Math.sin(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.cos(subject)).to be_within(0.01).of(0.70710678) } specify { expect(Math.tan(subject)).to be_within(0.01).of(1) } @@ -45,14 +43,33 @@ specify { expect(Math.tanh(subject)).to be_within(0.01).of(0.6557942026326724) } end - specify { expect(Math.hypot(Unit("1 m"), Unit("2 m"))).to be_within(Unit("0.01 m")).of(Unit("2.23607 m")) } - specify { expect(Math.hypot(Unit("1 m"), Unit("2 ft"))).to be_within(Unit("0.01 m")).of(Unit("1.17116 m")) } - specify { expect(Math.hypot(3,4)).to eq(5)} - specify { expect {Math.hypot(Unit("1 m"), Unit("2 lbs")) }.to raise_error(ArgumentError) } + specify do + expect( + Math.hypot( + RubyUnits::Unit.new('1 m'), + RubyUnits::Unit.new('2 m'))).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('2.23607 m')) + end + specify do + expect( + Math.hypot( + RubyUnits::Unit.new('1 m'), + RubyUnits::Unit.new('2 ft'))).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('1.17116 m')) + end + specify { expect(Math.hypot(3, 4)).to eq(5)} + specify do + expect { + Math.hypot( + RubyUnits::Unit.new('1 m'), + RubyUnits::Unit.new('2 lbs')) }.to raise_error(ArgumentError) + end - specify { expect(Math.atan2(Unit("1 m"), Unit("2 m"))).to be_within(0.01).of(0.4636476090008061) } - specify { expect(Math.atan2(Unit("1 m"), Unit("2 ft"))).to be_within(0.01).of(1.0233478888629426) } - specify { expect(Math.atan2(1,1)).to be_within(0.01).of(0.785398163397448)} - specify { expect {Math.atan2(Unit("1 m"), Unit("2 lbs"))}.to raise_error(ArgumentError) } + specify do + expect(Math.atan2(RubyUnits::Unit.new('1 m'), RubyUnits::Unit.new('2 m'))).to be_within(0.01).of(0.4636476090008061) + end + specify do + expect(Math.atan2(RubyUnits::Unit.new('1 m'), RubyUnits::Unit.new('2 ft'))).to be_within(0.01).of(1.0233478888629426) + end + specify { expect(Math.atan2(1, 1)).to be_within(0.01).of(0.785398163397448) } + specify { expect { Math.atan2(RubyUnits::Unit.new('1 m'), RubyUnits::Unit.new('2 lbs')) }.to raise_error(ArgumentError) } end end diff --git a/spec/ruby-units/object_spec.rb b/spec/ruby-units/object_spec.rb deleted file mode 100644 index 1050a25a..00000000 --- a/spec/ruby-units/object_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require File.dirname(__FILE__) + '/../spec_helper' - -describe Object do - specify { expect(Unit('1 mm')).to be_instance_of Unit} - specify { expect(U('1 mm')).to be_instance_of Unit} - specify { expect(u('1 mm')).to be_instance_of Unit} - specify { expect(Unit(0) + Unit(0)).to be_instance_of Unit} - specify { expect(Unit(0) - Unit(0)).to be_instance_of Unit} -end \ No newline at end of file diff --git a/spec/ruby-units/range_spec.rb b/spec/ruby-units/range_spec.rb index 245d98e5..38b1dd02 100644 --- a/spec/ruby-units/range_spec.rb +++ b/spec/ruby-units/range_spec.rb @@ -1,20 +1,19 @@ require File.dirname(__FILE__) + '/../spec_helper' -describe "Range" do - - context "of integer units" do - subject { (Unit('1 mm')..Unit('3 mm')) } - it { is_expected.to include(Unit('2 mm')) } +describe 'Range' do + context 'of integer units' do + subject { (RubyUnits::Unit.new('1 mm')..RubyUnits::Unit.new('3 mm')) } + it { is_expected.to include(RubyUnits::Unit.new('2 mm')) } describe '#to_a' do subject { super().to_a } - it { is_expected.to eq([ Unit('1 mm'), Unit('2 mm'), Unit('3 mm') ]) } + it { is_expected.to eq([RubyUnits::Unit.new('1 mm'), RubyUnits::Unit.new('2 mm'), RubyUnits::Unit.new('3 mm')]) } end end - - context "of floating point units" do - subject { (Unit('1.5 mm')..Unit('3.5 mm')) } - it { is_expected.to include(Unit('2.0 mm')) } - specify { expect { subject.to_a }.to raise_exception(ArgumentError)} + + context 'of floating point units' do + subject { (RubyUnits::Unit.new('1.5 mm')..RubyUnits::Unit.new('3.5 mm')) } + it { is_expected.to include(RubyUnits::Unit.new('2.0 mm')) } + specify { expect { subject.to_a }.to raise_exception(ArgumentError) } end -end \ No newline at end of file +end diff --git a/spec/ruby-units/string_spec.rb b/spec/ruby-units/string_spec.rb index a23fcdc1..eb55ea8e 100644 --- a/spec/ruby-units/string_spec.rb +++ b/spec/ruby-units/string_spec.rb @@ -3,15 +3,15 @@ describe String do context 'Unit creation from strings' do specify { expect('1 mm'.to_unit).to be_instance_of Unit } - specify { expect('1 m'.convert_to('ft')).to be_within(Unit.new('0.01 ft')).of Unit.new('3.28084 ft') } + specify { expect('1 m'.convert_to('ft')).to be_within(RubyUnits::Unit.new('0.01 ft')).of RubyUnits::Unit.new('3.28084 ft') } end context 'output format' do - subject { Unit('1.23456 m/s^2') } + subject { RubyUnits::Unit.new('1.23456 m/s^2') } specify { expect('' % subject).to eq('') } specify { expect('%0.2f' % subject).to eq('1.23 m/s^2') } specify { expect('%0.2f km/h^2' % subject).to eq('15999.90 km/h^2') } specify { expect('km/h^2' % subject).to eq('15999.9 km/h^2') } - specify { expect('%H:%M:%S' % Unit('1.5 h')).to eq('01:30:00') } + specify { expect('%H:%M:%S' % RubyUnits::Unit.new('1.5 h')).to eq('01:30:00') } end end diff --git a/spec/ruby-units/temperature_spec.rb b/spec/ruby-units/temperature_spec.rb index e11328cf..b0486447 100644 --- a/spec/ruby-units/temperature_spec.rb +++ b/spec/ruby-units/temperature_spec.rb @@ -3,112 +3,107 @@ describe 'temperatures' do describe 'redfine display name' do before(:all) do - Unit.redefine!("tempC") do |c| - c.aliases = %w{tC tempC} - c.display_name = "tC" + Unit.redefine!('tempC') do |c| + c.aliases = %w(tC tempC) + c.display_name = 'tC' end - Unit.redefine!("tempF") do |f| - f.aliases = %w{tF tempF} - f.display_name = "tF" + Unit.redefine!('tempF') do |f| + f.aliases = %w(tF tempF) + f.display_name = 'tF' end - Unit.redefine!("tempR") do |f| - f.aliases = %w{tR tempR} - f.display_name = "tR" + Unit.redefine!('tempR') do |f| + f.aliases = %w(tR tempR) + f.display_name = 'tR' end - Unit.redefine!("tempK") do |f| - f.aliases = %w{tK tempK} - f.display_name = "tK" + Unit.redefine!('tempK') do |f| + f.aliases = %w(tK tempK) + f.display_name = 'tK' end end - + after(:all) do - #define the temp units back to normal - Unit.define("tempK") do |unit| + # define the temp units back to normal + Unit.define('tempK') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{tempK} + unit.numerator = %w() + unit.aliases = %w(tempK) unit.kind = :temperature end - - Unit.define('tempC') do |tempC| - tempC.definition = Unit('1 tempK') + + Unit.define('tempC') do |tempc| + tempc.definition = RubyUnits::Unit.new('1 tempK') end - - temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 - - Unit.define('tempF') do |tempF| - tempF.definition = Unit(temp_convert_factor, 'tempK') + + temp_convert_factor = Rational(2_501_999_792_983_609, 4_503_599_627_370_496) # approximates 1/1.8 + + Unit.define('tempF') do |tempf| + tempf.definition = RubyUnits::Unit.new(temp_convert_factor, 'tempK') end - Unit.define('tempR') do |tempR| - tempR.definition = Unit('1 tempF') + Unit.define('tempR') do |tempr| + tempr.definition = RubyUnits::Unit.new('1 tempF') end end - - describe "Unit('100 tC')" do - subject {Unit("100 tC")} + + describe "RubyUnits::Unit.new('100 tC')" do + subject { RubyUnits::Unit.new('100 tC') } describe '#scalar' do subject { super().scalar } - it {is_expected.to be_within(0.001).of 100} + it { is_expected.to be_within(0.001).of 100 } end describe '#units' do subject { super().units } - it {is_expected.to eq("tC")} + it { is_expected.to eq('tC') } end describe '#kind' do subject { super().kind } - it {is_expected.to eq(:temperature)} + it { is_expected.to eq(:temperature) } end - it {is_expected.to be_temperature} - it {is_expected.to be_degree} - it {is_expected.not_to be_base} - it {is_expected.not_to be_unitless} - it {is_expected.not_to be_zero} + it { is_expected.to be_temperature } + it { is_expected.to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } describe '#base' do subject { super().base } - it {is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK")} + it { is_expected.to be_within(RubyUnits::Unit.new('0.01 degK')).of RubyUnits::Unit.new('373.15 tempK') } end describe '#temperature_scale' do subject { super().temperature_scale } - it {is_expected.to eq("degC")} + it { is_expected.to eq('degC') } end end - - context "between temperature scales" do + + context 'between temperature scales' do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - - specify { expect(Unit("100 tC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("0 tC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("37 tC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { expect(Unit("-273.15 tC")).to eq(Unit("0 tempK")) } - - specify { expect(Unit("212 tF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("32 tF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("98.6 tF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { expect(Unit("-459.67 tF")).to eq(Unit("0 tempK")) } - - specify { expect(Unit("671.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("491.67 tR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("558.27 tR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))} - specify { expect(Unit("0 tR")).to eq(Unit("0 tempK")) } - - specify { expect(Unit("100 tK").convert_to("tempC")).to be_within(U"0.01 degC").of(Unit("-173.15 tempC"))} - specify { expect(Unit("100 tK").convert_to("tempF")).to be_within(U"0.01 degF").of(Unit("-279.67 tempF"))} - specify { expect(Unit("100 tK").convert_to("tempR")).to be_within(U"0.01 degR").of(Unit("180 tempR"))} - end - - - + specify { expect(RubyUnits::Unit.new('100 tC')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('0 tC')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('37 tC')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('-273.15 tC')).to eq(RubyUnits::Unit.new('0 tempK')) } + + specify { expect(RubyUnits::Unit.new('212 tF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('32 tF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('98.6 tF')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('-459.67 tF')).to eq(RubyUnits::Unit.new('0 tempK')) } + + specify { expect(RubyUnits::Unit.new('671.67 tR')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('491.67 tR')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('558.27 tR')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('0 tR')).to eq(RubyUnits::Unit.new('0 tempK')) } + + specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempC')).to be_within(RubyUnits::Unit.new('0.01 degC')).of(RubyUnits::Unit.new('-173.15 tempC')) } + specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempF')).to be_within(RubyUnits::Unit.new('0.01 degF')).of(RubyUnits::Unit.new('-279.67 tempF')) } + specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempR')).to be_within(RubyUnits::Unit.new('0.01 degR')).of(RubyUnits::Unit.new('180 tempR')) } + end end end - \ No newline at end of file diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby-units/time_spec.rb index d60fbf8d..873536c5 100644 --- a/spec/ruby-units/time_spec.rb +++ b/spec/ruby-units/time_spec.rb @@ -45,13 +45,13 @@ context 'addition (+)' do specify { expect(Time.now + 1).to eq(Time.at(1303656390 + 1))} - specify { expect(Time.now + Unit("10 min")).to eq(Time.at(1303656390 + 600))} + specify { expect(Time.now + RubyUnits::Unit.new("10 min")).to eq(Time.at(1303656390 + 600))} end context 'subtraction (-)' do specify { expect(Time.now - 1).to eq(Time.at(1303656390 - 1))} - specify { expect(Time.now - Unit("10 min")).to eq(Time.at(1303656390 - 600))} - specify { expect(Time.now - Unit("150 years")).to eq(Time.parse("1861-04-24 09:46:30 -0500"))} + specify { expect(Time.now - RubyUnits::Unit.new("10 min")).to eq(Time.at(1303656390 - 600))} + specify { expect(Time.now - RubyUnits::Unit.new("150 years")).to eq(Time.parse("1861-04-24 09:46:30 -0500"))} end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index b29de8db..23b45494 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -6,16 +6,14 @@ it 'has 14 elements' do expect(subject.size).to eq(14) end - %w{kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte}.each do |u| - it { is_expected.to include(Unit(u)) } + %w(kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte).each do |u| + it { is_expected.to include(RubyUnits::Unit.new(u)) } end end - -describe "Create some simple units" do - +describe 'Create some simple units' do # zero string - describe Unit("0") do + describe RubyUnits::Unit.new('0') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -51,7 +49,7 @@ end # non-zero string - describe Unit("1") do + describe RubyUnits::Unit.new('1') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -87,7 +85,7 @@ end # numeric - describe Unit(1) do + describe RubyUnits::Unit.new(1) do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -123,7 +121,7 @@ end # rational - describe Unit(Rational(1, 2)) do + describe RubyUnits::Unit.new(Rational(1, 2)) do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -159,7 +157,7 @@ end # float - describe Unit(0.5) do + describe RubyUnits::Unit.new(0.5) do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -195,7 +193,7 @@ end # complex - describe Unit(Complex(1, 1)) do + describe RubyUnits::Unit.new(Complex(1, 1)) do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -230,7 +228,7 @@ end end - describe Unit("1+1i m") do + describe RubyUnits::Unit.new('1+1i m') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -246,7 +244,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("m") } + it { is_expected.to eq('m') } end describe '#kind' do @@ -266,7 +264,7 @@ end # scalar and unit - describe Unit("1 mm") do + describe RubyUnits::Unit.new('1 mm') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -297,12 +295,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("0.001 m")) } + it { is_expected.to eq(RubyUnits::Unit.new("0.001 m")) } end end # with a zero power - describe Unit("1 m^0") do + describe RubyUnits::Unit.new("1 m^0") do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -333,12 +331,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("1")) } + it { is_expected.to eq(RubyUnits::Unit.new("1")) } end end # unit only - describe Unit("mm") do + describe RubyUnits::Unit.new("mm") do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -369,12 +367,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("0.001 m")) } + it { is_expected.to eq(RubyUnits::Unit.new("0.001 m")) } end end # Compound unit - describe Unit("1 N*m") do + describe RubyUnits::Unit.new("1 N*m") do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -405,12 +403,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("1 kg*m^2/s^2")) } + it { is_expected.to eq(RubyUnits::Unit.new("1 kg*m^2/s^2")) } end end # scalar and unit with powers - describe Unit("10 m/s^2") do + describe RubyUnits::Unit.new("10 m/s^2") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -440,12 +438,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("10 m/s^2")) } + it { is_expected.to eq(RubyUnits::Unit.new("10 m/s^2")) } end end # feet/in form - describe Unit("5ft 6in") do + describe RubyUnits::Unit.new("5ft 6in") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -470,13 +468,13 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(Unit("0.01 m")).of Unit("1.6764 m") } + it { is_expected.to be_within(RubyUnits::Unit.new("0.01 m")).of RubyUnits::Unit.new("1.6764 m") } end specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } end # pound/ounces form - describe Unit("6lbs 5oz") do + describe RubyUnits::Unit.new("6lbs 5oz") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -501,13 +499,13 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(Unit("0.01 kg")).of Unit("2.8633 kg") } + it { is_expected.to be_within(RubyUnits::Unit.new("0.01 kg")).of RubyUnits::Unit.new("2.8633 kg") } end specify { expect(subject.to_s(:lbs)).to eq("6 lbs, 5 oz") } end # temperature - describe Unit("100 tempC") do + describe RubyUnits::Unit.new("100 tempC") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -532,7 +530,7 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(Unit("0.01 degK")).of Unit("373.15 tempK") } + it { is_expected.to be_within(RubyUnits::Unit.new("0.01 degK")).of RubyUnits::Unit.new("373.15 tempK") } end describe '#temperature_scale' do @@ -542,7 +540,7 @@ end # Time - describe Unit(Time.now) do + describe RubyUnits::Unit.new(Time.now) do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -577,7 +575,7 @@ end # degrees - describe Unit("100 degC") do + describe RubyUnits::Unit.new("100 degC") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -601,12 +599,12 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(Unit("0.01 degK")).of Unit("100 degK") } + it { is_expected.to be_within(RubyUnits::Unit.new("0.01 degK")).of RubyUnits::Unit.new("100 degK") } end end # percent - describe Unit("75%") do + describe RubyUnits::Unit.new("75%") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -641,7 +639,7 @@ end # angle - describe Unit("180 deg") do + describe RubyUnits::Unit.new("180 deg") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -676,7 +674,7 @@ end # radians - describe Unit("1 radian") do + describe RubyUnits::Unit.new("1 radian") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -711,7 +709,7 @@ end # counting - describe Unit("12 dozen") do + describe RubyUnits::Unit.new("12 dozen") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -746,7 +744,7 @@ end # rational scalar with unit - describe Unit("1/2 kg") do + describe RubyUnits::Unit.new("1/2 kg") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -781,7 +779,7 @@ end # rational scalar with compound unit - describe Unit("1/2 kg/m") do + describe RubyUnits::Unit.new("1/2 kg/m") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -853,9 +851,9 @@ end # time string - describe Unit("1:23:45,200") do + describe RubyUnits::Unit.new('1:23:45,200') do it { is_expected.to be_an_instance_of Unit } - it { is_expected.to eq(Unit("1 h") + Unit("23 min") + Unit("45 seconds") + Unit("200 usec")) } + it { is_expected.to eq(RubyUnits::Unit.new("1 h") + RubyUnits::Unit.new("23 min") + RubyUnits::Unit.new("45 seconds") + RubyUnits::Unit.new("200 usec")) } describe '#scalar' do subject { super().scalar } @@ -925,7 +923,7 @@ end # funky unit - describe Unit("1 attoparsec/microfortnight") do + describe RubyUnits::Unit.new("1 attoparsec/microfortnight") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -957,11 +955,11 @@ subject { super().temperature_scale } it { is_expected.to be_nil } end - it { expect(subject.convert_to("in/s")).to be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s")) } + it { expect(subject.convert_to("in/s")).to be_within(RubyUnits::Unit.new("0.0001 in/s")).of(RubyUnits::Unit.new("1.0043269330917 in/s")) } end # Farads - describe Unit("1 F") do + describe RubyUnits::Unit.new("1 F") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -995,7 +993,7 @@ end end - describe Unit("1 m^2 s^-2") do + describe RubyUnits::Unit.new("1 m^2 s^-2") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1029,7 +1027,7 @@ end end - describe Unit(1, "m^2", "s^2") do + describe RubyUnits::Unit.new(1, "m^2", "s^2") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1064,7 +1062,7 @@ end #scientific notation - describe Unit("1e6 cells") do + describe RubyUnits::Unit.new("1e6 cells") do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1104,7 +1102,7 @@ end #could be m*m - describe Unit("1 mm") do + describe RubyUnits::Unit.new("1 mm") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:length) } @@ -1112,7 +1110,7 @@ end #could be centi-day - describe Unit("1 cd") do + describe RubyUnits::Unit.new("1 cd") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:luminous_power) } @@ -1120,7 +1118,7 @@ end # could be milli-inch - describe Unit("1 min") do + describe RubyUnits::Unit.new("1 min") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:time) } @@ -1128,7 +1126,7 @@ end #could be femto-tons - describe Unit("1 ft") do + describe RubyUnits::Unit.new("1 ft") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:length) } @@ -1136,7 +1134,7 @@ end #could be deci-ounce - describe Unit("1 doz") do + describe RubyUnits::Unit.new("1 doz") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:unitless) } @@ -1144,10 +1142,10 @@ end # create with another unit - describe 10.unit(Unit("1 mm")) do + describe 10.to_unit(RubyUnits::Unit.new("1 mm")) do describe '#units' do subject { super().units } - it { is_expected.to eq("mm") } + it { is_expected.to eq('mm') } end describe '#scalar' do @@ -1157,7 +1155,7 @@ end #explicit create - describe Unit("1 /") do + describe RubyUnits::Unit.new("1 /") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:speed) } @@ -1169,7 +1167,7 @@ end end - describe Unit("1 /") do + describe RubyUnits::Unit.new("1 /") do describe '#kind' do subject { super().kind } it { is_expected.to eq(:yank) } @@ -1182,16 +1180,16 @@ end # without spaces - describe Unit('1g') do - specify { expect(subject).to eq(Unit('1 g')) } + describe RubyUnits::Unit.new('1g') do + specify { expect(subject).to eq(RubyUnits::Unit.new('1 g')) } end - describe Unit('-1g') do - specify { expect(subject).to eq(Unit('-1 g')) } + describe RubyUnits::Unit.new('-1g') do + specify { expect(subject).to eq(RubyUnits::Unit.new('-1 g')) } end - describe Unit('11/s') do - specify { expect(subject).to eq(Unit('11 1/s')) } + describe RubyUnits::Unit.new('11/s') do + specify { expect(subject).to eq(RubyUnits::Unit.new('11 1/s')) } end describe Unit.new("63.5029318kg") do @@ -1220,67 +1218,67 @@ describe "Unit handles attempts to create bad units" do specify "no empty strings" do - expect { Unit("") }.to raise_error(ArgumentError, "No Unit Specified") + expect { RubyUnits::Unit.new("") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no blank strings" do - expect { Unit(" ") }.to raise_error(ArgumentError, "No Unit Specified") + expect { RubyUnits::Unit.new(" ") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no strings with tabs" do - expect { Unit("\t") }.to raise_error(ArgumentError, "No Unit Specified") + expect { RubyUnits::Unit.new("\t") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no strings with newlines" do - expect { Unit("\n") }.to raise_error(ArgumentError, "No Unit Specified") + expect { RubyUnits::Unit.new("\n") }.to raise_error(ArgumentError, "No Unit Specified") end specify "no double slashes" do - expect { Unit("3 s/s/ft") }.to raise_error(ArgumentError, /Unit not recognized/) + expect { RubyUnits::Unit.new("3 s/s/ft") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no pipes or commas" do - expect { Unit("3 s**2|,s**2") }.to raise_error(ArgumentError, /Unit not recognized/) + expect { RubyUnits::Unit.new("3 s**2|,s**2") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no multiple spaces" do - expect { Unit("3 s**2 4s s**2") }.to raise_error(ArgumentError, /Unit not recognized/) + expect { RubyUnits::Unit.new("3 s**2 4s s**2") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no exponentiation of numbers" do - expect { Unit("3 s 5^6") }.to raise_error(ArgumentError, /Unit not recognized/) + expect { RubyUnits::Unit.new("3 s 5^6") }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no strings that don't specify a valid unit" do - expect { Unit("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") + expect { RubyUnits::Unit.new("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") end specify "no unhandled classes" do - expect { Unit(STDIN) }.to raise_error(ArgumentError, "Invalid Unit Format") + expect { RubyUnits::Unit.new(STDIN) }.to raise_error(ArgumentError, "Invalid Unit Format") end specify "no undefined units" do - expect { Unit("1 mFoo") }.to raise_error(ArgumentError, "'1 mFoo' Unit not recognized") - expect { Unit("1 second/mFoo") }.to raise_error(ArgumentError, "'1 second/mFoo' Unit not recognized") + expect { RubyUnits::Unit.new("1 mFoo") }.to raise_error(ArgumentError, "'1 mFoo' Unit not recognized") + expect { RubyUnits::Unit.new("1 second/mFoo") }.to raise_error(ArgumentError, "'1 second/mFoo' Unit not recognized") end specify "no units with powers greater than 19" do - expect { Unit("1 m^20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + expect { RubyUnits::Unit.new("1 m^20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") end specify "no units with powers less than 19" do - expect { Unit("1 m^-20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + expect { RubyUnits::Unit.new("1 m^-20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") end specify "no temperatures less than absolute zero" do - expect { Unit("-100 tempK") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") - expect { Unit("-100 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") - expect { Unit("-500/9 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + expect { RubyUnits::Unit.new("-100 tempK") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + expect { RubyUnits::Unit.new("-100 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + expect { RubyUnits::Unit.new("-500/9 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") end specify "no nil scalar" do - expect { Unit(nil, "feet") }.to raise_error(ArgumentError, "Invalid Unit Format") - expect { Unit(nil, "feet", "min") }.to raise_error(ArgumentError, "Invalid Unit Format") + expect { RubyUnits::Unit.new(nil, "feet") }.to raise_error(ArgumentError, "Invalid Unit Format") + expect { RubyUnits::Unit.new(nil, "feet", "min") }.to raise_error(ArgumentError, "Invalid Unit Format") end specify 'no double prefixes' do @@ -1313,7 +1311,7 @@ end describe '#to_yaml' do - subject { Unit('1 mm') } + subject { RubyUnits::Unit.new('1 mm') } describe '#to_yaml' do subject { super().to_yaml } @@ -1361,9 +1359,9 @@ Unit.undefine!('jiffy') end - describe "Unit('1e6 jiffy')" do + describe "RubyUnits::Unit.new('1e6 jiffy')" do # do this because the unit is not defined at the time this file is parsed, so it fails - subject { Unit("1e6 jiffy") } + subject { RubyUnits::Unit.new("1e6 jiffy") } it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -1395,7 +1393,7 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(Unit("10000 s")) } + it { is_expected.to eq(RubyUnits::Unit.new("10000 s")) } end end @@ -1418,9 +1416,9 @@ end end - describe "Unit('1 cup')" do + describe "RubyUnits::Unit.new('1 cup')" do # do this because the unit is going to be redefined - subject { Unit("1 cup") } + subject { RubyUnits::Unit.new("1 cup") } it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -1473,7 +1471,7 @@ Unit.undefine!("jiffy") end - specify { expect(Unit('1 jiffy').to_base.scalar).to eq(1/1000) } + specify { expect(RubyUnits::Unit.new('1 jiffy').to_base.scalar).to eq(1/1000) } end describe '#undefine!' do @@ -1492,7 +1490,7 @@ end specify "attempting to use an undefined unit fails" do - expect { Unit("1 jiffy") }.to raise_exception(ArgumentError) + expect { RubyUnits::Unit.new("1 jiffy") }.to raise_exception(ArgumentError) end it "should return true when undefining an unknown unit" do @@ -1503,7 +1501,7 @@ end describe '#clone' do - subject { Unit('1 mm') } + subject { RubyUnits::Unit.new('1 mm') } describe '#clone' do subject { super().clone } @@ -1514,92 +1512,92 @@ describe "Unit Comparisons" do context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do - specify { expect(Unit("1 ft") =~ Unit('1 m')).to be true } - specify { expect(Unit("1 ft") =~ "m").to be true } - specify { expect(Unit("1 ft")).to be_compatible_with Unit('1 m') } - specify { expect(Unit("1 ft")).to be_compatible_with "m" } - specify { expect(Unit("1 m")).to be_compatible_with Unit('1 kg*m/kg') } - specify { expect(Unit("1 ft") =~ Unit('1 kg')).to be false } - specify { expect(Unit("1 ft")).not_to be_compatible_with Unit('1 kg') } - specify { expect(Unit("1 ft")).not_to be_compatible_with nil } + specify { expect(RubyUnits::Unit.new("1 ft") =~ RubyUnits::Unit.new('1 m')).to be true } + specify { expect(RubyUnits::Unit.new("1 ft") =~ "m").to be true } + specify { expect(RubyUnits::Unit.new("1 ft")).to be_compatible_with RubyUnits::Unit.new('1 m') } + specify { expect(RubyUnits::Unit.new("1 ft")).to be_compatible_with "m" } + specify { expect(RubyUnits::Unit.new("1 m")).to be_compatible_with RubyUnits::Unit.new('1 kg*m/kg') } + specify { expect(RubyUnits::Unit.new("1 ft") =~ RubyUnits::Unit.new('1 kg')).to be false } + specify { expect(RubyUnits::Unit.new("1 ft")).not_to be_compatible_with RubyUnits::Unit.new('1 kg') } + specify { expect(RubyUnits::Unit.new("1 ft")).not_to be_compatible_with nil } end context "Equality" do context "with uncoercable objects" do - specify { expect(Unit("1 mm")).not_to eq(nil) } + specify { expect(RubyUnits::Unit.new("1 mm")).not_to eq(nil) } end context "units of same kind" do - specify { expect(Unit("1000 m")).to eq(Unit('1 km')) } - specify { expect(Unit("100 m")).not_to eq(Unit('1 km')) } - specify { expect(Unit("1 m")).to eq(Unit('100 cm')) } + specify { expect(RubyUnits::Unit.new("1000 m")).to eq(RubyUnits::Unit.new('1 km')) } + specify { expect(RubyUnits::Unit.new("100 m")).not_to eq(RubyUnits::Unit.new('1 km')) } + specify { expect(RubyUnits::Unit.new("1 m")).to eq(RubyUnits::Unit.new('100 cm')) } end context "units of incompatible types" do - specify { expect(Unit("1 m")).not_to eq(Unit("1 kg")) } + specify { expect(RubyUnits::Unit.new("1 m")).not_to eq(RubyUnits::Unit.new("1 kg")) } end context "units with a zero scalar are equal" do - specify { expect(Unit("0 m")).to eq(Unit("0 s")) } - specify { expect(Unit("0 m")).to eq(Unit("0 kg")) } + specify { expect(RubyUnits::Unit.new("0 m")).to eq(RubyUnits::Unit.new("0 s")) } + specify { expect(RubyUnits::Unit.new("0 m")).to eq(RubyUnits::Unit.new("0 kg")) } context "except for temperature units" do - specify { expect(Unit("0 tempK")).to eq(Unit("0 m")) } - specify { expect(Unit("0 tempR")).to eq(Unit("0 m")) } - specify { expect(Unit("0 tempC")).not_to eq(Unit("0 m")) } - specify { expect(Unit("0 tempF")).not_to eq(Unit("0 m")) } + specify { expect(RubyUnits::Unit.new("0 tempK")).to eq(RubyUnits::Unit.new("0 m")) } + specify { expect(RubyUnits::Unit.new("0 tempR")).to eq(RubyUnits::Unit.new("0 m")) } + specify { expect(RubyUnits::Unit.new("0 tempC")).not_to eq(RubyUnits::Unit.new("0 m")) } + specify { expect(RubyUnits::Unit.new("0 tempF")).not_to eq(RubyUnits::Unit.new("0 m")) } end end end context "Equivalence" do context "units and scalars are the exactly the same" do - specify { expect(Unit("1 m")).to be === Unit("1 m") } - specify { expect(Unit("1 m")).to be_same Unit("1 m") } - specify { expect(Unit("1 m")).to be_same_as Unit("1 m") } + specify { expect(RubyUnits::Unit.new("1 m")).to be === RubyUnits::Unit.new("1 m") } + specify { expect(RubyUnits::Unit.new("1 m")).to be_same RubyUnits::Unit.new("1 m") } + specify { expect(RubyUnits::Unit.new("1 m")).to be_same_as RubyUnits::Unit.new("1 m") } end context "units are compatible but not identical" do - specify { expect(Unit("1000 m")).not_to be === Unit("1 km") } - specify { expect(Unit("1000 m")).not_to be_same Unit("1 km") } - specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 km") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be === RubyUnits::Unit.new("1 km") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same RubyUnits::Unit.new("1 km") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same_as RubyUnits::Unit.new("1 km") } end context "units are not compatible" do - specify { expect(Unit("1000 m")).not_to be === Unit("1 hour") } - specify { expect(Unit("1000 m")).not_to be_same Unit("1 hour") } - specify { expect(Unit("1000 m")).not_to be_same_as Unit("1 hour") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be === RubyUnits::Unit.new("1 hour") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same RubyUnits::Unit.new("1 hour") } + specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same_as RubyUnits::Unit.new("1 hour") } end context "scalars are different" do - specify { expect(Unit("1 m")).not_to be === Unit("2 m") } - specify { expect(Unit("1 m")).not_to be_same Unit("2 m") } - specify { expect(Unit("1 m")).not_to be_same_as Unit("2 m") } + specify { expect(RubyUnits::Unit.new("1 m")).not_to be === RubyUnits::Unit.new("2 m") } + specify { expect(RubyUnits::Unit.new("1 m")).not_to be_same RubyUnits::Unit.new("2 m") } + specify { expect(RubyUnits::Unit.new("1 m")).not_to be_same_as RubyUnits::Unit.new("2 m") } end - specify { expect(Unit("1 m")).not_to be === nil } + specify { expect(RubyUnits::Unit.new("1 m")).not_to be === nil } end context "Comparisons" do context "compatible units can be compared" do - specify { expect(Unit("1 m")).to be < Unit("2 m") } - specify { expect(Unit("2 m")).to be > Unit("1 m") } - specify { expect(Unit("1 m")).to be < Unit("1 mi") } - specify { expect(Unit("2 m")).to be > Unit("1 ft") } - specify { expect(Unit("70 tempF")).to be > Unit("10 degC") } - specify { expect(Unit("1 m")).to be > 0 } - specify { expect { Unit("1 m") > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + specify { expect(RubyUnits::Unit.new("1 m")).to be < RubyUnits::Unit.new("2 m") } + specify { expect(RubyUnits::Unit.new("2 m")).to be > RubyUnits::Unit.new("1 m") } + specify { expect(RubyUnits::Unit.new("1 m")).to be < RubyUnits::Unit.new("1 mi") } + specify { expect(RubyUnits::Unit.new("2 m")).to be > RubyUnits::Unit.new("1 ft") } + specify { expect(RubyUnits::Unit.new("70 tempF")).to be > RubyUnits::Unit.new("10 degC") } + specify { expect(RubyUnits::Unit.new("1 m")).to be > 0 } + specify { expect { RubyUnits::Unit.new("1 m") > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end context "incompatible units cannot be compared" do - specify { expect { Unit("1 m") < Unit("1 liter") }.to raise_error(ArgumentError, "Incompatible Units ('m' not compatible with 'l')") } - specify { expect { Unit("1 kg") > Unit("60 mph") }.to raise_error(ArgumentError, "Incompatible Units ('kg' not compatible with 'mph')") } + specify { expect { RubyUnits::Unit.new("1 m") < RubyUnits::Unit.new("1 liter") }.to raise_error(ArgumentError, "Incompatible Units ('m' not compatible with 'l')") } + specify { expect { RubyUnits::Unit.new("1 kg") > RubyUnits::Unit.new("60 mph") }.to raise_error(ArgumentError, "Incompatible Units ('kg' not compatible with 'mph')") } end context "with coercions should be valid" do - specify { expect(Unit("1GB") > "500MB").to eq(true) } - specify { expect(Unit("0.5GB") < "900MB").to eq(true) } + specify { expect(RubyUnits::Unit.new("1GB") > "500MB").to eq(true) } + specify { expect(RubyUnits::Unit.new("0.5GB") < "900MB").to eq(true) } end end @@ -1608,54 +1606,54 @@ describe "Unit Conversions" do context "between compatible units" do - specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } - specify { expect(Unit("1 s").convert_to("ns")).to eq(Unit("1e9 ns")) } - specify { expect(Unit("1 s") >> "ns").to eq(Unit("1e9 ns")) } + specify { expect(RubyUnits::Unit.new("1 s").convert_to("ns")).to eq(RubyUnits::Unit.new("1e9 ns")) } + specify { expect(RubyUnits::Unit.new("1 s").convert_to("ns")).to eq(RubyUnits::Unit.new("1e9 ns")) } + specify { expect(RubyUnits::Unit.new("1 s") >> "ns").to eq(RubyUnits::Unit.new("1e9 ns")) } - specify { expect(Unit("1 m").convert_to(Unit("ft"))).to be_within(Unit("0.001 ft")).of(Unit("3.28084 ft")) } + specify { expect(RubyUnits::Unit.new("1 m").convert_to(RubyUnits::Unit.new("ft"))).to be_within(RubyUnits::Unit.new("0.001 ft")).of(RubyUnits::Unit.new("3.28084 ft")) } end context "between incompatible units" do - specify { expect { Unit("1 s").convert_to("m") }.to raise_error(ArgumentError, "Incompatible Units ('1 s' not compatible with 'm')") } + specify { expect { RubyUnits::Unit.new("1 s").convert_to("m") }.to raise_error(ArgumentError, "Incompatible Units ('1 s' not compatible with 'm')") } end context "given bad input" do - specify { expect { Unit("1 m").convert_to("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") } - specify { expect { Unit("1 m").convert_to(STDOUT) }.to raise_error(ArgumentError, "Unknown target units") } + specify { expect { RubyUnits::Unit.new("1 m").convert_to("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") } + specify { expect { RubyUnits::Unit.new("1 m").convert_to(STDOUT) }.to raise_error(ArgumentError, "Unknown target units") } end context "between temperature scales" do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. - specify { expect(Unit("100 tempC")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("0 tempC")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("37 tempC")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { expect(Unit("-273.15 tempC")).to eq(Unit("0 tempK")) } + specify { expect(RubyUnits::Unit.new('100 tempC')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('0 tempC')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('37 tempC')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('-273.15 tempC')).to eq(RubyUnits::Unit.new('0 tempK')) } - specify { expect(Unit("212 tempF")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("32 tempF")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("98.6 tempF")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { expect(Unit("-459.67 tempF")).to eq(Unit("0 tempK")) } + specify { expect(RubyUnits::Unit.new('212 tempF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('32 tempF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('98.6 tempF')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('-459.67 tempF')).to eq(RubyUnits::Unit.new('0 tempK')) } - specify { expect(Unit("671.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) } - specify { expect(Unit("491.67 tempR")).to be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) } - specify { expect(Unit("558.27 tempR")).to be_within(Unit("0.01 degK")).of(Unit("310.15 tempK")) } - specify { expect(Unit("0 tempR")).to eq(Unit("0 tempK")) } + specify { expect(RubyUnits::Unit.new('671.67 tempR')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('373.15 tempK')) } + specify { expect(RubyUnits::Unit.new('491.67 tempR')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('273.15 tempK')) } + specify { expect(RubyUnits::Unit.new('558.27 tempR')).to be_within(RubyUnits::Unit.new('0.01 degK')).of(RubyUnits::Unit.new('310.15 tempK')) } + specify { expect(RubyUnits::Unit.new('0 tempR')).to eq(RubyUnits::Unit.new('0 tempK')) } - specify { expect(Unit("100 tempK").convert_to("tempC")).to be_within(U "0.01 degC").of(Unit("-173.15 tempC")) } - specify { expect(Unit("100 tempK").convert_to("tempF")).to be_within(U "0.01 degF").of(Unit("-279.67 tempF")) } - specify { expect(Unit("100 tempK").convert_to("tempR")).to be_within(U "0.01 degR").of(Unit("180 tempR")) } + specify { expect(RubyUnits::Unit.new('100 tempK').convert_to('tempC')).to be_within(RubyUnits::Unit.new('0.01 degC')).of(RubyUnits::Unit.new('-173.15 tempC')) } + specify { expect(RubyUnits::Unit.new('100 tempK').convert_to('tempF')).to be_within(RubyUnits::Unit.new('0.01 degF')).of(RubyUnits::Unit.new('-279.67 tempF')) } + specify { expect(RubyUnits::Unit.new('100 tempK').convert_to('tempR')).to be_within(RubyUnits::Unit.new('0.01 degR')).of(RubyUnits::Unit.new('180 tempR')) } - specify { expect(Unit("1 degC")).to eq(Unit("1 degK")) } - specify { expect(Unit("1 degF")).to eq(Unit("1 degR")) } - specify { expect(Unit("1 degC")).to eq(Unit("1.8 degR")) } - specify { expect(Unit("1 degF")).to be_within(Unit("0.001 degK")).of(Unit("0.5555 degK")) } + specify { expect(RubyUnits::Unit.new('1 degC')).to eq(RubyUnits::Unit.new('1 degK')) } + specify { expect(RubyUnits::Unit.new('1 degF')).to eq(RubyUnits::Unit.new('1 degR')) } + specify { expect(RubyUnits::Unit.new('1 degC')).to eq(RubyUnits::Unit.new('1.8 degR')) } + specify { expect(RubyUnits::Unit.new('1 degF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('0.5555 degK')) } end context "reported bugs" do - specify { expect(Unit("189 Mtonne") * Unit("1189 g/tonne")).to eq(Unit("224721 tonne")) } - specify { expect((Unit("189 Mtonne") * Unit("1189 g/tonne")).convert_to("tonne")).to eq(Unit("224721 tonne")) } + specify { expect(RubyUnits::Unit.new("189 Mtonne") * RubyUnits::Unit.new("1189 g/tonne")).to eq(RubyUnits::Unit.new("224721 tonne")) } + specify { expect((RubyUnits::Unit.new("189 Mtonne") * RubyUnits::Unit.new("1189 g/tonne")).convert_to("tonne")).to eq(RubyUnits::Unit.new("224721 tonne")) } end describe "Foot-inch conversions" do @@ -1669,8 +1667,8 @@ ["88 in", %Q{7'4"}], ["89 in", %Q{7'5"}] ].each do |inches, feet| - specify { expect(Unit(inches).convert_to("ft")).to eq(Unit(feet)) } - specify { expect(Unit(inches).to_s(:ft)).to eq(feet) } + specify { expect(RubyUnits::Unit.new(inches).convert_to("ft")).to eq(RubyUnits::Unit.new(feet)) } + specify { expect(RubyUnits::Unit.new(inches).to_s(:ft)).to eq(feet) } end end @@ -1685,8 +1683,8 @@ ["88 oz", "5 lbs, 8 oz"], ["89 oz", "5 lbs, 9 oz"] ].each do |ounces, pounds| - specify { expect(Unit(ounces).convert_to("lbs")).to eq(Unit(pounds)) } - specify { expect(Unit(ounces).to_s(:lbs)).to eq(pounds) } + specify { expect(RubyUnits::Unit.new(ounces).convert_to("lbs")).to eq(RubyUnits::Unit.new(pounds)) } + specify { expect(RubyUnits::Unit.new(ounces).to_s(:lbs)).to eq(pounds) } end end end @@ -1695,176 +1693,176 @@ context "operators:" do context "addition (+)" do context "between compatible units" do - specify { expect(Unit("0 m") + Unit("10 m")).to eq(Unit("10 m")) } - specify { expect(Unit("5 kg") + Unit("10 kg")).to eq(Unit("15 kg")) } + specify { expect(RubyUnits::Unit.new("0 m") + RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("10 m")) } + specify { expect(RubyUnits::Unit.new("5 kg") + RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("15 kg")) } end context "between a zero unit and another unit" do - specify { expect(Unit("0 kg") + Unit("10 m")).to eq(Unit("10 m")) } - specify { expect(Unit("0 m") + Unit("10 kg")).to eq(Unit("10 kg")) } + specify { expect(RubyUnits::Unit.new("0 kg") + RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("10 m")) } + specify { expect(RubyUnits::Unit.new("0 m") + RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("10 kg")) } end context "between incompatible units" do - specify { expect { Unit("10 kg") + Unit("10 m") }.to raise_error(ArgumentError) } - specify { expect { Unit("10 m") + Unit("10 kg") }.to raise_error(ArgumentError) } - specify { expect { Unit("10 m") + nil }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 kg") + RubyUnits::Unit.new("10 m") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 m") + RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 m") + nil }.to raise_error(ArgumentError) } end context "a number from a unit" do - specify { expect { Unit("10 kg") + 1 }.to raise_error(ArgumentError) } - specify { expect { 10 + Unit("10 kg") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 kg") + 1 }.to raise_error(ArgumentError) } + specify { expect { 10 + RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { expect(Unit('10 kg') + %w{1 kg}).to eq(Unit('11 kg')) } - specify { expect(Unit('10 kg') + "1 kg").to eq(Unit('11 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') + %w{1 kg}).to eq(RubyUnits::Unit.new('11 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') + "1 kg").to eq(RubyUnits::Unit.new('11 kg')) } end context "between two temperatures" do - specify { expect { (Unit("100 tempK") + Unit("100 tempK")) }.to raise_error(ArgumentError, "Cannot add two temperatures") } + specify { expect { (RubyUnits::Unit.new("100 tempK") + RubyUnits::Unit.new("100 tempK")) }.to raise_error(ArgumentError, "Cannot add two temperatures") } end context "between a temperature and a degree" do - specify { expect(Unit("100 tempK") + Unit("100 degK")).to eq(Unit("200 tempK")) } + specify { expect(RubyUnits::Unit.new("100 tempK") + RubyUnits::Unit.new("100 degK")).to eq(RubyUnits::Unit.new("200 tempK")) } end context "between a degree and a temperature" do - specify { expect(Unit("100 degK") + Unit("100 tempK")).to eq(Unit("200 tempK")) } + specify { expect(RubyUnits::Unit.new("100 degK") + RubyUnits::Unit.new("100 tempK")).to eq(RubyUnits::Unit.new("200 tempK")) } end end context "subtracting (-)" do context "compatible units" do - specify { expect(Unit("0 m") - Unit("10 m")).to eq(Unit("-10 m")) } - specify { expect(Unit("5 kg") - Unit("10 kg")).to eq(Unit("-5 kg")) } + specify { expect(RubyUnits::Unit.new("0 m") - RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("-10 m")) } + specify { expect(RubyUnits::Unit.new("5 kg") - RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("-5 kg")) } end context "a unit from a zero unit" do - specify { expect(Unit("0 kg") - Unit("10 m")).to eq(Unit("-10 m")) } - specify { expect(Unit("0 m") - Unit("10 kg")).to eq(Unit("-10 kg")) } + specify { expect(RubyUnits::Unit.new("0 kg") - RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("-10 m")) } + specify { expect(RubyUnits::Unit.new("0 m") - RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("-10 kg")) } end context "incompatible units" do - specify { expect { Unit("10 kg") - Unit("10 m") }.to raise_error(ArgumentError) } - specify { expect { Unit("10 m") - Unit("10 kg") }.to raise_error(ArgumentError) } - specify { expect { Unit("10 m") - nil }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 kg") - RubyUnits::Unit.new("10 m") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 m") - RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 m") - nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { expect(Unit('10 kg') - %w{1 kg}).to eq(Unit('9 kg')) } - specify { expect(Unit('10 kg') - "1 kg").to eq(Unit('9 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') - %w{1 kg}).to eq(RubyUnits::Unit.new('9 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') - "1 kg").to eq(RubyUnits::Unit.new('9 kg')) } end context "a number from a unit" do - specify { expect { Unit("10 kg") - 1 }.to raise_error(ArgumentError) } - specify { expect { 10 - Unit("10 kg") }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new("10 kg") - 1 }.to raise_error(ArgumentError) } + specify { expect { 10 - RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } end context "between two temperatures" do - specify { expect(Unit("100 tempK") - Unit("100 tempK")).to eq(Unit("0 degK")) } + specify { expect(RubyUnits::Unit.new("100 tempK") - RubyUnits::Unit.new("100 tempK")).to eq(RubyUnits::Unit.new("0 degK")) } end context "between a temperature and a degree" do - specify { expect(Unit("100 tempK") - Unit("100 degK")).to eq(Unit("0 tempK")) } + specify { expect(RubyUnits::Unit.new("100 tempK") - RubyUnits::Unit.new("100 degK")).to eq(RubyUnits::Unit.new("0 tempK")) } end context "between a degree and a temperature" do - specify { expect { (Unit("100 degK") - Unit("100 tempK")) }.to raise_error(ArgumentError, "Cannot subtract a temperature from a differential degree unit") } + specify { expect { (RubyUnits::Unit.new("100 degK") - RubyUnits::Unit.new("100 tempK")) }.to raise_error(ArgumentError, "Cannot subtract a temperature from a differential degree unit") } end end context "multiplying (*)" do context "between compatible units" do - specify { expect(Unit("0 m") * Unit("10 m")).to eq(Unit("0 m^2")) } - specify { expect(Unit("5 kg") * Unit("10 kg")).to eq(Unit("50 kg^2")) } + specify { expect(RubyUnits::Unit.new("0 m") * RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("0 m^2")) } + specify { expect(RubyUnits::Unit.new("5 kg") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("50 kg^2")) } end context "between incompatible units" do - specify { expect(Unit("0 m") * Unit("10 kg")).to eq(Unit("0 kg*m")) } - specify { expect(Unit("5 m") * Unit("10 kg")).to eq(Unit("50 kg*m")) } - specify { expect { Unit("10 m") * nil }.to raise_error(ArgumentError) } + specify { expect(RubyUnits::Unit.new("0 m") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("0 kg*m")) } + specify { expect(RubyUnits::Unit.new("5 m") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("50 kg*m")) } + specify { expect { RubyUnits::Unit.new("10 m") * nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { expect(Unit('10 kg') * %w{1 kg}).to eq(Unit('10 kg^2')) } - specify { expect(Unit('10 kg') * "1 kg").to eq(Unit('10 kg^2')) } + specify { expect(RubyUnits::Unit.new('10 kg') * %w{1 kg}).to eq(RubyUnits::Unit.new('10 kg^2')) } + specify { expect(RubyUnits::Unit.new('10 kg') * "1 kg").to eq(RubyUnits::Unit.new('10 kg^2')) } end context "by a temperature" do - specify { expect { Unit("5 kg") * Unit("100 tempF") }.to raise_exception(ArgumentError) } + specify { expect { RubyUnits::Unit.new("5 kg") * RubyUnits::Unit.new("100 tempF") }.to raise_exception(ArgumentError) } end context "by a number" do - specify { expect(10 * Unit("5 kg")).to eq(Unit("50 kg")) } + specify { expect(10 * RubyUnits::Unit.new("5 kg")).to eq(RubyUnits::Unit.new("50 kg")) } end end context "dividing (/)" do context "compatible units" do - specify { expect(Unit("0 m") / Unit("10 m")).to eq(Unit(0)) } - specify { expect(Unit("5 kg") / Unit("10 kg")).to eq(Rational(1, 2)) } - specify { expect(Unit("5 kg") / Unit("5 kg")).to eq(1) } + specify { expect(RubyUnits::Unit.new("0 m") / RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new(0)) } + specify { expect(RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("10 kg")).to eq(Rational(1, 2)) } + specify { expect(RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("5 kg")).to eq(1) } end context "incompatible units" do - specify { expect(Unit("0 m") / Unit("10 kg")).to eq(Unit("0 m/kg")) } - specify { expect(Unit("5 m") / Unit("10 kg")).to eq(Unit("1/2 m/kg")) } - specify { expect { Unit("10 m") / nil }.to raise_error(ArgumentError) } + specify { expect(RubyUnits::Unit.new("0 m") / RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("0 m/kg")) } + specify { expect(RubyUnits::Unit.new("5 m") / RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("1/2 m/kg")) } + specify { expect { RubyUnits::Unit.new("10 m") / nil }.to raise_error(ArgumentError) } end context "between a unit and coerceable types" do - specify { expect(Unit('10 kg^2') / %w{1 kg}).to eq(Unit('10 kg')) } - specify { expect(Unit('10 kg^2') / "1 kg").to eq(Unit('10 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg^2') / %w{1 kg}).to eq(RubyUnits::Unit.new('10 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg^2') / "1 kg").to eq(RubyUnits::Unit.new('10 kg')) } end context "by a temperature" do - specify { expect { Unit("5 kg") / Unit("100 tempF") }.to raise_exception(ArgumentError) } + specify { expect { RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("100 tempF") }.to raise_exception(ArgumentError) } end context "a number by a unit" do - specify { expect(10 / Unit("5 kg")).to eq(Unit("2 1/kg")) } + specify { expect(10 / RubyUnits::Unit.new("5 kg")).to eq(RubyUnits::Unit.new("2 1/kg")) } end context "a unit by a number" do - specify { expect(Unit("5 kg") / 2).to eq(Unit("2.5 kg")) } + specify { expect(RubyUnits::Unit.new("5 kg") / 2).to eq(RubyUnits::Unit.new("2.5 kg")) } end context "by zero" do - specify { expect { Unit("10 m") / 0 }.to raise_error(ZeroDivisionError) } - specify { expect { Unit("10 m") / Unit("0 m") }.to raise_error(ZeroDivisionError) } - specify { expect { Unit("10 m") / Unit("0 kg") }.to raise_error(ZeroDivisionError) } + specify { expect { RubyUnits::Unit.new("10 m") / 0 }.to raise_error(ZeroDivisionError) } + specify { expect { RubyUnits::Unit.new("10 m") / RubyUnits::Unit.new("0 m") }.to raise_error(ZeroDivisionError) } + specify { expect { RubyUnits::Unit.new("10 m") / RubyUnits::Unit.new("0 kg") }.to raise_error(ZeroDivisionError) } end end context "exponentiating (**)" do specify "a temperature raises an execption" do - expect { Unit("100 tempK")**2 }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") + expect { RubyUnits::Unit.new("100 tempK")**2 }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - context Unit("0 m") do + context RubyUnits::Unit.new("0 m") do it { expect(subject**1).to eq(subject) } it { expect(subject**2).to eq(subject) } end - context Unit("1 m") do + context RubyUnits::Unit.new("1 m") do it { expect(subject**0).to eq(1) } it { expect(subject**1).to eq(subject) } it { expect(subject**(-1)).to eq(1/subject) } - it { expect(subject**(2)).to eq(Unit("1 m^2")) } - it { expect(subject**(-2)).to eq(Unit("1 1/m^2")) } + it { expect(subject**(2)).to eq(RubyUnits::Unit.new("1 m^2")) } + it { expect(subject**(-2)).to eq(RubyUnits::Unit.new("1 1/m^2")) } specify { expect { subject**(1/2) }.to raise_error(ArgumentError, "Illegal root") } # because 1 m^(1/2) doesn't make any sense specify { expect { subject**(Complex(1, 1)) }.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.") } - specify { expect { subject**(Unit("1 m")) }.to raise_error(ArgumentError, "Invalid Exponent") } + specify { expect { subject**(RubyUnits::Unit.new("1 m")) }.to raise_error(ArgumentError, "Invalid Exponent") } end - context Unit("1 m^2") do - it { expect(subject**(Rational(1, 2))).to eq(Unit("1 m")) } - it { expect(subject**(0.5)).to eq(Unit("1 m")) } + context RubyUnits::Unit.new("1 m^2") do + it { expect(subject**(Rational(1, 2))).to eq(RubyUnits::Unit.new("1 m")) } + it { expect(subject**(0.5)).to eq(RubyUnits::Unit.new("1 m")) } specify { expect { subject**(0.12345) }.to raise_error(ArgumentError, "Not a n-th root (1..9), use 1/n") } specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError, "Invalid Exponent") } @@ -1874,26 +1872,26 @@ context "modulo (%)" do context "compatible units" do - specify { expect(Unit("2 m") % Unit("1 m")).to eq(0) } - specify { expect(Unit("5 m") % Unit("2 m")).to eq(1) } + specify { expect(RubyUnits::Unit.new("2 m") % RubyUnits::Unit.new("1 m")).to eq(0) } + specify { expect(RubyUnits::Unit.new("5 m") % RubyUnits::Unit.new("2 m")).to eq(1) } end specify "incompatible units raises an exception" do - expect { Unit("1 m") % Unit("1 kg") }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '1 kg')") + expect { RubyUnits::Unit.new("1 m") % RubyUnits::Unit.new("1 kg") }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '1 kg')") end end context "unary negation (-)" do - specify { expect(-Unit("1 mm")).to eq(Unit("-1 mm")) } + specify { expect(-RubyUnits::Unit.new("1 mm")).to eq(RubyUnits::Unit.new("-1 mm")) } end context "unary plus (+)" do - specify { expect(+Unit('1 mm')).to eq(Unit('1 mm')) } + specify { expect(+RubyUnits::Unit.new('1 mm')).to eq(RubyUnits::Unit.new('1 mm')) } end end context "#power" do - subject { Unit("1 m") } + subject { RubyUnits::Unit.new("1 m") } it "raises an exception when passed a Float argument" do expect { subject.power(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") end @@ -1904,18 +1902,18 @@ expect { subject.power(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when called on a temperature unit" do - expect { Unit("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") + expect { RubyUnits::Unit.new("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") end - specify { expect(subject.power(-1)).to eq(Unit("1 1/m")) } + specify { expect(subject.power(-1)).to eq(RubyUnits::Unit.new("1 1/m")) } specify { expect(subject.power(0)).to eq(1) } specify { expect(subject.power(1)).to eq(subject) } - specify { expect(subject.power(2)).to eq(Unit("1 m^2")) } + specify { expect(subject.power(2)).to eq(RubyUnits::Unit.new("1 m^2")) } end context "#root" do - subject { Unit("1 m") } + subject { RubyUnits::Unit.new("1 m") } it "raises an exception when passed a Float argument" do expect { subject.root(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") end @@ -1926,47 +1924,47 @@ expect { subject.root(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") end it "raises an exception when called on a temperature unit" do - expect { Unit("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") + expect { RubyUnits::Unit.new("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") end - specify { expect(Unit("1 m^2").root(-2)).to eq(Unit("1 1/m")) } - specify { expect(subject.root(-1)).to eq(Unit("1 1/m")) } + specify { expect(RubyUnits::Unit.new("1 m^2").root(-2)).to eq(RubyUnits::Unit.new("1 1/m")) } + specify { expect(subject.root(-1)).to eq(RubyUnits::Unit.new("1 1/m")) } specify { expect { (subject.root(0)) }.to raise_error(ArgumentError, "0th root undefined") } specify { expect(subject.root(1)).to eq(subject) } - specify { expect(Unit("1 m^2").root(2)).to eq(Unit("1 m")) } + specify { expect(RubyUnits::Unit.new("1 m^2").root(2)).to eq(RubyUnits::Unit.new("1 m")) } end context "#inverse" do - specify { expect(Unit("1 m").inverse).to eq(Unit("1 1/m")) } - specify { expect { Unit("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } + specify { expect(RubyUnits::Unit.new("1 m").inverse).to eq(RubyUnits::Unit.new("1 1/m")) } + specify { expect { RubyUnits::Unit.new("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } end context "convert to scalars" do - specify { expect(Unit("10").to_i).to be_kind_of(Integer) } - specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new("10").to_i).to be_kind_of(Integer) } + specify { expect { RubyUnits::Unit.new("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } - specify { expect(Unit("10.0").to_f).to be_kind_of(Float) } - specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new("10.0").to_f).to be_kind_of(Float) } + specify { expect { RubyUnits::Unit.new("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } - specify { expect(Unit("1+1i").to_c).to be_kind_of(Complex) } - specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new("1+1i").to_c).to be_kind_of(Complex) } + specify { expect { RubyUnits::Unit.new("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } - specify { expect(Unit("3/7").to_r).to be_kind_of(Rational) } - specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new("3/7").to_r).to be_kind_of(Rational) } + specify { expect { RubyUnits::Unit.new("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } end context "absolute value (#abs)" do context "of a unitless unit" do specify "returns the absolute value of the scalar" do - expect(Unit("-10").abs).to eq(10) + expect(RubyUnits::Unit.new("-10").abs).to eq(10) end end context "of a unit" do specify "returns a unit with the absolute value of the scalar" do - expect(Unit("-10 m").abs).to eq(Unit("10 m")) + expect(RubyUnits::Unit.new("-10 m").abs).to eq(RubyUnits::Unit.new("10 m")) end end end @@ -1974,13 +1972,13 @@ context "#ceil" do context "of a unitless unit" do specify "returns the ceil of the scalar" do - expect(Unit("10.1").ceil).to eq(11) + expect(RubyUnits::Unit.new("10.1").ceil).to eq(11) end end context "of a unit" do specify "returns a unit with the ceil of the scalar" do - expect(Unit("10.1 m").ceil).to eq(Unit("11 m")) + expect(RubyUnits::Unit.new("10.1 m").ceil).to eq(RubyUnits::Unit.new("11 m")) end end end @@ -1988,13 +1986,13 @@ context "#floor" do context "of a unitless unit" do specify "returns the floor of the scalar" do - expect(Unit("10.1").floor).to eq(10) + expect(RubyUnits::Unit.new("10.1").floor).to eq(10) end end context "of a unit" do specify "returns a unit with the floor of the scalar" do - expect(Unit("10.1 m").floor).to eq(Unit("10 m")) + expect(RubyUnits::Unit.new("10.1 m").floor).to eq(RubyUnits::Unit.new("10 m")) end end end @@ -2002,13 +2000,13 @@ context "#round" do context "of a unitless unit" do specify "returns the round of the scalar" do - expect(Unit("10.5").round).to eq(11) + expect(RubyUnits::Unit.new("10.5").round).to eq(11) end end context "of a unit" do specify "returns a unit with the round of the scalar" do - expect(Unit("10.5 m").round).to eq(Unit("11 m")) + expect(RubyUnits::Unit.new("10.5 m").round).to eq(RubyUnits::Unit.new("11 m")) end end end @@ -2016,66 +2014,66 @@ context "#truncate" do context "of a unitless unit" do specify "returns the truncate of the scalar" do - expect(Unit("10.5").truncate).to eq(10) + expect(RubyUnits::Unit.new("10.5").truncate).to eq(10) end end context "of a unit" do specify "returns a unit with the truncate of the scalar" do - expect(Unit("10.5 m").truncate).to eq(Unit("10 m")) + expect(RubyUnits::Unit.new("10.5 m").truncate).to eq(RubyUnits::Unit.new("10 m")) end end context "of a complex unit" do specify "returns a unit with the truncate of the scalar" do - expect(Unit("10.5 kg*m/s^3").truncate).to eq(Unit("10 kg*m/s^3")) + expect(RubyUnits::Unit.new("10.5 kg*m/s^3").truncate).to eq(RubyUnits::Unit.new("10 kg*m/s^3")) end end end context '#zero?' do it "is true when the scalar is zero on the base scale" do - expect(Unit("0")).to be_zero - expect(Unit("0 mm")).to be_zero - expect(Unit("-273.15 tempC")).to be_zero + expect(RubyUnits::Unit.new("0")).to be_zero + expect(RubyUnits::Unit.new("0 mm")).to be_zero + expect(RubyUnits::Unit.new("-273.15 tempC")).to be_zero end it "is false when the scalar is not zero" do - expect(Unit("1")).not_to be_zero - expect(Unit("1 mm")).not_to be_zero - expect(Unit("0 tempC")).not_to be_zero + expect(RubyUnits::Unit.new("1")).not_to be_zero + expect(RubyUnits::Unit.new("1 mm")).not_to be_zero + expect(RubyUnits::Unit.new("0 tempC")).not_to be_zero end end context '#succ' do - specify { expect(Unit("1").succ).to eq(Unit("2")) } - specify { expect(Unit("1 mm").succ).to eq(Unit("2 mm")) } - specify { expect(Unit("1 mm").next).to eq(Unit("2 mm")) } - specify { expect(Unit("-1 mm").succ).to eq(Unit("0 mm")) } - specify { expect { Unit("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } + specify { expect(RubyUnits::Unit.new("1").succ).to eq(RubyUnits::Unit.new("2")) } + specify { expect(RubyUnits::Unit.new("1 mm").succ).to eq(RubyUnits::Unit.new("2 mm")) } + specify { expect(RubyUnits::Unit.new("1 mm").next).to eq(RubyUnits::Unit.new("2 mm")) } + specify { expect(RubyUnits::Unit.new("-1 mm").succ).to eq(RubyUnits::Unit.new("0 mm")) } + specify { expect { RubyUnits::Unit.new("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } end context '#pred' do - specify { expect(Unit("1").pred).to eq(Unit("0")) } - specify { expect(Unit("1 mm").pred).to eq(Unit("0 mm")) } - specify { expect(Unit("-1 mm").pred).to eq(Unit("-2 mm")) } - specify { expect { Unit("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } + specify { expect(RubyUnits::Unit.new("1").pred).to eq(RubyUnits::Unit.new("0")) } + specify { expect(RubyUnits::Unit.new("1 mm").pred).to eq(RubyUnits::Unit.new("0 mm")) } + specify { expect(RubyUnits::Unit.new("-1 mm").pred).to eq(RubyUnits::Unit.new("-2 mm")) } + specify { expect { RubyUnits::Unit.new("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } end context '#divmod' do - specify { expect(Unit("5 mm").divmod(Unit("2 mm"))).to eq([2, 1]) } - specify { expect(Unit("1 km").divmod(Unit("2 m"))).to eq([500, 0]) } - specify { expect { Unit('1 m').divmod(Unit('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } + specify { expect(RubyUnits::Unit.new("5 mm").divmod(RubyUnits::Unit.new("2 mm"))).to eq([2, 1]) } + specify { expect(RubyUnits::Unit.new("1 km").divmod(RubyUnits::Unit.new("2 m"))).to eq([500, 0]) } + specify { expect { RubyUnits::Unit.new('1 m').divmod(RubyUnits::Unit.new('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end context '#div' do - specify { expect(Unit('23 m').div(Unit('2 m'))).to eq(11) } + specify { expect(RubyUnits::Unit.new('23 m').div(RubyUnits::Unit.new('2 m'))).to eq(11) } end context '#best_prefix' do - specify { expect(Unit('1024 KiB').best_prefix).to eq(Unit('1 MiB')) } - specify { expect(Unit('1000 m').best_prefix).to eq(Unit('1 km')) } - specify { expect { Unit('0 m').best_prefix }.to_not raise_error } + specify { expect(RubyUnits::Unit.new('1024 KiB').best_prefix).to eq(RubyUnits::Unit.new('1 MiB')) } + specify { expect(RubyUnits::Unit.new('1000 m').best_prefix).to eq(RubyUnits::Unit.new('1 km')) } + specify { expect { RubyUnits::Unit.new('0 m').best_prefix }.to_not raise_error } end context "Time helper functions" do @@ -2086,41 +2084,41 @@ end context '#since' do - specify { expect(Unit("min").since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } - specify { expect(Unit("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(Unit("5544000 min")) } - specify { expect(Unit("min").since(Date.civil(2001, 4, 1))).to eq(Unit("5544000 min")) } - specify { expect { Unit("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { Unit("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new("min").since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new("5544000 min")) } + specify { expect(RubyUnits::Unit.new("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new("5544000 min")) } + specify { expect(RubyUnits::Unit.new("min").since(Date.civil(2001, 4, 1))).to eq(RubyUnits::Unit.new("5544000 min")) } + specify { expect { RubyUnits::Unit.new("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { RubyUnits::Unit.new("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#before' do - specify { expect(Unit("5 min").before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } - specify { expect(Unit("5 min").before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } - specify { expect(Unit("5 min").before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } - specify { expect { Unit('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { Unit('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new("5 min").before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } + specify { expect(RubyUnits::Unit.new("5 min").before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect(RubyUnits::Unit.new("5 min").before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect { RubyUnits::Unit.new('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { RubyUnits::Unit.new('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#ago' do - specify { expect(Unit("5 min").ago).to be_kind_of Time } - specify { expect(Unit("10000 y").ago).to be_kind_of Time } - specify { expect(Unit("1 year").ago).to eq(Time.utc(2010, 10, 16)) } + specify { expect(RubyUnits::Unit.new("5 min").ago).to be_kind_of Time } + specify { expect(RubyUnits::Unit.new("10000 y").ago).to be_kind_of Time } + specify { expect(RubyUnits::Unit.new("1 year").ago).to eq(Time.utc(2010, 10, 16)) } end context '#until' do - specify { expect(Unit("min").until(Date.civil(2011, 10, 17))).to eq(Unit("1440 min")) } - specify { expect(Unit("min").until(DateTime.civil(2011, 10, 21))).to eq(Unit("7200 min")) } - specify { expect(Unit("min").until(Time.utc(2011, 10, 21))).to eq(Unit("7200 min")) } - specify { expect { Unit('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { Unit('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new("min").until(Date.civil(2011, 10, 17))).to eq(RubyUnits::Unit.new("1440 min")) } + specify { expect(RubyUnits::Unit.new("min").until(DateTime.civil(2011, 10, 21))).to eq(RubyUnits::Unit.new("7200 min")) } + specify { expect(RubyUnits::Unit.new("min").until(Time.utc(2011, 10, 21))).to eq(RubyUnits::Unit.new("7200 min")) } + specify { expect { RubyUnits::Unit.new('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { RubyUnits::Unit.new('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end context '#from' do - specify { expect(Unit("1 day").from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } - specify { expect(Unit("5 min").from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 00, 05)) } - specify { expect(Unit("5 min").from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 00, 05)) } - specify { expect { Unit('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { Unit('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new("1 day").from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } + specify { expect(RubyUnits::Unit.new("5 min").from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 00, 05)) } + specify { expect(RubyUnits::Unit.new("5 min").from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 00, 05)) } + specify { expect { RubyUnits::Unit.new('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect { RubyUnits::Unit.new('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } end end @@ -2128,7 +2126,7 @@ end describe "Unit Output formatting" do - context Unit("10.5 m/s^2") do + context RubyUnits::Unit.new("10.5 m/s^2") do specify { expect(subject.to_s).to eq("10.5 m/s^2") } specify { expect(subject.to_s("%0.2f")).to eq("10.50 m/s^2") } specify { expect(subject.to_s("%0.2e km/s^2")).to eq("1.05e-02 km/s^2") } @@ -2160,10 +2158,10 @@ describe "Equations with Units" do context "Ideal Gas Law" do - let(:p) { Unit('100 kPa') } - let(:v) { Unit('1 m^3') } - let(:n) { Unit("1 mole") } - let(:r) { Unit("8.31451 J/mol*degK") } - specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(Unit("0.1 degK")).of(Unit("12027.2 tempK")) } + let(:p) { RubyUnits::Unit.new('100 kPa') } + let(:v) { RubyUnits::Unit.new('1 m^3') } + let(:n) { RubyUnits::Unit.new('1 mole') } + let(:r) { RubyUnits::Unit.new('8.31451 J/mol*degK') } + specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(RubyUnits::Unit.new('0.1 degK')).of(RubyUnits::Unit.new('12027.2 tempK')) } end end diff --git a/spec/ruby-units/utf-8/unit_spec.rb b/spec/ruby-units/utf-8/unit_spec.rb index 39975792..a78db837 100644 --- a/spec/ruby-units/utf-8/unit_spec.rb +++ b/spec/ruby-units/utf-8/unit_spec.rb @@ -6,17 +6,17 @@ context 'when the UTF-8 symbol is used' do context 'Angles' do it 'should be a degree' do - expect(Unit("180\u00B0").units).to eq('deg') + expect(RubyUnits::Unit.new("180\u00B0").units).to eq('deg') end end context 'Temperature' do it 'should be a degree Celcius' do - expect(Unit("180\u00B0C").units).to eq('degC') + expect(RubyUnits::Unit.new("180\u00B0C").units).to eq('degC') end it 'should be a degree Fahrenheit' do - expect(Unit("180\u00B0F").units).to eq('degF') + expect(RubyUnits::Unit.new("180\u00B0F").units).to eq('degF') end end end From 9a2b3c59381026cfa8f768e0baaf8fa557466dd8 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 23:52:42 -0500 Subject: [PATCH 085/150] Remove support for Uncertain numerics --- README.md | 319 +++++++++++++++++++++++---------------- lib/ruby_units/string.rb | 2 +- lib/ruby_units/unit.rb | 24 +-- 3 files changed, 197 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index a2328f80..7d59da43 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Ruby Units +Ruby Units +========== [![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) @@ -6,147 +7,202 @@ Kevin C. Olbrich, Ph.D. Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) -## Introduction -Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors. - -## Solution +Introduction +------------ + +Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors. + +Solution +-------- + The 'Ruby units' gem is designed to simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result. - -## Installation: -This package may be installed using: `gem install ruby-units` - -## Usage: - unit = Unit.new("1") # constant only - unit = Unit("mm") # unit only (defaults to a scalar of 1) - unit = Unit("1 mm") # create a simple unit - unit = Unit("1 mm/s") # a compound unit - unit = Unit("1 mm s^-1") # in exponent notation - unit = Unit("1 kg*m^2/s^2") # complex unit - unit = Unit("1 kg m^2 s^-2") # complex unit - unit = Unit("1 mm") # shorthand - unit = "1 mm".to_unit # convert string object - unit = object.to_unit # convert any object using object.to_s - unit = Unit('1/4 cup') # Rational number - unit = Unit('1+1i mm') # Complex Number - -## Rules: -1. only 1 quantity per unit (with 2 exceptions... 6'5" and '8 lbs 8 oz') -2. use SI notation when possible -3. spaces in units are allowed, but ones like '11/m' will be recognized as '11 1/m'. - -## Unit compatibility: -Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. - - unit1 =~ unit2 #=> true if units are compatible - unit1.compatible?(unit2) #=> true if units are compatible - -## Unit Math: - Unit#+() # Add. only works if units are compatible - Unit#-() # Subtract. only works if units are compatible - Unit#*() # Multiply. - Unit#/() # Divide. - Unit#**() # Exponentiate. Exponent must be an integer, can be positive, negative, or zero - Unit#inverse # Returns 1/unit - Unit#abs # Returns absolute value of the unit quantity. Strips off the units - Unit#ceil # rounds quantity to next highest integer - Unit#floor # rounds quantity down to next lower integer - Unit#round # rounds quantity to nearest integer - Unit#to_int # returns the quantity as an integer - -Unit will coerce other objects into a Unit if used in a formula. This means that .. - - Unit("1 mm") + "2 mm" == Unit("3 mm") - -This will work as expected so long as you start the formula with a Unit object. - -## Conversions & comparisons + +Installation: +------------- + +This package may be installed using: `gem install ruby-units` + +Usage: +------ + +``` +unit = Unit.new("1") # constant only +unit = Unit.new("mm") # unit only (defaults to a scalar of 1) +unit = Unit.new("1 mm") # create a simple unit +unit = Unit.new("1 mm/s") # a compound unit +unit = Unit.new("1 mm s^-1") # in exponent notation +unit = Unit.new("1 kg*m^2/s^2") # complex unit +unit = Unit.new("1 kg m^2 s^-2") # complex unit +unit = Unit.new("1 mm") # shorthand +unit = "1 mm".to_unit # convert string object +unit = object.to_unit # convert any object using object.to_s +unit = Unit.new('1/4 cup') # Rational number +unit = Unit.new('1+1i mm') # Complex Number +``` + +Rules: +------ + +1. only 1 quantity per unit (with 2 exceptions... 6'5" and '8 lbs 8 oz') +2. use SI notation when possible +3. spaces in units are allowed, but ones like '11/m' will be recognized as '11 1/m'. + +Unit compatibility: +------------------- + +Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. + +``` +unit1 =~ unit2 #=> true if units are compatible +unit1.compatible?(unit2) #=> true if units are compatible +``` + +Unit Math: +---------- + +``` +Unit#+() # Add. only works if units are compatible +Unit#-() # Subtract. only works if units are compatible +Unit#*() # Multiply. +Unit#/() # Divide. +Unit#**() # Exponentiate. Exponent must be an integer, can be positive, negative, or zero +Unit#inverse # Returns 1/unit +Unit#abs # Returns absolute value of the unit quantity. Strips off the units +Unit#ceil # rounds quantity to next highest integer +Unit#floor # rounds quantity down to next lower integer +Unit#round # rounds quantity to nearest integer +Unit#to_int # returns the quantity as an integer +``` + +Unit will coerce other objects into a Unit if used in a formula. This means that .. + +``` +Unit.new("1 mm") + "2 mm" == Unit.new("3 mm") +``` + +This will work as expected so long as you start the formula with a Unit object. + +Conversions & comparisons +------------------------- + Units can be converted to other units in a couple of ways. - unit1 = unit >> "ft" # convert to 'feet' - unit >>= "ft" # convert and overwrite original object - unit3 = unit1 + unit2 # resulting object will have the units of unit1 - unit3 = unit1 - unit2 # resulting object will have the units of unit1 - unit1 <=> unit2 # does comparison on quantities in base units, throws an exception if not compatible - unit1 === unit2 # true if units and quantity are the same, even if 'equivalent' by <=> - unit.convert_to('ft') # convert - unit1 + unit2 >> "ft" # converts result of math to 'ft' - (unit1 + unit2).convert_to('ft') # converts result to 'ft' - +``` +unit.convert_to('ft') # convert +unit1 = unit >> "ft" # convert to 'feet' +unit >>= "ft" # convert and overwrite original object +unit3 = unit1 + unit2 # resulting object will have the units of unit1 +unit3 = unit1 - unit2 # resulting object will have the units of unit1 +unit1 <=> unit2 # does comparison on quantities in base units, throws an exception if not compatible +unit1 === unit2 # true if units and quantity are the same, even if 'equivalent' by <=> +unit1 + unit2 >> "ft" # converts result of math to 'ft' +(unit1 + unit2).convert_to('ft') # converts result to 'ft' +``` + Any object that defines a 'to_unit' method will be automatically coerced to a unit during calculations. - -## Text Output -Units will display themselves nicely based on the display_name for the units and prefixes. -Since Unit implements a Unit#to_s, all that is needed in most cases is: - - "#{Unit('1 mm')}" #=> "1 mm" - + +Text Output +----------- + +Units will display themselves nicely based on the display_name for the units and prefixes. Since Unit implements a Unit#to_s, all that is needed in most cases is: + +``` +"#{Unit.new('1 mm')}" #=> "1 mm" +``` + The to_s also accepts some options. - Unit('1.5 mm').to_s("%0.2f") # "1.50 mm". Enter any valid format - string. Also accepts strftime format - Unit('1.5 mm').to_s("in") # converts to inches before printing - Unit("2 m").to_s(:ft) # returns 6'7" - Unit("100 kg").to_s(:lbs) # returns 220 lbs, 7 oz +``` +Unit.new('1.5 mm').to_s("%0.2f") # "1.50 mm". Enter any valid format + string. Also accepts strftime format +Unit.new('1.5 mm').to_s("in") # converts to inches before printing +Unit.new("2 m").to_s(:ft) # returns 6'7" +Unit.new("100 kg").to_s(:lbs) # returns 220 lbs, 7 oz +``` + +Time Helpers +------------ - -## Time Helpers Time, Date, and DateTime objects can have time units added or subtracted. - Time.now + Unit("10 min") +``` +Time.now + Unit.new("10 min") +``` -Several helpers have also been defined. -Note: If you include the 'Chronic' gem, you can specify times in natural - language. +Several helpers have also been defined. Note: If you include the 'Chronic' gem, you can specify times in natural language. - Unit('min').since(DateTime.parse('9/18/06 3:00pm')) +``` + Unit.new('min').since(DateTime.parse('9/18/06 3:00pm')) +``` Durations may be entered as 'HH:MM:SS, usec' and will be returned in 'hours'. - Unit('1:00') #=> 1 h - Unit('0:30') #=> 0.5 h - Unit('0:30:30') #=> 0.5 h + 30 sec +``` +Unit.new('1:00') #=> 1 h +Unit.new('0:30') #=> 0.5 h +Unit.new('0:30:30') #=> 0.5 h + 30 sec +``` If only one ":" is present, it is interpreted as the separator between hours and minutes. -## Ranges - [Unit('0 h')..Unit('10 h')].each {|x| p x} +Ranges +------ + +``` +[Unit.new('0 h')..Unit.new('10 h')].each {|x| p x} +``` + works so long as the starting point has an integer scalar -## Math functions -All Trig math functions (sin, cos, sinh, hypot...) can take a unit as their parameter. It will be converted to radians and then used if possible. +Math functions +-------------- + +All Trig math functions (sin, cos, sinh, hypot...) can take a unit as their parameter. It will be converted to radians and then used if possible. + +Temperatures +------------ -## Temperatures Ruby-units makes a distinction between a temperature (which technically is a property) and degrees of temperature (which temperatures are measured in). -Temperature units (i.e., 'tempK') can be converted back and forth, and will take into account the differences in the zero points of the various scales. Differential temperature (e.g., '100 degC'.unit) units behave like most other units. +Temperature units (i.e., 'tempK') can be converted back and forth, and will take into account the differences in the zero points of the various scales. Differential temperature (e.g., Unit.new('100 degC')) units behave like most other units. - Unit('37 tempC').convert_to('tempF') #=> 98.6 tempF +``` +Unit.new('37 tempC').convert_to('tempF') #=> 98.6 tempF +``` Ruby-units will raise an exception if you attempt to create a temperature unit that would fall below absolute zero. -Unit math on temperatures is fairly limited. +Unit math on temperatures is fairly limited. - Unit('100 tempC') + Unit('10 degC') # '110 tempC'.unit - Unit('100 tempC') - Unit('10 degC') # '90 tempC'.unit - Unit('100 tempC') + Unit('50 tempC') # exception - Unit('100 tempC') - Unit('50 tempC') # '50 degC'.unit - Unit('50 tempC') - Unit('100 tempC') # '-50 degC'.unit - Unit('100 tempC') * [scalar] # '100*scalar tempC'.unit - Unit('100 tempC') / [scalar] # '100/scalar tempC'.unit - Unit('100 tempC') * [unit] # exception - Unit('100 tempC') / [unit] # exception - Unit('100 tempC') ** N # exception +``` +Unit.new('100 tempC') + Unit.new('10 degC') # '110 tempC'.to_unit +Unit.new('100 tempC') - Unit.new('10 degC') # '90 tempC'.to_unit +Unit.new('100 tempC') + Unit.new('50 tempC') # exception (can't add two temperatures) +Unit.new('100 tempC') - Unit.new('50 tempC') # '50 degC'.to_unit (get the difference between two temperatures) +Unit.new('50 tempC') - Unit.new('100 tempC') # '-50 degC'.to_unit +Unit.new('100 tempC') * scalar # '100*scalar tempC'.to_unit +Unit.new('100 tempC') / scalar # '100/scalar tempC'.to_unit +Unit.new('100 tempC') * unit # exception +Unit.new('100 tempC') / unit # exception +Unit.new('100 tempC') ** N # exception - Unit('100 tempC').convert_to('degC') #=> Unit('100 degC') -This conversion references the 0 point on the scale of the temperature unit +Unit.new('100 tempC').convert_to('degC') #=> Unit.new('100 degC') +``` - Unit('100 degC').convert_to('tempC') #=> '-173 tempC'.unit -These conversions are always interpreted as being relative to absolute zero. -Conversions are probably better done like this... - - Unit('0 tempC') + Unit('100 degC') #=> Unit('100 tempC') +This conversion references the 0 point on the scale of the temperature unit -## Defining Units +``` +Unit.new('100 degC').convert_to('tempC') #=> '-173 tempC'.to_unit +``` + +These conversions are always interpreted as being relative to absolute zero. Conversions are probably better done like this... + +``` +Unit.new('0 tempC') + Unit.new('100 degC') #=> Unit.new('100 tempC') +``` + +Defining Units +-------------- It is possible to define new units or redefine existing ones. @@ -154,33 +210,38 @@ It is possible to define new units or redefine existing ones. The easiest approach is to define a unit in terms of other units. - Unit.define("foobar") do |foobar| - foobar.definition = Unit("1 foo") * Unit("1 bar") # anything that results in a Unit object - foobar.aliases = %w{foobar fb} # array of synonyms for the unit - foobar.display_name = "Foobar" # How unit is displayed when output - end - -### Redefine Existing Unit +``` +Unit.define("foobar") do |foobar| + foobar.definition = Unit.new("1 foo") * Unit.new("1 bar") # anything that results in a Unit object + foobar.aliases = %w{foobar fb} # array of synonyms for the unit + foobar.display_name = "Foobar" # How unit is displayed when output +end +``` -Redefining a unit allows the user to change a single aspect of a definition without having to re-create the entire definition. -This is useful for changing display names, adding aliases, etc. +### Redefine Existing Unit - Unit.redefine!("cup") do |cup| - cup.display_name = "cup" - end +Redefining a unit allows the user to change a single aspect of a definition without having to re-create the entire definition. This is useful for changing display names, adding aliases, etc. +``` +Unit.redefine!("cup") do |cup| + cup.display_name = "cup" +end +``` ### Namespaced Class -Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. -The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatiblity, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. +Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatiblity, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. To load ruby-units without this alias... - require 'ruby_units/namespaced' +``` +require 'ruby_units/namespaced' +``` When using bundler... - gem 'ruby-units', require: 'ruby_units/namespaced' +``` +gem 'ruby-units', require: 'ruby_units/namespaced' +``` -Note: when using the namespaced version, the Unit('unit string') helper will not be defined. +Note: when using the namespaced version, the Unit.new('unit string') helper will not be defined. diff --git a/lib/ruby_units/string.rb b/lib/ruby_units/string.rb index 9cfbfcb9..bdf55125 100644 --- a/lib/ruby_units/string.rb +++ b/lib/ruby_units/string.rb @@ -8,7 +8,7 @@ def to_unit(other = nil) alias_method :original_format, :% # format unit output using formating codes - # @example '%0.2f' % '1 mm'.unit => '1.00 mm' + # @example '%0.2f' % '1 mm'.to_unit => '1.00 mm' # @return [String] def format_with_unit(*other) case diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 5b50611e..c8595ac9 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -44,7 +44,6 @@ class Unit < Numeric TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/ BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/ NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/ - UNCERTAIN_REGEX = /#{SCI_NUMBER}\s*\+\/-\s*#{SCI_NUMBER}\s(.+)/ COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/ RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/ KELVIN = [''] @@ -547,7 +546,7 @@ def is_degree? alias :degree? :is_degree? # returns the 'degree' unit associated with a temperature unit - # @example '100 tempC'.unit.temperature_scale #=> 'degC' + # @example '100 tempC'.to_unit.temperature_scale #=> 'degC' # @return [String] possible values: degC, degF, degR, or degK def temperature_scale return nil unless self.is_temperature? @@ -681,7 +680,7 @@ def +(other) RubyUnits::Unit.new(:scalar => (other.scalar + self.convert_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)) + @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.to_unit.to_base.scalar)) RubyUnits::Unit.new(:scalar => (self.base_scalar + other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) end else @@ -720,7 +719,7 @@ def -(other) 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)) + @q ||= ((@@cached_units[self.units].scalar / @@cached_units[self.units].base_scalar) rescue (self.units.to_unit.scalar/self.units.to_unit.to_base.scalar)) RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) end else @@ -1095,7 +1094,7 @@ def truncate return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator) end - # returns next unit in a range. '1 mm'.unit.succ #=> '2 mm'.unit + # returns next unit in a range. '1 mm'.to_unit.succ #=> '2 mm'.to_unit # only works when the scalar is an integer # @return [Unit] # @raise [ArgumentError] when scalar is not equal to an integer @@ -1106,7 +1105,7 @@ def succ alias :next :succ - # returns previous unit in a range. '2 mm'.unit.pred #=> '1 mm'.unit + # returns previous unit in a range. '2 mm'.to_unit.pred #=> '1 mm'.to_unit # only works when the scalar is an integer # @return [Unit] # @raise [ArgumentError] when scalar is not equal to an integer @@ -1141,7 +1140,7 @@ def zero? return self.base_scalar.zero? end - # @example '5 min'.unit.ago + # @example '5 min'.to_unit.ago # @return [Unit] def ago return self.before @@ -1371,17 +1370,6 @@ def parse(passed_unit_string="0") unit_string.gsub!(/"/, 'inch') unit_string.gsub!(/#/, 'pound') - #:nocov: - #:nocov_19: - if defined?(Uncertain) && unit_string =~ /(\+\/-|±)/ - value, uncertainty, unit_s = unit_string.scan(UNCERTAIN_REGEX)[0] - result = unit_s.unit * Uncertain.new(value.to_f, uncertainty.to_f) - copy(result) - return - end - #:nocov: - #:nocov_19: - if defined?(Complex) && unit_string =~ COMPLEX_NUMBER real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] result = RubyUnits::Unit.new(unit_s || '1') * Complex(real.to_f, imaginary.to_f) From b42eef509d5bd2d651cf10cd11e1e993eed0c956 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 7 Nov 2015 23:59:04 -0500 Subject: [PATCH 086/150] remove TODO file, ignore Guardfile from gem --- Rakefile.rb | 2 +- TODO | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 TODO diff --git a/Rakefile.rb b/Rakefile.rb index a5a13062..03ee1541 100644 --- a/Rakefile.rb +++ b/Rakefile.rb @@ -12,7 +12,7 @@ gem.authors = ['Kevin Olbrich, Ph.D.'] gem.email = ['kevin.olbrich+ruby_units@gmail.com'] gem.homepage = 'https://github.com/olbrich/ruby-units' - gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile') + gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile', 'Guardfile') gem.license = 'MIT' end Jeweler::GemcutterTasks.new diff --git a/TODO b/TODO deleted file mode 100644 index b8edfa86..00000000 --- a/TODO +++ /dev/null @@ -1,3 +0,0 @@ -2006-10-02 Currency handling remains to be implemented well -2011-04-23 Refactor caching -2011-11-23 Perform all internal calculations in rational numbers to avoid round off problems \ No newline at end of file From 7606db441cbf6ec4e70573be4d156e60c624daf6 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 9 Nov 2015 12:30:58 -0500 Subject: [PATCH 087/150] address some parsing issues for feet and lbs.. fixes #123 --- CHANGELOG.txt | 1 + lib/ruby_units/unit.rb | 12 ++++++-- spec/ruby-units/unit_spec.rb | 53 +++++++++++++++++++----------------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c421b1ff..40d9e09a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,7 @@ Change Log for Ruby-units * remove `.unit` from Date * Fix an issue with redefining units that have already been cached * remove 'U()' and 'u()' constructors + * Fix issue #123 -- Fixes for singular unit parsing 2015-07-16 * Fix issue #129 -- doesn't handle number in the denominator 2015-05-09 * update test harness to use rspec 3 2014-02-21 1.4.5 * Fix issue #98 -- add mcg as a valid unit diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index c8595ac9..97997500 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -33,9 +33,15 @@ class Unit < Numeric @@UNIT_MATCH_REGEX = nil UNITY = '<1>' UNITY_ARRAY = [UNITY] - FEET_INCH_REGEX = /(\d+)\s*(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inches)/ + # ideally we would like to generate this regex from the alias for a 'feet' and 'inches', but they aren't + # defined at the point in the code where we need this regex. + FEET_INCH_UNITS_REGEX = /(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inch(?:es)?)/ + FEET_INCH_REGEX = /(\d+)\s*#{FEET_INCH_UNITS_REGEX}/ + # ideally we would like to generate this regex from the alias for a 'pound' and 'ounce', but they aren't + # defined at the point in the code where we need this regex. + LBS_OZ_UNIT_REGEX = /(?:#|lbs?|pounds?|pound-mass)+[\s,]*(\d+)\s*(?:ozs?|ounces?)/ + LBS_OZ_REGEX = /(\d+)\s*#{LBS_OZ_UNIT_REGEX}/ 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+)\/(\d+)\)?/ COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ @@ -342,7 +348,7 @@ def initialize(*options) opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ %r{\D/[\d+\.]+}) || - (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(pounds|lbs[ ,]\d+ ounces|oz)|('\d+")|(ft|feet[ ,]\d+ in|inch|inches)|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) + (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? end end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 23b45494..b01f121f 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -443,34 +443,37 @@ end # feet/in form - describe RubyUnits::Unit.new("5ft 6in") do - it { is_expected.to be_an_instance_of Unit } - - describe '#scalar' do - subject { super().scalar } - it { is_expected.to eq(5.5) } - end - - describe '#units' do - subject { super().units } - it { is_expected.to eq("ft") } - end + ['5 feet 6 inches', '5 feet 6 inch', '5ft 6in', '5 ft 6 in', %(5'6"), %(5' 6")].each do |unit| + describe unit do + subject { RubyUnits::Unit.new(unit) } + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(5.5) } + end - describe '#kind' do - subject { super().kind } - it { is_expected.to eq(:length) } - end - it { is_expected.not_to be_temperature } - it { is_expected.not_to be_degree } - it { is_expected.not_to be_base } - it { is_expected.not_to be_unitless } - it { is_expected.not_to be_zero } + describe '#units' do + subject { super().units } + it { is_expected.to eq("ft") } + end - describe '#base' do - subject { super().base } - it { is_expected.to be_within(RubyUnits::Unit.new("0.01 m")).of RubyUnits::Unit.new("1.6764 m") } + describe '#kind' do + subject { super().kind } + it { is_expected.to eq(:length) } + end + it { is_expected.not_to be_temperature } + it { is_expected.not_to be_degree } + it { is_expected.not_to be_base } + it { is_expected.not_to be_unitless } + it { is_expected.not_to be_zero } + + describe '#base' do + subject { super().base } + it { is_expected.to be_within(RubyUnits::Unit.new("0.01 m")).of RubyUnits::Unit.new("1.6764 m") } + end + specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } end - specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } end # pound/ounces form From a709568d9ac9d887c353931128953960096b9836 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 9 Nov 2015 12:40:49 -0500 Subject: [PATCH 088/150] Regenerate gemspec for version 2.0.0 --- ruby-units.gemspec | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 513ed200..85689f42 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,41 +2,37 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile.rb, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 1.4.5 ruby lib +# stub: ruby-units 2.0.0 ruby lib Gem::Specification.new do |s| s.name = "ruby-units" - s.version = "1.4.5" + s.version = "2.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2014-02-21" + s.date = "2015-11-09" s.description = "Provides classes and methods to perform unit math and conversions" s.email = ["kevin.olbrich+ruby_units@gmail.com"] s.extra_rdoc_files = [ + "CHANGELOG.txt", "LICENSE.txt", - "README.md", - "TODO" + "README.md" ] s.files = [ "CHANGELOG.txt", "LICENSE.txt", "README.md", "Rakefile.rb", - "TODO", "VERSION", "lib/ruby-units.rb", - "lib/ruby_units.rb", "lib/ruby_units/array.rb", "lib/ruby_units/cache.rb", "lib/ruby_units/date.rb", "lib/ruby_units/definition.rb", - "lib/ruby_units/fixnum.rb", "lib/ruby_units/math.rb", "lib/ruby_units/namespaced.rb", "lib/ruby_units/numeric.rb", - "lib/ruby_units/object.rb", "lib/ruby_units/string.rb", "lib/ruby_units/time.rb", "lib/ruby_units/unit.rb", @@ -49,8 +45,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units" s.licenses = ["MIT"] - s.post_install_message = "====================\nDeprecation Warning\n====================\n\nSeveral convenience methods that ruby-units added to the string class have\nbeen deprecated in this release. These methods include String#to, String#from, String#ago, String#before and others.\nIf your code relies on these functions, they can be added back by adding this line to your code.\n\nrequire 'ruby-units/string/extras'\n# note that these methods do not play well with Rails, which is one of the reasons they are being removed.\n\nThe extra functions mostly work the same, but will no longer properly handle cases when they are called with strings..\n\n'min'.from(\"4-1-2011\") # => Exception\n\nPass in a Date, Time, or DateTime object to get the expected result.\n\nThey will go away completely in the next release, so it would be a good idea to refactor your code\nto avoid using them. They will also throw deprecation warnings when they are used.\n" - s.rubygems_version = "2.2.2" + s.rubygems_version = "2.5.0" s.summary = "A class that performs unit conversions and unit math" if s.respond_to? :specification_version then @@ -59,16 +54,16 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, ["~> 1.0"]) s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end end From 658739b12c795aec56d39a7c4475dbf1bc9c5089 Mon Sep 17 00:00:00 2001 From: Rocco Stanzione Date: Sun, 29 May 2016 12:32:47 -0400 Subject: [PATCH 089/150] Add encoding to prefix definitions --- lib/ruby_units/unit_definitions/prefix.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 3901cd92..9d0d31be 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 { 'googol' => [%w{googol}, 1e100], From 5d45739f72ada3d2592b91385456d07a97d1e1bb Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 27 Jul 2016 09:14:22 -0400 Subject: [PATCH 090/150] add ruby 2.3.1 to travis, tell travis to skip installing development gems and move guard-rspec to development gems so we don't try to install guard for ci. --- .travis.yml | 4 ++++ Gemfile | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6df71900..e3f8f8f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ rvm: - 2.0.0 - 2.1.0 - 2.2.0 + - 2.3.1 - ruby-head - jruby-head jdk: @@ -17,8 +18,11 @@ matrix: jdk: openjdk6 - rvm: 2.2.0 jdk: openjdk6 + - rvm: 2.3.1 + jdk: openjdk6 - rvm: jruby-head jdk: openjdk6 - rvm: ruby-head jdk: openjdk6 script: bundle exec rake --trace +bundler_args: --without development diff --git a/Gemfile b/Gemfile index 5626b398..90a584ab 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,7 @@ group :development do gem 'bundler', '~> 1.0' gem 'jeweler' gem 'pry-byebug', platforms: :mri + gem 'guard-rspec' end group :test do @@ -11,5 +12,4 @@ group :test do gem 'simplecov' gem 'simplecov-html' gem 'rspec' - gem 'guard-rspec' end From 5d086d30cda544d216168dd5a4fbca81f9993a85 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 28 Jul 2016 08:24:29 -0700 Subject: [PATCH 091/150] tweak travis ruby versions --- .travis.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3f8f8f1..d7e7468c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,23 +6,6 @@ rvm: - 2.2.0 - 2.3.1 - ruby-head - - jruby-head -jdk: - - openjdk6 - - openjdk7 -matrix: - exclude: - - rvm: 2.0.0 - jdk: openjdk6 - - rvm: 2.1.0 - jdk: openjdk6 - - rvm: 2.2.0 - jdk: openjdk6 - - rvm: 2.3.1 - jdk: openjdk6 - - rvm: jruby-head - jdk: openjdk6 - - rvm: ruby-head - jdk: openjdk6 + - jruby script: bundle exec rake --trace bundler_args: --without development From 604c4e0cf51f698338c9ea1078fb4630ad1f29ef Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 28 Jul 2016 08:32:49 -0700 Subject: [PATCH 092/150] bump ruby-version --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 58594069..2bf1c1cc 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2.3 +2.3.1 From 4534b2cc2dcef2406c4ab1e05832ceafe515c188 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 28 Jul 2016 08:34:08 -0700 Subject: [PATCH 093/150] Version bump to 2.0.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 359a5b95..10bf840e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.0 \ No newline at end of file +2.0.1 \ No newline at end of file From 31973714f333401b3056fe52d6d2506a1e84681c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 28 Jul 2016 08:39:27 -0700 Subject: [PATCH 094/150] tweak .gitignore & .rubocop.yml --- .gitignore | 3 +++ .rubocop.yml | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 .rubocop.yml diff --git a/.gitignore b/.gitignore index 73dc5afb..715b20d1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ Gemfile.lock .rbx .idea doc +bin +tmp + diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..1b5ad23f --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,9 @@ +require: rubocop-rspec +AllCops: + TargetRubyVersion: 2.3 +Style/CaseEquality: + Enabled: false +Style/FrozenStringLiteralComment: + Enabled: false +Metrics/LineLength: + Enabled: false From d58f77cc896cb383cf6ca4b7bfa231df2f9c1046 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 28 Jul 2016 08:39:41 -0700 Subject: [PATCH 095/150] Regenerate gemspec for version 2.0.1 --- ruby-units.gemspec | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 85689f42..7208345c 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,20 +2,19 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile.rb, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.0.0 ruby lib +# stub: ruby-units 2.0.1 ruby lib Gem::Specification.new do |s| s.name = "ruby-units" - s.version = "2.0.0" + s.version = "2.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2015-11-09" + s.date = "2016-07-28" s.description = "Provides classes and methods to perform unit math and conversions" s.email = ["kevin.olbrich+ruby_units@gmail.com"] s.extra_rdoc_files = [ - "CHANGELOG.txt", "LICENSE.txt", "README.md" ] @@ -45,7 +44,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units" s.licenses = ["MIT"] - s.rubygems_version = "2.5.0" + s.rubygems_version = "2.5.1" s.summary = "A class that performs unit conversions and unit math" if s.respond_to? :specification_version then @@ -55,15 +54,18 @@ Gem::Specification.new do |s| s.add_development_dependency(%q, ["~> 1.0"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) end end From b61f273596b157e7f5191cdae6ad45ab9390a3ac Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 25 Nov 2016 14:22:48 -0500 Subject: [PATCH 096/150] Update travis config to include ruby 2.3.3, 2.2.6, and 2.1.10. Other, older versions are not supported --- .ruby-version | 2 +- .travis.yml | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.ruby-version b/.ruby-version index 2bf1c1cc..0bee604d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.1 +2.3.3 diff --git a/.travis.yml b/.travis.yml index d7e7468c..7d2a28f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ sudo: false language: ruby rvm: - - 2.0.0 - - 2.1.0 - - 2.2.0 - - 2.3.1 + - 2.3.3 + - 2.2.6 + - 2.1.10 - ruby-head - jruby script: bundle exec rake --trace From 98417720955410b73c89cc98e25dd1bd072874ed Mon Sep 17 00:00:00 2001 From: Greg Tangey Date: Sat, 26 Nov 2016 03:41:22 +0800 Subject: [PATCH 097/150] Feature/fix issue 126 (#140) * Test coverage for issue #126 * Ensure objects with the same value return the same hash - Fixes Issue #126 --- lib/ruby_units/unit.rb | 11 +++++++++++ spec/ruby-units/unit_spec.rb | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 97997500..dd84d6d2 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1237,6 +1237,17 @@ def best_prefix self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(_best_prefix)+self.units(false))) end + # override hash method so objects with same values are considered equal + def hash + [@scalar, + @numerator, + @denominator, + @is_base, + @signature, + @base_scalar, + @unit_name].hash + end + # Protected and Private Functions that should only be called from this class protected diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index b01f121f..4195e366 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -2168,3 +2168,23 @@ specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(RubyUnits::Unit.new('0.1 degK')).of(RubyUnits::Unit.new('12027.2 tempK')) } end end + +describe "Unit hash method" do + context "should return equal values for identical units" do + let(:kg_unit_1) { RubyUnits::Unit.new("2.2 kg") } + let(:kg_unit_2) { RubyUnits::Unit.new("2.2 kg") } + + specify { expect(kg_unit_1).to eq(kg_unit_2) } + specify { expect(kg_unit_1.hash).to eq(kg_unit_2.hash) } + specify { expect([kg_unit_1, kg_unit_2].uniq.size).to eq(1) } + end + + context "should return not equal values for differnet units" do + let(:kg_unit) { RubyUnits::Unit.new("2.2 kg") } + let(:lb_unit) { RubyUnits::Unit.new("2.2 lbs") } + + specify { expect(kg_unit).to_not eq(lb_unit) } + specify { expect(kg_unit.hash).to_not eq(lb_unit.hash) } + specify { expect([kg_unit, lb_unit].uniq.size).to eq(2) } + end +end From e5c676838e8b57909c373dc29bc5a34ad388132f Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 25 Nov 2016 15:29:36 -0500 Subject: [PATCH 098/150] Baublet: stone units (#142) * Add support for 'stone-pound' format. Also include a `to_s(:stone)` output format. --- lib/ruby_units/unit.rb | 18 +++++++++++++++++- lib/ruby_units/unit_definitions/standard.rb | 13 +++++++++---- spec/ruby-units/unit_spec.rb | 12 ++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index dd84d6d2..b56c3206 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -41,6 +41,11 @@ class Unit < Numeric # defined at the point in the code where we need this regex. LBS_OZ_UNIT_REGEX = /(?:#|lbs?|pounds?|pound-mass)+[\s,]*(\d+)\s*(?:ozs?|ounces?)/ LBS_OZ_REGEX = /(\d+)\s*#{LBS_OZ_UNIT_REGEX}/ + # ideally we would like to generate this regex from the alias for a 'stone' and 'pound', but they aren't + # defined at the point in the code where we need this regex. + # also note that the plural of 'stone' is still 'stone', but we accept 'stones' anyway. + STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/ + STONE_LB_REGEX = /(\d+)\s*#{STONE_LB_UNIT_REGEX}/ TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/ SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)} RATIONAL_NUMBER = /\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?/ @@ -348,7 +353,7 @@ def initialize(*options) opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ %r{\D/[\d+\.]+}) || - (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) + (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? end end @@ -494,6 +499,9 @@ def to_s(target_units=nil) when :lbs ounces = self.convert_to("oz").scalar.to_int out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" + when :stone + pounds = self.convert_to("lbs").scalar.to_int + out = "#{(pounds / 14).truncate} stone, #{(pounds % 14).round} lb" when String out = case target_units.strip when /\A\s*\Z/ # whitespace only @@ -1448,6 +1456,14 @@ def parse(passed_unit_string="0") return end + # stone -- 3 stone 5, 2 stone, 14 stone 3 pounds, etc. + stone, pounds = unit_string.scan(STONE_LB_REGEX)[0] + if (stone && pounds) + result = RubyUnits::Unit.new("#{stone} stone") + RubyUnits::Unit.new("#{pounds} lbs") + copy(result) + return + end + # more than one per. I.e., "1 m/s/s" raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 08b8bd75..6f7df77f 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -147,6 +147,11 @@ carat.aliases = %w{ct carat carats} end +RubyUnits::Unit.define('stone') do |stone| + stone.definition = RubyUnits::Unit.new('14 lbs') + stone.aliases = %w{st stone} +end + # time RubyUnits::Unit.define('minute') do |min| @@ -322,7 +327,7 @@ end RubyUnits::Unit.define('fahrenheit') do |fahrenheit| - fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') + fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') fahrenheit.aliases = %w{degF fahrenheit} end @@ -383,7 +388,7 @@ RubyUnits::Unit.define('slug') do |slug| slug.definition = RubyUnits::Unit.new('1 lbf*s^2/ft') - slug.aliases = %w{slug slugs} + slug.aliases = %w{slug slugs} end # pressure @@ -431,7 +436,7 @@ RubyUnits::Unit.define('inh2o') do |inh2o| density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC inh2o.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_water - inh2o.aliases = %w{inH2O inh2o inAq} + inh2o.aliases = %w{inH2O inh2o inAq} end #viscosity @@ -534,7 +539,7 @@ ohm.aliases = %w{Ohm ohm ohms} end -# magnetism +# magnetism RubyUnits::Unit.define('weber') do |weber| weber.definition = RubyUnits::Unit.new('1 V*s') diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index 4195e366..eb62f6ba 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -1690,6 +1690,18 @@ specify { expect(RubyUnits::Unit.new(ounces).to_s(:lbs)).to eq(pounds) } end end + + describe 'stone-pound conversions' do + [ + ["14 stone 4", '200 lbs'], + ['14 st 4', '200 lbs'], + ['14 stone, 4 pounds', '200 lbs'], + ['14 st, 4 lbs', '200 lbs' ] + ].each do |stone, pounds| + specify { expect(RubyUnits::Unit.new(stone).convert_to('lbs')).to eq(RubyUnits::Unit.new(pounds)) } + end + specify { expect(RubyUnits::Unit.new('200 lbs').to_s(:stone)).to eq '14 stone, 4 lb' } + end end describe "Unit Math" do From 0c68b58ede7d52562165de0b929fb6339733ec78 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 25 Nov 2016 15:38:53 -0500 Subject: [PATCH 099/150] update code climate configurations --- .codeclimate.yml | 30 +++++++ .csslintrc | 2 + .eslintignore | 1 + .eslintrc | 213 +++++++++++++++++++++++++++++++++++++++++++++++ .rubocop.yml | 1 - 5 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 .codeclimate.yml create mode 100644 .csslintrc create mode 100644 .eslintignore create mode 100644 .eslintrc diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000..a612f6c3 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,30 @@ +--- +engines: + bundler-audit: + enabled: false + csslint: + enabled: false + duplication: + enabled: true + config: + languages: + - ruby + eslint: + enabled: false + fixme: + enabled: true + rubocop: + enabled: true +ratings: + paths: + - Gemfile.lock + - "**.css" + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.py" + - "**.rb" +exclude_paths: +- spec/ diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 00000000..aacba956 --- /dev/null +++ b/.csslintrc @@ -0,0 +1,2 @@ +--exclude-exts=.min.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..96212a35 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/*{.,-}min.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..9faa3750 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,213 @@ +ecmaFeatures: + modules: true + jsx: true + +env: + amd: true + browser: true + es6: true + jquery: true + node: true + +# http://eslint.org/docs/rules/ +rules: + # Possible Errors + comma-dangle: [2, never] + no-cond-assign: 2 + no-console: 0 + no-constant-condition: 2 + no-control-regex: 2 + no-debugger: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-empty: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 2 + no-extra-parens: 0 + no-extra-semi: 2 + no-func-assign: 2 + no-inner-declarations: [2, functions] + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-negated-in-lhs: 2 + no-obj-calls: 2 + no-regex-spaces: 2 + no-sparse-arrays: 2 + no-unexpected-multiline: 2 + no-unreachable: 2 + use-isnan: 2 + valid-jsdoc: 0 + valid-typeof: 2 + + # Best Practices + accessor-pairs: 2 + block-scoped-var: 0 + complexity: [2, 6] + consistent-return: 0 + curly: 0 + default-case: 0 + dot-location: 0 + dot-notation: 0 + eqeqeq: 2 + guard-for-in: 2 + no-alert: 2 + no-caller: 2 + no-case-declarations: 2 + no-div-regex: 2 + no-else-return: 0 + no-empty-label: 2 + no-empty-pattern: 2 + no-eq-null: 2 + no-eval: 2 + no-extend-native: 2 + no-extra-bind: 2 + no-fallthrough: 2 + no-floating-decimal: 0 + no-implicit-coercion: 0 + no-implied-eval: 2 + no-invalid-this: 0 + no-iterator: 2 + no-labels: 0 + no-lone-blocks: 2 + no-loop-func: 2 + no-magic-number: 0 + no-multi-spaces: 0 + no-multi-str: 0 + no-native-reassign: 2 + no-new-func: 2 + no-new-wrappers: 2 + no-new: 2 + no-octal-escape: 2 + no-octal: 2 + no-proto: 2 + no-redeclare: 2 + no-return-assign: 2 + no-script-url: 2 + no-self-compare: 2 + no-sequences: 0 + no-throw-literal: 0 + no-unused-expressions: 2 + no-useless-call: 2 + no-useless-concat: 2 + no-void: 2 + no-warning-comments: 0 + no-with: 2 + radix: 2 + vars-on-top: 0 + wrap-iife: 2 + yoda: 0 + + # Strict + strict: 0 + + # Variables + init-declarations: 0 + no-catch-shadow: 2 + no-delete-var: 2 + no-label-var: 2 + no-shadow-restricted-names: 2 + no-shadow: 0 + no-undef-init: 2 + no-undef: 0 + no-undefined: 0 + no-unused-vars: 0 + no-use-before-define: 0 + + # Node.js and CommonJS + callback-return: 2 + global-require: 2 + handle-callback-err: 2 + no-mixed-requires: 0 + no-new-require: 0 + no-path-concat: 2 + no-process-exit: 2 + no-restricted-modules: 0 + no-sync: 0 + + # Stylistic Issues + array-bracket-spacing: 0 + block-spacing: 0 + brace-style: 0 + camelcase: 0 + comma-spacing: 0 + comma-style: 0 + computed-property-spacing: 0 + consistent-this: 0 + eol-last: 0 + func-names: 0 + func-style: 0 + id-length: 0 + id-match: 0 + indent: 0 + jsx-quotes: 0 + key-spacing: 0 + linebreak-style: 0 + lines-around-comment: 0 + max-depth: 0 + max-len: 0 + max-nested-callbacks: 0 + max-params: 0 + max-statements: [2, 30] + new-cap: 0 + new-parens: 0 + newline-after-var: 0 + no-array-constructor: 0 + no-bitwise: 0 + no-continue: 0 + no-inline-comments: 0 + no-lonely-if: 0 + no-mixed-spaces-and-tabs: 0 + no-multiple-empty-lines: 0 + no-negated-condition: 0 + no-nested-ternary: 0 + no-new-object: 0 + no-plusplus: 0 + no-restricted-syntax: 0 + no-spaced-func: 0 + no-ternary: 0 + no-trailing-spaces: 0 + no-underscore-dangle: 0 + no-unneeded-ternary: 0 + object-curly-spacing: 0 + one-var: 0 + operator-assignment: 0 + operator-linebreak: 0 + padded-blocks: 0 + quote-props: 0 + quotes: 0 + require-jsdoc: 0 + semi-spacing: 0 + semi: 0 + sort-vars: 0 + space-after-keywords: 0 + space-before-blocks: 0 + space-before-function-paren: 0 + space-before-keywords: 0 + space-in-parens: 0 + space-infix-ops: 0 + space-return-throw-case: 0 + space-unary-ops: 0 + spaced-comment: 0 + wrap-regex: 0 + + # ECMAScript 6 + arrow-body-style: 0 + arrow-parens: 0 + arrow-spacing: 0 + constructor-super: 0 + generator-star-spacing: 0 + no-arrow-condition: 0 + no-class-assign: 0 + no-const-assign: 0 + no-dupe-class-members: 0 + no-this-before-super: 0 + no-var: 0 + object-shorthand: 0 + prefer-arrow-callback: 0 + prefer-const: 0 + prefer-reflect: 0 + prefer-spread: 0 + prefer-template: 0 + require-yield: 0 diff --git a/.rubocop.yml b/.rubocop.yml index 1b5ad23f..b89c14c9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,3 @@ -require: rubocop-rspec AllCops: TargetRubyVersion: 2.3 Style/CaseEquality: From 7c893dd7aed2164c6ec0ed1ceb15d74eea9c43a7 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 25 Nov 2016 21:23:51 -0500 Subject: [PATCH 100/150] rubocop/codeclimate configs and fixes --- .codeclimate.yml | 3 +- .rubocop.yml | 4 + .rubocop_todo.yml | 354 ++++++ Guardfile | 9 +- lib/ruby_units/cache.rb | 33 +- lib/ruby_units/date.rb | 6 +- lib/ruby_units/definition.rb | 46 +- lib/ruby_units/math.rb | 63 +- lib/ruby_units/string.rb | 7 +- lib/ruby_units/time.rb | 19 +- lib/ruby_units/unit.rb | 1248 +++++++++---------- lib/ruby_units/unit_definitions/base.rb | 87 +- lib/ruby_units/unit_definitions/prefix.rb | 60 +- lib/ruby_units/unit_definitions/standard.rb | 264 ++-- lib/ruby_units/version.rb | 2 +- spec/ruby-units/array_spec.rb | 18 +- spec/ruby-units/complex_spec.rb | 17 +- spec/ruby-units/date_spec.rb | 4 +- spec/ruby-units/numeric_spec.rb | 14 +- spec/ruby-units/time_spec.rb | 41 +- spec/ruby-units/unit_spec.rb | 1028 ++++++++------- spec/spec_helper.rb | 2 +- 22 files changed, 1824 insertions(+), 1505 deletions(-) create mode 100644 .rubocop_todo.yml diff --git a/.codeclimate.yml b/.codeclimate.yml index a612f6c3..fabacdcf 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -27,4 +27,5 @@ ratings: - "**.py" - "**.rb" exclude_paths: -- spec/ +- ruby-units.gemspec +- bin/ diff --git a/.rubocop.yml b/.rubocop.yml index b89c14c9..a53ac571 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,9 @@ +inherit_from: .rubocop_todo.yml AllCops: TargetRubyVersion: 2.3 + Exclude: + - ruby-units.gemspec + - bin/* Style/CaseEquality: Enabled: false Style/FrozenStringLiteralComment: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..d5824081 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,354 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2016-11-26 14:04:52 -0500 using RuboCop version 0.45.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +Lint/EmptyWhen: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AlignWith, SupportedStyles, AutoCorrect. +# SupportedStyles: keyword, variable, start_of_line +Lint/EndAlignment: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +Lint/ParenthesesAsGroupedExpression: + Exclude: + - 'spec/ruby-units/unit_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. +Lint/UnusedMethodArgument: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +Lint/UselessAssignment: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 20 +Metrics/AbcSize: + Max: 175 + +# Offense count: 8 +Metrics/BlockNesting: + Max: 4 + +# Offense count: 1 +# Configuration parameters: CountComments. +Metrics/ClassLength: + Max: 1093 + +# Offense count: 15 +Metrics/CyclomaticComplexity: + Max: 46 + +# Offense count: 24 +# Configuration parameters: CountComments. +Metrics/MethodLength: + Max: 106 + +# Offense count: 14 +Metrics/PerceivedComplexity: + Max: 46 + +# Offense count: 6 +# Cop supports --auto-correct. +Style/AlignArray: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods. +# SupportedStyles: line_count_based, semantic, braces_for_chaining +# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object +# FunctionalMethods: let, let!, subject, watch +# IgnoredMethods: lambda, proc, it +Style/BlockDelimiters: + Exclude: + - 'spec/ruby-units/math_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/BlockEndNewline: + Exclude: + - 'spec/ruby-units/math_spec.rb' + +# Offense count: 1 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Exclude: + - 'lib/ruby_units/definition.rb' + +# Offense count: 32 +Style/ClassVars: + Exclude: + - 'lib/ruby_units/cache.rb' + - 'lib/ruby_units/unit.rb' + +# Offense count: 6 +Style/Documentation: + Exclude: + - 'spec/**/*' + - 'test/**/*' + - 'lib/ruby_units/array.rb' + - 'lib/ruby_units/cache.rb' + - 'lib/ruby_units/numeric.rb' + - 'lib/ruby_units/string.rb' + - 'lib/ruby_units/unit.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: leading, trailing +Style/DotPosition: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/ElseAlignment: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +Style/EmptyCaseCondition: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts. +Style/FileName: + Exclude: + - 'Rakefile.rb' + - 'lib/ruby-units.rb' + +# Offense count: 5 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: for, each +Style/For: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 6 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: format, sprintf, percent +Style/FormatString: + Exclude: + - 'lib/ruby_units/unit.rb' + - 'spec/ruby-units/string_spec.rb' + +# Offense count: 4 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Exclude: + - 'lib/ruby_units/math.rb' + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +Style/IdenticalConditionalBranches: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: MaxLineLength. +# Style/IfUnlessModifier: +# Exclude: +# - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Style/IndentArray: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Style/IndentHash: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: Width. +Style/IndentationWidth: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: SupportedStyles. +# SupportedStyles: call, braces +Style/LambdaCall: + EnforcedStyle: braces + +# Offense count: 2 +# Cop supports --auto-correct. +Style/MultilineIfThen: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: symmetrical, new_line, same_line +Style/MultilineMethodCallBraceLayout: + Exclude: + - 'spec/ruby-units/math_spec.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: aligned, indented, indented_relative_to_receiver +Style/MultilineMethodCallIndentation: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: aligned, indented +Style/MultilineOperationIndentation: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/NilComparison: + Exclude: + - 'spec/ruby-units/unit_spec.rb' + +# Offense count: 16 +# Cop supports --auto-correct. +Style/PerlBackrefs: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: short, verbose +Style/PreferredHashMethods: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +Style/RedundantException: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +Style/RedundantParentheses: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 100 +# Cop supports --auto-correct. +# Style/RedundantSelf: +# Exclude: +# - 'lib/ruby_units/unit.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Exclude: + - 'lib/ruby_units/unit.rb' + - 'spec/ruby-units/unit_spec.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +Style/RescueModifier: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowAsExpressionSeparator. +Style/Semicolon: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: only_raise, only_fail, semantic +Style/SignalException: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 5 +# Configuration parameters: Methods. +# Methods: {"reduce"=>["acc", "elem"]}, {"inject"=>["acc", "elem"]} +Style/SingleLineBlockParams: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Style/SpaceAfterComma: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +Style/SpaceInsideBlockBraces: + Exclude: + - 'spec/ruby-units/math_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Style/SpaceInsideStringInterpolation: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. +# SupportedStyles: require_parentheses, require_no_parentheses +Style/TernaryParentheses: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Style/UnneededInterpolation: + Exclude: + - 'lib/ruby_units/unit.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Style/WhileUntilDo: + Exclude: + - 'lib/ruby_units/unit.rb' diff --git a/Guardfile b/Guardfile index 0469987f..fd444fcf 100644 --- a/Guardfile +++ b/Guardfile @@ -16,17 +16,16 @@ clearing :on # * zeus: 'zeus rspec' (requires the server to be started separately) # * 'just' rspec: 'rspec' -guard :rspec, cmd: "bundle exec rspec" do - require "ostruct" +guard :rspec, cmd: 'bundle exec rspec' do + require 'ostruct' # Generic Ruby apps rspec = OpenStruct.new rspec.spec = ->(m) { "spec/#{m}_spec.rb" } - rspec.spec_dir = "spec" - rspec.spec_helper = "spec/spec_helper.rb" + rspec.spec_dir = 'spec' + rspec.spec_helper = 'spec/spec_helper.rb' watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.("lib/#{m[1]}") } watch(rspec.spec_helper) { rspec.spec_dir } - end diff --git a/lib/ruby_units/cache.rb b/lib/ruby_units/cache.rb index 6eaaccaa..669cdd02 100644 --- a/lib/ruby_units/cache.rb +++ b/lib/ruby_units/cache.rb @@ -1,20 +1,21 @@ -class RubyUnits::Unit < Numeric - @@cached_units = {} - - class Cache - def self.get(key = nil) - key.nil? ? @@cached_units : @@cached_units[key] - end - - def self.set(key, value) - @@cached_units[key] = value - end +module RubyUnits + class Unit < Numeric + @@cached_units = {} + + class Cache + def self.get(key = nil) + key.nil? ? @@cached_units : @@cached_units[key] + end + + def self.set(key, value) + @@cached_units[key] = value + end - def self.clear - @@cached_units = {} - @@base_unit_cache = {} - Unit.new(1) + def self.clear + @@cached_units = {} + @@base_unit_cache = {} + Unit.new(1) + end end - end end diff --git a/lib/ruby_units/date.rb b/lib/ruby_units/date.rb index b08a6705..27b55ab8 100644 --- a/lib/ruby_units/date.rb +++ b/lib/ruby_units/date.rb @@ -3,7 +3,7 @@ # Allow date objects to do offsets by a time unit # Date.today + Unit.new("1 week") => gives today+1 week class Date - alias_method :unit_date_add, :+ + alias unit_date_add + # @param [Object] other # @return [Unit] def +(other) @@ -16,7 +16,7 @@ def +(other) end end - alias_method :unit_date_sub, :- + alias unit_date_sub - # @param [Object] other # @return [Unit] def -(other) @@ -46,7 +46,7 @@ def to_time end # :nocov_19: - alias_method :units_datetime_inspect, :inspect + alias units_datetime_inspect inspect # @deprecated def inspect(dump = false) return units_datetime_inspect if dump diff --git a/lib/ruby_units/definition.rb b/lib/ruby_units/definition.rb index bdd7826b..8dd483e1 100644 --- a/lib/ruby_units/definition.rb +++ b/lib/ruby_units/definition.rb @@ -1,8 +1,6 @@ class RubyUnits::Unit < Numeric - # Handle the definition of units class Definition - # @return [Array] attr_writer :aliases @@ -30,14 +28,14 @@ class Definition # unit.definition = RubyUnits::Unit.new("7/4 inches") # end # - def initialize(_name, _definition = [], &block) + def initialize(name, definition = []) yield self if block_given? - self.name ||= _name.gsub(/[<>]/,'') - @aliases ||= (_definition[0] || [_name]) - @scalar ||= _definition[1] - @kind ||= _definition[2] - @numerator ||= _definition[3] || RubyUnits::Unit::UNITY_ARRAY - @denominator ||= _definition[4] || RubyUnits::Unit::UNITY_ARRAY + self.name ||= name.gsub(/[<>]/, '') + @aliases ||= (definition[0] || [name]) + @scalar ||= definition[1] + @kind ||= definition[2] + @numerator ||= definition[3] || RubyUnits::Unit::UNITY_ARRAY + @denominator ||= definition[4] || RubyUnits::Unit::UNITY_ARRAY @display_name ||= @aliases.first end @@ -46,14 +44,14 @@ def initialize(_name, _definition = [], &block) # @return [String, nil] # @todo refactor Unit and Unit::Definition so we don't need to wrap units with angle brackets def name - "<#{@name}>" if (defined?(@name) && @name) + "<#{@name}>" if defined?(@name) && @name end # set the name, strip off '<' and '>' # @param [String] # @return [String] - def name=(_name) - @name = _name.gsub(/[<>]/,'') + def name=(name_value) + @name = name_value.gsub(/[<>]/, '') end # alias array must contain the name of the unit and entries must be unique @@ -66,35 +64,35 @@ def aliases # @param [Unit] unit # @return [Unit::Definition] def definition=(unit) - _base = unit.to_base - @scalar = _base.scalar - @kind = _base.kind - @numerator = _base.numerator - @denominator = _base.denominator + base = unit.to_base + @scalar = base.scalar + @kind = base.kind + @numerator = base.numerator + @denominator = base.denominator self end # is this definition for a prefix? # @return [Boolean] def prefix? - self.kind == :prefix + kind == :prefix end # Is this definition the unity definition? # @return [Boolean] def unity? - self.prefix? && self.scalar == 1 + prefix? && scalar == 1 end # is this a base unit? # units are base units if the scalar is one, and the unit is defined in terms of itself. # @return [Boolean] def base? - (self.denominator == RubyUnits::Unit::UNITY_ARRAY) && - (self.numerator != RubyUnits::Unit::UNITY_ARRAY) && - (self.numerator.size == 1) && - (self.scalar == 1) && - (self.numerator.first == self.name) + (denominator == RubyUnits::Unit::UNITY_ARRAY) && + (numerator != RubyUnits::Unit::UNITY_ARRAY) && + (numerator.size == 1) && + (scalar == 1) && + (numerator.first == self.name) end end end diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index 5eea1838..bced95e9 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -1,14 +1,13 @@ require 'mathn' -# Math will convert unit objects to radians and then attempt to use the value for -# trigonometric functions. +# Math will convert unit objects to radians and then attempt to use the value for +# trigonometric functions. module Math - - alias :unit_sqrt :sqrt + alias unit_sqrt sqrt # @return [Numeric] def sqrt(n) if RubyUnits::Unit === n - (n**(Rational(1,2))).to_unit + (n**Rational(1, 2)).to_unit else unit_sqrt(n) end @@ -19,12 +18,12 @@ def sqrt(n) module_function :sqrt #:nocov: - if self.respond_to?(:cbrt) - alias :unit_cbrt :cbrt + if respond_to?(:cbrt) + alias unit_cbrt cbrt # @return [Numeric] def cbrt(n) if RubyUnits::Unit === n - (n**(Rational(1,3))).to_unit + (n**Rational(1, 3)).to_unit else unit_cbrt(n) end @@ -35,18 +34,18 @@ def cbrt(n) module_function :cbrt end #:nocov: - - alias :unit_sin :sin + + alias unit_sin sin # @return [Numeric] def sin(n) - RubyUnits::Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) + RubyUnits::Unit === n ? unit_sin(n.convert_to('radian').scalar) : unit_sin(n) end # @return [Numeric] module_function :unit_sin # @return [Numeric] module_function :sin - alias :unit_cos :cos + alias unit_cos cos # @return [Numeric] def cos(n) RubyUnits::Unit === n ? unit_cos(n.convert_to('radian').scalar) : unit_cos(n) @@ -55,8 +54,8 @@ def cos(n) module_function :unit_cos # @return [Numeric] module_function :cos - - alias :unit_sinh :sinh + + alias unit_sinh sinh # @return [Numeric] def sinh(n) RubyUnits::Unit === n ? unit_sinh(n.convert_to('radian').scalar) : unit_sinh(n) @@ -66,7 +65,7 @@ def sinh(n) # @return [Numeric] module_function :sinh - alias :unit_cosh :cosh + alias unit_cosh cosh # @return [Numeric] def cosh(n) RubyUnits::Unit === n ? unit_cosh(n.convert_to('radian').scalar) : unit_cosh(n) @@ -76,17 +75,17 @@ def cosh(n) # @return [Numeric] module_function :cosh - alias :unit_tan :tan + alias unit_tan tan # @return [Numeric] def tan(n) - RubyUnits::Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) + RubyUnits::Unit === n ? unit_tan(n.convert_to('radian').scalar) : unit_tan(n) end # @return [Numeric] module_function :tan # @return [Numeric] module_function :unit_tan - alias :unit_tanh :tanh + alias unit_tanh tanh # @return [Numeric] def tanh(n) RubyUnits::Unit === n ? unit_tanh(n.convert_to('radian').scalar) : unit_tanh(n) @@ -96,36 +95,34 @@ def tanh(n) # @return [Numeric] module_function :tanh - alias :unit_hypot :hypot + alias unit_hypot hypot # Convert parameters to consistent units and perform the function # @return [Numeric] - def hypot(x,y) + def hypot(x, y) if RubyUnits::Unit === x && RubyUnits::Unit === y - (x**2 + y**2)**(1/2) + (x**2 + y**2)**(1 / 2) else - unit_hypot(x,y) + unit_hypot(x, y) end end # @return [Numeric] module_function :unit_hypot # @return [Numeric] module_function :hypot - - alias :unit_atan2 :atan2 - # @return [Numeric] - def atan2(x,y) - case - when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x !~ y) - raise ArgumentError, "Incompatible RubyUnits::Units" - when (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x =~ y) - Math::unit_atan2(x.base_scalar, y.base_scalar) + + alias unit_atan2 atan2 + # @return [Numeric] + def atan2(x, y) + if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x !~ y) + raise ArgumentError, 'Incompatible RubyUnits::Units' + elsif (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x =~ y) + Math.unit_atan2(x.base_scalar, y.base_scalar) else - Math::unit_atan2(x,y) + Math.unit_atan2(x, y) end end # @return [Numeric] module_function :unit_atan2 # @return [Numeric] module_function :atan2 - end diff --git a/lib/ruby_units/string.rb b/lib/ruby_units/string.rb index bdf55125..24d0fd4f 100644 --- a/lib/ruby_units/string.rb +++ b/lib/ruby_units/string.rb @@ -6,19 +6,18 @@ def to_unit(other = nil) other ? RubyUnits::Unit.new(self).convert_to(other) : RubyUnits::Unit.new(self) end - alias_method :original_format, :% + alias original_format % # format unit output using formating codes # @example '%0.2f' % '1 mm'.to_unit => '1.00 mm' # @return [String] def format_with_unit(*other) - case - when other.first.is_a?(RubyUnits::Unit) + if other.first.is_a?(RubyUnits::Unit) other.first.to_s(self) else original_format(*other) end end - alias_method :%, :format_with_unit + alias % format_with_unit # @param (see RubyUnits::Unit#convert_to) # @return (see RubyUnits::Unit#convert_to) diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index a76a3fda..4111c9c8 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -5,7 +5,6 @@ # is in years, decades, or centuries. This leads to less precise values, but ones that match the # calendar better. class Time - class << self alias unit_time_at at end @@ -15,15 +14,15 @@ class << self # @param [Time] arg # @param [Integer] ms # @return [RubyUnits::Unit, Time] - def self.at(arg, ms=nil) + def self.at(arg, ms = nil) case arg when Time unit_time_at(arg) when RubyUnits::Unit if ms - unit_time_at(arg.convert_to("s").scalar, ms) + unit_time_at(arg.convert_to('s').scalar, ms) else - unit_time_at(arg.convert_to("s").scalar) + unit_time_at(arg.convert_to('s').scalar) end else ms.nil? ? unit_time_at(arg) : unit_time_at(arg, ms) @@ -41,16 +40,16 @@ def to_unit(other = nil) # :nocov_19: end - alias :unit_add :+ + alias unit_add + # @return [RubyUnits::Unit, Time] def +(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units + other = other.convert_to('d').round.convert_to('s') if %w(y decade century).include? other.units begin unit_add(other.convert_to('s').scalar) rescue RangeError - self.to_datetime + other + to_datetime + other end else unit_add(other) @@ -64,17 +63,17 @@ def self.in(duration) Time.now + duration.to_unit end - alias :unit_sub :- + alias unit_sub - # @return [RubyUnits::Unit, Time] def -(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if ['y', 'decade', 'century'].include? other.units + other = other.convert_to('d').round.convert_to('s') if %w(y decade century).include? other.units begin unit_sub(other.convert_to('s').scalar) rescue RangeError - self.send(:to_datetime) - other + send(:to_datetime) - other end else unit_sub(other) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index b56c3206..04fd1512 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -25,14 +25,14 @@ module RubyUnits class Unit < Numeric VERSION = Unit::Version::STRING @@definitions = {} - @@PREFIX_VALUES = {} - @@PREFIX_MAP = {} - @@UNIT_MAP = {} - @@UNIT_VALUES = {} - @@UNIT_REGEX = nil - @@UNIT_MATCH_REGEX = nil - UNITY = '<1>' - UNITY_ARRAY = [UNITY] + @@prefix_values = {} + @@prefix_map = {} + @@unit_map = {} + @@unit_values = {} + @@unit_regex = nil + @@unit_match_regex = nil + UNITY = '<1>'.freeze + UNITY_ARRAY = [UNITY].freeze # ideally we would like to generate this regex from the alias for a 'feet' and 'inches', but they aren't # defined at the point in the code where we need this regex. FEET_INCH_UNITS_REGEX = /(?:'|ft|feet)\s*(\d+)\s*(?:"|in|inch(?:es)?)/ @@ -44,7 +44,7 @@ class Unit < Numeric # ideally we would like to generate this regex from the alias for a 'stone' and 'pound', but they aren't # defined at the point in the code where we need this regex. # also note that the plural of 'stone' is still 'stone', but we accept 'stones' anyway. - STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/ + STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/ STONE_LB_REGEX = /(\d+)\s*#{STONE_LB_UNIT_REGEX}/ TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/ SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)} @@ -57,11 +57,11 @@ class Unit < Numeric NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/ COMPLEX_REGEX = /#{COMPLEX_NUMBER}\s?(.+)?/ RATIONAL_REGEX = /#{RATIONAL_NUMBER}\s?(.+)?/ - KELVIN = [''] - FAHRENHEIT = [''] - RANKINE = [''] - CELSIUS = [''] - @@TEMP_REGEX = nil + KELVIN = [''].freeze + FAHRENHEIT = [''].freeze + RANKINE = [''].freeze + CELSIUS = [''].freeze + @@temp_regex = nil SIGNATURE_VECTOR = [ :length, :time, @@ -73,14 +73,14 @@ class Unit < Numeric :currency, :information, :angle - ] - @@KINDS = { - -312078 => :elastance, - -312058 => :resistance, - -312038 => :inductance, - -152040 => :magnetism, - -152038 => :magnetism, - -152058 => :potential, + ].freeze + @@kinds = { + -312_078 => :elastance, + -312_058 => :resistance, + -312_038 => :inductance, + -152_040 => :magnetism, + -152_038 => :magnetism, + -152_058 => :potential, -7997 => :specific_volume, -79 => :snap, -59 => :jolt, @@ -108,65 +108,66 @@ class Unit < Numeric 7997 => :density, 7998 => :area_density, 8000 => :mass, - 152020 => :radiation_exposure, - 159999 => :magnetism, - 160000 => :current, - 160020 => :charge, - 312058 => :conductance, - 312078 => :capacitance, - 3199980 => :activity, - 3199997 => :molar_concentration, - 3200000 => :substance, - 63999998 => :illuminance, - 64000000 => :luminous_power, - 1280000000 => :currency, - 25600000000 => :information, - 511999999980 => :angular_velocity, - 512000000000 => :angle - } + 152_020 => :radiation_exposure, + 159_999 => :magnetism, + 160_000 => :current, + 160_020 => :charge, + 312_058 => :conductance, + 312_078 => :capacitance, + 3_199_980 => :activity, + 3_199_997 => :molar_concentration, + 3_200_000 => :substance, + 63_999_998 => :illuminance, + 64_000_000 => :luminous_power, + 1_280_000_000 => :currency, + 25_600_000_000 => :information, + 511_999_999_980 => :angular_velocity, + 512_000_000_000 => :angle + }.freeze @@cached_units = {} @@base_unit_cache = {} + # Class Methods + # setup internal arrays and hashes # @return [true] def self.setup - self.clear_cache - @@PREFIX_VALUES = {} - @@PREFIX_MAP = {} - @@UNIT_VALUES = {} - @@UNIT_MAP = {} - @@UNIT_REGEX = nil - @@UNIT_MATCH_REGEX = nil - @@PREFIX_REGEX = nil - - @@definitions.each do |name, definition| - self.use_definition(definition) + clear_cache + @@prefix_values = {} + @@prefix_map = {} + @@unit_values = {} + @@unit_map = {} + @@unit_regex = nil + @@unit_match_regex = nil + @@prefix_regex = nil + + @@definitions.each do |_name, definition| + use_definition(definition) end RubyUnits::Unit.new(1) - return true + true end - # determine if a unit is already defined # @param [String] unit # @return [Boolean] def self.defined?(unit) - self.definitions.values.any? { |d| d.aliases.include?(unit) } + definitions.values.any? { |d| d.aliases.include?(unit) } end # return the unit definition for a unit # @param [String] unit # @return [RubyUnits::Unit::Definition, nil] - def self.definition(_unit) - unit = (_unit =~ /^<.+>$/) ? _unit : "<#{_unit}>" - return @@definitions[unit] + def self.definition(unit_name) + unit = (unit_name =~ /^<.+>$/) ? unit_name : "<#{unit_name}>" + @@definitions[unit] end # return a list of all defined units # @return [Array] def self.definitions - return @@definitions + @@definitions end # @param [RubyUnits::Unit::Definition|String] unit_definition @@ -185,12 +186,12 @@ def self.definitions # RubyUnits::Unit.define(unit_definition) def self.define(unit_definition, &block) if block_given? - raise ArgumentError, "When using the block form of RubyUnits::Unit.define, pass the name of the unit" unless unit_definition.instance_of?(String) + raise ArgumentError, 'When using the block form of RubyUnits::Unit.define, pass the name of the unit' unless unit_definition.instance_of?(String) unit_definition = RubyUnits::Unit::Definition.new(unit_definition, &block) end RubyUnits::Unit.definitions[unit_definition.name] = unit_definition RubyUnits::Unit.use_definition(unit_definition) - return unit_definition + unit_definition end # @param [String] name Name of unit to redefine @@ -216,6 +217,186 @@ def self.undefine!(unit) RubyUnits::Unit.setup end + # @return [Hash] + def self.cached + @@cached_units + end + + # @return [true] + def self.clear_cache + @@cached_units = {} + @@base_unit_cache = {} + RubyUnits::Unit.new(1) + true + end + + # @return [Hash] + def self.base_unit_cache + @@base_unit_cache + end + + # @example parse strings + # "1 minute in seconds" + # @param [String] input + # @return [Unit] + def self.parse(input) + first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first + second.nil? ? RubyUnits::Unit.new(first) : RubyUnits::Unit.new(first).convert_to(second) + end + + # @param [Numeric] q quantity + # @param [Array] n numerator + # @param [Array] d denominator + # @return [Hash] + def self.eliminate_terms(q, n, d) + num = n.dup + den = d.dup + + num.delete_if { |v| v == UNITY } + den.delete_if { |v| v == UNITY } + combined = Hash.new(0) + + i = 0 + loop do + break if i > num.size + if @@prefix_values.has_key? num[i] + k = [num[i], num[i + 1]] + i += 2 + else + k = num[i] + i += 1 + end + combined[k] += 1 unless k.nil? || k == UNITY + end + + j = 0 + loop do + break if j > den.size + if @@prefix_values.has_key? den[j] + k = [den[j], den[j + 1]] + j += 2 + else + k = den[j] + j += 1 + end + combined[k] -= 1 unless k.nil? || k == UNITY + end + + num = [] + den = [] + for key, value in combined do + case + when value.positive? + value.times { num << key } + when value.negative? + value.abs.times { den << key } + end + end + num = UNITY_ARRAY if num.empty? + den = UNITY_ARRAY if den.empty? + { scalar: q, numerator: num.flatten.compact, denominator: den.flatten.compact } + end + + # return an array of base units + # @return [Array] + def self.base_units + @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) } + end + + # parse a string consisting of a number and a unit string + # NOTE: This does not properly handle units formatted like '12mg/6ml' + # @param [String] string + # @return [Array] consisting of [Numeric, "unit"] + def self.parse_into_numbers_and_units(string) + # scientific notation.... 123.234E22, -123.456e-10 + sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} + # rational numbers.... -1/3, 1/5, 20/100, -6 1/2, -6-1/2 + rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?} + # complex numbers... -1.2+3i, +1.2-3.3i + complex = %r{#{sci}{2,2}i} + anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?} + + num, unit = string.scan(anynumber).first + + [ + case num + when NilClass + 1 + when complex + if num.respond_to?(:to_c) + num.to_c + else + #:nocov_19: + Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map(&:to_i)) + #:nocov_19: + end + when rational + # if it has whitespace, it will be of the form '6 1/2' + if num =~ RATIONAL_NUMBER + sign = ($1 == '-') ? -1 : 1 + n = $2.to_i + f = Rational($3.to_i,$4.to_i) + sign * (n + f) + else + Rational(*num.split('/').map(&:to_i)) + end + else + num.to_f + end, + unit.to_s.strip + ] + end + + # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. + # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names + # @return [String] + def self.unit_regex + @@unit_regex ||= @@unit_map.keys.sort_by { |unit_name| [unit_name.length, unit_name] }.reverse.join('|') + end + + # return a regex used to match units + # @return [RegExp] + def self.unit_match_regex + @@unit_match_regex ||= /(#{RubyUnits::Unit.prefix_regex})??(#{RubyUnits::Unit.unit_regex})\b/ + end + + # return a regexp fragment used to match prefixes + # @return [String] + # @private + def self.prefix_regex + @@prefix_regex ||= @@prefix_map.keys.sort_by { |prefix| [prefix.length, prefix] }.reverse.join('|') + end + + def self.temp_regex + @@temp_regex ||= Regexp.new "(?:#{ + temp_units = %w(tempK tempC tempF tempR degK degC degF degR) + aliases = temp_units.map do |unit| + d = RubyUnits::Unit.definition(unit) + d && d.aliases + end.flatten.compact + regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') + regex_str + })" + end + + # inject a definition into the internal array and set it up for use + def self.use_definition(definition) + @@unit_match_regex = nil # invalidate the unit match regex + @@temp_regex = nil # invalidate the temp regex + if definition.prefix? + @@prefix_values[definition.name] = definition.scalar + definition.aliases.each { |alias_name| @@prefix_map[alias_name] = definition.name } + @@prefix_regex = nil # invalidate the prefix regex + else + @@unit_values[definition.name] = {} + @@unit_values[definition.name][:scalar] = definition.scalar + @@unit_values[definition.name][:numerator] = definition.numerator if definition.numerator + @@unit_values[definition.name][:denominator] = definition.denominator if definition.denominator + definition.aliases.each { |alias_name| @@unit_map[alias_name] = definition.name } + @@unit_regex = nil # invalidate the unit regex + end + end + include Comparable # @return [Numeric] @@ -249,7 +430,9 @@ def self.undefine!(unit) # @param [Class] # @return [Boolean] def kind_of?(klass) - self.scalar.kind_of?(klass) + # rubocop:disable Style/ClassCheck + scalar.kind_of?(klass) + # rubocop:enable Style/ClassCheck end # Used to copy one unit to another @@ -259,11 +442,11 @@ def copy(from) @scalar = from.scalar @numerator = from.numerator @denominator = from.denominator - @is_base = from.is_base? + @base = from.base? @signature = from.signature @base_scalar = from.base_scalar @unit_name = from.unit_name rescue nil - return self + self end # Create a new Unit object. Can be initialized using a String, a Hash, an Array, Time, DateTime @@ -279,7 +462,7 @@ def copy(from) # "6'4\""" -- recognized as 6 feet + 4 inches # "8 lbs 8 oz" -- recognized as 8 lbs + 8 ounces # [1, 'kg'] - # {:scalar => 1, :numerator=>'kg'} + # {scalar: 1, numerator: 'kg'} # # @param [Unit,String,Hash,Array,Date,Time,DateTime] options # @return [Unit] @@ -292,7 +475,7 @@ def initialize(*options) @unit_name = nil @signature = nil @output = {} - raise ArgumentError, "Invalid Unit Format" if options[0].nil? + raise ArgumentError, 'Invalid Unit Format' if options[0].nil? if options.size == 2 # options[0] is the scalar # options[1] is a unit string @@ -305,8 +488,8 @@ def initialize(*options) return end if options.size == 3 - options[1] = options[1].join if options[1].kind_of?(Array) - options[2] = options[2].join if options[2].kind_of?(Array) + options[1] = options[1].join if options[1].is_a?(Array) + options[2] = options[2].join if options[2].is_a?(Array) begin cached = @@cached_units["#{options[1]}/#{options[2]}"] * options[0] copy(cached) @@ -317,88 +500,58 @@ def initialize(*options) end case options[0] - when Unit - copy(options[0]) - return - when Hash - @scalar = options[0][:scalar] || 1 - @numerator = options[0][:numerator] || UNITY_ARRAY - @denominator = options[0][:denominator] || UNITY_ARRAY - @signature = options[0][:signature] - when Array - initialize(*options[0]) - return - when Numeric - @scalar = options[0] - @numerator = @denominator = UNITY_ARRAY - when Time - @scalar = options[0].to_f - @numerator = [''] - @denominator = UNITY_ARRAY - when DateTime, Date - @scalar = options[0].ajd - @numerator = [''] - @denominator = UNITY_ARRAY - when /^\s*$/ - raise ArgumentError, "No Unit Specified" - when String - parse(options[0]) - else - raise ArgumentError, "Invalid Unit Format" + when Unit + copy(options[0]) + return + when Hash + @scalar = options[0][:scalar] || 1 + @numerator = options[0][:numerator] || UNITY_ARRAY + @denominator = options[0][:denominator] || UNITY_ARRAY + @signature = options[0][:signature] + when Array + initialize(*options[0]) + return + when Numeric + @scalar = options[0] + @numerator = @denominator = UNITY_ARRAY + when Time + @scalar = options[0].to_f + @numerator = [''] + @denominator = UNITY_ARRAY + when DateTime, Date + @scalar = options[0].ajd + @numerator = [''] + @denominator = UNITY_ARRAY + when /^\s*$/ + raise ArgumentError, 'No Unit Specified' + when String + parse(options[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 || "" + update_base_scalar + raise ArgumentError, 'Temperatures must not be less than absolute zero' if temperature? && base_scalar.negative? + unary_unit = units || '' if options.first.instance_of?(String) opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ %r{\D/[\d+\.]+}) || (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) - @@cached_units[opt_units] = (self.scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? + @@cached_units[opt_units] = (scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? end end unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) then - @@cached_units[unary_unit] = (self.scalar == 1 ? self : unary_unit.to_unit) + @@cached_units[unary_unit] = (scalar == 1 ? self : unary_unit.to_unit) end - [@scalar, @numerator, @denominator, @base_scalar, @signature, @is_base].each { |x| x.freeze } - return self + [@scalar, @numerator, @denominator, @base_scalar, @signature, @base].each(&:freeze) + self end # @todo: figure out how to handle :counting units. This method should probably return :counting instead of :unitless for 'each' # return the kind of the unit (:mass, :length, etc...) # @return [Symbol] def kind - return @@KINDS[self.signature] - end - - # @private - # @return [Hash] - def self.cached - return @@cached_units - end - - # @private - # @return [true] - def self.clear_cache - @@cached_units = {} - @@base_unit_cache = {} - RubyUnits::Unit.new(1) - return true - end - - # @private - # @return [Hash] - def self.base_unit_cache - return @@base_unit_cache - end - - # @example parse strings - # "1 minute in seconds" - # @param [String] input - # @return [Unit] - def self.parse(input) - first, second = input.scan(/(.+)\s(?:in|to|as)\s(.+)/i).first - second.nil? ? RubyUnits::Unit.new(first) : RubyUnits::Unit.new(first).convert_to(second) + @@kinds[signature] end # @return [Unit] @@ -406,59 +559,59 @@ def to_unit self end - alias :unit :to_unit + alias unit to_unit # Is this unit in base form? # @return [Boolean] - def is_base? - return @is_base if defined? @is_base - @is_base = (@numerator + @denominator).compact.uniq. + def base? + return @base if defined? @base + @base = (@numerator + @denominator).compact.uniq. map { |unit| RubyUnits::Unit.definition(unit) }. all? { |element| element.unity? || element.base? } - return @is_base + @base end - alias :base? :is_base? + alias is_base? base? # convert to base SI units # results of the conversion are cached so subsequent calls to this will be fast # @return [Unit] # @todo this is brittle as it depends on the display_name of a unit, which can be changed def to_base - return self if self.is_base? - if @@UNIT_MAP[self.units] =~ /\A<(?:temp|deg)[CRF]>\Z/ - @signature = @@KINDS.key(:temperature) + return self if base? + if @@unit_map[units] =~ /\A<(?:temp|deg)[CRF]>\Z/ + @signature = @@kinds.key(:temperature) base = case - when self.is_temperature? - self.convert_to('tempK') - when self.is_degree? - self.convert_to('degK') + when temperature? + convert_to('tempK') + when degree? + convert_to('degK') end return base end - cached = ((@@base_unit_cache[self.units] * self.scalar) rescue nil) + cached = ((@@base_unit_cache[units] * 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] + 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] + 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] + 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] + 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 @@ -466,11 +619,11 @@ def to_base den = den.flatten.compact num = UNITY_ARRAY if num.empty? base = RubyUnits::Unit.new(RubyUnits::Unit.eliminate_terms(q, num, den)) - @@base_unit_cache[self.units]=base - return base * @scalar + @@base_unit_cache[units] = base + base * @scalar end - alias :base :to_base + alias base to_base # Generate human readable output. # If the name of a unit is passed, the unit will first be converted to the target unit before output. @@ -487,46 +640,46 @@ def to_base # # @param [Symbol] target_units # @return [String] - def to_s(target_units=nil) + def to_s(target_units = nil) out = @output[target_units] if out return out else case target_units when :ft - inches = self.convert_to("in").scalar.to_int + inches = convert_to('in').scalar.to_int out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" when :lbs - ounces = self.convert_to("oz").scalar.to_int + ounces = convert_to('oz').scalar.to_int out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" when :stone - pounds = self.convert_to("lbs").scalar.to_int + pounds = convert_to('lbs').scalar.to_int out = "#{(pounds / 14).truncate} stone, #{(pounds % 14).round} lb" when String out = case target_units.strip when /\A\s*\Z/ # whitespace only '' - when /(%[\-+\.\w#]+)\s*(.+)*/ #format string like '%0.2f in' + when /(%[\-+\.\w#]+)\s*(.+)*/ # format string like '%0.2f in' begin - if $2 #unit specified, need to convert - self.convert_to($2).to_s($1) + if $2 # unit specified, need to convert + convert_to($2).to_s($1) else - "#{$1 % @scalar} #{$2 || self.units}".strip + "#{$1 % @scalar} #{$2 || units}".strip end rescue # parse it like a strftime format string (DateTime.new(0) + self).strftime(target_units) end - when /(\S+)/ #unit only 'mm' or '1/mm' - self.convert_to($1).to_s + when /(\S+)/ # unit only 'mm' or '1/mm' + convert_to($1).to_s else - raise "unhandled case" + raise 'unhandled case' end else out = case @scalar when Rational, Complex - "#{@scalar} #{self.units}" + "#{@scalar} #{units}" else - "#{'%g' % @scalar} #{self.units}" + "#{'%g' % @scalar} #{units}" end.strip end @output[target_units] = out @@ -545,33 +698,33 @@ def inspect(dump = nil) # true if unit is a 'temperature', false if a 'degree' or anything else # @return [Boolean] # @todo use unit definition to determine if it's a temperature instead of a regex - def is_temperature? - return self.is_degree? && (!(@@UNIT_MAP[self.units] =~ /temp[CFRK]/).nil?) + def temperature? + degree? && (!(@@unit_map[units] =~ /temp[CFRK]/).nil?) end - alias :temperature? :is_temperature? + alias is_temperature? temperature? # true if a degree unit or equivalent. # @return [Boolean] - def is_degree? - return self.kind == :temperature + def degree? + kind == :temperature end - alias :degree? :is_degree? + alias is_degree? degree? # returns the 'degree' unit associated with a temperature unit # @example '100 tempC'.to_unit.temperature_scale #=> 'degC' # @return [String] possible values: degC, degF, degR, or degK def temperature_scale - return nil unless self.is_temperature? - return "deg#{@@UNIT_MAP[self.units][/temp([CFRK])/, 1]}" + return nil unless temperature? + "deg#{@@unit_map[units][/temp([CFRK])/, 1]}" end # returns true if no associated units # false, even if the units are "unitless" like 'radians, each, etc' # @return [Boolean] def unitless? - return(@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) + (@numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY) end # Compare two Unit objects. Throws an exception if they are not of compatible types. @@ -582,18 +735,18 @@ def unitless? # @raise [ArgumentError] when units are not compatible def <=>(other) case - when !self.base_scalar.respond_to?(:<=>) - raise NoMethodError, "undefined method `<=>' for #{self.base_scalar.inspect}" - when other.nil? - return self.base_scalar <=> nil - when !self.is_temperature? && other.respond_to?(:zero?) && other.zero? - return self.base_scalar <=> 0 - when other.instance_of?(Unit) - raise ArgumentError, "Incompatible Units ('#{self.units}' not compatible with '#{other.units}')" unless self =~ other - return self.base_scalar <=> other.base_scalar - else - x, y = coerce(other) - return y <=> x + when !base_scalar.respond_to?(:<=>) + raise NoMethodError, "undefined method `<=>' for #{base_scalar.inspect}" + when other.nil? + base_scalar <=> nil + when !temperature? && other.respond_to?(:zero?) && other.zero? + base_scalar <=> 0 + when other.instance_of?(Unit) + raise ArgumentError, "Incompatible Units ('#{units}' not compatible with '#{other.units}')" unless self =~ other + base_scalar <=> other.base_scalar + else + x, y = coerce(other) + y <=> x end end @@ -607,18 +760,18 @@ def <=>(other) # @return [Boolean] 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 - begin - x, y = coerce(other) - return x == y - rescue ArgumentError # return false when object cannot be coerced - return false - end + when other.respond_to?(:zero?) && other.zero? + zero? + when other.instance_of?(Unit) + return false unless self =~ other + base_scalar == other.base_scalar + else + begin + x, y = coerce(other) + x == y + rescue ArgumentError # return false when object cannot be coerced + false + end end end @@ -633,20 +786,20 @@ def ==(other) # @return [Boolean] def =~(other) case other - when Unit - self.signature == other.signature - else - begin - x, y = coerce(other) - return x =~ y - rescue ArgumentError - return false - end + when Unit + signature == other.signature + else + begin + x, y = coerce(other) + return x =~ y + rescue ArgumentError + return false + end end end - alias :compatible? :=~ - alias :compatible_with? :=~ + alias compatible? =~ + alias compatible_with? =~ # Compare two units. Returns true if quantities and units match # @example @@ -656,20 +809,20 @@ def =~(other) # @return [Boolean] def ===(other) case other - when Unit - (self.scalar == other.scalar) && (self.units == other.units) - else - begin - x, y = coerce(other) - return x === y - rescue ArgumentError - return false - end + when Unit + (scalar == other.scalar) && (units == other.units) + else + begin + x, y = coerce(other) + return x === y + rescue ArgumentError + return false + end end end - alias :same? :=== - alias :same_as? :=== + alias same? === + alias same_as? === # 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. @@ -681,30 +834,30 @@ def ===(other) # @raise [ArgumentError] when adding a fixed time or date to a time span 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? - RubyUnits::Unit.new(:scalar => (self.scalar + other.convert_to(self.temperature_scale).scalar), :numerator => @numerator, :denominator => @denominator, :signature => @signature) - else - RubyUnits::Unit.new(:scalar => (other.scalar + self.convert_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.to_unit.to_base.scalar)) - RubyUnits::Unit.new(:scalar => (self.base_scalar + other.base_scalar)*@q, :numerator => @numerator, :denominator => @denominator, :signature => @signature) - end + when Unit + case + when zero? + other.dup + when self =~ other + raise ArgumentError, 'Cannot add two temperatures' if [self, other].all?(&:temperature?) + if [self, other].any?(&:temperature?) + if temperature? + RubyUnits::Unit.new(scalar: (scalar + other.convert_to(temperature_scale).scalar), numerator: @numerator, denominator: @denominator, signature: @signature) else - raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" + RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature) + end + else + @q ||= ((@@cached_units[units].scalar / @@cached_units[units].base_scalar) rescue units.to_unit.to_base.scalar) + RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) 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 + 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 @@ -716,34 +869,34 @@ def +(other) # @raise [ArgumentError] when subtracting a fixed time from a time span def -(other) case other - when Unit + when Unit + case + when zero? + if other.zero? + other.dup * -1 # preserve Units class + else + -other.dup + end + when self =~ other case - when self.zero? - if other.zero? - other.dup * -1 # preserve Units class - else - -other.dup - end - when self =~ other - case - when [self, other].all? { |x| x.is_temperature? } - RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => KELVIN, :denominator => UNITY_ARRAY, :signature => @signature).convert_to(self.temperature_scale) - when self.is_temperature? - RubyUnits::Unit.new(:scalar => (self.base_scalar - other.base_scalar), :numerator => [''], :denominator => UNITY_ARRAY, :signature => @signature).convert_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.to_unit.scalar/self.units.to_unit.to_base.scalar)) - RubyUnits::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}')" + when [self, other].all?(&:temperature?) + RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: KELVIN, denominator: UNITY_ARRAY, signature: @signature).convert_to(temperature_scale) + when temperature? + RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: [''], denominator: UNITY_ARRAY, signature: @signature).convert_to(self) + when other.temperature? + raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' + else + @q ||= ((@@cached_units[units].scalar / @@cached_units[units].base_scalar) rescue (units.to_unit.scalar / units.to_unit.to_base.scalar)) + RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) 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) - return y-x + 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 @@ -753,16 +906,16 @@ def -(other) # @raise [ArgumentError] when attempting to multiply two temperatures 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) - when Numeric - return RubyUnits::Unit.new(:scalar => @scalar*other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) - else - x, y = coerce(other) - return x * y + when Unit + raise ArgumentError, 'Cannot multiply by temperatures' if [other, self].any?(&:temperature?) + opts = RubyUnits::Unit.eliminate_terms(@scalar * other.scalar, @numerator + other.numerator, @denominator + other.denominator) + opts[:signature] = @signature + other.signature + RubyUnits::Unit.new(opts) + when Numeric + RubyUnits::Unit.new(scalar: @scalar * other, numerator: @numerator, denominator: @denominator, signature: @signature) + else + x, y = coerce(other) + x * y end end @@ -774,18 +927,18 @@ def *(other) # @raise [ArgumentError] if attempting to divide a temperature by another temperature 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 = RubyUnits::Unit.eliminate_terms(@scalar/other.scalar, @numerator + other.denominator, @denominator + other.numerator) - opts.merge!(:signature => @signature - other.signature) - return RubyUnits::Unit.new(opts) - when Numeric - raise ZeroDivisionError if other.zero? - return RubyUnits::Unit.new(:scalar => @scalar/other, :numerator => @numerator, :denominator => @denominator, :signature => @signature) - else - x, y = coerce(other) - return y / x + when Unit + raise ZeroDivisionError if other.zero? + raise ArgumentError, 'Cannot divide with temperatures' if [other, self].any?(&:temperature?) + opts = RubyUnits::Unit.eliminate_terms(@scalar / other.scalar, @numerator + other.denominator, @denominator + other.numerator) + opts[:signature] = @signature - other.signature + RubyUnits::Unit.new(opts) + when Numeric + raise ZeroDivisionError if other.zero? + RubyUnits::Unit.new(scalar: @scalar / other, numerator: @numerator, denominator: @denominator, signature: @signature) + else + x, y = coerce(other) + y / x end end @@ -796,10 +949,10 @@ def /(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) + if units == other.units + return scalar.divmod(other.scalar) else - return self.to_base.scalar.divmod(other.to_base.scalar) + return to_base.scalar.divmod(other.to_base.scalar) end end @@ -807,7 +960,7 @@ def divmod(other) # @param [Object] other # @return [Integer] def %(other) - return self.divmod(other).last + divmod(other).last end # Exponentiate. Only takes integer powers. @@ -825,26 +978,26 @@ def %(other) # @raise [ArgumentError] when attempting to raise to a complex number # @raise [ArgumentError] when an invalid exponent is passed 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 + raise ArgumentError, 'Cannot raise a temperature to a power' if temperature? + if other.is_a?(Numeric) + return inverse if other == -1 return self if other == 1 return 1 if other.zero? end case other - when Rational - return self.power(other.numerator).root(other.denominator) - when Integer - return 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 - return self.root((1/other).to_int) - when Complex - raise ArgumentError, "exponentiation of complex numbers is not yet supported." - else - raise ArgumentError, "Invalid Exponent" + when Rational + return power(other.numerator).root(other.denominator) + when Integer + return 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 + return root((1 / other).to_int) + when Complex + raise ArgumentError, 'exponentiation of complex numbers is not yet supported.' + else + raise ArgumentError, 'Invalid Exponent' end end @@ -854,15 +1007,15 @@ def **(other) # @raise [ArgumentError] when attempting to raise a temperature to a power # @raise [ArgumentError] when n is not an integer 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 + raise ArgumentError, 'Cannot raise a temperature to a power' if temperature? + raise ArgumentError, 'Exponent must an Integer' unless n.is_a?(Integer) + return inverse if n == -1 return 1 if n.zero? return self if n == 1 - if n > 0 then - return (1..(n-1).to_i).inject(self) { |product, x| product * self } + if n.positive? then + return (1..(n - 1).to_i).inject(self) { |product, _| product * self } else - return (1..-(n-1).to_i).inject(self) { |product, x| product / self } + return (1..-(n - 1).to_i).inject(self) { |product, _| product / self } end end @@ -874,37 +1027,37 @@ def power(n) # @raise [ArgumentError] when n is not an integer # @raise [ArgumentError] when n is 0 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? + raise ArgumentError, 'Cannot take the root of a temperature' if temperature? + raise ArgumentError, 'Exponent must an Integer' unless n.is_a?(Integer) + raise ArgumentError, '0th root undefined' if n.zero? return self if n == 1 - return self.root(n.abs).inverse if n < 0 + return root(n.abs).inverse if n.negative? - vec = self.unit_signature_vector - vec =vec.map { |x| x % n } - raise ArgumentError, "Illegal root" unless vec.max == 0 + vec = unit_signature_vector + vec = vec.map { |x| x % n } + raise ArgumentError, 'Illegal root' unless vec.max.zero? 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)) } + x = num.find_all { |i| i == item }.size + r = ((x / n) * (n - 1)).to_int + r.times { 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)) } + x = den.find_all { |i| i == item }.size + r = ((x / n) * (n - 1)).to_int + r.times { den.delete_at(den.index(item)) } end - q = @scalar < 0 ? (-1)**Rational(1, n) * (@scalar.abs)**Rational(1, n) : @scalar**Rational(1, n) - return RubyUnits::Unit.new(:scalar => q, :numerator => num, :denominator => den) + q = @scalar.negative? ? (-1)**Rational(1, n) * (@scalar.abs)**Rational(1, n) : @scalar**Rational(1, n) + RubyUnits::Unit.new(scalar: q, numerator: num, denominator: den) end # returns inverse of Unit (1/unit) # @return [Unit] def inverse - return RubyUnits::Unit.new("1") / self + RubyUnits::Unit.new('1') / self end # convert to a specified unit string or to the same units as another Unit @@ -930,90 +1083,90 @@ def convert_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 + if (Unit === other && other.temperature?) || (String === other && other =~ /temp[CFRK]/) + raise ArgumentError, 'Receiver is not a temperature unit' unless degree? + start_unit = units target_unit = other.units rescue other unless @base_scalar - @base_scalar = case @@UNIT_MAP[start_unit] - when '' - @scalar + 273.15 - when '' - @scalar - when '' - (@scalar+459.67)*Rational(5, 9) - when '' - @scalar*Rational(5, 9) + @base_scalar = case @@unit_map[start_unit] + when '' + @scalar + 273.15 + when '' + @scalar + when '' + (@scalar + 459.67) * Rational(5, 9) + when '' + @scalar * Rational(5, 9) end end - q= case @@UNIT_MAP[target_unit] - when '' - @base_scalar - 273.15 - when '' - @base_scalar - when '' - @base_scalar * Rational(9, 5) - 459.67 - when '' - @base_scalar * Rational(9, 5) - end + q = case @@unit_map[target_unit] + when '' + @base_scalar - 273.15 + when '' + @base_scalar + when '' + @base_scalar * Rational(9, 5) - 459.67 + when '' + @base_scalar * Rational(9, 5) + end return RubyUnits::Unit.new("#{q} #{target_unit}") else case other - when Unit - return self if other.units == self.units - target = other - when String - target = RubyUnits::Unit.new(other) - else - raise ArgumentError, "Unknown target units" + when Unit + return self if other.units == units + target = other + when String + target = RubyUnits::Unit.new(other) + else + raise ArgumentError, 'Unknown target units' end raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" 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 - - q = @scalar * ((_numerator1 + _denominator2).inject(1) { |product, n| product*n }) / - ((_numerator2 + _denominator1).inject(1) { |product, n| product*n }) - return RubyUnits::Unit.new(:scalar => q, :numerator => target.numerator, :denominator => target.denominator, :signature => target.signature) + numerator1 = @numerator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact + denominator1 = @denominator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |i| i.is_a?(Numeric) ? i : @@unit_values[i][:scalar] }.compact + numerator2 = target.numerator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact + denominator2 = target.denominator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact + + q = @scalar * ((numerator1 + denominator2).inject(1) { |product, n| product * n }) / + ((numerator2 + denominator1).inject(1) { |product, n| product * n }) + return RubyUnits::Unit.new(scalar: q, numerator: target.numerator, denominator: target.denominator, signature: target.signature) end end - alias :>> :convert_to - alias :to :convert_to + alias >> convert_to + alias to convert_to # converts the unit back to a float if it is unitless. Otherwise raises an exception # @return [Float] # @raise [RuntimeError] when not unitless def to_f - return @scalar.to_f if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Float unless unitless. Use Unit#scalar" + return @scalar.to_f if unitless? + raise RuntimeError, "Cannot convert '#{self}' to Float unless unitless. Use Unit#scalar" end # converts the unit back to a complex if it is unitless. Otherwise raises an exception # @return [Complex] # @raise [RuntimeError] when not unitless def to_c - return Complex(@scalar) if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Complex unless unitless. Use Unit#scalar" + return Complex(@scalar) if unitless? + raise RuntimeError, "Cannot convert '#{self}' to Complex unless unitless. Use Unit#scalar" end # if unitless, returns an int, otherwise raises an error # @return [Integer] # @raise [RuntimeError] when not unitless def to_i - return @scalar.to_int if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Integer unless unitless. Use Unit#scalar" + return @scalar.to_int if unitless? + raise RuntimeError, "Cannot convert '#{self}' to Integer unless unitless. Use Unit#scalar" end - alias :to_int :to_i + alias to_int to_i # if unitless, returns a Rational, otherwise raises an error # @return [Rational] # @raise [RuntimeError] when not unitless def to_r - return @scalar.to_r if self.unitless? - raise RuntimeError, "Cannot convert '#{self.to_s}' to Rational unless unitless. Use Unit#scalar" + return @scalar.to_r if unitless? + raise RuntimeError, "Cannot convert '#{self}' to Rational unless unitless. Use Unit#scalar" end # Returns string formatted for json @@ -1025,14 +1178,14 @@ def as_json(*args) # returns the 'unit' part of the Unit object without the scalar # @return [String] def units(with_prefix = true) - return "" if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY + return '' if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY output_numerator = [] output_denominator = [] num = @numerator.clone.compact den = @denominator.clone.compact if @numerator == UNITY_ARRAY - output_numerator << "1" + output_numerator << '1' else while defn = RubyUnits::Unit.definition(num.shift) do if defn && defn.prefix? @@ -1066,46 +1219,46 @@ def units(with_prefix = true) map { |x| [x, output_denominator.count(x)] }. map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } out = "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip - return out + out end # negates the scalar of the Unit # @return [Numeric,Unit] def -@ - return -@scalar if self.unitless? - return (self.dup * -1) + return -@scalar if unitless? + dup * -1 end # absolute value of a unit # @return [Numeric,Unit] def abs - return @scalar.abs if self.unitless? - return RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator) + return @scalar.abs if unitless? + RubyUnits::Unit.new(@scalar.abs, @numerator, @denominator) end # ceil of a unit # @return [Numeric,Unit] def ceil - return @scalar.ceil if self.unitless? - return RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator) + return @scalar.ceil if unitless? + RubyUnits::Unit.new(@scalar.ceil, @numerator, @denominator) end # @return [Numeric,Unit] def floor - return @scalar.floor if self.unitless? - return RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator) + return @scalar.floor if unitless? + RubyUnits::Unit.new(@scalar.floor, @numerator, @denominator) end # @return [Numeric,Unit] def round(ndigits = 0) - return @scalar.round(ndigits) if self.unitless? - return RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) + return @scalar.round(ndigits) if unitless? + RubyUnits::Unit.new(@scalar.round(ndigits), @numerator, @denominator) end # @return [Numeric, Unit] def truncate - return @scalar.truncate if self.unitless? - return RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator) + return @scalar.truncate if unitless? + RubyUnits::Unit.new(@scalar.truncate, @numerator, @denominator) end # returns next unit in a range. '1 mm'.to_unit.succ #=> '2 mm'.to_unit @@ -1113,65 +1266,65 @@ def truncate # @return [Unit] # @raise [ArgumentError] when scalar is not equal to an integer def succ - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return RubyUnits::Unit.new(@scalar.to_i.succ, @numerator, @denominator) + raise ArgumentError, 'Non Integer Scalar' unless @scalar == @scalar.to_i + RubyUnits::Unit.new(@scalar.to_i.succ, @numerator, @denominator) end - alias :next :succ + alias next succ # returns previous unit in a range. '2 mm'.to_unit.pred #=> '1 mm'.to_unit # only works when the scalar is an integer # @return [Unit] # @raise [ArgumentError] when scalar is not equal to an integer def pred - raise ArgumentError, "Non Integer Scalar" unless @scalar == @scalar.to_i - return RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator) + raise ArgumentError, 'Non Integer Scalar' unless @scalar == @scalar.to_i + RubyUnits::Unit.new(@scalar.to_i.pred, @numerator, @denominator) end # Tries to make a Time object from current unit. Assumes the current unit hold the duration in seconds from the epoch. # @return [Time] def to_time - return Time.at(self) + Time.at(self) end - alias :time :to_time + alias time to_time # convert a duration to a DateTime. This will work so long as the duration is the duration from the zero date # defined by DateTime # @return [DateTime] def to_datetime - return DateTime.new!(self.convert_to('d').scalar) + DateTime.new!(convert_to('d').scalar) end # @return [Date] def to_date - return Date.new0(self.convert_to('d').scalar) + Date.new0(convert_to('d').scalar) end # true if scalar is zero # @return [Boolean] def zero? - return self.base_scalar.zero? + base_scalar.zero? end # @example '5 min'.to_unit.ago # @return [Unit] def ago - return self.before + before end # @example '5 min'.before(time) # @return [Unit] def before(time_point = ::Time.now) case time_point - when Time, Date, DateTime - return (time_point - self rescue time_point.to_datetime - self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + when Time, Date, DateTime + return (time_point - self rescue time_point.to_datetime - self) + else + raise ArgumentError, 'Must specify a Time, Date, or DateTime' end end - alias :before_now :before + alias before_now before # @example 'min'.since(time) # @param [Time, Date, DateTime] time_point @@ -1180,9 +1333,9 @@ def before(time_point = ::Time.now) def since(time_point) case time_point when Time - return (Time.now - time_point).to_unit('s').convert_to(self) + (Time.now - time_point).to_unit('s').convert_to(self) when DateTime, Date - return (DateTime.now - time_point).to_unit('d').convert_to(self) + (DateTime.now - time_point).to_unit('d').convert_to(self) else fail ArgumentError, 'Must specify a Time, Date, or DateTime' end @@ -1194,9 +1347,9 @@ def since(time_point) def until(time_point) case time_point when Time - return (time_point - Time.now).to_unit('s').convert_to(self) + (time_point - Time.now).to_unit('s').convert_to(self) when DateTime, Date - return (time_point - DateTime.now).to_unit('d').convert_to(self) + (time_point - DateTime.now).to_unit('d').convert_to(self) else fail ArgumentError, 'Must specify a Time, Date, or DateTime' end @@ -1208,41 +1361,39 @@ def until(time_point) # @raise [ArgumentError] when passed argument is not a Time, Date, or DateTime def from(time_point) case time_point - when Time, DateTime, Date - return (time_point + self rescue time_point.to_datetime + self) - else - raise ArgumentError, "Must specify a Time, Date, or DateTime" + when Time, DateTime, Date + (time_point + self rescue time_point.to_datetime + self) + else + raise ArgumentError, 'Must specify a Time, Date, or DateTime' end end - alias :after :from - alias :from_now :from + alias after from + alias from_now from # automatically coerce objects to units when possible # if an object defines a 'to_unit' method, it will be coerced using that method # @param [Object, #to_unit] # @return [Array] def coerce(other) - if other.respond_to? :to_unit - return [other.to_unit, self] - end + return [other.to_unit, self] if other.respond_to? :to_unit case other - when Unit - return [other, self] - else - return [RubyUnits::Unit.new(other), self] + when Unit + [other, self] + else + [RubyUnits::Unit.new(other), self] end end # returns a new unit that has been scaled to be more in line with typical usage. def best_prefix - return self.to_base if self.scalar == 0 - _best_prefix = if (self.kind == :information) - @@PREFIX_VALUES.key(2**((Math.log(self.base_scalar,2) / 10.0).floor * 10)) + return to_base if scalar.zero? + best_prefix = if kind == :information + @@prefix_values.key(2**((Math.log(base_scalar,2) / 10.0).floor * 10)) else - @@PREFIX_VALUES.key(10**((Math.log10(self.base_scalar) / 3.0).floor * 3)) + @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3)) end - self.to(RubyUnits::Unit.new(@@PREFIX_MAP.key(_best_prefix)+self.units(false))) + to(RubyUnits::Unit.new(@@prefix_map.key(best_prefix) + units(false))) end # override hash method so objects with same values are considered equal @@ -1250,7 +1401,7 @@ def hash [@scalar, @numerator, @denominator, - @is_base, + @base, @signature, @base_scalar, @unit_name].hash @@ -1262,11 +1413,11 @@ def hash # figure out what the scalar part of the base unit for this unit is # @return [nil] def update_base_scalar - if self.is_base? + if base? @base_scalar = @scalar @signature = unit_signature else - base = self.to_base + base = to_base @base_scalar = base.scalar @signature = base.signature end @@ -1276,7 +1427,7 @@ def update_base_scalar # @return [Array] # @raise [ArgumentError] when exponent associated with a unit is > 20 or < -20 def unit_signature_vector - return self.to_base.unit_signature_vector unless self.is_base? + return to_base.unit_signature_vector unless base? vector = Array.new(SIGNATURE_VECTOR.size, 0) # it's possible to have a kind that misses the array... kinds like :counting # are more like prefixes, so don't use them to calculate the vector @@ -1288,11 +1439,10 @@ def unit_signature_vector index = SIGNATURE_VECTOR.index(definition.kind) vector[index] -= 1 if index end - raise ArgumentError, "Power out of range (-20 < net power of a unit < 20)" if vector.any? { |x| x.abs >=20 } - return vector + raise ArgumentError, 'Power out of range (-20 < net power of a unit < 20)' if vector.any? { |x| x.abs >= 20 } + vector end - private # used by #dup to duplicate a Unit @@ -1313,61 +1463,8 @@ def unit_signature return @signature unless @signature.nil? vector = unit_signature_vector vector.each_with_index { |item, index| vector[index] = item * 20**index } - @signature=vector.inject(0) { |sum, n| sum+n } - return @signature - end - - # @param [Numeric] q quantity - # @param [Array] n numerator - # @param [Array] d denominator - # @return [Hash] - def self.eliminate_terms(q, n, d) - num = n.dup - den = d.dup - - num.delete_if { |v| v == UNITY } - den.delete_if { |v| v == UNITY } - combined = Hash.new(0) - - i = 0 - loop do - break if i > num.size - if @@PREFIX_VALUES.has_key? num[i] - k = [num[i], num[i+1]] - i += 2 - else - k = num[i] - i += 1 - end - combined[k] += 1 unless k.nil? || k == UNITY - end - - j = 0 - loop do - break if j > den.size - if @@PREFIX_VALUES.has_key? den[j] - k = [den[j], den[j+1]] - j += 2 - else - k = den[j] - j += 1 - end - combined[k] -= 1 unless k.nil? || k == UNITY - end - - num = [] - den = [] - for key, value in combined do - case - when value > 0 - value.times { num << key } - when value < 0 - value.abs.times { den << key } - end - end - num = UNITY_ARRAY if num.empty? - den = UNITY_ARRAY if den.empty? - return { :scalar => q, :numerator => num.flatten.compact, :denominator => den.flatten.compact } + @signature = vector.inject(0) { |sum, n| sum + n } + @signature end # parse a string into a unit object. @@ -1383,11 +1480,9 @@ def self.eliminate_terms(q, n, d) # 8 lbs 8 oz -- recognized as 8 lbs + 8 ounces # @return [nil | Unit] # @todo This should either be a separate class or at least a class method - def parse(passed_unit_string="0") + def parse(passed_unit_string = '0') unit_string = passed_unit_string.dup - if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ - unit_string = "#{$1} USD" - end + unit_string = "#{$1} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8 unit_string.gsub!(/%/, 'percent') @@ -1406,7 +1501,7 @@ def parse(passed_unit_string="0") sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] sign = (sign == '-') ? -1 : 1 rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i)) - result = RubyUnits::Unit.new(unit_s || '1') * rational + result = RubyUnits::Unit.new(unit_s || '1') * rational copy(result) return end @@ -1414,7 +1509,7 @@ def parse(passed_unit_string="0") unit_string =~ NUMBER_REGEX unit = @@cached_units[$2] mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 - mult = mult.to_int if (mult.to_int == mult) + mult = mult.to_int if mult.to_int == mult if unit copy(unit) @scalar *= mult @@ -1422,15 +1517,15 @@ def parse(passed_unit_string="0") return self end - while unit_string.gsub! /(<#{@@UNIT_REGEX})><(#{@@UNIT_REGEX}>)/, '\1*\2' + while unit_string.gsub!(/(<#{@@unit_regex})><(#{@@unit_regex}>)/, '\1*\2') # collapse into ... end # ... and then strip the remaining brackets for x*y*z - unit_string.gsub!(/[<>]/, "") + unit_string.gsub!(/[<>]/, '') if unit_string =~ /:/ hours, minutes, seconds, microseconds = unit_string.scan(TIME_REGEX)[0] - raise ArgumentError, "Invalid Duration" if [hours, minutes, seconds, microseconds].all? { |x| x.nil? } + raise ArgumentError, 'Invalid Duration' if [hours, minutes, seconds, microseconds].all?(&:nil?) result = RubyUnits::Unit.new("#{hours || 0} h") + RubyUnits::Unit.new("#{minutes || 0} minutes") + RubyUnits::Unit.new("#{seconds || 0} seconds") + @@ -1442,7 +1537,7 @@ def parse(passed_unit_string="0") # Special processing for unusual unit strings # feet -- 6'5" feet, inches = unit_string.scan(FEET_INCH_REGEX)[0] - if (feet && inches) + if feet && inches result = RubyUnits::Unit.new("#{feet} ft") + RubyUnits::Unit.new("#{inches} inches") copy(result) return @@ -1450,7 +1545,7 @@ def parse(passed_unit_string="0") # weight -- 8 lbs 12 oz pounds, oz = unit_string.scan(LBS_OZ_REGEX)[0] - if (pounds && oz) + if pounds && oz result = RubyUnits::Unit.new("#{pounds} lbs") + RubyUnits::Unit.new("#{oz} oz") copy(result) return @@ -1458,7 +1553,7 @@ def parse(passed_unit_string="0") # stone -- 3 stone 5, 2 stone, 14 stone 3 pounds, etc. stone, pounds = unit_string.scan(STONE_LB_REGEX)[0] - if (stone && pounds) + if stone && pounds result = RubyUnits::Unit.new("#{stone} stone") + RubyUnits::Unit.new("#{pounds} lbs") copy(result) return @@ -1466,27 +1561,27 @@ def parse(passed_unit_string="0") # more than one per. I.e., "1 m/s/s" raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 - raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size > 0 - @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] #parse the string into parts + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size.positive? + @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] # parse the string into parts top.scan(TOP_REGEX).each do |item| n = item[1].to_i x = "#{item[0]} " case - when n>=0 - top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { |s| x * n } - when n<0 - bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, "") + when n >= 0 + top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { x * n } + when n.negative? + bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '') end end if bottom - bottom.gsub!(BOTTOM_REGEX) { |s| "#{$1} " * $2.to_i } + bottom.gsub!(BOTTOM_REGEX) { "#{$1} " * $2.to_i } # Separate leading decimal from denominator, if any bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] end @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? - @scalar = 1 unless @scalar.kind_of? Numeric - @scalar = @scalar.to_int if (@scalar.to_int == @scalar) + @scalar = 1 unless @scalar.is_a? Numeric + @scalar = @scalar.to_int if @scalar.to_int == @scalar case when bottom_scalar.nil? || bottom_scalar.empty? @@ -1496,11 +1591,10 @@ def parse(passed_unit_string="0") @scalar /= bottom_scalar.to_f end - @numerator ||= UNITY_ARRAY @denominator ||= UNITY_ARRAY - @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if top - @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if { |x| x.empty? }.compact if bottom + @numerator = top.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if top + @denominator = bottom.scan(RubyUnits::Unit.unit_match_regex).delete_if(&:empty?).compact if bottom # eliminate all known terms from this string. This is a quick check to see if the passed unit # contains terms that are not defined. @@ -1508,114 +1602,16 @@ def parse(passed_unit_string="0") raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty? @numerator = @numerator.map do |item| - @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] - end.flatten.compact.delete_if { |x| x.empty? } + @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]] + end.flatten.compact.delete_if(&:empty?) @denominator = @denominator.map do |item| - @@PREFIX_MAP[item[0]] ? [@@PREFIX_MAP[item[0]], @@UNIT_MAP[item[1]]] : [@@UNIT_MAP[item[1]]] - end.flatten.compact.delete_if { |x| x.empty? } + @@prefix_map[item[0]] ? [@@prefix_map[item[0]], @@unit_map[item[1]]] : [@@unit_map[item[1]]] + end.flatten.compact.delete_if(&:empty?) @numerator = UNITY_ARRAY if @numerator.empty? @denominator = UNITY_ARRAY if @denominator.empty? - return self - end - - # return an array of base units - # @return [Array] - def self.base_units - return @@base_units ||= @@definitions.dup.delete_if { |_, defn| !defn.base? }.keys.map { |u| RubyUnits::Unit.new(u) } - end - - # parse a string consisting of a number and a unit string - # NOTE: This does not properly handle units formatted like '12mg/6ml' - # @param [String] string - # @return [Array] consisting of [Numeric, "unit"] - # @private - def self.parse_into_numbers_and_units(string) - # scientific notation.... 123.234E22, -123.456e-10 - sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} - # rational numbers.... -1/3, 1/5, 20/100, -6 1/2, -6-1/2 - rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?} - # complex numbers... -1.2+3i, +1.2-3.3i - complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?} - - num, unit = string.scan(anynumber).first - - return [case num - when NilClass - 1 - when complex - if num.respond_to?(:to_c) - num.to_c - else - #:nocov_19: - Complex(*num.scan(/(#{sci})(#{sci})i/).flatten.map { |n| n.to_i }) - #:nocov_19: - end - when rational - # if it has whitespace, it will be of the form '6 1/2' - if num =~ RATIONAL_NUMBER - sign = ($1 == '-') ? -1 : 1 - n = $2.to_i - f = Rational($3.to_i,$4.to_i) - sign * (n + f) - else - Rational(*num.split("/").map { |x| x.to_i }) - end - else - num.to_f - end, unit.to_s.strip] - end - - # return a fragment of a regex to be used for matching units or reconstruct it if hasn't been used yet. - # Unit names are reverse sorted by length so the regexp matcher will prefer longer and more specific names - # @return [String] - # @private - def self.unit_regex - @@UNIT_REGEX ||= @@UNIT_MAP.keys.sort_by { |unit_name| [unit_name.length, unit_name] }.reverse.join('|') - end - - # return a regex used to match units - # @return [RegExp] - # @private - def self.unit_match_regex - @@UNIT_MATCH_REGEX ||= /(#{RubyUnits::Unit.prefix_regex})??(#{RubyUnits::Unit.unit_regex})\b/ - end - - # return a regexp fragment used to match prefixes - # @return [String] - # @private - def self.prefix_regex - return @@PREFIX_REGEX ||= @@PREFIX_MAP.keys.sort_by { |prefix| [prefix.length, prefix] }.reverse.join('|') - end - - def self.temp_regex - @@TEMP_REGEX ||= Regexp.new "(?:#{ - temp_units=%w(tempK tempC tempF tempR degK degC degF degR) - aliases =temp_units.map { |unit| d=RubyUnits::Unit.definition(unit); d && d.aliases }.flatten.compact - regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') - regex_str - })" - end - - # inject a definition into the internal array and set it up for use - # @private - def self.use_definition(definition) - @@UNIT_MATCH_REGEX = nil #invalidate the unit match regex - @@TEMP_REGEX = nil #invalidate the temp regex - if definition.prefix? - @@PREFIX_VALUES[definition.name] = definition.scalar - definition.aliases.each { |_alias| @@PREFIX_MAP[_alias] = definition.name } - @@PREFIX_REGEX = nil #invalidate the prefix regex - else - @@UNIT_VALUES[definition.name] = {} - @@UNIT_VALUES[definition.name][:scalar] = definition.scalar - @@UNIT_VALUES[definition.name][:numerator] = definition.numerator if definition.numerator - @@UNIT_VALUES[definition.name][:denominator] = definition.denominator if definition.denominator - definition.aliases.each { |_alias| @@UNIT_MAP[_alias] = definition.name } - @@UNIT_REGEX = nil #invalidate the unit regex - end + self end end end diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index 36a1eff7..d3cf3fa6 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -1,103 +1,100 @@ # seed the cache RubyUnits::Unit.new('1') -RubyUnits::Unit.define("meter") do |unit| +RubyUnits::Unit.define('meter') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{m meter meters metre metres} + unit.numerator = %w() + unit.aliases = %w(m meter meters metre metres) unit.kind = :length end -RubyUnits::Unit.define("kilogram") do |unit| +RubyUnits::Unit.define('kilogram') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{kg kilogram kilograms} + unit.numerator = %w() + unit.aliases = %w(kg kilogram kilograms) unit.kind = :mass end -RubyUnits::Unit.define("second") do |unit| +RubyUnits::Unit.define('second') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{s sec second seconds} + unit.numerator = %w() + unit.aliases = %w(s sec second seconds) unit.kind = :time end -RubyUnits::Unit.define("mole") do |unit| +RubyUnits::Unit.define('mole') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{mol mole} + unit.numerator = %w() + unit.aliases = %w(mol mole) unit.kind = :substance end -RubyUnits::Unit.define("ampere") do |unit| +RubyUnits::Unit.define('ampere') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{A ampere amperes amp amps} + unit.numerator = %w() + unit.aliases = %w(A ampere amperes amp amps) unit.kind = :current end -RubyUnits::Unit.define("radian") do |unit| +RubyUnits::Unit.define('radian') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{rad radian radians} + unit.numerator = %w() + unit.aliases = %w(rad radian radians) unit.kind = :angle end -RubyUnits::Unit.define("kelvin") do |unit| +RubyUnits::Unit.define('kelvin') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{degK kelvin} + unit.numerator = %w() + unit.aliases = %w(degK kelvin) unit.kind = :temperature end -RubyUnits::Unit.define("tempK") do |unit| +RubyUnits::Unit.define('tempK') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{tempK} + unit.numerator = %w() + unit.aliases = %w(tempK) unit.kind = :temperature end -RubyUnits::Unit.define("byte") do |unit| +RubyUnits::Unit.define('byte') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{B byte bytes} + unit.numerator = %w() + unit.aliases = %w(B byte bytes) unit.kind = :information end -RubyUnits::Unit.define("dollar") do |unit| +RubyUnits::Unit.define('dollar') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{USD dollar} + unit.numerator = %w() + unit.aliases = %w(USD dollar) unit.kind = :currency end -RubyUnits::Unit.define("candela") do |unit| +RubyUnits::Unit.define('candela') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{cd candela} + unit.numerator = %w() + unit.aliases = %w(cd candela) unit.kind = :luminosity end -RubyUnits::Unit.define("each") do |unit| +RubyUnits::Unit.define('each') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{each} + unit.numerator = %w() + unit.aliases = %w(each) unit.kind = :counting end -RubyUnits::Unit.define("steradian") do |unit| +RubyUnits::Unit.define('steradian') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{sr steradian steradians} + unit.numerator = %w() + unit.aliases = %w(sr steradian steradians) unit.kind = :solid_angle end -RubyUnits::Unit.define("decibel") do |unit| +RubyUnits::Unit.define('decibel') do |unit| unit.scalar = 1 - unit.numerator = %w{} - unit.aliases = %w{dB decibel decibels} + unit.numerator = %w() + unit.aliases = %w(dB decibel decibels) unit.kind = :logarithmic end - - - diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 9d0d31be..e706ff09 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,36 +1,36 @@ # encoding: utf-8 { - 'googol' => [%w{googol}, 1e100], - 'yobi' => [%w{Yi Yobi yobi}, 2**80], - 'zebi' => [%w{Zi Zebi zebi}, 2**70], - 'exbi' => [%w{Ei Exbi exbi}, 2**60], - 'pebi' => [%w{Pi Pebi pebi}, 2**50], - 'tebi' => [%w{Ti Tebi tebi}, 2**40], - 'gibi' => [%w{Gi Gibi gibi}, 2**30], - 'mebi' => [%w{Mi Mebi mebi}, 2**20], - 'kibi' => [%w{Ki Kibi kibi}, 2**10], - 'yotta' => [%w{Y Yotta yotta}, 1e24], - 'zetta' => [%w{Z Zetta zetta}, 1e21], - 'exa' => [%w{E Exa exa}, 1e18], - 'peta' => [%w{P Peta peta}, 1e15], - 'tera' => [%w{T Tera tera}, 1e12], - 'giga' => [%w{G Giga giga}, 1e9], - 'mega' => [%w{M Mega mega}, 1e6], - 'kilo' => [%w{k kilo}, 1e3], - 'hecto' => [%w{h Hecto hecto}, 1e2], - 'deca' => [%w{da Deca deca deka}, 1e1], - '1' => [%w{1}, 1], - 'deci' => [%w{d Deci deci}, Rational(1,1e1)], - 'centi' => [%w{c Centi centi}, Rational(1,1e2)], - 'milli' => [%w{m Milli milli}, Rational(1,1e3)], - 'micro' => [%w{u µ Micro micro mc}, Rational(1,1e6)], - 'nano' => [%w{n Nano nano}, Rational(1,1e9)], - 'pico' => [%w{p Pico pico}, Rational(1,1e12)], - 'femto' => [%w{f Femto femto}, Rational(1,1e15)], - 'atto' => [%w{a Atto atto}, Rational(1,1e18)], - 'zepto' => [%w{z Zepto zepto}, Rational(1,1e21)], - 'yocto' => [%w{y Yocto yocto}, Rational(1,1e24)] + 'googol' => [%w(googol), 1e100], + 'yobi' => [%w(Yi Yobi yobi), 2**80], + 'zebi' => [%w(Zi Zebi zebi), 2**70], + 'exbi' => [%w(Ei Exbi exbi), 2**60], + 'pebi' => [%w(Pi Pebi pebi), 2**50], + 'tebi' => [%w(Ti Tebi tebi), 2**40], + 'gibi' => [%w(Gi Gibi gibi), 2**30], + 'mebi' => [%w(Mi Mebi mebi), 2**20], + 'kibi' => [%w(Ki Kibi kibi), 2**10], + 'yotta' => [%w(Y Yotta yotta), 1e24], + 'zetta' => [%w(Z Zetta zetta), 1e21], + 'exa' => [%w(E Exa exa), 1e18], + 'peta' => [%w(P Peta peta), 1e15], + 'tera' => [%w(T Tera tera), 1e12], + 'giga' => [%w(G Giga giga), 1e9], + 'mega' => [%w(M Mega mega), 1e6], + 'kilo' => [%w(k kilo), 1e3], + 'hecto' => [%w(h Hecto hecto), 1e2], + 'deca' => [%w(da Deca deca deka), 1e1], + '1' => [%w(1), 1], + 'deci' => [%w(d Deci deci), Rational(1, 1e1)], + 'centi' => [%w(c Centi centi), Rational(1, 1e2)], + 'milli' => [%w(m Milli milli), Rational(1, 1e3)], + 'micro' => [%w(u µ Micro micro mc), Rational(1, 1e6)], + 'nano' => [%w(n Nano nano), Rational(1, 1e9)], + 'pico' => [%w(p Pico pico), Rational(1, 1e12)], + 'femto' => [%w(f Femto femto), Rational(1, 1e15)], + 'atto' => [%w(a Atto atto), Rational(1, 1e18)], + 'zepto' => [%w(z Zepto zepto), Rational(1, 1e21)], + 'yocto' => [%w(y Yocto yocto), Rational(1, 1e24)] }.each do |name, definition| RubyUnits::Unit.define(name) do |unit| aliases, scalar = definition diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 6f7df77f..1bde4ad5 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -2,92 +2,92 @@ RubyUnits::Unit.define('inch') do |inch| inch.definition = RubyUnits::Unit.new('254/10000 meter') - inch.aliases = %w{in inch inches "} + inch.aliases = %w(in inch inches ") end RubyUnits::Unit.define('foot') do |foot| foot.definition = RubyUnits::Unit.new('12 inches') - foot.aliases = %w{ft foot feet '} + foot.aliases = %w(ft foot feet ') end RubyUnits::Unit.define('survey-foot') do |sft| sft.definition = RubyUnits::Unit.new('1200/3937 meter') - sft.aliases = %w{sft sfoot sfeet} + sft.aliases = %w(sft sfoot sfeet) end RubyUnits::Unit.define('yard') do |yard| yard.definition = RubyUnits::Unit.new('3 ft') - yard.aliases = %w{yd yard yards} + yard.aliases = %w(yd yard yards) end RubyUnits::Unit.define('mile') do |mile| mile.definition = RubyUnits::Unit.new('5280 ft') - mile.aliases = %w{mi mile miles} + mile.aliases = %w(mi mile miles) end RubyUnits::Unit.define('naut-mile') do |naut| naut.definition = RubyUnits::Unit.new('1852 m') - naut.aliases = %w{nmi M NM} + naut.aliases = %w(nmi M NM) end # on land RubyUnits::Unit.define('league') do |league| league.definition = RubyUnits::Unit.new('3 miles') - league.aliases = %w{league leagues} + league.aliases = %w(league leagues) end # at sea RubyUnits::Unit.define('naut-league') do |naut_league| naut_league.definition = RubyUnits::Unit.new('3 nmi') - naut_league.aliases = %w{nleague nleagues} + naut_league.aliases = %w(nleague nleagues) end RubyUnits::Unit.define('furlong') do |furlong| furlong.definition = RubyUnits::Unit.new('1/8 mile') - furlong.aliases = %w{fur furlong furlongs} + furlong.aliases = %w(fur furlong furlongs) end RubyUnits::Unit.define('rod') do |rod| rod.definition = RubyUnits::Unit.new('33/2 feet') - rod.aliases = %w{rd rod rods} + rod.aliases = %w(rd rod rods) end RubyUnits::Unit.define('fathom') do |fathom| fathom.definition = RubyUnits::Unit.new('6 ft') - fathom.aliases = %w{fathom fathoms} + fathom.aliases = %w(fathom fathoms) end RubyUnits::Unit.define('mil') do |mil| mil.definition = RubyUnits::Unit.new('1/1000 inch') - mil.aliases = %w{mil mils} + mil.aliases = %w(mil mils) end RubyUnits::Unit.define('angstrom') do |ang| ang.definition = RubyUnits::Unit.new('1/10 nm') - ang.aliases = %w{ang angstrom angstroms} + ang.aliases = %w(ang angstrom angstroms) end # typesetting RubyUnits::Unit.define('pica') do |pica| pica.definition = RubyUnits::Unit.new('1/72 ft') - pica.aliases = %w{P pica picas} + pica.aliases = %w(P pica picas) end RubyUnits::Unit.define('point') do |point| point.definition = RubyUnits::Unit.new('1/12 pica') - point.aliases = %w{point points} + point.aliases = %w(point points) end RubyUnits::Unit.define('dot') do |dot| dot.definition = RubyUnits::Unit.new('1 each') - dot.aliases = %w{dot dots} + dot.aliases = %w(dot dots) dot.kind = :counting end RubyUnits::Unit.define('pixel') do |pixel| pixel.definition = RubyUnits::Unit.new('1 each') - pixel.aliases = %w{px pixel pixels} + pixel.aliases = %w(px pixel pixels) pixel.kind = :counting end @@ -105,93 +105,91 @@ RubyUnits::Unit.define('AMU') do |amu| amu.definition = RubyUnits::Unit.new('0.012 kg/mol') / (12 * avagadro_constant) - amu.aliases = %w{u AMU amu} + amu.aliases = %w(u AMU amu) end RubyUnits::Unit.define('dalton') do |dalton| dalton.definition = RubyUnits::Unit.new('1 amu') - dalton.aliases = %w{Da dalton daltons} + dalton.aliases = %w(Da dalton daltons) end -standard_gravitation = RubyUnits::Unit.new('9.80665 m/s^2') - RubyUnits::Unit.define('metric-ton') do |mton| mton.definition = RubyUnits::Unit.new('1000 kg') - mton.aliases = %w{tonne} + mton.aliases = %w(tonne) end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations RubyUnits::Unit.define('pound') do |pound| - pound.definition = RubyUnits::Unit.new(Rational(45359237,1e8), 'kg') - pound.aliases = %w{lbs lb lbm pound-mass pound pounds #} + pound.definition = RubyUnits::Unit.new(Rational(45_359_237, 1e8), 'kg') + pound.aliases = %w(lbs lb lbm pound-mass pound pounds #) end RubyUnits::Unit.define('ounce') do |ounce| ounce.definition = RubyUnits::Unit.new('1/16 lbs') - ounce.aliases = %w{oz ounce ounces} + ounce.aliases = %w(oz ounce ounces) end RubyUnits::Unit.define('gram') do |gram| gram.definition = RubyUnits::Unit.new('1/1000 kg') - gram.aliases = %w{g gram grams gramme grammes} + gram.aliases = %w(g gram grams gramme grammes) end RubyUnits::Unit.define('short-ton') do |ton| ton.definition = RubyUnits::Unit.new('2000 lbs') - ton.aliases = %w{tn ton tons short-tons} + ton.aliases = %w(tn ton tons short-tons) end RubyUnits::Unit.define('carat') do |carat| carat.definition = RubyUnits::Unit.new('1/5000 kg') - carat.aliases = %w{ct carat carats} + carat.aliases = %w(ct carat carats) end RubyUnits::Unit.define('stone') do |stone| stone.definition = RubyUnits::Unit.new('14 lbs') - stone.aliases = %w{st stone} + stone.aliases = %w(st stone) end # time RubyUnits::Unit.define('minute') do |min| min.definition = RubyUnits::Unit.new('60 seconds') - min.aliases = %w{min minute minutes} + min.aliases = %w(min minute minutes) end RubyUnits::Unit.define('hour') do |hour| hour.definition = RubyUnits::Unit.new('60 minutes') - hour.aliases = %w{h hr hrs hour hours} + hour.aliases = %w(h hr hrs hour hours) end RubyUnits::Unit.define('day') do |day| day.definition = RubyUnits::Unit.new('24 hours') - day.aliases = %w{d day days} + day.aliases = %w(d day days) end RubyUnits::Unit.define('week') do |week| week.definition = RubyUnits::Unit.new('7 days') - week.aliases = %w{wk week weeks} + week.aliases = %w(wk week weeks) end RubyUnits::Unit.define('fortnight') do |fortnight| fortnight.definition = RubyUnits::Unit.new('2 weeks') - fortnight.aliases = %w{fortnight fortnights} + fortnight.aliases = %w(fortnight fortnights) end RubyUnits::Unit.define('year') do |year| year.definition = RubyUnits::Unit.new('31556926 seconds') # works out to 365.24219907407405 days - year.aliases = %w{y yr year years annum} + year.aliases = %w(y yr year years annum) end RubyUnits::Unit.define('decade') do |decade| decade.definition = RubyUnits::Unit.new('10 years') - decade.aliases = %w{decade decades} + decade.aliases = %w(decade decades) end RubyUnits::Unit.define('century') do |century| century.definition = RubyUnits::Unit.new('100 years') - century.aliases = %w{century centuries} + century.aliases = %w(century centuries) end # area @@ -202,7 +200,7 @@ RubyUnits::Unit.define('acre') do |acre| acre.definition = RubyUnits::Unit.new('1 mi')**2 / 640 - acre.aliases = %w{acre acres} + acre.aliases = %w(acre acres) end RubyUnits::Unit.define('sqft') do |sqft| @@ -217,42 +215,42 @@ RubyUnits::Unit.define('liter') do |liter| liter.definition = RubyUnits::Unit.new('1/1000 m^3') - liter.aliases = %w{l L liter liters litre litres} + liter.aliases = %w(l L liter liters litre litres) end RubyUnits::Unit.define('gallon') do |gallon| gallon.definition = RubyUnits::Unit.new('231 in^3') - gallon.aliases = %w{gal gallon gallons} + gallon.aliases = %w(gal gallon gallons) end RubyUnits::Unit.define('quart') do |quart| quart.definition = RubyUnits::Unit.new('1/4 gal') - quart.aliases = %w{qt quart quarts} + quart.aliases = %w(qt quart quarts) end RubyUnits::Unit.define('pint') do |pint| pint.definition = RubyUnits::Unit.new('1/8 gal') - pint.aliases = %w{pt pint pints} + pint.aliases = %w(pt pint pints) end RubyUnits::Unit.define('cup') do |cup| cup.definition = RubyUnits::Unit.new('1/16 gal') - cup.aliases = %w{cu cup cups} + cup.aliases = %w(cu cup cups) end RubyUnits::Unit.define('fluid-ounce') do |floz| floz.definition = RubyUnits::Unit.new('1/128 gal') - floz.aliases = %w{floz fluid-ounce fluid-ounces} + floz.aliases = %w(floz fluid-ounce fluid-ounces) end RubyUnits::Unit.define('tablespoon') do |tbsp| tbsp.definition = RubyUnits::Unit.new('1/2 floz') - tbsp.aliases = %w{tbs tbsp tablespoon tablespoons} + tbsp.aliases = %w(tbs tbsp tablespoon tablespoons) end RubyUnits::Unit.define('teaspoon') do |tsp| tsp.definition = RubyUnits::Unit.new('1/3 tablespoon') - tsp.aliases = %w{tsp teaspoon teaspoons} + tsp.aliases = %w(tsp teaspoon teaspoons) end ## @@ -262,14 +260,14 @@ # http://en.wikipedia.org/wiki/Board_foot RubyUnits::Unit.define('bdft') do |bdft| bdft.definition = RubyUnits::Unit.new('1/12 ft^3') - bdft.aliases = %w{fbm boardfoot boardfeet bf} + bdft.aliases = %w(fbm boardfoot boardfeet bf) end # volumetric flow RubyUnits::Unit.define('cfm') do |cfm| cfm.definition = RubyUnits::Unit.new('1 ft^3/minute') - cfm.aliases = %w{cfm CFM CFPM} + cfm.aliases = %w(cfm CFM CFPM) end # speed @@ -288,64 +286,64 @@ RubyUnits::Unit.define('knot') do |knot| knot.definition = RubyUnits::Unit.new('1 nmi/hour') - knot.aliases = %w{kt kn kts knot knots} + knot.aliases = %w(kt kn kts knot knots) end RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors - gee.definition = RubyUnits::Unit.new(Rational(196133,20000), 'm/s^2') # equivalent to 9.80665 m/s^2 - gee.aliases = %w{gee standard-gravitation} + gee.definition = RubyUnits::Unit.new(Rational(196_133, 20_000), 'm/s^2') # equivalent to 9.80665 m/s^2 + gee.aliases = %w(gee standard-gravitation) end # temperature differences RubyUnits::Unit.define('newton') do |newton| newton.definition = RubyUnits::Unit.new('1 kg*m/s^2') - newton.aliases = %w{N newton newtons} + newton.aliases = %w(N newton newtons) end RubyUnits::Unit.define('dyne') do |dyne| dyne.definition = RubyUnits::Unit.new('1/100000 N') - dyne.aliases = %w{dyn dyne} + dyne.aliases = %w(dyn dyne) end RubyUnits::Unit.define('pound-force') do |lbf| lbf.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 gee') - lbf.aliases = %w{lbf pound-force} + lbf.aliases = %w(lbf pound-force) end RubyUnits::Unit.define('poundal') do |poundal| poundal.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 ft/s^2') - poundal.aliases = %w{pdl poundal poundals} + poundal.aliases = %w(pdl poundal poundals) end -temp_convert_factor = Rational(2501999792983609,4503599627370496) # approximates 1/1.8 +temp_convert_factor = Rational(2_501_999_792_983_609, 4_503_599_627_370_496) # approximates 1/1.8 RubyUnits::Unit.define('celsius') do |celsius| celsius.definition = RubyUnits::Unit.new('1 degK') - celsius.aliases = %w{degC celsius centigrade} + celsius.aliases = %w(degC celsius centigrade) end RubyUnits::Unit.define('fahrenheit') do |fahrenheit| fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') - fahrenheit.aliases = %w{degF fahrenheit} + fahrenheit.aliases = %w(degF fahrenheit) end RubyUnits::Unit.define('rankine') do |rankine| rankine.definition = RubyUnits::Unit.new('1 degF') - rankine.aliases = %w{degR rankine} + rankine.aliases = %w(degR rankine) end -RubyUnits::Unit.define('tempC') do |tempC| - tempC.definition = RubyUnits::Unit.new('1 tempK') +RubyUnits::Unit.define('tempC') do |temp_c| + temp_c.definition = RubyUnits::Unit.new('1 tempK') end -RubyUnits::Unit.define('tempF') do |tempF| - tempF.definition = RubyUnits::Unit.new(temp_convert_factor, 'tempK') +RubyUnits::Unit.define('tempF') do |temp_f| + temp_f.definition = RubyUnits::Unit.new(temp_convert_factor, 'tempK') end -RubyUnits::Unit.define('tempR') do |tempR| - tempR.definition = RubyUnits::Unit.new('1 tempF') +RubyUnits::Unit.define('tempR') do |temp_r| + temp_r.definition = RubyUnits::Unit.new('1 tempF') end # astronomy @@ -354,58 +352,58 @@ RubyUnits::Unit.define('light-second') do |ls| ls.definition = RubyUnits::Unit.new('1 s') * speed_of_light - ls.aliases = %w{ls lsec light-second} + ls.aliases = %w(ls lsec light-second) end RubyUnits::Unit.define('light-minute') do |lmin| lmin.definition = RubyUnits::Unit.new('1 min') * speed_of_light - lmin.aliases = %w{lmin light-minute} + lmin.aliases = %w(lmin light-minute) end RubyUnits::Unit.define('light-year') do |ly| ly.definition = RubyUnits::Unit.new('1 y') * speed_of_light - ly.aliases = %w{ly light-year} + ly.aliases = %w(ly light-year) end RubyUnits::Unit.define('parsec') do |parsec| parsec.definition = RubyUnits::Unit.new('3.26163626 ly') - parsec.aliases = %w{pc parsec parsecs} + parsec.aliases = %w(pc parsec parsecs) end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit RubyUnits::Unit.define('AU') do |au| au.definition = RubyUnits::Unit.new('149597870700 m') - au.aliases = %w{AU astronomical-unit} + au.aliases = %w(AU astronomical-unit) end RubyUnits::Unit.define('redshift') do |red| red.definition = RubyUnits::Unit.new('1.302773e26 m') - red.aliases = %w{z red-shift} + red.aliases = %w(z red-shift) end # mass RubyUnits::Unit.define('slug') do |slug| slug.definition = RubyUnits::Unit.new('1 lbf*s^2/ft') - slug.aliases = %w{slug slugs} + slug.aliases = %w(slug slugs) end # pressure RubyUnits::Unit.define('pascal') do |pascal| pascal.definition = RubyUnits::Unit.new('1 kg/m*s^2') - pascal.aliases = %w{Pa pascal pascals} + pascal.aliases = %w(Pa pascal pascals) end RubyUnits::Unit.define('bar') do |bar| bar.definition = RubyUnits::Unit.new('100 kPa') - bar.aliases = %w{bar bars} + bar.aliases = %w(bar bars) end RubyUnits::Unit.define('atm') do |atm| atm.definition = RubyUnits::Unit.new('101325 Pa') - atm.aliases = %w{atm ATM atmosphere atmospheres} + atm.aliases = %w(atm ATM atmosphere atmospheres) end RubyUnits::Unit.define('mmHg') do |mmhg| @@ -420,7 +418,7 @@ RubyUnits::Unit.define('torr') do |torr| torr.definition = RubyUnits::Unit.new('1/760 atm') - torr.aliases = %w{Torr torr} + torr.aliases = %w(Torr torr) end RubyUnits::Unit.define('psi') do |psi| @@ -430,225 +428,225 @@ RubyUnits::Unit.define('cmh2o') do |cmh2o| density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC cmh2o.definition = RubyUnits::Unit.new('1 cm') * RubyUnits::Unit.new('1 gee') * density_of_water - cmh2o.aliases = %w{cmH2O cmh2o cmAq} + cmh2o.aliases = %w(cmH2O cmh2o cmAq) end RubyUnits::Unit.define('inh2o') do |inh2o| density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC inh2o.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_water - inh2o.aliases = %w{inH2O inh2o inAq} + inh2o.aliases = %w(inH2O inh2o inAq) end -#viscosity +# viscosity RubyUnits::Unit.define('poise') do |poise| poise.definition = RubyUnits::Unit.new('dPa*s') - poise.aliases = %w{P poise} + poise.aliases = %w(P poise) end RubyUnits::Unit.define('stokes') do |stokes| stokes.definition = RubyUnits::Unit.new('1 cm^2/s') - stokes.aliases = %w{St stokes} + stokes.aliases = %w(St stokes) end # #energy RubyUnits::Unit.define('joule') do |joule| joule.definition = RubyUnits::Unit.new('1 N*m') - joule.aliases = %w{J joule joules} + joule.aliases = %w(J joule joules) end RubyUnits::Unit.define('erg') do |erg| erg.definition = RubyUnits::Unit.new('1 g*cm^2/s^2') - erg.aliases = %w{erg ergs} + erg.aliases = %w(erg ergs) end -#power +# power RubyUnits::Unit.define('watt') do |watt| watt.definition = RubyUnits::Unit.new('1 N*m/s') - watt.aliases = %w{W Watt watt watts} + watt.aliases = %w(W Watt watt watts) end RubyUnits::Unit.define('horsepower') do |hp| hp.definition = RubyUnits::Unit.new('33000 ft*lbf/min') - hp.aliases = %w{hp horsepower} + hp.aliases = %w(hp horsepower) end # energy RubyUnits::Unit.define('btu') do |btu| btu.definition = RubyUnits::Unit.new('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard - btu.aliases = %w{Btu btu Btus btus} + btu.aliases = %w(Btu btu Btus btus) end RubyUnits::Unit.define('therm') do |therm| therm.definition = RubyUnits::Unit.new('100 kBtu') - therm.aliases = %w{thm therm therms Therm} + therm.aliases = %w(thm therm therms Therm) end # "small" calorie RubyUnits::Unit.define('calorie') do |calorie| calorie.definition = RubyUnits::Unit.new('4.184 J') - calorie.aliases = %w{cal calorie calories} + calorie.aliases = %w(cal calorie calories) end # "big" calorie RubyUnits::Unit.define('Calorie') do |calorie| calorie.definition = RubyUnits::Unit.new('1 kcal') - calorie.aliases = %w{Cal Calorie Calories} + calorie.aliases = %w(Cal Calorie Calories) end RubyUnits::Unit.define('molar') do |molar| molar.definition = RubyUnits::Unit.new('1 mole/l') - molar.aliases = %w{M molar} + molar.aliases = %w(M molar) end # potential RubyUnits::Unit.define('volt') do |volt| volt.definition = RubyUnits::Unit.new('1 W/A') - volt.aliases = %w{V volt volts} + volt.aliases = %w(V volt volts) end # capacitance RubyUnits::Unit.define('farad') do |farad| farad.definition = RubyUnits::Unit.new('1 A*s/V') - farad.aliases = %w{F farad farads} + farad.aliases = %w(F farad farads) end # charge RubyUnits::Unit.define('coulomb') do |coulomb| coulomb.definition = RubyUnits::Unit.new('1 A*s') - coulomb.aliases = %w{C coulomb coulombs} + coulomb.aliases = %w(C coulomb coulombs) end # conductance RubyUnits::Unit.define('siemens') do |siemens| siemens.definition = RubyUnits::Unit.new('1 A/V') - siemens.aliases = %w{S siemens} + siemens.aliases = %w(S siemens) end # inductance RubyUnits::Unit.define('henry') do |henry| henry.definition = RubyUnits::Unit.new('1 J/A^2') - henry.aliases = %w{H henry henries} + henry.aliases = %w(H henry henries) end # resistance RubyUnits::Unit.define('ohm') do |ohm| ohm.definition = RubyUnits::Unit.new('1 V/A') - ohm.aliases = %w{Ohm ohm ohms} + ohm.aliases = %w(Ohm ohm ohms) end # magnetism RubyUnits::Unit.define('weber') do |weber| weber.definition = RubyUnits::Unit.new('1 V*s') - weber.aliases = %w{Wb weber webers} + weber.aliases = %w(Wb weber webers) end RubyUnits::Unit.define('tesla') do |tesla| tesla.definition = RubyUnits::Unit.new('1 V*s/m^2') - tesla.aliases = %w{T tesla teslas} + tesla.aliases = %w(T tesla teslas) end RubyUnits::Unit.define('gauss') do |gauss| gauss.definition = RubyUnits::Unit.new('100 microT') - gauss.aliases = %w{G gauss} + gauss.aliases = %w(G gauss) end RubyUnits::Unit.define('maxwell') do |maxwell| maxwell.definition = RubyUnits::Unit.new('1 gauss*cm^2') - maxwell.aliases = %w{Mx maxwell maxwells} + maxwell.aliases = %w(Mx maxwell maxwells) end RubyUnits::Unit.define('oersted') do |oersted| - oersted.definition = RubyUnits::Unit.new(250.0/Math::PI, 'A/m') - oersted.aliases = %w{Oe oersted oersteds} + oersted.definition = RubyUnits::Unit.new(250.0 / Math::PI, 'A/m') + oersted.aliases = %w(Oe oersted oersteds) end -#activity +# activity RubyUnits::Unit.define('katal') do |katal| katal.definition = RubyUnits::Unit.new('1 mole/sec') - katal.aliases = %w{kat katal} + katal.aliases = %w(kat katal) end RubyUnits::Unit.define('unit') do |unit| unit.definition = RubyUnits::Unit.new('1/60 microkatal') - unit.aliases = %w{U enzUnit units} + unit.aliases = %w(U enzUnit units) end -#frequency +# frequency RubyUnits::Unit.define('hertz') do |hz| hz.definition = RubyUnits::Unit.new('1 1/s') - hz.aliases = %w{Hz hertz} + hz.aliases = %w(Hz hertz) end -#angle +# angle RubyUnits::Unit.define('degree') do |deg| deg.definition = RubyUnits::Unit.new(Math::PI / 180.0, 'radian') - deg.aliases = %w{deg degree degrees} + deg.aliases = %w(deg degree degrees) end RubyUnits::Unit.define('grad') do |grad| grad.definition = RubyUnits::Unit.new(Math::PI / 200.0, 'radian') - grad.aliases = %w{grad gradian grads} + grad.aliases = %w(grad gradian grads) end -#rotation +# rotation RubyUnits::Unit.define('rotation') do |rotation| - rotation.definition = RubyUnits::Unit.new(2.0*Math::PI, 'radian') + rotation.definition = RubyUnits::Unit.new(2.0 * Math::PI, 'radian') end RubyUnits::Unit.define('rpm') do |rpm| rpm.definition = RubyUnits::Unit.new('1 rotation/min') end -#memory +# memory RubyUnits::Unit.define('bit') do |bit| bit.definition = RubyUnits::Unit.new('1/8 byte') - bit.aliases = %w{b bit} + bit.aliases = %w(b bit) end -#currency +# currency RubyUnits::Unit.define('cents') do |cents| cents.definition = RubyUnits::Unit.new('1/100 dollar') end -#luminosity +# luminosity RubyUnits::Unit.define('lumen') do |lumen| lumen.definition = RubyUnits::Unit.new('1 cd*steradian') - lumen.aliases = %w{lm lumen} + lumen.aliases = %w(lm lumen) end RubyUnits::Unit.define('lux') do |lux| lux.definition = RubyUnits::Unit.new('1 lumen/m^2') end -#radiation +# radiation RubyUnits::Unit.define('gray') do |gray| gray.definition = RubyUnits::Unit.new('1 J/kg') - gray.aliases = %w{Gy gray grays} + gray.aliases = %w(Gy gray grays) end RubyUnits::Unit.define('roentgen') do |roentgen| roentgen.definition = RubyUnits::Unit.new('2.58e-4 C/kg') - roentgen.aliases = %w{R roentgen} + roentgen.aliases = %w(R roentgen) end RubyUnits::Unit.define('sievert') do |sievert| sievert.definition = RubyUnits::Unit.new('1 J/kg') - sievert.aliases = %w{Sv sievert sieverts} + sievert.aliases = %w(Sv sievert sieverts) end RubyUnits::Unit.define('becquerel') do |becquerel| becquerel.definition = RubyUnits::Unit.new('1 1/s') - becquerel.aliases = %w{Bq becquerel becquerels} + becquerel.aliases = %w(Bq becquerel becquerels) end RubyUnits::Unit.define('curie') do |curie| curie.definition = RubyUnits::Unit.new('37 GBq') - curie.aliases = %w{Ci curie curies} + curie.aliases = %w(Ci curie curies) end RubyUnits::Unit.define('count') do |count| @@ -672,43 +670,43 @@ # misc RubyUnits::Unit.define('dozen') do |dozen| dozen.definition = RubyUnits::Unit.new('12 each') - dozen.aliases = %w{doz dz dozen} - dozen.kind = :counting + dozen.aliases = %w(doz dz dozen) + dozen.kind = :counting end RubyUnits::Unit.define('gross') do |gross| gross.definition = RubyUnits::Unit.new('12 dozen') - gross.aliases = %w{gr gross} - gross.kind = :counting + gross.aliases = %w(gr gross) + gross.kind = :counting end RubyUnits::Unit.define('cell') do |cell| cell.definition = RubyUnits::Unit.new('1 each') - cell.aliases = %w{cells cell} + cell.aliases = %w(cells cell) cell.kind = :counting end RubyUnits::Unit.define('base-pair') do |bp| bp.definition = RubyUnits::Unit.new('1 each') - bp.aliases = %w{bp base-pair} + bp.aliases = %w(bp base-pair) bp.kind = :counting end RubyUnits::Unit.define('nucleotide') do |nt| nt.definition = RubyUnits::Unit.new('1 each') - nt.aliases = %w{nt} + nt.aliases = %w(nt) nt.kind = :counting end RubyUnits::Unit.define('molecule') do |molecule| molecule.definition = RubyUnits::Unit.new('1 each') - molecule.aliases = %w{molecule molecules} + molecule.aliases = %w(molecule molecules) molecule.kind = :counting end RubyUnits::Unit.define('percent') do |percent| percent.definition = RubyUnits::Unit.new('1/100') - percent.aliases = %w{% percent} + percent.aliases = %w(% percent) end RubyUnits::Unit.define('ppm') do |ppm| diff --git a/lib/ruby_units/version.rb b/lib/ruby_units/version.rb index 059e2ca3..81b19556 100644 --- a/lib/ruby_units/version.rb +++ b/lib/ruby_units/version.rb @@ -2,7 +2,7 @@ module RubyUnits class Unit < Numeric # Pull the version number from the VERSION file module Version - STRING = File.read(File.dirname(__FILE__) + "/../../VERSION") + STRING = File.read(File.dirname(__FILE__) + '/../../VERSION') end end end diff --git a/spec/ruby-units/array_spec.rb b/spec/ruby-units/array_spec.rb index aca122c6..3c5157fe 100644 --- a/spec/ruby-units/array_spec.rb +++ b/spec/ruby-units/array_spec.rb @@ -1,14 +1,12 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Array do - subject { [1, 'cm'] } - - it {is_expected.to be_kind_of Array} - it {is_expected.to respond_to :to_unit} - - specify { expect(subject.to_unit).to be_instance_of Unit} - specify { expect(subject.to_unit).to eq("1 cm".to_unit) } - specify { expect(subject.to_unit('mm')).to eq("10 mm".to_unit)} - -end \ No newline at end of file + + it { is_expected.to be_kind_of Array } + it { is_expected.to respond_to :to_unit } + + specify { expect(subject.to_unit).to be_instance_of Unit } + specify { expect(subject.to_unit).to eq('1 cm'.to_unit) } + specify { expect(subject.to_unit('mm')).to eq('10 mm'.to_unit) } +end diff --git a/spec/ruby-units/complex_spec.rb b/spec/ruby-units/complex_spec.rb index c6e96731..af7ff923 100644 --- a/spec/ruby-units/complex_spec.rb +++ b/spec/ruby-units/complex_spec.rb @@ -5,22 +5,21 @@ # so it stands to reason that complex units should also not support :> or :< describe Complex do - subject { Complex(1,1) } + subject { Complex(1, 1) } it { is_expected.to respond_to :to_unit } end -describe "Complex Unit" do +describe 'Complex Unit' do subject { Complex(1.0, -1.0).to_unit } - it { is_expected.to be_instance_of Unit} + it { is_expected.to be_instance_of Unit } it(:scalar) { is_expected.to be_kind_of Complex } - it { is_expected.to eq("1-1i".to_unit) } - it { is_expected.to be === "1-1i".to_unit } + it { is_expected.to eq('1-1i'.to_unit) } + it { is_expected.to be === '1-1i'.to_unit } - it "is not comparable" do - expect { subject > "1+1i".to_unit }.to raise_error(NoMethodError) - expect { subject < "1+1i".to_unit }.to raise_error(NoMethodError) + it 'is not comparable' do + expect { subject > '1+1i'.to_unit }.to raise_error(NoMethodError) + expect { subject < '1+1i'.to_unit }.to raise_error(NoMethodError) end - end diff --git a/spec/ruby-units/date_spec.rb b/spec/ruby-units/date_spec.rb index 998713b2..2ae06542 100644 --- a/spec/ruby-units/date_spec.rb +++ b/spec/ruby-units/date_spec.rb @@ -39,11 +39,11 @@ specify { expect(subject - '5 days'.to_unit).to eq(Date.new(2011, 3, 27)) } specify { expect { subject + Date.new(2011, 4, 1) }.to raise_error(ArgumentError) } - specify { expect { subject + DateTime.new(2011, 4, 1, 12, 00, 00) }.to raise_error(ArgumentError) } + specify { expect { subject + DateTime.new(2011, 4, 1, 12, 0, 0) }.to raise_error(ArgumentError) } specify { expect { subject + Time.parse('2011-04-01 12:00:00') }.to raise_error(ArgumentError) } specify { expect(subject - Date.new(2011, 4, 1)).to be_zero } - specify { expect(subject - DateTime.new(2011, 4, 1, 00, 00, 00)).to be_zero } + specify { expect(subject - DateTime.new(2011, 4, 1, 0, 0, 0)).to be_zero } specify { expect { (subject - Time.parse('2011-04-01 00:00')) }.to raise_error(ArgumentError) } specify { expect(Date.new(2011, 4, 1) + 1).to eq(Date.new(2011, 4, 2)) } end diff --git a/spec/ruby-units/numeric_spec.rb b/spec/ruby-units/numeric_spec.rb index f26afb72..92f7375f 100644 --- a/spec/ruby-units/numeric_spec.rb +++ b/spec/ruby-units/numeric_spec.rb @@ -3,10 +3,10 @@ # some rubies return an array of strings for .instance_methods and others return an array of symbols # so let's stringify them before we compare describe Numeric do - specify { expect(Float.instance_methods.map {|m| m.to_s}).to include("to_unit") } - specify { expect(Integer.instance_methods.map {|m| m.to_s}).to include("to_unit") } - specify { expect(Fixnum.instance_methods.map {|m| m.to_s}).to include("to_unit") } - specify { expect(Complex.instance_methods.map {|m| m.to_s}).to include("to_unit") } - specify { expect(Bignum.instance_methods.map {|m| m.to_s}).to include("to_unit") } - specify { expect(Rational.instance_methods.map {|m| m.to_s}).to include("to_unit") } -end \ No newline at end of file + specify { expect(Float.instance_methods.map(&:to_s)).to include('to_unit') } + specify { expect(Integer.instance_methods.map(&:to_s)).to include('to_unit') } + specify { expect(Integer.instance_methods.map(&:to_s)).to include('to_unit') } + specify { expect(Complex.instance_methods.map(&:to_s)).to include('to_unit') } + specify { expect(Integer.instance_methods.map(&:to_s)).to include('to_unit') } + specify { expect(Rational.instance_methods.map(&:to_s)).to include('to_unit') } +end diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby-units/time_spec.rb index 873536c5..7bad22f3 100644 --- a/spec/ruby-units/time_spec.rb +++ b/spec/ruby-units/time_spec.rb @@ -1,27 +1,27 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Time do - let(:now) { Time.at(1303656390) } + let(:now) { Time.at(1_303_656_390) } before(:each) do allow(Time).to receive(:now).and_return(now) end - context ".at" do - subject { Date.new(2011,4,1).to_unit } - specify { expect(Time.at(Time.at(0)).utc.strftime("%D %T")).to eq("01/01/70 00:00:00") } - specify { expect(Time.at(subject - Date.new(1970,1,1)).getutc.strftime("%D %T")).to eq("04/01/11 00:00:00")} - specify { expect(Time.at(subject - Date.new(1970,1,1), 500).usec).to eq(500)} + context '.at' do + subject { Date.new(2011, 4, 1).to_unit } + specify { expect(Time.at(Time.at(0)).utc.strftime('%D %T')).to eq('01/01/70 00:00:00') } + specify { expect(Time.at(subject - Date.new(1970, 1, 1)).getutc.strftime('%D %T')).to eq('04/01/11 00:00:00') } + specify { expect(Time.at(subject - Date.new(1970, 1, 1), 500).usec).to eq(500) } end - context ".in" do - specify { expect(Time.in("5 min")).to be_a Time} - specify { expect(Time.in("5 min")).to be > Time.now} + context '.in' do + specify { expect(Time.in('5 min')).to be_a Time } + specify { expect(Time.in('5 min')).to be > Time.now } end context '#to_date' do - subject { Time.parse("2012-01-31 11:59:59") } - specify { expect(subject.to_date.to_s).to eq("2012-01-31") } - specify { expect((subject+1).to_date.to_s).to eq("2012-01-31") } + subject { Time.parse('2012-01-31 11:59:59') } + specify { expect(subject.to_date.to_s).to eq('2012-01-31') } + specify { expect((subject + 1).to_date.to_s).to eq('2012-01-31') } end context '#to_unit' do @@ -36,22 +36,21 @@ subject { super().to_unit } describe '#units' do subject { super().units } - it { is_expected.to eq("s") } + it { is_expected.to eq('s') } end end - specify { expect(subject.to_unit('h').kind).to eq(:time)} - specify { expect(subject.to_unit('h').units).to eq('h')} + specify { expect(subject.to_unit('h').kind).to eq(:time) } + specify { expect(subject.to_unit('h').units).to eq('h') } end context 'addition (+)' do - specify { expect(Time.now + 1).to eq(Time.at(1303656390 + 1))} - specify { expect(Time.now + RubyUnits::Unit.new("10 min")).to eq(Time.at(1303656390 + 600))} + specify { expect(Time.now + 1).to eq(Time.at(1_303_656_390 + 1)) } + specify { expect(Time.now + RubyUnits::Unit.new('10 min')).to eq(Time.at(1_303_656_390 + 600)) } end context 'subtraction (-)' do - specify { expect(Time.now - 1).to eq(Time.at(1303656390 - 1))} - specify { expect(Time.now - RubyUnits::Unit.new("10 min")).to eq(Time.at(1303656390 - 600))} - specify { expect(Time.now - RubyUnits::Unit.new("150 years")).to eq(Time.parse("1861-04-24 09:46:30 -0500"))} + specify { expect(Time.now - 1).to eq(Time.at(1_303_656_390 - 1)) } + specify { expect(Time.now - RubyUnits::Unit.new('10 min')).to eq(Time.at(1_303_656_390 - 600)) } + specify { expect(Time.now - RubyUnits::Unit.new('150 years')).to eq(Time.parse('1861-04-24 09:46:30 -0500')) } end - end diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby-units/unit_spec.rb index eb62f6ba..556b31d7 100644 --- a/spec/ruby-units/unit_spec.rb +++ b/spec/ruby-units/unit_spec.rb @@ -280,7 +280,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("mm") } + it { is_expected.to eq('mm') } end describe '#kind' do @@ -295,12 +295,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("0.001 m")) } + it { is_expected.to eq(RubyUnits::Unit.new('0.001 m')) } end end # with a zero power - describe RubyUnits::Unit.new("1 m^0") do + describe RubyUnits::Unit.new('1 m^0') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -316,7 +316,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("") } + it { is_expected.to eq('') } end describe '#kind' do @@ -331,12 +331,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("1")) } + it { is_expected.to eq(RubyUnits::Unit.new('1')) } end end # unit only - describe RubyUnits::Unit.new("mm") do + describe RubyUnits::Unit.new('mm') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -352,7 +352,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("mm") } + it { is_expected.to eq('mm') } end describe '#kind' do @@ -367,12 +367,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("0.001 m")) } + it { is_expected.to eq(RubyUnits::Unit.new('0.001 m')) } end end # Compound unit - describe RubyUnits::Unit.new("1 N*m") do + describe RubyUnits::Unit.new('1 N*m') do it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -388,7 +388,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("N*m") } + it { is_expected.to eq('N*m') } end describe '#kind' do @@ -403,12 +403,12 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("1 kg*m^2/s^2")) } + it { is_expected.to eq(RubyUnits::Unit.new('1 kg*m^2/s^2')) } end end # scalar and unit with powers - describe RubyUnits::Unit.new("10 m/s^2") do + describe RubyUnits::Unit.new('10 m/s^2') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -423,7 +423,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("m/s^2") } + it { is_expected.to eq('m/s^2') } end describe '#kind' do @@ -438,7 +438,7 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("10 m/s^2")) } + it { is_expected.to eq(RubyUnits::Unit.new('10 m/s^2')) } end end @@ -455,7 +455,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("ft") } + it { is_expected.to eq('ft') } end describe '#kind' do @@ -470,14 +470,14 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(RubyUnits::Unit.new("0.01 m")).of RubyUnits::Unit.new("1.6764 m") } + it { is_expected.to be_within(RubyUnits::Unit.new('0.01 m')).of RubyUnits::Unit.new('1.6764 m') } end - specify { expect(subject.to_s(:ft)).to eq(%{5'6"}) } + specify { expect(subject.to_s(:ft)).to eq(%(5'6")) } end end # pound/ounces form - describe RubyUnits::Unit.new("6lbs 5oz") do + describe RubyUnits::Unit.new('6lbs 5oz') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -487,7 +487,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("lbs") } + it { is_expected.to eq('lbs') } end describe '#kind' do @@ -502,13 +502,13 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(RubyUnits::Unit.new("0.01 kg")).of RubyUnits::Unit.new("2.8633 kg") } + it { is_expected.to be_within(RubyUnits::Unit.new('0.01 kg')).of RubyUnits::Unit.new('2.8633 kg') } end - specify { expect(subject.to_s(:lbs)).to eq("6 lbs, 5 oz") } + specify { expect(subject.to_s(:lbs)).to eq('6 lbs, 5 oz') } end # temperature - describe RubyUnits::Unit.new("100 tempC") do + describe RubyUnits::Unit.new('100 tempC') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -518,7 +518,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("tempC") } + it { is_expected.to eq('tempC') } end describe '#kind' do @@ -533,12 +533,12 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(RubyUnits::Unit.new("0.01 degK")).of RubyUnits::Unit.new("373.15 tempK") } + it { is_expected.to be_within(RubyUnits::Unit.new('0.01 degK')).of RubyUnits::Unit.new('373.15 tempK') } end describe '#temperature_scale' do subject { super().temperature_scale } - it { is_expected.to eq("degC") } + it { is_expected.to eq('degC') } end end @@ -553,7 +553,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("s") } + it { is_expected.to eq('s') } end describe '#kind' do @@ -578,7 +578,7 @@ end # degrees - describe RubyUnits::Unit.new("100 degC") do + describe RubyUnits::Unit.new('100 degC') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -588,7 +588,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("degC") } + it { is_expected.to eq('degC') } end describe '#kind' do @@ -602,12 +602,12 @@ describe '#base' do subject { super().base } - it { is_expected.to be_within(RubyUnits::Unit.new("0.01 degK")).of RubyUnits::Unit.new("100 degK") } + it { is_expected.to be_within(RubyUnits::Unit.new('0.01 degK')).of RubyUnits::Unit.new('100 degK') } end end # percent - describe RubyUnits::Unit.new("75%") do + describe RubyUnits::Unit.new('75%') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -617,7 +617,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("%") } + it { is_expected.to eq('%') } end describe '#kind' do @@ -642,7 +642,7 @@ end # angle - describe RubyUnits::Unit.new("180 deg") do + describe RubyUnits::Unit.new('180 deg') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -652,7 +652,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("deg") } + it { is_expected.to eq('deg') } end describe '#kind' do @@ -677,7 +677,7 @@ end # radians - describe RubyUnits::Unit.new("1 radian") do + describe RubyUnits::Unit.new('1 radian') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -687,7 +687,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("rad") } + it { is_expected.to eq('rad') } end describe '#kind' do @@ -712,7 +712,7 @@ end # counting - describe RubyUnits::Unit.new("12 dozen") do + describe RubyUnits::Unit.new('12 dozen') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -722,7 +722,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("doz") } + it { is_expected.to eq('doz') } end describe '#kind' do @@ -747,7 +747,7 @@ end # rational scalar with unit - describe RubyUnits::Unit.new("1/2 kg") do + describe RubyUnits::Unit.new('1/2 kg') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -757,7 +757,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("kg") } + it { is_expected.to eq('kg') } end describe '#kind' do @@ -782,7 +782,7 @@ end # rational scalar with compound unit - describe RubyUnits::Unit.new("1/2 kg/m") do + describe RubyUnits::Unit.new('1/2 kg/m') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -792,7 +792,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("kg/m") } + it { is_expected.to eq('kg/m') } end describe '#kind' do @@ -823,7 +823,7 @@ describe '#scalar' do subject { super().scalar } it { is_expected.to be_an Numeric } - it { is_expected.to eq (12.0/6.0) } + it { is_expected.to eq (12.0 / 6.0) } end describe '#units' do @@ -856,7 +856,7 @@ # time string describe RubyUnits::Unit.new('1:23:45,200') do it { is_expected.to be_an_instance_of Unit } - it { is_expected.to eq(RubyUnits::Unit.new("1 h") + RubyUnits::Unit.new("23 min") + RubyUnits::Unit.new("45 seconds") + RubyUnits::Unit.new("200 usec")) } + it { is_expected.to eq(RubyUnits::Unit.new('1 h') + RubyUnits::Unit.new('23 min') + RubyUnits::Unit.new('45 seconds') + RubyUnits::Unit.new('200 usec')) } describe '#scalar' do subject { super().scalar } @@ -865,7 +865,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("h") } + it { is_expected.to eq('h') } end describe '#kind' do @@ -891,7 +891,7 @@ # also '1 hours as minutes' # '1 hour to minutes' - describe Unit.parse("1 hour in minutes") do + describe Unit.parse('1 hour in minutes') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -901,7 +901,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("min") } + it { is_expected.to eq('min') } end describe '#kind' do @@ -926,7 +926,7 @@ end # funky unit - describe RubyUnits::Unit.new("1 attoparsec/microfortnight") do + describe RubyUnits::Unit.new('1 attoparsec/microfortnight') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -936,7 +936,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("apc/ufortnight") } + it { is_expected.to eq('apc/ufortnight') } end describe '#kind' do @@ -958,11 +958,11 @@ subject { super().temperature_scale } it { is_expected.to be_nil } end - it { expect(subject.convert_to("in/s")).to be_within(RubyUnits::Unit.new("0.0001 in/s")).of(RubyUnits::Unit.new("1.0043269330917 in/s")) } + it { expect(subject.convert_to('in/s')).to be_within(RubyUnits::Unit.new('0.0001 in/s')).of(RubyUnits::Unit.new('1.0043269330917 in/s')) } end # Farads - describe RubyUnits::Unit.new("1 F") do + describe RubyUnits::Unit.new('1 F') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -972,7 +972,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("F") } + it { is_expected.to eq('F') } end describe '#kind' do @@ -996,7 +996,7 @@ end end - describe RubyUnits::Unit.new("1 m^2 s^-2") do + describe RubyUnits::Unit.new('1 m^2 s^-2') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1006,7 +1006,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("m^2/s^2") } + it { is_expected.to eq('m^2/s^2') } end describe '#kind' do @@ -1030,7 +1030,7 @@ end end - describe RubyUnits::Unit.new(1, "m^2", "s^2") do + describe RubyUnits::Unit.new(1, 'm^2', 's^2') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1040,7 +1040,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("m^2/s^2") } + it { is_expected.to eq('m^2/s^2') } end describe '#kind' do @@ -1064,8 +1064,8 @@ end end - #scientific notation - describe RubyUnits::Unit.new("1e6 cells") do + # scientific notation + describe RubyUnits::Unit.new('1e6 cells') do it { is_expected.to be_an_instance_of Unit } describe '#scalar' do @@ -1080,7 +1080,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("cells") } + it { is_expected.to eq('cells') } end describe '#kind' do @@ -1104,16 +1104,16 @@ end end - #could be m*m - describe RubyUnits::Unit.new("1 mm") do + # could be m*m + describe RubyUnits::Unit.new('1 mm') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:length) } end end - #could be centi-day - describe RubyUnits::Unit.new("1 cd") do + # could be centi-day + describe RubyUnits::Unit.new('1 cd') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:luminous_power) } @@ -1121,23 +1121,23 @@ end # could be milli-inch - describe RubyUnits::Unit.new("1 min") do + describe RubyUnits::Unit.new('1 min') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:time) } end end - #could be femto-tons - describe RubyUnits::Unit.new("1 ft") do + # could be femto-tons + describe RubyUnits::Unit.new('1 ft') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:length) } end end - #could be deci-ounce - describe RubyUnits::Unit.new("1 doz") do + # could be deci-ounce + describe RubyUnits::Unit.new('1 doz') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:unitless) } @@ -1145,7 +1145,7 @@ end # create with another unit - describe 10.to_unit(RubyUnits::Unit.new("1 mm")) do + describe 10.to_unit(RubyUnits::Unit.new('1 mm')) do describe '#units' do subject { super().units } it { is_expected.to eq('mm') } @@ -1157,8 +1157,8 @@ end end - #explicit create - describe RubyUnits::Unit.new("1 /") do + # explicit create + describe RubyUnits::Unit.new('1 /') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:speed) } @@ -1166,11 +1166,11 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("m/s") } + it { is_expected.to eq('m/s') } end end - describe RubyUnits::Unit.new("1 /") do + describe RubyUnits::Unit.new('1 /') do describe '#kind' do subject { super().kind } it { is_expected.to eq(:yank) } @@ -1178,7 +1178,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("kg*m/s^3") } + it { is_expected.to eq('kg*m/s^3') } end end @@ -1195,8 +1195,8 @@ specify { expect(subject).to eq(RubyUnits::Unit.new('11 1/s')) } end - describe Unit.new("63.5029318kg") do - specify { expect(subject).to eq(Unit.new("63.5029318 kg")) } + describe Unit.new('63.5029318kg') do + specify { expect(subject).to eq(Unit.new('63.5029318 kg')) } end # mixed fraction @@ -1210,106 +1210,104 @@ end describe Unit.new('100 mcg') do - specify { expect(subject).to eq(Unit.new('100 ug'))} + specify { expect(subject).to eq(Unit.new('100 ug')) } end describe Unit.new('100 mcL') do - specify { expect(subject).to eq(Unit.new('100 uL'))} + specify { expect(subject).to eq(Unit.new('100 uL')) } end - end -describe "Unit handles attempts to create bad units" do - specify "no empty strings" do - expect { RubyUnits::Unit.new("") }.to raise_error(ArgumentError, "No Unit Specified") +describe 'Unit handles attempts to create bad units' do + specify 'no empty strings' do + expect { RubyUnits::Unit.new('') }.to raise_error(ArgumentError, 'No Unit Specified') end - specify "no blank strings" do - expect { RubyUnits::Unit.new(" ") }.to raise_error(ArgumentError, "No Unit Specified") + specify 'no blank strings' do + expect { RubyUnits::Unit.new(' ') }.to raise_error(ArgumentError, 'No Unit Specified') end - specify "no strings with tabs" do - expect { RubyUnits::Unit.new("\t") }.to raise_error(ArgumentError, "No Unit Specified") + specify 'no strings with tabs' do + expect { RubyUnits::Unit.new("\t") }.to raise_error(ArgumentError, 'No Unit Specified') end - specify "no strings with newlines" do - expect { RubyUnits::Unit.new("\n") }.to raise_error(ArgumentError, "No Unit Specified") + specify 'no strings with newlines' do + expect { RubyUnits::Unit.new("\n") }.to raise_error(ArgumentError, 'No Unit Specified') end - specify "no double slashes" do - expect { RubyUnits::Unit.new("3 s/s/ft") }.to raise_error(ArgumentError, /Unit not recognized/) + specify 'no double slashes' do + expect { RubyUnits::Unit.new('3 s/s/ft') }.to raise_error(ArgumentError, /Unit not recognized/) end - specify "no pipes or commas" do - expect { RubyUnits::Unit.new("3 s**2|,s**2") }.to raise_error(ArgumentError, /Unit not recognized/) + specify 'no pipes or commas' do + expect { RubyUnits::Unit.new('3 s**2|,s**2') }.to raise_error(ArgumentError, /Unit not recognized/) end - specify "no multiple spaces" do - expect { RubyUnits::Unit.new("3 s**2 4s s**2") }.to raise_error(ArgumentError, /Unit not recognized/) + specify 'no multiple spaces' do + expect { RubyUnits::Unit.new('3 s**2 4s s**2') }.to raise_error(ArgumentError, /Unit not recognized/) end - specify "no exponentiation of numbers" do - expect { RubyUnits::Unit.new("3 s 5^6") }.to raise_error(ArgumentError, /Unit not recognized/) + specify 'no exponentiation of numbers' do + expect { RubyUnits::Unit.new('3 s 5^6') }.to raise_error(ArgumentError, /Unit not recognized/) end specify "no strings that don't specify a valid unit" do - expect { RubyUnits::Unit.new("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") + expect { RubyUnits::Unit.new('random string') }.to raise_error(ArgumentError, "'random string' Unit not recognized") end - specify "no unhandled classes" do - expect { RubyUnits::Unit.new(STDIN) }.to raise_error(ArgumentError, "Invalid Unit Format") + specify 'no unhandled classes' do + expect { RubyUnits::Unit.new(STDIN) }.to raise_error(ArgumentError, 'Invalid Unit Format') end - specify "no undefined units" do - expect { RubyUnits::Unit.new("1 mFoo") }.to raise_error(ArgumentError, "'1 mFoo' Unit not recognized") - expect { RubyUnits::Unit.new("1 second/mFoo") }.to raise_error(ArgumentError, "'1 second/mFoo' Unit not recognized") + specify 'no undefined units' do + expect { RubyUnits::Unit.new('1 mFoo') }.to raise_error(ArgumentError, "'1 mFoo' Unit not recognized") + expect { RubyUnits::Unit.new('1 second/mFoo') }.to raise_error(ArgumentError, "'1 second/mFoo' Unit not recognized") end - specify "no units with powers greater than 19" do - expect { RubyUnits::Unit.new("1 m^20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + specify 'no units with powers greater than 19' do + expect { RubyUnits::Unit.new('1 m^20') }.to raise_error(ArgumentError, 'Power out of range (-20 < net power of a unit < 20)') end - specify "no units with powers less than 19" do - expect { RubyUnits::Unit.new("1 m^-20") }.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)") + specify 'no units with powers less than 19' do + expect { RubyUnits::Unit.new('1 m^-20') }.to raise_error(ArgumentError, 'Power out of range (-20 < net power of a unit < 20)') end - specify "no temperatures less than absolute zero" do - expect { RubyUnits::Unit.new("-100 tempK") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") - expect { RubyUnits::Unit.new("-100 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") - expect { RubyUnits::Unit.new("-500/9 tempR") }.to raise_error(ArgumentError, "Temperatures must not be less than absolute zero") + specify 'no temperatures less than absolute zero' do + expect { RubyUnits::Unit.new('-100 tempK') }.to raise_error(ArgumentError, 'Temperatures must not be less than absolute zero') + expect { RubyUnits::Unit.new('-100 tempR') }.to raise_error(ArgumentError, 'Temperatures must not be less than absolute zero') + expect { RubyUnits::Unit.new('-500/9 tempR') }.to raise_error(ArgumentError, 'Temperatures must not be less than absolute zero') end - specify "no nil scalar" do - expect { RubyUnits::Unit.new(nil, "feet") }.to raise_error(ArgumentError, "Invalid Unit Format") - expect { RubyUnits::Unit.new(nil, "feet", "min") }.to raise_error(ArgumentError, "Invalid Unit Format") + specify 'no nil scalar' do + expect { RubyUnits::Unit.new(nil, 'feet') }.to raise_error(ArgumentError, 'Invalid Unit Format') + expect { RubyUnits::Unit.new(nil, 'feet', 'min') }.to raise_error(ArgumentError, 'Invalid Unit Format') end specify 'no double prefixes' do expect { Unit.new('1 mmm') }.to raise_error(ArgumentError, /Unit not recognized/) end - end describe Unit do - it "is a subclass of Numeric" do + it 'is a subclass of Numeric' do expect(described_class).to be < Numeric end - it "is Comparable" do + it 'is Comparable' do expect(described_class).to be < Comparable end - describe "#defined?" do - it "should return true when asked about a defined unit" do - expect(Unit.defined?("meter")).to be_truthy + describe '#defined?' do + it 'should return true when asked about a defined unit' do + expect(Unit.defined?('meter')).to be_truthy end - it "should return true when asked about an alias for a unit" do - expect(Unit.defined?("m")).to be_truthy + it 'should return true when asked about an alias for a unit' do + expect(Unit.defined?('m')).to be_truthy end - it "should return false when asked about a unit that is not defined" do - expect(Unit.defined?("doohickey")).to be_falsey + it 'should return false when asked about a unit that is not defined' do + expect(Unit.defined?('doohickey')).to be_falsey end end @@ -1322,38 +1320,38 @@ end end - describe "#definition" do - context "The requested unit is defined" do + describe '#definition' do + context 'The requested unit is defined' do before(:each) do @definition = Unit.definition('mph') end - it "should return a Unit::Definition" do + it 'should return a Unit::Definition' do expect(@definition).to be_instance_of(Unit::Definition) end - specify { expect(@definition.name).to eq("") } - specify { expect(@definition.aliases).to eq(%w{mph}) } + specify { expect(@definition.name).to eq('') } + specify { expect(@definition.aliases).to eq(%w(mph)) } specify { expect(@definition.numerator).to eq(['']) } specify { expect(@definition.denominator).to eq(['']) } specify { expect(@definition.kind).to eq(:speed) } specify { expect(@definition.scalar).to be === 0.44704 } end - context "The requested unit is not defined" do - it "should return nil" do - expect(Unit.definition("doohickey")).to be_nil + context 'The requested unit is not defined' do + it 'should return nil' do + expect(Unit.definition('doohickey')).to be_nil end end end - describe "#define" do - describe "a new unit" do + describe '#define' do + describe 'a new unit' do before(:each) do - @jiffy = Unit.define("jiffy") do |jiffy| - jiffy.scalar = (1/100) - jiffy.aliases = %w{jif} - jiffy.numerator = [""] + @jiffy = Unit.define('jiffy') do |jiffy| + jiffy.scalar = (1 / 100) + jiffy.aliases = %w(jif) + jiffy.numerator = [''] jiffy.kind = :time end end @@ -1364,7 +1362,7 @@ describe "RubyUnits::Unit.new('1e6 jiffy')" do # do this because the unit is not defined at the time this file is parsed, so it fails - subject { RubyUnits::Unit.new("1e6 jiffy") } + subject { RubyUnits::Unit.new('1e6 jiffy') } it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -1381,7 +1379,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("jif") } + it { is_expected.to eq('jif') } end describe '#kind' do @@ -1396,32 +1394,32 @@ describe '#base' do subject { super().base } - it { is_expected.to eq(RubyUnits::Unit.new("10000 s")) } + it { is_expected.to eq(RubyUnits::Unit.new('10000 s')) } end end - it "should register the new unit" do + it 'should register the new unit' do expect(Unit.defined?('jiffy')).to be_truthy end end - describe "an existing unit again" do + describe 'an existing unit again' do before(:each) do @cups = Unit.definition('cup') @original_display_name = @cups.display_name - @cups.display_name = "cupz" + @cups.display_name = 'cupz' Unit.define(@cups) end after(:each) do - Unit.redefine!("cup") do |cup| + Unit.redefine!('cup') do |cup| cup.display_name = @original_display_name end end describe "RubyUnits::Unit.new('1 cup')" do # do this because the unit is going to be redefined - subject { RubyUnits::Unit.new("1 cup") } + subject { RubyUnits::Unit.new('1 cup') } it { is_expected.to be_a Numeric } it { is_expected.to be_an_instance_of Unit } @@ -1438,7 +1436,7 @@ describe '#units' do subject { super().units } - it { is_expected.to eq("cupz") } + it { is_expected.to eq('cupz') } end describe '#kind' do @@ -1451,56 +1449,53 @@ it { is_expected.not_to be_unitless } it { is_expected.not_to be_zero } end - end - end describe '#redefine!' do before(:each) do - @jiffy = Unit.define("jiffy") do |jiffy| - jiffy.scalar = (1/100) - jiffy.aliases = %w{jif} - jiffy.numerator = [""] + @jiffy = Unit.define('jiffy') do |jiffy| + jiffy.scalar = (1 / 100) + jiffy.aliases = %w(jif) + jiffy.numerator = [''] jiffy.kind = :time end Unit.redefine!('jiffy') do |jiffy| - jiffy.scalar = (1/1000) + jiffy.scalar = (1 / 1000) end end after(:each) do - Unit.undefine!("jiffy") + Unit.undefine!('jiffy') end - specify { expect(RubyUnits::Unit.new('1 jiffy').to_base.scalar).to eq(1/1000) } + specify { expect(RubyUnits::Unit.new('1 jiffy').to_base.scalar).to eq(1 / 1000) } end describe '#undefine!' do before(:each) do - @jiffy = Unit.define("jiffy") do |jiffy| - jiffy.scalar = (1/100) - jiffy.aliases = %w{jif} - jiffy.numerator = [""] + @jiffy = Unit.define('jiffy') do |jiffy| + jiffy.scalar = (1 / 100) + jiffy.aliases = %w(jif) + jiffy.numerator = [''] jiffy.kind = :time end - Unit.undefine!("jiffy") + Unit.undefine!('jiffy') end - specify "the unit should be undefined" do + specify 'the unit should be undefined' do expect(Unit.defined?('jiffy')).to be_falsey end - specify "attempting to use an undefined unit fails" do - expect { RubyUnits::Unit.new("1 jiffy") }.to raise_exception(ArgumentError) + specify 'attempting to use an undefined unit fails' do + expect { RubyUnits::Unit.new('1 jiffy') }.to raise_exception(ArgumentError) end - it "should return true when undefining an unknown unit" do - expect(Unit.defined?("unknown")).to be_falsey - expect(Unit.undefine!("unknown")).to be_truthy + it 'should return true when undefining an unknown unit' do + expect(Unit.defined?('unknown')).to be_falsey + expect(Unit.undefine!('unknown')).to be_truthy end - end describe '#clone' do @@ -1513,119 +1508,116 @@ end end -describe "Unit Comparisons" do +describe 'Unit Comparisons' do context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do - specify { expect(RubyUnits::Unit.new("1 ft") =~ RubyUnits::Unit.new('1 m')).to be true } - specify { expect(RubyUnits::Unit.new("1 ft") =~ "m").to be true } - specify { expect(RubyUnits::Unit.new("1 ft")).to be_compatible_with RubyUnits::Unit.new('1 m') } - specify { expect(RubyUnits::Unit.new("1 ft")).to be_compatible_with "m" } - specify { expect(RubyUnits::Unit.new("1 m")).to be_compatible_with RubyUnits::Unit.new('1 kg*m/kg') } - specify { expect(RubyUnits::Unit.new("1 ft") =~ RubyUnits::Unit.new('1 kg')).to be false } - specify { expect(RubyUnits::Unit.new("1 ft")).not_to be_compatible_with RubyUnits::Unit.new('1 kg') } - specify { expect(RubyUnits::Unit.new("1 ft")).not_to be_compatible_with nil } + specify { expect(RubyUnits::Unit.new('1 ft') =~ RubyUnits::Unit.new('1 m')).to be true } + specify { expect(RubyUnits::Unit.new('1 ft') =~ 'm').to be true } + specify { expect(RubyUnits::Unit.new('1 ft')).to be_compatible_with RubyUnits::Unit.new('1 m') } + specify { expect(RubyUnits::Unit.new('1 ft')).to be_compatible_with 'm' } + specify { expect(RubyUnits::Unit.new('1 m')).to be_compatible_with RubyUnits::Unit.new('1 kg*m/kg') } + specify { expect(RubyUnits::Unit.new('1 ft') =~ RubyUnits::Unit.new('1 kg')).to be false } + specify { expect(RubyUnits::Unit.new('1 ft')).not_to be_compatible_with RubyUnits::Unit.new('1 kg') } + specify { expect(RubyUnits::Unit.new('1 ft')).not_to be_compatible_with nil } end - context "Equality" do - - context "with uncoercable objects" do - specify { expect(RubyUnits::Unit.new("1 mm")).not_to eq(nil) } + context 'Equality' do + context 'with uncoercable objects' do + specify { expect(RubyUnits::Unit.new('1 mm')).not_to eq(nil) } end - context "units of same kind" do - specify { expect(RubyUnits::Unit.new("1000 m")).to eq(RubyUnits::Unit.new('1 km')) } - specify { expect(RubyUnits::Unit.new("100 m")).not_to eq(RubyUnits::Unit.new('1 km')) } - specify { expect(RubyUnits::Unit.new("1 m")).to eq(RubyUnits::Unit.new('100 cm')) } + context 'units of same kind' do + specify { expect(RubyUnits::Unit.new('1000 m')).to eq(RubyUnits::Unit.new('1 km')) } + specify { expect(RubyUnits::Unit.new('100 m')).not_to eq(RubyUnits::Unit.new('1 km')) } + specify { expect(RubyUnits::Unit.new('1 m')).to eq(RubyUnits::Unit.new('100 cm')) } end - context "units of incompatible types" do - specify { expect(RubyUnits::Unit.new("1 m")).not_to eq(RubyUnits::Unit.new("1 kg")) } + context 'units of incompatible types' do + specify { expect(RubyUnits::Unit.new('1 m')).not_to eq(RubyUnits::Unit.new('1 kg')) } end - context "units with a zero scalar are equal" do - specify { expect(RubyUnits::Unit.new("0 m")).to eq(RubyUnits::Unit.new("0 s")) } - specify { expect(RubyUnits::Unit.new("0 m")).to eq(RubyUnits::Unit.new("0 kg")) } + context 'units with a zero scalar are equal' do + specify { expect(RubyUnits::Unit.new('0 m')).to eq(RubyUnits::Unit.new('0 s')) } + specify { expect(RubyUnits::Unit.new('0 m')).to eq(RubyUnits::Unit.new('0 kg')) } - context "except for temperature units" do - specify { expect(RubyUnits::Unit.new("0 tempK")).to eq(RubyUnits::Unit.new("0 m")) } - specify { expect(RubyUnits::Unit.new("0 tempR")).to eq(RubyUnits::Unit.new("0 m")) } - specify { expect(RubyUnits::Unit.new("0 tempC")).not_to eq(RubyUnits::Unit.new("0 m")) } - specify { expect(RubyUnits::Unit.new("0 tempF")).not_to eq(RubyUnits::Unit.new("0 m")) } + context 'except for temperature units' do + specify { expect(RubyUnits::Unit.new('0 tempK')).to eq(RubyUnits::Unit.new('0 m')) } + specify { expect(RubyUnits::Unit.new('0 tempR')).to eq(RubyUnits::Unit.new('0 m')) } + specify { expect(RubyUnits::Unit.new('0 tempC')).not_to eq(RubyUnits::Unit.new('0 m')) } + specify { expect(RubyUnits::Unit.new('0 tempF')).not_to eq(RubyUnits::Unit.new('0 m')) } end end end - context "Equivalence" do - context "units and scalars are the exactly the same" do - specify { expect(RubyUnits::Unit.new("1 m")).to be === RubyUnits::Unit.new("1 m") } - specify { expect(RubyUnits::Unit.new("1 m")).to be_same RubyUnits::Unit.new("1 m") } - specify { expect(RubyUnits::Unit.new("1 m")).to be_same_as RubyUnits::Unit.new("1 m") } + context 'Equivalence' do + context 'units and scalars are the exactly the same' do + specify { expect(RubyUnits::Unit.new('1 m')).to be === RubyUnits::Unit.new('1 m') } + specify { expect(RubyUnits::Unit.new('1 m')).to be_same RubyUnits::Unit.new('1 m') } + specify { expect(RubyUnits::Unit.new('1 m')).to be_same_as RubyUnits::Unit.new('1 m') } end - context "units are compatible but not identical" do - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be === RubyUnits::Unit.new("1 km") } - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same RubyUnits::Unit.new("1 km") } - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same_as RubyUnits::Unit.new("1 km") } + context 'units are compatible but not identical' do + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be === RubyUnits::Unit.new('1 km') } + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be_same RubyUnits::Unit.new('1 km') } + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be_same_as RubyUnits::Unit.new('1 km') } end - context "units are not compatible" do - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be === RubyUnits::Unit.new("1 hour") } - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same RubyUnits::Unit.new("1 hour") } - specify { expect(RubyUnits::Unit.new("1000 m")).not_to be_same_as RubyUnits::Unit.new("1 hour") } + context 'units are not compatible' do + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be === RubyUnits::Unit.new('1 hour') } + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be_same RubyUnits::Unit.new('1 hour') } + specify { expect(RubyUnits::Unit.new('1000 m')).not_to be_same_as RubyUnits::Unit.new('1 hour') } end - context "scalars are different" do - specify { expect(RubyUnits::Unit.new("1 m")).not_to be === RubyUnits::Unit.new("2 m") } - specify { expect(RubyUnits::Unit.new("1 m")).not_to be_same RubyUnits::Unit.new("2 m") } - specify { expect(RubyUnits::Unit.new("1 m")).not_to be_same_as RubyUnits::Unit.new("2 m") } + context 'scalars are different' do + specify { expect(RubyUnits::Unit.new('1 m')).not_to be === RubyUnits::Unit.new('2 m') } + specify { expect(RubyUnits::Unit.new('1 m')).not_to be_same RubyUnits::Unit.new('2 m') } + specify { expect(RubyUnits::Unit.new('1 m')).not_to be_same_as RubyUnits::Unit.new('2 m') } end - specify { expect(RubyUnits::Unit.new("1 m")).not_to be === nil } + specify { expect(RubyUnits::Unit.new('1 m')).not_to be === nil } end - context "Comparisons" do - context "compatible units can be compared" do - specify { expect(RubyUnits::Unit.new("1 m")).to be < RubyUnits::Unit.new("2 m") } - specify { expect(RubyUnits::Unit.new("2 m")).to be > RubyUnits::Unit.new("1 m") } - specify { expect(RubyUnits::Unit.new("1 m")).to be < RubyUnits::Unit.new("1 mi") } - specify { expect(RubyUnits::Unit.new("2 m")).to be > RubyUnits::Unit.new("1 ft") } - specify { expect(RubyUnits::Unit.new("70 tempF")).to be > RubyUnits::Unit.new("10 degC") } - specify { expect(RubyUnits::Unit.new("1 m")).to be > 0 } - specify { expect { RubyUnits::Unit.new("1 m") > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } + context 'Comparisons' do + context 'compatible units can be compared' do + specify { expect(RubyUnits::Unit.new('1 m')).to be < RubyUnits::Unit.new('2 m') } + specify { expect(RubyUnits::Unit.new('2 m')).to be > RubyUnits::Unit.new('1 m') } + specify { expect(RubyUnits::Unit.new('1 m')).to be < RubyUnits::Unit.new('1 mi') } + specify { expect(RubyUnits::Unit.new('2 m')).to be > RubyUnits::Unit.new('1 ft') } + specify { expect(RubyUnits::Unit.new('70 tempF')).to be > RubyUnits::Unit.new('10 degC') } + specify { expect(RubyUnits::Unit.new('1 m')).to be > 0 } + specify { expect { RubyUnits::Unit.new('1 m') > nil }.to raise_error(ArgumentError, /comparison of RubyUnits::Unit with (nil failed|NilClass)/) } end - context "incompatible units cannot be compared" do - specify { expect { RubyUnits::Unit.new("1 m") < RubyUnits::Unit.new("1 liter") }.to raise_error(ArgumentError, "Incompatible Units ('m' not compatible with 'l')") } - specify { expect { RubyUnits::Unit.new("1 kg") > RubyUnits::Unit.new("60 mph") }.to raise_error(ArgumentError, "Incompatible Units ('kg' not compatible with 'mph')") } + context 'incompatible units cannot be compared' do + specify { expect { RubyUnits::Unit.new('1 m') < RubyUnits::Unit.new('1 liter') }.to raise_error(ArgumentError, "Incompatible Units ('m' not compatible with 'l')") } + specify { expect { RubyUnits::Unit.new('1 kg') > RubyUnits::Unit.new('60 mph') }.to raise_error(ArgumentError, "Incompatible Units ('kg' not compatible with 'mph')") } end - context "with coercions should be valid" do - specify { expect(RubyUnits::Unit.new("1GB") > "500MB").to eq(true) } - specify { expect(RubyUnits::Unit.new("0.5GB") < "900MB").to eq(true) } + context 'with coercions should be valid' do + specify { expect(RubyUnits::Unit.new('1GB') > '500MB').to eq(true) } + specify { expect(RubyUnits::Unit.new('0.5GB') < '900MB').to eq(true) } end end - end -describe "Unit Conversions" do - - context "between compatible units" do - specify { expect(RubyUnits::Unit.new("1 s").convert_to("ns")).to eq(RubyUnits::Unit.new("1e9 ns")) } - specify { expect(RubyUnits::Unit.new("1 s").convert_to("ns")).to eq(RubyUnits::Unit.new("1e9 ns")) } - specify { expect(RubyUnits::Unit.new("1 s") >> "ns").to eq(RubyUnits::Unit.new("1e9 ns")) } +describe 'Unit Conversions' do + context 'between compatible units' do + specify { expect(RubyUnits::Unit.new('1 s').convert_to('ns')).to eq(RubyUnits::Unit.new('1e9 ns')) } + specify { expect(RubyUnits::Unit.new('1 s').convert_to('ns')).to eq(RubyUnits::Unit.new('1e9 ns')) } + specify { expect(RubyUnits::Unit.new('1 s') >> 'ns').to eq(RubyUnits::Unit.new('1e9 ns')) } - specify { expect(RubyUnits::Unit.new("1 m").convert_to(RubyUnits::Unit.new("ft"))).to be_within(RubyUnits::Unit.new("0.001 ft")).of(RubyUnits::Unit.new("3.28084 ft")) } + specify { expect(RubyUnits::Unit.new('1 m').convert_to(RubyUnits::Unit.new('ft'))).to be_within(RubyUnits::Unit.new('0.001 ft')).of(RubyUnits::Unit.new('3.28084 ft')) } end - context "between incompatible units" do - specify { expect { RubyUnits::Unit.new("1 s").convert_to("m") }.to raise_error(ArgumentError, "Incompatible Units ('1 s' not compatible with 'm')") } + context 'between incompatible units' do + specify { expect { RubyUnits::Unit.new('1 s').convert_to('m') }.to raise_error(ArgumentError, "Incompatible Units ('1 s' not compatible with 'm')") } end - context "given bad input" do - specify { expect { RubyUnits::Unit.new("1 m").convert_to("random string") }.to raise_error(ArgumentError, "'random string' Unit not recognized") } - specify { expect { RubyUnits::Unit.new("1 m").convert_to(STDOUT) }.to raise_error(ArgumentError, "Unknown target units") } + context 'given bad input' do + specify { expect { RubyUnits::Unit.new('1 m').convert_to('random string') }.to raise_error(ArgumentError, "'random string' Unit not recognized") } + specify { expect { RubyUnits::Unit.new('1 m').convert_to(STDOUT) }.to raise_error(ArgumentError, 'Unknown target units') } end - context "between temperature scales" do + context 'between temperature scales' do # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent # differences between temperatures, offsets, or other differential temperatures. @@ -1654,49 +1646,49 @@ specify { expect(RubyUnits::Unit.new('1 degF')).to be_within(RubyUnits::Unit.new('0.001 degK')).of(RubyUnits::Unit.new('0.5555 degK')) } end - context "reported bugs" do - specify { expect(RubyUnits::Unit.new("189 Mtonne") * RubyUnits::Unit.new("1189 g/tonne")).to eq(RubyUnits::Unit.new("224721 tonne")) } - specify { expect((RubyUnits::Unit.new("189 Mtonne") * RubyUnits::Unit.new("1189 g/tonne")).convert_to("tonne")).to eq(RubyUnits::Unit.new("224721 tonne")) } + context 'reported bugs' do + specify { expect(RubyUnits::Unit.new('189 Mtonne') * RubyUnits::Unit.new('1189 g/tonne')).to eq(RubyUnits::Unit.new('224721 tonne')) } + specify { expect((RubyUnits::Unit.new('189 Mtonne') * RubyUnits::Unit.new('1189 g/tonne')).convert_to('tonne')).to eq(RubyUnits::Unit.new('224721 tonne')) } end - describe "Foot-inch conversions" do + describe 'Foot-inch conversions' do [ - ["76 in", %Q{6'4"}], - ["77 in", %Q{6'5"}], - ["78 in", %Q{6'6"}], - ["79 in", %Q{6'7"}], - ["80 in", %Q{6'8"}], - ["87 in", %Q{7'3"}], - ["88 in", %Q{7'4"}], - ["89 in", %Q{7'5"}] + ['76 in', %(6'4")], + ['77 in', %(6'5")], + ['78 in', %(6'6")], + ['79 in', %(6'7")], + ['80 in', %(6'8")], + ['87 in', %(7'3")], + ['88 in', %(7'4")], + ['89 in', %(7'5")] ].each do |inches, feet| - specify { expect(RubyUnits::Unit.new(inches).convert_to("ft")).to eq(RubyUnits::Unit.new(feet)) } + specify { expect(RubyUnits::Unit.new(inches).convert_to('ft')).to eq(RubyUnits::Unit.new(feet)) } specify { expect(RubyUnits::Unit.new(inches).to_s(:ft)).to eq(feet) } end end - describe "pound-ounce conversions" do + describe 'pound-ounce conversions' do [ - ["76 oz", "4 lbs, 12 oz"], - ["77 oz", "4 lbs, 13 oz"], - ["78 oz", "4 lbs, 14 oz"], - ["79 oz", "4 lbs, 15 oz"], - ["80 oz", "5 lbs, 0 oz"], - ["87 oz", "5 lbs, 7 oz"], - ["88 oz", "5 lbs, 8 oz"], - ["89 oz", "5 lbs, 9 oz"] + ['76 oz', '4 lbs, 12 oz'], + ['77 oz', '4 lbs, 13 oz'], + ['78 oz', '4 lbs, 14 oz'], + ['79 oz', '4 lbs, 15 oz'], + ['80 oz', '5 lbs, 0 oz'], + ['87 oz', '5 lbs, 7 oz'], + ['88 oz', '5 lbs, 8 oz'], + ['89 oz', '5 lbs, 9 oz'] ].each do |ounces, pounds| - specify { expect(RubyUnits::Unit.new(ounces).convert_to("lbs")).to eq(RubyUnits::Unit.new(pounds)) } + specify { expect(RubyUnits::Unit.new(ounces).convert_to('lbs')).to eq(RubyUnits::Unit.new(pounds)) } specify { expect(RubyUnits::Unit.new(ounces).to_s(:lbs)).to eq(pounds) } end end describe 'stone-pound conversions' do [ - ["14 stone 4", '200 lbs'], + ['14 stone 4', '200 lbs'], ['14 st 4', '200 lbs'], ['14 stone, 4 pounds', '200 lbs'], - ['14 st, 4 lbs', '200 lbs' ] + ['14 st, 4 lbs', '200 lbs'] ].each do |stone, pounds| specify { expect(RubyUnits::Unit.new(stone).convert_to('lbs')).to eq(RubyUnits::Unit.new(pounds)) } end @@ -1704,380 +1696,372 @@ end end -describe "Unit Math" do - context "operators:" do - context "addition (+)" do - context "between compatible units" do - specify { expect(RubyUnits::Unit.new("0 m") + RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("10 m")) } - specify { expect(RubyUnits::Unit.new("5 kg") + RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("15 kg")) } +describe 'Unit Math' do + context 'operators:' do + context 'addition (+)' do + context 'between compatible units' do + specify { expect(RubyUnits::Unit.new('0 m') + RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new('10 m')) } + specify { expect(RubyUnits::Unit.new('5 kg') + RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('15 kg')) } end - context "between a zero unit and another unit" do - specify { expect(RubyUnits::Unit.new("0 kg") + RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("10 m")) } - specify { expect(RubyUnits::Unit.new("0 m") + RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("10 kg")) } + context 'between a zero unit and another unit' do + specify { expect(RubyUnits::Unit.new('0 kg') + RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new('10 m')) } + specify { expect(RubyUnits::Unit.new('0 m') + RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('10 kg')) } end - context "between incompatible units" do - specify { expect { RubyUnits::Unit.new("10 kg") + RubyUnits::Unit.new("10 m") }.to raise_error(ArgumentError) } - specify { expect { RubyUnits::Unit.new("10 m") + RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } - specify { expect { RubyUnits::Unit.new("10 m") + nil }.to raise_error(ArgumentError) } + context 'between incompatible units' do + specify { expect { RubyUnits::Unit.new('10 kg') + RubyUnits::Unit.new('10 m') }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new('10 m') + RubyUnits::Unit.new('10 kg') }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new('10 m') + nil }.to raise_error(ArgumentError) } end - context "a number from a unit" do - specify { expect { RubyUnits::Unit.new("10 kg") + 1 }.to raise_error(ArgumentError) } - specify { expect { 10 + RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } + context 'a number from a unit' do + specify { expect { RubyUnits::Unit.new('10 kg') + 1 }.to raise_error(ArgumentError) } + specify { expect { 10 + RubyUnits::Unit.new('10 kg') }.to raise_error(ArgumentError) } end - context "between a unit and coerceable types" do - specify { expect(RubyUnits::Unit.new('10 kg') + %w{1 kg}).to eq(RubyUnits::Unit.new('11 kg')) } - specify { expect(RubyUnits::Unit.new('10 kg') + "1 kg").to eq(RubyUnits::Unit.new('11 kg')) } + context 'between a unit and coerceable types' do + specify { expect(RubyUnits::Unit.new('10 kg') + %w(1 kg)).to eq(RubyUnits::Unit.new('11 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') + '1 kg').to eq(RubyUnits::Unit.new('11 kg')) } end - context "between two temperatures" do - specify { expect { (RubyUnits::Unit.new("100 tempK") + RubyUnits::Unit.new("100 tempK")) }.to raise_error(ArgumentError, "Cannot add two temperatures") } + context 'between two temperatures' do + specify { expect { (RubyUnits::Unit.new('100 tempK') + RubyUnits::Unit.new('100 tempK')) }.to raise_error(ArgumentError, 'Cannot add two temperatures') } end - context "between a temperature and a degree" do - specify { expect(RubyUnits::Unit.new("100 tempK") + RubyUnits::Unit.new("100 degK")).to eq(RubyUnits::Unit.new("200 tempK")) } + context 'between a temperature and a degree' do + specify { expect(RubyUnits::Unit.new('100 tempK') + RubyUnits::Unit.new('100 degK')).to eq(RubyUnits::Unit.new('200 tempK')) } end - context "between a degree and a temperature" do - specify { expect(RubyUnits::Unit.new("100 degK") + RubyUnits::Unit.new("100 tempK")).to eq(RubyUnits::Unit.new("200 tempK")) } + context 'between a degree and a temperature' do + specify { expect(RubyUnits::Unit.new('100 degK') + RubyUnits::Unit.new('100 tempK')).to eq(RubyUnits::Unit.new('200 tempK')) } end - end - context "subtracting (-)" do - context "compatible units" do - specify { expect(RubyUnits::Unit.new("0 m") - RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("-10 m")) } - specify { expect(RubyUnits::Unit.new("5 kg") - RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("-5 kg")) } + context 'subtracting (-)' do + context 'compatible units' do + specify { expect(RubyUnits::Unit.new('0 m') - RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new('-10 m')) } + specify { expect(RubyUnits::Unit.new('5 kg') - RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('-5 kg')) } end - context "a unit from a zero unit" do - specify { expect(RubyUnits::Unit.new("0 kg") - RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("-10 m")) } - specify { expect(RubyUnits::Unit.new("0 m") - RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("-10 kg")) } + context 'a unit from a zero unit' do + specify { expect(RubyUnits::Unit.new('0 kg') - RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new('-10 m')) } + specify { expect(RubyUnits::Unit.new('0 m') - RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('-10 kg')) } end - context "incompatible units" do - specify { expect { RubyUnits::Unit.new("10 kg") - RubyUnits::Unit.new("10 m") }.to raise_error(ArgumentError) } - specify { expect { RubyUnits::Unit.new("10 m") - RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } - specify { expect { RubyUnits::Unit.new("10 m") - nil }.to raise_error(ArgumentError) } + context 'incompatible units' do + specify { expect { RubyUnits::Unit.new('10 kg') - RubyUnits::Unit.new('10 m') }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new('10 m') - RubyUnits::Unit.new('10 kg') }.to raise_error(ArgumentError) } + specify { expect { RubyUnits::Unit.new('10 m') - nil }.to raise_error(ArgumentError) } end - context "between a unit and coerceable types" do - specify { expect(RubyUnits::Unit.new('10 kg') - %w{1 kg}).to eq(RubyUnits::Unit.new('9 kg')) } - specify { expect(RubyUnits::Unit.new('10 kg') - "1 kg").to eq(RubyUnits::Unit.new('9 kg')) } + context 'between a unit and coerceable types' do + specify { expect(RubyUnits::Unit.new('10 kg') - %w(1 kg)).to eq(RubyUnits::Unit.new('9 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') - '1 kg').to eq(RubyUnits::Unit.new('9 kg')) } end - context "a number from a unit" do - specify { expect { RubyUnits::Unit.new("10 kg") - 1 }.to raise_error(ArgumentError) } - specify { expect { 10 - RubyUnits::Unit.new("10 kg") }.to raise_error(ArgumentError) } + context 'a number from a unit' do + specify { expect { RubyUnits::Unit.new('10 kg') - 1 }.to raise_error(ArgumentError) } + specify { expect { 10 - RubyUnits::Unit.new('10 kg') }.to raise_error(ArgumentError) } end - context "between two temperatures" do - specify { expect(RubyUnits::Unit.new("100 tempK") - RubyUnits::Unit.new("100 tempK")).to eq(RubyUnits::Unit.new("0 degK")) } + context 'between two temperatures' do + specify { expect(RubyUnits::Unit.new('100 tempK') - RubyUnits::Unit.new('100 tempK')).to eq(RubyUnits::Unit.new('0 degK')) } end - context "between a temperature and a degree" do - specify { expect(RubyUnits::Unit.new("100 tempK") - RubyUnits::Unit.new("100 degK")).to eq(RubyUnits::Unit.new("0 tempK")) } + context 'between a temperature and a degree' do + specify { expect(RubyUnits::Unit.new('100 tempK') - RubyUnits::Unit.new('100 degK')).to eq(RubyUnits::Unit.new('0 tempK')) } end - context "between a degree and a temperature" do - specify { expect { (RubyUnits::Unit.new("100 degK") - RubyUnits::Unit.new("100 tempK")) }.to raise_error(ArgumentError, "Cannot subtract a temperature from a differential degree unit") } + context 'between a degree and a temperature' do + specify { expect { (RubyUnits::Unit.new('100 degK') - RubyUnits::Unit.new('100 tempK')) }.to raise_error(ArgumentError, 'Cannot subtract a temperature from a differential degree unit') } end - end - context "multiplying (*)" do - context "between compatible units" do - specify { expect(RubyUnits::Unit.new("0 m") * RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new("0 m^2")) } - specify { expect(RubyUnits::Unit.new("5 kg") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("50 kg^2")) } + context 'multiplying (*)' do + context 'between compatible units' do + specify { expect(RubyUnits::Unit.new('0 m') * RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new('0 m^2')) } + specify { expect(RubyUnits::Unit.new('5 kg') * RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('50 kg^2')) } end - context "between incompatible units" do - specify { expect(RubyUnits::Unit.new("0 m") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("0 kg*m")) } - specify { expect(RubyUnits::Unit.new("5 m") * RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("50 kg*m")) } - specify { expect { RubyUnits::Unit.new("10 m") * nil }.to raise_error(ArgumentError) } + context 'between incompatible units' do + specify { expect(RubyUnits::Unit.new('0 m') * RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('0 kg*m')) } + specify { expect(RubyUnits::Unit.new('5 m') * RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('50 kg*m')) } + specify { expect { RubyUnits::Unit.new('10 m') * nil }.to raise_error(ArgumentError) } end - context "between a unit and coerceable types" do - specify { expect(RubyUnits::Unit.new('10 kg') * %w{1 kg}).to eq(RubyUnits::Unit.new('10 kg^2')) } - specify { expect(RubyUnits::Unit.new('10 kg') * "1 kg").to eq(RubyUnits::Unit.new('10 kg^2')) } + context 'between a unit and coerceable types' do + specify { expect(RubyUnits::Unit.new('10 kg') * %w(1 kg)).to eq(RubyUnits::Unit.new('10 kg^2')) } + specify { expect(RubyUnits::Unit.new('10 kg') * '1 kg').to eq(RubyUnits::Unit.new('10 kg^2')) } end - context "by a temperature" do - specify { expect { RubyUnits::Unit.new("5 kg") * RubyUnits::Unit.new("100 tempF") }.to raise_exception(ArgumentError) } + context 'by a temperature' do + specify { expect { RubyUnits::Unit.new('5 kg') * RubyUnits::Unit.new('100 tempF') }.to raise_exception(ArgumentError) } end - context "by a number" do - specify { expect(10 * RubyUnits::Unit.new("5 kg")).to eq(RubyUnits::Unit.new("50 kg")) } + context 'by a number' do + specify { expect(10 * RubyUnits::Unit.new('5 kg')).to eq(RubyUnits::Unit.new('50 kg')) } end - end - context "dividing (/)" do - context "compatible units" do - specify { expect(RubyUnits::Unit.new("0 m") / RubyUnits::Unit.new("10 m")).to eq(RubyUnits::Unit.new(0)) } - specify { expect(RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("10 kg")).to eq(Rational(1, 2)) } - specify { expect(RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("5 kg")).to eq(1) } + context 'dividing (/)' do + context 'compatible units' do + specify { expect(RubyUnits::Unit.new('0 m') / RubyUnits::Unit.new('10 m')).to eq(RubyUnits::Unit.new(0)) } + specify { expect(RubyUnits::Unit.new('5 kg') / RubyUnits::Unit.new('10 kg')).to eq(Rational(1, 2)) } + specify { expect(RubyUnits::Unit.new('5 kg') / RubyUnits::Unit.new('5 kg')).to eq(1) } end - context "incompatible units" do - specify { expect(RubyUnits::Unit.new("0 m") / RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("0 m/kg")) } - specify { expect(RubyUnits::Unit.new("5 m") / RubyUnits::Unit.new("10 kg")).to eq(RubyUnits::Unit.new("1/2 m/kg")) } - specify { expect { RubyUnits::Unit.new("10 m") / nil }.to raise_error(ArgumentError) } + context 'incompatible units' do + specify { expect(RubyUnits::Unit.new('0 m') / RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('0 m/kg')) } + specify { expect(RubyUnits::Unit.new('5 m') / RubyUnits::Unit.new('10 kg')).to eq(RubyUnits::Unit.new('1/2 m/kg')) } + specify { expect { RubyUnits::Unit.new('10 m') / nil }.to raise_error(ArgumentError) } end - context "between a unit and coerceable types" do - specify { expect(RubyUnits::Unit.new('10 kg^2') / %w{1 kg}).to eq(RubyUnits::Unit.new('10 kg')) } - specify { expect(RubyUnits::Unit.new('10 kg^2') / "1 kg").to eq(RubyUnits::Unit.new('10 kg')) } + context 'between a unit and coerceable types' do + specify { expect(RubyUnits::Unit.new('10 kg^2') / %w(1 kg)).to eq(RubyUnits::Unit.new('10 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg^2') / '1 kg').to eq(RubyUnits::Unit.new('10 kg')) } end - context "by a temperature" do - specify { expect { RubyUnits::Unit.new("5 kg") / RubyUnits::Unit.new("100 tempF") }.to raise_exception(ArgumentError) } + context 'by a temperature' do + specify { expect { RubyUnits::Unit.new('5 kg') / RubyUnits::Unit.new('100 tempF') }.to raise_exception(ArgumentError) } end - context "a number by a unit" do - specify { expect(10 / RubyUnits::Unit.new("5 kg")).to eq(RubyUnits::Unit.new("2 1/kg")) } + context 'a number by a unit' do + specify { expect(10 / RubyUnits::Unit.new('5 kg')).to eq(RubyUnits::Unit.new('2 1/kg')) } end - context "a unit by a number" do - specify { expect(RubyUnits::Unit.new("5 kg") / 2).to eq(RubyUnits::Unit.new("2.5 kg")) } + context 'a unit by a number' do + specify { expect(RubyUnits::Unit.new('5 kg') / 2).to eq(RubyUnits::Unit.new('2.5 kg')) } end - context "by zero" do - specify { expect { RubyUnits::Unit.new("10 m") / 0 }.to raise_error(ZeroDivisionError) } - specify { expect { RubyUnits::Unit.new("10 m") / RubyUnits::Unit.new("0 m") }.to raise_error(ZeroDivisionError) } - specify { expect { RubyUnits::Unit.new("10 m") / RubyUnits::Unit.new("0 kg") }.to raise_error(ZeroDivisionError) } + context 'by zero' do + specify { expect { RubyUnits::Unit.new('10 m') / 0 }.to raise_error(ZeroDivisionError) } + specify { expect { RubyUnits::Unit.new('10 m') / RubyUnits::Unit.new('0 m') }.to raise_error(ZeroDivisionError) } + specify { expect { RubyUnits::Unit.new('10 m') / RubyUnits::Unit.new('0 kg') }.to raise_error(ZeroDivisionError) } end end - context "exponentiating (**)" do - - specify "a temperature raises an execption" do - expect { RubyUnits::Unit.new("100 tempK")**2 }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") + context 'exponentiating (**)' do + specify 'a temperature raises an execption' do + expect { RubyUnits::Unit.new('100 tempK')**2 }.to raise_error(ArgumentError, 'Cannot raise a temperature to a power') end - context RubyUnits::Unit.new("0 m") do + context RubyUnits::Unit.new('0 m') do it { expect(subject**1).to eq(subject) } it { expect(subject**2).to eq(subject) } end - context RubyUnits::Unit.new("1 m") do + context RubyUnits::Unit.new('1 m') do it { expect(subject**0).to eq(1) } it { expect(subject**1).to eq(subject) } - it { expect(subject**(-1)).to eq(1/subject) } - it { expect(subject**(2)).to eq(RubyUnits::Unit.new("1 m^2")) } - it { expect(subject**(-2)).to eq(RubyUnits::Unit.new("1 1/m^2")) } - specify { expect { subject**(1/2) }.to raise_error(ArgumentError, "Illegal root") } + it { expect(subject**-1).to eq(1 / subject) } + it { expect(subject**2).to eq(RubyUnits::Unit.new('1 m^2')) } + it { expect(subject**-2).to eq(RubyUnits::Unit.new('1 1/m^2')) } + specify { expect { subject**(1 / 2) }.to raise_error(ArgumentError, 'Illegal root') } # because 1 m^(1/2) doesn't make any sense - specify { expect { subject**(Complex(1, 1)) }.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.") } - specify { expect { subject**(RubyUnits::Unit.new("1 m")) }.to raise_error(ArgumentError, "Invalid Exponent") } + specify { expect { subject**Complex(1, 1) }.to raise_error(ArgumentError, 'exponentiation of complex numbers is not yet supported.') } + specify { expect { subject**RubyUnits::Unit.new('1 m') }.to raise_error(ArgumentError, 'Invalid Exponent') } end - context RubyUnits::Unit.new("1 m^2") do - it { expect(subject**(Rational(1, 2))).to eq(RubyUnits::Unit.new("1 m")) } - it { expect(subject**(0.5)).to eq(RubyUnits::Unit.new("1 m")) } + context RubyUnits::Unit.new('1 m^2') do + it { expect(subject**Rational(1, 2)).to eq(RubyUnits::Unit.new('1 m')) } + it { expect(subject**0.5).to eq(RubyUnits::Unit.new('1 m')) } - specify { expect { subject**(0.12345) }.to raise_error(ArgumentError, "Not a n-th root (1..9), use 1/n") } - specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError, "Invalid Exponent") } + specify { expect { subject**0.12345 }.to raise_error(ArgumentError, 'Not a n-th root (1..9), use 1/n') } + specify { expect { subject**'abcdefg' }.to raise_error(ArgumentError, 'Invalid Exponent') } end - end - context "modulo (%)" do - context "compatible units" do - specify { expect(RubyUnits::Unit.new("2 m") % RubyUnits::Unit.new("1 m")).to eq(0) } - specify { expect(RubyUnits::Unit.new("5 m") % RubyUnits::Unit.new("2 m")).to eq(1) } + context 'modulo (%)' do + context 'compatible units' do + specify { expect(RubyUnits::Unit.new('2 m') % RubyUnits::Unit.new('1 m')).to eq(0) } + specify { expect(RubyUnits::Unit.new('5 m') % RubyUnits::Unit.new('2 m')).to eq(1) } end - specify "incompatible units raises an exception" do - expect { RubyUnits::Unit.new("1 m") % RubyUnits::Unit.new("1 kg") }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '1 kg')") + specify 'incompatible units raises an exception' do + expect { RubyUnits::Unit.new('1 m') % RubyUnits::Unit.new('1 kg') }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '1 kg')") end end - context "unary negation (-)" do - specify { expect(-RubyUnits::Unit.new("1 mm")).to eq(RubyUnits::Unit.new("-1 mm")) } + context 'unary negation (-)' do + specify { expect(-RubyUnits::Unit.new('1 mm')).to eq(RubyUnits::Unit.new('-1 mm')) } end - context "unary plus (+)" do + context 'unary plus (+)' do specify { expect(+RubyUnits::Unit.new('1 mm')).to eq(RubyUnits::Unit.new('1 mm')) } end end - context "#power" do - subject { RubyUnits::Unit.new("1 m") } - it "raises an exception when passed a Float argument" do - expect { subject.power(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") + context '#power' do + subject { RubyUnits::Unit.new('1 m') } + it 'raises an exception when passed a Float argument' do + expect { subject.power(1.5) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when passed a Rational argument" do - expect { subject.power(Rational(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") + it 'raises an exception when passed a Rational argument' do + expect { subject.power(Rational(1, 2)) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when passed a Complex argument" do - expect { subject.power(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") + it 'raises an exception when passed a Complex argument' do + expect { subject.power(Complex(1, 2)) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when called on a temperature unit" do - expect { RubyUnits::Unit.new("100 tempC").power(2) }.to raise_error(ArgumentError, "Cannot raise a temperature to a power") + it 'raises an exception when called on a temperature unit' do + expect { RubyUnits::Unit.new('100 tempC').power(2) }.to raise_error(ArgumentError, 'Cannot raise a temperature to a power') end - specify { expect(subject.power(-1)).to eq(RubyUnits::Unit.new("1 1/m")) } + specify { expect(subject.power(-1)).to eq(RubyUnits::Unit.new('1 1/m')) } specify { expect(subject.power(0)).to eq(1) } specify { expect(subject.power(1)).to eq(subject) } - specify { expect(subject.power(2)).to eq(RubyUnits::Unit.new("1 m^2")) } - + specify { expect(subject.power(2)).to eq(RubyUnits::Unit.new('1 m^2')) } end - context "#root" do - subject { RubyUnits::Unit.new("1 m") } - it "raises an exception when passed a Float argument" do - expect { subject.root(1.5) }.to raise_error(ArgumentError, "Exponent must an Integer") + context '#root' do + subject { RubyUnits::Unit.new('1 m') } + it 'raises an exception when passed a Float argument' do + expect { subject.root(1.5) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when passed a Rational argument" do - expect { subject.root(Rational(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") + it 'raises an exception when passed a Rational argument' do + expect { subject.root(Rational(1, 2)) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when passed a Complex argument" do - expect { subject.root(Complex(1, 2)) }.to raise_error(ArgumentError, "Exponent must an Integer") + it 'raises an exception when passed a Complex argument' do + expect { subject.root(Complex(1, 2)) }.to raise_error(ArgumentError, 'Exponent must an Integer') end - it "raises an exception when called on a temperature unit" do - expect { RubyUnits::Unit.new("100 tempC").root(2) }.to raise_error(ArgumentError, "Cannot take the root of a temperature") + it 'raises an exception when called on a temperature unit' do + expect { RubyUnits::Unit.new('100 tempC').root(2) }.to raise_error(ArgumentError, 'Cannot take the root of a temperature') end - specify { expect(RubyUnits::Unit.new("1 m^2").root(-2)).to eq(RubyUnits::Unit.new("1 1/m")) } - specify { expect(subject.root(-1)).to eq(RubyUnits::Unit.new("1 1/m")) } - specify { expect { (subject.root(0)) }.to raise_error(ArgumentError, "0th root undefined") } + specify { expect(RubyUnits::Unit.new('1 m^2').root(-2)).to eq(RubyUnits::Unit.new('1 1/m')) } + specify { expect(subject.root(-1)).to eq(RubyUnits::Unit.new('1 1/m')) } + specify { expect { subject.root(0) }.to raise_error(ArgumentError, '0th root undefined') } specify { expect(subject.root(1)).to eq(subject) } - specify { expect(RubyUnits::Unit.new("1 m^2").root(2)).to eq(RubyUnits::Unit.new("1 m")) } - + specify { expect(RubyUnits::Unit.new('1 m^2').root(2)).to eq(RubyUnits::Unit.new('1 m')) } end - context "#inverse" do - specify { expect(RubyUnits::Unit.new("1 m").inverse).to eq(RubyUnits::Unit.new("1 1/m")) } - specify { expect { RubyUnits::Unit.new("100 tempK").inverse }.to raise_error(ArgumentError, "Cannot divide with temperatures") } + context '#inverse' do + specify { expect(RubyUnits::Unit.new('1 m').inverse).to eq(RubyUnits::Unit.new('1 1/m')) } + specify { expect { RubyUnits::Unit.new('100 tempK').inverse }.to raise_error(ArgumentError, 'Cannot divide with temperatures') } end - context "convert to scalars" do - specify { expect(RubyUnits::Unit.new("10").to_i).to be_kind_of(Integer) } - specify { expect { RubyUnits::Unit.new("10 m").to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } + context 'convert to scalars' do + specify { expect(RubyUnits::Unit.new('10').to_i).to be_kind_of(Integer) } + specify { expect { RubyUnits::Unit.new('10 m').to_i }.to raise_error(RuntimeError, "Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") } - specify { expect(RubyUnits::Unit.new("10.0").to_f).to be_kind_of(Float) } - specify { expect { RubyUnits::Unit.new("10.0 m").to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new('10.0').to_f).to be_kind_of(Float) } + specify { expect { RubyUnits::Unit.new('10.0 m').to_f }.to raise_error(RuntimeError, "Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") } - specify { expect(RubyUnits::Unit.new("1+1i").to_c).to be_kind_of(Complex) } - specify { expect { RubyUnits::Unit.new("1+1i m").to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } - - specify { expect(RubyUnits::Unit.new("3/7").to_r).to be_kind_of(Rational) } - specify { expect { RubyUnits::Unit.new("3/7 m").to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new('1+1i').to_c).to be_kind_of(Complex) } + specify { expect { RubyUnits::Unit.new('1+1i m').to_c }.to raise_error(RuntimeError, "Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") } + specify { expect(RubyUnits::Unit.new('3/7').to_r).to be_kind_of(Rational) } + specify { expect { RubyUnits::Unit.new('3/7 m').to_r }.to raise_error(RuntimeError, "Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") } end - context "absolute value (#abs)" do - context "of a unitless unit" do - specify "returns the absolute value of the scalar" do - expect(RubyUnits::Unit.new("-10").abs).to eq(10) + context 'absolute value (#abs)' do + context 'of a unitless unit' do + specify 'returns the absolute value of the scalar' do + expect(RubyUnits::Unit.new('-10').abs).to eq(10) end end - context "of a unit" do - specify "returns a unit with the absolute value of the scalar" do - expect(RubyUnits::Unit.new("-10 m").abs).to eq(RubyUnits::Unit.new("10 m")) + context 'of a unit' do + specify 'returns a unit with the absolute value of the scalar' do + expect(RubyUnits::Unit.new('-10 m').abs).to eq(RubyUnits::Unit.new('10 m')) end end end - context "#ceil" do - context "of a unitless unit" do - specify "returns the ceil of the scalar" do - expect(RubyUnits::Unit.new("10.1").ceil).to eq(11) + context '#ceil' do + context 'of a unitless unit' do + specify 'returns the ceil of the scalar' do + expect(RubyUnits::Unit.new('10.1').ceil).to eq(11) end end - context "of a unit" do - specify "returns a unit with the ceil of the scalar" do - expect(RubyUnits::Unit.new("10.1 m").ceil).to eq(RubyUnits::Unit.new("11 m")) + context 'of a unit' do + specify 'returns a unit with the ceil of the scalar' do + expect(RubyUnits::Unit.new('10.1 m').ceil).to eq(RubyUnits::Unit.new('11 m')) end end end - context "#floor" do - context "of a unitless unit" do - specify "returns the floor of the scalar" do - expect(RubyUnits::Unit.new("10.1").floor).to eq(10) + context '#floor' do + context 'of a unitless unit' do + specify 'returns the floor of the scalar' do + expect(RubyUnits::Unit.new('10.1').floor).to eq(10) end end - context "of a unit" do - specify "returns a unit with the floor of the scalar" do - expect(RubyUnits::Unit.new("10.1 m").floor).to eq(RubyUnits::Unit.new("10 m")) + context 'of a unit' do + specify 'returns a unit with the floor of the scalar' do + expect(RubyUnits::Unit.new('10.1 m').floor).to eq(RubyUnits::Unit.new('10 m')) end end end - context "#round" do - context "of a unitless unit" do - specify "returns the round of the scalar" do - expect(RubyUnits::Unit.new("10.5").round).to eq(11) + context '#round' do + context 'of a unitless unit' do + specify 'returns the round of the scalar' do + expect(RubyUnits::Unit.new('10.5').round).to eq(11) end end - context "of a unit" do - specify "returns a unit with the round of the scalar" do - expect(RubyUnits::Unit.new("10.5 m").round).to eq(RubyUnits::Unit.new("11 m")) + context 'of a unit' do + specify 'returns a unit with the round of the scalar' do + expect(RubyUnits::Unit.new('10.5 m').round).to eq(RubyUnits::Unit.new('11 m')) end end end - context "#truncate" do - context "of a unitless unit" do - specify "returns the truncate of the scalar" do - expect(RubyUnits::Unit.new("10.5").truncate).to eq(10) + context '#truncate' do + context 'of a unitless unit' do + specify 'returns the truncate of the scalar' do + expect(RubyUnits::Unit.new('10.5').truncate).to eq(10) end end - context "of a unit" do - specify "returns a unit with the truncate of the scalar" do - expect(RubyUnits::Unit.new("10.5 m").truncate).to eq(RubyUnits::Unit.new("10 m")) + context 'of a unit' do + specify 'returns a unit with the truncate of the scalar' do + expect(RubyUnits::Unit.new('10.5 m').truncate).to eq(RubyUnits::Unit.new('10 m')) end end - context "of a complex unit" do - specify "returns a unit with the truncate of the scalar" do - expect(RubyUnits::Unit.new("10.5 kg*m/s^3").truncate).to eq(RubyUnits::Unit.new("10 kg*m/s^3")) + context 'of a complex unit' do + specify 'returns a unit with the truncate of the scalar' do + expect(RubyUnits::Unit.new('10.5 kg*m/s^3').truncate).to eq(RubyUnits::Unit.new('10 kg*m/s^3')) end end end context '#zero?' do - it "is true when the scalar is zero on the base scale" do - expect(RubyUnits::Unit.new("0")).to be_zero - expect(RubyUnits::Unit.new("0 mm")).to be_zero - expect(RubyUnits::Unit.new("-273.15 tempC")).to be_zero + it 'is true when the scalar is zero on the base scale' do + expect(RubyUnits::Unit.new('0')).to be_zero + expect(RubyUnits::Unit.new('0 mm')).to be_zero + expect(RubyUnits::Unit.new('-273.15 tempC')).to be_zero end - it "is false when the scalar is not zero" do - expect(RubyUnits::Unit.new("1")).not_to be_zero - expect(RubyUnits::Unit.new("1 mm")).not_to be_zero - expect(RubyUnits::Unit.new("0 tempC")).not_to be_zero + it 'is false when the scalar is not zero' do + expect(RubyUnits::Unit.new('1')).not_to be_zero + expect(RubyUnits::Unit.new('1 mm')).not_to be_zero + expect(RubyUnits::Unit.new('0 tempC')).not_to be_zero end end context '#succ' do - specify { expect(RubyUnits::Unit.new("1").succ).to eq(RubyUnits::Unit.new("2")) } - specify { expect(RubyUnits::Unit.new("1 mm").succ).to eq(RubyUnits::Unit.new("2 mm")) } - specify { expect(RubyUnits::Unit.new("1 mm").next).to eq(RubyUnits::Unit.new("2 mm")) } - specify { expect(RubyUnits::Unit.new("-1 mm").succ).to eq(RubyUnits::Unit.new("0 mm")) } - specify { expect { RubyUnits::Unit.new("1.5 mm").succ }.to raise_error(ArgumentError, "Non Integer Scalar") } + specify { expect(RubyUnits::Unit.new('1').succ).to eq(RubyUnits::Unit.new('2')) } + specify { expect(RubyUnits::Unit.new('1 mm').succ).to eq(RubyUnits::Unit.new('2 mm')) } + specify { expect(RubyUnits::Unit.new('1 mm').next).to eq(RubyUnits::Unit.new('2 mm')) } + specify { expect(RubyUnits::Unit.new('-1 mm').succ).to eq(RubyUnits::Unit.new('0 mm')) } + specify { expect { RubyUnits::Unit.new('1.5 mm').succ }.to raise_error(ArgumentError, 'Non Integer Scalar') } end context '#pred' do - specify { expect(RubyUnits::Unit.new("1").pred).to eq(RubyUnits::Unit.new("0")) } - specify { expect(RubyUnits::Unit.new("1 mm").pred).to eq(RubyUnits::Unit.new("0 mm")) } - specify { expect(RubyUnits::Unit.new("-1 mm").pred).to eq(RubyUnits::Unit.new("-2 mm")) } - specify { expect { RubyUnits::Unit.new("1.5 mm").pred }.to raise_error(ArgumentError, "Non Integer Scalar") } + specify { expect(RubyUnits::Unit.new('1').pred).to eq(RubyUnits::Unit.new('0')) } + specify { expect(RubyUnits::Unit.new('1 mm').pred).to eq(RubyUnits::Unit.new('0 mm')) } + specify { expect(RubyUnits::Unit.new('-1 mm').pred).to eq(RubyUnits::Unit.new('-2 mm')) } + specify { expect { RubyUnits::Unit.new('1.5 mm').pred }.to raise_error(ArgumentError, 'Non Integer Scalar') } end context '#divmod' do - specify { expect(RubyUnits::Unit.new("5 mm").divmod(RubyUnits::Unit.new("2 mm"))).to eq([2, 1]) } - specify { expect(RubyUnits::Unit.new("1 km").divmod(RubyUnits::Unit.new("2 m"))).to eq([500, 0]) } + specify { expect(RubyUnits::Unit.new('5 mm').divmod(RubyUnits::Unit.new('2 mm'))).to eq([2, 1]) } + specify { expect(RubyUnits::Unit.new('1 km').divmod(RubyUnits::Unit.new('2 m'))).to eq([500, 0]) } specify { expect { RubyUnits::Unit.new('1 m').divmod(RubyUnits::Unit.new('2 kg')) }.to raise_error(ArgumentError, "Incompatible Units ('1 m' not compatible with '2 kg')") } end @@ -2091,7 +2075,7 @@ specify { expect { RubyUnits::Unit.new('0 m').best_prefix }.to_not raise_error } end - context "Time helper functions" do + context 'Time helper functions' do before do allow(Time).to receive(:now).and_return(Time.utc(2011, 10, 16)) allow(DateTime).to receive(:now).and_return(DateTime.civil(2011, 10, 16)) @@ -2099,55 +2083,53 @@ end context '#since' do - specify { expect(RubyUnits::Unit.new("min").since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new("5544000 min")) } - specify { expect(RubyUnits::Unit.new("min").since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new("5544000 min")) } - specify { expect(RubyUnits::Unit.new("min").since(Date.civil(2001, 4, 1))).to eq(RubyUnits::Unit.new("5544000 min")) } - specify { expect { RubyUnits::Unit.new("min").since("4-1-2001") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { RubyUnits::Unit.new("min").since(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new('min').since(Time.utc(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new('5544000 min')) } + specify { expect(RubyUnits::Unit.new('min').since(DateTime.civil(2001, 4, 1, 0, 0, 0))).to eq(RubyUnits::Unit.new('5544000 min')) } + specify { expect(RubyUnits::Unit.new('min').since(Date.civil(2001, 4, 1))).to eq(RubyUnits::Unit.new('5544000 min')) } + specify { expect { RubyUnits::Unit.new('min').since('4-1-2001') }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } + specify { expect { RubyUnits::Unit.new('min').since(nil) }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } end context '#before' do - specify { expect(RubyUnits::Unit.new("5 min").before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } - specify { expect(RubyUnits::Unit.new("5 min").before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } - specify { expect(RubyUnits::Unit.new("5 min").before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } - specify { expect { RubyUnits::Unit.new('5 min').before(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { RubyUnits::Unit.new('5 min').before("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new('5 min').before(Time.now)).to eq(Time.utc(2011, 10, 15, 23, 55)) } + specify { expect(RubyUnits::Unit.new('5 min').before(DateTime.now)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect(RubyUnits::Unit.new('5 min').before(Date.today)).to eq(DateTime.civil(2011, 10, 15, 23, 55)) } + specify { expect { RubyUnits::Unit.new('5 min').before(nil) }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } + specify { expect { RubyUnits::Unit.new('5 min').before('12:00') }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } end context '#ago' do - specify { expect(RubyUnits::Unit.new("5 min").ago).to be_kind_of Time } - specify { expect(RubyUnits::Unit.new("10000 y").ago).to be_kind_of Time } - specify { expect(RubyUnits::Unit.new("1 year").ago).to eq(Time.utc(2010, 10, 16)) } + specify { expect(RubyUnits::Unit.new('5 min').ago).to be_kind_of Time } + specify { expect(RubyUnits::Unit.new('10000 y').ago).to be_kind_of Time } + specify { expect(RubyUnits::Unit.new('1 year').ago).to eq(Time.utc(2010, 10, 16)) } end context '#until' do - specify { expect(RubyUnits::Unit.new("min").until(Date.civil(2011, 10, 17))).to eq(RubyUnits::Unit.new("1440 min")) } - specify { expect(RubyUnits::Unit.new("min").until(DateTime.civil(2011, 10, 21))).to eq(RubyUnits::Unit.new("7200 min")) } - specify { expect(RubyUnits::Unit.new("min").until(Time.utc(2011, 10, 21))).to eq(RubyUnits::Unit.new("7200 min")) } - specify { expect { RubyUnits::Unit.new('5 min').until(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { RubyUnits::Unit.new('5 min').until("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new('min').until(Date.civil(2011, 10, 17))).to eq(RubyUnits::Unit.new('1440 min')) } + specify { expect(RubyUnits::Unit.new('min').until(DateTime.civil(2011, 10, 21))).to eq(RubyUnits::Unit.new('7200 min')) } + specify { expect(RubyUnits::Unit.new('min').until(Time.utc(2011, 10, 21))).to eq(RubyUnits::Unit.new('7200 min')) } + specify { expect { RubyUnits::Unit.new('5 min').until(nil) }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } + specify { expect { RubyUnits::Unit.new('5 min').until('12:00') }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } end context '#from' do - specify { expect(RubyUnits::Unit.new("1 day").from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } - specify { expect(RubyUnits::Unit.new("5 min").from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 00, 05)) } - specify { expect(RubyUnits::Unit.new("5 min").from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 00, 05)) } - specify { expect { RubyUnits::Unit.new('5 min').from(nil) }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } - specify { expect { RubyUnits::Unit.new('5 min').from("12:00") }.to raise_error(ArgumentError, "Must specify a Time, Date, or DateTime") } + specify { expect(RubyUnits::Unit.new('1 day').from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } + specify { expect(RubyUnits::Unit.new('5 min').from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 0o0, 0o5)) } + specify { expect(RubyUnits::Unit.new('5 min').from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 0o0, 0o5)) } + specify { expect { RubyUnits::Unit.new('5 min').from(nil) }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } + specify { expect { RubyUnits::Unit.new('5 min').from('12:00') }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } end - end - end -describe "Unit Output formatting" do - context RubyUnits::Unit.new("10.5 m/s^2") do - specify { expect(subject.to_s).to eq("10.5 m/s^2") } - specify { expect(subject.to_s("%0.2f")).to eq("10.50 m/s^2") } - specify { expect(subject.to_s("%0.2e km/s^2")).to eq("1.05e-02 km/s^2") } - specify { expect(subject.to_s("km/s^2")).to eq("0.0105 km/s^2") } - specify { expect(subject.to_s(STDOUT)).to eq("10.5 m/s^2") } - specify { expect { subject.to_s("random string") }.to raise_error(ArgumentError, "'random' Unit not recognized") } +describe 'Unit Output formatting' do + context RubyUnits::Unit.new('10.5 m/s^2') do + specify { expect(subject.to_s).to eq('10.5 m/s^2') } + specify { expect(subject.to_s('%0.2f')).to eq('10.50 m/s^2') } + specify { expect(subject.to_s('%0.2e km/s^2')).to eq('1.05e-02 km/s^2') } + specify { expect(subject.to_s('km/s^2')).to eq('0.0105 km/s^2') } + specify { expect(subject.to_s(STDOUT)).to eq('10.5 m/s^2') } + specify { expect { subject.to_s('random string') }.to raise_error(ArgumentError, "'random' Unit not recognized") } end context 'for a unit with a custom display_name' do @@ -2166,34 +2148,32 @@ subject { Unit.new('8 cups') } specify { expect(subject.to_s).to eq('8 cupz') } - end - end -describe "Equations with Units" do - context "Ideal Gas Law" do +describe 'Equations with Units' do + context 'Ideal Gas Law' do let(:p) { RubyUnits::Unit.new('100 kPa') } let(:v) { RubyUnits::Unit.new('1 m^3') } let(:n) { RubyUnits::Unit.new('1 mole') } let(:r) { RubyUnits::Unit.new('8.31451 J/mol*degK') } - specify { expect(((p*v)/(n*r)).convert_to('tempK')).to be_within(RubyUnits::Unit.new('0.1 degK')).of(RubyUnits::Unit.new('12027.2 tempK')) } + specify { expect(((p * v) / (n * r)).convert_to('tempK')).to be_within(RubyUnits::Unit.new('0.1 degK')).of(RubyUnits::Unit.new('12027.2 tempK')) } end end -describe "Unit hash method" do - context "should return equal values for identical units" do - let(:kg_unit_1) { RubyUnits::Unit.new("2.2 kg") } - let(:kg_unit_2) { RubyUnits::Unit.new("2.2 kg") } +describe 'Unit hash method' do + context 'should return equal values for identical units' do + let(:kg_unit_1) { RubyUnits::Unit.new('2.2 kg') } + let(:kg_unit_2) { RubyUnits::Unit.new('2.2 kg') } specify { expect(kg_unit_1).to eq(kg_unit_2) } specify { expect(kg_unit_1.hash).to eq(kg_unit_2.hash) } specify { expect([kg_unit_1, kg_unit_2].uniq.size).to eq(1) } end - context "should return not equal values for differnet units" do - let(:kg_unit) { RubyUnits::Unit.new("2.2 kg") } - let(:lb_unit) { RubyUnits::Unit.new("2.2 lbs") } + context 'should return not equal values for differnet units' do + let(:kg_unit) { RubyUnits::Unit.new('2.2 kg') } + let(:lb_unit) { RubyUnits::Unit.new('2.2 lbs') } specify { expect(kg_unit).to_not eq(lb_unit) } specify { expect(kg_unit.hash).to_not eq(lb_unit.hash) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 787d1f92..ff080a1d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,4 +16,4 @@ config.run_all_when_everything_filtered = true end -require File.dirname(__FILE__) + "/../lib/ruby-units" +require File.dirname(__FILE__) + '/../lib/ruby-units' From ecf8b90c33b1c4130c9c71277a892f9a53eea604 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 27 Nov 2016 12:53:37 -0500 Subject: [PATCH 101/150] fix Guardfile --- Guardfile | 2 +- spec/{ruby-units => ruby_units}/array_spec.rb | 0 spec/{ruby-units => ruby_units}/bugs_spec.rb | 0 spec/{ruby-units => ruby_units}/cache_spec.rb | 0 spec/{ruby-units => ruby_units}/complex_spec.rb | 0 spec/{ruby-units => ruby_units}/date_spec.rb | 0 spec/{ruby-units => ruby_units}/definition_spec.rb | 0 spec/{ruby-units => ruby_units}/math_spec.rb | 0 spec/{ruby-units => ruby_units}/numeric_spec.rb | 0 spec/{ruby-units => ruby_units}/range_spec.rb | 0 spec/{ruby-units => ruby_units}/string_spec.rb | 0 spec/{ruby-units => ruby_units}/temperature_spec.rb | 0 spec/{ruby-units => ruby_units}/time_spec.rb | 0 spec/{ruby-units => ruby_units}/unit_spec.rb | 0 spec/{ruby-units => ruby_units}/utf-8/unit_spec.rb | 0 15 files changed, 1 insertion(+), 1 deletion(-) rename spec/{ruby-units => ruby_units}/array_spec.rb (100%) rename spec/{ruby-units => ruby_units}/bugs_spec.rb (100%) rename spec/{ruby-units => ruby_units}/cache_spec.rb (100%) rename spec/{ruby-units => ruby_units}/complex_spec.rb (100%) rename spec/{ruby-units => ruby_units}/date_spec.rb (100%) rename spec/{ruby-units => ruby_units}/definition_spec.rb (100%) rename spec/{ruby-units => ruby_units}/math_spec.rb (100%) rename spec/{ruby-units => ruby_units}/numeric_spec.rb (100%) rename spec/{ruby-units => ruby_units}/range_spec.rb (100%) rename spec/{ruby-units => ruby_units}/string_spec.rb (100%) rename spec/{ruby-units => ruby_units}/temperature_spec.rb (100%) rename spec/{ruby-units => ruby_units}/time_spec.rb (100%) rename spec/{ruby-units => ruby_units}/unit_spec.rb (100%) rename spec/{ruby-units => ruby_units}/utf-8/unit_spec.rb (100%) diff --git a/Guardfile b/Guardfile index fd444fcf..d8edab3f 100644 --- a/Guardfile +++ b/Guardfile @@ -26,6 +26,6 @@ guard :rspec, cmd: 'bundle exec rspec' do rspec.spec_helper = 'spec/spec_helper.rb' watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.("lib/#{m[1]}") } + watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.(m[1]) } watch(rspec.spec_helper) { rspec.spec_dir } end diff --git a/spec/ruby-units/array_spec.rb b/spec/ruby_units/array_spec.rb similarity index 100% rename from spec/ruby-units/array_spec.rb rename to spec/ruby_units/array_spec.rb diff --git a/spec/ruby-units/bugs_spec.rb b/spec/ruby_units/bugs_spec.rb similarity index 100% rename from spec/ruby-units/bugs_spec.rb rename to spec/ruby_units/bugs_spec.rb diff --git a/spec/ruby-units/cache_spec.rb b/spec/ruby_units/cache_spec.rb similarity index 100% rename from spec/ruby-units/cache_spec.rb rename to spec/ruby_units/cache_spec.rb diff --git a/spec/ruby-units/complex_spec.rb b/spec/ruby_units/complex_spec.rb similarity index 100% rename from spec/ruby-units/complex_spec.rb rename to spec/ruby_units/complex_spec.rb diff --git a/spec/ruby-units/date_spec.rb b/spec/ruby_units/date_spec.rb similarity index 100% rename from spec/ruby-units/date_spec.rb rename to spec/ruby_units/date_spec.rb diff --git a/spec/ruby-units/definition_spec.rb b/spec/ruby_units/definition_spec.rb similarity index 100% rename from spec/ruby-units/definition_spec.rb rename to spec/ruby_units/definition_spec.rb diff --git a/spec/ruby-units/math_spec.rb b/spec/ruby_units/math_spec.rb similarity index 100% rename from spec/ruby-units/math_spec.rb rename to spec/ruby_units/math_spec.rb diff --git a/spec/ruby-units/numeric_spec.rb b/spec/ruby_units/numeric_spec.rb similarity index 100% rename from spec/ruby-units/numeric_spec.rb rename to spec/ruby_units/numeric_spec.rb diff --git a/spec/ruby-units/range_spec.rb b/spec/ruby_units/range_spec.rb similarity index 100% rename from spec/ruby-units/range_spec.rb rename to spec/ruby_units/range_spec.rb diff --git a/spec/ruby-units/string_spec.rb b/spec/ruby_units/string_spec.rb similarity index 100% rename from spec/ruby-units/string_spec.rb rename to spec/ruby_units/string_spec.rb diff --git a/spec/ruby-units/temperature_spec.rb b/spec/ruby_units/temperature_spec.rb similarity index 100% rename from spec/ruby-units/temperature_spec.rb rename to spec/ruby_units/temperature_spec.rb diff --git a/spec/ruby-units/time_spec.rb b/spec/ruby_units/time_spec.rb similarity index 100% rename from spec/ruby-units/time_spec.rb rename to spec/ruby_units/time_spec.rb diff --git a/spec/ruby-units/unit_spec.rb b/spec/ruby_units/unit_spec.rb similarity index 100% rename from spec/ruby-units/unit_spec.rb rename to spec/ruby_units/unit_spec.rb diff --git a/spec/ruby-units/utf-8/unit_spec.rb b/spec/ruby_units/utf-8/unit_spec.rb similarity index 100% rename from spec/ruby-units/utf-8/unit_spec.rb rename to spec/ruby_units/utf-8/unit_spec.rb From d5576e84215902165ba811627fe4bc80fbbed6ba Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 27 Nov 2016 18:45:01 -0500 Subject: [PATCH 102/150] formatting changes --- .rubocop_todo.yml | 77 ++++-------------------------------- spec/ruby_units/math_spec.rb | 16 +++++--- spec/ruby_units/unit_spec.rb | 2 +- 3 files changed, 19 insertions(+), 76 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d5824081..fff31216 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,17 +1,11 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-11-26 14:04:52 -0500 using RuboCop version 0.45.0. +# on 2016-11-27 18:43:25 -0500 using RuboCop version 0.45.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 2 -# Configuration parameters: AllowSafeAssignment. -Lint/AssignmentInCondition: - Exclude: - - 'lib/ruby_units/unit.rb' - # Offense count: 1 Lint/EmptyWhen: Exclude: @@ -25,11 +19,6 @@ Lint/EndAlignment: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 1 -Lint/ParenthesesAsGroupedExpression: - Exclude: - - 'spec/ruby-units/unit_spec.rb' - # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. @@ -46,14 +35,14 @@ Lint/UselessAssignment: Metrics/AbcSize: Max: 175 -# Offense count: 8 +# Offense count: 6 Metrics/BlockNesting: Max: 4 # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1093 + Max: 1075 # Offense count: 15 Metrics/CyclomaticComplexity: @@ -62,7 +51,7 @@ Metrics/CyclomaticComplexity: # Offense count: 24 # Configuration parameters: CountComments. Metrics/MethodLength: - Max: 106 + Max: 104 # Offense count: 14 Metrics/PerceivedComplexity: @@ -74,23 +63,6 @@ Style/AlignArray: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods. -# SupportedStyles: line_count_based, semantic, braces_for_chaining -# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object -# FunctionalMethods: let, let!, subject, watch -# IgnoredMethods: lambda, proc, it -Style/BlockDelimiters: - Exclude: - - 'spec/ruby-units/math_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/BlockEndNewline: - Exclude: - - 'spec/ruby-units/math_spec.rb' - # Offense count: 1 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: nested, compact @@ -155,7 +127,7 @@ Style/For: Style/FormatString: Exclude: - 'lib/ruby_units/unit.rb' - - 'spec/ruby-units/string_spec.rb' + - 'spec/ruby_units/string_spec.rb' # Offense count: 4 # Configuration parameters: MinBodyLength. @@ -169,13 +141,6 @@ Style/IdenticalConditionalBranches: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: MaxLineLength. -# Style/IfUnlessModifier: -# Exclude: -# - 'lib/ruby_units/unit.rb' - # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. @@ -212,14 +177,6 @@ Style/MultilineIfThen: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 5 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: symmetrical, new_line, same_line -Style/MultilineMethodCallBraceLayout: - Exclude: - - 'spec/ruby-units/math_spec.rb' - # Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. @@ -240,7 +197,7 @@ Style/MultilineOperationIndentation: # Cop supports --auto-correct. Style/NilComparison: Exclude: - - 'spec/ruby-units/unit_spec.rb' + - 'spec/ruby_units/unit_spec.rb' # Offense count: 16 # Cop supports --auto-correct. @@ -268,12 +225,6 @@ Style/RedundantParentheses: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 100 -# Cop supports --auto-correct. -# Style/RedundantSelf: -# Exclude: -# - 'lib/ruby_units/unit.rb' - # Offense count: 9 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. @@ -281,7 +232,7 @@ Style/RedundantParentheses: Style/RegexpLiteral: Exclude: - 'lib/ruby_units/unit.rb' - - 'spec/ruby-units/unit_spec.rb' + - 'spec/ruby_units/unit_spec.rb' # Offense count: 9 # Cop supports --auto-correct. @@ -317,14 +268,6 @@ Style/SpaceAfterComma: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -Style/SpaceInsideBlockBraces: - Exclude: - - 'spec/ruby-units/math_spec.rb' - # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. @@ -346,9 +289,3 @@ Style/TernaryParentheses: Style/UnneededInterpolation: Exclude: - 'lib/ruby_units/unit.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/WhileUntilDo: - Exclude: - - 'lib/ruby_units/unit.rb' diff --git a/spec/ruby_units/math_spec.rb b/spec/ruby_units/math_spec.rb index 69e0c6d8..e33ceeaf 100644 --- a/spec/ruby_units/math_spec.rb +++ b/spec/ruby_units/math_spec.rb @@ -47,20 +47,26 @@ expect( Math.hypot( RubyUnits::Unit.new('1 m'), - RubyUnits::Unit.new('2 m'))).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('2.23607 m')) + RubyUnits::Unit.new('2 m') + ) + ).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('2.23607 m')) end specify do expect( Math.hypot( RubyUnits::Unit.new('1 m'), - RubyUnits::Unit.new('2 ft'))).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('1.17116 m')) + RubyUnits::Unit.new('2 ft') + ) + ).to be_within(RubyUnits::Unit.new('0.01 m')).of(RubyUnits::Unit.new('1.17116 m')) end - specify { expect(Math.hypot(3, 4)).to eq(5)} + specify { expect(Math.hypot(3, 4)).to eq(5) } specify do - expect { + expect do Math.hypot( RubyUnits::Unit.new('1 m'), - RubyUnits::Unit.new('2 lbs')) }.to raise_error(ArgumentError) + RubyUnits::Unit.new('2 lbs') + ) + end.to raise_error(ArgumentError) end specify do diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index 556b31d7..3d5071c3 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -823,7 +823,7 @@ describe '#scalar' do subject { super().scalar } it { is_expected.to be_an Numeric } - it { is_expected.to eq (12.0 / 6.0) } + it { is_expected.to eq(12.0 / 6.0) } end describe '#units' do From 3df23b91b9e5f126b42e5726815c1eca9eacca54 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 27 Nov 2016 18:45:33 -0500 Subject: [PATCH 103/150] refactor units... call signature changed. --- lib/ruby_units/unit.rb | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 04fd1512..610d8aa9 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1177,39 +1177,25 @@ def as_json(*args) # returns the 'unit' part of the Unit object without the scalar # @return [String] - def units(with_prefix = true) + def units(with_prefix: true) return '' if @numerator == UNITY_ARRAY && @denominator == UNITY_ARRAY - output_numerator = [] + output_numerator = ['1'] output_denominator = [] num = @numerator.clone.compact den = @denominator.clone.compact - if @numerator == UNITY_ARRAY - output_numerator << '1' - else - while defn = RubyUnits::Unit.definition(num.shift) do - if defn && defn.prefix? - if with_prefix - output_numerator << (defn.display_name + RubyUnits::Unit.definition(num.shift).display_name) - end - else - output_numerator << defn.display_name - end - end + unless @numerator == UNITY_ARRAY + definitions = num.map { |element| RubyUnits::Unit.definition(element) } + definitions.reject!(&:prefix?) unless with_prefix + definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a + output_numerator = definitions.map { |element| element.map(&:display_name).join } end - if @denominator == UNITY_ARRAY - output_denominator = [] - else - while defn = RubyUnits::Unit.definition(den.shift) do - if defn && defn.prefix? - if with_prefix - output_denominator << (defn.display_name + RubyUnits::Unit.definition(den.shift).display_name) - end - else - output_denominator << defn.display_name - end - end + unless @denominator == UNITY_ARRAY + definitions = den.map { |element| RubyUnits::Unit.definition(element) } + definitions.reject!(&:prefix?) unless with_prefix + definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a + output_denominator = definitions.map { |element| element.map(&:display_name).join } end on = output_numerator.uniq. @@ -1393,7 +1379,7 @@ def best_prefix else @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3)) end - to(RubyUnits::Unit.new(@@prefix_map.key(best_prefix) + units(false))) + to(RubyUnits::Unit.new(@@prefix_map.key(best_prefix) + units(with_prefix: false))) end # override hash method so objects with same values are considered equal From 4d50e72cbf7de3fa190f97a586aae02ff4104c23 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 27 Nov 2016 19:02:33 -0500 Subject: [PATCH 104/150] more cleanup --- .rubocop_todo.yml | 16 +++++----------- lib/ruby_units/unit.rb | 36 ++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index fff31216..4bff277f 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,15 +1,15 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-11-27 18:43:25 -0500 using RuboCop version 0.45.0. +# on 2016-11-27 18:46:42 -0500 using RuboCop version 0.45.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 -Lint/EmptyWhen: - Exclude: - - 'lib/ruby_units/unit.rb' +# Lint/EmptyWhen: +# Exclude: +# - 'lib/ruby_units/unit.rb' # Offense count: 1 # Cop supports --auto-correct. @@ -42,7 +42,7 @@ Metrics/BlockNesting: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1075 + Max: 1077 # Offense count: 15 Metrics/CyclomaticComplexity: @@ -57,12 +57,6 @@ Metrics/MethodLength: Metrics/PerceivedComplexity: Max: 46 -# Offense count: 6 -# Cop supports --auto-correct. -Style/AlignArray: - Exclude: - - 'lib/ruby_units/unit.rb' - # Offense count: 1 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: nested, compact diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 610d8aa9..dced3324 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1384,13 +1384,15 @@ def best_prefix # override hash method so objects with same values are considered equal def hash - [@scalar, - @numerator, - @denominator, - @base, - @signature, - @base_scalar, - @unit_name].hash + [ + @scalar, + @numerator, + @denominator, + @base, + @signature, + @base_scalar, + @unit_name + ].hash end # Protected and Private Functions that should only be called from this class @@ -1471,10 +1473,7 @@ def parse(passed_unit_string = '0') unit_string = "#{$1} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8 - unit_string.gsub!(/%/, 'percent') - unit_string.gsub!(/'/, 'feet') - unit_string.gsub!(/"/, 'inch') - unit_string.gsub!(/#/, 'pound') + unit_string.gsub!(/[%'"#]/, '%' => 'percent', "'" => 'feet', '"' => 'inch', '#' => 'pound') if defined?(Complex) && unit_string =~ COMPLEX_NUMBER real, imaginary, unit_s = unit_string.scan(COMPLEX_REGEX)[0] @@ -1569,13 +1568,14 @@ def parse(passed_unit_string = '0') @scalar = 1 unless @scalar.is_a? Numeric @scalar = @scalar.to_int if @scalar.to_int == @scalar - case - when bottom_scalar.nil? || bottom_scalar.empty? - when bottom_scalar.to_i == bottom_scalar - @scalar /= bottom_scalar.to_i - else - @scalar /= bottom_scalar.to_f - end + bottom_scalar = 1 if bottom_scalar.nil? || bottom_scalar.empty? + bottom_scalar = if bottom_scalar.to_i == bottom_scalar + bottom_scalar.to_i + else + bottom_scalar.to_f + end + + @scalar /= bottom_scalar @numerator ||= UNITY_ARRAY @denominator ||= UNITY_ARRAY From a3e849ca1818c3a6b39ea0ca438bc05efd31c297 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 27 Nov 2016 19:25:26 -0500 Subject: [PATCH 105/150] formatting --- .rubocop_todo.yml | 72 ++++++------------------------- lib/ruby_units/unit.rb | 96 ++++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 109 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4bff277f..cf33d83e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,39 +1,14 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-11-27 18:46:42 -0500 using RuboCop version 0.45.0. +# on 2016-11-27 19:24:58 -0500 using RuboCop version 0.45.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -# Lint/EmptyWhen: -# Exclude: -# - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AlignWith, SupportedStyles, AutoCorrect. -# SupportedStyles: keyword, variable, start_of_line -Lint/EndAlignment: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. -Lint/UnusedMethodArgument: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -Lint/UselessAssignment: - Exclude: - - 'lib/ruby_units/unit.rb' - # Offense count: 20 Metrics/AbcSize: - Max: 175 + Max: 173 # Offense count: 6 Metrics/BlockNesting: @@ -42,7 +17,7 @@ Metrics/BlockNesting: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1077 + Max: 1078 # Offense count: 15 Metrics/CyclomaticComplexity: @@ -51,11 +26,11 @@ Metrics/CyclomaticComplexity: # Offense count: 24 # Configuration parameters: CountComments. Metrics/MethodLength: - Max: 104 + Max: 101 # Offense count: 14 Metrics/PerceivedComplexity: - Max: 46 + Max: 47 # Offense count: 1 # Configuration parameters: EnforcedStyle, SupportedStyles. @@ -81,25 +56,11 @@ Style/Documentation: - 'lib/ruby_units/string.rb' - 'lib/ruby_units/unit.rb' -# Offense count: 6 +# Offense count: 8 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: leading, trailing -Style/DotPosition: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/ElseAlignment: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 9 -# Cop supports --auto-correct. -Style/EmptyCaseCondition: - Exclude: - - 'lib/ruby_units/unit.rb' +# Style/EmptyCaseCondition: +# Exclude: +# - 'lib/ruby_units/unit.rb' # Offense count: 2 # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts. @@ -111,9 +72,9 @@ Style/FileName: # Offense count: 5 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: for, each -Style/For: - Exclude: - - 'lib/ruby_units/unit.rb' +# Style/For: +# Exclude: +# - 'lib/ruby_units/unit.rb' # Offense count: 6 # Configuration parameters: EnforcedStyle, SupportedStyles. @@ -151,13 +112,6 @@ Style/IndentHash: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Width. -Style/IndentationWidth: - Exclude: - - 'lib/ruby_units/unit.rb' - # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: SupportedStyles. @@ -171,7 +125,7 @@ Style/MultilineIfThen: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 6 +# Offense count: 10 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # SupportedStyles: aligned, indented, indented_relative_to_receiver diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index dced3324..d3ec61d6 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -284,11 +284,10 @@ def self.eliminate_terms(q, n, d) num = [] den = [] - for key, value in combined do - case - when value.positive? + combined.each do |key, value| + if value.positive? value.times { num << key } - when value.negative? + elsif value.negative? value.abs.times { den << key } end end @@ -533,7 +532,7 @@ def initialize(*options) raise ArgumentError, 'Temperatures must not be less than absolute zero' if temperature? && base_scalar.negative? unary_unit = units || '' if options.first.instance_of?(String) - opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) + _opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) unless @@cached_units.keys.include?(opt_units) || (opt_units =~ %r{\D/[\d+\.]+}) || (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) @@ -565,9 +564,11 @@ def to_unit # @return [Boolean] def base? return @base if defined? @base - @base = (@numerator + @denominator).compact.uniq. - map { |unit| RubyUnits::Unit.definition(unit) }. - all? { |element| element.unity? || element.base? } + @base = (@numerator + @denominator) + .compact + .uniq + .map { |unit| RubyUnits::Unit.definition(unit) } + .all? { |element| element.unity? || element.base? } @base end @@ -581,10 +582,9 @@ def to_base return self if base? if @@unit_map[units] =~ /\A<(?:temp|deg)[CRF]>\Z/ @signature = @@kinds.key(:temperature) - base = case - when temperature? + base = if temperature? convert_to('tempK') - when degree? + elsif degree? convert_to('degK') end return base @@ -596,7 +596,7 @@ def to_base num = [] den = [] q = 1 - for unit in @numerator.compact do + @numerator.compact.each do |unit| if @@prefix_values[unit] q *= @@prefix_values[unit] else @@ -605,7 +605,7 @@ def to_base den << @@unit_values[unit][:denominator] if @@unit_values[unit] && @@unit_values[unit][:denominator] end end - for unit in @denominator.compact do + @denominator.compact.each do |unit| if @@prefix_values[unit] q /= @@prefix_values[unit] else @@ -734,14 +734,13 @@ def unitless? # @raise [NoMethodError] when other does not define <=> # @raise [ArgumentError] when units are not compatible def <=>(other) - case - when !base_scalar.respond_to?(:<=>) + if !base_scalar.respond_to?(:<=>) raise NoMethodError, "undefined method `<=>' for #{base_scalar.inspect}" - when other.nil? + elsif other.nil? base_scalar <=> nil - when !temperature? && other.respond_to?(:zero?) && other.zero? + elsif !temperature? && other.respond_to?(:zero?) && other.zero? base_scalar <=> 0 - when other.instance_of?(Unit) + elsif other.instance_of?(Unit) raise ArgumentError, "Incompatible Units ('#{units}' not compatible with '#{other.units}')" unless self =~ other base_scalar <=> other.base_scalar else @@ -759,10 +758,9 @@ def <=>(other) # @param [Object] other # @return [Boolean] def ==(other) - case - when other.respond_to?(:zero?) && other.zero? + if other.respond_to?(:zero?) && other.zero? zero? - when other.instance_of?(Unit) + elsif other.instance_of?(Unit) return false unless self =~ other base_scalar == other.base_scalar else @@ -835,10 +833,9 @@ def ===(other) def +(other) case other when Unit - case - when zero? + if zero? other.dup - when self =~ other + elsif self =~ other raise ArgumentError, 'Cannot add two temperatures' if [self, other].all?(&:temperature?) if [self, other].any?(&:temperature?) if temperature? @@ -870,20 +867,18 @@ def +(other) def -(other) case other when Unit - case - when zero? + if zero? if other.zero? other.dup * -1 # preserve Units class else -other.dup end - when self =~ other - case - when [self, other].all?(&:temperature?) + elsif self =~ other + if [self, other].all?(&:temperature?) RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: KELVIN, denominator: UNITY_ARRAY, signature: @signature).convert_to(temperature_scale) - when temperature? + elsif temperature? RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: [''], denominator: UNITY_ARRAY, signature: @signature).convert_to(self) - when other.temperature? + elsif other.temperature? raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' else @q ||= ((@@cached_units[units].scalar / @@cached_units[units].base_scalar) rescue (units.to_unit.scalar / units.to_unit.to_base.scalar)) @@ -1039,13 +1034,13 @@ def root(n) num = @numerator.dup den = @denominator.dup - for item in @numerator.uniq do + @numerator.uniq.each do |item| x = num.find_all { |i| i == item }.size r = ((x / n) * (n - 1)).to_int r.times { num.delete_at(num.index(item)) } end - for item in @denominator.uniq do + @denominator.uniq.each do |item| x = den.find_all { |i| i == item }.size r = ((x / n) * (n - 1)).to_int r.times { den.delete_at(den.index(item)) } @@ -1171,7 +1166,7 @@ def to_r # Returns string formatted for json # @return [String] - def as_json(*args) + def as_json(*) to_s end @@ -1198,14 +1193,15 @@ def units(with_prefix: true) output_denominator = definitions.map { |element| element.map(&:display_name).join } end - on = output_numerator.uniq. - map { |x| [x, output_numerator.count(x)] }. - map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } - od = output_denominator.uniq. - map { |x| [x, output_denominator.count(x)] }. - map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } - out = "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip - out + on = output_numerator + .uniq + .map { |x| [x, output_numerator.count(x)] } + .map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + od = output_denominator + .uniq + .map { |x| [x, output_denominator.count(x)] } + .map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip end # negates the scalar of the Unit @@ -1375,10 +1371,10 @@ def coerce(other) def best_prefix return to_base if scalar.zero? best_prefix = if kind == :information - @@prefix_values.key(2**((Math.log(base_scalar,2) / 10.0).floor * 10)) - else - @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3)) - end + @@prefix_values.key(2**((Math.log(base_scalar,2) / 10.0).floor * 10)) + else + @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3)) + end to(RubyUnits::Unit.new(@@prefix_map.key(best_prefix) + units(with_prefix: false))) end @@ -1551,11 +1547,11 @@ def parse(passed_unit_string = '0') top.scan(TOP_REGEX).each do |item| n = item[1].to_i x = "#{item[0]} " - case - when n >= 0 + if n >= 0 top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { x * n } - when n.negative? - bottom = "#{bottom} #{x * -n}"; top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '') + elsif n.negative? + bottom = "#{bottom} #{x * -n}" + top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '') end end if bottom From c25868a299403a471c5917342620b1d22bfe09ae Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 28 Nov 2016 08:22:46 -0500 Subject: [PATCH 106/150] add terminal notifier --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index 90a584ab..f364c38c 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ group :development do gem 'jeweler' gem 'pry-byebug', platforms: :mri gem 'guard-rspec' + gem 'terminal-notifier-guard' end group :test do From 925d46e971041da022ed32082c6fd46c0b0f8b19 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 28 Nov 2016 08:28:44 -0500 Subject: [PATCH 107/150] formatting --- .rubocop.yml | 2 + .rubocop_todo.yml | 162 +----------------- Guardfile | 2 +- Rakefile.rb => Rakefile | 0 lib/ruby_units/math.rb | 5 +- lib/ruby_units/unit.rb | 316 +++++++++++++++++------------------ spec/ruby_units/unit_spec.rb | 2 +- 7 files changed, 165 insertions(+), 324 deletions(-) rename Rakefile.rb => Rakefile (100%) diff --git a/.rubocop.yml b/.rubocop.yml index a53ac571..f4cb81ce 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,3 +10,5 @@ Style/FrozenStringLiteralComment: Enabled: false Metrics/LineLength: Enabled: false +Style/SingleLineBlockParams: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cf33d83e..30fb2275 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-11-27 19:24:58 -0500 using RuboCop version 0.45.0. +# on 2016-11-28 15:01:20 -0500 using RuboCop version 0.45.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -10,14 +10,14 @@ Metrics/AbcSize: Max: 173 -# Offense count: 6 +# Offense count: 4 Metrics/BlockNesting: Max: 4 # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1078 + Max: 1060 # Offense count: 15 Metrics/CyclomaticComplexity: @@ -28,9 +28,9 @@ Metrics/CyclomaticComplexity: Metrics/MethodLength: Max: 101 -# Offense count: 14 +# Offense count: 13 Metrics/PerceivedComplexity: - Max: 47 + Max: 48 # Offense count: 1 # Configuration parameters: EnforcedStyle, SupportedStyles. @@ -56,26 +56,12 @@ Style/Documentation: - 'lib/ruby_units/string.rb' - 'lib/ruby_units/unit.rb' -# Offense count: 8 -# Cop supports --auto-correct. -# Style/EmptyCaseCondition: -# Exclude: -# - 'lib/ruby_units/unit.rb' - -# Offense count: 2 +# Offense count: 1 # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts. Style/FileName: Exclude: - - 'Rakefile.rb' - 'lib/ruby-units.rb' -# Offense count: 5 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: for, each -# Style/For: -# Exclude: -# - 'lib/ruby_units/unit.rb' - # Offense count: 6 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: format, sprintf, percent @@ -84,63 +70,6 @@ Style/FormatString: - 'lib/ruby_units/unit.rb' - 'spec/ruby_units/string_spec.rb' -# Offense count: 4 -# Configuration parameters: MinBodyLength. -Style/GuardClause: - Exclude: - - 'lib/ruby_units/math.rb' - - 'lib/ruby_units/unit.rb' - -# Offense count: 2 -Style/IdenticalConditionalBranches: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_brackets -Style/IndentArray: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_braces -Style/IndentHash: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: SupportedStyles. -# SupportedStyles: call, braces -Style/LambdaCall: - EnforcedStyle: braces - -# Offense count: 2 -# Cop supports --auto-correct. -Style/MultilineIfThen: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 10 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: aligned, indented, indented_relative_to_receiver -Style/MultilineMethodCallIndentation: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: aligned, indented -Style/MultilineOperationIndentation: - Exclude: - - 'lib/ruby_units/unit.rb' - # Offense count: 1 # Cop supports --auto-correct. Style/NilComparison: @@ -153,87 +82,8 @@ Style/PerlBackrefs: Exclude: - 'lib/ruby_units/unit.rb' -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: short, verbose -Style/PreferredHashMethods: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -Style/RedundantException: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -Style/RedundantParentheses: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 9 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. -# SupportedStyles: slashes, percent_r, mixed -Style/RegexpLiteral: - Exclude: - - 'lib/ruby_units/unit.rb' - - 'spec/ruby_units/unit_spec.rb' - # Offense count: 9 # Cop supports --auto-correct. Style/RescueModifier: Exclude: - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowAsExpressionSeparator. -Style/Semicolon: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: only_raise, only_fail, semantic -Style/SignalException: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 5 -# Configuration parameters: Methods. -# Methods: {"reduce"=>["acc", "elem"]}, {"inject"=>["acc", "elem"]} -Style/SingleLineBlockParams: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/SpaceAfterComma: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: space, no_space -Style/SpaceInsideStringInterpolation: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. -# SupportedStyles: require_parentheses, require_no_parentheses -Style/TernaryParentheses: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/UnneededInterpolation: - Exclude: - - 'lib/ruby_units/unit.rb' diff --git a/Guardfile b/Guardfile index d8edab3f..ff332898 100644 --- a/Guardfile +++ b/Guardfile @@ -26,6 +26,6 @@ guard :rspec, cmd: 'bundle exec rspec' do rspec.spec_helper = 'spec/spec_helper.rb' watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.(m[1]) } + watch(%r{^lib/(.+)\.rb$}) { |m| rspec.spec.call(m[1]) } watch(rspec.spec_helper) { rspec.spec_dir } end diff --git a/Rakefile.rb b/Rakefile similarity index 100% rename from Rakefile.rb rename to Rakefile diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index bced95e9..07d6e157 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -113,9 +113,8 @@ def hypot(x, y) alias unit_atan2 atan2 # @return [Numeric] def atan2(x, y) - if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x !~ y) - raise ArgumentError, 'Incompatible RubyUnits::Units' - elsif (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && (x =~ y) + raise ArgumentError, 'Incompatible RubyUnits::Units' if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && !x.compatible?(y) + if (x.is_a?(RubyUnits::Unit) && y.is_a?(RubyUnits::Unit)) && x.compatible?(y) Math.unit_atan2(x.base_scalar, y.base_scalar) else Math.unit_atan2(x, y) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index d3ec61d6..6b68ec6b 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -47,11 +47,11 @@ class Unit < Numeric STONE_LB_UNIT_REGEX = /(?:sts?|stones?)+[\s,]*(\d+)\s*(?:#|lbs?|pounds?|pound-mass)*/ STONE_LB_REGEX = /(\d+)\s*#{STONE_LB_UNIT_REGEX}/ TIME_REGEX = /(\d+)*:(\d+)*:*(\d+)*[:,]*(\d+)*/ - SCI_NUMBER = %r{([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)} - RATIONAL_NUMBER = /\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?/ + SCI_NUMBER = /([+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*)/ + RATIONAL_NUMBER = %r{\(?([+-])?(\d+[ -])?(\d+)\/(\d+)\)?} COMPLEX_NUMBER = /#{SCI_NUMBER}?#{SCI_NUMBER}i\b/ NUMBER_REGEX = /#{SCI_NUMBER}*\s*(.+)?/ - UNIT_STRING_REGEX = /#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*/ + UNIT_STRING_REGEX = %r{#{SCI_NUMBER}*\s*([^\/]*)\/*(.+)*} TOP_REGEX = /([^ \*]+)(?:\^|\*\*)([\d-]+)/ BOTTOM_REGEX = /([^* ]+)(?:\^|\*\*)(\d+)/ NUMBER_UNIT_REGEX = /#{SCI_NUMBER}?(.*)/ @@ -62,67 +62,67 @@ class Unit < Numeric RANKINE = [''].freeze CELSIUS = [''].freeze @@temp_regex = nil - SIGNATURE_VECTOR = [ - :length, - :time, - :temperature, - :mass, - :current, - :substance, - :luminosity, - :currency, - :information, - :angle - ].freeze + SIGNATURE_VECTOR = %i( + length + time + temperature + mass + current + substance + luminosity + currency + information + angle + ).freeze @@kinds = { - -312_078 => :elastance, - -312_058 => :resistance, - -312_038 => :inductance, - -152_040 => :magnetism, - -152_038 => :magnetism, - -152_058 => :potential, - -7997 => :specific_volume, - -79 => :snap, - -59 => :jolt, - -39 => :acceleration, - -38 => :radiation, - -20 => :frequency, - -19 => :speed, - -18 => :viscosity, - -17 => :volumetric_flow, - -1 => :wavenumber, - 0 => :unitless, - 1 => :length, - 2 => :area, - 3 => :volume, - 20 => :time, - 400 => :temperature, - 7941 => :yank, - 7942 => :power, - 7959 => :pressure, - 7962 => :energy, - 7979 => :viscosity, - 7961 => :force, - 7981 => :momentum, - 7982 => :angular_momentum, - 7997 => :density, - 7998 => :area_density, - 8000 => :mass, - 152_020 => :radiation_exposure, - 159_999 => :magnetism, - 160_000 => :current, - 160_020 => :charge, - 312_058 => :conductance, - 312_078 => :capacitance, - 3_199_980 => :activity, - 3_199_997 => :molar_concentration, - 3_200_000 => :substance, - 63_999_998 => :illuminance, - 64_000_000 => :luminous_power, - 1_280_000_000 => :currency, - 25_600_000_000 => :information, - 511_999_999_980 => :angular_velocity, - 512_000_000_000 => :angle + -312_078 => :elastance, + -312_058 => :resistance, + -312_038 => :inductance, + -152_040 => :magnetism, + -152_038 => :magnetism, + -152_058 => :potential, + -7997 => :specific_volume, + -79 => :snap, + -59 => :jolt, + -39 => :acceleration, + -38 => :radiation, + -20 => :frequency, + -19 => :speed, + -18 => :viscosity, + -17 => :volumetric_flow, + -1 => :wavenumber, + 0 => :unitless, + 1 => :length, + 2 => :area, + 3 => :volume, + 20 => :time, + 400 => :temperature, + 7941 => :yank, + 7942 => :power, + 7959 => :pressure, + 7962 => :energy, + 7979 => :viscosity, + 7961 => :force, + 7981 => :momentum, + 7982 => :angular_momentum, + 7997 => :density, + 7998 => :area_density, + 8000 => :mass, + 152_020 => :radiation_exposure, + 159_999 => :magnetism, + 160_000 => :current, + 160_020 => :charge, + 312_058 => :conductance, + 312_078 => :capacitance, + 3_199_980 => :activity, + 3_199_997 => :molar_concentration, + 3_200_000 => :substance, + 63_999_998 => :illuminance, + 64_000_000 => :luminous_power, + 1_280_000_000 => :currency, + 25_600_000_000 => :information, + 511_999_999_980 => :angular_velocity, + 512_000_000_000 => :angle }.freeze @@cached_units = {} @@base_unit_cache = {} @@ -160,7 +160,7 @@ def self.defined?(unit) # @param [String] unit # @return [RubyUnits::Unit::Definition, nil] def self.definition(unit_name) - unit = (unit_name =~ /^<.+>$/) ? unit_name : "<#{unit_name}>" + unit = unit_name =~ /^<.+>$/ ? unit_name : "<#{unit_name}>" @@definitions[unit] end @@ -201,7 +201,7 @@ def self.define(unit_definition, &block) # @return (see RubyUnits::Unit.define) # Get the definition for a unit and allow it to be redefined def self.redefine!(name) - fail ArgumentError, 'A block is required to redefine a unit' unless block_given? + raise ArgumentError, 'A block is required to redefine a unit' unless block_given? unit_definition = definition(name) yield unit_definition @@definitions.delete("<#{name}>") @@ -259,7 +259,7 @@ def self.eliminate_terms(q, n, d) i = 0 loop do break if i > num.size - if @@prefix_values.has_key? num[i] + if @@prefix_values.key? num[i] k = [num[i], num[i + 1]] i += 2 else @@ -272,7 +272,7 @@ def self.eliminate_terms(q, n, d) j = 0 loop do break if j > den.size - if @@prefix_values.has_key? den[j] + if @@prefix_values.key? den[j] k = [den[j], den[j + 1]] j += 2 else @@ -308,12 +308,12 @@ def self.base_units # @return [Array] consisting of [Numeric, "unit"] def self.parse_into_numbers_and_units(string) # scientific notation.... 123.234E22, -123.456e-10 - sci = %r{[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*} + sci = /[+-]?\d*[.]?\d+(?:[Ee][+-]?)?\d*/ # rational numbers.... -1/3, 1/5, 20/100, -6 1/2, -6-1/2 rational = %r{\(?[+-]?(?:\d+[ -])?\d+\/\d+\)?} # complex numbers... -1.2+3i, +1.2-3.3i - complex = %r{#{sci}{2,2}i} - anynumber = %r{(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?} + complex = /#{sci}{2,2}i/ + anynumber = /(?:(#{complex}|#{rational}|#{sci}))?\s?([^-\d\.].*)?/ num, unit = string.scan(anynumber).first @@ -332,9 +332,9 @@ def self.parse_into_numbers_and_units(string) when rational # if it has whitespace, it will be of the form '6 1/2' if num =~ RATIONAL_NUMBER - sign = ($1 == '-') ? -1 : 1 + sign = $1 == '-' ? -1 : 1 n = $2.to_i - f = Rational($3.to_i,$4.to_i) + f = Rational($3.to_i, $4.to_i) sign * (n + f) else Rational(*num.split('/').map(&:to_i)) @@ -367,15 +367,15 @@ def self.prefix_regex end def self.temp_regex - @@temp_regex ||= Regexp.new "(?:#{ - temp_units = %w(tempK tempC tempF tempR degK degC degF degR) - aliases = temp_units.map do |unit| - d = RubyUnits::Unit.definition(unit) - d && d.aliases - end.flatten.compact - regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') - regex_str - })" + @@temp_regex ||= begin + temp_units = %w(tempK tempC tempF tempR degK degC degF degR) + aliases = temp_units.map do |unit| + d = RubyUnits::Unit.definition(unit) + d && d.aliases + end.flatten.compact + regex_str = aliases.empty? ? '(?!x)x' : aliases.join('|') + Regexp.new "(?:#{regex_str})" + end end # inject a definition into the internal array and set it up for use @@ -533,13 +533,13 @@ def initialize(*options) unary_unit = units || '' if options.first.instance_of?(String) _opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) - unless @@cached_units.keys.include?(opt_units) || - (opt_units =~ %r{\D/[\d+\.]+}) || - (opt_units =~ /(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-/) + unless @@cached_units.keys.include?(opt_units) || + (opt_units =~ %r{\D/[\d+\.]+}) || + (opt_units =~ %r{(#{RubyUnits::Unit.temp_regex})|(#{STONE_LB_UNIT_REGEX})|(#{LBS_OZ_UNIT_REGEX})|(#{FEET_INCH_UNITS_REGEX})|%|(#{TIME_REGEX})|i\s?(.+)?|±|\+\/-}) @@cached_units[opt_units] = (scalar == 1 ? self : opt_units.to_unit) if opt_units && !opt_units.empty? end end - unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) then + unless @@cached_units.keys.include?(unary_unit) || (unary_unit =~ /#{RubyUnits::Unit.temp_regex}/) @@cached_units[unary_unit] = (scalar == 1 ? self : unary_unit.to_unit) end [@scalar, @numerator, @denominator, @base_scalar, @signature, @base].each(&:freeze) @@ -565,10 +565,10 @@ def to_unit def base? return @base if defined? @base @base = (@numerator + @denominator) - .compact - .uniq - .map { |unit| RubyUnits::Unit.definition(unit) } - .all? { |element| element.unity? || element.base? } + .compact + .uniq + .map { |unit| RubyUnits::Unit.definition(unit) } + .all? { |element| element.unity? || element.base? } @base end @@ -642,49 +642,46 @@ def to_base # @return [String] def to_s(target_units = nil) out = @output[target_units] - if out - return out - else - case target_units - when :ft - inches = convert_to('in').scalar.to_int - out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" - when :lbs - ounces = convert_to('oz').scalar.to_int - out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" - when :stone - pounds = convert_to('lbs').scalar.to_int - out = "#{(pounds / 14).truncate} stone, #{(pounds % 14).round} lb" - when String - out = case target_units.strip - when /\A\s*\Z/ # whitespace only - '' - when /(%[\-+\.\w#]+)\s*(.+)*/ # format string like '%0.2f in' - begin - if $2 # unit specified, need to convert - convert_to($2).to_s($1) - else - "#{$1 % @scalar} #{$2 || units}".strip - end - rescue # parse it like a strftime format string - (DateTime.new(0) + self).strftime(target_units) + return out if out + case target_units + when :ft + inches = convert_to('in').scalar.to_int + out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" + when :lbs + ounces = convert_to('oz').scalar.to_int + out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" + when :stone + pounds = convert_to('lbs').scalar.to_int + out = "#{(pounds / 14).truncate} stone, #{(pounds % 14).round} lb" + when String + out = case target_units.strip + when /\A\s*\Z/ # whitespace only + '' + when /(%[\-+\.\w#]+)\s*(.+)*/ # format string like '%0.2f in' + begin + if $2 # unit specified, need to convert + convert_to($2).to_s($1) + else + "#{$1 % @scalar} #{$2 || units}".strip end - when /(\S+)/ # unit only 'mm' or '1/mm' - convert_to($1).to_s - else - raise 'unhandled case' + rescue # parse it like a strftime format string + (DateTime.new(0) + self).strftime(target_units) end - else - out = case @scalar - when Rational, Complex - "#{@scalar} #{units}" - else - "#{'%g' % @scalar} #{units}" - end.strip - end - @output[target_units] = out - return out + when /(\S+)/ # unit only 'mm' or '1/mm' + convert_to($1).to_s + else + raise 'unhandled case' + end + else + out = case @scalar + when Rational, Complex + "#{@scalar} #{units}" + else + "#{'%g' % @scalar} #{units}" + end.strip end + @output[target_units] = out + out end # Normally pretty prints the unit, but if you really want to see the guts of it, pass ':dump' @@ -699,7 +696,7 @@ def inspect(dump = nil) # @return [Boolean] # @todo use unit definition to determine if it's a temperature instead of a regex def temperature? - degree? && (!(@@unit_map[units] =~ /temp[CFRK]/).nil?) + degree? && !(@@unit_map[units] =~ /temp[CFRK]/).nil? end alias is_temperature? temperature? @@ -734,9 +731,8 @@ def unitless? # @raise [NoMethodError] when other does not define <=> # @raise [ArgumentError] when units are not compatible def <=>(other) - if !base_scalar.respond_to?(:<=>) - raise NoMethodError, "undefined method `<=>' for #{base_scalar.inspect}" - elsif other.nil? + raise NoMethodError, "undefined method `<=>' for #{base_scalar.inspect}" unless base_scalar.respond_to?(:<=>) + if other.nil? base_scalar <=> nil elsif !temperature? && other.respond_to?(:zero?) && other.zero? base_scalar <=> 0 @@ -944,11 +940,8 @@ def /(other) # @return [Array] def divmod(other) raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" unless self =~ other - if units == other.units - return scalar.divmod(other.scalar) - else - return to_base.scalar.divmod(other.to_base.scalar) - end + return scalar.divmod(other.scalar) if units == other.units + to_base.scalar.divmod(other.to_base.scalar) end # perform a modulo on a unit, will raise an exception if the units are not compatible @@ -985,7 +978,7 @@ def **(other) when Integer return power(other) when Float - return self**(other.to_i) if other == other.to_i + 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 return root((1 / other).to_int) @@ -1007,11 +1000,8 @@ def power(n) return inverse if n == -1 return 1 if n.zero? return self if n == 1 - if n.positive? then - return (1..(n - 1).to_i).inject(self) { |product, _| product * self } - else - return (1..-(n - 1).to_i).inject(self) { |product, _| product / self } - end + return (1..(n - 1).to_i).inject(self) { |acc, _elem| acc * self } if n.positive? + (1..-(n - 1).to_i).inject(self) { |acc, _elem| acc / self } end # Calculates the n-th root of a unit @@ -1045,7 +1035,7 @@ def root(n) r = ((x / n) * (n - 1)).to_int r.times { den.delete_at(den.index(item)) } end - q = @scalar.negative? ? (-1)**Rational(1, n) * (@scalar.abs)**Rational(1, n) : @scalar**Rational(1, n) + q = @scalar.negative? ? -1**Rational(1, n) * @scalar.abs**Rational(1, n) : @scalar**Rational(1, n) RubyUnits::Unit.new(scalar: q, numerator: num, denominator: den) end @@ -1121,8 +1111,8 @@ def convert_to(other) numerator2 = target.numerator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact denominator2 = target.denominator.map { |x| @@prefix_values[x] ? @@prefix_values[x] : x }.map { |x| x.is_a?(Numeric) ? x : @@unit_values[x][:scalar] }.compact - q = @scalar * ((numerator1 + denominator2).inject(1) { |product, n| product * n }) / - ((numerator2 + denominator1).inject(1) { |product, n| product * n }) + q = @scalar * ((numerator1 + denominator2).inject(1) { |acc, elem| acc * elem }) / + ((numerator2 + denominator1).inject(1) { |acc, elem| acc * elem }) return RubyUnits::Unit.new(scalar: q, numerator: target.numerator, denominator: target.denominator, signature: target.signature) end end @@ -1135,7 +1125,7 @@ def convert_to(other) # @raise [RuntimeError] when not unitless def to_f return @scalar.to_f if unitless? - raise RuntimeError, "Cannot convert '#{self}' to Float unless unitless. Use Unit#scalar" + raise "Cannot convert '#{self}' to Float unless unitless. Use Unit#scalar" end # converts the unit back to a complex if it is unitless. Otherwise raises an exception @@ -1143,7 +1133,7 @@ def to_f # @raise [RuntimeError] when not unitless def to_c return Complex(@scalar) if unitless? - raise RuntimeError, "Cannot convert '#{self}' to Complex unless unitless. Use Unit#scalar" + raise "Cannot convert '#{self}' to Complex unless unitless. Use Unit#scalar" end # if unitless, returns an int, otherwise raises an error @@ -1151,7 +1141,7 @@ def to_c # @raise [RuntimeError] when not unitless def to_i return @scalar.to_int if unitless? - raise RuntimeError, "Cannot convert '#{self}' to Integer unless unitless. Use Unit#scalar" + raise "Cannot convert '#{self}' to Integer unless unitless. Use Unit#scalar" end alias to_int to_i @@ -1161,7 +1151,7 @@ def to_i # @raise [RuntimeError] when not unitless def to_r return @scalar.to_r if unitless? - raise RuntimeError, "Cannot convert '#{self}' to Rational unless unitless. Use Unit#scalar" + raise "Cannot convert '#{self}' to Rational unless unitless. Use Unit#scalar" end # Returns string formatted for json @@ -1194,13 +1184,13 @@ def units(with_prefix: true) end on = output_numerator - .uniq - .map { |x| [x, output_numerator.count(x)] } - .map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + .uniq + .map { |x| [x, output_numerator.count(x)] } + .map { |element, power| (element.to_s.strip + (power > 1 ? "^#{power}" : '')) } od = output_denominator - .uniq - .map { |x| [x, output_denominator.count(x)] } - .map { |element, power| ("#{element}".strip + (power > 1 ? "^#{power}" : '')) } + .uniq + .map { |x| [x, output_denominator.count(x)] } + .map { |element, power| (element.to_s.strip + (power > 1 ? "^#{power}" : '')) } "#{on.join('*')}#{od.empty? ? '' : '/' + od.join('*')}".strip end @@ -1319,7 +1309,7 @@ def since(time_point) when DateTime, Date (DateTime.now - time_point).to_unit('d').convert_to(self) else - fail ArgumentError, 'Must specify a Time, Date, or DateTime' + raise ArgumentError, 'Must specify a Time, Date, or DateTime' end end @@ -1333,7 +1323,7 @@ def until(time_point) when DateTime, Date (time_point - DateTime.now).to_unit('d').convert_to(self) else - fail ArgumentError, 'Must specify a Time, Date, or DateTime' + raise ArgumentError, 'Must specify a Time, Date, or DateTime' end end @@ -1371,7 +1361,7 @@ def coerce(other) def best_prefix return to_base if scalar.zero? best_prefix = if kind == :information - @@prefix_values.key(2**((Math.log(base_scalar,2) / 10.0).floor * 10)) + @@prefix_values.key(2**((Math.log(base_scalar, 2) / 10.0).floor * 10)) else @@prefix_values.key(10**((Math.log10(base_scalar) / 3.0).floor * 3)) end @@ -1447,7 +1437,7 @@ def unit_signature return @signature unless @signature.nil? vector = unit_signature_vector vector.each_with_index { |item, index| vector[index] = item * 20**index } - @signature = vector.inject(0) { |sum, n| sum + n } + @signature = vector.inject(0) { |acc, elem| acc + elem } @signature end @@ -1480,7 +1470,7 @@ def parse(passed_unit_string = '0') if defined?(Rational) && unit_string =~ RATIONAL_NUMBER sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] - sign = (sign == '-') ? -1 : 1 + sign = sign == '-' ? -1 : 1 rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i)) result = RubyUnits::Unit.new(unit_s || '1') * rational copy(result) @@ -1580,7 +1570,7 @@ def parse(passed_unit_string = '0') # eliminate all known terms from this string. This is a quick check to see if the passed unit # contains terms that are not defined. - used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(/[\d\*, "'_^\/\$]/, '') + used = "#{top} #{bottom}".to_s.gsub(RubyUnits::Unit.unit_match_regex, '').gsub(%r{[\d\*, "'_^\/\$]}, '') raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") unless used.empty? @numerator = @numerator.map do |item| diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index 3d5071c3..baa91825 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -1316,7 +1316,7 @@ describe '#to_yaml' do subject { super().to_yaml } - it { is_expected.to match(/--- !ruby\/object:RubyUnits::Unit/) } + it { is_expected.to match(%r{--- !ruby\/object:RubyUnits::Unit}) } end end From 234db8243fa0ab946e5ee61245d9e3ba32fe6570 Mon Sep 17 00:00:00 2001 From: Kunal Shah Date: Thu, 1 Dec 2016 00:57:46 -0500 Subject: [PATCH 108/150] Throw an error if the Unit definition isn't found (#147) --- lib/ruby_units/unit.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 6b68ec6b..8068b270 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -203,6 +203,7 @@ def self.define(unit_definition, &block) def self.redefine!(name) raise ArgumentError, 'A block is required to redefine a unit' unless block_given? unit_definition = definition(name) + raise(ArgumentError, "'#{name}' Unit not recognized") unless unit_definition yield unit_definition @@definitions.delete("<#{name}>") define(unit_definition) From 8c4821af331dcd40b47a3c4ed19553aec88f85e5 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 14:30:17 -0500 Subject: [PATCH 109/150] Ruby 2.4.0 (#148) * update build tools to check ruby 2.4.0 * clean up usage of some newer methods for compatibility with older ruby versions * add notes to readme * ensure we are using jruby that emulates a ruby 2.* series * workaround for jruby bug (see https://github.com/jruby/jruby/issues/4410) --- .rubocop.yml | 2 +- .rubocop_todo.yml | 8 +++---- .ruby-version | 2 +- .travis.yml | 3 ++- Gemfile | 5 +++-- README.md | 20 ++++++++++++++++- lib/ruby_units/math.rb | 2 +- lib/ruby_units/unit.rb | 51 +++++++++++++++++++++++++++++++----------- 8 files changed, 69 insertions(+), 24 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index f4cb81ce..c83e5d7d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,6 @@ inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 2.3 + TargetRubyVersion: 2.2 Exclude: - ruby-units.gemspec - bin/* diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 30fb2275..859f9cf8 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-11-28 15:01:20 -0500 using RuboCop version 0.45.0. +# on 2016-12-26 14:41:04 -0500 using RuboCop version 0.46.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -8,7 +8,7 @@ # Offense count: 20 Metrics/AbcSize: - Max: 173 + Max: 171 # Offense count: 4 Metrics/BlockNesting: @@ -17,7 +17,7 @@ Metrics/BlockNesting: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1060 + Max: 1080 # Offense count: 15 Metrics/CyclomaticComplexity: @@ -28,7 +28,7 @@ Metrics/CyclomaticComplexity: Metrics/MethodLength: Max: 101 -# Offense count: 13 +# Offense count: 12 Metrics/PerceivedComplexity: Max: 48 diff --git a/.ruby-version b/.ruby-version index 0bee604d..197c4d5c 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.3 +2.4.0 diff --git a/.travis.yml b/.travis.yml index 7d2a28f4..70cdeaca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,11 @@ sudo: false language: ruby rvm: + - 2.4.0 - 2.3.3 - 2.2.6 - 2.1.10 - ruby-head - - jruby + - jruby-9.1.6.0 script: bundle exec rake --trace bundler_args: --without development diff --git a/Gemfile b/Gemfile index f364c38c..6a2db6d6 100644 --- a/Gemfile +++ b/Gemfile @@ -2,15 +2,16 @@ source 'https://rubygems.org' group :development do gem 'bundler', '~> 1.0' + gem 'guard-rspec' gem 'jeweler' + gem 'pry' gem 'pry-byebug', platforms: :mri - gem 'guard-rspec' gem 'terminal-notifier-guard' end group :test do gem 'rake' + gem 'rspec' gem 'simplecov' gem 'simplecov-html' - gem 'rspec' end diff --git a/README.md b/README.md index 7d59da43..d1d909ba 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ end ### Namespaced Class -Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatiblity, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. +Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatibility, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. To load ruby-units without this alias... @@ -245,3 +245,21 @@ gem 'ruby-units', require: 'ruby_units/namespaced' ``` Note: when using the namespaced version, the Unit.new('unit string') helper will not be defined. + +### NOTES + +#### Mathn + +Note that the current implementation of ruby-units requires 'mathn' from the ruby standard library. +This tends to change the behavior of integer math in ways that many people do not expect, and can be the source +of numerous bugs and odd behaviors. If you encounter what appears to be a bug in your code that seems to be related +to the use of ruby-units, try to reproduce the bug by just including 'mathn' by itself. + +If you identify a bug in a gem or code that uses mathn, please file a bug report or create a pull request to fix it. + +#### Performance vs. Accuracy + +Ruby units was originally intended to provide a robust and accurate way to do arbitrary unit conversions. +In some cases, these conversions can result in the creation and garbage collection of a lot of intermediate objects during +calculations. This in turn can have a negative impact on performance. The design of ruby-units has emphasized accuracy +over speed. YMMV if you are doing a lot of math involving units. diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index 07d6e157..3f3cf90c 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -6,7 +6,7 @@ module Math alias unit_sqrt sqrt # @return [Numeric] def sqrt(n) - if RubyUnits::Unit === n + if n.is_a?(RubyUnits::Unit) (n**Rational(1, 2)).to_unit else unit_sqrt(n) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 8068b270..9bc891d0 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -286,9 +286,9 @@ def self.eliminate_terms(q, n, d) num = [] den = [] combined.each do |key, value| - if value.positive? + if value >= 0 value.times { num << key } - elsif value.negative? + elsif value < 0 value.abs.times { den << key } end end @@ -530,7 +530,7 @@ def initialize(*options) raise ArgumentError, 'Invalid Unit Format' end update_base_scalar - raise ArgumentError, 'Temperatures must not be less than absolute zero' if temperature? && base_scalar.negative? + raise ArgumentError, 'Temperatures must not be less than absolute zero' if temperature? && base_scalar < 0 unary_unit = units || '' if options.first.instance_of?(String) _opt_scalar, opt_units = RubyUnits::Unit.parse_into_numbers_and_units(options[0]) @@ -1001,7 +1001,7 @@ def power(n) return inverse if n == -1 return 1 if n.zero? return self if n == 1 - return (1..(n - 1).to_i).inject(self) { |acc, _elem| acc * self } if n.positive? + return (1..(n - 1).to_i).inject(self) { |acc, _elem| acc * self } if n >= 0 (1..-(n - 1).to_i).inject(self) { |acc, _elem| acc / self } end @@ -1017,7 +1017,7 @@ def root(n) raise ArgumentError, 'Exponent must an Integer' unless n.is_a?(Integer) raise ArgumentError, '0th root undefined' if n.zero? return self if n == 1 - return root(n.abs).inverse if n.negative? + return root(n.abs).inverse if n < 0 vec = unit_signature_vector vec = vec.map { |x| x % n } @@ -1036,8 +1036,7 @@ def root(n) r = ((x / n) * (n - 1)).to_int r.times { den.delete_at(den.index(item)) } end - q = @scalar.negative? ? -1**Rational(1, n) * @scalar.abs**Rational(1, n) : @scalar**Rational(1, n) - RubyUnits::Unit.new(scalar: q, numerator: num, denominator: den) + RubyUnits::Unit.new(scalar: @scalar**Rational(1, n), numerator: num, denominator: den) end # returns inverse of Unit (1/unit) @@ -1170,17 +1169,43 @@ def units(with_prefix: true) num = @numerator.clone.compact den = @denominator.clone.compact - unless @numerator == UNITY_ARRAY + unless num == UNITY_ARRAY definitions = num.map { |element| RubyUnits::Unit.definition(element) } definitions.reject!(&:prefix?) unless with_prefix - definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a + # there is a bug in jruby 9.1.6.0's implementation of chunk_while + # see https://github.com/jruby/jruby/issues/4410 + # TODO: fix this after jruby fixes their bug. + definitions = if definitions.respond_to?(:chunk_while) && RUBY_ENGINE != 'jruby' + definitions.chunk_while { |defn, _| defn.prefix? }.to_a + else # chunk_while is new to ruby 2.3+, so fallback to less efficient methods for older ruby + result = [] + enumerator = definitions.to_enum + loop do + first = enumerator.next + result << (first.prefix? ? [first, enumerator.next] : [first]) + end + result + end output_numerator = definitions.map { |element| element.map(&:display_name).join } end - unless @denominator == UNITY_ARRAY + unless den == UNITY_ARRAY definitions = den.map { |element| RubyUnits::Unit.definition(element) } definitions.reject!(&:prefix?) unless with_prefix - definitions = definitions.chunk_while { |defn, _| defn.prefix? }.to_a + # there is a bug in jruby 9.1.6.0's implementation of chunk_while + # see https://github.com/jruby/jruby/issues/4410 + # TODO: fix this after jruby fixes their bug. + definitions = if definitions.respond_to?(:chunk_while) && RUBY_ENGINE != 'jruby' + definitions.chunk_while { |defn, _| defn.prefix? }.to_a + else # chunk_while is new to ruby 2.3+, so fallback to less efficient methods for older ruby + result = [] + enumerator = definitions.to_enum + loop do + first = enumerator.next + result << (first.prefix? ? [first, enumerator.next] : [first]) + end + result + end output_denominator = definitions.map { |element| element.map(&:display_name).join } end @@ -1533,14 +1558,14 @@ def parse(passed_unit_string = '0') # more than one per. I.e., "1 m/s/s" raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.count('/') > 1 - raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string.scan(/\s[02-9]/).size.positive? + raise(ArgumentError, "'#{passed_unit_string}' Unit not recognized") if unit_string =~ /\s[02-9]/ @scalar, top, bottom = unit_string.scan(UNIT_STRING_REGEX)[0] # parse the string into parts top.scan(TOP_REGEX).each do |item| n = item[1].to_i x = "#{item[0]} " if n >= 0 top.gsub!(/#{item[0]}(\^|\*\*)#{n}/) { x * n } - elsif n.negative? + elsif n < 0 bottom = "#{bottom} #{x * -n}" top.gsub!(/#{item[0]}(\^|\*\*)#{n}/, '') end From baf96b9310bf75276e7926c7b05a4ba7f647fbfa Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 16:12:58 -0500 Subject: [PATCH 110/150] add comments about .units and .scalar (fixes #120) --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d1d909ba..82cd7d98 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Unit.new('1.5 mm').to_s("%0.2f") # "1.50 mm". Enter any valid format Unit.new('1.5 mm').to_s("in") # converts to inches before printing Unit.new("2 m").to_s(:ft) # returns 6'7" Unit.new("100 kg").to_s(:lbs) # returns 220 lbs, 7 oz +Unit.new("100 kg").to_s(:stone) # returns 15 stone, 10 lb ``` Time Helpers @@ -228,6 +229,18 @@ Unit.redefine!("cup") do |cup| end ``` +### Useful methods + +1. `scalar` will return the numeric portion of the unit without the attached units +2. `base_scalar` will return the scalar in base units (SI) +3. `units` will return the name of the units (without the scalar) +4. `base` will return the unit converted to base units (SI) + +### Storing in a database + +Units can be stored in a database as either the string representation or in two separate columns defining the scalar and the units. +Note that if sorting by units is desired you will want to ensure that you are storing the scalars in a consistent unit (i.e, the base units). + ### Namespaced Class Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatibility, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. @@ -262,4 +275,4 @@ If you identify a bug in a gem or code that uses mathn, please file a bug report Ruby units was originally intended to provide a robust and accurate way to do arbitrary unit conversions. In some cases, these conversions can result in the creation and garbage collection of a lot of intermediate objects during calculations. This in turn can have a negative impact on performance. The design of ruby-units has emphasized accuracy -over speed. YMMV if you are doing a lot of math involving units. +over speed. YMMV if you are doing a lot of math involving units. From 6ecf4ea4677e7963bb82aed18acfa7c32001fac2 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 16:18:46 -0500 Subject: [PATCH 111/150] redefine 'grad' to 'gon' (fixes #105) --- CHANGELOG.txt | 1 + lib/ruby_units/unit_definitions/standard.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 40d9e09a..e73ccf6e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,6 @@ Change Log for Ruby-units ========================= + * Fix issue #105 -- change 'grad' to 'gon' 2015-11-07 2.0.0 * remove support for ruby versions less than 2.0 * remove `.unit` and `.u` from String * remove `.unit` from Date diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 1bde4ad5..1c4dbf90 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -588,9 +588,9 @@ deg.aliases = %w(deg degree degrees) end -RubyUnits::Unit.define('grad') do |grad| +RubyUnits::Unit.define('gon') do |grad| grad.definition = RubyUnits::Unit.new(Math::PI / 200.0, 'radian') - grad.aliases = %w(grad gradian grads) + grad.aliases = %w(gon grad gradian grads) end # rotation From a04590c160df6448f133c7de26daec2d735490b6 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 16:58:05 -0500 Subject: [PATCH 112/150] Allow configuration of optional separator on output. (#149) --- CHANGELOG.txt | 2 ++ README.md | 16 +++++++++++ lib/ruby_units/configuration.rb | 41 +++++++++++++++++++++++++++ lib/ruby_units/namespaced.rb | 1 + lib/ruby_units/unit.rb | 11 +++---- spec/ruby_units/configuration_spec.rb | 28 ++++++++++++++++++ 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 lib/ruby_units/configuration.rb create mode 100644 spec/ruby_units/configuration_spec.rb diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e73ccf6e..454e8747 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,7 @@ Change Log for Ruby-units ========================= +2016-12-28 2.1.0 * add support for ruby 2.4.0 + * allow configuration for optional separator on output * Fix issue #105 -- change 'grad' to 'gon' 2015-11-07 2.0.0 * remove support for ruby versions less than 2.0 * remove `.unit` and `.u` from String diff --git a/README.md b/README.md index 82cd7d98..c35fec11 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,21 @@ gem 'ruby-units', require: 'ruby_units/namespaced' Note: when using the namespaced version, the Unit.new('unit string') helper will not be defined. +### Configuration + +Configuration options can be set like: + +``` +RubyUnits.configure do |config| + config.separator = false +end +``` + +Currently there is only one configuration you can set: + +1. separator (true/false): should a space be used to separate the scalar from the unit part during output. + + ### NOTES #### Mathn @@ -266,6 +281,7 @@ Note: when using the namespaced version, the Unit.new('unit string') helper will Note that the current implementation of ruby-units requires 'mathn' from the ruby standard library. This tends to change the behavior of integer math in ways that many people do not expect, and can be the source of numerous bugs and odd behaviors. If you encounter what appears to be a bug in your code that seems to be related + to the use of ruby-units, try to reproduce the bug by just including 'mathn' by itself. If you identify a bug in a gem or code that uses mathn, please file a bug report or create a pull request to fix it. diff --git a/lib/ruby_units/configuration.rb b/lib/ruby_units/configuration.rb new file mode 100644 index 00000000..43ec328d --- /dev/null +++ b/lib/ruby_units/configuration.rb @@ -0,0 +1,41 @@ +# allow for optional configuration of RubyUnits +# +# Usage: +# +# RubyUnits.configure do |config| +# config.separator = false +# end +module RubyUnits + class << self + attr_writer :configuration + end + + def self.configuration + @configuration ||= Configuration.new + end + + def self.reset + @configuration = Configuration.new + end + + def self.configure + yield configuration + end + + # holds actual configuration values for RubyUnits + class Configuration + # used to separate the scalar from the unit when generating output. + # set to nil to prevent adding a space to the string representation of a unit + # separators other than ' ' and '' may work, but you may encounter problems + attr_reader :separator + + def initialize + self.separator = true + end + + def separator=(value) + raise ArgumentError, "configuration 'separator' may only be true or false" unless value.class == TrueClass || value.class == FalseClass + @separator = value ? ' ' : nil + end + end +end diff --git a/lib/ruby_units/namespaced.rb b/lib/ruby_units/namespaced.rb index 34b75412..0509d845 100644 --- a/lib/ruby_units/namespaced.rb +++ b/lib/ruby_units/namespaced.rb @@ -3,6 +3,7 @@ # require_relative this file to avoid creating an class alias from Unit to RubyUnits::Unit require_relative 'version' +require_relative 'configuration' require_relative 'definition' require_relative 'cache' require_relative 'array' diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 9bc891d0..a45fc733 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -644,16 +644,17 @@ def to_base def to_s(target_units = nil) out = @output[target_units] return out if out + separator = RubyUnits.configuration.separator case target_units when :ft inches = convert_to('in').scalar.to_int out = "#{(inches / 12).truncate}\'#{(inches % 12).round}\"" when :lbs ounces = convert_to('oz').scalar.to_int - out = "#{(ounces / 16).truncate} lbs, #{(ounces % 16).round} oz" + out = "#{(ounces / 16).truncate}#{separator}lbs, #{(ounces % 16).round}#{separator}oz" when :stone pounds = convert_to('lbs').scalar.to_int - out = "#{(pounds / 14).truncate} stone, #{(pounds % 14).round} lb" + out = "#{(pounds / 14).truncate}#{separator}stone, #{(pounds % 14).round}#{separator}lb" when String out = case target_units.strip when /\A\s*\Z/ # whitespace only @@ -663,7 +664,7 @@ def to_s(target_units = nil) if $2 # unit specified, need to convert convert_to($2).to_s($1) else - "#{$1 % @scalar} #{$2 || units}".strip + "#{$1 % @scalar}#{separator}#{$2 || units}".strip end rescue # parse it like a strftime format string (DateTime.new(0) + self).strftime(target_units) @@ -676,9 +677,9 @@ def to_s(target_units = nil) else out = case @scalar when Rational, Complex - "#{@scalar} #{units}" + "#{@scalar}#{separator}#{units}" else - "#{'%g' % @scalar} #{units}" + "#{'%g' % @scalar}#{separator}#{units}" end.strip end @output[target_units] = out diff --git a/spec/ruby_units/configuration_spec.rb b/spec/ruby_units/configuration_spec.rb new file mode 100644 index 00000000..f32fb88e --- /dev/null +++ b/spec/ruby_units/configuration_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe RubyUnits::Configuration do + context '.separator is true' do + it 'has a space between the scalar and the unit' do + expect(RubyUnits::Unit.new('1 m').to_s).to eq '1 m' + end + end + + context '.separator is false' do + around(:each) do |example| + RubyUnits.configure do |config| + config.separator = false + end + example.run + RubyUnits.reset + end + + it 'does not have a space between the scalar and the unit' do + expect(RubyUnits::Unit.new('1 m').to_s).to eq '1m' + expect(RubyUnits::Unit.new('14.5 lbs').to_s(:lbs)).to eq '14lbs, 8oz' + expect(RubyUnits::Unit.new('220 lbs').to_s(:stone)).to eq '15stone, 10lb' + expect(RubyUnits::Unit.new('14.2 ft').to_s(:ft)).to eq %(14'2") + expect(RubyUnits::Unit.new('1/2 cup').to_s).to eq '1/2cu' + expect(RubyUnits::Unit.new('123.55 lbs').to_s('%0.2f')).to eq '123.55lbs' + end + end +end From 2e0cced64c0ac763492fdd563641264a03364134 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 18:40:53 -0500 Subject: [PATCH 113/150] Remove 'kind_of' method. It was inconsistent and caused some strange problems. Fixes #144 (#150) --- Gemfile | 2 ++ lib/ruby_units/unit.rb | 9 --------- spec/ruby_units/complex_spec.rb | 4 ++-- spec/ruby_units/math_spec.rb | 2 +- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 6a2db6d6..e133fc28 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,7 @@ source 'https://rubygems.org' +ruby RUBY_VERSION + group :development do gem 'bundler', '~> 1.0' gem 'guard-rspec' diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index a45fc733..8e559f31 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -426,15 +426,6 @@ def self.use_definition(definition) # @return [String] attr_accessor :unit_name - # needed to make complex units play nice -- otherwise not detected as a complex_generic - # @param [Class] - # @return [Boolean] - def kind_of?(klass) - # rubocop:disable Style/ClassCheck - scalar.kind_of?(klass) - # rubocop:enable Style/ClassCheck - end - # Used to copy one unit to another # @param [Unit] from Unit to copy definition from # @return [Unit] diff --git a/spec/ruby_units/complex_spec.rb b/spec/ruby_units/complex_spec.rb index af7ff923..82bb89c5 100644 --- a/spec/ruby_units/complex_spec.rb +++ b/spec/ruby_units/complex_spec.rb @@ -12,8 +12,8 @@ describe 'Complex Unit' do subject { Complex(1.0, -1.0).to_unit } - it { is_expected.to be_instance_of Unit } - it(:scalar) { is_expected.to be_kind_of Complex } + it { is_expected.to be_a Unit } + it { expect(subject.scalar).to be_a Complex } it { is_expected.to eq('1-1i'.to_unit) } it { is_expected.to be === '1-1i'.to_unit } diff --git a/spec/ruby_units/math_spec.rb b/spec/ruby_units/math_spec.rb index e33ceeaf..f7f65922 100644 --- a/spec/ruby_units/math_spec.rb +++ b/spec/ruby_units/math_spec.rb @@ -4,7 +4,7 @@ describe '#sqrt' do specify { expect(Math.sqrt(RubyUnits::Unit.new('1 mm^6'))).to eq(RubyUnits::Unit.new('1 mm^3')) } specify { expect(Math.sqrt(4)).to eq(2) } - specify { expect(Math.sqrt(RubyUnits::Unit.new('-9 mm^2'))).to be_kind_of(Complex) } + specify { expect(Math.sqrt(RubyUnits::Unit.new('-9 mm^2')).scalar).to be_kind_of(Complex) } end describe '#cbrt' do From 86bb9c319bf7739c2f2ef52e1df7aecfc612636e Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 18:43:04 -0500 Subject: [PATCH 114/150] Version bump to 2.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 10bf840e..50aea0e7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.1 \ No newline at end of file +2.1.0 \ No newline at end of file From 5e72f3b1c704db546cb6421648c44c43139dfe95 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Fri, 30 Dec 2016 18:57:44 -0500 Subject: [PATCH 115/150] update gemspec --- ruby-units.gemspec | 61 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 7208345c..dcb94a75 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -1,19 +1,19 @@ # Generated by jeweler # DO NOT EDIT THIS FILE DIRECTLY -# Instead, edit Jeweler::Tasks in Rakefile.rb, and run 'rake gemspec' +# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.0.1 ruby lib +# stub: ruby-units 2.1.0 ruby lib Gem::Specification.new do |s| - s.name = "ruby-units" - s.version = "2.0.1" + s.name = "ruby-units".freeze + s.version = "2.1.0" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.require_paths = ["lib"] - s.authors = ["Kevin Olbrich, Ph.D."] - s.date = "2016-07-28" - s.description = "Provides classes and methods to perform unit math and conversions" - s.email = ["kevin.olbrich+ruby_units@gmail.com"] + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Kevin Olbrich, Ph.D.".freeze] + s.date = "2016-12-30" + s.description = "Provides classes and methods to perform unit math and conversions".freeze + s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] s.extra_rdoc_files = [ "LICENSE.txt", "README.md" @@ -22,11 +22,12 @@ Gem::Specification.new do |s| "CHANGELOG.txt", "LICENSE.txt", "README.md", - "Rakefile.rb", + "Rakefile", "VERSION", "lib/ruby-units.rb", "lib/ruby_units/array.rb", "lib/ruby_units/cache.rb", + "lib/ruby_units/configuration.rb", "lib/ruby_units/date.rb", "lib/ruby_units/definition.rb", "lib/ruby_units/math.rb", @@ -42,30 +43,36 @@ Gem::Specification.new do |s| "lib/ruby_units/version.rb", "ruby-units.gemspec" ] - s.homepage = "https://github.com/olbrich/ruby-units" - s.licenses = ["MIT"] - s.rubygems_version = "2.5.1" - s.summary = "A class that performs unit conversions and unit math" + s.homepage = "https://github.com/olbrich/ruby-units".freeze + s.licenses = ["MIT".freeze] + s.rubygems_version = "2.6.8".freeze + s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 1.0"]) - s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) - s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q.freeze, ["~> 1.0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) else - s.add_dependency(%q, ["~> 1.0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) end else - s.add_dependency(%q, ["~> 1.0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) end end From ae67e49e9dcb2dc94888f6eb3a4132d684959f84 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 31 Dec 2016 00:24:58 -0500 Subject: [PATCH 116/150] ignore specs for code climate analysis --- .codeclimate.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index fabacdcf..4aeef9a9 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -29,3 +29,4 @@ ratings: exclude_paths: - ruby-units.gemspec - bin/ +- spec/ From a3620e049a900f5972cc36c32c8f271127df094b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 25 Apr 2017 16:23:48 -0700 Subject: [PATCH 117/150] Update supported ruby versions. Ruby 2.1 has been dropped. --- .ruby-version | 2 +- .travis.yml | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.ruby-version b/.ruby-version index 197c4d5c..005119ba 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.0 +2.4.1 diff --git a/.travis.yml b/.travis.yml index 70cdeaca..fb2652a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ sudo: false language: ruby rvm: - - 2.4.0 - - 2.3.3 - - 2.2.6 - - 2.1.10 + - 2.4.1 + - 2.3.4 + - 2.2.7 - ruby-head - jruby-9.1.6.0 script: bundle exec rake --trace From 9de5951fba704fc32f170a84413df702d3368b0b Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 7 Aug 2017 10:45:34 -0400 Subject: [PATCH 118/150] Remove mathn (#157) * remove 'mathn' as a dependency and adjust code to retain accuracy without it. --- .rubocop_todo.yml | 6 ++--- README.md | 17 ++++++-------- lib/ruby_units/math.rb | 4 +--- lib/ruby_units/unit.rb | 44 ++++++++++++++++++++---------------- ruby-units.gemspec | 3 +-- spec/ruby_units/unit_spec.rb | 14 ++++++------ 6 files changed, 43 insertions(+), 45 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 859f9cf8..d1ff16df 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-12-26 14:41:04 -0500 using RuboCop version 0.46.0. +# on 2017-07-11 15:18:46 -0700 using RuboCop version 0.46.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -17,9 +17,9 @@ Metrics/BlockNesting: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1080 + Max: 1082 -# Offense count: 15 +# Offense count: 16 Metrics/CyclomaticComplexity: Max: 46 diff --git a/README.md b/README.md index c35fec11..0535017a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,13 @@ Kevin C. Olbrich, Ph.D. Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) +Prerelease Notes +---------------- + +This version removes 'mathn' as a dependency. Mathn alters the behavior of some mathematical operators, which +frequently causes unexpected behavior and can be a source of difficult to diagnose bugs. Mathn is also scheduled to be removed from +the Ruby standard library. + Introduction ------------ @@ -276,16 +283,6 @@ Currently there is only one configuration you can set: ### NOTES -#### Mathn - -Note that the current implementation of ruby-units requires 'mathn' from the ruby standard library. -This tends to change the behavior of integer math in ways that many people do not expect, and can be the source -of numerous bugs and odd behaviors. If you encounter what appears to be a bug in your code that seems to be related - -to the use of ruby-units, try to reproduce the bug by just including 'mathn' by itself. - -If you identify a bug in a gem or code that uses mathn, please file a bug report or create a pull request to fix it. - #### Performance vs. Accuracy Ruby units was originally intended to provide a robust and accurate way to do arbitrary unit conversions. diff --git a/lib/ruby_units/math.rb b/lib/ruby_units/math.rb index 3f3cf90c..baff5786 100644 --- a/lib/ruby_units/math.rb +++ b/lib/ruby_units/math.rb @@ -1,5 +1,3 @@ -require 'mathn' - # Math will convert unit objects to radians and then attempt to use the value for # trigonometric functions. module Math @@ -100,7 +98,7 @@ def tanh(n) # @return [Numeric] def hypot(x, y) if RubyUnits::Unit === x && RubyUnits::Unit === y - (x**2 + y**2)**(1 / 2) + (x**2 + y**2)**Rational(1, 2) else unit_hypot(x, y) end diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 8e559f31..3adea151 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -587,23 +587,23 @@ def to_base num = [] den = [] - q = 1 - @numerator.compact.each do |unit| - if @@prefix_values[unit] - q *= @@prefix_values[unit] + q = Rational(1) + @numerator.compact.each do |num_unit| + if @@prefix_values[num_unit] + q *= @@prefix_values[num_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] + q *= @@unit_values[num_unit][:scalar] if @@unit_values[num_unit] + num << @@unit_values[num_unit][:numerator] if @@unit_values[num_unit] && @@unit_values[num_unit][:numerator] + den << @@unit_values[num_unit][:denominator] if @@unit_values[num_unit] && @@unit_values[num_unit][:denominator] end end - @denominator.compact.each do |unit| - if @@prefix_values[unit] - q /= @@prefix_values[unit] + @denominator.compact.each do |num_unit| + if @@prefix_values[num_unit] + q /= @@prefix_values[num_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] + q /= @@unit_values[num_unit][:scalar] if @@unit_values[num_unit] + den << @@unit_values[num_unit][:numerator] if @@unit_values[num_unit] && @@unit_values[num_unit][:numerator] + num << @@unit_values[num_unit][:denominator] if @@unit_values[num_unit] && @@unit_values[num_unit][:denominator] end end @@ -833,7 +833,7 @@ def +(other) RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature) end else - @q ||= ((@@cached_units[units].scalar / @@cached_units[units].base_scalar) rescue units.to_unit.to_base.scalar) + @q ||= (Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) rescue units.to_unit.to_base.scalar) RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) end else @@ -870,7 +870,7 @@ def -(other) elsif other.temperature? raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' else - @q ||= ((@@cached_units[units].scalar / @@cached_units[units].base_scalar) rescue (units.to_unit.scalar / units.to_unit.to_base.scalar)) + @q ||= (Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) rescue Rational(units.to_unit.scalar, units.to_unit.to_base.scalar)) RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) end else @@ -914,12 +914,16 @@ def /(other) when Unit raise ZeroDivisionError if other.zero? raise ArgumentError, 'Cannot divide with temperatures' if [other, self].any?(&:temperature?) - opts = RubyUnits::Unit.eliminate_terms(@scalar / other.scalar, @numerator + other.denominator, @denominator + other.numerator) + sc = Rational(@scalar, other.scalar) + sc = sc.numerator if sc.denominator == 1 + opts = RubyUnits::Unit.eliminate_terms(sc, @numerator + other.denominator, @denominator + other.numerator) opts[:signature] = @signature - other.signature RubyUnits::Unit.new(opts) when Numeric raise ZeroDivisionError if other.zero? - RubyUnits::Unit.new(scalar: @scalar / other, numerator: @numerator, denominator: @denominator, signature: @signature) + sc = Rational(@scalar, other) + sc = sc.numerator if sc.denominator == 1 + RubyUnits::Unit.new(scalar: sc, numerator: @numerator, denominator: @denominator, signature: @signature) else x, y = coerce(other) y / x @@ -972,11 +976,11 @@ def **(other) return power(other) when Float return self**other.to_i if other == other.to_i - valid = (1..9).map { |x| 1 / x } + valid = (1..9).map { |n| Rational(1, n) } raise ArgumentError, 'Not a n-th root (1..9), use 1/n' unless valid.include? other.abs - return root((1 / other).to_int) + return root(Rational(1, other).to_int) when Complex - raise ArgumentError, 'exponentiation of complex numbers is not yet supported.' + raise ArgumentError, 'exponentiation of complex numbers is not supported.' else raise ArgumentError, 'Invalid Exponent' end diff --git a/ruby-units.gemspec b/ruby-units.gemspec index dcb94a75..64b1bb9f 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -45,7 +45,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units".freeze s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.8".freeze + s.rubygems_version = "2.6.10".freeze s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then @@ -75,4 +75,3 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) end end - diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index baa91825..3ca80bb1 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -896,7 +896,7 @@ describe '#scalar' do subject { super().scalar } - it { is_expected.to be_an Integer } + it { is_expected.to eq 60 } end describe '#units' do @@ -1348,8 +1348,9 @@ describe '#define' do describe 'a new unit' do before(:each) do + # do this because the unit is not defined at the time this file is parsed, so it fails @jiffy = Unit.define('jiffy') do |jiffy| - jiffy.scalar = (1 / 100) + jiffy.scalar = Rational(1, 100) jiffy.aliases = %w(jif) jiffy.numerator = [''] jiffy.kind = :time @@ -1361,7 +1362,6 @@ end describe "RubyUnits::Unit.new('1e6 jiffy')" do - # do this because the unit is not defined at the time this file is parsed, so it fails subject { RubyUnits::Unit.new('1e6 jiffy') } it { is_expected.to be_a Numeric } @@ -1857,9 +1857,9 @@ it { expect(subject**-1).to eq(1 / subject) } it { expect(subject**2).to eq(RubyUnits::Unit.new('1 m^2')) } it { expect(subject**-2).to eq(RubyUnits::Unit.new('1 1/m^2')) } - specify { expect { subject**(1 / 2) }.to raise_error(ArgumentError, 'Illegal root') } + specify { expect { subject**Rational(1, 2) }.to raise_error(ArgumentError, 'Illegal root') } # because 1 m^(1/2) doesn't make any sense - specify { expect { subject**Complex(1, 1) }.to raise_error(ArgumentError, 'exponentiation of complex numbers is not yet supported.') } + specify { expect { subject**Complex(1, 1) }.to raise_error(ArgumentError, 'exponentiation of complex numbers is not supported.') } specify { expect { subject**RubyUnits::Unit.new('1 m') }.to raise_error(ArgumentError, 'Invalid Exponent') } end @@ -2114,8 +2114,8 @@ context '#from' do specify { expect(RubyUnits::Unit.new('1 day').from(Date.civil(2011, 10, 17))).to eq(Date.civil(2011, 10, 18)) } - specify { expect(RubyUnits::Unit.new('5 min').from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 0o0, 0o5)) } - specify { expect(RubyUnits::Unit.new('5 min').from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 0o0, 0o5)) } + specify { expect(RubyUnits::Unit.new('5 min').from(DateTime.civil(2011, 10, 21))).to eq(DateTime.civil(2011, 10, 21, 0, 5)) } + specify { expect(RubyUnits::Unit.new('5 min').from(Time.utc(2011, 10, 21))).to eq(Time.utc(2011, 10, 21, 0, 5)) } specify { expect { RubyUnits::Unit.new('5 min').from(nil) }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } specify { expect { RubyUnits::Unit.new('5 min').from('12:00') }.to raise_error(ArgumentError, 'Must specify a Time, Date, or DateTime') } end From a443a61fce4970926544f31b56caf77c02b6cb40 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 7 Aug 2017 10:46:49 -0400 Subject: [PATCH 119/150] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0535017a..fe994568 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Kevin C. Olbrich, Ph.D. Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) -Prerelease Notes ----------------- +Notes +----- This version removes 'mathn' as a dependency. Mathn alters the behavior of some mathematical operators, which frequently causes unexpected behavior and can be a source of difficult to diagnose bugs. Mathn is also scheduled to be removed from From 982116fa66a8311ea866d6339403ca76e13bca94 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 7 Aug 2017 10:50:48 -0400 Subject: [PATCH 120/150] Version bump to 2.2.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 50aea0e7..e3a4f193 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 \ No newline at end of file +2.2.0 \ No newline at end of file From e02391b137ae0df4eadb9565647e0b8a00dda406 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 7 Aug 2017 10:51:28 -0400 Subject: [PATCH 121/150] Regenerate gemspec for version 2.2.0 --- ruby-units.gemspec | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 64b1bb9f..15da609f 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,16 +2,16 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.1.0 ruby lib +# stub: ruby-units 2.2.0 ruby lib Gem::Specification.new do |s| s.name = "ruby-units".freeze - s.version = "2.1.0" + s.version = "2.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2016-12-30" + s.date = "2017-08-07" s.description = "Provides classes and methods to perform unit math and conversions".freeze s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] s.extra_rdoc_files = [ @@ -45,7 +45,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units".freeze s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.10".freeze + s.rubygems_version = "2.6.11".freeze s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then @@ -75,3 +75,4 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) end end + From ae87805b9ba54f43495916e4d2fbc4a50c4c598d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Mon, 7 Aug 2017 10:54:39 -0400 Subject: [PATCH 122/150] update changelog --- CHANGELOG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 454e8747..f76fa564 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,8 @@ Change Log for Ruby-units ========================= +2017-08-07 2.2.0 * add support for ruby 2.4.1 + * drop support for ruby 2.1.0 + * remove dependency on mathn (see #157) 2016-12-28 2.1.0 * add support for ruby 2.4.0 * allow configuration for optional separator on output * Fix issue #105 -- change 'grad' to 'gon' From 73a9893feb719aebecbae359c935c339bcc5c202 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sun, 1 Oct 2017 13:06:41 -0400 Subject: [PATCH 123/150] Maintenance (#160) * update supported ruby versions, install rubocop --- .codeclimate.yml | 9 +- .ruby-version | 2 +- .travis.yml | 8 +- Gemfile | 1 + Guardfile | 2 +- lib/ruby_units/date.rb | 4 +- lib/ruby_units/time.rb | 4 +- lib/ruby_units/unit.rb | 7 +- lib/ruby_units/unit_definitions/base.rb | 56 ++--- lib/ruby_units/unit_definitions/prefix.rb | 60 +++--- lib/ruby_units/unit_definitions/standard.rb | 216 ++++++++++---------- spec/ruby_units/definition_spec.rb | 2 +- spec/ruby_units/temperature_spec.rb | 12 +- spec/ruby_units/unit_spec.rb | 18 +- 14 files changed, 198 insertions(+), 203 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 4aeef9a9..dcaa009b 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -15,16 +15,9 @@ engines: enabled: true rubocop: enabled: true + channel: rubocop-0-49 ratings: paths: - - Gemfile.lock - - "**.css" - - "**.inc" - - "**.js" - - "**.jsx" - - "**.module" - - "**.php" - - "**.py" - "**.rb" exclude_paths: - ruby-units.gemspec diff --git a/.ruby-version b/.ruby-version index 005119ba..23a63f52 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.1 +2.2.8 diff --git a/.travis.yml b/.travis.yml index fb2652a2..550a9385 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ sudo: false language: ruby rvm: - - 2.4.1 - - 2.3.4 - - 2.2.7 + - 2.4.2 + - 2.3.5 + - 2.2.8 - ruby-head - - jruby-9.1.6.0 + - jruby-9.1.13.0 script: bundle exec rake --trace bundler_args: --without development diff --git a/Gemfile b/Gemfile index e133fc28..0d6abc98 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,7 @@ end group :test do gem 'rake' gem 'rspec' + gem 'rubocop', '= 0.49.1' # match codeclimate gem 'simplecov' gem 'simplecov-html' end diff --git a/Guardfile b/Guardfile index ff332898..b1d0e6cb 100644 --- a/Guardfile +++ b/Guardfile @@ -2,7 +2,7 @@ # More info at https://github.com/guard/guard#readme ## Uncomment and set this to only include directories you want to watch -directories %w(lib spec) +directories %w[lib spec] ## Uncomment to clear the screen before every task clearing :on diff --git a/lib/ruby_units/date.rb b/lib/ruby_units/date.rb index 27b55ab8..5a8d23d3 100644 --- a/lib/ruby_units/date.rb +++ b/lib/ruby_units/date.rb @@ -9,7 +9,7 @@ class Date def +(other) case other when RubyUnits::Unit - other = other.convert_to('d').round if %w(y decade century).include? other.units + other = other.convert_to('d').round if %w[y decade century].include? other.units unit_date_add(other.convert_to('day').scalar) else unit_date_add(other) @@ -22,7 +22,7 @@ def +(other) def -(other) case other when RubyUnits::Unit - other = other.convert_to('d').round if %w(y decade century).include? other.units + other = other.convert_to('d').round if %w[y decade century].include? other.units unit_date_sub(other.convert_to('day').scalar) else unit_date_sub(other) diff --git a/lib/ruby_units/time.rb b/lib/ruby_units/time.rb index 4111c9c8..717f0c60 100644 --- a/lib/ruby_units/time.rb +++ b/lib/ruby_units/time.rb @@ -45,7 +45,7 @@ def to_unit(other = nil) def +(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if %w(y decade century).include? other.units + other = other.convert_to('d').round.convert_to('s') if %w[y decade century].include? other.units begin unit_add(other.convert_to('s').scalar) rescue RangeError @@ -69,7 +69,7 @@ def self.in(duration) def -(other) case other when RubyUnits::Unit - other = other.convert_to('d').round.convert_to('s') if %w(y decade century).include? other.units + other = other.convert_to('d').round.convert_to('s') if %w[y decade century].include? other.units begin unit_sub(other.convert_to('s').scalar) rescue RangeError diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 3adea151..90d6a675 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1,4 +1,5 @@ # encoding: utf-8 + require 'date' # Copyright 2006-2015 # @author Kevin C. Olbrich, Ph.D. @@ -62,7 +63,7 @@ class Unit < Numeric RANKINE = [''].freeze CELSIUS = [''].freeze @@temp_regex = nil - SIGNATURE_VECTOR = %i( + SIGNATURE_VECTOR = %i[ length time temperature @@ -73,7 +74,7 @@ class Unit < Numeric currency information angle - ).freeze + ].freeze @@kinds = { -312_078 => :elastance, -312_058 => :resistance, @@ -369,7 +370,7 @@ def self.prefix_regex def self.temp_regex @@temp_regex ||= begin - temp_units = %w(tempK tempC tempF tempR degK degC degF degR) + temp_units = %w[tempK tempC tempF tempR degK degC degF degR] aliases = temp_units.map do |unit| d = RubyUnits::Unit.definition(unit) d && d.aliases diff --git a/lib/ruby_units/unit_definitions/base.rb b/lib/ruby_units/unit_definitions/base.rb index d3cf3fa6..c87572e5 100644 --- a/lib/ruby_units/unit_definitions/base.rb +++ b/lib/ruby_units/unit_definitions/base.rb @@ -3,98 +3,98 @@ RubyUnits::Unit.define('meter') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(m meter meters metre metres) + unit.numerator = %w[] + unit.aliases = %w[m meter meters metre metres] unit.kind = :length end RubyUnits::Unit.define('kilogram') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(kg kilogram kilograms) + unit.numerator = %w[] + unit.aliases = %w[kg kilogram kilograms] unit.kind = :mass end RubyUnits::Unit.define('second') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(s sec second seconds) + unit.numerator = %w[] + unit.aliases = %w[s sec second seconds] unit.kind = :time end RubyUnits::Unit.define('mole') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(mol mole) + unit.numerator = %w[] + unit.aliases = %w[mol mole] unit.kind = :substance end RubyUnits::Unit.define('ampere') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(A ampere amperes amp amps) + unit.numerator = %w[] + unit.aliases = %w[A ampere amperes amp amps] unit.kind = :current end RubyUnits::Unit.define('radian') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(rad radian radians) + unit.numerator = %w[] + unit.aliases = %w[rad radian radians] unit.kind = :angle end RubyUnits::Unit.define('kelvin') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(degK kelvin) + unit.numerator = %w[] + unit.aliases = %w[degK kelvin] unit.kind = :temperature end RubyUnits::Unit.define('tempK') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(tempK) + unit.numerator = %w[] + unit.aliases = %w[tempK] unit.kind = :temperature end RubyUnits::Unit.define('byte') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(B byte bytes) + unit.numerator = %w[] + unit.aliases = %w[B byte bytes] unit.kind = :information end RubyUnits::Unit.define('dollar') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(USD dollar) + unit.numerator = %w[] + unit.aliases = %w[USD dollar] unit.kind = :currency end RubyUnits::Unit.define('candela') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(cd candela) + unit.numerator = %w[] + unit.aliases = %w[cd candela] unit.kind = :luminosity end RubyUnits::Unit.define('each') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(each) + unit.numerator = %w[] + unit.aliases = %w[each] unit.kind = :counting end RubyUnits::Unit.define('steradian') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(sr steradian steradians) + unit.numerator = %w[] + unit.aliases = %w[sr steradian steradians] unit.kind = :solid_angle end RubyUnits::Unit.define('decibel') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(dB decibel decibels) + unit.numerator = %w[] + unit.aliases = %w[dB decibel decibels] unit.kind = :logarithmic end diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index e706ff09..7dc0f552 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,36 +1,36 @@ # encoding: utf-8 { - 'googol' => [%w(googol), 1e100], - 'yobi' => [%w(Yi Yobi yobi), 2**80], - 'zebi' => [%w(Zi Zebi zebi), 2**70], - 'exbi' => [%w(Ei Exbi exbi), 2**60], - 'pebi' => [%w(Pi Pebi pebi), 2**50], - 'tebi' => [%w(Ti Tebi tebi), 2**40], - 'gibi' => [%w(Gi Gibi gibi), 2**30], - 'mebi' => [%w(Mi Mebi mebi), 2**20], - 'kibi' => [%w(Ki Kibi kibi), 2**10], - 'yotta' => [%w(Y Yotta yotta), 1e24], - 'zetta' => [%w(Z Zetta zetta), 1e21], - 'exa' => [%w(E Exa exa), 1e18], - 'peta' => [%w(P Peta peta), 1e15], - 'tera' => [%w(T Tera tera), 1e12], - 'giga' => [%w(G Giga giga), 1e9], - 'mega' => [%w(M Mega mega), 1e6], - 'kilo' => [%w(k kilo), 1e3], - 'hecto' => [%w(h Hecto hecto), 1e2], - 'deca' => [%w(da Deca deca deka), 1e1], - '1' => [%w(1), 1], - 'deci' => [%w(d Deci deci), Rational(1, 1e1)], - 'centi' => [%w(c Centi centi), Rational(1, 1e2)], - 'milli' => [%w(m Milli milli), Rational(1, 1e3)], - 'micro' => [%w(u µ Micro micro mc), Rational(1, 1e6)], - 'nano' => [%w(n Nano nano), Rational(1, 1e9)], - 'pico' => [%w(p Pico pico), Rational(1, 1e12)], - 'femto' => [%w(f Femto femto), Rational(1, 1e15)], - 'atto' => [%w(a Atto atto), Rational(1, 1e18)], - 'zepto' => [%w(z Zepto zepto), Rational(1, 1e21)], - 'yocto' => [%w(y Yocto yocto), Rational(1, 1e24)] + 'googol' => [%w[googol], 1e100], + 'yobi' => [%w[Yi Yobi yobi], 2**80], + 'zebi' => [%w[Zi Zebi zebi], 2**70], + 'exbi' => [%w[Ei Exbi exbi], 2**60], + 'pebi' => [%w[Pi Pebi pebi], 2**50], + 'tebi' => [%w[Ti Tebi tebi], 2**40], + 'gibi' => [%w[Gi Gibi gibi], 2**30], + 'mebi' => [%w[Mi Mebi mebi], 2**20], + 'kibi' => [%w[Ki Kibi kibi], 2**10], + 'yotta' => [%w[Y Yotta yotta], 1e24], + 'zetta' => [%w[Z Zetta zetta], 1e21], + 'exa' => [%w[E Exa exa], 1e18], + 'peta' => [%w[P Peta peta], 1e15], + 'tera' => [%w[T Tera tera], 1e12], + 'giga' => [%w[G Giga giga], 1e9], + 'mega' => [%w[M Mega mega], 1e6], + 'kilo' => [%w[k kilo], 1e3], + 'hecto' => [%w[h Hecto hecto], 1e2], + 'deca' => [%w[da Deca deca deka], 1e1], + '1' => [%w[1], 1], + 'deci' => [%w[d Deci deci], Rational(1, 1e1)], + 'centi' => [%w[c Centi centi], Rational(1, 1e2)], + 'milli' => [%w[m Milli milli], Rational(1, 1e3)], + 'micro' => [%w[u µ Micro micro mc], Rational(1, 1e6)], + 'nano' => [%w[n Nano nano], Rational(1, 1e9)], + 'pico' => [%w[p Pico pico], Rational(1, 1e12)], + 'femto' => [%w[f Femto femto], Rational(1, 1e15)], + 'atto' => [%w[a Atto atto], Rational(1, 1e18)], + 'zepto' => [%w[z Zepto zepto], Rational(1, 1e21)], + 'yocto' => [%w[y Yocto yocto], Rational(1, 1e24)] }.each do |name, definition| RubyUnits::Unit.define(name) do |unit| aliases, scalar = definition diff --git a/lib/ruby_units/unit_definitions/standard.rb b/lib/ruby_units/unit_definitions/standard.rb index 1c4dbf90..26510df4 100644 --- a/lib/ruby_units/unit_definitions/standard.rb +++ b/lib/ruby_units/unit_definitions/standard.rb @@ -2,92 +2,92 @@ RubyUnits::Unit.define('inch') do |inch| inch.definition = RubyUnits::Unit.new('254/10000 meter') - inch.aliases = %w(in inch inches ") + inch.aliases = %w[in inch inches "] end RubyUnits::Unit.define('foot') do |foot| foot.definition = RubyUnits::Unit.new('12 inches') - foot.aliases = %w(ft foot feet ') + foot.aliases = %w[ft foot feet '] end RubyUnits::Unit.define('survey-foot') do |sft| sft.definition = RubyUnits::Unit.new('1200/3937 meter') - sft.aliases = %w(sft sfoot sfeet) + sft.aliases = %w[sft sfoot sfeet] end RubyUnits::Unit.define('yard') do |yard| yard.definition = RubyUnits::Unit.new('3 ft') - yard.aliases = %w(yd yard yards) + yard.aliases = %w[yd yard yards] end RubyUnits::Unit.define('mile') do |mile| mile.definition = RubyUnits::Unit.new('5280 ft') - mile.aliases = %w(mi mile miles) + mile.aliases = %w[mi mile miles] end RubyUnits::Unit.define('naut-mile') do |naut| naut.definition = RubyUnits::Unit.new('1852 m') - naut.aliases = %w(nmi M NM) + naut.aliases = %w[nmi M NM] end # on land RubyUnits::Unit.define('league') do |league| league.definition = RubyUnits::Unit.new('3 miles') - league.aliases = %w(league leagues) + league.aliases = %w[league leagues] end # at sea RubyUnits::Unit.define('naut-league') do |naut_league| naut_league.definition = RubyUnits::Unit.new('3 nmi') - naut_league.aliases = %w(nleague nleagues) + naut_league.aliases = %w[nleague nleagues] end RubyUnits::Unit.define('furlong') do |furlong| furlong.definition = RubyUnits::Unit.new('1/8 mile') - furlong.aliases = %w(fur furlong furlongs) + furlong.aliases = %w[fur furlong furlongs] end RubyUnits::Unit.define('rod') do |rod| rod.definition = RubyUnits::Unit.new('33/2 feet') - rod.aliases = %w(rd rod rods) + rod.aliases = %w[rd rod rods] end RubyUnits::Unit.define('fathom') do |fathom| fathom.definition = RubyUnits::Unit.new('6 ft') - fathom.aliases = %w(fathom fathoms) + fathom.aliases = %w[fathom fathoms] end RubyUnits::Unit.define('mil') do |mil| mil.definition = RubyUnits::Unit.new('1/1000 inch') - mil.aliases = %w(mil mils) + mil.aliases = %w[mil mils] end RubyUnits::Unit.define('angstrom') do |ang| ang.definition = RubyUnits::Unit.new('1/10 nm') - ang.aliases = %w(ang angstrom angstroms) + ang.aliases = %w[ang angstrom angstroms] end # typesetting RubyUnits::Unit.define('pica') do |pica| pica.definition = RubyUnits::Unit.new('1/72 ft') - pica.aliases = %w(P pica picas) + pica.aliases = %w[P pica picas] end RubyUnits::Unit.define('point') do |point| point.definition = RubyUnits::Unit.new('1/12 pica') - point.aliases = %w(point points) + point.aliases = %w[point points] end RubyUnits::Unit.define('dot') do |dot| dot.definition = RubyUnits::Unit.new('1 each') - dot.aliases = %w(dot dots) + dot.aliases = %w[dot dots] dot.kind = :counting end RubyUnits::Unit.define('pixel') do |pixel| pixel.definition = RubyUnits::Unit.new('1 each') - pixel.aliases = %w(px pixel pixels) + pixel.aliases = %w[px pixel pixels] pixel.kind = :counting end @@ -105,91 +105,91 @@ RubyUnits::Unit.define('AMU') do |amu| amu.definition = RubyUnits::Unit.new('0.012 kg/mol') / (12 * avagadro_constant) - amu.aliases = %w(u AMU amu) + amu.aliases = %w[u AMU amu] end RubyUnits::Unit.define('dalton') do |dalton| dalton.definition = RubyUnits::Unit.new('1 amu') - dalton.aliases = %w(Da dalton daltons) + dalton.aliases = %w[Da dalton daltons] end RubyUnits::Unit.define('metric-ton') do |mton| mton.definition = RubyUnits::Unit.new('1000 kg') - mton.aliases = %w(tonne) + mton.aliases = %w[tonne] end # defined as a rational number to preserve accuracy and minimize round-off errors during # calculations RubyUnits::Unit.define('pound') do |pound| pound.definition = RubyUnits::Unit.new(Rational(45_359_237, 1e8), 'kg') - pound.aliases = %w(lbs lb lbm pound-mass pound pounds #) + pound.aliases = %w[lbs lb lbm pound-mass pound pounds #] end RubyUnits::Unit.define('ounce') do |ounce| ounce.definition = RubyUnits::Unit.new('1/16 lbs') - ounce.aliases = %w(oz ounce ounces) + ounce.aliases = %w[oz ounce ounces] end RubyUnits::Unit.define('gram') do |gram| gram.definition = RubyUnits::Unit.new('1/1000 kg') - gram.aliases = %w(g gram grams gramme grammes) + gram.aliases = %w[g gram grams gramme grammes] end RubyUnits::Unit.define('short-ton') do |ton| ton.definition = RubyUnits::Unit.new('2000 lbs') - ton.aliases = %w(tn ton tons short-tons) + ton.aliases = %w[tn ton tons short-tons] end RubyUnits::Unit.define('carat') do |carat| carat.definition = RubyUnits::Unit.new('1/5000 kg') - carat.aliases = %w(ct carat carats) + carat.aliases = %w[ct carat carats] end RubyUnits::Unit.define('stone') do |stone| stone.definition = RubyUnits::Unit.new('14 lbs') - stone.aliases = %w(st stone) + stone.aliases = %w[st stone] end # time RubyUnits::Unit.define('minute') do |min| min.definition = RubyUnits::Unit.new('60 seconds') - min.aliases = %w(min minute minutes) + min.aliases = %w[min minute minutes] end RubyUnits::Unit.define('hour') do |hour| hour.definition = RubyUnits::Unit.new('60 minutes') - hour.aliases = %w(h hr hrs hour hours) + hour.aliases = %w[h hr hrs hour hours] end RubyUnits::Unit.define('day') do |day| day.definition = RubyUnits::Unit.new('24 hours') - day.aliases = %w(d day days) + day.aliases = %w[d day days] end RubyUnits::Unit.define('week') do |week| week.definition = RubyUnits::Unit.new('7 days') - week.aliases = %w(wk week weeks) + week.aliases = %w[wk week weeks] end RubyUnits::Unit.define('fortnight') do |fortnight| fortnight.definition = RubyUnits::Unit.new('2 weeks') - fortnight.aliases = %w(fortnight fortnights) + fortnight.aliases = %w[fortnight fortnights] end RubyUnits::Unit.define('year') do |year| year.definition = RubyUnits::Unit.new('31556926 seconds') # works out to 365.24219907407405 days - year.aliases = %w(y yr year years annum) + year.aliases = %w[y yr year years annum] end RubyUnits::Unit.define('decade') do |decade| decade.definition = RubyUnits::Unit.new('10 years') - decade.aliases = %w(decade decades) + decade.aliases = %w[decade decades] end RubyUnits::Unit.define('century') do |century| century.definition = RubyUnits::Unit.new('100 years') - century.aliases = %w(century centuries) + century.aliases = %w[century centuries] end # area @@ -200,7 +200,7 @@ RubyUnits::Unit.define('acre') do |acre| acre.definition = RubyUnits::Unit.new('1 mi')**2 / 640 - acre.aliases = %w(acre acres) + acre.aliases = %w[acre acres] end RubyUnits::Unit.define('sqft') do |sqft| @@ -215,42 +215,42 @@ RubyUnits::Unit.define('liter') do |liter| liter.definition = RubyUnits::Unit.new('1/1000 m^3') - liter.aliases = %w(l L liter liters litre litres) + liter.aliases = %w[l L liter liters litre litres] end RubyUnits::Unit.define('gallon') do |gallon| gallon.definition = RubyUnits::Unit.new('231 in^3') - gallon.aliases = %w(gal gallon gallons) + gallon.aliases = %w[gal gallon gallons] end RubyUnits::Unit.define('quart') do |quart| quart.definition = RubyUnits::Unit.new('1/4 gal') - quart.aliases = %w(qt quart quarts) + quart.aliases = %w[qt quart quarts] end RubyUnits::Unit.define('pint') do |pint| pint.definition = RubyUnits::Unit.new('1/8 gal') - pint.aliases = %w(pt pint pints) + pint.aliases = %w[pt pint pints] end RubyUnits::Unit.define('cup') do |cup| cup.definition = RubyUnits::Unit.new('1/16 gal') - cup.aliases = %w(cu cup cups) + cup.aliases = %w[cu cup cups] end RubyUnits::Unit.define('fluid-ounce') do |floz| floz.definition = RubyUnits::Unit.new('1/128 gal') - floz.aliases = %w(floz fluid-ounce fluid-ounces) + floz.aliases = %w[floz fluid-ounce fluid-ounces] end RubyUnits::Unit.define('tablespoon') do |tbsp| tbsp.definition = RubyUnits::Unit.new('1/2 floz') - tbsp.aliases = %w(tbs tbsp tablespoon tablespoons) + tbsp.aliases = %w[tbs tbsp tablespoon tablespoons] end RubyUnits::Unit.define('teaspoon') do |tsp| tsp.definition = RubyUnits::Unit.new('1/3 tablespoon') - tsp.aliases = %w(tsp teaspoon teaspoons) + tsp.aliases = %w[tsp teaspoon teaspoons] end ## @@ -260,14 +260,14 @@ # http://en.wikipedia.org/wiki/Board_foot RubyUnits::Unit.define('bdft') do |bdft| bdft.definition = RubyUnits::Unit.new('1/12 ft^3') - bdft.aliases = %w(fbm boardfoot boardfeet bf) + bdft.aliases = %w[fbm boardfoot boardfeet bf] end # volumetric flow RubyUnits::Unit.define('cfm') do |cfm| cfm.definition = RubyUnits::Unit.new('1 ft^3/minute') - cfm.aliases = %w(cfm CFM CFPM) + cfm.aliases = %w[cfm CFM CFPM] end # speed @@ -286,52 +286,52 @@ RubyUnits::Unit.define('knot') do |knot| knot.definition = RubyUnits::Unit.new('1 nmi/hour') - knot.aliases = %w(kt kn kts knot knots) + knot.aliases = %w[kt kn kts knot knots] end RubyUnits::Unit.define('gee') do |gee| # approximated as a rational number to minimize round-off errors gee.definition = RubyUnits::Unit.new(Rational(196_133, 20_000), 'm/s^2') # equivalent to 9.80665 m/s^2 - gee.aliases = %w(gee standard-gravitation) + gee.aliases = %w[gee standard-gravitation] end # temperature differences RubyUnits::Unit.define('newton') do |newton| newton.definition = RubyUnits::Unit.new('1 kg*m/s^2') - newton.aliases = %w(N newton newtons) + newton.aliases = %w[N newton newtons] end RubyUnits::Unit.define('dyne') do |dyne| dyne.definition = RubyUnits::Unit.new('1/100000 N') - dyne.aliases = %w(dyn dyne) + dyne.aliases = %w[dyn dyne] end RubyUnits::Unit.define('pound-force') do |lbf| lbf.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 gee') - lbf.aliases = %w(lbf pound-force) + lbf.aliases = %w[lbf pound-force] end RubyUnits::Unit.define('poundal') do |poundal| poundal.definition = RubyUnits::Unit.new('1 lb') * RubyUnits::Unit.new('1 ft/s^2') - poundal.aliases = %w(pdl poundal poundals) + poundal.aliases = %w[pdl poundal poundals] end temp_convert_factor = Rational(2_501_999_792_983_609, 4_503_599_627_370_496) # approximates 1/1.8 RubyUnits::Unit.define('celsius') do |celsius| celsius.definition = RubyUnits::Unit.new('1 degK') - celsius.aliases = %w(degC celsius centigrade) + celsius.aliases = %w[degC celsius centigrade] end RubyUnits::Unit.define('fahrenheit') do |fahrenheit| fahrenheit.definition = RubyUnits::Unit.new(temp_convert_factor, 'degK') - fahrenheit.aliases = %w(degF fahrenheit) + fahrenheit.aliases = %w[degF fahrenheit] end RubyUnits::Unit.define('rankine') do |rankine| rankine.definition = RubyUnits::Unit.new('1 degF') - rankine.aliases = %w(degR rankine) + rankine.aliases = %w[degR rankine] end RubyUnits::Unit.define('tempC') do |temp_c| @@ -352,58 +352,58 @@ RubyUnits::Unit.define('light-second') do |ls| ls.definition = RubyUnits::Unit.new('1 s') * speed_of_light - ls.aliases = %w(ls lsec light-second) + ls.aliases = %w[ls lsec light-second] end RubyUnits::Unit.define('light-minute') do |lmin| lmin.definition = RubyUnits::Unit.new('1 min') * speed_of_light - lmin.aliases = %w(lmin light-minute) + lmin.aliases = %w[lmin light-minute] end RubyUnits::Unit.define('light-year') do |ly| ly.definition = RubyUnits::Unit.new('1 y') * speed_of_light - ly.aliases = %w(ly light-year) + ly.aliases = %w[ly light-year] end RubyUnits::Unit.define('parsec') do |parsec| parsec.definition = RubyUnits::Unit.new('3.26163626 ly') - parsec.aliases = %w(pc parsec parsecs) + parsec.aliases = %w[pc parsec parsecs] end # once was '149597900000 m' but there appears to be a more accurate estimate according to wikipedia # see http://en.wikipedia.org/wiki/Astronomical_unit RubyUnits::Unit.define('AU') do |au| au.definition = RubyUnits::Unit.new('149597870700 m') - au.aliases = %w(AU astronomical-unit) + au.aliases = %w[AU astronomical-unit] end RubyUnits::Unit.define('redshift') do |red| red.definition = RubyUnits::Unit.new('1.302773e26 m') - red.aliases = %w(z red-shift) + red.aliases = %w[z red-shift] end # mass RubyUnits::Unit.define('slug') do |slug| slug.definition = RubyUnits::Unit.new('1 lbf*s^2/ft') - slug.aliases = %w(slug slugs) + slug.aliases = %w[slug slugs] end # pressure RubyUnits::Unit.define('pascal') do |pascal| pascal.definition = RubyUnits::Unit.new('1 kg/m*s^2') - pascal.aliases = %w(Pa pascal pascals) + pascal.aliases = %w[Pa pascal pascals] end RubyUnits::Unit.define('bar') do |bar| bar.definition = RubyUnits::Unit.new('100 kPa') - bar.aliases = %w(bar bars) + bar.aliases = %w[bar bars] end RubyUnits::Unit.define('atm') do |atm| atm.definition = RubyUnits::Unit.new('101325 Pa') - atm.aliases = %w(atm ATM atmosphere atmospheres) + atm.aliases = %w[atm ATM atmosphere atmospheres] end RubyUnits::Unit.define('mmHg') do |mmhg| @@ -418,7 +418,7 @@ RubyUnits::Unit.define('torr') do |torr| torr.definition = RubyUnits::Unit.new('1/760 atm') - torr.aliases = %w(Torr torr) + torr.aliases = %w[Torr torr] end RubyUnits::Unit.define('psi') do |psi| @@ -428,169 +428,169 @@ RubyUnits::Unit.define('cmh2o') do |cmh2o| density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC cmh2o.definition = RubyUnits::Unit.new('1 cm') * RubyUnits::Unit.new('1 gee') * density_of_water - cmh2o.aliases = %w(cmH2O cmh2o cmAq) + cmh2o.aliases = %w[cmH2O cmh2o cmAq] end RubyUnits::Unit.define('inh2o') do |inh2o| density_of_water = RubyUnits::Unit.new('1 g/cm^3') # at 4 tempC inh2o.definition = RubyUnits::Unit.new('1 in') * RubyUnits::Unit.new('1 gee') * density_of_water - inh2o.aliases = %w(inH2O inh2o inAq) + inh2o.aliases = %w[inH2O inh2o inAq] end # viscosity RubyUnits::Unit.define('poise') do |poise| poise.definition = RubyUnits::Unit.new('dPa*s') - poise.aliases = %w(P poise) + poise.aliases = %w[P poise] end RubyUnits::Unit.define('stokes') do |stokes| stokes.definition = RubyUnits::Unit.new('1 cm^2/s') - stokes.aliases = %w(St stokes) + stokes.aliases = %w[St stokes] end # #energy RubyUnits::Unit.define('joule') do |joule| joule.definition = RubyUnits::Unit.new('1 N*m') - joule.aliases = %w(J joule joules) + joule.aliases = %w[J joule joules] end RubyUnits::Unit.define('erg') do |erg| erg.definition = RubyUnits::Unit.new('1 g*cm^2/s^2') - erg.aliases = %w(erg ergs) + erg.aliases = %w[erg ergs] end # power RubyUnits::Unit.define('watt') do |watt| watt.definition = RubyUnits::Unit.new('1 N*m/s') - watt.aliases = %w(W Watt watt watts) + watt.aliases = %w[W Watt watt watts] end RubyUnits::Unit.define('horsepower') do |hp| hp.definition = RubyUnits::Unit.new('33000 ft*lbf/min') - hp.aliases = %w(hp horsepower) + hp.aliases = %w[hp horsepower] end # energy RubyUnits::Unit.define('btu') do |btu| btu.definition = RubyUnits::Unit.new('2320092679909671/2199023255552 J') # 1055.056 J --- ISO standard - btu.aliases = %w(Btu btu Btus btus) + btu.aliases = %w[Btu btu Btus btus] end RubyUnits::Unit.define('therm') do |therm| therm.definition = RubyUnits::Unit.new('100 kBtu') - therm.aliases = %w(thm therm therms Therm) + therm.aliases = %w[thm therm therms Therm] end # "small" calorie RubyUnits::Unit.define('calorie') do |calorie| calorie.definition = RubyUnits::Unit.new('4.184 J') - calorie.aliases = %w(cal calorie calories) + calorie.aliases = %w[cal calorie calories] end # "big" calorie RubyUnits::Unit.define('Calorie') do |calorie| calorie.definition = RubyUnits::Unit.new('1 kcal') - calorie.aliases = %w(Cal Calorie Calories) + calorie.aliases = %w[Cal Calorie Calories] end RubyUnits::Unit.define('molar') do |molar| molar.definition = RubyUnits::Unit.new('1 mole/l') - molar.aliases = %w(M molar) + molar.aliases = %w[M molar] end # potential RubyUnits::Unit.define('volt') do |volt| volt.definition = RubyUnits::Unit.new('1 W/A') - volt.aliases = %w(V volt volts) + volt.aliases = %w[V volt volts] end # capacitance RubyUnits::Unit.define('farad') do |farad| farad.definition = RubyUnits::Unit.new('1 A*s/V') - farad.aliases = %w(F farad farads) + farad.aliases = %w[F farad farads] end # charge RubyUnits::Unit.define('coulomb') do |coulomb| coulomb.definition = RubyUnits::Unit.new('1 A*s') - coulomb.aliases = %w(C coulomb coulombs) + coulomb.aliases = %w[C coulomb coulombs] end # conductance RubyUnits::Unit.define('siemens') do |siemens| siemens.definition = RubyUnits::Unit.new('1 A/V') - siemens.aliases = %w(S siemens) + siemens.aliases = %w[S siemens] end # inductance RubyUnits::Unit.define('henry') do |henry| henry.definition = RubyUnits::Unit.new('1 J/A^2') - henry.aliases = %w(H henry henries) + henry.aliases = %w[H henry henries] end # resistance RubyUnits::Unit.define('ohm') do |ohm| ohm.definition = RubyUnits::Unit.new('1 V/A') - ohm.aliases = %w(Ohm ohm ohms) + ohm.aliases = %w[Ohm ohm ohms] end # magnetism RubyUnits::Unit.define('weber') do |weber| weber.definition = RubyUnits::Unit.new('1 V*s') - weber.aliases = %w(Wb weber webers) + weber.aliases = %w[Wb weber webers] end RubyUnits::Unit.define('tesla') do |tesla| tesla.definition = RubyUnits::Unit.new('1 V*s/m^2') - tesla.aliases = %w(T tesla teslas) + tesla.aliases = %w[T tesla teslas] end RubyUnits::Unit.define('gauss') do |gauss| gauss.definition = RubyUnits::Unit.new('100 microT') - gauss.aliases = %w(G gauss) + gauss.aliases = %w[G gauss] end RubyUnits::Unit.define('maxwell') do |maxwell| maxwell.definition = RubyUnits::Unit.new('1 gauss*cm^2') - maxwell.aliases = %w(Mx maxwell maxwells) + maxwell.aliases = %w[Mx maxwell maxwells] end RubyUnits::Unit.define('oersted') do |oersted| oersted.definition = RubyUnits::Unit.new(250.0 / Math::PI, 'A/m') - oersted.aliases = %w(Oe oersted oersteds) + oersted.aliases = %w[Oe oersted oersteds] end # activity RubyUnits::Unit.define('katal') do |katal| katal.definition = RubyUnits::Unit.new('1 mole/sec') - katal.aliases = %w(kat katal) + katal.aliases = %w[kat katal] end RubyUnits::Unit.define('unit') do |unit| unit.definition = RubyUnits::Unit.new('1/60 microkatal') - unit.aliases = %w(U enzUnit units) + unit.aliases = %w[U enzUnit units] end # frequency RubyUnits::Unit.define('hertz') do |hz| hz.definition = RubyUnits::Unit.new('1 1/s') - hz.aliases = %w(Hz hertz) + hz.aliases = %w[Hz hertz] end # angle RubyUnits::Unit.define('degree') do |deg| deg.definition = RubyUnits::Unit.new(Math::PI / 180.0, 'radian') - deg.aliases = %w(deg degree degrees) + deg.aliases = %w[deg degree degrees] end RubyUnits::Unit.define('gon') do |grad| grad.definition = RubyUnits::Unit.new(Math::PI / 200.0, 'radian') - grad.aliases = %w(gon grad gradian grads) + grad.aliases = %w[gon grad gradian grads] end # rotation @@ -605,7 +605,7 @@ # memory RubyUnits::Unit.define('bit') do |bit| bit.definition = RubyUnits::Unit.new('1/8 byte') - bit.aliases = %w(b bit) + bit.aliases = %w[b bit] end # currency @@ -616,7 +616,7 @@ # luminosity RubyUnits::Unit.define('lumen') do |lumen| lumen.definition = RubyUnits::Unit.new('1 cd*steradian') - lumen.aliases = %w(lm lumen) + lumen.aliases = %w[lm lumen] end RubyUnits::Unit.define('lux') do |lux| @@ -626,27 +626,27 @@ # radiation RubyUnits::Unit.define('gray') do |gray| gray.definition = RubyUnits::Unit.new('1 J/kg') - gray.aliases = %w(Gy gray grays) + gray.aliases = %w[Gy gray grays] end RubyUnits::Unit.define('roentgen') do |roentgen| roentgen.definition = RubyUnits::Unit.new('2.58e-4 C/kg') - roentgen.aliases = %w(R roentgen) + roentgen.aliases = %w[R roentgen] end RubyUnits::Unit.define('sievert') do |sievert| sievert.definition = RubyUnits::Unit.new('1 J/kg') - sievert.aliases = %w(Sv sievert sieverts) + sievert.aliases = %w[Sv sievert sieverts] end RubyUnits::Unit.define('becquerel') do |becquerel| becquerel.definition = RubyUnits::Unit.new('1 1/s') - becquerel.aliases = %w(Bq becquerel becquerels) + becquerel.aliases = %w[Bq becquerel becquerels] end RubyUnits::Unit.define('curie') do |curie| curie.definition = RubyUnits::Unit.new('37 GBq') - curie.aliases = %w(Ci curie curies) + curie.aliases = %w[Ci curie curies] end RubyUnits::Unit.define('count') do |count| @@ -670,43 +670,43 @@ # misc RubyUnits::Unit.define('dozen') do |dozen| dozen.definition = RubyUnits::Unit.new('12 each') - dozen.aliases = %w(doz dz dozen) + dozen.aliases = %w[doz dz dozen] dozen.kind = :counting end RubyUnits::Unit.define('gross') do |gross| gross.definition = RubyUnits::Unit.new('12 dozen') - gross.aliases = %w(gr gross) + gross.aliases = %w[gr gross] gross.kind = :counting end RubyUnits::Unit.define('cell') do |cell| cell.definition = RubyUnits::Unit.new('1 each') - cell.aliases = %w(cells cell) + cell.aliases = %w[cells cell] cell.kind = :counting end RubyUnits::Unit.define('base-pair') do |bp| bp.definition = RubyUnits::Unit.new('1 each') - bp.aliases = %w(bp base-pair) + bp.aliases = %w[bp base-pair] bp.kind = :counting end RubyUnits::Unit.define('nucleotide') do |nt| nt.definition = RubyUnits::Unit.new('1 each') - nt.aliases = %w(nt) + nt.aliases = %w[nt] nt.kind = :counting end RubyUnits::Unit.define('molecule') do |molecule| molecule.definition = RubyUnits::Unit.new('1 each') - molecule.aliases = %w(molecule molecules) + molecule.aliases = %w[molecule molecules] molecule.kind = :counting end RubyUnits::Unit.define('percent') do |percent| percent.definition = RubyUnits::Unit.new('1/100') - percent.aliases = %w(% percent) + percent.aliases = %w[% percent] end RubyUnits::Unit.define('ppm') do |ppm| diff --git a/spec/ruby_units/definition_spec.rb b/spec/ruby_units/definition_spec.rb index 9014ce8e..b9ab7e38 100644 --- a/spec/ruby_units/definition_spec.rb +++ b/spec/ruby_units/definition_spec.rb @@ -16,7 +16,7 @@ describe '#aliases' do subject { super().aliases } - it { is_expected.to eq(%w(eV electron-volt)) } + it { is_expected.to eq(%w[eV electron-volt]) } end describe '#scalar' do diff --git a/spec/ruby_units/temperature_spec.rb b/spec/ruby_units/temperature_spec.rb index b0486447..22135ddf 100644 --- a/spec/ruby_units/temperature_spec.rb +++ b/spec/ruby_units/temperature_spec.rb @@ -4,22 +4,22 @@ describe 'redfine display name' do before(:all) do Unit.redefine!('tempC') do |c| - c.aliases = %w(tC tempC) + c.aliases = %w[tC tempC] c.display_name = 'tC' end Unit.redefine!('tempF') do |f| - f.aliases = %w(tF tempF) + f.aliases = %w[tF tempF] f.display_name = 'tF' end Unit.redefine!('tempR') do |f| - f.aliases = %w(tR tempR) + f.aliases = %w[tR tempR] f.display_name = 'tR' end Unit.redefine!('tempK') do |f| - f.aliases = %w(tK tempK) + f.aliases = %w[tK tempK] f.display_name = 'tK' end end @@ -28,8 +28,8 @@ # define the temp units back to normal Unit.define('tempK') do |unit| unit.scalar = 1 - unit.numerator = %w() - unit.aliases = %w(tempK) + unit.numerator = %w[] + unit.aliases = %w[tempK] unit.kind = :temperature end diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index 3ca80bb1..a1510134 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -6,7 +6,7 @@ it 'has 14 elements' do expect(subject.size).to eq(14) end - %w(kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte).each do |u| + %w[kilogram meter second ampere degK tempK mole candela each dollar steradian radian decibel byte].each do |u| it { is_expected.to include(RubyUnits::Unit.new(u)) } end end @@ -1331,7 +1331,7 @@ end specify { expect(@definition.name).to eq('') } - specify { expect(@definition.aliases).to eq(%w(mph)) } + specify { expect(@definition.aliases).to eq(%w[mph]) } specify { expect(@definition.numerator).to eq(['']) } specify { expect(@definition.denominator).to eq(['']) } specify { expect(@definition.kind).to eq(:speed) } @@ -1351,7 +1351,7 @@ # do this because the unit is not defined at the time this file is parsed, so it fails @jiffy = Unit.define('jiffy') do |jiffy| jiffy.scalar = Rational(1, 100) - jiffy.aliases = %w(jif) + jiffy.aliases = %w[jif] jiffy.numerator = [''] jiffy.kind = :time end @@ -1456,7 +1456,7 @@ before(:each) do @jiffy = Unit.define('jiffy') do |jiffy| jiffy.scalar = (1 / 100) - jiffy.aliases = %w(jif) + jiffy.aliases = %w[jif] jiffy.numerator = [''] jiffy.kind = :time end @@ -1477,7 +1477,7 @@ before(:each) do @jiffy = Unit.define('jiffy') do |jiffy| jiffy.scalar = (1 / 100) - jiffy.aliases = %w(jif) + jiffy.aliases = %w[jif] jiffy.numerator = [''] jiffy.kind = :time end @@ -1721,7 +1721,7 @@ end context 'between a unit and coerceable types' do - specify { expect(RubyUnits::Unit.new('10 kg') + %w(1 kg)).to eq(RubyUnits::Unit.new('11 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') + %w[1 kg]).to eq(RubyUnits::Unit.new('11 kg')) } specify { expect(RubyUnits::Unit.new('10 kg') + '1 kg').to eq(RubyUnits::Unit.new('11 kg')) } end @@ -1756,7 +1756,7 @@ end context 'between a unit and coerceable types' do - specify { expect(RubyUnits::Unit.new('10 kg') - %w(1 kg)).to eq(RubyUnits::Unit.new('9 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg') - %w[1 kg]).to eq(RubyUnits::Unit.new('9 kg')) } specify { expect(RubyUnits::Unit.new('10 kg') - '1 kg').to eq(RubyUnits::Unit.new('9 kg')) } end @@ -1791,7 +1791,7 @@ end context 'between a unit and coerceable types' do - specify { expect(RubyUnits::Unit.new('10 kg') * %w(1 kg)).to eq(RubyUnits::Unit.new('10 kg^2')) } + specify { expect(RubyUnits::Unit.new('10 kg') * %w[1 kg]).to eq(RubyUnits::Unit.new('10 kg^2')) } specify { expect(RubyUnits::Unit.new('10 kg') * '1 kg').to eq(RubyUnits::Unit.new('10 kg^2')) } end @@ -1818,7 +1818,7 @@ end context 'between a unit and coerceable types' do - specify { expect(RubyUnits::Unit.new('10 kg^2') / %w(1 kg)).to eq(RubyUnits::Unit.new('10 kg')) } + specify { expect(RubyUnits::Unit.new('10 kg^2') / %w[1 kg]).to eq(RubyUnits::Unit.new('10 kg')) } specify { expect(RubyUnits::Unit.new('10 kg^2') / '1 kg').to eq(RubyUnits::Unit.new('10 kg')) } end From cb308c1fcc29107b236bffc041d29c9dcb2efeca Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 1 Nov 2017 15:12:02 -0400 Subject: [PATCH 124/150] fixes #159: rational scalars should display as integers when they are equal to integers (#161) --- .rubocop_todo.yml | 23 ++++++++++++++++++++--- Gemfile | 1 + lib/ruby_units/unit.rb | 7 +++++-- spec/ruby_units/unit_spec.rb | 8 ++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d1ff16df..7fc2e627 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,23 +1,38 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-07-11 15:18:46 -0700 using RuboCop version 0.46.0. +# on 2017-10-01 16:04:33 -0400 using RuboCop version 0.49.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideBlockBraces: + Exclude: + - 'spec/ruby_units/unit_spec.rb' + # Offense count: 20 Metrics/AbcSize: Max: 171 +# Offense count: 51 +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/BlockLength: + Max: 969 + # Offense count: 4 +# Configuration parameters: CountBlocks. Metrics/BlockNesting: Max: 4 # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 1082 + Max: 1084 # Offense count: 16 Metrics/CyclomaticComplexity: @@ -57,12 +72,14 @@ Style/Documentation: - 'lib/ruby_units/unit.rb' # Offense count: 1 -# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts. +# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms. +# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS Style/FileName: Exclude: - 'lib/ruby-units.rb' # Offense count: 6 +# Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: format, sprintf, percent Style/FormatString: diff --git a/Gemfile b/Gemfile index 0d6abc98..82b63c9d 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ group :development do gem 'jeweler' gem 'pry' gem 'pry-byebug', platforms: :mri + gem 'terminal-notifier' gem 'terminal-notifier-guard' end diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 90d6a675..f5a13393 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -496,7 +496,7 @@ def initialize(*options) copy(options[0]) return when Hash - @scalar = options[0][:scalar] || 1 + @scalar = (options[0][:scalar] || 1) @numerator = options[0][:numerator] || UNITY_ARRAY @denominator = options[0][:denominator] || UNITY_ARRAY @signature = options[0][:signature] @@ -631,6 +631,7 @@ def to_base # # output is cached so subsequent calls for the same format will be fast # + # @note Rational scalars that are equal to an integer will be represented as integers (i.e, 6/1 => 6, 4/2 => 2, etc..) # @param [Symbol] target_units # @return [String] def to_s(target_units = nil) @@ -668,8 +669,10 @@ def to_s(target_units = nil) end else out = case @scalar - when Rational, Complex + when Complex "#{@scalar}#{separator}#{units}" + when Rational + "#{@scalar == @scalar.to_i ? @scalar.to_i : @scalar}#{separator}#{units}" else "#{'%g' % @scalar}#{separator}#{units}" end.strip diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index a1510134..0a2cd45b 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -781,6 +781,14 @@ end end + describe RubyUnits::Unit.new('6/1 lbs') do + it { is_expected.to be_an_instance_of Unit } + describe '#to_s' do + subject { super().to_s } + it { is_expected.to eq '6 lbs'} + end + end + # rational scalar with compound unit describe RubyUnits::Unit.new('1/2 kg/m') do it { is_expected.to be_an_instance_of Unit } From 8a4256f88443528ab6c7bc97a726aa79dc34a4d4 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 6 Dec 2017 21:51:13 -0500 Subject: [PATCH 125/150] rubocop cleanup --- .codeclimate.yml | 2 +- .rubocop.yml | 8 +- .rubocop_todo.yml | 106 ---------------------- Gemfile | 2 +- lib/ruby_units/unit.rb | 84 ++++++++++++----- lib/ruby_units/unit_definitions/prefix.rb | 2 - spec/ruby_units/unit_spec.rb | 4 +- spec/ruby_units/utf-8/unit_spec.rb | 2 - 8 files changed, 71 insertions(+), 139 deletions(-) delete mode 100644 .rubocop_todo.yml diff --git a/.codeclimate.yml b/.codeclimate.yml index dcaa009b..4bf04a3a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -15,7 +15,7 @@ engines: enabled: true rubocop: enabled: true - channel: rubocop-0-49 + channel: rubocop-0-51 ratings: paths: - "**.rb" diff --git a/.rubocop.yml b/.rubocop.yml index c83e5d7d..287881da 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,3 @@ -inherit_from: .rubocop_todo.yml AllCops: TargetRubyVersion: 2.2 Exclude: @@ -12,3 +11,10 @@ Metrics/LineLength: Enabled: false Style/SingleLineBlockParams: Enabled: false +Naming/FileName: + Exclude: + - 'lib/ruby-units.rb' +Style/FormatString: + Enabled: false +Style/DateTime: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 7fc2e627..00000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,106 +0,0 @@ -# This configuration was generated by -# `rubocop --auto-gen-config` -# on 2017-10-01 16:04:33 -0400 using RuboCop version 0.49.1. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceInsideBlockBraces: - Exclude: - - 'spec/ruby_units/unit_spec.rb' - -# Offense count: 20 -Metrics/AbcSize: - Max: 171 - -# Offense count: 51 -# Configuration parameters: CountComments, ExcludedMethods. -Metrics/BlockLength: - Max: 969 - -# Offense count: 4 -# Configuration parameters: CountBlocks. -Metrics/BlockNesting: - Max: 4 - -# Offense count: 1 -# Configuration parameters: CountComments. -Metrics/ClassLength: - Max: 1084 - -# Offense count: 16 -Metrics/CyclomaticComplexity: - Max: 46 - -# Offense count: 24 -# Configuration parameters: CountComments. -Metrics/MethodLength: - Max: 101 - -# Offense count: 12 -Metrics/PerceivedComplexity: - Max: 48 - -# Offense count: 1 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: nested, compact -Style/ClassAndModuleChildren: - Exclude: - - 'lib/ruby_units/definition.rb' - -# Offense count: 32 -Style/ClassVars: - Exclude: - - 'lib/ruby_units/cache.rb' - - 'lib/ruby_units/unit.rb' - -# Offense count: 6 -Style/Documentation: - Exclude: - - 'spec/**/*' - - 'test/**/*' - - 'lib/ruby_units/array.rb' - - 'lib/ruby_units/cache.rb' - - 'lib/ruby_units/numeric.rb' - - 'lib/ruby_units/string.rb' - - 'lib/ruby_units/unit.rb' - -# Offense count: 1 -# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms. -# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS -Style/FileName: - Exclude: - - 'lib/ruby-units.rb' - -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: format, sprintf, percent -Style/FormatString: - Exclude: - - 'lib/ruby_units/unit.rb' - - 'spec/ruby_units/string_spec.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/NilComparison: - Exclude: - - 'spec/ruby_units/unit_spec.rb' - -# Offense count: 16 -# Cop supports --auto-correct. -Style/PerlBackrefs: - Exclude: - - 'lib/ruby_units/unit.rb' - -# Offense count: 9 -# Cop supports --auto-correct. -Style/RescueModifier: - Exclude: - - 'lib/ruby_units/unit.rb' diff --git a/Gemfile b/Gemfile index 82b63c9d..13ce4450 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,7 @@ end group :test do gem 'rake' gem 'rspec' - gem 'rubocop', '= 0.49.1' # match codeclimate + gem 'rubocop', '~> 0.51.0' # match codeclimate gem 'simplecov' gem 'simplecov-html' end diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index f5a13393..7aed50e4 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1,5 +1,3 @@ -# encoding: utf-8 - require 'date' # Copyright 2006-2015 # @author Kevin C. Olbrich, Ph.D. @@ -334,9 +332,9 @@ def self.parse_into_numbers_and_units(string) when rational # if it has whitespace, it will be of the form '6 1/2' if num =~ RATIONAL_NUMBER - sign = $1 == '-' ? -1 : 1 - n = $2.to_i - f = Rational($3.to_i, $4.to_i) + sign = Regexp.last_match(1) == '-' ? -1 : 1 + n = Regexp.last_match(2).to_i + f = Rational(Regexp.last_match(3).to_i, Regexp.last_match(4).to_i) sign * (n + f) else Rational(*num.split('/').map(&:to_i)) @@ -437,7 +435,11 @@ def copy(from) @base = from.base? @signature = from.signature @base_scalar = from.base_scalar - @unit_name = from.unit_name rescue nil + @unit_name = begin + from.unit_name + rescue + nil + end self end @@ -475,7 +477,11 @@ def initialize(*options) cached = @@cached_units[options[1]] * options[0] copy(cached) rescue - initialize("#{options[0]} #{(options[1].units rescue options[1])}") + initialize("#{options[0]} #{(begin + options[1].units + rescue + options[1] + end)}") end return end @@ -583,7 +589,11 @@ def to_base return base end - cached = ((@@base_unit_cache[units] * scalar) rescue nil) + cached = (begin + (@@base_unit_cache[units] * scalar) + rescue + nil + end) return cached if cached num = [] @@ -654,16 +664,16 @@ def to_s(target_units = nil) '' when /(%[\-+\.\w#]+)\s*(.+)*/ # format string like '%0.2f in' begin - if $2 # unit specified, need to convert - convert_to($2).to_s($1) + if Regexp.last_match(2) # unit specified, need to convert + convert_to(Regexp.last_match(2)).to_s(Regexp.last_match(1)) else - "#{$1 % @scalar}#{separator}#{$2 || units}".strip + "#{Regexp.last_match(1) % @scalar}#{separator}#{Regexp.last_match(2) || units}".strip end rescue # parse it like a strftime format string (DateTime.new(0) + self).strftime(target_units) end when /(\S+)/ # unit only 'mm' or '1/mm' - convert_to($1).to_s + convert_to(Regexp.last_match(1)).to_s else raise 'unhandled case' end @@ -837,7 +847,13 @@ def +(other) RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature) end else - @q ||= (Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) rescue units.to_unit.to_base.scalar) + @q ||= begin + begin + Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) + rescue + units.to_unit.to_base.scalar + end + end RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) end else @@ -874,7 +890,13 @@ def -(other) elsif other.temperature? raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' else - @q ||= (Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) rescue Rational(units.to_unit.scalar, units.to_unit.to_base.scalar)) + @q ||= begin + begin + Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) + rescue + Rational(units.to_unit.scalar, units.to_unit.to_base.scalar) + end + end RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) end else @@ -1071,9 +1093,12 @@ def convert_to(other) if (Unit === other && other.temperature?) || (String === other && other =~ /temp[CFRK]/) raise ArgumentError, 'Receiver is not a temperature unit' unless degree? start_unit = units - target_unit = other.units rescue other - unless @base_scalar - @base_scalar = case @@unit_map[start_unit] + target_unit = begin + other.units + rescue + other + end + @base_scalar ||= case @@unit_map[start_unit] when '' @scalar + 273.15 when '' @@ -1083,7 +1108,6 @@ def convert_to(other) when '' @scalar * Rational(5, 9) end - end q = case @@unit_map[target_unit] when '' @base_scalar - 273.15 @@ -1316,7 +1340,11 @@ def ago def before(time_point = ::Time.now) case time_point when Time, Date, DateTime - return (time_point - self rescue time_point.to_datetime - self) + return (begin + time_point - self + rescue + time_point.to_datetime - self + end) else raise ArgumentError, 'Must specify a Time, Date, or DateTime' end @@ -1360,7 +1388,11 @@ def until(time_point) def from(time_point) case time_point when Time, DateTime, Date - (time_point + self rescue time_point.to_datetime + self) + (begin + time_point + self + rescue + time_point.to_datetime + self + end) else raise ArgumentError, 'Must specify a Time, Date, or DateTime' end @@ -1482,7 +1514,7 @@ def unit_signature # @todo This should either be a separate class or at least a class method def parse(passed_unit_string = '0') unit_string = passed_unit_string.dup - unit_string = "#{$1} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ + unit_string = "#{Regexp.last_match(1)} USD" if unit_string =~ /\$\s*(#{NUMBER_REGEX})/ unit_string.gsub!("\u00b0".force_encoding('utf-8'), 'deg') if unit_string.encoding == Encoding::UTF_8 unit_string.gsub!(/[%'"#]/, '%' => 'percent', "'" => 'feet', '"' => 'inch', '#' => 'pound') @@ -1504,8 +1536,12 @@ def parse(passed_unit_string = '0') end unit_string =~ NUMBER_REGEX - unit = @@cached_units[$2] - mult = ($1.empty? ? 1.0 : $1.to_f) rescue 1.0 + unit = @@cached_units[Regexp.last_match(2)] + mult = begin + (Regexp.last_match(1).empty? ? 1.0 : Regexp.last_match(1).to_f) + rescue + 1.0 + end mult = mult.to_int if mult.to_int == mult if unit copy(unit) @@ -1571,7 +1607,7 @@ def parse(passed_unit_string = '0') end end if bottom - bottom.gsub!(BOTTOM_REGEX) { "#{$1} " * $2.to_i } + bottom.gsub!(BOTTOM_REGEX) { "#{Regexp.last_match(1)} " * Regexp.last_match(2).to_i } # Separate leading decimal from denominator, if any bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] end diff --git a/lib/ruby_units/unit_definitions/prefix.rb b/lib/ruby_units/unit_definitions/prefix.rb index 7dc0f552..852497b7 100644 --- a/lib/ruby_units/unit_definitions/prefix.rb +++ b/lib/ruby_units/unit_definitions/prefix.rb @@ -1,5 +1,3 @@ -# encoding: utf-8 - { 'googol' => [%w[googol], 1e100], 'yobi' => [%w[Yi Yobi yobi], 2**80], diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index 0a2cd45b..c02cd766 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -785,7 +785,7 @@ it { is_expected.to be_an_instance_of Unit } describe '#to_s' do subject { super().to_s } - it { is_expected.to eq '6 lbs'} + it { is_expected.to eq '6 lbs' } end end @@ -1581,7 +1581,7 @@ specify { expect(RubyUnits::Unit.new('1 m')).not_to be_same_as RubyUnits::Unit.new('2 m') } end - specify { expect(RubyUnits::Unit.new('1 m')).not_to be === nil } + specify { expect(RubyUnits::Unit.new('1 m')).not_to be_nil } end context 'Comparisons' do diff --git a/spec/ruby_units/utf-8/unit_spec.rb b/spec/ruby_units/utf-8/unit_spec.rb index a78db837..89e92be9 100644 --- a/spec/ruby_units/utf-8/unit_spec.rb +++ b/spec/ruby_units/utf-8/unit_spec.rb @@ -1,5 +1,3 @@ -# encoding: utf-8 - require File.dirname(__FILE__) + '/../../spec_helper' describe Unit, 'Degrees' do From b97de1cc667c65bcc5a01e6c46b29fc5f48f1b7e Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 6 Dec 2017 22:05:58 -0500 Subject: [PATCH 126/150] update travis configs to report code coverage --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 550a9385..3bde2725 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,11 @@ rvm: - 2.2.8 - ruby-head - jruby-9.1.13.0 -script: bundle exec rake --trace +before_script: + - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter + - chmod +x ./cc-test-reporter + - ./cc-test-reporter before-build +script: bundle exec rake +after_script: + - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT bundler_args: --without development From fc358aa3f248189b74ab5170eabd0edbc68b67e6 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 7 Dec 2017 09:24:40 -0500 Subject: [PATCH 127/150] update changelog --- CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f76fa564..a997c017 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,6 @@ Change Log for Ruby-units ========================= +2017-12-07 2.2.1 * fix an issue with formatting of rational scalars (see #159) 2017-08-07 2.2.0 * add support for ruby 2.4.1 * drop support for ruby 2.1.0 * remove dependency on mathn (see #157) From 21234f5575ae835d316b568e9ee2e69d51fda53c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 7 Dec 2017 09:24:53 -0500 Subject: [PATCH 128/150] Version bump to 2.2.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e3a4f193..fae692e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.0 \ No newline at end of file +2.2.1 \ No newline at end of file From 3db8ab4f483f0b6e9dfb6247dde0872da20c1e06 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Thu, 7 Dec 2017 09:25:42 -0500 Subject: [PATCH 129/150] Regenerate gemspec for version 2.2.1 --- ruby-units.gemspec | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 15da609f..286f237b 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,19 +2,20 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.2.0 ruby lib +# stub: ruby-units 2.2.1 ruby lib Gem::Specification.new do |s| s.name = "ruby-units".freeze - s.version = "2.2.0" + s.version = "2.2.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2017-08-07" + s.date = "2017-12-07" s.description = "Provides classes and methods to perform unit math and conversions".freeze s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] s.extra_rdoc_files = [ + "CHANGELOG.txt", "LICENSE.txt", "README.md" ] @@ -45,7 +46,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units".freeze s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.11".freeze + s.rubygems_version = "2.6.13".freeze s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then @@ -57,6 +58,7 @@ Gem::Specification.new do |s| s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else s.add_dependency(%q.freeze, ["~> 1.0"]) @@ -64,6 +66,7 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end else @@ -72,6 +75,7 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end end From a4c370b80f7ac57ec25cea2ddbe7a04529409222 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 27 Dec 2017 15:31:11 -0500 Subject: [PATCH 130/150] Update ruby versions (#163) * update supported rubygems to include 2.5.0, 2.4.3, 2.3.6, 2.2.9 and jruby 9.1.15.0 --- .ruby-version | 2 +- .travis.yml | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.ruby-version b/.ruby-version index 23a63f52..a6333e40 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.2.8 +2.2.9 diff --git a/.travis.yml b/.travis.yml index 3bde2725..bd9a7f23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,14 @@ sudo: false language: ruby rvm: - - 2.4.2 - - 2.3.5 - - 2.2.8 + - 2.5.0 + - 2.4.3 + - 2.3.6 + - 2.2.9 - ruby-head - - jruby-9.1.13.0 + - jruby-9.1.15.0 +before_install: + - gem update --system before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter From 858097f2496a504e7a1556a4ffddcb331a5db16a Mon Sep 17 00:00:00 2001 From: Jimmy Zhang Date: Wed, 7 Feb 2018 13:25:10 +1100 Subject: [PATCH 131/150] fix: temperature converting rational issue (#164) --- lib/ruby_units/unit.rb | 10 +++++----- spec/ruby_units/temperature_spec.rb | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 7aed50e4..60d31ec9 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1104,19 +1104,19 @@ def convert_to(other) when '' @scalar when '' - (@scalar + 459.67) * Rational(5, 9) + (@scalar + 459.67).to_r * Rational(5, 9) when '' - @scalar * Rational(5, 9) + @scalar.to_r * Rational(5, 9) end q = case @@unit_map[target_unit] when '' - @base_scalar - 273.15 + @base_scalar - 273.15r when '' @base_scalar when '' - @base_scalar * Rational(9, 5) - 459.67 + @base_scalar.to_r * Rational(9, 5) - 459.67r when '' - @base_scalar * Rational(9, 5) + @base_scalar.to_r * Rational(9, 5) end return RubyUnits::Unit.new("#{q} #{target_unit}") else diff --git a/spec/ruby_units/temperature_spec.rb b/spec/ruby_units/temperature_spec.rb index 22135ddf..2f7e8582 100644 --- a/spec/ruby_units/temperature_spec.rb +++ b/spec/ruby_units/temperature_spec.rb @@ -104,6 +104,8 @@ specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempC')).to be_within(RubyUnits::Unit.new('0.01 degC')).of(RubyUnits::Unit.new('-173.15 tempC')) } specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempF')).to be_within(RubyUnits::Unit.new('0.01 degF')).of(RubyUnits::Unit.new('-279.67 tempF')) } specify { expect(RubyUnits::Unit.new('100 tK').convert_to('tempR')).to be_within(RubyUnits::Unit.new('0.01 degR')).of(RubyUnits::Unit.new('180 tempR')) } + + specify { expect(RubyUnits::Unit.new('32 tF').convert_to('tempC')).to eq(RubyUnits::Unit.new('0 tC')) } end end end From 3331de18e65e108bd24c6c15aaf9cab0f73f196c Mon Sep 17 00:00:00 2001 From: Kevin Olbrich <22176+olbrich@users.noreply.github.com> Date: Tue, 6 Mar 2018 17:11:19 -0500 Subject: [PATCH 132/150] Fix add (+) and subtract (-) for BigDecimal scalars. (#167) --- Gemfile | 1 + lib/ruby_units/unit.rb | 18 ++------------- spec/benchmarks/bigdecimal.rb | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 spec/benchmarks/bigdecimal.rb diff --git a/Gemfile b/Gemfile index 13ce4450..6c9f09d2 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ group :development do gem 'jeweler' gem 'pry' gem 'pry-byebug', platforms: :mri + gem 'ruby-prof' gem 'terminal-notifier' gem 'terminal-notifier-guard' end diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 60d31ec9..32d4e188 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -847,14 +847,7 @@ def +(other) RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature) end else - @q ||= begin - begin - Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) - rescue - units.to_unit.to_base.scalar - end - end - RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) + RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units) end else raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" @@ -890,14 +883,7 @@ def -(other) elsif other.temperature? raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' else - @q ||= begin - begin - Rational(@@cached_units[units].scalar, @@cached_units[units].base_scalar) - rescue - Rational(units.to_unit.scalar, units.to_unit.to_base.scalar) - end - end - RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar) * @q, numerator: @numerator, denominator: @denominator, signature: @signature) + RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units) end else raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" diff --git a/spec/benchmarks/bigdecimal.rb b/spec/benchmarks/bigdecimal.rb new file mode 100644 index 00000000..fd243362 --- /dev/null +++ b/spec/benchmarks/bigdecimal.rb @@ -0,0 +1,41 @@ +require_relative '../spec_helper' +require 'bigdecimal' +require 'bigdecimal/util' +require 'benchmark' +require 'ruby-prof' +a = [ + [2.025, "gal"], + [5.575, "gal"], + [8.975, "gal"], + [1.5, "gal"], + [9, "gal"], + [1.85, "gal"], + [2.25, "gal"], + [1.05, "gal"], + [4.725, "gal"], + [3.55, "gal"], + [4.725, "gal"], + [3.75, "gal"], + [6.275, "gal"], + [0.525, "gal"], + [3.475, "gal"], + [0.85, "gal"] +] + +b = a.map{|ns,nu| Unit.new(ns.to_d, nu)} + +result = RubyProf.profile(merge_fibers: true) do + puts b.reduce(:+) +end + +# print a graph profile to text +printer = RubyProf::GraphPrinter.new(result) +printer.print(STDOUT, {}) + +result = RubyProf.profile(merge_fibers: true) do + puts b.reduce(:-) +end + +# print a graph profile to text +printer = RubyProf::GraphPrinter.new(result) +printer.print(STDOUT, {}) From 61f00398d78abc1d281955e5e8a64bcafb1c8fdc Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 6 Mar 2018 17:18:57 -0500 Subject: [PATCH 133/150] Version bump to 2.3.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fae692e4..cc6612c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.1 \ No newline at end of file +2.3.0 \ No newline at end of file From 2b3c927b44bcda0a4d125281eca3f475892888b7 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 6 Mar 2018 17:19:23 -0500 Subject: [PATCH 134/150] Update changelog --- CHANGELOG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a997c017..89b8c95a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,8 @@ Change Log for Ruby-units ========================= +2018-03-06 2.3.0 * Fix add (+) and subtract (-) for BigDecimal scalars. (see #167) + * Update ruby versions (#163) + * fix: temperature converting rational issue (#164) 2017-12-07 2.2.1 * fix an issue with formatting of rational scalars (see #159) 2017-08-07 2.2.0 * add support for ruby 2.4.1 * drop support for ruby 2.1.0 From 413165d4c045ec8fb3b59123b1285135f43e48ba Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Tue, 6 Mar 2018 17:20:14 -0500 Subject: [PATCH 135/150] Regenerate gemspec for version 2.3.0 --- ruby-units.gemspec | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 286f237b..92b541c4 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,16 +2,16 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.2.1 ruby lib +# stub: ruby-units 2.3.0 ruby lib Gem::Specification.new do |s| s.name = "ruby-units".freeze - s.version = "2.2.1" + s.version = "2.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2017-12-07" + s.date = "2018-03-06" s.description = "Provides classes and methods to perform unit math and conversions".freeze s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] s.extra_rdoc_files = [ @@ -46,7 +46,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units".freeze s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.13".freeze + s.rubygems_version = "2.7.4".freeze s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then @@ -58,6 +58,7 @@ Gem::Specification.new do |s| s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, [">= 0"]) else @@ -66,6 +67,7 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end @@ -75,6 +77,7 @@ Gem::Specification.new do |s| s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, [">= 0"]) end From 2e24efb12def67917dff625dfe8bac3ad8e4d429 Mon Sep 17 00:00:00 2001 From: fossabot Date: Thu, 22 Mar 2018 03:31:16 -0700 Subject: [PATCH 136/150] Add license scan report and status Signed-off-by: fossabot --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index fe994568..a1cb5dd5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Ruby Units ========== [![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Folbrich%2Fruby-units.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Folbrich%2Fruby-units?ref=badge_shield) Kevin C. Olbrich, Ph.D. @@ -289,3 +290,7 @@ Ruby units was originally intended to provide a robust and accurate way to do ar In some cases, these conversions can result in the creation and garbage collection of a lot of intermediate objects during calculations. This in turn can have a negative impact on performance. The design of ruby-units has emphasized accuracy over speed. YMMV if you are doing a lot of math involving units. + + +## License +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Folbrich%2Fruby-units.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Folbrich%2Fruby-units?ref=badge_large) \ No newline at end of file From 8c3b1fbd03def7bfd36fd66439107bc333316a08 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich <22176+olbrich@users.noreply.github.com> Date: Thu, 5 Jul 2018 20:04:44 -0400 Subject: [PATCH 137/150] Ruby version support (#169) * Drop build support for ruby 2.2 --- .rubocop.yml | 2 +- .ruby-version | 3 ++- .travis.yml | 15 ++++++++++----- Gemfile | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 287881da..a3dac22a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 2.2 + TargetRubyVersion: 2.3 Exclude: - ruby-units.gemspec - bin/* diff --git a/.ruby-version b/.ruby-version index a6333e40..c52f96ac 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1,2 @@ -2.2.9 +2.3 + diff --git a/.travis.yml b/.travis.yml index bd9a7f23..2914f867 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,13 @@ sudo: false language: ruby rvm: - - 2.5.0 - - 2.4.3 - - 2.3.6 - - 2.2.9 + - 2.5 + - 2.4 + - 2.3 + - jruby-9.1 + - jruby-9.2 + - jruby-head - ruby-head - - jruby-9.1.15.0 before_install: - gem update --system before_script: @@ -17,3 +18,7 @@ script: bundle exec rake after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT bundler_args: --without development +matrix: + allow_failures: + - rvm: ruby-head + - rvm: jruby-head diff --git a/Gemfile b/Gemfile index 6c9f09d2..0e4a02d4 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ group :development do gem 'jeweler' gem 'pry' gem 'pry-byebug', platforms: :mri - gem 'ruby-prof' + gem 'ruby-prof', platforms: :mri gem 'terminal-notifier' gem 'terminal-notifier-guard' end From 1f44b20fbce4cf222b6ee46f6d2545ce103cc31d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich <22176+olbrich@users.noreply.github.com> Date: Wed, 26 Sep 2018 13:21:14 -0400 Subject: [PATCH 138/150] Fix unitless addition and subtraction (#175) When adding or subtracting two unitless numbers, the result used to be converted to the same units as the receiver. This didn't work if the receiver was unitless. The fix changes the way we do the conversion in a way that is not subject to this problem. --- lib/ruby_units/unit.rb | 4 ++-- spec/ruby_units/unit_spec.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 32d4e188..5b03e66c 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -847,7 +847,7 @@ def +(other) RubyUnits::Unit.new(scalar: (other.scalar + convert_to(other.temperature_scale).scalar), numerator: other.numerator, denominator: other.denominator, signature: other.signature) end else - RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units) + RubyUnits::Unit.new(scalar: (base_scalar + other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).convert_to(self) end else raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" @@ -883,7 +883,7 @@ def -(other) elsif other.temperature? raise ArgumentError, 'Cannot subtract a temperature from a differential degree unit' else - RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).to(units) + RubyUnits::Unit.new(scalar: (base_scalar - other.base_scalar), numerator: base.numerator, denominator: base.denominator, signature: @signature).convert_to(self) end else raise ArgumentError, "Incompatible Units ('#{self}' not compatible with '#{other}')" diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index c02cd766..6ea4805f 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -1744,6 +1744,10 @@ context 'between a degree and a temperature' do specify { expect(RubyUnits::Unit.new('100 degK') + RubyUnits::Unit.new('100 tempK')).to eq(RubyUnits::Unit.new('200 tempK')) } end + + context 'between two unitless units' do + specify { expect(RubyUnits::Unit.new('1') + RubyUnits::Unit.new('2')).to eq 3 } + end end context 'subtracting (-)' do @@ -1784,6 +1788,10 @@ context 'between a degree and a temperature' do specify { expect { (RubyUnits::Unit.new('100 degK') - RubyUnits::Unit.new('100 tempK')) }.to raise_error(ArgumentError, 'Cannot subtract a temperature from a differential degree unit') } end + + context 'a unitless unit from another unitless unit' do + specify { expect(RubyUnits::Unit.new('1') - RubyUnits::Unit.new('2')).to eq -1 } + end end context 'multiplying (*)' do From 8067fdd9f63a61c100f105ce40f7d8986d84cbb4 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 26 Sep 2018 13:21:52 -0400 Subject: [PATCH 139/150] Version bump to 2.3.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index cc6612c3..a6254504 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.0 \ No newline at end of file +2.3.1 \ No newline at end of file From 31c440769c9c1ad6bd54beb984f3150a25996b07 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Wed, 26 Sep 2018 13:22:28 -0400 Subject: [PATCH 140/150] Regenerate gemspec for version 2.3.1 --- ruby-units.gemspec | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 92b541c4..511d4363 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -2,20 +2,19 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: ruby-units 2.3.0 ruby lib +# stub: ruby-units 2.3.1 ruby lib Gem::Specification.new do |s| s.name = "ruby-units".freeze - s.version = "2.3.0" + s.version = "2.3.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2018-03-06" + s.date = "2018-09-26" s.description = "Provides classes and methods to perform unit math and conversions".freeze s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] s.extra_rdoc_files = [ - "CHANGELOG.txt", "LICENSE.txt", "README.md" ] @@ -46,7 +45,7 @@ Gem::Specification.new do |s| ] s.homepage = "https://github.com/olbrich/ruby-units".freeze s.licenses = ["MIT".freeze] - s.rubygems_version = "2.7.4".freeze + s.rubygems_version = "2.6.14".freeze s.summary = "A class that performs unit conversions and unit math".freeze if s.respond_to? :specification_version then From be5063aac9929fff866a928f258ac4b29f0388df Mon Sep 17 00:00:00 2001 From: Jaryd Krishnan Date: Sun, 30 Dec 2018 12:39:02 -0600 Subject: [PATCH 141/150] Add ruby 2.6 to travis matrix (#176) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2914f867..1a15193c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ sudo: false language: ruby rvm: + - 2.6 - 2.5 - 2.4 - 2.3 From a7f4845d4254d844d8cc699b95e430dcf2594db5 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich <22176+olbrich@users.noreply.github.com> Date: Sat, 2 Mar 2019 15:53:37 -0500 Subject: [PATCH 142/150] Update travis build (#177) --- .codeclimate.yml | 2 +- .gitignore | 1 + .travis.yml | 2 ++ Gemfile | 22 +++++++++++----------- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 4bf04a3a..2c12d30e 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -15,7 +15,7 @@ engines: enabled: true rubocop: enabled: true - channel: rubocop-0-51 + channel: rubocop-0-63 ratings: paths: - "**.rb" diff --git a/.gitignore b/.gitignore index 715b20d1..e221c19b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ pkg .yardoc +.bundle coverage Gemfile.lock *.rbc diff --git a/.travis.yml b/.travis.yml index 1a15193c..0e6f5a7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ sudo: false language: ruby +cache: bundler +dist: xenial rvm: - 2.6 - 2.5 diff --git a/Gemfile b/Gemfile index 0e4a02d4..aa30124b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,22 +1,22 @@ source 'https://rubygems.org' -ruby RUBY_VERSION - group :development do - gem 'bundler', '~> 1.0' - gem 'guard-rspec' - gem 'jeweler' + gem 'bundler' + gem 'guard-rspec', require: false + gem 'jeweler', require: false + gem 'pry-byebug', platform: :mri gem 'pry' - gem 'pry-byebug', platforms: :mri - gem 'ruby-prof', platforms: :mri - gem 'terminal-notifier' + gem 'rubocop', '~> 0.63.0', require: false # match codeclimate + gem 'ruby-maven', platform: :jruby + gem 'ruby-prof', platform: :mri gem 'terminal-notifier-guard' + gem 'terminal-notifier' end group :test do - gem 'rake' + gem 'rake', require: false gem 'rspec' - gem 'rubocop', '~> 0.51.0' # match codeclimate + gem 'simplecov-html', require: false gem 'simplecov' - gem 'simplecov-html' + gem 'wwtd', require: false end From e5901da3594f138afeaa507cb06d0204bed1639f Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 2 Mar 2019 23:02:49 -0500 Subject: [PATCH 143/150] Restructure gem and gemspec to eliminate need for jeweler --- .gitignore | 23 ++- .rspec | 2 + CODE_OF_CONDUCT.md | 74 ++++++++++ Gemfile | 17 +-- Gemfile.lock | 173 ++++++++++++++++++++++ Gemfile.tmp | 22 +++ LICENSE.txt | 35 ++--- README.md.tmp | 291 ++++++++++++++++++++++++++++++++++++++ Rakefile | 29 +--- Rakefile.tmp | 27 ++++ VERSION | 1 - bin/console | 14 ++ bin/rake | 16 +++ bin/rubocop | 29 ++++ bin/setup | 8 ++ lib/ruby_units/unit.rb | 1 - lib/ruby_units/version.rb | 5 +- ruby-units.gemspec | 112 +++++---------- ruby-units.gemspec.tmp | 84 +++++++++++ spec/spec_helper.rb | 2 +- 20 files changed, 814 insertions(+), 151 deletions(-) create mode 100644 .rspec create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Gemfile.lock create mode 100644 Gemfile.tmp create mode 100644 README.md.tmp create mode 100644 Rakefile.tmp delete mode 100644 VERSION create mode 100755 bin/console create mode 100755 bin/rake create mode 100755 bin/rubocop create mode 100755 bin/setup create mode 100644 ruby-units.gemspec.tmp diff --git a/.gitignore b/.gitignore index e221c19b..b04a8c84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,11 @@ -pkg -.yardoc -.bundle -coverage -Gemfile.lock -*.rbc -.rspec -.rvmrc -.rbx -.idea -doc -bin -tmp +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +# rspec failure tracking +.rspec_status diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..83e16f80 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..ba00be10 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at kevin.olbrich@mckesson.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Gemfile b/Gemfile index aa30124b..ee75b366 100644 --- a/Gemfile +++ b/Gemfile @@ -1,22 +1,17 @@ -source 'https://rubygems.org' +source "https://rubygems.org" group :development do - gem 'bundler' - gem 'guard-rspec', require: false - gem 'jeweler', require: false gem 'pry-byebug', platform: :mri - gem 'pry' - gem 'rubocop', '~> 0.63.0', require: false # match codeclimate gem 'ruby-maven', platform: :jruby gem 'ruby-prof', platform: :mri - gem 'terminal-notifier-guard' - gem 'terminal-notifier' end +# This is a minimal set of Gems required to build on travis group :test do - gem 'rake', require: false + gem 'bundler' + gem 'rake' gem 'rspec' - gem 'simplecov-html', require: false gem 'simplecov' - gem 'wwtd', require: false end + +gemspec diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..9d688b6b --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,173 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.4.0) + ast (2.4.0) + builder (3.2.3) + byebug (10.0.2) + coderay (1.1.2) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) + diff-lcs (1.3) + docile (1.3.1) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + ffi (1.9.25) + ffi (1.9.25-java) + formatador (0.2.5) + git (1.5.0) + github_api (0.16.0) + addressable (~> 2.4.0) + descendants_tracker (~> 0.0.4) + faraday (~> 0.8, < 0.10) + hashie (>= 3.4) + mime-types (>= 1.16, < 3.0) + oauth2 (~> 1.0) + guard (2.14.2) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) + hashie (3.6.0) + highline (2.0.0) + jar-dependencies (0.3.12) + jaro_winkler (1.5.2) + jaro_winkler (1.5.2-java) + jeweler (2.3.9) + builder + bundler + git (>= 1.2.5) + github_api (~> 0.16.0) + highline (>= 1.6.15) + nokogiri (>= 1.5.10) + psych + rake + rdoc + semver2 + json (2.1.0) + json (2.1.0-java) + jwt (1.5.6) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + lumberjack (1.0.13) + method_source (0.9.0) + mime-types (2.99.3) + mini_portile2 (2.3.0) + multi_json (1.13.1) + multi_xml (0.6.0) + multipart-post (2.0.0) + nenv (0.3.0) + nokogiri (1.8.4) + mini_portile2 (~> 2.3.0) + nokogiri (1.8.4-java) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + parallel (1.14.0) + parser (2.6.0.0) + ast (~> 2.4.0) + powerpack (0.1.2) + pry (0.11.3) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry (0.11.3-java) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + spoon (~> 0.0) + pry-byebug (3.6.0) + byebug (~> 10.0) + pry (~> 0.10) + psych (3.0.2) + psych (3.0.2-java) + jar-dependencies (>= 0.1.7) + rack (2.0.5) + rainbow (3.0.0) + rake (12.3.1) + rb-fsevent (0.10.3) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + rdoc (6.0.4) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-support (3.8.0) + rubocop (0.63.1) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.5, != 2.5.1.1) + powerpack (~> 0.1) + rainbow (>= 2.2.2, < 4.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.4.0) + ruby-maven (3.3.12) + ruby-maven-libs (~> 3.3.9) + ruby-maven-libs (3.3.9) + ruby-prof (0.17.0) + ruby-progressbar (1.10.0) + ruby_dep (1.5.0) + semver2 (3.4.2) + shellany (0.0.1) + simplecov (0.16.1) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + spoon (0.0.6) + ffi + terminal-notifier (2.0.0) + terminal-notifier-guard (1.7.0) + thor (0.20.0) + thread_safe (0.3.6) + thread_safe (0.3.6-java) + unicode-display_width (1.4.1) + wwtd (1.3.0) + +PLATFORMS + java + ruby + +DEPENDENCIES + bundler + guard-rspec + jeweler + pry + pry-byebug + rake + rspec + rubocop (~> 0.63.0) + ruby-maven + ruby-prof + simplecov + simplecov-html + terminal-notifier + terminal-notifier-guard + wwtd + +BUNDLED WITH + 1.17.3 diff --git a/Gemfile.tmp b/Gemfile.tmp new file mode 100644 index 00000000..aa30124b --- /dev/null +++ b/Gemfile.tmp @@ -0,0 +1,22 @@ +source 'https://rubygems.org' + +group :development do + gem 'bundler' + gem 'guard-rspec', require: false + gem 'jeweler', require: false + gem 'pry-byebug', platform: :mri + gem 'pry' + gem 'rubocop', '~> 0.63.0', require: false # match codeclimate + gem 'ruby-maven', platform: :jruby + gem 'ruby-prof', platform: :mri + gem 'terminal-notifier-guard' + gem 'terminal-notifier' +end + +group :test do + gem 'rake', require: false + gem 'rspec' + gem 'simplecov-html', require: false + gem 'simplecov' + gem 'wwtd', require: false +end diff --git a/LICENSE.txt b/LICENSE.txt index 4ccbfebf..8f6b4010 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,20 +1,21 @@ -Copyright (c) 2006-2012 Kevin C. Olbrich, Ph.D. +The MIT License (MIT) -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Copyright (c) 2019 Kevin Olbrich -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md.tmp b/README.md.tmp new file mode 100644 index 00000000..fe994568 --- /dev/null +++ b/README.md.tmp @@ -0,0 +1,291 @@ +Ruby Units +========== + +[![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) + +Kevin C. Olbrich, Ph.D. + +Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) + +Notes +----- + +This version removes 'mathn' as a dependency. Mathn alters the behavior of some mathematical operators, which +frequently causes unexpected behavior and can be a source of difficult to diagnose bugs. Mathn is also scheduled to be removed from +the Ruby standard library. + +Introduction +------------ + +Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors. + +Solution +-------- + +The 'Ruby units' gem is designed to simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result. + +Installation: +------------- + +This package may be installed using: `gem install ruby-units` + +Usage: +------ + +``` +unit = Unit.new("1") # constant only +unit = Unit.new("mm") # unit only (defaults to a scalar of 1) +unit = Unit.new("1 mm") # create a simple unit +unit = Unit.new("1 mm/s") # a compound unit +unit = Unit.new("1 mm s^-1") # in exponent notation +unit = Unit.new("1 kg*m^2/s^2") # complex unit +unit = Unit.new("1 kg m^2 s^-2") # complex unit +unit = Unit.new("1 mm") # shorthand +unit = "1 mm".to_unit # convert string object +unit = object.to_unit # convert any object using object.to_s +unit = Unit.new('1/4 cup') # Rational number +unit = Unit.new('1+1i mm') # Complex Number +``` + +Rules: +------ + +1. only 1 quantity per unit (with 2 exceptions... 6'5" and '8 lbs 8 oz') +2. use SI notation when possible +3. spaces in units are allowed, but ones like '11/m' will be recognized as '11 1/m'. + +Unit compatibility: +------------------- + +Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. + +``` +unit1 =~ unit2 #=> true if units are compatible +unit1.compatible?(unit2) #=> true if units are compatible +``` + +Unit Math: +---------- + +``` +Unit#+() # Add. only works if units are compatible +Unit#-() # Subtract. only works if units are compatible +Unit#*() # Multiply. +Unit#/() # Divide. +Unit#**() # Exponentiate. Exponent must be an integer, can be positive, negative, or zero +Unit#inverse # Returns 1/unit +Unit#abs # Returns absolute value of the unit quantity. Strips off the units +Unit#ceil # rounds quantity to next highest integer +Unit#floor # rounds quantity down to next lower integer +Unit#round # rounds quantity to nearest integer +Unit#to_int # returns the quantity as an integer +``` + +Unit will coerce other objects into a Unit if used in a formula. This means that .. + +``` +Unit.new("1 mm") + "2 mm" == Unit.new("3 mm") +``` + +This will work as expected so long as you start the formula with a Unit object. + +Conversions & comparisons +------------------------- + +Units can be converted to other units in a couple of ways. + +``` +unit.convert_to('ft') # convert +unit1 = unit >> "ft" # convert to 'feet' +unit >>= "ft" # convert and overwrite original object +unit3 = unit1 + unit2 # resulting object will have the units of unit1 +unit3 = unit1 - unit2 # resulting object will have the units of unit1 +unit1 <=> unit2 # does comparison on quantities in base units, throws an exception if not compatible +unit1 === unit2 # true if units and quantity are the same, even if 'equivalent' by <=> +unit1 + unit2 >> "ft" # converts result of math to 'ft' +(unit1 + unit2).convert_to('ft') # converts result to 'ft' +``` + +Any object that defines a 'to_unit' method will be automatically coerced to a unit during calculations. + +Text Output +----------- + +Units will display themselves nicely based on the display_name for the units and prefixes. Since Unit implements a Unit#to_s, all that is needed in most cases is: + +``` +"#{Unit.new('1 mm')}" #=> "1 mm" +``` + +The to_s also accepts some options. + +``` +Unit.new('1.5 mm').to_s("%0.2f") # "1.50 mm". Enter any valid format + string. Also accepts strftime format +Unit.new('1.5 mm').to_s("in") # converts to inches before printing +Unit.new("2 m").to_s(:ft) # returns 6'7" +Unit.new("100 kg").to_s(:lbs) # returns 220 lbs, 7 oz +Unit.new("100 kg").to_s(:stone) # returns 15 stone, 10 lb +``` + +Time Helpers +------------ + +Time, Date, and DateTime objects can have time units added or subtracted. + +``` +Time.now + Unit.new("10 min") +``` + +Several helpers have also been defined. Note: If you include the 'Chronic' gem, you can specify times in natural language. + +``` + Unit.new('min').since(DateTime.parse('9/18/06 3:00pm')) +``` + +Durations may be entered as 'HH:MM:SS, usec' and will be returned in 'hours'. + +``` +Unit.new('1:00') #=> 1 h +Unit.new('0:30') #=> 0.5 h +Unit.new('0:30:30') #=> 0.5 h + 30 sec +``` + +If only one ":" is present, it is interpreted as the separator between hours and minutes. + +Ranges +------ + +``` +[Unit.new('0 h')..Unit.new('10 h')].each {|x| p x} +``` + +works so long as the starting point has an integer scalar + +Math functions +-------------- + +All Trig math functions (sin, cos, sinh, hypot...) can take a unit as their parameter. It will be converted to radians and then used if possible. + +Temperatures +------------ + +Ruby-units makes a distinction between a temperature (which technically is a property) and degrees of temperature (which temperatures are measured in). + +Temperature units (i.e., 'tempK') can be converted back and forth, and will take into account the differences in the zero points of the various scales. Differential temperature (e.g., Unit.new('100 degC')) units behave like most other units. + +``` +Unit.new('37 tempC').convert_to('tempF') #=> 98.6 tempF +``` + +Ruby-units will raise an exception if you attempt to create a temperature unit that would fall below absolute zero. + +Unit math on temperatures is fairly limited. + +``` +Unit.new('100 tempC') + Unit.new('10 degC') # '110 tempC'.to_unit +Unit.new('100 tempC') - Unit.new('10 degC') # '90 tempC'.to_unit +Unit.new('100 tempC') + Unit.new('50 tempC') # exception (can't add two temperatures) +Unit.new('100 tempC') - Unit.new('50 tempC') # '50 degC'.to_unit (get the difference between two temperatures) +Unit.new('50 tempC') - Unit.new('100 tempC') # '-50 degC'.to_unit +Unit.new('100 tempC') * scalar # '100*scalar tempC'.to_unit +Unit.new('100 tempC') / scalar # '100/scalar tempC'.to_unit +Unit.new('100 tempC') * unit # exception +Unit.new('100 tempC') / unit # exception +Unit.new('100 tempC') ** N # exception + +Unit.new('100 tempC').convert_to('degC') #=> Unit.new('100 degC') +``` + +This conversion references the 0 point on the scale of the temperature unit + +``` +Unit.new('100 degC').convert_to('tempC') #=> '-173 tempC'.to_unit +``` + +These conversions are always interpreted as being relative to absolute zero. Conversions are probably better done like this... + +``` +Unit.new('0 tempC') + Unit.new('100 degC') #=> Unit.new('100 tempC') +``` + +Defining Units +-------------- + +It is possible to define new units or redefine existing ones. + +### Define New Unit + +The easiest approach is to define a unit in terms of other units. + +``` +Unit.define("foobar") do |foobar| + foobar.definition = Unit.new("1 foo") * Unit.new("1 bar") # anything that results in a Unit object + foobar.aliases = %w{foobar fb} # array of synonyms for the unit + foobar.display_name = "Foobar" # How unit is displayed when output +end +``` + +### Redefine Existing Unit + +Redefining a unit allows the user to change a single aspect of a definition without having to re-create the entire definition. This is useful for changing display names, adding aliases, etc. + +``` +Unit.redefine!("cup") do |cup| + cup.display_name = "cup" +end +``` + +### Useful methods + +1. `scalar` will return the numeric portion of the unit without the attached units +2. `base_scalar` will return the scalar in base units (SI) +3. `units` will return the name of the units (without the scalar) +4. `base` will return the unit converted to base units (SI) + +### Storing in a database + +Units can be stored in a database as either the string representation or in two separate columns defining the scalar and the units. +Note that if sorting by units is desired you will want to ensure that you are storing the scalars in a consistent unit (i.e, the base units). + +### Namespaced Class + +Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatibility, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. + +To load ruby-units without this alias... + +``` +require 'ruby_units/namespaced' +``` + +When using bundler... + +``` +gem 'ruby-units', require: 'ruby_units/namespaced' +``` + +Note: when using the namespaced version, the Unit.new('unit string') helper will not be defined. + +### Configuration + +Configuration options can be set like: + +``` +RubyUnits.configure do |config| + config.separator = false +end +``` + +Currently there is only one configuration you can set: + +1. separator (true/false): should a space be used to separate the scalar from the unit part during output. + + +### NOTES + +#### Performance vs. Accuracy + +Ruby units was originally intended to provide a robust and accurate way to do arbitrary unit conversions. +In some cases, these conversions can result in the creation and garbage collection of a lot of intermediate objects during +calculations. This in turn can have a negative impact on performance. The design of ruby-units has emphasized accuracy +over speed. YMMV if you are doing a lot of math involving units. diff --git a/Rakefile b/Rakefile index 03ee1541..b7e9ed54 100644 --- a/Rakefile +++ b/Rakefile @@ -1,27 +1,6 @@ -require 'rubygems' -require 'rake' -require 'rake/testtask' -require './lib/ruby-units' +require "bundler/gem_tasks" +require "rspec/core/rake_task" -begin - require 'jeweler' - Jeweler::Tasks.new do |gem| - gem.name = 'ruby-units' - gem.summary = 'A class that performs unit conversions and unit math' - gem.description = 'Provides classes and methods to perform unit math and conversions' - gem.authors = ['Kevin Olbrich, Ph.D.'] - gem.email = ['kevin.olbrich+ruby_units@gmail.com'] - gem.homepage = 'https://github.com/olbrich/ruby-units' - gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile', 'Guardfile') - gem.license = 'MIT' - end - Jeweler::GemcutterTasks.new -rescue LoadError - puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler' -end +RSpec::Core::RakeTask.new(:spec) -require 'rspec/core/rake_task' -desc 'Run specs' -RSpec::Core::RakeTask.new - -task default: :spec +task :default => :spec diff --git a/Rakefile.tmp b/Rakefile.tmp new file mode 100644 index 00000000..03ee1541 --- /dev/null +++ b/Rakefile.tmp @@ -0,0 +1,27 @@ +require 'rubygems' +require 'rake' +require 'rake/testtask' +require './lib/ruby-units' + +begin + require 'jeweler' + Jeweler::Tasks.new do |gem| + gem.name = 'ruby-units' + gem.summary = 'A class that performs unit conversions and unit math' + gem.description = 'Provides classes and methods to perform unit math and conversions' + gem.authors = ['Kevin Olbrich, Ph.D.'] + gem.email = ['kevin.olbrich+ruby_units@gmail.com'] + gem.homepage = 'https://github.com/olbrich/ruby-units' + gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile', 'Guardfile') + gem.license = 'MIT' + end + Jeweler::GemcutterTasks.new +rescue LoadError + puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler' +end + +require 'rspec/core/rake_task' +desc 'Run specs' +RSpec::Core::RakeTask.new + +task default: :spec diff --git a/VERSION b/VERSION deleted file mode 100644 index a6254504..00000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.3.1 \ No newline at end of file diff --git a/bin/console b/bin/console new file mode 100755 index 00000000..f8bb9ce1 --- /dev/null +++ b/bin/console @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "ruby/units" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/bin/rake b/bin/rake new file mode 100755 index 00000000..26c7a2d5 --- /dev/null +++ b/bin/rake @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rake', 'rake') diff --git a/bin/rubocop b/bin/rubocop new file mode 100755 index 00000000..d0c48829 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..dce67d86 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index 5b03e66c..b1864f97 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -22,7 +22,6 @@ # module RubyUnits class Unit < Numeric - VERSION = Unit::Version::STRING @@definitions = {} @@prefix_values = {} @@prefix_map = {} diff --git a/lib/ruby_units/version.rb b/lib/ruby_units/version.rb index 81b19556..fad81d01 100644 --- a/lib/ruby_units/version.rb +++ b/lib/ruby_units/version.rb @@ -1,8 +1,5 @@ module RubyUnits class Unit < Numeric - # Pull the version number from the VERSION file - module Version - STRING = File.read(File.dirname(__FILE__) + '/../../VERSION') - end + VERSION = "2.3.1" end end diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 511d4363..067fcc65 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -1,84 +1,40 @@ -# Generated by jeweler -# DO NOT EDIT THIS FILE DIRECTLY -# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' -# -*- encoding: utf-8 -*- -# stub: ruby-units 2.3.1 ruby lib +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'ruby_units/version' -Gem::Specification.new do |s| - s.name = "ruby-units".freeze - s.version = "2.3.1" +Gem::Specification.new do |spec| + spec.name = 'ruby-units' + spec.version = RubyUnits::Unit::VERSION + spec.authors = ['Kevin Olbrich'] + spec.email = ['kevin.olbrich@gmail.com'] - s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= - s.require_paths = ["lib".freeze] - s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2018-09-26" - s.description = "Provides classes and methods to perform unit math and conversions".freeze - s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] - s.extra_rdoc_files = [ - "LICENSE.txt", - "README.md" - ] - s.files = [ - "CHANGELOG.txt", - "LICENSE.txt", - "README.md", - "Rakefile", - "VERSION", - "lib/ruby-units.rb", - "lib/ruby_units/array.rb", - "lib/ruby_units/cache.rb", - "lib/ruby_units/configuration.rb", - "lib/ruby_units/date.rb", - "lib/ruby_units/definition.rb", - "lib/ruby_units/math.rb", - "lib/ruby_units/namespaced.rb", - "lib/ruby_units/numeric.rb", - "lib/ruby_units/string.rb", - "lib/ruby_units/time.rb", - "lib/ruby_units/unit.rb", - "lib/ruby_units/unit_definitions.rb", - "lib/ruby_units/unit_definitions/base.rb", - "lib/ruby_units/unit_definitions/prefix.rb", - "lib/ruby_units/unit_definitions/standard.rb", - "lib/ruby_units/version.rb", - "ruby-units.gemspec" - ] - s.homepage = "https://github.com/olbrich/ruby-units".freeze - s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.14".freeze - s.summary = "A class that performs unit conversions and unit math".freeze + spec.required_rubygems_version = '>= 2.0' + spec.required_ruby_version = '>= 2.3' + spec.summary = 'Provides classes and methods to perform unit math and conversions' + spec.description = 'Provides classes and methods to perform unit math and conversions' + spec.homepage = 'https://github.com/olbrich/ruby-units' + spec.license = 'MIT' - if s.respond_to? :specification_version then - s.specification_version = 4 + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://github.com/olbrich/ruby-units' + spec.metadata['changelog_uri'] = 'https://github.com/olbrich/ruby-units/releases' - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q.freeze, ["~> 1.0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - else - s.add_dependency(%q.freeze, ["~> 1.0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - end - else - s.add_dependency(%q.freeze, ["~> 1.0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } end -end + spec.require_paths = ['lib'] + spec.add_development_dependency 'guard-rspec' + spec.add_development_dependency 'pry' + spec.add_development_dependency 'rubocop', '~> 0.63.0' # match codeclimate + spec.add_development_dependency 'simplecov-html' + spec.add_development_dependency 'simplecov' + spec.add_development_dependency 'terminal-notifier-guard' + spec.add_development_dependency 'terminal-notifier' + spec.add_development_dependency 'wwtd' + spec.add_development_dependency 'bundler' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rspec', '~> 3.0' +end diff --git a/ruby-units.gemspec.tmp b/ruby-units.gemspec.tmp new file mode 100644 index 00000000..511d4363 --- /dev/null +++ b/ruby-units.gemspec.tmp @@ -0,0 +1,84 @@ +# Generated by jeweler +# DO NOT EDIT THIS FILE DIRECTLY +# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' +# -*- encoding: utf-8 -*- +# stub: ruby-units 2.3.1 ruby lib + +Gem::Specification.new do |s| + s.name = "ruby-units".freeze + s.version = "2.3.1" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["Kevin Olbrich, Ph.D.".freeze] + s.date = "2018-09-26" + s.description = "Provides classes and methods to perform unit math and conversions".freeze + s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] + s.extra_rdoc_files = [ + "LICENSE.txt", + "README.md" + ] + s.files = [ + "CHANGELOG.txt", + "LICENSE.txt", + "README.md", + "Rakefile", + "VERSION", + "lib/ruby-units.rb", + "lib/ruby_units/array.rb", + "lib/ruby_units/cache.rb", + "lib/ruby_units/configuration.rb", + "lib/ruby_units/date.rb", + "lib/ruby_units/definition.rb", + "lib/ruby_units/math.rb", + "lib/ruby_units/namespaced.rb", + "lib/ruby_units/numeric.rb", + "lib/ruby_units/string.rb", + "lib/ruby_units/time.rb", + "lib/ruby_units/unit.rb", + "lib/ruby_units/unit_definitions.rb", + "lib/ruby_units/unit_definitions/base.rb", + "lib/ruby_units/unit_definitions/prefix.rb", + "lib/ruby_units/unit_definitions/standard.rb", + "lib/ruby_units/version.rb", + "ruby-units.gemspec" + ] + s.homepage = "https://github.com/olbrich/ruby-units".freeze + s.licenses = ["MIT".freeze] + s.rubygems_version = "2.6.14".freeze + s.summary = "A class that performs unit conversions and unit math".freeze + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q.freeze, ["~> 1.0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + else + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + end + else + s.add_dependency(%q.freeze, ["~> 1.0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) + end +end + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ff080a1d..8fe3372a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,9 @@ require 'rubygems' +require 'simplecov' require 'bundler/setup' Bundler.require(:development, :test) require 'rspec/core' -require 'simplecov' SimpleCov.start do add_filter '/spec/' add_filter '/test/' From 9ec26267f1d9a2e8533bb5e3cc30f4a56eaf6f40 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 2 Mar 2019 23:06:31 -0500 Subject: [PATCH 144/150] don't checkin lock file --- .gitignore | 3 + Gemfile.lock | 173 --------------------------------------------------- 2 files changed, 3 insertions(+), 173 deletions(-) delete mode 100644 Gemfile.lock diff --git a/.gitignore b/.gitignore index b04a8c84..607dea85 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ # rspec failure tracking .rspec_status + +# don't check in Gemfile.lock for a gem +Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 9d688b6b..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,173 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.4.0) - ast (2.4.0) - builder (3.2.3) - byebug (10.0.2) - coderay (1.1.2) - descendants_tracker (0.0.4) - thread_safe (~> 0.3, >= 0.3.1) - diff-lcs (1.3) - docile (1.3.1) - faraday (0.9.2) - multipart-post (>= 1.2, < 3) - ffi (1.9.25) - ffi (1.9.25-java) - formatador (0.2.5) - git (1.5.0) - github_api (0.16.0) - addressable (~> 2.4.0) - descendants_tracker (~> 0.0.4) - faraday (~> 0.8, < 0.10) - hashie (>= 3.4) - mime-types (>= 1.16, < 3.0) - oauth2 (~> 1.0) - guard (2.14.2) - formatador (>= 0.2.4) - listen (>= 2.7, < 4.0) - lumberjack (>= 1.0.12, < 2.0) - nenv (~> 0.1) - notiffany (~> 0.0) - pry (>= 0.9.12) - shellany (~> 0.0) - thor (>= 0.18.1) - guard-compat (1.2.1) - guard-rspec (4.7.3) - guard (~> 2.1) - guard-compat (~> 1.1) - rspec (>= 2.99.0, < 4.0) - hashie (3.6.0) - highline (2.0.0) - jar-dependencies (0.3.12) - jaro_winkler (1.5.2) - jaro_winkler (1.5.2-java) - jeweler (2.3.9) - builder - bundler - git (>= 1.2.5) - github_api (~> 0.16.0) - highline (>= 1.6.15) - nokogiri (>= 1.5.10) - psych - rake - rdoc - semver2 - json (2.1.0) - json (2.1.0-java) - jwt (1.5.6) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - lumberjack (1.0.13) - method_source (0.9.0) - mime-types (2.99.3) - mini_portile2 (2.3.0) - multi_json (1.13.1) - multi_xml (0.6.0) - multipart-post (2.0.0) - nenv (0.3.0) - nokogiri (1.8.4) - mini_portile2 (~> 2.3.0) - nokogiri (1.8.4-java) - notiffany (0.1.1) - nenv (~> 0.1) - shellany (~> 0.0) - oauth2 (1.4.0) - faraday (>= 0.8, < 0.13) - jwt (~> 1.0) - multi_json (~> 1.3) - multi_xml (~> 0.5) - rack (>= 1.2, < 3) - parallel (1.14.0) - parser (2.6.0.0) - ast (~> 2.4.0) - powerpack (0.1.2) - pry (0.11.3) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry (0.11.3-java) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - spoon (~> 0.0) - pry-byebug (3.6.0) - byebug (~> 10.0) - pry (~> 0.10) - psych (3.0.2) - psych (3.0.2-java) - jar-dependencies (>= 0.1.7) - rack (2.0.5) - rainbow (3.0.0) - rake (12.3.1) - rb-fsevent (0.10.3) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) - rdoc (6.0.4) - rspec (3.8.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-core (3.8.0) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.0) - rubocop (0.63.1) - jaro_winkler (~> 1.5.1) - parallel (~> 1.10) - parser (>= 2.5, != 2.5.1.1) - powerpack (~> 0.1) - rainbow (>= 2.2.2, < 4.0) - ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.4.0) - ruby-maven (3.3.12) - ruby-maven-libs (~> 3.3.9) - ruby-maven-libs (3.3.9) - ruby-prof (0.17.0) - ruby-progressbar (1.10.0) - ruby_dep (1.5.0) - semver2 (3.4.2) - shellany (0.0.1) - simplecov (0.16.1) - docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - spoon (0.0.6) - ffi - terminal-notifier (2.0.0) - terminal-notifier-guard (1.7.0) - thor (0.20.0) - thread_safe (0.3.6) - thread_safe (0.3.6-java) - unicode-display_width (1.4.1) - wwtd (1.3.0) - -PLATFORMS - java - ruby - -DEPENDENCIES - bundler - guard-rspec - jeweler - pry - pry-byebug - rake - rspec - rubocop (~> 0.63.0) - ruby-maven - ruby-prof - simplecov - simplecov-html - terminal-notifier - terminal-notifier-guard - wwtd - -BUNDLED WITH - 1.17.3 From 230dbf9e551101a10a9ba96b8f0a3b5822ace051 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 2 Mar 2019 23:09:52 -0500 Subject: [PATCH 145/150] delete some temp files --- Gemfile.tmp | 22 ---- README.md.tmp | 291 ----------------------------------------- ruby-units.gemspec.tmp | 84 ------------ 3 files changed, 397 deletions(-) delete mode 100644 Gemfile.tmp delete mode 100644 README.md.tmp delete mode 100644 ruby-units.gemspec.tmp diff --git a/Gemfile.tmp b/Gemfile.tmp deleted file mode 100644 index aa30124b..00000000 --- a/Gemfile.tmp +++ /dev/null @@ -1,22 +0,0 @@ -source 'https://rubygems.org' - -group :development do - gem 'bundler' - gem 'guard-rspec', require: false - gem 'jeweler', require: false - gem 'pry-byebug', platform: :mri - gem 'pry' - gem 'rubocop', '~> 0.63.0', require: false # match codeclimate - gem 'ruby-maven', platform: :jruby - gem 'ruby-prof', platform: :mri - gem 'terminal-notifier-guard' - gem 'terminal-notifier' -end - -group :test do - gem 'rake', require: false - gem 'rspec' - gem 'simplecov-html', require: false - gem 'simplecov' - gem 'wwtd', require: false -end diff --git a/README.md.tmp b/README.md.tmp deleted file mode 100644 index fe994568..00000000 --- a/README.md.tmp +++ /dev/null @@ -1,291 +0,0 @@ -Ruby Units -========== - -[![Build Status](https://secure.travis-ci.org/olbrich/ruby-units.png)](http://travis-ci.org/olbrich/ruby-units) - -Kevin C. Olbrich, Ph.D. - -Project page: [http://github.com/olbrich/ruby-units](http://github.com/olbrich/ruby-units) - -Notes ------ - -This version removes 'mathn' as a dependency. Mathn alters the behavior of some mathematical operators, which -frequently causes unexpected behavior and can be a source of difficult to diagnose bugs. Mathn is also scheduled to be removed from -the Ruby standard library. - -Introduction ------------- - -Many technical applications make use of specialized calculations at some point. Frequently, these calculations require unit conversions to ensure accurate results. Needless to say, this is a pain to properly keep track of, and is prone to numerous errors. - -Solution --------- - -The 'Ruby units' gem is designed to simplify the handling of units for scientific calculations. The units of each quantity are specified when a Unit object is created and the Unit class will handle all subsequent conversions and manipulations to ensure an accurate result. - -Installation: -------------- - -This package may be installed using: `gem install ruby-units` - -Usage: ------- - -``` -unit = Unit.new("1") # constant only -unit = Unit.new("mm") # unit only (defaults to a scalar of 1) -unit = Unit.new("1 mm") # create a simple unit -unit = Unit.new("1 mm/s") # a compound unit -unit = Unit.new("1 mm s^-1") # in exponent notation -unit = Unit.new("1 kg*m^2/s^2") # complex unit -unit = Unit.new("1 kg m^2 s^-2") # complex unit -unit = Unit.new("1 mm") # shorthand -unit = "1 mm".to_unit # convert string object -unit = object.to_unit # convert any object using object.to_s -unit = Unit.new('1/4 cup') # Rational number -unit = Unit.new('1+1i mm') # Complex Number -``` - -Rules: ------- - -1. only 1 quantity per unit (with 2 exceptions... 6'5" and '8 lbs 8 oz') -2. use SI notation when possible -3. spaces in units are allowed, but ones like '11/m' will be recognized as '11 1/m'. - -Unit compatibility: -------------------- - -Many methods require that the units of two operands are compatible. Compatible units are those that can be easily converted into each other, such as 'meters' and 'feet'. - -``` -unit1 =~ unit2 #=> true if units are compatible -unit1.compatible?(unit2) #=> true if units are compatible -``` - -Unit Math: ----------- - -``` -Unit#+() # Add. only works if units are compatible -Unit#-() # Subtract. only works if units are compatible -Unit#*() # Multiply. -Unit#/() # Divide. -Unit#**() # Exponentiate. Exponent must be an integer, can be positive, negative, or zero -Unit#inverse # Returns 1/unit -Unit#abs # Returns absolute value of the unit quantity. Strips off the units -Unit#ceil # rounds quantity to next highest integer -Unit#floor # rounds quantity down to next lower integer -Unit#round # rounds quantity to nearest integer -Unit#to_int # returns the quantity as an integer -``` - -Unit will coerce other objects into a Unit if used in a formula. This means that .. - -``` -Unit.new("1 mm") + "2 mm" == Unit.new("3 mm") -``` - -This will work as expected so long as you start the formula with a Unit object. - -Conversions & comparisons -------------------------- - -Units can be converted to other units in a couple of ways. - -``` -unit.convert_to('ft') # convert -unit1 = unit >> "ft" # convert to 'feet' -unit >>= "ft" # convert and overwrite original object -unit3 = unit1 + unit2 # resulting object will have the units of unit1 -unit3 = unit1 - unit2 # resulting object will have the units of unit1 -unit1 <=> unit2 # does comparison on quantities in base units, throws an exception if not compatible -unit1 === unit2 # true if units and quantity are the same, even if 'equivalent' by <=> -unit1 + unit2 >> "ft" # converts result of math to 'ft' -(unit1 + unit2).convert_to('ft') # converts result to 'ft' -``` - -Any object that defines a 'to_unit' method will be automatically coerced to a unit during calculations. - -Text Output ------------ - -Units will display themselves nicely based on the display_name for the units and prefixes. Since Unit implements a Unit#to_s, all that is needed in most cases is: - -``` -"#{Unit.new('1 mm')}" #=> "1 mm" -``` - -The to_s also accepts some options. - -``` -Unit.new('1.5 mm').to_s("%0.2f") # "1.50 mm". Enter any valid format - string. Also accepts strftime format -Unit.new('1.5 mm').to_s("in") # converts to inches before printing -Unit.new("2 m").to_s(:ft) # returns 6'7" -Unit.new("100 kg").to_s(:lbs) # returns 220 lbs, 7 oz -Unit.new("100 kg").to_s(:stone) # returns 15 stone, 10 lb -``` - -Time Helpers ------------- - -Time, Date, and DateTime objects can have time units added or subtracted. - -``` -Time.now + Unit.new("10 min") -``` - -Several helpers have also been defined. Note: If you include the 'Chronic' gem, you can specify times in natural language. - -``` - Unit.new('min').since(DateTime.parse('9/18/06 3:00pm')) -``` - -Durations may be entered as 'HH:MM:SS, usec' and will be returned in 'hours'. - -``` -Unit.new('1:00') #=> 1 h -Unit.new('0:30') #=> 0.5 h -Unit.new('0:30:30') #=> 0.5 h + 30 sec -``` - -If only one ":" is present, it is interpreted as the separator between hours and minutes. - -Ranges ------- - -``` -[Unit.new('0 h')..Unit.new('10 h')].each {|x| p x} -``` - -works so long as the starting point has an integer scalar - -Math functions --------------- - -All Trig math functions (sin, cos, sinh, hypot...) can take a unit as their parameter. It will be converted to radians and then used if possible. - -Temperatures ------------- - -Ruby-units makes a distinction between a temperature (which technically is a property) and degrees of temperature (which temperatures are measured in). - -Temperature units (i.e., 'tempK') can be converted back and forth, and will take into account the differences in the zero points of the various scales. Differential temperature (e.g., Unit.new('100 degC')) units behave like most other units. - -``` -Unit.new('37 tempC').convert_to('tempF') #=> 98.6 tempF -``` - -Ruby-units will raise an exception if you attempt to create a temperature unit that would fall below absolute zero. - -Unit math on temperatures is fairly limited. - -``` -Unit.new('100 tempC') + Unit.new('10 degC') # '110 tempC'.to_unit -Unit.new('100 tempC') - Unit.new('10 degC') # '90 tempC'.to_unit -Unit.new('100 tempC') + Unit.new('50 tempC') # exception (can't add two temperatures) -Unit.new('100 tempC') - Unit.new('50 tempC') # '50 degC'.to_unit (get the difference between two temperatures) -Unit.new('50 tempC') - Unit.new('100 tempC') # '-50 degC'.to_unit -Unit.new('100 tempC') * scalar # '100*scalar tempC'.to_unit -Unit.new('100 tempC') / scalar # '100/scalar tempC'.to_unit -Unit.new('100 tempC') * unit # exception -Unit.new('100 tempC') / unit # exception -Unit.new('100 tempC') ** N # exception - -Unit.new('100 tempC').convert_to('degC') #=> Unit.new('100 degC') -``` - -This conversion references the 0 point on the scale of the temperature unit - -``` -Unit.new('100 degC').convert_to('tempC') #=> '-173 tempC'.to_unit -``` - -These conversions are always interpreted as being relative to absolute zero. Conversions are probably better done like this... - -``` -Unit.new('0 tempC') + Unit.new('100 degC') #=> Unit.new('100 tempC') -``` - -Defining Units --------------- - -It is possible to define new units or redefine existing ones. - -### Define New Unit - -The easiest approach is to define a unit in terms of other units. - -``` -Unit.define("foobar") do |foobar| - foobar.definition = Unit.new("1 foo") * Unit.new("1 bar") # anything that results in a Unit object - foobar.aliases = %w{foobar fb} # array of synonyms for the unit - foobar.display_name = "Foobar" # How unit is displayed when output -end -``` - -### Redefine Existing Unit - -Redefining a unit allows the user to change a single aspect of a definition without having to re-create the entire definition. This is useful for changing display names, adding aliases, etc. - -``` -Unit.redefine!("cup") do |cup| - cup.display_name = "cup" -end -``` - -### Useful methods - -1. `scalar` will return the numeric portion of the unit without the attached units -2. `base_scalar` will return the scalar in base units (SI) -3. `units` will return the name of the units (without the scalar) -4. `base` will return the unit converted to base units (SI) - -### Storing in a database - -Units can be stored in a database as either the string representation or in two separate columns defining the scalar and the units. -Note that if sorting by units is desired you will want to ensure that you are storing the scalars in a consistent unit (i.e, the base units). - -### Namespaced Class - -Sometimes the default class 'Unit' may conflict with other gems or applications. Internally ruby-units defines itself using the RubyUnits namespace. The actual class of a unit is the RubyUnits::Unit. For simplicity and backwards compatibility, the '::Unit' class is defined as an alias to '::RubyUnits::Unit'. - -To load ruby-units without this alias... - -``` -require 'ruby_units/namespaced' -``` - -When using bundler... - -``` -gem 'ruby-units', require: 'ruby_units/namespaced' -``` - -Note: when using the namespaced version, the Unit.new('unit string') helper will not be defined. - -### Configuration - -Configuration options can be set like: - -``` -RubyUnits.configure do |config| - config.separator = false -end -``` - -Currently there is only one configuration you can set: - -1. separator (true/false): should a space be used to separate the scalar from the unit part during output. - - -### NOTES - -#### Performance vs. Accuracy - -Ruby units was originally intended to provide a robust and accurate way to do arbitrary unit conversions. -In some cases, these conversions can result in the creation and garbage collection of a lot of intermediate objects during -calculations. This in turn can have a negative impact on performance. The design of ruby-units has emphasized accuracy -over speed. YMMV if you are doing a lot of math involving units. diff --git a/ruby-units.gemspec.tmp b/ruby-units.gemspec.tmp deleted file mode 100644 index 511d4363..00000000 --- a/ruby-units.gemspec.tmp +++ /dev/null @@ -1,84 +0,0 @@ -# Generated by jeweler -# DO NOT EDIT THIS FILE DIRECTLY -# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' -# -*- encoding: utf-8 -*- -# stub: ruby-units 2.3.1 ruby lib - -Gem::Specification.new do |s| - s.name = "ruby-units".freeze - s.version = "2.3.1" - - s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= - s.require_paths = ["lib".freeze] - s.authors = ["Kevin Olbrich, Ph.D.".freeze] - s.date = "2018-09-26" - s.description = "Provides classes and methods to perform unit math and conversions".freeze - s.email = ["kevin.olbrich+ruby_units@gmail.com".freeze] - s.extra_rdoc_files = [ - "LICENSE.txt", - "README.md" - ] - s.files = [ - "CHANGELOG.txt", - "LICENSE.txt", - "README.md", - "Rakefile", - "VERSION", - "lib/ruby-units.rb", - "lib/ruby_units/array.rb", - "lib/ruby_units/cache.rb", - "lib/ruby_units/configuration.rb", - "lib/ruby_units/date.rb", - "lib/ruby_units/definition.rb", - "lib/ruby_units/math.rb", - "lib/ruby_units/namespaced.rb", - "lib/ruby_units/numeric.rb", - "lib/ruby_units/string.rb", - "lib/ruby_units/time.rb", - "lib/ruby_units/unit.rb", - "lib/ruby_units/unit_definitions.rb", - "lib/ruby_units/unit_definitions/base.rb", - "lib/ruby_units/unit_definitions/prefix.rb", - "lib/ruby_units/unit_definitions/standard.rb", - "lib/ruby_units/version.rb", - "ruby-units.gemspec" - ] - s.homepage = "https://github.com/olbrich/ruby-units".freeze - s.licenses = ["MIT".freeze] - s.rubygems_version = "2.6.14".freeze - s.summary = "A class that performs unit conversions and unit math".freeze - - if s.respond_to? :specification_version then - s.specification_version = 4 - - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q.freeze, ["~> 1.0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - s.add_development_dependency(%q.freeze, [">= 0"]) - else - s.add_dependency(%q.freeze, ["~> 1.0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - end - else - s.add_dependency(%q.freeze, ["~> 1.0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - s.add_dependency(%q.freeze, [">= 0"]) - end -end - From b22118fb1a3d868af0c2ae7cb857d4bfbab2e244 Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 2 Mar 2019 23:12:46 -0500 Subject: [PATCH 146/150] cleanup more files --- .gitignore | 2 +- Rakefile.tmp | 27 --------------------------- bin/console | 14 -------------- bin/rake | 16 ---------------- bin/rubocop | 29 ----------------------------- bin/setup | 8 -------- 6 files changed, 1 insertion(+), 95 deletions(-) delete mode 100644 Rakefile.tmp delete mode 100755 bin/console delete mode 100755 bin/rake delete mode 100755 bin/rubocop delete mode 100755 bin/setup diff --git a/.gitignore b/.gitignore index 607dea85..9ee78a5d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ /pkg/ /spec/reports/ /tmp/ - +/bin/ # rspec failure tracking .rspec_status diff --git a/Rakefile.tmp b/Rakefile.tmp deleted file mode 100644 index 03ee1541..00000000 --- a/Rakefile.tmp +++ /dev/null @@ -1,27 +0,0 @@ -require 'rubygems' -require 'rake' -require 'rake/testtask' -require './lib/ruby-units' - -begin - require 'jeweler' - Jeweler::Tasks.new do |gem| - gem.name = 'ruby-units' - gem.summary = 'A class that performs unit conversions and unit math' - gem.description = 'Provides classes and methods to perform unit math and conversions' - gem.authors = ['Kevin Olbrich, Ph.D.'] - gem.email = ['kevin.olbrich+ruby_units@gmail.com'] - gem.homepage = 'https://github.com/olbrich/ruby-units' - gem.files.exclude('.*', 'test/**/*', 'spec/**/*', 'Gemfile', 'Guardfile') - gem.license = 'MIT' - end - Jeweler::GemcutterTasks.new -rescue LoadError - puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler' -end - -require 'rspec/core/rake_task' -desc 'Run specs' -RSpec::Core::RakeTask.new - -task default: :spec diff --git a/bin/console b/bin/console deleted file mode 100755 index f8bb9ce1..00000000 --- a/bin/console +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby - -require "bundler/setup" -require "ruby/units" - -# You can add fixtures and/or initialization code here to make experimenting -# with your gem easier. You can also use a different console, if you like. - -# (If you use this, don't forget to add pry to your Gemfile!) -# require "pry" -# Pry.start - -require "irb" -IRB.start(__FILE__) diff --git a/bin/rake b/bin/rake deleted file mode 100755 index 26c7a2d5..00000000 --- a/bin/rake +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'rake' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('rake', 'rake') diff --git a/bin/rubocop b/bin/rubocop deleted file mode 100755 index d0c48829..00000000 --- a/bin/rubocop +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application 'rubocop' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -bundle_binstub = File.expand_path("../bundle", __FILE__) - -if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ - load(bundle_binstub) - else - abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. -Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") - end -end - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("rubocop", "rubocop") diff --git a/bin/setup b/bin/setup deleted file mode 100755 index dce67d86..00000000 --- a/bin/setup +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' -set -vx - -bundle install - -# Do any other automated setup that you need to do here From 075b249c66c6a20a1e46f86ac284e0a9a038583d Mon Sep 17 00:00:00 2001 From: Kevin Olbrich Date: Sat, 2 Mar 2019 23:16:41 -0500 Subject: [PATCH 147/150] style changes --- Gemfile | 2 +- Rakefile | 6 +++--- lib/ruby_units/version.rb | 2 +- ruby-units.gemspec | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index ee75b366..daccdc61 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "https://rubygems.org" +source 'https://rubygems.org' group :development do gem 'pry-byebug', platform: :mri diff --git a/Rakefile b/Rakefile index b7e9ed54..4c774a2b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ -require "bundler/gem_tasks" -require "rspec/core/rake_task" +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) -task :default => :spec +task default: :spec diff --git a/lib/ruby_units/version.rb b/lib/ruby_units/version.rb index fad81d01..b11b0209 100644 --- a/lib/ruby_units/version.rb +++ b/lib/ruby_units/version.rb @@ -1,5 +1,5 @@ module RubyUnits class Unit < Numeric - VERSION = "2.3.1" + VERSION = '2.3.1'.freeze end end diff --git a/ruby-units.gemspec b/ruby-units.gemspec index 067fcc65..f0600d17 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -26,15 +26,15 @@ Gem::Specification.new do |spec| end spec.require_paths = ['lib'] + spec.add_development_dependency 'bundler' spec.add_development_dependency 'guard-rspec' spec.add_development_dependency 'pry' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rspec', '~> 3.0' spec.add_development_dependency 'rubocop', '~> 0.63.0' # match codeclimate spec.add_development_dependency 'simplecov-html' spec.add_development_dependency 'simplecov' spec.add_development_dependency 'terminal-notifier-guard' spec.add_development_dependency 'terminal-notifier' spec.add_development_dependency 'wwtd' - spec.add_development_dependency 'bundler' - spec.add_development_dependency 'rake' - spec.add_development_dependency 'rspec', '~> 3.0' end From 3b606d856ab4b2a0cd3e585aa3cae467118d42cf Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2019 10:16:27 +0000 Subject: [PATCH 148/150] Update rubocop requirement from ~> 0.63.0 to ~> 0.77.0 Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version. - [Release notes](https://github.com/rubocop-hq/rubocop/releases) - [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.63.0...v0.77.0) Signed-off-by: dependabot-preview[bot] --- ruby-units.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby-units.gemspec b/ruby-units.gemspec index f0600d17..391bf1fc 100644 --- a/ruby-units.gemspec +++ b/ruby-units.gemspec @@ -31,7 +31,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry' spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rubocop', '~> 0.63.0' # match codeclimate + spec.add_development_dependency 'rubocop', '~> 0.77.0' # match codeclimate spec.add_development_dependency 'simplecov-html' spec.add_development_dependency 'simplecov' spec.add_development_dependency 'terminal-notifier-guard' From 30d180bbe5cc68378d52a3514294258c7942167b Mon Sep 17 00:00:00 2001 From: Stephen Wrathall Date: Mon, 30 Nov 2020 14:40:00 +0800 Subject: [PATCH 149/150] Add support for per N E.g. "2 kg/100kg" or "4 l/1000l". It's similar to a percentage, but can be for any scalar number, and is often the terminology used in industry, rather than percentages. E.g. in Agriculture - adding 4 liters of Roundup per 100 liters of tank mixture. --- lib/ruby_units/unit.rb | 5 +- spec/ruby_units/unit_spec.rb | 88 ++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/lib/ruby_units/unit.rb b/lib/ruby_units/unit.rb index b1864f97..307771a4 100644 --- a/lib/ruby_units/unit.rb +++ b/lib/ruby_units/unit.rb @@ -1511,7 +1511,8 @@ def parse(passed_unit_string = '0') return end - if defined?(Rational) && unit_string =~ RATIONAL_NUMBER + power_match = %r{\^\d+/\d+} # This prevents thinking e.g. kg^2/100l is rational because of 2/100 + if defined?(Rational) && unit_string =~ RATIONAL_NUMBER && !unit_string.match(power_match) sign, proper, numerator, denominator, unit_s = unit_string.scan(RATIONAL_REGEX)[0] sign = sign == '-' ? -1 : 1 rational = sign * (proper.to_i + Rational(numerator.to_i, denominator.to_i)) @@ -1594,7 +1595,7 @@ def parse(passed_unit_string = '0') if bottom bottom.gsub!(BOTTOM_REGEX) { "#{Regexp.last_match(1)} " * Regexp.last_match(2).to_i } # Separate leading decimal from denominator, if any - bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] + bottom_scalar, bottom = bottom.scan(NUMBER_UNIT_REGEX)[0] unless self.class.defined?(bottom) # Maintain scalar if it's part of the unit definition end @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? diff --git a/spec/ruby_units/unit_spec.rb b/spec/ruby_units/unit_spec.rb index 6ea4805f..ac91458f 100644 --- a/spec/ruby_units/unit_spec.rb +++ b/spec/ruby_units/unit_spec.rb @@ -861,6 +861,94 @@ end end + describe 'Units with rates of per N ' do + subject { Unit.new(2, 'kg/100kg') } + + before do + Unit.clear_cache # Needed for the following definition to consistently work + Unit.define('100kg') do |u| + u.definition = Unit.new('100 kg') + u.aliases = %w[100kg] + end + end + + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Numeric } + it { is_expected.to eq(2) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_a String } + it { is_expected.to eq('kg/100kg') } + end + + context 'when there is a power involved (e.g. liters squared)' do + subject { Unit.new(2, 'l^2/100kg') } + + it { is_expected.to be_an_instance_of Unit } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to be_an Numeric } + it { is_expected.to eq(2) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to be_a String } + it { is_expected.to eq('l^2/100kg') } + end + end + + describe 'Calculations' do + describe 'Addition' do + subject { Unit.new(2, 'kg/100kg') + Unit.new(2, 'kg/100kg') } + + describe '#scalar', skip: 'TODO: Fix the 4/1 here' do + subject { super().scalar } + it { is_expected.to eq('4') } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq('kg/100kg') } + end + end + + describe 'Multiplication' do + subject { Unit.new(2, 'kg/100kg') * Unit.new(2, 'kg/100kg') } + + describe '#scalar', skip: 'TODO: Fix the infinite loop here' do + subject { super().scalar } + it { is_expected.to eq('4') } + end + + describe '#units', skip: 'TODO: Fix the infinite loop here' do + subject { super().units } + it { is_expected.to eq('kg/100kg') } + end + end + + describe 'Division' do + subject { Unit.new(4, 'kg/100kg') / Unit.new(2, 'kg/100kg') } + + describe '#scalar' do + subject { super().scalar } + it { is_expected.to eq(2) } + end + + describe '#units' do + subject { super().units } + it { is_expected.to eq('') } + end + end + end + end + # time string describe RubyUnits::Unit.new('1:23:45,200') do it { is_expected.to be_an_instance_of Unit } From a2681f31d3d52fd2d20f1ac16b7fb6c63e04818e Mon Sep 17 00:00:00 2001 From: Stephen Wrathall Date: Mon, 30 Nov 2020 14:52:29 +0800 Subject: [PATCH 150/150] Local dev changes to get ruby-units working locally --- .gitignore | 1 + .ruby-version | 3 +-- Gemfile | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9ee78a5d..9878e20a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /bin/ # rspec failure tracking .rspec_status +.byebug_history # don't check in Gemfile.lock for a gem Gemfile.lock diff --git a/.ruby-version b/.ruby-version index c52f96ac..bc4abe86 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1,2 +1 @@ -2.3 - +2.3.8 diff --git a/Gemfile b/Gemfile index daccdc61..d682a7aa 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' group :development do + gem 'pry', '0.12.2' # Pry fails with error on load with version 0.13.1 - `NameError: uninitialized constant Pry::Command::ExitAll` gem 'pry-byebug', platform: :mri gem 'ruby-maven', platform: :jruby gem 'ruby-prof', platform: :mri