unitwise 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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