auom 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +18 -0
  3. data/.rubocop.yml +1 -1
  4. data/Changelog.md +5 -0
  5. data/Gemfile +2 -0
  6. data/Rakefile +2 -0
  7. data/auom.gemspec +6 -4
  8. data/config/devtools.yml +2 -0
  9. data/config/flay.yml +1 -1
  10. data/config/reek.yml +96 -97
  11. data/config/rubocop.yml +3 -0
  12. data/lib/auom.rb +2 -1
  13. data/lib/auom/algebra.rb +2 -0
  14. data/lib/auom/equalization.rb +2 -2
  15. data/lib/auom/inspection.rb +15 -10
  16. data/lib/auom/relational.rb +6 -76
  17. data/lib/auom/unit.rb +6 -8
  18. data/spec/shared/incompatible_operation_behavior.rb +2 -0
  19. data/spec/shared/operation_behavior.rb +3 -0
  20. data/spec/shared/sunits_shared.rb +2 -0
  21. data/spec/spec_helper.rb +2 -0
  22. data/spec/unit/auom/algebra_spec.rb +279 -0
  23. data/spec/unit/auom/{equalization/equality_operator_spec.rb → equalization_spec.rb} +2 -1
  24. data/spec/unit/auom/inspection_spec.rb +73 -0
  25. data/spec/unit/auom/relational_spec.rb +39 -0
  26. data/spec/unit/auom/unit_spec.rb +377 -0
  27. metadata +18 -57
  28. data/.circle.yml +0 -4
  29. data/TODO +0 -1
  30. data/spec/unit/auom/algebra/add_spec.rb +0 -57
  31. data/spec/unit/auom/algebra/divide_spec.rb +0 -83
  32. data/spec/unit/auom/algebra/multiply_spec.rb +0 -80
  33. data/spec/unit/auom/algebra/substract_spec.rb +0 -57
  34. data/spec/unit/auom/inspection/class_methods/prettify_unit_part_spec.rb +0 -29
  35. data/spec/unit/auom/inspection/inspect_spec.rb +0 -39
  36. data/spec/unit/auom/relational/greater_than_or_equal_to_predicate_spec.rb +0 -38
  37. data/spec/unit/auom/relational/greater_than_predicate_spec.rb +0 -38
  38. data/spec/unit/auom/relational/less_than_or_equal_to_predicate_spec.rb +0 -38
  39. data/spec/unit/auom/relational/less_than_predicate_spec.rb +0 -38
  40. data/spec/unit/auom/unit/assert_same_unit_spec.rb +0 -20
  41. data/spec/unit/auom/unit/class_methods/convert_spec.rb +0 -33
  42. data/spec/unit/auom/unit/class_methods/lookup_spec.rb +0 -19
  43. data/spec/unit/auom/unit/class_methods/new_spec.rb +0 -152
  44. data/spec/unit/auom/unit/class_methods/try_convert_spec.rb +0 -35
  45. data/spec/unit/auom/unit/class_methods/units_spec.rb +0 -9
  46. data/spec/unit/auom/unit/denominators_spec.rb +0 -14
  47. data/spec/unit/auom/unit/numerators_spec.rb +0 -14
  48. data/spec/unit/auom/unit/same_unit_predicate_spec.rb +0 -20
  49. data/spec/unit/auom/unit/scalar_spec.rb +0 -14
  50. data/spec/unit/auom/unit/unit +0 -0
  51. data/spec/unit/auom/unit/unit_spec.rb +0 -14
  52. data/spec/unit/auom/unit/unitless_predicate_spec.rb +0 -22
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AUOM
2
4
  # A scalar with units
3
5
  class Unit
@@ -102,7 +104,7 @@ module AUOM
102
104
  # @api public
103
105
  #
104
106
  def unitless?
105
- numerators.empty? and denominators.empty?
107
+ numerators.empty? && denominators.empty?
106
108
  end
107
109
 
108
110
  # Test if units are the same
@@ -173,8 +175,7 @@ module AUOM
173
175
  scalar, numerators = resolve([*numerators], scalar, :*)
174
176
  scalar, denominators = resolve([*denominators], scalar, :/)
175
177
 
176
- # sorting on #to_s as Symbol#<=> is not present on 1.8.7
177
- super(scalar, *[numerators, denominators].map { |base| base.sort_by(&:to_s) }).freeze
178
+ super(scalar, *[numerators, denominators].map(&:sort)).freeze
178
179
  end
179
180
 
180
181
  # Assert units are the same
@@ -186,9 +187,7 @@ module AUOM
186
187
  # @api private
187
188
  #
188
189
  def assert_same_unit(other)
189
- unless same_unit?(other)
190
- fail ArgumentError, 'Incompatible units'
191
- end
190
+ fail ArgumentError, 'Incompatible units' unless same_unit?(other)
192
191
 
193
192
  self
194
193
  end
@@ -209,6 +208,7 @@ module AUOM
209
208
  unless converted
210
209
  fail ArgumentError, "Cannot convert #{operand.inspect} to #{self}"
211
210
  end
211
+
212
212
  converted
213
213
  end
214
214
 
@@ -254,7 +254,6 @@ module AUOM
254
254
  @denominators = denominators.freeze
255
255
 
256
256
  @unit = [numerators, denominators].freeze
257
- scalar.freeze
258
257
  end
259
258
 
260
259
  # Return rational converted from value
@@ -317,6 +316,5 @@ module AUOM
317
316
  end
318
317
 
319
318
  private_class_method :lookup
320
-
321
319
  end # Unit
322
320
  end # AUOM
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for 'an incompatible operation' do
2
4
  it 'should raise ArgumentError' do
3
5
  expect { subject }.to raise_error(ArgumentError, 'Incompatible units')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for 'an operation' do
2
4
  it 'returns a new object' do
3
5
  expect(object).to_not equal(subject)
@@ -6,6 +8,7 @@ shared_examples_for 'an operation' do
6
8
  it 'is idempotent on equivalency' do
7
9
  first = subject
8
10
  fail unless RSpec.configuration.threadsafe?
11
+
9
12
  mutex = __memoized.instance_variable_get(:@mutex)
10
13
  memoized = __memoized.instance_variable_get(:@memoized)
11
14
  mutex.synchronize { memoized.delete(:subject) }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for 'unitless unit' do
2
4
  its(:numerators) { should == [] }
3
5
  its(:denominators) { should == [] }
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'auom'
2
4
  require 'devtools/spec_helper'
@@ -0,0 +1,279 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe AUOM::Algebra do
4
+ describe '#add' do
5
+ subject { object.add(operand) }
6
+
7
+ let(:object) { AUOM::Unit.new(*arguments) }
8
+
9
+ context 'when unit is unitless' do
10
+ let(:arguments) { [1] }
11
+
12
+ context 'and operand is an Integer' do
13
+ let(:operand) { 2 }
14
+
15
+ it_should_behave_like 'an operation'
16
+
17
+ it { should eql(AUOM::Unit.new(3)) }
18
+ end
19
+
20
+ context 'and operand is a unitless unit' do
21
+ let(:operand) { AUOM::Unit.new(2) }
22
+
23
+ it { should eql(AUOM::Unit.new(3)) }
24
+ end
25
+
26
+ context 'and operand is a unitful unit' do
27
+ let(:operand) { AUOM::Unit.new(2, :meter) }
28
+
29
+ it_should_behave_like 'an incompatible operation'
30
+ end
31
+ end
32
+
33
+ context 'when unit is unitful' do
34
+ let(:arguments) { [1, :meter, :euro] }
35
+
36
+ context 'and operand is an Integer' do
37
+ let(:operand) { 2 }
38
+
39
+ it_should_behave_like 'an incompatible operation'
40
+ end
41
+
42
+ context 'and operand is a unitless unit' do
43
+ let(:operand) { AUOM::Unit.new(2) }
44
+
45
+ it_should_behave_like 'an incompatible operation'
46
+ end
47
+
48
+ context 'and operand is a incompatible unit' do
49
+ let(:operand) { AUOM::Unit.new(2, :euro) }
50
+
51
+ it_should_behave_like 'an incompatible operation'
52
+ end
53
+
54
+ context 'and operand is a compatible unit' do
55
+ let(:operand) { AUOM::Unit.new(2, :meter, :euro) }
56
+
57
+ it { should eql(AUOM::Unit.new(3, :meter, :euro)) }
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#divide' do
63
+ subject { object.divide(operand) }
64
+
65
+ let(:object) { AUOM::Unit.new(*arguments) }
66
+
67
+ context 'with unitless unit' do
68
+ let(:arguments) { [4] }
69
+
70
+ context 'when operand is a fixnum' do
71
+ let(:operand) { 2 }
72
+
73
+ it_should_behave_like 'an operation'
74
+
75
+ it { should eql(AUOM::Unit.new(2)) }
76
+ end
77
+
78
+ context 'when operand is a unitless unit' do
79
+ let(:operand) { AUOM::Unit.new(2) }
80
+
81
+ it_should_behave_like 'an operation'
82
+
83
+ it { should eql(AUOM::Unit.new(2)) }
84
+ end
85
+
86
+ context 'when operand is a unitful unit' do
87
+ let(:operand) { AUOM::Unit.new(2, :meter) }
88
+
89
+ it_should_behave_like 'an operation'
90
+
91
+ it { should eql(AUOM::Unit.new(2, [], :meter)) }
92
+ end
93
+ end
94
+
95
+ context 'with unitful unit' do
96
+ let(:arguments) { [2, :meter] }
97
+
98
+ context 'when operand is a fixnum' do
99
+ let(:operand) { 1 }
100
+
101
+ it_should_behave_like 'an operation'
102
+
103
+ it { should eql(AUOM::Unit.new(2, :meter)) }
104
+ end
105
+
106
+ context 'when operand is a unitless unit' do
107
+ let(:operand) { AUOM::Unit.new(1) }
108
+
109
+ it_should_behave_like 'an operation'
110
+
111
+ it { should eql(AUOM::Unit.new(2, :meter)) }
112
+ end
113
+
114
+ context 'when operand is a unitful unit' do
115
+ context 'and units get added to denominator' do
116
+ let(:operand) { AUOM::Unit.new(1, :euro) }
117
+
118
+ it_should_behave_like 'an operation'
119
+
120
+ it { should eql(AUOM::Unit.new(2, :meter, :euro)) }
121
+ end
122
+
123
+ context 'and units get added to numerator' do
124
+ let(:operand) { AUOM::Unit.new(1, nil, :euro) }
125
+
126
+ it_should_behave_like 'an operation'
127
+
128
+ it { should eql(AUOM::Unit.new(2, %i[euro meter])) }
129
+ end
130
+
131
+ context 'and units cancel each other' do
132
+ let(:operand) { AUOM::Unit.new(1, :meter) }
133
+
134
+ it_should_behave_like 'an operation'
135
+
136
+ it { should eql(AUOM::Unit.new(2)) }
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ describe '#multiply' do
143
+ subject { object.multiply(operand) }
144
+
145
+ let(:object) { AUOM::Unit.new(*arguments) }
146
+
147
+ context 'with unitless unit' do
148
+ let(:arguments) { [2] }
149
+
150
+ context 'when operand is a fixnum' do
151
+ let(:operand) { 3 }
152
+
153
+ it_should_behave_like 'an operation'
154
+
155
+ it { should eql(AUOM::Unit.new(6)) }
156
+ end
157
+
158
+ context 'when operand is a unitless unit' do
159
+ let(:operand) { AUOM::Unit.new(3) }
160
+
161
+ it_should_behave_like 'an operation'
162
+
163
+ it { should eql(AUOM::Unit.new(6)) }
164
+ end
165
+
166
+ context 'when operand is a unitful unit' do
167
+ let(:operand) { AUOM::Unit.new(3, :meter) }
168
+
169
+ it_should_behave_like 'an operation'
170
+
171
+ it { should eql(AUOM::Unit.new(6, :meter)) }
172
+ end
173
+ end
174
+
175
+ context 'with unitful unit' do
176
+ let(:arguments) { [2, :meter, :kilogramm] }
177
+
178
+ context 'when operand is a fixnum' do
179
+ let(:operand) { 3 }
180
+
181
+ it_should_behave_like 'an operation'
182
+
183
+ it { should eql(AUOM::Unit.new(6, :meter, :kilogramm)) }
184
+ end
185
+
186
+ context 'when operand is a unitless unit' do
187
+ let(:operand) { AUOM::Unit.new(3) }
188
+
189
+ it_should_behave_like 'an operation'
190
+
191
+ it { should eql(AUOM::Unit.new(6, :meter, :kilogramm)) }
192
+ end
193
+
194
+ context 'when operand is a unitful unit' do
195
+ context 'and units get added to numerator' do
196
+ let(:operand) { AUOM::Unit.new(3, :meter) }
197
+
198
+ it_should_behave_like 'an operation'
199
+
200
+ it { should eql(AUOM::Unit.new(6, %i[meter meter], :kilogramm)) }
201
+ end
202
+
203
+ context 'and units get added to denominator' do
204
+ let(:operand) { AUOM::Unit.new(3, [], :euro) }
205
+
206
+ it_should_behave_like 'an operation'
207
+
208
+ it { should eql(AUOM::Unit.new(6, :meter, %i[euro kilogramm])) }
209
+ end
210
+
211
+ context 'and units cancel each other' do
212
+ let(:operand) { AUOM::Unit.new(3, [], :meter) }
213
+
214
+ it_should_behave_like 'an operation'
215
+
216
+ it { should eql(AUOM::Unit.new(6, [], :kilogramm)) }
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ describe '#subtract' do
223
+ subject { object.subtract(operand) }
224
+
225
+ let(:object) { AUOM::Unit.new(*arguments) }
226
+
227
+ context 'when unit is unitless' do
228
+ let(:arguments) { [1] }
229
+
230
+ context 'and operand is an Integer' do
231
+ let(:operand) { 1 }
232
+
233
+ it_should_behave_like 'an operation'
234
+
235
+ it { should eql(AUOM::Unit.new(0)) }
236
+ end
237
+
238
+ context 'and operand is a unitless unit' do
239
+ let(:operand) { AUOM::Unit.new(1) }
240
+
241
+ it { should eql(AUOM::Unit.new(0)) }
242
+ end
243
+
244
+ context 'and operand is a unitful unit' do
245
+ let(:operand) { AUOM::Unit.new(1, :meter) }
246
+
247
+ it_should_behave_like 'an incompatible operation'
248
+ end
249
+ end
250
+
251
+ context 'when unit is unitful' do
252
+ let(:arguments) { [1, :meter] }
253
+
254
+ context 'and operand is an Integer' do
255
+ let(:operand) { 1 }
256
+
257
+ it_should_behave_like 'an incompatible operation'
258
+ end
259
+
260
+ context 'and operand is a unitless unit' do
261
+ let(:operand) { AUOM::Unit.new(1) }
262
+
263
+ it_should_behave_like 'an incompatible operation'
264
+ end
265
+
266
+ context 'and operand is a incompatible unit' do
267
+ let(:operand) { AUOM::Unit.new(1, :euro) }
268
+
269
+ it_should_behave_like 'an incompatible operation'
270
+ end
271
+
272
+ context 'and operand is a compatible unit' do
273
+ let(:operand) { AUOM::Unit.new(1, :meter) }
274
+
275
+ it { should eql(AUOM::Unit.new(0, :meter)) }
276
+ end
277
+ end
278
+ end
279
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  describe AUOM::Equalization, '#==' do
2
4
  subject { object == other }
3
5
 
4
6
  let(:object) { AUOM::Unit.new(1, :meter) }
5
7
 
6
8
  context 'when is other kind of object' do
7
-
8
9
  context 'that cannot be converted' do
9
10
  let(:other) { Object.new }
10
11
 
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe AUOM::Inspection do
4
+ describe '#inspect' do
5
+ subject { object.inspect }
6
+
7
+ let(:object) { AUOM::Unit.new(scalar, *unit) }
8
+ let(:unit) { [] }
9
+
10
+ context 'when scalar is exact in decimal' do
11
+ let(:scalar) { 1 }
12
+
13
+ it { should eql('<AUOM::Unit @scalar=1>') }
14
+ end
15
+
16
+ context 'when scalar is NOT exact in decimal' do
17
+ let(:scalar) { Rational(1, 2) }
18
+
19
+ it { should eql('<AUOM::Unit @scalar=~0.5000>') }
20
+ end
21
+
22
+ context 'when has only numerator' do
23
+ let(:scalar) { Rational(1, 3) }
24
+ let(:unit) { [:meter] }
25
+
26
+ it { should eql('<AUOM::Unit @scalar=~0.3333 meter>') }
27
+ end
28
+
29
+ context 'when has only denominator' do
30
+ let(:scalar) { Rational(1, 3) }
31
+ let(:unit) { [[], :meter] }
32
+
33
+ it { should eql('<AUOM::Unit @scalar=~0.3333 1/meter>') }
34
+ end
35
+
36
+ context 'when has numerator and denominator' do
37
+ let(:scalar) { Rational(1, 3) }
38
+ let(:unit) { %i[euro meter] }
39
+
40
+ it { should eql('<AUOM::Unit @scalar=~0.3333 euro/meter>') }
41
+ end
42
+ end
43
+
44
+ describe '.prettify_unit_part' do
45
+ subject { object.prettify_unit_part(part) }
46
+
47
+ let(:object) { AUOM::Inspection }
48
+
49
+ context 'with simple part' do
50
+ let(:part) { [:meter] }
51
+
52
+ it { should eql('meter') }
53
+ end
54
+
55
+ context 'with mixed part' do
56
+ let(:part) { %i[meter euro] }
57
+
58
+ it { should eql('euro*meter') }
59
+ end
60
+
61
+ context 'with complex part' do
62
+ let(:part) { %i[meter meter euro] }
63
+
64
+ it { should eql('meter^2*euro') }
65
+ end
66
+
67
+ context 'with very complex part' do
68
+ let(:part) { %i[meter meter euro euro kilogramm] }
69
+
70
+ it { should eql('euro^2*meter^2*kilogramm') }
71
+ end
72
+ end
73
+ end