auom 0.0.3

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