ruby-units 1.2.0 → 1.3.0.a

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.
data/TODO CHANGED
@@ -1,3 +1,2 @@
1
- 2010-03-05 update for ruby 1.9
2
- 2010-03-05 update tests to use specs or cucumber stories
3
- 2006-10-02 Currency handling remains to be implemented well
1
+ 2006-10-02 Currency handling remains to be implemented well
2
+ 2011-04-23 Refactor caching
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Array do
4
+
5
+ subject { [1, 'cm'] }
6
+
7
+ it {should be_kind_of Array}
8
+ it {should respond_to :to_unit}
9
+
10
+ specify { subject.to_unit.should be_instance_of Unit}
11
+ specify { subject.to_unit.should == "1 cm".to_unit }
12
+ specify { subject.to_unit('mm').should == "10 mm".to_unit}
13
+
14
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ # Complex numbers are a bit strange
4
+ # Technically you can't really compare them using <=>, and ruby 1.9 does not implement this method for them
5
+ # so it stands to reason that complex units should also not support :> or :<
6
+
7
+ describe Complex do
8
+ subject { Complex(1,1) }
9
+ it { should respond_to :to_unit }
10
+ end
11
+
12
+ describe "Complex Unit" do
13
+ subject { Complex(1.0, -1.0).to_unit }
14
+
15
+ it { should be_instance_of Unit}
16
+ it(:scalar) { should be_kind_of Complex }
17
+
18
+ it { should == "1-1i".to_unit }
19
+ it { should === "1-1i".to_unit }
20
+
21
+ if RUBY_VERSION < "1.9"
22
+ context "in Ruby < 1.9" do
23
+ it "is comparable" do
24
+ subject.should > "1+0.5i".to_unit
25
+ subject.should < "2+1i".to_unit
26
+ end
27
+ end
28
+ else
29
+ context "in Ruby >= 1.9" do
30
+ it "is not comparable" do
31
+ expect { subject > "1+1i".to_unit }.to raise_error(NoMethodError)
32
+ expect { subject < "1+1i".to_unit }.to raise_error(NoMethodError)
33
+ end
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Date do
4
+ subject { Date.new(2011,4,1) }
5
+
6
+ it {should be_instance_of Date}
7
+ it {should respond_to :to_unit}
8
+ it {should respond_to :to_time}
9
+ it {should respond_to :to_date}
10
+
11
+ specify { (subject + "5 days".unit).should == Date.new(2011,4,6) }
12
+ specify { (subject - "5 days".unit).should == Date.new(2011,3,27) }
13
+ # 2012 is a leap year...
14
+ specify { (subject + "1 year".unit).should == Date.new(2012,3,31) }
15
+ specify { (subject - "1 year".unit).should == Date.new(2010,4,1) }
16
+ end
17
+
18
+ describe "Date Unit" do
19
+
20
+ subject { Date.new(2011,4,1).to_unit }
21
+
22
+ it { should be_instance_of Unit }
23
+ its(:scalar) { should be_kind_of Rational }
24
+ its(:units) { should == "d" }
25
+ its(:kind) { should == :time }
26
+
27
+ specify { (subject + "5 days".unit).should == Date.new(2011,4,6) }
28
+ specify { (subject - "5 days".unit).should == Date.new(2011,3,27) }
29
+
30
+ specify { expect { subject + Date.new(2011,4,1) }.to raise_error(ArgumentError) }
31
+ specify { expect { subject + DateTime.new(2011,4,1,12,00,00) }.to raise_error(ArgumentError) }
32
+ specify { expect { subject + Time.parse("2011-04-01 12:00:00") }.to raise_error(ArgumentError) }
33
+
34
+ specify { (subject - Date.new(2011,4,1)).should be_zero }
35
+ specify { (subject - DateTime.new(2011,4,1,00,00,00)).should be_zero }
36
+ specify { expect {(subject - Time.parse("2011-04-01 00:00"))}.to raise_error(ArgumentError) }
37
+ specify { (Date.new(2011,4,1) + 1).should == Date.new(2011,4,2)}
38
+ end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Math do
4
+ context "with '1 mm^6'" do
5
+ subject { '1 mm^6'.to_unit }
6
+
7
+ specify { Math.sqrt(subject).should == '1 mm^3'.to_unit }
8
+ specify { Math.sqrt(4).should == 2 }
9
+
10
+ if RUBY_VERSION > "1.9"
11
+ # cbrt is only defined in Ruby > 1.9
12
+ specify { Math.cbrt(subject).should == '1 mm^2'.to_unit }
13
+ specify { Math.cbrt(8).should == 2 }
14
+ end
15
+
16
+ end
17
+
18
+ context "Trigonometry functions" do
19
+
20
+ context "with '45 deg' unit" do
21
+ subject { "45 deg".unit }
22
+ specify { Math.sin(subject).should be_within(0.01).of(0.70710678) }
23
+ specify { Math.cos(subject).should be_within(0.01).of(0.70710678) }
24
+ specify { Math.tan(subject).should be_within(0.01).of(1) }
25
+ specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) }
26
+ specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) }
27
+ specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) }
28
+ end
29
+
30
+ context "with 'PI/4 radians' unit" do
31
+ subject { (Math::PI/4).unit('radians') }
32
+ specify { Math.sin(subject).should be_within(0.01).of(0.70710678) }
33
+ specify { Math.cos(subject).should be_within(0.01).of(0.70710678) }
34
+ specify { Math.tan(subject).should be_within(0.01).of(1) }
35
+ specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) }
36
+ specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) }
37
+ specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) }
38
+ end
39
+
40
+ context "with 'PI/4' continues to work" do
41
+ subject { (Math::PI/4) }
42
+ specify { Math.sin(subject).should be_within(0.01).of(0.70710678) }
43
+ specify { Math.cos(subject).should be_within(0.01).of(0.70710678) }
44
+ specify { Math.tan(subject).should be_within(0.01).of(1) }
45
+ specify { Math.sinh(subject).should be_within(0.01).of(0.8686709614860095) }
46
+ specify { Math.cosh(subject).should be_within(0.01).of(1.3246090892520057) }
47
+ specify { Math.tanh(subject).should be_within(0.01).of(0.6557942026326724) }
48
+ end
49
+
50
+ specify { Math.hypot("1 m".unit, "2 m".unit).should be_within("0.01 m".unit).of("2.23607 m".unit) }
51
+ specify { Math.hypot("1 m".unit, "2 ft".unit).should be_within("0.01 m".unit).of("1.17116 m".unit) }
52
+ specify { expect {Math.hypot("1 m".unit, "2 lbs".unit) }.to raise_error(ArgumentError) }
53
+
54
+ specify { Math.atan2("1 m".unit, "2 m".unit).should be_within(0.01).of(0.4636476090008061) }
55
+ specify { Math.atan2("1 m".unit, "2 ft".unit).should be_within(0.01).of(1.0233478888629426) }
56
+ specify { Math.atan2(1,1).should be_within(0.01).of(0.785398163397448)}
57
+ specify { expect {Math.atan2("1 m".unit, "2 lbs".unit)}.to raise_error(ArgumentError) }
58
+
59
+ end
60
+
61
+
62
+
63
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ # some rubies return an array of strings for .instance_methods and others return an array of symbols
4
+ # so let's stringify them before we compare
5
+ describe Numeric do
6
+ specify { Float.instance_methods.map {|m| m.to_s}.should include("to_unit") }
7
+ specify { Integer.instance_methods.map {|m| m.to_s}.should include("to_unit") }
8
+ specify { Fixnum.instance_methods.map {|m| m.to_s}.should include("to_unit") }
9
+ specify { Complex.instance_methods.map {|m| m.to_s}.should include("to_unit") }
10
+ specify { Bignum.instance_methods.map {|m| m.to_s}.should include("to_unit") }
11
+ specify { Rational.instance_methods.map {|m| m.to_s}.should include("to_unit") }
12
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Object do
4
+ specify { Unit('1 mm').should be_instance_of Unit}
5
+ specify { U('1 mm').should be_instance_of Unit}
6
+ specify { u('1 mm').should be_instance_of Unit}
7
+ end
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe String do
4
+ context "Unit creation from strings" do
5
+ specify { "1 mm".to_unit.should be_instance_of Unit }
6
+ specify { "1 mm".unit.should be_instance_of Unit }
7
+ specify { "1 mm".u.should be_instance_of Unit }
8
+ specify { "1 m".to("ft").should be_within(Unit("0.01 ft")).of Unit("3.28084 ft") }
9
+ end
10
+
11
+ context "Time syntax sugar" do
12
+ before(:each) do
13
+ Time.stub(:now).and_return(Time.at(1303656390))
14
+ Date.stub(:today).and_return(Date.new(2011,4,1))
15
+ DateTime.stub(:now).and_return(DateTime.new(2011,4,1,0,0,0))
16
+ end
17
+ specify { "5 min".ago.should be_instance_of Time }
18
+
19
+ specify { "5 min".from.should be_instance_of Time }
20
+ specify { "5 min".from('now').should be_instance_of Time }
21
+ specify { "5 min".from_now.should be_instance_of Time }
22
+
23
+ specify { "5 min".after('12:00').should be_instance_of Time }
24
+
25
+ specify { "5 min".before.should be_instance_of Time}
26
+ specify { "5 min".before('now').should be_instance_of Time}
27
+ specify { "5 min".before_now.should be_instance_of Time}
28
+ specify { "5 min".before('12:00').should be_instance_of Time}
29
+
30
+ specify { "min".since.should be_instance_of Unit}
31
+ specify { "min".since("12:00").should be_instance_of Unit}
32
+ specify { "min".since(Time.now - 60).should == Unit("1 min")}
33
+ specify { "days".since(Date.today - 3).should == Unit("3 d")}
34
+ specify { expect {"days".since(1000) }.to raise_error(ArgumentError, "Must specify a Time, DateTime, or String")}
35
+
36
+ specify { "min".until.should be_instance_of Unit}
37
+ specify { "min".until("12:00").should be_instance_of Unit}
38
+ specify { "min".until(Time.now + 60).should == Unit("1 min")}
39
+ specify { "days".until(Date.today + 3).should == Unit("3 d")}
40
+ specify { expect {"days".until(1000) }.to raise_error(ArgumentError, "Must specify a Time, DateTime, or String")}
41
+
42
+ specify { "today".to_date.should be_instance_of Date }
43
+ specify { "2011-4-1".to_date.should be_instance_of Date }
44
+
45
+ specify { "now".to_datetime.should be_instance_of DateTime }
46
+ specify { "now".to_time.should be_instance_of Time }
47
+
48
+ if RUBY_VERSION < "1.9" && RUBY_PLATFORM != 'java'
49
+ specify {"10001-01-01 12:00".time.should be_instance_of DateTime }
50
+ else
51
+ specify { "10001-01-01 12:00".time.should be_instance_of Time }
52
+ end
53
+ specify { "2001-01-01 12:00".time.should be_instance_of Time }
54
+
55
+ end
56
+
57
+ context "output format" do
58
+ subject { Unit("1.23456 m/s^2") }
59
+ specify { ("" % subject).should == ""}
60
+ specify { ("%0.2f" % subject).should == "1.23 m/s^2"}
61
+ specify { ("%0.2f km/h^2" % subject).should == "15999.90 km/h^2"}
62
+ specify { ("km/h^2" % subject).should == "15999.9 km/h^2"}
63
+ specify { ("%H:%M:%S" % Unit("1.5 h")).should == "01:30:00"}
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Time do
4
+ before(:each) do
5
+ Time.stub(:now).and_return(Time.at(1303656390))
6
+ end
7
+
8
+ context ".at" do
9
+ subject { Date.new(2011,4,1).to_unit }
10
+ specify { Time.at(subject - Date.new(1970,1,1)).strftime("%D %T").should == "03/31/11 20:00:00"}
11
+ end
12
+
13
+ context ".in" do
14
+ specify { Time.in("5 min").should be_a Time}
15
+ specify { Time.in("5 min").should > Time.now}
16
+ end
17
+
18
+ context 'addition (+)' do
19
+ specify { (Time.now + 1).should == Time.at(1303656390 + 1)}
20
+ specify { (Time.now + Unit("10 min")).should == Time.at(1303656390 + 600)}
21
+ end
22
+
23
+ context 'subtraction (-)' do
24
+ specify { (Time.now - 1).should == Time.at(1303656390 - 1)}
25
+ specify { (Time.now - Unit("10 min")).should == Time.at(1303656390 - 600)}
26
+ end
27
+
28
+ end
@@ -0,0 +1,855 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Create some simple units" do
4
+
5
+ describe Unit("0") do
6
+ it {should be_a Numeric}
7
+ it {should be_an_instance_of Unit}
8
+ its(:scalar) {should === 0}
9
+ its(:scalar) {should be_an Integer}
10
+ its(:units) {should be_empty}
11
+ its(:kind) {should == :unitless}
12
+ it {should_not be_temperature}
13
+ it {should_not be_degree}
14
+ it {should be_base}
15
+ it {should be_unitless}
16
+ it {should be_zero}
17
+ its(:base) {should == subject}
18
+ end
19
+
20
+ describe Unit("1") do
21
+ it {should be_a Numeric}
22
+ it {should be_an_instance_of Unit}
23
+ its(:scalar) {should === 1}
24
+ its(:scalar) {should be_an Integer}
25
+ its(:units) {should be_empty}
26
+ its(:kind) {should == :unitless}
27
+ it {should_not be_temperature}
28
+ it {should_not be_degree}
29
+ it {should be_base}
30
+ it {should be_unitless}
31
+ it {should_not be_zero}
32
+ its(:base) {should == subject}
33
+ end
34
+
35
+ describe Unit(1) do
36
+ it {should be_a Numeric}
37
+ it {should be_an_instance_of Unit}
38
+ its(:scalar) {should === 1}
39
+ its(:scalar) {should be_an Integer}
40
+ its(:units) {should be_empty}
41
+ its(:kind) {should == :unitless}
42
+ it {should_not be_temperature}
43
+ it {should_not be_degree}
44
+ it {should be_base}
45
+ it {should be_unitless}
46
+ it {should_not be_zero}
47
+ its(:base) {should == subject}
48
+ end
49
+
50
+ describe Unit(Rational(1,2)) do
51
+ it {should be_a Numeric}
52
+ it {should be_an_instance_of Unit}
53
+ its(:scalar) {should === Rational(1,2)}
54
+ its(:scalar) {should be_a Rational}
55
+ its(:units) {should be_empty}
56
+ its(:kind) {should == :unitless}
57
+ it {should_not be_temperature}
58
+ it {should_not be_degree}
59
+ it {should be_base}
60
+ it {should be_unitless}
61
+ it {should_not be_zero}
62
+ its(:base) {should == subject}
63
+ end
64
+
65
+ describe Unit(0.5) do
66
+ it {should be_a Numeric}
67
+ it {should be_an_instance_of Unit}
68
+ its(:scalar) {should === 0.5}
69
+ its(:scalar) {should be_a Float}
70
+ its(:units) {should be_empty}
71
+ its(:kind) {should == :unitless}
72
+ it {should_not be_temperature}
73
+ it {should_not be_degree}
74
+ it {should be_base}
75
+ it {should be_unitless}
76
+ it {should_not be_zero}
77
+ its(:base) {should == subject}
78
+ end
79
+
80
+ describe Unit(Complex(1,1)) do
81
+ it {should be_a Numeric}
82
+ it {should be_an_instance_of Unit}
83
+ its(:scalar) {should === Complex(1,1)}
84
+ its(:scalar) {should be_a Complex}
85
+ its(:units) {should be_empty}
86
+ its(:kind) {should == :unitless}
87
+ it {should_not be_temperature}
88
+ it {should_not be_degree}
89
+ it {should be_base}
90
+ it {should be_unitless}
91
+ it {should_not be_zero}
92
+ its(:base) {should == subject}
93
+ end
94
+
95
+ describe Unit("1 mm") do
96
+ it {should be_a Numeric}
97
+ it {should be_an_instance_of Unit}
98
+ its(:scalar) {should == 1}
99
+ its(:scalar) {should be_an Integer}
100
+ its(:units) {should == "mm"}
101
+ its(:kind) {should == :length}
102
+ it {should_not be_temperature}
103
+ it {should_not be_degree}
104
+ it {should_not be_base}
105
+ it {should_not be_unitless}
106
+ it {should_not be_zero}
107
+ its(:base) {should == Unit("0.001 m")}
108
+ end
109
+
110
+ describe Unit("10 m/s^2") do
111
+ it {should be_an_instance_of Unit}
112
+ its(:scalar) {should == 10}
113
+ its(:scalar) {should be_an Integer}
114
+ its(:units) {should == "m/s^2"}
115
+ its(:kind) {should == :acceleration}
116
+ it {should_not be_temperature}
117
+ it {should_not be_degree}
118
+ it {should be_base}
119
+ it {should_not be_unitless}
120
+ it {should_not be_zero}
121
+ its(:base) {should == Unit("10 m/s^2")}
122
+ end
123
+
124
+ describe Unit("5ft 6in") do
125
+ it {should be_an_instance_of Unit}
126
+ its(:scalar) {should == 5.5}
127
+ its(:units) {should == "ft"}
128
+ its(:kind) {should == :length}
129
+ it {should_not be_temperature}
130
+ it {should_not be_degree}
131
+ it {should_not be_base}
132
+ it {should_not be_unitless}
133
+ it {should_not be_zero}
134
+ its(:base) {should be_within(Unit("0.01 m")).of Unit("1.6764 m")}
135
+ specify { subject.to_s(:ft).should == %{5'6"} }
136
+ end
137
+
138
+ describe Unit("6lbs 5oz") do
139
+ it {should be_an_instance_of Unit}
140
+ its(:scalar) {should be_within(0.001).of 6.312}
141
+ its(:units) {should == "lbs"}
142
+ its(:kind) {should == :mass}
143
+ it {should_not be_temperature}
144
+ it {should_not be_degree}
145
+ it {should_not be_base}
146
+ it {should_not be_unitless}
147
+ it {should_not be_zero}
148
+ its(:base) {should be_within(Unit("0.01 kg")).of Unit("2.8633 kg")}
149
+ specify { subject.to_s(:lbs).should == "6 lbs, 5 oz" }
150
+ end
151
+
152
+ describe Unit("100 tempC") do
153
+ it {should be_an_instance_of Unit}
154
+ its(:scalar) {should be_within(0.001).of 100}
155
+ its(:units) {should == "tempC"}
156
+ its(:kind) {should == :temperature}
157
+ it {should be_temperature}
158
+ it {should be_degree}
159
+ it {should_not be_base}
160
+ it {should_not be_unitless}
161
+ it {should_not be_zero}
162
+ its(:base) {should be_within(Unit("0.01 degK")).of Unit("373.15 tempK")}
163
+ its(:temperature_scale) {should == "degC"}
164
+ end
165
+
166
+ describe Unit(Time.now) do
167
+ it {should be_an_instance_of Unit}
168
+ its(:scalar) {should be_a(Numeric)}
169
+ its(:units) {should == "s"}
170
+ its(:kind) {should == :time}
171
+ it {should_not be_temperature}
172
+ it {should_not be_degree}
173
+ it {should be_base}
174
+ it {should_not be_unitless}
175
+ it {should_not be_zero}
176
+ its(:base) {should be_a(Numeric)}
177
+ its(:temperature_scale) {should be_nil}
178
+ end
179
+
180
+ describe Unit("100 degC") do
181
+ it {should be_an_instance_of Unit}
182
+ its(:scalar) {should be_within(0.001).of 100}
183
+ its(:units) {should == "degC"}
184
+ its(:kind) {should == :temperature}
185
+ it {should_not be_temperature}
186
+ it {should be_degree}
187
+ it {should_not be_base}
188
+ it {should_not be_unitless}
189
+ its(:base) {should be_within(Unit("0.01 degK")).of Unit("100 degK")}
190
+ end
191
+
192
+ describe Unit("75%") do
193
+ it {should be_an_instance_of Unit}
194
+ its(:scalar) {should be_an Integer}
195
+ its(:units) {should == "%"}
196
+ its(:kind) {should == :unitless}
197
+ it {should_not be_temperature}
198
+ it {should_not be_degree}
199
+ it {should_not be_base}
200
+ it {should_not be_unitless}
201
+ it {should_not be_zero}
202
+ its(:base) {should be_a(Numeric)}
203
+ its(:temperature_scale) {should be_nil}
204
+ end
205
+
206
+ describe Unit("180 deg") do
207
+ it {should be_an_instance_of Unit}
208
+ its(:scalar) {should be_a Numeric}
209
+ its(:units) {should == "deg"}
210
+ its(:kind) {should == :angle}
211
+ it {should_not be_temperature}
212
+ it {should_not be_degree}
213
+ it {should_not be_base}
214
+ it {should_not be_unitless}
215
+ it {should_not be_zero}
216
+ its(:base) {should be_a(Numeric)}
217
+ its(:temperature_scale) {should be_nil}
218
+ end
219
+
220
+ describe Unit("1 radian") do
221
+ it {should be_an_instance_of Unit}
222
+ its(:scalar) {should be_a Numeric}
223
+ its(:units) {should == "rad"}
224
+ its(:kind) {should == :angle}
225
+ it {should_not be_temperature}
226
+ it {should_not be_degree}
227
+ it {should be_base}
228
+ it {should_not be_unitless}
229
+ it {should_not be_zero}
230
+ its(:base) {should be_a Numeric}
231
+ its(:temperature_scale) {should be_nil}
232
+ end
233
+
234
+ describe Unit("12 dozen") do
235
+ it {should be_an_instance_of Unit}
236
+ its(:scalar) {should be_an Integer}
237
+ its(:units) {should == "doz"}
238
+ its(:kind) {should == :unitless}
239
+ it {should_not be_temperature}
240
+ it {should_not be_degree}
241
+ it {should_not be_base}
242
+ it {should_not be_unitless}
243
+ it {should_not be_zero}
244
+ its(:base) {should be_a Numeric}
245
+ its(:temperature_scale) {should be_nil}
246
+ end
247
+
248
+ describe Unit("1/2 kg") do
249
+ it {should be_an_instance_of Unit}
250
+ its(:scalar) {should be_an Rational}
251
+ its(:units) {should == "kg"}
252
+ its(:kind) {should == :mass}
253
+ it {should_not be_temperature}
254
+ it {should_not be_degree}
255
+ it {should be_base}
256
+ it {should_not be_unitless}
257
+ it {should_not be_zero}
258
+ its(:base) {should be_a Numeric}
259
+ its(:temperature_scale) {should be_nil}
260
+ end
261
+
262
+ describe Unit("1/2 kg/m") do
263
+ it {should be_an_instance_of Unit}
264
+ its(:scalar) {should be_an Rational}
265
+ its(:units) {should == "kg/m"}
266
+ its(:kind) {should be_nil}
267
+ it {should_not be_temperature}
268
+ it {should_not be_degree}
269
+ it {should be_base}
270
+ it {should_not be_unitless}
271
+ it {should_not be_zero}
272
+ its(:base) {should be_a Numeric}
273
+ its(:temperature_scale) {should be_nil}
274
+ end
275
+
276
+ describe Unit("1:23:45") do
277
+ it {should be_an_instance_of Unit}
278
+ its(:scalar) {should be_an Rational}
279
+ its(:units) {should == "h"}
280
+ its(:kind) {should == :time}
281
+ it {should_not be_temperature}
282
+ it {should_not be_degree}
283
+ it {should_not be_base}
284
+ it {should_not be_unitless}
285
+ it {should_not be_zero}
286
+ its(:base) {should be_a Numeric}
287
+ its(:temperature_scale) {should be_nil}
288
+ end
289
+
290
+ # also '1 hours as minutes'
291
+ # '1 hour to minutes'
292
+ describe Unit.parse("1 hour in minutes") do
293
+ it {should be_an_instance_of Unit}
294
+ its(:scalar) {should be_an Integer}
295
+ its(:units) {should == "min"}
296
+ its(:kind) {should == :time}
297
+ it {should_not be_temperature}
298
+ it {should_not be_degree}
299
+ it {should_not be_base}
300
+ it {should_not be_unitless}
301
+ it {should_not be_zero}
302
+ its(:base) {should be_a Numeric}
303
+ its(:temperature_scale) {should be_nil}
304
+ end
305
+
306
+ describe Unit.new("1 attoparsec/microfortnight") do
307
+ it {should be_an_instance_of Unit}
308
+ its(:scalar) {should be_an Integer}
309
+ its(:units) {should == "apc/ufortnight"}
310
+ its(:kind) {should == :speed}
311
+ it {should_not be_temperature}
312
+ it {should_not be_degree}
313
+ it {should_not be_base}
314
+ it {should_not be_unitless}
315
+ it {should_not be_zero}
316
+ its(:base) {should be_a Numeric}
317
+ its(:temperature_scale) {should be_nil}
318
+ it { subject.to("in/s").should be_within(Unit("0.0001 in/s")).of(Unit("1.0043269330917 in/s"))}
319
+ end
320
+
321
+
322
+ end
323
+
324
+ describe "Unit handles attempts to create bad units" do
325
+ specify "no empty strings" do
326
+ expect {Unit("")}.to raise_error(ArgumentError,"No Unit Specified")
327
+ end
328
+
329
+ specify "no blank strings" do
330
+ expect {Unit(" ")}.to raise_error(ArgumentError,"No Unit Specified")
331
+ end
332
+
333
+ specify "no strings with tabs" do
334
+ expect {Unit("\t")}.to raise_error(ArgumentError,"No Unit Specified")
335
+ end
336
+
337
+ specify "no strings with newlines" do
338
+ expect {Unit("\n")}.to raise_error(ArgumentError,"No Unit Specified")
339
+ end
340
+
341
+ specify "no strings that don't specify a valid unit" do
342
+ expect {Unit("random string")}.to raise_error(ArgumentError,"'random string' Unit not recognized")
343
+ end
344
+
345
+ specify "no unhandled classes" do
346
+ expect {Unit(STDIN)}.to raise_error(ArgumentError,"Invalid Unit Format")
347
+ end
348
+
349
+ specify "no undefined units" do
350
+ expect {Unit("1 mFoo")}.to raise_error(ArgumentError,"'1 mFoo' Unit not recognized")
351
+ end
352
+
353
+ specify "no units with powers greater than 19" do
354
+ expect {Unit("1 m^20")}.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)")
355
+ end
356
+
357
+ specify "no units with powers less than 19" do
358
+ expect {Unit("1 m^-20")}.to raise_error(ArgumentError, "Power out of range (-20 < net power of a unit < 20)")
359
+ end
360
+
361
+ specify "no temperatures less than absolute zero" do
362
+ expect {Unit("-100 tempK")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero")
363
+ expect {Unit("-100 tempR")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero")
364
+ expect {Unit("-500/9 tempR")}.to raise_error(ArgumentError,"Temperatures must not be less than absolute zero")
365
+ end
366
+
367
+ end
368
+
369
+ describe Unit do
370
+ it "is a subclass of Numeric" do
371
+ described_class.should < Numeric
372
+ end
373
+ it "is Comparable" do
374
+ described_class.should < Comparable
375
+ end
376
+ end
377
+
378
+ describe "Unit Comparisons" do
379
+ context "Unit should detect if two units are 'compatible' (i.e., can be converted into each other)" do
380
+ specify { Unit("1 ft").should =~ Unit('1 m')}
381
+ specify { Unit("1 ft").should =~ "m"}
382
+ specify { Unit("1 ft").should be_compatible_with Unit('1 m')}
383
+ specify { Unit("1 ft").should be_compatible_with "m"}
384
+ specify { Unit("1 m").should be_compatible_with Unit('1 kg*m/kg')}
385
+ specify { Unit("1 ft").should_not =~ Unit('1 kg')}
386
+ specify { Unit("1 ft").should_not be_compatible_with Unit('1 kg')}
387
+ end
388
+
389
+ context "Equality" do
390
+ context "units of same kind" do
391
+ specify { Unit("1000 m").should == Unit('1 km')}
392
+ specify { Unit("100 m").should_not == Unit('1 km')}
393
+ specify { Unit("1 m").should == Unit('100 cm')}
394
+ end
395
+
396
+ context "units of incompatible types" do
397
+ specify { Unit("1 m").should_not == Unit("1 kg")}
398
+ end
399
+
400
+ context "units with a zero scalar are equal" do
401
+ specify {Unit("0 m").should == Unit("0 s")}
402
+ specify {Unit("0 m").should == Unit("0 kg")}
403
+
404
+ context "except for temperature units" do
405
+ specify {Unit("0 tempK").should == Unit("0 m")}
406
+ specify {Unit("0 tempR").should == Unit("0 m")}
407
+ specify {Unit("0 tempC").should_not == Unit("0 m")}
408
+ specify {Unit("0 tempF").should_not == Unit("0 m")}
409
+ end
410
+ end
411
+ end
412
+
413
+ context "Equivalence" do
414
+ context "units and scalars are the exactly the same" do
415
+ specify { Unit("1 m").should === Unit("1 m")}
416
+ specify { Unit("1 m").should be_same Unit("1 m")}
417
+ specify { Unit("1 m").should be_same_as Unit("1 m")}
418
+ end
419
+
420
+ context "units are compatible but not identical" do
421
+ specify { Unit("1000 m").should_not === Unit("1 km")}
422
+ specify { Unit("1000 m").should_not be_same Unit("1 km")}
423
+ specify { Unit("1000 m").should_not be_same_as Unit("1 km")}
424
+ end
425
+
426
+ context "units are not compatible" do
427
+ specify { Unit("1000 m").should_not === Unit("1 hour")}
428
+ specify { Unit("1000 m").should_not be_same Unit("1 hour")}
429
+ specify { Unit("1000 m").should_not be_same_as Unit("1 hour")}
430
+ end
431
+
432
+ context "scalars are different" do
433
+ specify { Unit("1 m").should_not === Unit("2 m")}
434
+ specify { Unit("1 m").should_not be_same Unit("2 m")}
435
+ specify { Unit("1 m").should_not be_same_as Unit("2 m")}
436
+ end
437
+ end
438
+
439
+ context "Comparisons" do
440
+ context "compatible units can be compared" do
441
+ specify { Unit("1 m").should < Unit("2 m")}
442
+ specify { Unit("2 m").should > Unit("1 m")}
443
+ specify { Unit("1 m").should < Unit("1 mi")}
444
+ specify { Unit("2 m").should > Unit("1 ft")}
445
+ specify { Unit("70 tempF").should > Unit("10 degC")}
446
+ specify { Unit("1 m").should > 0 }
447
+ end
448
+
449
+ context "incompatible units cannot be compared" do
450
+ specify { expect { Unit("1 m") < Unit("1 liter")}.to raise_error(ArgumentError,"Incompatible Units (m !~ l)")}
451
+ specify { expect { Unit("1 kg") > Unit("60 mph")}.to raise_error(ArgumentError,"Incompatible Units (kg !~ mph)")}
452
+ end
453
+ end
454
+
455
+ end
456
+
457
+ describe "Unit Conversions" do
458
+
459
+ context "between compatible units" do
460
+ specify { Unit("1 s").to("ns").should == Unit("1e9 ns")}
461
+ specify { Unit("1 s").convert_to("ns").should == Unit("1e9 ns")}
462
+ specify { (Unit("1 s") >> "ns").should == Unit("1e9 ns")}
463
+
464
+ specify { Unit("1 m").to(Unit("ft")).should be_within(Unit("0.001 ft")).of(Unit("3.28084 ft"))}
465
+ end
466
+
467
+ context "between incompatible units" do
468
+ specify { expect { Unit("1 s").to("m")}.to raise_error(ArgumentError,"Incompatible Units")}
469
+ end
470
+
471
+ context "given bad input" do
472
+ specify { expect { Unit("1 m").to("random string")}.to raise_error(ArgumentError,"'random string' Unit not recognized")}
473
+ specify { expect { Unit("1 m").to(STDOUT)}.to raise_error(ArgumentError,"Unknown target units")}
474
+ end
475
+
476
+ context "between temperature scales" do
477
+ # note that 'temp' units are for temperature readings on a scale, while 'deg' units are used to represent
478
+ # differences between temperatures, offsets, or other differential temperatures.
479
+
480
+ specify { Unit("100 tempC").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
481
+ specify { Unit("0 tempC").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
482
+ specify { Unit("37 tempC").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
483
+ specify { Unit("-273.15 tempC").should == Unit("0 tempK") }
484
+
485
+ specify { Unit("212 tempF").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
486
+ specify { Unit("32 tempF").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
487
+ specify { Unit("98.6 tempF").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
488
+ specify { Unit("-459.67 tempF").should == Unit("0 tempK") }
489
+
490
+ specify { Unit("671.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("373.15 tempK")) }
491
+ specify { Unit("491.67 tempR").should be_within(Unit("0.001 degK")).of(Unit("273.15 tempK")) }
492
+ specify { Unit("558.27 tempR").should be_within(Unit("0.01 degK")).of(Unit("310.15 tempK"))}
493
+ specify { Unit("0 tempR").should == Unit("0 tempK") }
494
+
495
+ specify { Unit("100 tempK").to("tempC").should be_within(U"0.01 degC").of(Unit("-173.15 tempC"))}
496
+ specify { Unit("100 tempK").to("tempF").should be_within(U"0.01 degF").of(Unit("-279.67 tempF"))}
497
+ specify { Unit("100 tempK").to("tempR").should be_within(U"0.01 degR").of(Unit("180 tempR"))}
498
+
499
+ specify { Unit("1 degC").should == Unit("1 degK")}
500
+ specify { Unit("1 degF").should == Unit("1 degR")}
501
+ specify { Unit("1 degC").should == Unit("1.8 degR")}
502
+ specify { Unit("1 degF").should be_within(Unit("0.001 degK")).of(Unit("0.5555 degK"))}
503
+ end
504
+ end
505
+
506
+ describe "Unit Math" do
507
+ context "operators:" do
508
+ context "addition (+)" do
509
+ context "between compatible units" do
510
+ specify { (Unit("0 m") + Unit("10 m")).should == Unit("10 m")}
511
+ specify { (Unit("5 kg") + Unit("10 kg")).should == Unit("15 kg")}
512
+ end
513
+
514
+ context "between a zero unit and another unit" do
515
+ specify { (Unit("0 kg") + Unit("10 m")).should == Unit("10 m")}
516
+ specify { (Unit("0 m") + Unit("10 kg")).should == Unit("10 kg")}
517
+ end
518
+
519
+ context "between incompatible units" do
520
+ specify { expect {Unit("10 kg") + Unit("10 m")}.to raise_error(ArgumentError)}
521
+ specify { expect {Unit("10 m") + Unit("10 kg")}.to raise_error(ArgumentError)}
522
+ end
523
+
524
+ context "a number from a unit" do
525
+ specify { expect { Unit("10 kg") + 1 }.to raise_error(ArgumentError)}
526
+ specify { expect { 10 + Unit("10 kg") }.to raise_error(ArgumentError)}
527
+ end
528
+
529
+ context "between two temperatures" do
530
+ specify { expect {(Unit("100 tempK") + Unit("100 tempK"))}.to raise_error(ArgumentError,"Cannot add two temperatures") }
531
+ end
532
+
533
+ context "between a temperature and a degree" do
534
+ specify { (Unit("100 tempK") + Unit("100 degK")).should == Unit("200 tempK") }
535
+ end
536
+
537
+ context "between a degree and a temperature" do
538
+ specify { (Unit("100 degK") + Unit("100 tempK")).should == Unit("200 tempK") }
539
+ end
540
+
541
+ end
542
+
543
+ context "subtracting (-)" do
544
+ context "compatible units" do
545
+ specify { (Unit("0 m") - Unit("10 m")).should == Unit("-10 m")}
546
+ specify { (Unit("5 kg") - Unit("10 kg")).should == Unit("-5 kg")}
547
+ end
548
+
549
+ context "a unit from a zero unit" do
550
+ specify { (Unit("0 kg") - Unit("10 m")).should == Unit("-10 m")}
551
+ specify { (Unit("0 m") - Unit("10 kg")).should == Unit("-10 kg")}
552
+ end
553
+
554
+ context "incompatible units" do
555
+ specify { expect {Unit("10 kg") - Unit("10 m")}.to raise_error(ArgumentError)}
556
+ specify { expect {Unit("10 m") - Unit("10 kg")}.to raise_error(ArgumentError)}
557
+ end
558
+
559
+ context "a number from a unit" do
560
+ specify { expect { Unit("10 kg") - 1 }.to raise_error(ArgumentError)}
561
+ specify { expect { 10 - Unit("10 kg") }.to raise_error(ArgumentError)}
562
+ end
563
+
564
+ context "between two temperatures" do
565
+ specify { (Unit("100 tempK") - Unit("100 tempK")).should == Unit("0 degK") }
566
+ end
567
+
568
+ context "between a temperature and a degree" do
569
+ specify { (Unit("100 tempK") - Unit("100 degK")).should == Unit("0 tempK") }
570
+ end
571
+
572
+ context "between a degree and a temperature" do
573
+ specify { expect {(Unit("100 degK") - Unit("100 tempK"))}.to raise_error(ArgumentError,"Cannot subtract a temperature from a differential degree unit")}
574
+ end
575
+
576
+ end
577
+
578
+ context "multiplying (*)" do
579
+ context "between compatible units" do
580
+ specify { (Unit("0 m") * Unit("10 m")).should == Unit("0 m^2")}
581
+ specify { (Unit("5 kg") * Unit("10 kg")).should == Unit("50 kg^2")}
582
+ end
583
+
584
+ context "between incompatible units" do
585
+ specify { (Unit("0 m") * Unit("10 kg")).should == Unit("0 kg*m")}
586
+ specify { (Unit("5 m") * Unit("10 kg")).should == Unit("50 kg*m")}
587
+ end
588
+
589
+ context "by a temperature" do
590
+ specify { expect { Unit("5 kg") * Unit("100 tempF")}.to raise_exception(ArgumentError) }
591
+ end
592
+
593
+ context "by a number" do
594
+ specify { (10 * Unit("5 kg")).should == Unit("50 kg")}
595
+ end
596
+
597
+ end
598
+
599
+ context "dividing (/)" do
600
+ context "compatible units" do
601
+ specify { (Unit("0 m") / Unit("10 m")).should == Unit(0)}
602
+ specify { (Unit("5 kg") / Unit("10 kg")).should == Rational(1,2)}
603
+ end
604
+
605
+ context "incompatible units" do
606
+ specify { (Unit("0 m") / Unit("10 kg")).should == Unit("0 m/kg")}
607
+ specify { (Unit("5 m") / Unit("10 kg")).should == Unit("1/2 m/kg")}
608
+ end
609
+
610
+ context "by a temperature" do
611
+ specify { expect { Unit("5 kg") / Unit("100 tempF")}.to raise_exception(ArgumentError) }
612
+ end
613
+
614
+ context "a number by a unit" do
615
+ specify { (10 / Unit("5 kg")).should == Unit("2 1/kg")}
616
+ end
617
+
618
+ context "a unit by a number" do
619
+ specify { (Unit("5 kg") / 2).should == Unit("2.5 kg")}
620
+ end
621
+
622
+ context "by zero" do
623
+ specify { expect { Unit("10 m") / 0}.to raise_error(ZeroDivisionError)}
624
+ specify { expect { Unit("10 m") / Unit("0 m")}.to raise_error(ZeroDivisionError)}
625
+ specify { expect { Unit("10 m") / Unit("0 kg")}.to raise_error(ZeroDivisionError)}
626
+ end
627
+ end
628
+
629
+ context "exponentiating (**)" do
630
+
631
+ specify "a temperature raises an execption" do
632
+ expect { Unit("100 tempK")**2 }.to raise_error(ArgumentError,"Cannot raise a temperature to a power")
633
+ end
634
+
635
+ context Unit("0 m") do
636
+ it { (subject**1).should == subject }
637
+ it { (subject**2).should == subject }
638
+ end
639
+
640
+ context Unit("1 m") do
641
+ it { (subject**0).should == 1 }
642
+ it { (subject**1).should == subject }
643
+ it { (subject**(-1)).should == 1/subject }
644
+ it { (subject**(2)).should == Unit("1 m^2")}
645
+ it { (subject**(-2)).should == Unit("1 1/m^2")}
646
+ specify { expect { subject**(1/2)}.to raise_error(ArgumentError, "Illegal root")}
647
+ # because 1 m^(1/2) doesn't make any sense
648
+ specify { expect { subject**(Complex(1,1))}.to raise_error(ArgumentError, "exponentiation of complex numbers is not yet supported.")}
649
+ specify { expect { subject**(Unit("1 m"))}.to raise_error(ArgumentError, "Invalid Exponent")}
650
+ end
651
+
652
+ context Unit("1 m^2") do
653
+ it { (subject**(Rational(1,2))).should == Unit("1 m")}
654
+ it { (subject**(0.5)).should == Unit("1 m")}
655
+
656
+ specify { expect { subject**(0.12345) }.to raise_error(ArgumentError,"Not a n-th root (1..9), use 1/n")}
657
+ specify { expect { subject**("abcdefg") }.to raise_error(ArgumentError,"Invalid Exponent")}
658
+ end
659
+
660
+ end
661
+
662
+ context "modulo (%)" do
663
+ context "compatible units" do
664
+ specify { (Unit("2 m") % Unit("1 m")).should == 0 }
665
+ specify { (Unit("5 m") % Unit("2 m")).should == 1 }
666
+ end
667
+
668
+ specify "incompatible units raises an exception" do
669
+ expect { Unit("1 m") % Unit("1 kg")}.to raise_error(ArgumentError,"Incompatible Units")
670
+ end
671
+ end
672
+ end
673
+
674
+ context "#power" do
675
+ subject { Unit("1 m") }
676
+ it "raises an exception when passed a Float argument" do
677
+ expect {subject.power(1.5)}.to raise_error(ArgumentError,"Exponent must an Integer")
678
+ end
679
+ it "raises an exception when passed a Rational argument" do
680
+ expect {subject.power(Rational(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer")
681
+ end
682
+ it "raises an exception when passed a Complex argument" do
683
+ expect {subject.power(Complex(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer")
684
+ end
685
+ it "raises an exception when called on a temperature unit" do
686
+ expect { Unit("100 tempC").power(2)}.to raise_error(ArgumentError,"Cannot raise a temperature to a power")
687
+ end
688
+
689
+ specify { (subject.power(-1)).should == Unit("1 1/m") }
690
+ specify { (subject.power(0)).should == 1 }
691
+ specify { (subject.power(1)).should == subject }
692
+ specify { (subject.power(2)).should == Unit("1 m^2") }
693
+
694
+ end
695
+
696
+ context "#root" do
697
+ subject { Unit("1 m") }
698
+ it "raises an exception when passed a Float argument" do
699
+ expect {subject.root(1.5)}.to raise_error(ArgumentError,"Exponent must an Integer")
700
+ end
701
+ it "raises an exception when passed a Rational argument" do
702
+ expect {subject.root(Rational(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer")
703
+ end
704
+ it "raises an exception when passed a Complex argument" do
705
+ expect {subject.root(Complex(1,2))}.to raise_error(ArgumentError,"Exponent must an Integer")
706
+ end
707
+ it "raises an exception when called on a temperature unit" do
708
+ expect { Unit("100 tempC").root(2)}.to raise_error(ArgumentError,"Cannot take the root of a temperature")
709
+ end
710
+
711
+ specify { (Unit("1 m^2").root(-2)).should == Unit("1 1/m") }
712
+ specify { (subject.root(-1)).should == Unit("1 1/m") }
713
+ specify { expect {(subject.root(0))}.to raise_error(ArgumentError, "0th root undefined")}
714
+ specify { (subject.root(1)).should == subject }
715
+ specify { (Unit("1 m^2").root(2)).should == Unit("1 m") }
716
+
717
+ end
718
+
719
+ context "#inverse" do
720
+ specify { Unit("1 m").inverse.should == Unit("1 1/m") }
721
+ specify { expect {Unit("100 tempK").inverse}.to raise_error(ArgumentError,"Cannot divide with temperatures") }
722
+ end
723
+
724
+ context "convert to scalars" do
725
+ specify {Unit("10").to_i.should be_kind_of(Integer)}
726
+ specify { expect { Unit("10 m").to_i }.to raise_error(RuntimeError,"Cannot convert '10 m' to Integer unless unitless. Use Unit#scalar") }
727
+
728
+ specify {Unit("10.0").to_f.should be_kind_of(Float)}
729
+ specify { expect { Unit("10.0 m").to_f }.to raise_error(RuntimeError,"Cannot convert '10 m' to Float unless unitless. Use Unit#scalar") }
730
+
731
+ specify {Unit("1+1i").to_c.should be_kind_of(Complex)}
732
+ specify { expect { Unit("1+1i m").to_c }.to raise_error(RuntimeError,"Cannot convert '1.0+1.0i m' to Complex unless unitless. Use Unit#scalar") }
733
+
734
+ specify {Unit("3/7").to_r.should be_kind_of(Rational)}
735
+ specify { expect { Unit("3/7 m").to_r }.to raise_error(RuntimeError,"Cannot convert '3/7 m' to Rational unless unitless. Use Unit#scalar") }
736
+
737
+ end
738
+
739
+ context "absolute value (#abs)" do
740
+ context "of a unitless unit" do
741
+ specify "returns the absolute value of the scalar" do
742
+ Unit("-10").abs.should == 10
743
+ end
744
+ end
745
+
746
+ context "of a unit" do
747
+ specify "returns a unit with the absolute value of the scalar" do
748
+ Unit("-10 m").abs.should == Unit("10 m")
749
+ end
750
+ end
751
+ end
752
+
753
+ context "#ceil" do
754
+ context "of a unitless unit" do
755
+ specify "returns the ceil of the scalar" do
756
+ Unit("10.1").ceil.should == 11
757
+ end
758
+ end
759
+
760
+ context "of a unit" do
761
+ specify "returns a unit with the ceil of the scalar" do
762
+ Unit("10.1 m").ceil.should == Unit("11 m")
763
+ end
764
+ end
765
+ end
766
+
767
+ context "#floor" do
768
+ context "of a unitless unit" do
769
+ specify "returns the floor of the scalar" do
770
+ Unit("10.1").floor.should == 10
771
+ end
772
+ end
773
+
774
+ context "of a unit" do
775
+ specify "returns a unit with the floor of the scalar" do
776
+ Unit("10.1 m").floor.should == Unit("10 m")
777
+ end
778
+ end
779
+ end
780
+
781
+ context "#round" do
782
+ context "of a unitless unit" do
783
+ specify "returns the round of the scalar" do
784
+ Unit("10.5").round.should == 11
785
+ end
786
+ end
787
+
788
+ context "of a unit" do
789
+ specify "returns a unit with the round of the scalar" do
790
+ Unit("10.5 m").round.should == Unit("11 m")
791
+ end
792
+ end
793
+ end
794
+
795
+ context "#truncate" do
796
+ context "of a unitless unit" do
797
+ specify "returns the truncate of the scalar" do
798
+ Unit("10.5").truncate.should == 10
799
+ end
800
+ end
801
+
802
+ context "of a unit" do
803
+ specify "returns a unit with the truncate of the scalar" do
804
+ Unit("10.5 m").truncate.should == Unit("10 m")
805
+ end
806
+ end
807
+ end
808
+
809
+ context '#zero?' do
810
+ it "is true when the scalar is zero on the base scale" do
811
+ Unit("0").should be_zero
812
+ Unit("0 mm").should be_zero
813
+ Unit("-273.15 tempC").should be_zero
814
+ end
815
+
816
+ it "is false when the scalar is not zero" do
817
+ Unit("1").should_not be_zero
818
+ Unit("1 mm").should_not be_zero
819
+ Unit("0 tempC").should_not be_zero
820
+ end
821
+ end
822
+
823
+ context '#succ' do
824
+ specify { Unit("1").succ.should == Unit("2")}
825
+ specify { Unit("1 mm").succ.should == Unit("2 mm")}
826
+ specify { Unit("1 mm").next.should == Unit("2 mm")}
827
+ specify { Unit("-1 mm").succ.should == Unit("0 mm")}
828
+ specify { expect {Unit("1.5 mm").succ}.to raise_error(ArgumentError,"Non Integer Scalar")}
829
+ end
830
+
831
+ context '#pred' do
832
+ specify { Unit("1").pred.should == Unit("0")}
833
+ specify { Unit("1 mm").pred.should == Unit("0 mm")}
834
+ specify { Unit("-1 mm").pred.should == Unit("-2 mm")}
835
+ specify { expect {Unit("1.5 mm").pred}.to raise_error(ArgumentError,"Non Integer Scalar")}
836
+ end
837
+
838
+ context '#divmod' do
839
+ specify { Unit("5 mm").divmod(Unit("2 mm")).should == [2,1] }
840
+ specify { Unit("1 km").divmod(Unit("2 m")).should == [500,0] }
841
+ end
842
+
843
+ end
844
+
845
+ describe "Unit Output formatting" do
846
+ context Unit("10.5 m/s^2") do
847
+ specify { subject.to_s.should == "10.5 m/s^2" }
848
+ specify { subject.to_s("%0.2f").should == "10.50 m/s^2"}
849
+ specify { subject.to_s("%0.2e km/s^2").should == "1.05e-02 km/s^2"}
850
+ specify { subject.to_s("km/s^2").should == "0.0105 km/s^2"}
851
+ specify { subject.to_s(STDOUT).should == "10.5 m/s^2" }
852
+ specify { expect {subject.to_s("random string")}.to raise_error(ArgumentError,"'random' Unit not recognized")}
853
+ end
854
+
855
+ end