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.
Files changed (54) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +13 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.devtools +52 -0
  6. data/Guardfile +8 -0
  7. data/LICENSE +20 -0
  8. data/README.md +92 -0
  9. data/Rakefile +5 -0
  10. data/TODO +3 -0
  11. data/auom.gemspec +21 -0
  12. data/config/flay.yml +3 -0
  13. data/config/flog.yml +2 -0
  14. data/config/heckle.yml +9 -0
  15. data/config/roodi.yml +20 -0
  16. data/config/site.reek +95 -0
  17. data/config/yardstick.yml +2 -0
  18. data/lib/auom.rb +287 -0
  19. data/lib/auom/algebra.rb +129 -0
  20. data/lib/auom/equalization.rb +90 -0
  21. data/lib/auom/inspection.rb +103 -0
  22. data/lib/auom/version.rb +3 -0
  23. data/spec/rcov.opts +7 -0
  24. data/spec/shared/command_method_behavior.rb +7 -0
  25. data/spec/shared/each_method_behaviour.rb +15 -0
  26. data/spec/shared/hash_method_behavior.rb +17 -0
  27. data/spec/shared/idempotent_method_behavior.rb +7 -0
  28. data/spec/shared/incompatible_operation_behavior.rb +5 -0
  29. data/spec/shared/invertible_method_behaviour.rb +9 -0
  30. data/spec/shared/operation_behavior.rb +12 -0
  31. data/spec/shared/sunits_shared.rb +6 -0
  32. data/spec/spec.opts +3 -0
  33. data/spec/spec_helper.rb +13 -0
  34. data/spec/unit/auom/add_spec.rb +0 -0
  35. data/spec/unit/auom/algebra/add_spec.rb +59 -0
  36. data/spec/unit/auom/algebra/divide_spec.rb +74 -0
  37. data/spec/unit/auom/algebra/multiply_spec.rb +74 -0
  38. data/spec/unit/auom/algebra/substract_spec.rb +59 -0
  39. data/spec/unit/auom/equalization/eql_spec.rb +40 -0
  40. data/spec/unit/auom/equalization/equal_value_spec.rb +57 -0
  41. data/spec/unit/auom/equalization/hash_spec.rb +13 -0
  42. data/spec/unit/auom/inspection/class_methods/prettify_unit_part_spec.rb +27 -0
  43. data/spec/unit/auom/inspection/inspect_spec.rb +41 -0
  44. data/spec/unit/auom/unit/class_methods/convert_spec.rb +35 -0
  45. data/spec/unit/auom/unit/class_methods/lookup_spec.rb +21 -0
  46. data/spec/unit/auom/unit/class_methods/new_spec.rb +156 -0
  47. data/spec/unit/auom/unit/class_methods/try_convert_spec.rb +31 -0
  48. data/spec/unit/auom/unit/class_methods/units_spec.rb +11 -0
  49. data/spec/unit/auom/unit/denominators_spec.rb +16 -0
  50. data/spec/unit/auom/unit/numerators_spec.rb +16 -0
  51. data/spec/unit/auom/unit/scalar_spec.rb +16 -0
  52. data/spec/unit/auom/unit/unit_spec.rb +16 -0
  53. data/spec/unit/auom/unit/unitless_spec.rb +18 -0
  54. metadata +164 -0
@@ -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
@@ -0,0 +1,3 @@
1
+ module AUOM
2
+ VERSION = '0.0.3'.freeze
3
+ end
@@ -0,0 +1,7 @@
1
+ --exclude-only "spec/,^/"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
7
+ --failure-threshold 100
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'a command method' do
4
+ it 'returns self' do
5
+ should equal(object)
6
+ end
7
+ end
@@ -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,7 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'an idempotent method' do
4
+ it 'is idempotent' do
5
+ should equal(instance_eval(&self.class.subject))
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ shared_examples_for 'an incompatible operation' do
2
+ it 'should raise ArgumentError' do
3
+ expect { subject }.to raise_error(ArgumentError,'Incompatible units for substraction or addition')
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'an invertible method' do
4
+ it_should_behave_like 'an idempotent method'
5
+
6
+ it 'is invertible' do
7
+ subject.inverse.should equal(object)
8
+ end
9
+ 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
+
@@ -0,0 +1,6 @@
1
+ shared_examples_for 'unitless unit' do
2
+ its(:numerators) { should == [] }
3
+ its(:denominators) { should == [] }
4
+ its(:unit) { should == [[],[]] }
5
+ it { should be_unitless }
6
+ end
@@ -0,0 +1,3 @@
1
+ --color
2
+ --loadby random
3
+ --format profile
@@ -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'