auom 0.2.0 → 0.3.0
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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +18 -0
- data/.rubocop.yml +1 -1
- data/Changelog.md +5 -0
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/auom.gemspec +6 -4
- data/config/devtools.yml +2 -0
- data/config/flay.yml +1 -1
- data/config/reek.yml +96 -97
- data/config/rubocop.yml +3 -0
- data/lib/auom.rb +2 -1
- data/lib/auom/algebra.rb +2 -0
- data/lib/auom/equalization.rb +2 -2
- data/lib/auom/inspection.rb +15 -10
- data/lib/auom/relational.rb +6 -76
- data/lib/auom/unit.rb +6 -8
- data/spec/shared/incompatible_operation_behavior.rb +2 -0
- data/spec/shared/operation_behavior.rb +3 -0
- data/spec/shared/sunits_shared.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/auom/algebra_spec.rb +279 -0
- data/spec/unit/auom/{equalization/equality_operator_spec.rb → equalization_spec.rb} +2 -1
- data/spec/unit/auom/inspection_spec.rb +73 -0
- data/spec/unit/auom/relational_spec.rb +39 -0
- data/spec/unit/auom/unit_spec.rb +377 -0
- metadata +18 -57
- data/.circle.yml +0 -4
- data/TODO +0 -1
- data/spec/unit/auom/algebra/add_spec.rb +0 -57
- data/spec/unit/auom/algebra/divide_spec.rb +0 -83
- data/spec/unit/auom/algebra/multiply_spec.rb +0 -80
- data/spec/unit/auom/algebra/substract_spec.rb +0 -57
- data/spec/unit/auom/inspection/class_methods/prettify_unit_part_spec.rb +0 -29
- data/spec/unit/auom/inspection/inspect_spec.rb +0 -39
- data/spec/unit/auom/relational/greater_than_or_equal_to_predicate_spec.rb +0 -38
- data/spec/unit/auom/relational/greater_than_predicate_spec.rb +0 -38
- data/spec/unit/auom/relational/less_than_or_equal_to_predicate_spec.rb +0 -38
- data/spec/unit/auom/relational/less_than_predicate_spec.rb +0 -38
- data/spec/unit/auom/unit/assert_same_unit_spec.rb +0 -20
- data/spec/unit/auom/unit/class_methods/convert_spec.rb +0 -33
- data/spec/unit/auom/unit/class_methods/lookup_spec.rb +0 -19
- data/spec/unit/auom/unit/class_methods/new_spec.rb +0 -152
- data/spec/unit/auom/unit/class_methods/try_convert_spec.rb +0 -35
- data/spec/unit/auom/unit/class_methods/units_spec.rb +0 -9
- data/spec/unit/auom/unit/denominators_spec.rb +0 -14
- data/spec/unit/auom/unit/numerators_spec.rb +0 -14
- data/spec/unit/auom/unit/same_unit_predicate_spec.rb +0 -20
- data/spec/unit/auom/unit/scalar_spec.rb +0 -14
- data/spec/unit/auom/unit/unit +0 -0
- data/spec/unit/auom/unit/unit_spec.rb +0 -14
- data/spec/unit/auom/unit/unitless_predicate_spec.rb +0 -22
data/lib/auom/unit.rb
CHANGED
@@ -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?
|
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
|
-
|
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 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) }
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|