ruby-measurement 1.2.0 → 1.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.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/CI.yml +30 -0
  3. data/CHANGELOG.md +25 -10
  4. data/README.md +13 -7
  5. data/lib/ruby-measurement/core_ext/string.rb +2 -2
  6. data/lib/ruby-measurement/core_ext/symbol.rb +1 -1
  7. data/lib/ruby-measurement/measurement.rb +101 -42
  8. data/lib/ruby-measurement/unit.rb +34 -28
  9. data/lib/ruby-measurement/version.rb +1 -1
  10. data/ruby-measurement.gemspec +5 -4
  11. data/spec/ruby-measurement/core_ext/numeric_spec.rb +2 -2
  12. data/spec/ruby-measurement/core_ext/string_spec.rb +12 -12
  13. data/spec/ruby-measurement/core_ext/symbol_spec.rb +3 -3
  14. data/spec/ruby-measurement/definitions/metric/area_spec.rb +32 -32
  15. data/spec/ruby-measurement/definitions/metric/capacity_spec.rb +18 -18
  16. data/spec/ruby-measurement/definitions/metric/length_spec.rb +128 -128
  17. data/spec/ruby-measurement/definitions/metric/volume_spec.rb +128 -128
  18. data/spec/ruby-measurement/definitions/metric/weight_spec.rb +160 -160
  19. data/spec/ruby-measurement/definitions/us_customary/area_spec.rb +72 -72
  20. data/spec/ruby-measurement/definitions/us_customary/capacity_spec.rb +32 -32
  21. data/spec/ruby-measurement/definitions/us_customary/length_spec.rb +128 -128
  22. data/spec/ruby-measurement/definitions/us_customary/volume_spec.rb +98 -98
  23. data/spec/ruby-measurement/definitions/us_customary/weight_spec.rb +72 -72
  24. data/spec/ruby-measurement/measurement_spec.rb +238 -164
  25. data/spec/ruby-measurement/unit_builder_spec.rb +35 -35
  26. data/spec/ruby-measurement/unit_spec.rb +84 -41
  27. data/tasks/rspec.rake +1 -1
  28. metadata +29 -25
  29. data/.travis.yml +0 -4
@@ -1,342 +1,416 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe Measurement do
4
- subject { Measurement }
5
-
5
+ RSpec.describe Measurement do
6
+ subject { described_class }
7
+
6
8
  describe '.new' do
7
9
  describe 'with valid quantity' do
8
10
  it 'sets the quantity' do
9
- subject.new(3).quantity.should eq 3
11
+ expect(subject.new(3).quantity).to eq 3
10
12
  end
11
-
13
+
12
14
  it 'sets the default unit' do
13
- subject.new(3).unit.should eq subject::Unit[:count]
15
+ expect(subject.new(3).unit).to eq subject::Unit[:count]
14
16
  end
15
17
  end
16
-
18
+
17
19
  describe 'with valid quantity and unit name' do
18
20
  it 'sets the quantity' do
19
- subject.new(2, :dozen).quantity.should eq 2
21
+ expect(subject.new(2, :dozen).quantity).to eq 2
20
22
  end
21
-
23
+
22
24
  it 'sets the unit' do
23
- subject.new(2, :dozen).unit.should eq subject::Unit[:dozen]
25
+ expect(subject.new(2, :dozen).unit).to eq subject::Unit[:dozen]
24
26
  end
25
27
  end
26
-
28
+
27
29
  describe 'with valid quantity and unit' do
28
30
  it 'sets the quantity' do
29
- subject.new(2, subject::Unit[:dozen]).quantity.should eq 2
31
+ expect(subject.new(2, subject::Unit[:dozen]).quantity).to eq 2
30
32
  end
31
-
33
+
32
34
  it 'sets the unit' do
33
- subject.new(2, subject::Unit[:dozen]).unit.should eq subject::Unit[:dozen]
35
+ expect(subject.new(2, subject::Unit[:dozen]).unit).to eq subject::Unit[:dozen]
34
36
  end
35
37
  end
36
-
38
+
37
39
  describe 'with invalid quantity' do
38
40
  it 'raises exception' do
39
- expect { subject.new('hi') }.to raise_exception
41
+ expect { subject.new('hi') }.to raise_error(ArgumentError, "Invalid quantity: 'hi'")
40
42
  end
41
43
  end
42
-
44
+
43
45
  describe 'with invalid unit' do
44
46
  it 'raises exception' do
45
- expect { subject.new(3, :finklebaum) }.to raise_exception
47
+ expect { subject.new(3, :finklebaum) }.to raise_error(ArgumentError, "Invalid unit: 'finklebaum'")
46
48
  end
47
49
  end
48
50
  end
49
-
51
+
50
52
  describe '.parse' do
51
53
  describe 'quantity' do
52
54
  it 'parses scientific notation' do
53
55
  m = subject.parse('4.3e12')
54
- m.quantity.should eq 4.3e12
55
- m.unit.should eq subject::Unit[:count]
56
-
56
+ expect(m.quantity).to eq 4.3e12
57
+ expect(m.unit).to eq Measurement::Unit[:count]
58
+
57
59
  m = subject.parse('4.3e12 dozen')
58
- m.quantity.should eq 4.3e12
59
- m.unit.should eq subject::Unit[:dozen]
60
-
60
+ expect(m.quantity).to eq 4.3e12
61
+ expect(m.unit).to eq Measurement::Unit[:dozen]
62
+
61
63
  m = subject.parse('4.3e12doz')
62
- m.quantity.should eq 4.3e12
63
- m.unit.should eq subject::Unit[:dozen]
64
+ expect(m.quantity).to eq 4.3e12
65
+ expect(m.unit).to eq Measurement::Unit[:dozen]
64
66
  end
65
-
67
+
66
68
  it 'parses fractions' do
67
69
  m = subject.parse('1/4')
68
- m.quantity.should eq 0.25
69
- m.unit.should eq subject::Unit[:count]
70
-
70
+ expect(m.quantity).to eq 0.25
71
+ expect(m.unit).to eq Measurement::Unit[:count]
72
+
71
73
  m = subject.parse('1/4 dozen')
72
- m.quantity.should eq 0.25
73
- m.unit.should eq subject::Unit[:dozen]
74
-
74
+ expect(m.quantity).to eq 0.25
75
+ expect(m.unit).to eq Measurement::Unit[:dozen]
76
+
75
77
  m = subject.parse('1/4doz')
76
- m.quantity.should eq 0.25
77
- m.unit.should eq subject::Unit[:dozen]
78
+ expect(m.quantity).to eq 0.25
79
+ expect(m.unit).to eq Measurement::Unit[:dozen]
78
80
  end
79
-
81
+
80
82
  it 'parses mixed fractions' do
81
83
  m = subject.parse('3 2/5')
82
- m.quantity.should eq 3.4
83
- m.unit.should eq subject::Unit[:count]
84
-
84
+ expect(m.quantity).to eq 3.4
85
+ expect(m.unit).to eq Measurement::Unit[:count]
86
+
85
87
  m = subject.parse('3 2/5 dozen')
86
- m.quantity.should eq 3.4
87
- m.unit.should eq subject::Unit[:dozen]
88
-
89
- m = subject.parse('3 2/5')
90
- m.quantity.should eq 3.4
91
- m.unit.should eq subject::Unit[:count]
88
+ expect(m.quantity).to eq 3.4
89
+ expect(m.unit).to eq Measurement::Unit[:dozen]
92
90
  end
93
-
91
+
92
+ it 'parses fractions with special characters' do
93
+ m = subject.parse('⅜')
94
+ expect(m.quantity).to eq 0.375
95
+ expect(m.unit).to eq Measurement::Unit[:count]
96
+
97
+ m = subject.parse('⅜ dozen')
98
+ expect(m.quantity).to eq 0.375
99
+ expect(m.unit).to eq Measurement::Unit[:dozen]
100
+
101
+ m = subject.parse('⅜doz')
102
+ expect(m.quantity).to eq 0.375
103
+ expect(m.unit).to eq Measurement::Unit[:dozen]
104
+ end
105
+
106
+ it 'parses mixed fractions with special characters' do
107
+ m = subject.parse('3⅜')
108
+ expect(m.quantity).to eq 3.375
109
+ expect(m.unit).to eq Measurement::Unit[:count]
110
+
111
+ m = subject.parse('3 ⅜')
112
+ expect(m.quantity).to eq 3.375
113
+ expect(m.unit).to eq Measurement::Unit[:count]
114
+
115
+ m = subject.parse('3⅜ dozen')
116
+ expect(m.quantity).to eq 3.375
117
+ expect(m.unit).to eq Measurement::Unit[:dozen]
118
+
119
+ m = subject.parse('3 ⅜ dozen')
120
+ expect(m.quantity).to eq 3.375
121
+ expect(m.unit).to eq Measurement::Unit[:dozen]
122
+
123
+ m = subject.parse('3⅜doz')
124
+ expect(m.quantity).to eq 3.375
125
+ expect(m.unit).to eq Measurement::Unit[:dozen]
126
+ end
127
+
94
128
  it 'parses decimals' do
95
129
  m = subject.parse('2.1')
96
- m.quantity.should eq 2.1
97
- m.unit.should eq subject::Unit[:count]
98
-
130
+ expect(m.quantity).to eq 2.1
131
+ expect(m.unit).to eq Measurement::Unit[:count]
132
+
99
133
  m = subject.parse('2.1 dozen')
100
- m.quantity.should eq 2.1
101
- m.unit.should eq subject::Unit[:dozen]
102
-
134
+ expect(m.quantity).to eq 2.1
135
+ expect(m.unit).to eq Measurement::Unit[:dozen]
136
+
103
137
  m = subject.parse('2.1doz')
104
- m.quantity.should eq 2.1
105
- m.unit.should eq subject::Unit[:dozen]
138
+ expect(m.quantity).to eq 2.1
139
+ expect(m.unit).to eq Measurement::Unit[:dozen]
106
140
  end
107
141
  end
108
-
142
+
109
143
  describe 'unit' do
110
144
  it 'converts when defined' do
111
- subject.parse('3 dozen').unit.should eq subject::Unit[:dozen]
145
+ expect(subject.parse('3 dozen').unit).to eq Measurement::Unit[:dozen]
112
146
  end
113
-
147
+
114
148
  it 'raises exception when undefined' do
115
- expect { subject.parse('3 finklebaums') }.to raise_error
149
+ expect { subject.parse('3 finklebaums') }.to raise_error(ArgumentError, "Invalid unit: 'finklebaums'")
116
150
  end
117
151
  end
118
152
  end
119
-
153
+
120
154
  describe '.define' do
121
155
  it 'delegates to Unit.define' do
122
- subject::Unit.should_receive(:define)
156
+ expect(Measurement::Unit).to receive(:define)
123
157
  subject.define(:something)
124
158
  end
125
159
  end
126
-
160
+
127
161
  describe '#convert_to' do
128
162
  let(:measurement) { subject.new(3) }
129
-
163
+
130
164
  it 'returns copy of self when target unit matches current unit' do
131
165
  result = measurement.convert_to(:count)
132
- result.should_not be measurement
133
- result.should eq measurement
166
+ expect(result).to_not be measurement
167
+ expect(result).to eq measurement
134
168
  end
135
-
169
+
136
170
  it 'returns target unit if it exists and is convertable' do
137
171
  result = measurement.convert_to(:dozen)
138
- result.quantity.should eq 0.25
139
- result.unit.should eq subject::Unit[:dozen]
172
+ expect(result.quantity).to eq 0.25
173
+ expect(result.unit).to eq Measurement::Unit[:dozen]
140
174
  end
141
-
175
+
142
176
  it 'raises exception if unit exists and is not convertable' do
143
- expect { measurement.convert_to(:inches) }.to raise_error
177
+ expect { measurement.convert_to(:inches) }.to raise_error(ArgumentError, "Invalid conversion: 'count' to 'in.'")
144
178
  end
145
-
179
+
146
180
  it 'raises exception if unit does not exist' do
147
- expect { measurement.convert_to(:finklebaum) }.to raise_error
181
+ expect { measurement.convert_to(:finklebaum) }.to raise_error(ArgumentError, "Invalid unit: 'finklebaum'")
148
182
  end
149
183
  end
150
-
184
+
151
185
  describe '#convert_to!' do
152
186
  let(:measurement) { subject.new(3) }
153
-
187
+
154
188
  it 'modifies the object' do
155
189
  measurement.convert_to!(:dozen)
156
- measurement.quantity.should eq 0.25
157
- measurement.unit.should eq subject::Unit[:dozen]
190
+ expect(measurement.quantity).to eq 0.25
191
+ expect(measurement.unit).to eq Measurement::Unit[:dozen]
158
192
  end
159
193
  end
160
-
194
+
161
195
  describe '#+' do
162
196
  let(:measurement) { subject.new(3) }
163
-
197
+
164
198
  it 'adds numeric values' do
165
199
  result = measurement + 4
166
- result.quantity.should eq 7
167
- result.unit.should eq measurement.unit
200
+ expect(result.quantity).to eq 7
201
+ expect(result.unit).to eq measurement.unit
168
202
  end
169
-
203
+
170
204
  it 'adds units of the same type' do
171
205
  other = subject.new(4)
172
- other.unit.should eq measurement.unit
173
-
206
+ expect(other.unit).to eq measurement.unit
207
+
174
208
  result = measurement + other
175
- result.quantity.should eq 7
176
- result.unit.should eq measurement.unit
209
+ expect(result.quantity).to eq 7
210
+ expect(result.unit).to eq measurement.unit
177
211
  end
178
-
212
+
179
213
  it 'adds units of a convertable type' do
180
214
  other = subject.new(2, :dozen)
181
- other.unit.should_not eq measurement.unit
182
-
215
+ expect(other.unit).to_not eq measurement.unit
216
+
183
217
  result = measurement + other
184
- result.quantity.should eq 27
185
- result.unit.should eq measurement.unit
218
+ expect(result.quantity).to eq 27
219
+ expect(result.unit).to eq measurement.unit
186
220
  end
187
-
221
+
188
222
  it 'raises exception for incompatible units' do
189
223
  other = subject.new(4, :inches)
190
- other.unit.should_not eq measurement.unit
191
- expect { measurement + other }.to raise_error
224
+ expect(other.unit).to_not eq measurement.unit
225
+ expect { measurement + other }.to raise_error(ArgumentError, "Invalid conversion: 'in.' to 'count'")
192
226
  end
193
227
  end
194
-
228
+
195
229
  describe '#-' do
196
230
  let(:measurement) { subject.new(3) }
197
-
231
+
198
232
  it 'subtracts numeric values' do
199
233
  result = measurement - 4
200
- result.quantity.should eq -1
201
- result.unit.should eq measurement.unit
234
+ expect(result.quantity).to eq(-1)
235
+ expect(result.unit).to eq measurement.unit
202
236
  end
203
-
237
+
204
238
  it 'subtracts units of the same type' do
205
239
  other = subject.new(4)
206
- other.unit.should eq measurement.unit
207
-
240
+ expect(other.unit).to eq measurement.unit
241
+
208
242
  result = measurement - other
209
- result.quantity.should eq -1
210
- result.unit.should eq measurement.unit
243
+ expect(result.quantity).to eq(-1)
244
+ expect(result.unit).to eq measurement.unit
211
245
  end
212
-
246
+
213
247
  it 'subtracts units of a convertable type' do
214
248
  other = subject.new(2, :dozen)
215
- other.unit.should_not eq measurement.unit
216
-
249
+ expect(other.unit).to_not eq measurement.unit
250
+
217
251
  result = measurement - other
218
- result.quantity.should eq -21
219
- result.unit.should eq measurement.unit
252
+ expect(result.quantity).to eq(-21)
253
+ expect(result.unit).to eq measurement.unit
220
254
  end
221
-
255
+
222
256
  it 'raises exception for incompatible units' do
223
257
  other = subject.new(4, :inches)
224
- other.unit.should_not eq measurement.unit
225
- expect { measurement - other }.to raise_error
258
+ expect(other.unit).to_not eq measurement.unit
259
+ expect { measurement - other }.to raise_error(ArgumentError, "Invalid conversion: 'in.' to 'count'")
226
260
  end
227
261
  end
228
-
262
+
229
263
  describe '#*' do
230
264
  let(:measurement) { subject.new(3) }
231
-
265
+
232
266
  it 'multiplies numeric values' do
233
267
  result = measurement * 4
234
- result.quantity.should eq 12
235
- result.unit.should eq measurement.unit
268
+ expect(result.quantity).to eq 12
269
+ expect(result.unit).to eq measurement.unit
236
270
  end
237
-
271
+
238
272
  it 'multiplies units of the same type' do
239
273
  other = subject.new(4)
240
- other.unit.should eq measurement.unit
241
-
274
+ expect(other.unit).to eq measurement.unit
275
+
242
276
  result = measurement * other
243
- result.quantity.should eq 12
244
- result.unit.should eq measurement.unit
277
+ expect(result.quantity).to eq 12
278
+ expect(result.unit).to eq measurement.unit
245
279
  end
246
-
280
+
247
281
  it 'multiplies units of a convertable type' do
248
282
  other = subject.new(2, :dozen)
249
- other.unit.should_not eq measurement.unit
250
-
283
+ expect(other.unit).to_not eq measurement.unit
284
+
251
285
  result = measurement * other
252
- result.quantity.should eq 72
253
- result.unit.should eq measurement.unit
286
+ expect(result.quantity).to eq 72
287
+ expect(result.unit).to eq measurement.unit
254
288
  end
255
-
289
+
256
290
  it 'raises exception for incompatible units' do
257
291
  other = subject.new(4, :inches)
258
- other.unit.should_not eq measurement.unit
259
- expect { measurement * other }.to raise_error
292
+ expect(other.unit).to_not eq measurement.unit
293
+ expect { measurement * other }.to raise_error(ArgumentError, "Invalid conversion: 'in.' to 'count'")
260
294
  end
261
295
  end
262
-
296
+
263
297
  describe '#/' do
264
298
  let(:measurement) { subject.new(12) }
265
-
299
+
266
300
  it 'divides numeric values' do
267
301
  result = measurement / 4
268
- result.quantity.should eq 3
269
- result.unit.should eq measurement.unit
302
+ expect(result.quantity).to eq 3
303
+ expect(result.unit).to eq measurement.unit
270
304
  end
271
-
305
+
272
306
  it 'divides units of the same type' do
273
307
  other = subject.new(4)
274
- other.unit.should eq measurement.unit
275
-
308
+ expect(other.unit).to eq measurement.unit
309
+
276
310
  result = measurement / other
277
- result.quantity.should eq 3
278
- result.unit.should eq measurement.unit
311
+ expect(result.quantity).to eq 3
312
+ expect(result.unit).to eq measurement.unit
279
313
  end
280
-
314
+
281
315
  it 'divides units of a convertable type' do
282
316
  other = subject.new(1, :dozen)
283
- other.unit.should_not eq measurement.unit
284
-
317
+ expect(other.unit).to_not eq measurement.unit
318
+
285
319
  result = measurement / other
286
- result.quantity.should eq 1
287
- result.unit.should eq measurement.unit
320
+ expect(result.quantity).to eq 1
321
+ expect(result.unit).to eq measurement.unit
288
322
  end
289
-
323
+
290
324
  it 'raises exception for incompatible units' do
291
325
  other = subject.new(4, :inches)
292
- other.unit.should_not eq measurement.unit
293
- expect { measurement / other }.to raise_error
326
+ expect(other.unit).to_not eq measurement.unit
327
+ expect { measurement / other }.to raise_error(ArgumentError, "Invalid conversion: 'in.' to 'count'")
294
328
  end
295
329
  end
296
-
330
+
297
331
  describe '#**' do
298
332
  let(:measurement) { subject.new(3) }
299
-
333
+
300
334
  it 'raises to the power of numeric values' do
301
- (measurement ** 3).quantity.should eq 27
335
+ expect((measurement ** 3).quantity).to eq 27
302
336
  end
303
-
337
+
304
338
  it 'raises exception for non-numeric values' do
305
- expect { measurement ** subject.new(3) }.to raise_error
339
+ expect { measurement ** subject.new(3) }.to raise_error(ArgumentError, 'Invalid arithmetic: 3 count ** 3 count')
306
340
  end
307
341
  end
308
-
342
+
309
343
  describe '#==' do
310
344
  let(:measurement) { subject.new(3) }
311
-
345
+
312
346
  it 'returns true for measurements with same quantity and unit' do
313
- (measurement == subject.new(3)).should be_true
347
+ expect(measurement == subject.new(3)).to be true
314
348
  end
315
-
349
+
316
350
  it 'returns false for measurements with same quantity and different unit' do
317
- (measurement == subject.new(3, :dozen)).should be_false
351
+ expect(measurement == subject.new(3, :dozen)).to be false
318
352
  end
319
-
353
+
320
354
  it 'returns false for measurements with same unit and different quantity' do
321
- (measurement == subject.new(4)).should be_false
355
+ expect(measurement == subject.new(4)).to be false
322
356
  end
323
-
357
+
324
358
  it 'returns false for non-measurement objects' do
325
- (measurement == 3).should be_false
359
+ expect(measurement == 3).to be false
326
360
  end
327
361
  end
328
-
362
+
363
+ describe '#>' do
364
+ let(:measurement) { subject.new(3) }
365
+
366
+ it 'raises ArgumentError for non-measurement objects' do
367
+ expect { measurement > 2 }.to raise_error(ArgumentError)
368
+ end
369
+
370
+ it 'returns false for measurements for different unit' do
371
+ expect { measurement > subject.new(2, :dozen) }.to raise_error(ArgumentError)
372
+ end
373
+
374
+ it 'returns true for measurements with same unit and larger quantity' do
375
+ expect(measurement > subject.new(2)).to be true
376
+ end
377
+
378
+ it 'returns false for measurements with same unit and smaller quantity' do
379
+ expect(measurement > subject.new(4)).to be false
380
+ end
381
+ end
382
+
383
+ describe '#<' do
384
+ let(:measurement) { subject.new(3) }
385
+
386
+ it 'raises ArgumentError for non-measurement objects' do
387
+ expect { measurement < 4 }.to raise_error(ArgumentError)
388
+ end
389
+
390
+ it 'returns false for measurements for different unit' do
391
+ expect { measurement < subject.new(4, :dozen) }.to raise_error(ArgumentError)
392
+ end
393
+
394
+ it 'returns true for measurements with same unit and smaller quantity' do
395
+ expect(measurement < subject.new(4)).to be true
396
+ end
397
+
398
+ it 'returns false for measurements with same unit and larger quantity' do
399
+ expect(measurement < subject.new(2)).to be false
400
+ end
401
+ end
402
+
329
403
  describe '#to_s' do
330
404
  it 'returns the quantity and unit' do
331
- subject.new(3.5).to_s.should eq '3.5 count'
332
- subject.new(2, :dozen).to_s.should eq '2 doz'
405
+ expect(subject.new(3.5).to_s).to eq '3.5 count'
406
+ expect(subject.new(2, :dozen).to_s).to eq '2 doz'
333
407
  end
334
408
  end
335
-
409
+
336
410
  describe '#inspect' do
337
411
  it 'returns the quantity and unit' do
338
- subject.new(3.5).inspect.should eq '3.5 count'
339
- subject.new(2, :dozen).inspect.should eq '2 doz'
412
+ expect(subject.new(3.5).inspect).to eq '3.5 count'
413
+ expect(subject.new(2, :dozen).inspect).to eq '2 doz'
340
414
  end
341
415
  end
342
416
  end