unitwise 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d970e26b0f67f67405f4ee70e3c147cd9b1a816b
4
- data.tar.gz: fd6e3942b5f6b1d1c9738dc6b6354023813a8f41
3
+ metadata.gz: d6ff99c65554976100b5a3cc719eb53aa95fc769
4
+ data.tar.gz: f3264f24f7f00d2380f2433ac4f5c6d0b7631b04
5
5
  SHA512:
6
- metadata.gz: bec5e1b8cc43f3c72cee9c6291f8938580ef5e1d15d7ee85c0795398c6f2efa6e8b58818a97ec9d52b89f9bfd683050b46548de18c4ab1f9d1b1fc818d718d84
7
- data.tar.gz: 64a1c445e9bde3bf1bd8cf501946bbb2cfb2b1d98c0f28a4fd22a90d46aae312d443a3b4099447897cc6ca104072edfb3c82f58abf103e9bda70adc555bec4a1
6
+ metadata.gz: 83c29762b50698411daacac88989649953282968257a932f86e224b8b9e84e5139cc912b25bf8ff4647df1dda3c6b1e5884e3285284a7b3fc463ff928ad1046c
7
+ data.tar.gz: a93702efcf3fcb0f849be1a6cd6a2219c5892df763ffa14f1284c2bb45a2d75c451a9c40db141591cde42ddde0dcbeecb6efcc1386ad795bd1f65d75542e2fdd
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ rvm:
6
6
  - 2.0.0
7
7
  - 2.1.0
8
8
  - ruby-head
9
- - rbx
10
9
  - rbx-2
11
10
  matrix:
12
11
  include:
@@ -14,8 +13,7 @@ matrix:
14
13
  env: JRUBY_OPTS="$JRUBY_OPTS --debug"
15
14
  - rvm: jruby-head
16
15
  env: JRUBY_OPTS="$JRUBY_OPTS --debug"
17
- allow_failure:
18
- - rvm: rbx
16
+ allow_failures:
19
17
  - rvm: ruby-head
20
18
  - rvm: jruby-head
21
19
  fast_finish: true
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # [Unitwise](//github.com/joshwlewis/unitwise)
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/unitwise.png)](http://badge.fury.io/rb/unitwise)
4
- [![Build Status](https://travis-ci.org/joshwlewis/unitwise.png)](https://travis-ci.org/joshwlewis/unitwise)
5
- [![Dependency Status](https://gemnasium.com/joshwlewis/unitwise.png)](https://gemnasium.com/joshwlewis/unitwise)
6
- [![Coverage Status](https://coveralls.io/repos/joshwlewis/unitwise/badge.png)](https://coveralls.io/r/joshwlewis/unitwise)
7
- [![Code Climate](https://codeclimate.com/github/joshwlewis/unitwise.png)](https://codeclimate.com/github/joshwlewis/unitwise)
8
- [![Inline docs](http://inch-pages.github.io/github/joshwlewis/unitwise.png)](http://inch-pages.github.io/github/joshwlewis/unitwise)
3
+ [![Gem Version](http://img.shields.io/gem/v/unitwise.svg?style=flat)](https://rubygems.org/gems/unitwise)
4
+ [![Build Status](http://img.shields.io/travis/joshwlewis/unitwise.svg?style=flat)](https://travis-ci.org/joshwlewis/unitwise)
5
+ [![Dependency Status](http://img.shields.io/gemnasium/joshwlewis/unitwise.svg?style=flat)](https://gemnasium.com/joshwlewis/unitwise)
6
+ [![Coverage Status](http://img.shields.io/coveralls/joshwlewis/unitwise.svg?style=flat)](https://coveralls.io/r/joshwlewis/unitwise)
7
+ [![Code Climate](http://img.shields.io/codeclimate/github/joshwlewis/unitwise.svg?style=flat)](https://codeclimate.com/github/joshwlewis/unitwise)
9
8
  ![Analytics](https://ga-beacon.appspot.com/UA-49481499-1/joshwlewis/unitwise?pixel)
10
9
 
11
10
  Unitwise is a Ruby library for unit measurement conversion and math.
data/lib/unitwise.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'liner'
2
2
 
3
- require "unitwise/version"
3
+ require 'unitwise/version'
4
4
  require 'unitwise/base'
5
5
  require 'unitwise/expression'
6
6
  require 'unitwise/compatible'
@@ -36,7 +36,7 @@ module Unitwise
36
36
  # A helper to get the location of a yaml data file
37
37
  # @api private
38
38
  def self.data_file(key)
39
- File.join path, "data", "#{key}.yaml"
39
+ File.join path, 'data', "#{key}.yaml"
40
40
  end
41
41
  end
42
42
 
data/lib/unitwise/atom.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Unitwise
2
2
  # Atoms are the most basic elements in Unitwise. They are named coded and
3
- # scaled units without prefixes, multipliers, exponents, etc. Examples are
3
+ # scaled units without prefixes, multipliers, exponents, etc. Examples are
4
4
  # 'meter', 'hour', 'pound force'.
5
5
  class Atom < Base
6
6
  liner :classification, :property, :metric, :special, :arbitrary, :dim
@@ -11,13 +11,13 @@ module Unitwise
11
11
  # Array of hashes representing atom properties.
12
12
  # @api private
13
13
  def data
14
- @data ||= data_files.reduce([]){|m,f| m += YAML::load File.open(f)}
14
+ @data ||= data_files.map { |file| YAML.load(File.open file) }.flatten
15
15
  end
16
16
 
17
17
  # Data files containing atom data
18
18
  # @api private
19
19
  def data_files
20
- %w(base_unit derived_unit).map{|type| Unitwise.data_file type}
20
+ %w(base_unit derived_unit).map { |type| Unitwise.data_file type }
21
21
  end
22
22
  end
23
23
 
@@ -26,10 +26,10 @@ module Unitwise
26
26
  # @return [true, false]
27
27
  # @api public
28
28
  def base?
29
- scale.nil? && !@dim.nil?
29
+ !!(@dim && !scale)
30
30
  end
31
31
 
32
- # Determine if an atom is derived. Derived atoms are defined with respect
32
+ # Determine if an atom is derived. Derived atoms are defined with respect
33
33
  # to other atoms.
34
34
  # @return [true, false]
35
35
  # @api public
@@ -55,7 +55,7 @@ module Unitwise
55
55
  end
56
56
  alias_method :special?, :special
57
57
 
58
- # Determine if a unit is arbitrary. Arbitrary atoms are not of any specific
58
+ # Determine if a unit is arbitrary. Arbitrary atoms are not of any specific
59
59
  # dimension and have no general meaning, therefore cannot be compared with
60
60
  # any other unit.
61
61
  # @return [true, false]
@@ -98,7 +98,7 @@ module Unitwise
98
98
  end
99
99
  end
100
100
 
101
- # Get a numeric value that can be used to with other atoms to compare with
101
+ # Get a numeric value that can be used to with other atoms to compare with
102
102
  # or operate on. Base units have a scalar of 1.
103
103
  # @return [Numeric]
104
104
  # @api public
@@ -111,7 +111,7 @@ module Unitwise
111
111
  # @param x [Numeric] The number to convert to or convert from
112
112
  # @param forward [true, false] Convert to or convert from
113
113
  # @return [Numeric] The converted value
114
- def functional(x=scalar, forward=true)
114
+ def functional(x = scalar, forward = true)
115
115
  scale.functional(x, forward)
116
116
  end
117
117
 
@@ -121,6 +121,5 @@ module Unitwise
121
121
  def root_terms
122
122
  base? ? [Term.new(atom_code: primary_code)] : scale.root_terms
123
123
  end
124
-
125
124
  end
126
- end
125
+ end
data/lib/unitwise/base.rb CHANGED
@@ -1,14 +1,16 @@
1
1
  require 'yaml'
2
2
  module Unitwise
3
+ # The base class that Atom and Prefix are extended from. This class includes
4
+ # shared functionality from those classes only.
3
5
  class Base
4
6
  liner :names, :primary_code, :secondary_code, :symbol, :scale
5
7
 
6
8
  def self.all
7
- @all ||= data.map{|d| self.new d }
9
+ @all ||= data.map { |d| new d }
8
10
  end
9
11
 
10
- def self.find(string, method=:primary_code)
11
- self.all.find do |i|
12
+ def self.find(string, method = :primary_code)
13
+ all.find do |i|
12
14
  key = i.send(method)
13
15
  if key.respond_to?(:each)
14
16
  key.include?(string)
@@ -36,6 +38,5 @@ module Unitwise
36
38
  def to_s
37
39
  primary_code
38
40
  end
39
-
40
41
  end
41
- end
42
+ end
@@ -3,7 +3,6 @@ module Unitwise
3
3
  # measurements. This is done by determining the objects atomic composition
4
4
  # represented as a Signed Multiset.
5
5
  module Compatible
6
-
7
6
  # @api private
8
7
  def self.included(base)
9
8
  base.send :include, Comparable
@@ -14,7 +13,8 @@ module Unitwise
14
13
  # @api public
15
14
  def composition
16
15
  root_terms.reduce(SignedMultiset.new) do |s, t|
17
- s.increment(t.atom.dim, t.exponent) if t.atom; s
16
+ s.increment(t.atom.dim, t.exponent) if t.atom
17
+ s
18
18
  end
19
19
  end
20
20
 
@@ -29,7 +29,7 @@ module Unitwise
29
29
  # @return [String]
30
30
  # @api public
31
31
  def composition_string
32
- composition.sort.map do |k,v|
32
+ composition.sort.map do |k, v|
33
33
  v == 1 ? k.to_s : "#{k}#{v}"
34
34
  end.join('.')
35
35
  end
@@ -38,7 +38,7 @@ module Unitwise
38
38
  # @return [true false]
39
39
  # @api public
40
40
  def compatible_with?(other)
41
- self.composition == other.composition
41
+ composition == other.composition
42
42
  end
43
43
 
44
44
  # Compare whether the instance is greater, less than or equal to other.
@@ -50,4 +50,4 @@ module Unitwise
50
50
  end
51
51
  end
52
52
  end
53
- end
53
+ end
@@ -4,4 +4,4 @@ module Unitwise
4
4
 
5
5
  class ConversionError < Exception
6
6
  end
7
- end
7
+ end
@@ -26,22 +26,30 @@ module Unitwise
26
26
  # @param expression [String] The string you wish to convert
27
27
  # @return [Array]
28
28
  # @example
29
- # Unitwise::Expression.decompose("m2/s2")
29
+ # Unitwise::Expression.decompose("m2/s2")
30
30
  # # => [<Unitwise::Term m2>, <Unitwise::Term s-2>]
31
31
  # @api public
32
32
  def decompose(expression)
33
33
  expression = expression.to_s
34
- @decompose ||= {}
35
- if @decompose.has_key?(expression)
36
- @decompose[expression]
34
+ if decomposed.key?(expression)
35
+ decomposed[expression]
37
36
  else
38
- @decompose[expression] = begin
37
+ decomposed[expression] = begin
39
38
  Decomposer.new(expression).terms
40
39
  rescue ExpressionError
41
40
  nil
42
41
  end
43
42
  end
44
43
  end
44
+
45
+ private
46
+
47
+ # A cache of decomposed strings.
48
+ # @return [Hash]
49
+ # @api private
50
+ def decomposed
51
+ @decomposed ||= {}
52
+ end
45
53
  end
46
54
  end
47
- end
55
+ end
data/lib/unitwise/ext.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  require 'unitwise'
2
- require 'unitwise/ext/numeric'
2
+ require 'unitwise/ext/numeric'
@@ -1,36 +1,40 @@
1
1
  module Unitwise
2
+ # Functional is an alterative function-based scale for atoms with a
3
+ # non-linear (or non-zero y-intercept) scale. This is most commonly used for
4
+ # temperatures. Known functions for converting to and from special atoms
5
+ # are setup as class methods here.
2
6
  class Functional < Scale
3
7
  extend Math
4
8
 
5
- def self._cel(x, forward=true)
9
+ def self._cel(x, forward = true)
6
10
  forward ? x - 273.15 : x + 273.15
7
11
  end
8
12
 
9
- def self._degf(x, forward=true)
13
+ def self._degf(x, forward = true)
10
14
  forward ? 9.0 * x / 5.0 - 459.67 : 5.0 / 9 * (x + 459.67)
11
15
  end
12
16
 
13
- def self._hpX(x, forward=true)
17
+ def self._hpX(x, forward = true)
14
18
  forward ? -log10(x) : 10 ** -x
15
19
  end
16
20
 
17
- def self._hpC(x, forward=true)
18
- forward ? -log(x) / log(100) : 100 ** -x
21
+ def self._hpC(x, forward = true)
22
+ forward ? -log(x) / log(100) : 100 ** -x
19
23
  end
20
24
 
21
- def self._tan100(x, forward=true)
25
+ def self._tan100(x, forward = true)
22
26
  forward ? 100 * tan(x) : atan(x / 100)
23
27
  end
24
28
 
25
- def self._ph(x, forward=true)
29
+ def self._ph(x, forward = true)
26
30
  _hpX(x,forward)
27
31
  end
28
32
 
29
- def self._ld(x, forward=true)
33
+ def self._ld(x, forward = true)
30
34
  forward ? log2(x) : 2 ** x
31
35
  end
32
36
 
33
- def self._ln(x, forward=true)
37
+ def self._ln(x, forward = true)
34
38
  forward ? log(x) : Math::E ** x
35
39
  end
36
40
 
@@ -39,19 +43,29 @@ module Unitwise
39
43
  end
40
44
 
41
45
  def self._2lg(x, forward = true)
42
- forward ? 2 * log10(x) : 10 ** ( x / 2 )
46
+ forward ? 2 * log10(x) : 10 ** (x / 2)
43
47
  end
44
48
 
45
49
  attr_reader :function_name
46
50
 
51
+ # Setup a new functional.
52
+ # @param value [Numeric] The magnitude of the scale
53
+ # @param unit [Unitwise::Unit, String] The unit of the scale
54
+ # @param function_name [String, Symbol] One of the class methods above to be
55
+ # used for conversion
47
56
  def initialize(value, unit, function_name)
48
57
  @function_name = function_name
49
58
  super(value, unit)
50
59
  end
51
60
 
52
- def functional(x=scalar, forward = true)
61
+ # Get the equivalent scalar value of a unit based on the atom's function.
62
+ # @params x [Numeric]
63
+ # @params forward [true, false] The direction of the conversion. Use true
64
+ # when converting from the special, use false when converting to the special.
65
+ # @return [Numeric]
66
+ # @api public
67
+ def functional(x = scalar, forward = true)
53
68
  self.class.send(:"_#{function_name}", x, forward)
54
69
  end
55
-
56
70
  end
57
- end
71
+ end
@@ -4,19 +4,16 @@ module Unitwise
4
4
  # the value is the magnitued. This is the primary class that outside code
5
5
  # will interact with. Comes with conversion, comparison, and math methods.
6
6
  class Measurement < Scale
7
-
8
7
  # Create a new Measurement
9
8
  # @param value [Numeric] The scalar value for the measurement
10
9
  # @param unit [String, Measurement::Unit] Either a string expression, or a
11
10
  # Measurement::Unit
12
11
  # @example
13
- # Unitwise::Measurement.new(20, 'm/s') # => #<Unitwise::Measurement 20 m/s>
12
+ # Unitwise::Measurement.new(20, 'm/s')
14
13
  # @api public
15
14
  def initialize(*args)
16
15
  super(*args)
17
- if terms.nil?
18
- raise ExpressionError, "Could not evaluate `#{unit}`."
19
- end
16
+ fail ExpressionError, "Could not evaluate `#{unit}`." if terms.nil?
20
17
  end
21
18
 
22
19
  # Convert this measurement to a compatible unit.
@@ -31,7 +28,7 @@ module Unitwise
31
28
  if compatible_with?(other_unit)
32
29
  new(converted_value(other_unit), other_unit)
33
30
  else
34
- raise ConversionError, "Can't convert #{self} to #{other_unit}."
31
+ fail ConversionError, "Can't convert #{self} to #{other_unit}."
35
32
  end
36
33
  end
37
34
 
@@ -42,7 +39,8 @@ module Unitwise
42
39
  # measurement * some_other_measurement
43
40
  # @api public
44
41
  def *(other)
45
- operate(:*, other) || raise(TypeError, "Can't multiply #{self} by #{other}.")
42
+ operate(:*, other) ||
43
+ fail(TypeError, "Can't multiply #{self} by #{other}.")
46
44
  end
47
45
 
48
46
  # Divide this measurement by a number or another measurement
@@ -52,7 +50,7 @@ module Unitwise
52
50
  # measurement / some_other_measurement
53
51
  # @api public
54
52
  def /(other)
55
- operate(:/, other) || raise(TypeError, "Can't divide #{self} by #{other}")
53
+ operate(:/, other) || fail(TypeError, "Can't divide #{self} by #{other}")
56
54
  end
57
55
 
58
56
  # Add another measurement to this unit. Units must be compatible.
@@ -61,7 +59,7 @@ module Unitwise
61
59
  # measurement + some_other_measurement
62
60
  # @api public
63
61
  def +(other)
64
- combine(:+, other) || raise(TypeError, "Can't add #{other} to #{self}.")
62
+ combine(:+, other) || fail(TypeError, "Can't add #{other} to #{self}.")
65
63
  end
66
64
 
67
65
  # Subtract another measurement from this unit. Units must be compatible.
@@ -70,7 +68,8 @@ module Unitwise
70
68
  # measurement - some_other_measurement
71
69
  # @api public
72
70
  def -(other)
73
- combine(:-, other) || raise(TypeError, "Can't subtract #{other} from #{self}.")
71
+ combine(:-, other) ||
72
+ fail(TypeError, "Can't subtract #{other} from #{self}.")
74
73
  end
75
74
 
76
75
  # Raise a measurement to a numeric power.
@@ -78,11 +77,11 @@ module Unitwise
78
77
  # @example
79
78
  # measurement ** 2
80
79
  # @api public
81
- def **(number)
82
- if number.is_a?(Numeric)
83
- new( value ** number, unit ** number )
80
+ def **(other)
81
+ if other.is_a?(Numeric)
82
+ new(value ** other, unit ** other)
84
83
  else
85
- raise TypeError, "Can't raise #{self} to #{number} power."
84
+ fail TypeError, "Can't raise #{self} to #{other} power."
86
85
  end
87
86
  end
88
87
 
@@ -97,7 +96,7 @@ module Unitwise
97
96
  when Numeric
98
97
  return self.class.new(other, '1'), self
99
98
  else
100
- raise TypeError, "#{self.class} can't be coerced into #{other.class}"
99
+ fail TypeError, "#{self.class} can't be coerced into #{other.class}"
101
100
  end
102
101
  end
103
102
 
@@ -108,7 +107,7 @@ module Unitwise
108
107
  def to_i
109
108
  Integer(value)
110
109
  end
111
- alias :to_int :to_i
110
+ alias_method :to_int, :to_i
112
111
 
113
112
  # Convert a measurement to a Float.
114
113
  # @example
@@ -184,12 +183,13 @@ module Unitwise
184
183
  elsif other.respond_to?(:composition)
185
184
  if compatible_with?(other)
186
185
  converted = other.convert_to(unit)
187
- new(value.send(operator, converted.value), unit.send(operator, converted.unit))
186
+ new(value.send(operator, converted.value),
187
+ unit.send(operator, converted.unit))
188
188
  else
189
- new(value.send(operator, other.value), unit.send(operator, other.unit))
189
+ new(value.send(operator, other.value),
190
+ unit.send(operator, other.unit))
190
191
  end
191
192
  end
192
193
  end
193
-
194
194
  end
195
- end
195
+ end
@@ -1,17 +1,24 @@
1
1
  module Unitwise
2
+ # A prefix can be used with metric atoms to modify their scale.
2
3
  class Prefix < Base
3
4
  liner :scalar
4
5
 
6
+ # The data loaded from the UCUM spec files
7
+ # @api semipublic
5
8
  def self.data
6
- @data ||= YAML::load File.open(data_file)
9
+ @data ||= YAML.load File.open(data_file)
7
10
  end
8
11
 
12
+ # The location of the UCUM spec prefix data file
13
+ # @api semipublic
9
14
  def self.data_file
10
15
  Unitwise.data_file 'prefix'
11
16
  end
12
17
 
18
+ # Set the scalar value for the prefix, always as a Fixnum
19
+ # @api semipublic
13
20
  def scalar=(value)
14
21
  @scalar = value.to_f
15
22
  end
16
23
  end
17
- end
24
+ end
@@ -1,5 +1,5 @@
1
1
  module Unitwise
2
- # A Unitwise::Scale represents a value and a unit, sort of like a vector, it
2
+ # A Unitwise::Scale represents a value and a unit, sort of like a vector, it
3
3
  # has two components. In this case, it's a value and unit rather than a
4
4
  # magnitude and direction. This class should be considered mostly privateish.
5
5
  class Scale
@@ -46,7 +46,7 @@ module Unitwise
46
46
  # @param forward [true, false] whether to convert to this unit or from it.
47
47
  # @return [Numeric]
48
48
  # @api public
49
- def functional(x=value, forward=true)
49
+ def functional(x = value, forward = true)
50
50
  unit.functional(x, forward)
51
51
  end
52
52
 
@@ -58,7 +58,7 @@ module Unitwise
58
58
  value * unit.scalar
59
59
  end
60
60
 
61
- # The base units this scale's unit is derived from
61
+ # The base terms this scale's unit is derived from
62
62
  # @return [Array] An array of Unitwise::Term
63
63
  # @api public
64
64
  def root_terms
@@ -82,4 +82,4 @@ module Unitwise
82
82
  "#<#{self.class} value=#{value} unit=#{unit}>"
83
83
  end
84
84
  end
85
- end
85
+ end
@@ -24,7 +24,6 @@ module Unitwise
24
24
  def hash
25
25
  Nori.new.parse(body)["root"]
26
26
  end
27
-
28
27
  end
29
28
  end
30
- end
29
+ end
data/lib/unitwise/term.rb CHANGED
@@ -1,49 +1,92 @@
1
1
  require 'signed_multiset'
2
2
  module Unitwise
3
+ # A Term is the combination of an atom, prefix, factor and annotation.
4
+ # Not all properties have to be present. Examples: 'g', 'mm', 'mi2', '4[pi]',
5
+ # 'kJ{Electric Potential}'
3
6
  class Term < Liner.new(:atom, :prefix, :factor, :exponent, :annotation)
4
7
  include Unitwise::Compatible
5
8
 
9
+ # Setup a new term. Send a hash of properties, or ordered property values.
10
+ # @api public
6
11
  def initialize(*args)
7
12
  super(*args)
8
13
  freeze
9
14
  end
10
15
 
16
+ # Set the atom.
17
+ # @param value [String, Atom] Either a string representing an Atom, or an
18
+ # Atom
19
+ # @api public
11
20
  def atom=(value)
12
21
  value.is_a?(Atom) ? super(value) : super(Atom.find(value.to_s))
13
22
  end
14
23
 
24
+ # Set the prefix.
25
+ # @param value [String, Prefix] Either a string representing a Prefix, or
26
+ # a Prefix
15
27
  def prefix=(value)
16
28
  value.is_a?(Prefix) ? super(value) : super(Prefix.find(value.to_s))
17
29
  end
18
30
 
31
+ # Is this term special?
32
+ # @return [true, false]
19
33
  def special?
20
34
  atom.special rescue false
21
35
  end
22
36
 
37
+ # Determine how far away a unit is from a base unit.
38
+ # @return [Integer]
39
+ # @api public
23
40
  def depth
24
41
  atom ? atom.depth + 1 : 0
25
42
  end
26
43
 
44
+ # Determine if this is the last term in the scale chain
45
+ # @return [true, false]
46
+ # @api public
27
47
  def terminal?
28
48
  depth <= 3
29
49
  end
30
50
 
51
+ # The multiplication factor for this term. The default value is 1.
52
+ # @return [Numeric]
53
+ # @api public
31
54
  def factor
32
55
  super || 1
33
56
  end
34
57
 
58
+ # The exponent for this term. The default value is 1.
59
+ # @return [Numeric]
60
+ # @api public
35
61
  def exponent
36
62
  super || 1
37
63
  end
38
64
 
65
+ # The unitless value for this term. This is the equivalent value of it's
66
+ # base atom
67
+ # @return [Numeric]
68
+ # @api public
39
69
  def scalar
40
- (factor * (prefix ? prefix.scalar : 1) * (atom ? atom.scalar : 1)) ** exponent
70
+ (factor * (prefix ? prefix.scalar : 1) *
71
+ (atom ? atom.scalar : 1)) ** exponent
41
72
  end
42
73
 
43
- def functional(x=scalar, forward=true)
44
- (factor * (prefix ? prefix.scalar : 1)) * (atom ? atom.functional(x, forward) : 1) ** exponent
74
+ # Get the equivalent scalar value of a unit based on the atom's function.
75
+ # @params x [Numeric]
76
+ # @params forward [true, false] The direction of the conversion. Use true
77
+ # when converting from the special, use false when converting to the
78
+ # special.
79
+ # @return [Numeric]
80
+ # @api public
81
+ # @param x [Numeric] The value
82
+ def functional(x = scalar, forward = true)
83
+ (factor * (prefix ? prefix.scalar : 1)) *
84
+ (atom ? atom.functional(x, forward) : 1) ** exponent
45
85
  end
46
86
 
87
+ # The base units this term is derived from
88
+ # @return [Array] An array of Unitwise::Term
89
+ # @api public
47
90
  def root_terms
48
91
  if terminal?
49
92
  [self]
@@ -54,6 +97,9 @@ module Unitwise
54
97
  end
55
98
  end
56
99
 
100
+ # Term multiplication. Multiply by a Unit, another Term, or a Numeric.
101
+ # params other [Unit, Term, Numeric]
102
+ # @return [Term]
57
103
  def *(other)
58
104
  if other.respond_to?(:terms)
59
105
  Unit.new(other.terms << self)
@@ -64,9 +110,12 @@ module Unitwise
64
110
  end
65
111
  end
66
112
 
113
+ # Term division. Divide by a Unit, another Term, or a Numeric.
114
+ # params other [Unit, Term, Numeric]
115
+ # @return [Term]
67
116
  def /(other)
68
117
  if other.respond_to?(:terms)
69
- Unit.new(other.terms.map{|t| t ** -1} << self)
118
+ Unit.new(other.terms.map { |t| t ** -1 } << self)
70
119
  elsif other.respond_to?(:atom)
71
120
  Unit.new([self, other ** -1])
72
121
  elsif other.is_a?(Numeric)
@@ -74,14 +123,22 @@ module Unitwise
74
123
  end
75
124
  end
76
125
 
77
- def **(integer)
78
- self.class.new(to_hash.merge(exponent: exponent * integer))
126
+ # Term exponentiation. Raise a term to a numeric power.
127
+ # params other [Numeric]
128
+ # @return [Term]
129
+ def **(other)
130
+ if other.is_a?(Numeric)
131
+ self.class.new(to_hash.merge(exponent: exponent * other))
132
+ else
133
+ fail TypeError, "Can't raise #{self} to #{other}."
134
+ end
79
135
  end
80
136
 
137
+ # String representation for this term.
138
+ # @return [String]
81
139
  def to_s
82
140
  [(factor if factor != 1), prefix.to_s,
83
141
  atom.to_s, (exponent if exponent != 1)].compact.join('')
84
142
  end
85
-
86
143
  end
87
- end
144
+ end
data/lib/unitwise/unit.rb CHANGED
@@ -1,8 +1,14 @@
1
1
  module Unitwise
2
+ # A Unit is essentially a collection of Unitwise::Term. Terms can be combined
3
+ # through multiplication or division to create a unit. A unit does not have
4
+ # a magnitude, but it does have a scale.
2
5
  class Unit
3
6
  liner :expression, :terms
4
7
  include Unitwise::Compatible
5
8
 
9
+ # Create a new unit. You can send an expression or a collection of terms
10
+ # @param input [String, Unit, [Term]] A string expression, a unit, or a
11
+ # collection of tems.
6
12
  def initialize(input)
7
13
  if input.respond_to?(:expression)
8
14
  @expression = input.expression
@@ -29,7 +35,7 @@ module Unitwise
29
35
  terms.count == 1 && terms.all?(&:special?)
30
36
  end
31
37
 
32
- def functional(x=scalar, forward=true)
38
+ def functional(x = scalar, forward = true)
33
39
  terms.first.functional(x, forward)
34
40
  end
35
41
 
@@ -42,7 +48,7 @@ module Unitwise
42
48
  end
43
49
 
44
50
  def scalar
45
- terms.map(&:scalar).inject(&:*)
51
+ terms.map(&:scalar).reduce(&:*)
46
52
  end
47
53
 
48
54
  def *(other)
@@ -51,28 +57,32 @@ module Unitwise
51
57
  elsif other.respond_to?(:atom)
52
58
  self.class.new(terms << other)
53
59
  elsif other.is_a?(Numeric)
54
- self.class.new(terms.map{ |t| t * other })
60
+ self.class.new(terms.map { |t| t * other })
55
61
  else
56
- raise TypeError, "Can't multiply #{inspect} by #{other}."
62
+ fail TypeError, "Can't multiply #{self} by #{other}."
57
63
  end
58
64
  end
59
65
 
60
66
  def /(other)
61
67
  if other.respond_to?(:terms)
62
- self.class.new(terms + other.terms.map{ |t| t ** -1})
68
+ self.class.new(terms + other.terms.map { |t| t ** -1 })
63
69
  elsif other.respond_to?(:atom)
64
70
  self.class.new(terms << other ** -1)
65
71
  else
66
- raise TypeError, "Can't divide #{inspect} by #{other}."
72
+ fail TypeError, "Can't divide #{self} by #{other}."
67
73
  end
68
74
  end
69
75
 
70
- def **(number)
71
- self.class.new(terms.map{ |t| t ** number })
76
+ def **(other)
77
+ if other.is_a?(Numeric)
78
+ self.class.new(terms.map { |t| t ** other })
79
+ else
80
+ fail TypeError, "Can't raise #{self} to #{other}."
81
+ end
72
82
  end
73
83
 
74
84
  def to_s
75
85
  expression
76
86
  end
77
87
  end
78
- end
88
+ end
@@ -1,3 +1,3 @@
1
1
  module Unitwise
2
- VERSION = "0.5.0"
2
+ VERSION = '0.5.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unitwise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Lewis