auom 0.0.3
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.
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +10 -0
- data/Gemfile.devtools +52 -0
- data/Guardfile +8 -0
- data/LICENSE +20 -0
- data/README.md +92 -0
- data/Rakefile +5 -0
- data/TODO +3 -0
- data/auom.gemspec +21 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/heckle.yml +9 -0
- data/config/roodi.yml +20 -0
- data/config/site.reek +95 -0
- data/config/yardstick.yml +2 -0
- data/lib/auom.rb +287 -0
- data/lib/auom/algebra.rb +129 -0
- data/lib/auom/equalization.rb +90 -0
- data/lib/auom/inspection.rb +103 -0
- data/lib/auom/version.rb +3 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/command_method_behavior.rb +7 -0
- data/spec/shared/each_method_behaviour.rb +15 -0
- data/spec/shared/hash_method_behavior.rb +17 -0
- data/spec/shared/idempotent_method_behavior.rb +7 -0
- data/spec/shared/incompatible_operation_behavior.rb +5 -0
- data/spec/shared/invertible_method_behaviour.rb +9 -0
- data/spec/shared/operation_behavior.rb +12 -0
- data/spec/shared/sunits_shared.rb +6 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/unit/auom/add_spec.rb +0 -0
- data/spec/unit/auom/algebra/add_spec.rb +59 -0
- data/spec/unit/auom/algebra/divide_spec.rb +74 -0
- data/spec/unit/auom/algebra/multiply_spec.rb +74 -0
- data/spec/unit/auom/algebra/substract_spec.rb +59 -0
- data/spec/unit/auom/equalization/eql_spec.rb +40 -0
- data/spec/unit/auom/equalization/equal_value_spec.rb +57 -0
- data/spec/unit/auom/equalization/hash_spec.rb +13 -0
- data/spec/unit/auom/inspection/class_methods/prettify_unit_part_spec.rb +27 -0
- data/spec/unit/auom/inspection/inspect_spec.rb +41 -0
- data/spec/unit/auom/unit/class_methods/convert_spec.rb +35 -0
- data/spec/unit/auom/unit/class_methods/lookup_spec.rb +21 -0
- data/spec/unit/auom/unit/class_methods/new_spec.rb +156 -0
- data/spec/unit/auom/unit/class_methods/try_convert_spec.rb +31 -0
- data/spec/unit/auom/unit/class_methods/units_spec.rb +11 -0
- data/spec/unit/auom/unit/denominators_spec.rb +16 -0
- data/spec/unit/auom/unit/numerators_spec.rb +16 -0
- data/spec/unit/auom/unit/scalar_spec.rb +16 -0
- data/spec/unit/auom/unit/unit_spec.rb +16 -0
- data/spec/unit/auom/unit/unitless_spec.rb +18 -0
- metadata +164 -0
data/lib/auom/algebra.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
module AUOM
|
2
|
+
# The AUOM algebra
|
3
|
+
module Algebra
|
4
|
+
# Return addition result
|
5
|
+
#
|
6
|
+
# @param [Object] operand
|
7
|
+
#
|
8
|
+
# @return [Unit]
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # unitless
|
13
|
+
# Unit.new(1) + Unit.new(2) # => <Unit @scalar=3>
|
14
|
+
#
|
15
|
+
# # with unit
|
16
|
+
# Unit.new(1,:meter) + Unit.new(2,:meter) # => <AUOM::Unit @scalar=3 meter>
|
17
|
+
#
|
18
|
+
# # incompatible unit
|
19
|
+
# Unit.new(1,:meter) + Unit.new(2,:euro) # raises ArgumentError!
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
#
|
23
|
+
def add(operand)
|
24
|
+
klass = self.class
|
25
|
+
operand = klass.convert(operand)
|
26
|
+
|
27
|
+
unless operand.unit == unit
|
28
|
+
raise ArgumentError, 'Incompatible units for substraction or addition'
|
29
|
+
end
|
30
|
+
|
31
|
+
klass.new(
|
32
|
+
operand.scalar + scalar,
|
33
|
+
numerators.dup,
|
34
|
+
denominators.dup
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :+ :add
|
39
|
+
|
40
|
+
# Return substraction result
|
41
|
+
#
|
42
|
+
# @param [Object] operand
|
43
|
+
#
|
44
|
+
# @return [Unit]
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
#
|
48
|
+
# # unitless
|
49
|
+
# Unit.new(2) - Unit.new(1) # => <Unit @scalar=1>
|
50
|
+
#
|
51
|
+
# # with unit
|
52
|
+
# Unit.new(2,:meter) - Unit.new(1,:meter) # => <AUOM::Unit @scalar=1 meter>
|
53
|
+
#
|
54
|
+
# # incompatible unit
|
55
|
+
# Unit.new(2,:meter) - Unit.new(1,:euro) # raises ArgumentError!
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
#
|
59
|
+
def substract(operand)
|
60
|
+
self.add(self.class.convert(operand) * -1)
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :- :substract
|
64
|
+
|
65
|
+
# Return multiplication result
|
66
|
+
#
|
67
|
+
# @param [Object] operand
|
68
|
+
#
|
69
|
+
# @return [Unit]
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
#
|
73
|
+
# # unitless
|
74
|
+
# Unit.new(2) * Unit.new(1) # => <Unit @scalar=2>
|
75
|
+
#
|
76
|
+
# # with unit
|
77
|
+
# Unit.new(2, :meter) * Unit.new(1, :meter) # => <AUOM::Unit @scalar=2 meter^2>
|
78
|
+
#
|
79
|
+
# # differend units
|
80
|
+
# Unit.new(2, :meter) * Unit.new(1, :euro) # => <AUOM::Unit @scalar=2 meter*euro>
|
81
|
+
#
|
82
|
+
# @api public
|
83
|
+
#
|
84
|
+
def multiply(operand)
|
85
|
+
klass = self.class
|
86
|
+
operand = klass.convert(operand)
|
87
|
+
|
88
|
+
klass.new(
|
89
|
+
operand.scalar * scalar,
|
90
|
+
numerators + operand.numerators,
|
91
|
+
denominators + operand.denominators
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
alias :* :multiply
|
96
|
+
|
97
|
+
# Return division result
|
98
|
+
#
|
99
|
+
# @param [Object] operand
|
100
|
+
#
|
101
|
+
# @return [Unit]
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
#
|
105
|
+
# # unitless
|
106
|
+
# Unit.new(2) / Unit.new(1) # => <Unit @scalar=2>
|
107
|
+
#
|
108
|
+
# # with unit
|
109
|
+
# Unit.new(2, :meter) / Unit.new(1, :meter) # => <AUOM::Unit @scalar=2>
|
110
|
+
#
|
111
|
+
# # differend units
|
112
|
+
# Unit.new(2, :meter) / Unit.new(1, :euro) # => <AUOM::Unit @scalar=2 meter/euro>
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
#
|
116
|
+
def divide(operand)
|
117
|
+
klass = self.class
|
118
|
+
operand = klass.convert(operand)
|
119
|
+
|
120
|
+
self * klass.new(
|
121
|
+
1 / operand.scalar,
|
122
|
+
operand.denominators.dup,
|
123
|
+
operand.numerators.dup
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
alias :/ :divide
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module AUOM
|
2
|
+
# Equalization for auom units
|
3
|
+
module Equalization
|
4
|
+
# Check for equivalent value and try to convert
|
5
|
+
#
|
6
|
+
# @param [Object] other
|
7
|
+
#
|
8
|
+
# @return [true]
|
9
|
+
# return true if is other is a unit and scalar and unit is the same after try of conversion.
|
10
|
+
#
|
11
|
+
# @return [false]
|
12
|
+
# return false otherwise
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# u = Unit.new(1, :meter)
|
17
|
+
# u == u # => true
|
18
|
+
# u == 1 # => false
|
19
|
+
# u == Unit.new(1, :meter) # => true
|
20
|
+
#
|
21
|
+
# u = Unit.new(1)
|
22
|
+
# u == 1 # => true
|
23
|
+
# u == Rational(1) # => true
|
24
|
+
# u == 1.0 # => false
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
#
|
28
|
+
def ==(other)
|
29
|
+
eql?(self.class.try_convert(other))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check for equivalent value and not try to convert
|
33
|
+
#
|
34
|
+
# @param [Object] other
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
#
|
38
|
+
# u = Unit.new(1, :meter)
|
39
|
+
# u == u # => true
|
40
|
+
# u == 1 # => false
|
41
|
+
# u == Unit.new(1, :meter) # => true
|
42
|
+
#
|
43
|
+
# u = Unit.new(1)
|
44
|
+
# u == 1 # => false
|
45
|
+
# u == Rational(1) # => false
|
46
|
+
# u == 1.0 # => false
|
47
|
+
#
|
48
|
+
# @return [true]
|
49
|
+
# return true if is other is a unit and scalar and unit is the same
|
50
|
+
#
|
51
|
+
# @return [false]
|
52
|
+
# return false otherwise
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
#
|
56
|
+
def eql?(other)
|
57
|
+
(instance_of?(other.class) && cmp?(other))
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return hash value
|
61
|
+
#
|
62
|
+
# @return [Fixnum]
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
#
|
66
|
+
# Unit.new(1, :meter).to_hash # => 012345678
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
#
|
70
|
+
def hash
|
71
|
+
scalar.hash ^ unit.hash
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Compare with other unit instance
|
77
|
+
#
|
78
|
+
# @return [true]
|
79
|
+
# returns true if unit and scalar is aequivalent
|
80
|
+
#
|
81
|
+
# @return [false]
|
82
|
+
# return false otherwise
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
#
|
86
|
+
def cmp?(other)
|
87
|
+
scalar.eql?(other.scalar) && unit.eql?(other.unit)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module AUOM
|
2
|
+
# Inspection module for auom units
|
3
|
+
module Inspection
|
4
|
+
# Return inspectable representation
|
5
|
+
#
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
def inspect
|
11
|
+
sprintf('<%s @scalar=%s%s>', self.class.name, pretty_scalar, pretty_unit)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Return prettyfied scalar
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
def pretty_scalar
|
23
|
+
scalar = self.scalar
|
24
|
+
|
25
|
+
unless fractions?
|
26
|
+
scalar.to_i
|
27
|
+
else
|
28
|
+
'~%0.4f' % scalar.to_f
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return prettyfied unit part
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
def pretty_unit
|
39
|
+
return '' if unitless?
|
40
|
+
|
41
|
+
klass = self.class
|
42
|
+
numerator = Inspection.prettify_unit_part(@numerators)
|
43
|
+
denominator = Inspection.prettify_unit_part(@denominators)
|
44
|
+
|
45
|
+
numerator = '1' if numerator.empty?
|
46
|
+
if denominator.empty?
|
47
|
+
return " #{numerator}"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
sprintf(' %s/%s', numerator, denominator)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Check if scalar has fractions in decimal representation
|
55
|
+
#
|
56
|
+
# @return [true]
|
57
|
+
# if scalar has fractions in decimal representation
|
58
|
+
#
|
59
|
+
# @return [false]
|
60
|
+
# if scalar NOT has fractions in decimal representation
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
#
|
64
|
+
def fractions?
|
65
|
+
scalar = self.scalar
|
66
|
+
!(scalar.numerator % scalar.denominator).zero?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return prettified units
|
70
|
+
#
|
71
|
+
# @param [Array] base
|
72
|
+
#
|
73
|
+
# @return [String]
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
#
|
77
|
+
def self.prettify_unit_part(base)
|
78
|
+
counts(base).map { |unit,length| length > 1 ? "#{unit}^#{length}" : unit }.join('*')
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return unit counts
|
82
|
+
#
|
83
|
+
# @param [Array] base
|
84
|
+
#
|
85
|
+
# @return [Hash]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
#
|
89
|
+
def self.counts(base)
|
90
|
+
counts = base.each_with_object(Hash.new(0)) { |unit,hash| hash[unit] += 1 }
|
91
|
+
counts.sort do |left,right|
|
92
|
+
result = right.last <=> left.last
|
93
|
+
if result == 0
|
94
|
+
left.first <=> right.first
|
95
|
+
else
|
96
|
+
result
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private_class_method :counts
|
102
|
+
end
|
103
|
+
end
|
data/lib/auom/version.rb
ADDED
data/spec/rcov.opts
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'an #each method' do
|
4
|
+
it_should_behave_like 'a command method'
|
5
|
+
|
6
|
+
context 'with no block' do
|
7
|
+
subject { object.each }
|
8
|
+
|
9
|
+
it { should be_instance_of(to_enum.class) }
|
10
|
+
|
11
|
+
it 'yields the expected values' do
|
12
|
+
subject.to_a.should eql(object.to_a)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'a hash method' do
|
4
|
+
it_should_behave_like 'an idempotent method'
|
5
|
+
|
6
|
+
specification = proc do
|
7
|
+
should be_instance_of(Fixnum)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is a fixnum' do
|
11
|
+
instance_eval(&specification)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'memoizes the hash code' do
|
15
|
+
subject.should eql(object.memoized(:hash))
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
shared_examples_for 'an operation' do
|
2
|
+
it 'returns a new object' do
|
3
|
+
object.should_not equal(subject)
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'is idempotent on equivalency' do
|
7
|
+
should eql(instance_eval(&self.class.subject))
|
8
|
+
end
|
9
|
+
|
10
|
+
its(:scalar) { should be_kind_of(::Rational) }
|
11
|
+
end
|
12
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec' # try for RSpec 2
|
3
|
+
rescue LoadError
|
4
|
+
require 'spec' # try for RSpec 1
|
5
|
+
RSpec = Spec::Runner
|
6
|
+
end
|
7
|
+
|
8
|
+
$LOAD_PATH << File.expand_path('../lib', __FILE__)
|
9
|
+
|
10
|
+
Dir.glob('spec/examples/**/*.rb').each { |file| require File.expand_path(file) }
|
11
|
+
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
12
|
+
|
13
|
+
require 'auom'
|