unitwise-193 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +21 -0
- data/CHANGELOG.md +44 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +297 -0
- data/Rakefile +21 -0
- data/data/base_unit.yaml +43 -0
- data/data/derived_unit.yaml +3542 -0
- data/data/prefix.yaml +121 -0
- data/lib/unitwise.rb +70 -0
- data/lib/unitwise/atom.rb +121 -0
- data/lib/unitwise/base.rb +58 -0
- data/lib/unitwise/compatible.rb +60 -0
- data/lib/unitwise/errors.rb +7 -0
- data/lib/unitwise/expression.rb +35 -0
- data/lib/unitwise/expression/composer.rb +41 -0
- data/lib/unitwise/expression/decomposer.rb +68 -0
- data/lib/unitwise/expression/matcher.rb +47 -0
- data/lib/unitwise/expression/parser.rb +58 -0
- data/lib/unitwise/expression/transformer.rb +37 -0
- data/lib/unitwise/ext.rb +2 -0
- data/lib/unitwise/ext/numeric.rb +45 -0
- data/lib/unitwise/functional.rb +117 -0
- data/lib/unitwise/measurement.rb +198 -0
- data/lib/unitwise/prefix.rb +24 -0
- data/lib/unitwise/scale.rb +139 -0
- data/lib/unitwise/search.rb +46 -0
- data/lib/unitwise/standard.rb +29 -0
- data/lib/unitwise/standard/base.rb +73 -0
- data/lib/unitwise/standard/base_unit.rb +21 -0
- data/lib/unitwise/standard/derived_unit.rb +49 -0
- data/lib/unitwise/standard/extras.rb +17 -0
- data/lib/unitwise/standard/function.rb +35 -0
- data/lib/unitwise/standard/prefix.rb +17 -0
- data/lib/unitwise/standard/scale.rb +25 -0
- data/lib/unitwise/term.rb +142 -0
- data/lib/unitwise/unit.rb +181 -0
- data/lib/unitwise/version.rb +3 -0
- data/test/support/scale_tests.rb +117 -0
- data/test/test_helper.rb +19 -0
- data/test/unitwise/atom_test.rb +129 -0
- data/test/unitwise/base_test.rb +6 -0
- data/test/unitwise/expression/decomposer_test.rb +45 -0
- data/test/unitwise/expression/matcher_test.rb +42 -0
- data/test/unitwise/expression/parser_test.rb +109 -0
- data/test/unitwise/ext/numeric_test.rb +54 -0
- data/test/unitwise/functional_test.rb +17 -0
- data/test/unitwise/measurement_test.rb +233 -0
- data/test/unitwise/prefix_test.rb +25 -0
- data/test/unitwise/scale_test.rb +7 -0
- data/test/unitwise/search_test.rb +18 -0
- data/test/unitwise/term_test.rb +55 -0
- data/test/unitwise/unit_test.rb +87 -0
- data/test/unitwise_test.rb +35 -0
- data/unitwise.gemspec +33 -0
- metadata +246 -0
data/test/test_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
if RUBY_VERSION > '1.8.7'
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest/pride'
|
8
|
+
|
9
|
+
require 'unitwise'
|
10
|
+
|
11
|
+
module Minitest::Assertions
|
12
|
+
def assert_almost_equal(expected, actual)
|
13
|
+
message = "Expected #{actual} to be almost equal to #{expected}"
|
14
|
+
range = 0.00001
|
15
|
+
assert expected + range > actual && expected - range < actual, message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Numeric.infect_an_assertion :assert_almost_equal, :must_almost_equal
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Unitwise::Atom do
|
4
|
+
subject { Unitwise::Atom }
|
5
|
+
describe "::data" do
|
6
|
+
it "must have data" do
|
7
|
+
subject.data.must_be_instance_of Array
|
8
|
+
subject.data.count.must_be :>, 0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "::all" do
|
13
|
+
it "must be an Array of instances" do
|
14
|
+
subject.all.must_be_instance_of Array
|
15
|
+
subject.all.first.must_be_instance_of Unitwise::Atom
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "::find" do
|
20
|
+
it "must find atoms" do
|
21
|
+
subject.find("m").must_be_instance_of Unitwise::Atom
|
22
|
+
subject.find("V").must_be_instance_of Unitwise::Atom
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:second) { Unitwise::Atom.find("s") }
|
27
|
+
let(:yard) { Unitwise::Atom.find("[yd_i]")}
|
28
|
+
let(:pi) { Unitwise::Atom.find("[pi]")}
|
29
|
+
let(:celsius) { Unitwise::Atom.find("Cel")}
|
30
|
+
let(:pfu) { Unitwise::Atom.find("[PFU]")}
|
31
|
+
let(:joule) { Unitwise::Atom.find("J")}
|
32
|
+
describe "#scale" do
|
33
|
+
it "must be nil for base atoms" do
|
34
|
+
second.scale.must_equal nil
|
35
|
+
end
|
36
|
+
it "sould be a Scale object for derived atoms" do
|
37
|
+
yard.scale.must_be_instance_of Unitwise::Scale
|
38
|
+
end
|
39
|
+
it "must be a FunctionalScale object for special atoms" do
|
40
|
+
celsius.scale.must_be_instance_of Unitwise::Functional
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#base?" do
|
45
|
+
it "must be true for base atoms" do
|
46
|
+
second.base?.must_equal true
|
47
|
+
end
|
48
|
+
it "must be false for derived atoms" do
|
49
|
+
yard.base?.must_equal false
|
50
|
+
pi.base?.must_equal false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#derived?" do
|
55
|
+
it "must be false for base atoms" do
|
56
|
+
second.derived?.must_equal false
|
57
|
+
end
|
58
|
+
it "must be true for derived atoms" do
|
59
|
+
yard.derived?.must_equal true
|
60
|
+
celsius.derived?.must_equal true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#metric?" do
|
65
|
+
it "must be true for base atoms" do
|
66
|
+
second.metric?.must_equal true
|
67
|
+
end
|
68
|
+
it "must be false for english atoms" do
|
69
|
+
yard.metric?.must_equal false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#special?" do
|
74
|
+
it "must be true for special atoms" do
|
75
|
+
celsius.special?.must_equal true
|
76
|
+
end
|
77
|
+
it "must be false for non-special atoms" do
|
78
|
+
second.special?.must_equal false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#arbitrary?" do
|
83
|
+
it "must be true for arbitrary atoms" do
|
84
|
+
pfu.arbitrary?.must_equal true
|
85
|
+
end
|
86
|
+
it "must be false for non-arbitrary atoms" do
|
87
|
+
yard.arbitrary?.must_equal false
|
88
|
+
celsius.arbitrary?.must_equal false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#terminal?" do
|
93
|
+
it "must be true for atoms without a valid measurement atom" do
|
94
|
+
second.terminal?.must_equal true
|
95
|
+
pi.terminal?.must_equal true
|
96
|
+
end
|
97
|
+
it "must be false for child atoms" do
|
98
|
+
yard.terminal?.must_equal false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#scalar" do
|
103
|
+
it "must return scalar relative to terminal atom" do
|
104
|
+
second.scalar.must_equal 1
|
105
|
+
yard.scalar.must_almost_equal 0.9144
|
106
|
+
pi.scalar.must_almost_equal 3.141592653589793
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#dim" do
|
111
|
+
it "must return the dim" do
|
112
|
+
second.dim.must_equal 'T'
|
113
|
+
yard.dim.must_equal 'L'
|
114
|
+
joule.dim.must_equal 'L2.M.T-2'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#measurement=" do
|
119
|
+
it "must create a new measurement object and set attributes" do
|
120
|
+
skip("need to figure out mocking and stubbing with minitest")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#frozen?" do
|
125
|
+
it "should be frozen" do
|
126
|
+
second.frozen?.must_equal true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Unitwise::Expression::Decomposer do
|
4
|
+
subject { Unitwise::Expression::Decomposer }
|
5
|
+
|
6
|
+
describe "#terms" do
|
7
|
+
it "should accept codes" do
|
8
|
+
fts = subject.new("[ft_i]/s").terms
|
9
|
+
fts.count.must_equal 2
|
10
|
+
end
|
11
|
+
it "should accept names" do
|
12
|
+
kms = subject.new("kilometer/second").terms
|
13
|
+
kms.count.must_equal 2
|
14
|
+
end
|
15
|
+
it "should accept spaced names" do
|
16
|
+
ncg = subject.new("Newtonian constant of gravitation").terms
|
17
|
+
ncg.count.must_equal 1
|
18
|
+
end
|
19
|
+
it "should accept parameterized names" do
|
20
|
+
pc = subject.new("planck_constant").terms
|
21
|
+
pc.count.must_equal 1
|
22
|
+
end
|
23
|
+
it "should accept symbols" do
|
24
|
+
saff = subject.new("<i>g<sub>n</sub></i>").terms
|
25
|
+
saff.count.must_equal 1
|
26
|
+
end
|
27
|
+
it "should accept complex units" do
|
28
|
+
complex = subject.new("(mg.(km/s)3/J)2.Pa").terms
|
29
|
+
complex.count.must_equal 5
|
30
|
+
end
|
31
|
+
it "should accept more complex units" do
|
32
|
+
complex = subject.new("4.1(mm/2s3)4.7.3J-2").terms
|
33
|
+
complex.count.must_equal 3
|
34
|
+
end
|
35
|
+
it "should accept weird units" do
|
36
|
+
frequency = subject.new("/s").terms
|
37
|
+
frequency.count.must_equal 1
|
38
|
+
end
|
39
|
+
it "should accept units with a factor and unit" do
|
40
|
+
oddity = subject.new("2ms2").terms
|
41
|
+
oddity.count.must_equal 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Unitwise::Expression::Matcher do
|
4
|
+
describe "::atom(:codes)" do
|
5
|
+
subject { Unitwise::Expression::Matcher.atom(:primary_code)}
|
6
|
+
it "must be an Alternative list" do
|
7
|
+
subject.must_be_instance_of Parslet::Atoms::Alternative
|
8
|
+
end
|
9
|
+
it "must parse [in_i]" do
|
10
|
+
subject.parse("[in_i]").must_equal("[in_i]")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
describe "::metric_atom(:names)" do
|
14
|
+
subject { Unitwise::Expression::Matcher.metric_atom(:names)}
|
15
|
+
it "must be an Alternative list of names" do
|
16
|
+
subject.must_be_instance_of Parslet::Atoms::Alternative
|
17
|
+
end
|
18
|
+
it "must parse 'Joule'" do
|
19
|
+
subject.parse('Joule').must_equal('Joule')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "::atom(:slugs)" do
|
24
|
+
subject { Unitwise::Expression::Matcher.atom(:slugs)}
|
25
|
+
it "must be an Alternative list of slugs" do
|
26
|
+
subject.must_be_instance_of Parslet::Atoms::Alternative
|
27
|
+
end
|
28
|
+
it "must match 'georgian_year'" do
|
29
|
+
subject.parse("mean_gregorian_year").must_equal("mean_gregorian_year")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "::prefix(:symbol)" do
|
34
|
+
subject { Unitwise::Expression::Matcher.prefix(:symbol)}
|
35
|
+
it "must be an Alternative list of symbols" do
|
36
|
+
subject.must_be_instance_of Parslet::Atoms::Alternative
|
37
|
+
end
|
38
|
+
it "must parse 'h'" do
|
39
|
+
subject.parse('h').must_equal('h')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Unitwise::Expression::Parser do
|
4
|
+
subject { Unitwise::Expression::Parser.new}
|
5
|
+
describe '#metric_atom' do
|
6
|
+
it "must match 'N'" do
|
7
|
+
subject.metric_atom.parse('N')[:atom_code].must_equal('N')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#atom' do
|
12
|
+
it "must match '[in_i]'" do
|
13
|
+
subject.atom.parse('[in_i]')[:atom_code].must_equal('[in_i]')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#prefix' do
|
18
|
+
it "must match 'k'" do
|
19
|
+
subject.prefix.parse('k')[:prefix_code].must_equal('k')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#annotation' do
|
24
|
+
it "must match '{foobar}'" do
|
25
|
+
subject.annotation.parse('{foobar}')[:annotation].must_equal('foobar')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#factor" do
|
30
|
+
it "must match positives and fixnums" do
|
31
|
+
subject.factor.parse('3.2')[:factor].must_equal(:fixnum => '3.2')
|
32
|
+
end
|
33
|
+
it "must match negatives and integers" do
|
34
|
+
subject.factor.parse('-5')[:factor].must_equal(:integer => '-5')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#exponent" do
|
39
|
+
it "must match positives integers" do
|
40
|
+
subject.exponent.parse('4')[:exponent].must_equal(:integer => '4')
|
41
|
+
end
|
42
|
+
it "must match negative integers" do
|
43
|
+
subject.exponent.parse('-5')[:exponent].must_equal(:integer => '-5')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "term" do
|
48
|
+
it "must match basic atoms" do
|
49
|
+
subject.term.parse('[in_i]')[:term][:atom][:atom_code].must_equal('[in_i]')
|
50
|
+
end
|
51
|
+
it "must match prefixed atoms" do
|
52
|
+
match = subject.term.parse('ks')[:term]
|
53
|
+
match[:atom][:atom_code].must_equal('s')
|
54
|
+
match[:prefix][:prefix_code].must_equal('k')
|
55
|
+
end
|
56
|
+
it "must match exponential atoms" do
|
57
|
+
match = subject.term.parse('cm3')[:term]
|
58
|
+
match[:atom][:atom_code].must_equal 'm'
|
59
|
+
match[:prefix][:prefix_code].must_equal 'c'
|
60
|
+
match[:exponent][:integer].must_equal '3'
|
61
|
+
end
|
62
|
+
it "must match factors" do
|
63
|
+
subject.term.parse('3.2')[:term][:factor][:fixnum].must_equal '3.2'
|
64
|
+
end
|
65
|
+
it "must match annotations" do
|
66
|
+
match = subject.term.parse('N{Normal}')[:term]
|
67
|
+
match[:atom][:atom_code].must_equal 'N'
|
68
|
+
match[:annotation].must_equal 'Normal'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#group' do
|
73
|
+
it "must match parentheses with a term" do
|
74
|
+
match = subject.group.parse('(s2)')[:group][:nested][:left][:term]
|
75
|
+
match[:atom][:atom_code].must_equal 's'
|
76
|
+
match[:exponent][:integer].must_equal '2'
|
77
|
+
end
|
78
|
+
it "must match nested groups" do
|
79
|
+
match = subject.group.parse('((kg))')[:group][:nested][:left][:group][:nested][:left][:term]
|
80
|
+
match[:atom][:atom_code].must_equal 'g'
|
81
|
+
match[:prefix][:prefix_code].must_equal 'k'
|
82
|
+
end
|
83
|
+
it "must pass exponents down" do
|
84
|
+
match = subject.group.parse('([in_i])3')[:group]
|
85
|
+
match[:exponent][:integer].must_equal '3'
|
86
|
+
match[:nested][:left][:term][:atom][:atom_code].must_equal '[in_i]'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#expression" do
|
91
|
+
it "must match left only" do
|
92
|
+
match = subject.expression.parse('m')
|
93
|
+
match[:left][:term][:atom][:atom_code].must_equal("m")
|
94
|
+
end
|
95
|
+
it "must match left + right + operator" do
|
96
|
+
match = subject.expression.parse('m.s')
|
97
|
+
match[:left][:term][:atom][:atom_code].must_equal("m")
|
98
|
+
match[:operator].must_equal('.')
|
99
|
+
match[:right][:left][:term][:atom][:atom_code].must_equal('s')
|
100
|
+
end
|
101
|
+
it "must match operator + right" do
|
102
|
+
match = subject.expression.parse("/s")
|
103
|
+
match[:operator].must_equal('/')
|
104
|
+
match[:right][:left][:term][:atom][:atom_code].must_equal('s')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'unitwise/ext'
|
3
|
+
describe Numeric do
|
4
|
+
describe "#convert" do
|
5
|
+
it "must work for Integer" do
|
6
|
+
measurement = 22.convert_to("kg")
|
7
|
+
measurement.must_be_instance_of(Unitwise::Measurement)
|
8
|
+
measurement.value.must_equal 22
|
9
|
+
end
|
10
|
+
it "must work for Fixnum" do
|
11
|
+
measurement = 24.25.convert_to("[ft_i]")
|
12
|
+
measurement.must_be_instance_of(Unitwise::Measurement)
|
13
|
+
measurement.value.must_equal 24.25
|
14
|
+
end
|
15
|
+
it "must work for Float" do
|
16
|
+
measurement = (22.0/7).convert_to("[mi_i]")
|
17
|
+
measurement.must_be_instance_of(Unitwise::Measurement)
|
18
|
+
measurement.value.must_equal 3.142857142857143
|
19
|
+
end
|
20
|
+
it "must work for Rational" do
|
21
|
+
measurement = Rational(22/7).convert_to("N/m2")
|
22
|
+
measurement.must_be_instance_of(Unitwise::Measurement)
|
23
|
+
measurement.value.must_equal Rational(22/7)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#method_missing" do
|
28
|
+
it "must match 'mm'" do
|
29
|
+
mm = 2.5.mm
|
30
|
+
mm.must_be_instance_of(Unitwise::Measurement)
|
31
|
+
mm.value.must_equal 2.5
|
32
|
+
1.0.respond_to?(:mm).must_equal true
|
33
|
+
3.respond_to?(:to_mm).must_equal true
|
34
|
+
end
|
35
|
+
it "must match 'to_mm'" do
|
36
|
+
mm = 2.5.to_mm
|
37
|
+
mm.must_be_instance_of(Unitwise::Measurement)
|
38
|
+
mm.value.must_equal 2.5
|
39
|
+
4.0.methods.grep(/mm/).count.must_equal 2
|
40
|
+
1.methods.grep(/mm/).count.must_equal 2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "must not match 'foo'" do
|
44
|
+
lambda { 1.foo }.must_raise NoMethodError
|
45
|
+
end
|
46
|
+
|
47
|
+
it "must not match 'to_foo'" do
|
48
|
+
lambda { 1.to_foo }.must_raise NoMethodError
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Unitwise::Functional do
|
4
|
+
subject { Unitwise::Functional }
|
5
|
+
%w{cel degf hpX hpC tan100 ph ld ln lg 2lg}.each do |function|
|
6
|
+
describe function do
|
7
|
+
it 'should convert back and forth' do
|
8
|
+
number = rand(1000) / 1000.0
|
9
|
+
there = subject.send "to_#{function}", number
|
10
|
+
back_again = subject.send "from_#{function}", there
|
11
|
+
rounded_result = (back_again * 1000).round / 1000.0
|
12
|
+
rounded_result.must_equal number
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'test_helper'
|
3
|
+
require 'support/scale_tests'
|
4
|
+
|
5
|
+
describe Unitwise::Measurement do
|
6
|
+
let(:described_class) { Unitwise::Measurement }
|
7
|
+
include ScaleTests
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
it "should raise an error for unknown units" do
|
11
|
+
lambda { Unitwise::Measurement.new(1,"funkitron") }.must_raise(Unitwise::ExpressionError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#convert_to" do
|
16
|
+
it "must convert to a similar unit code" do
|
17
|
+
mph.convert_to('km/h').value.must_almost_equal(96.56063)
|
18
|
+
end
|
19
|
+
it "must raise an error if the units aren't similar" do
|
20
|
+
lambda { mph.convert_to('N') }.must_raise Unitwise::ConversionError
|
21
|
+
end
|
22
|
+
it "must convert special units to their base units" do
|
23
|
+
cel.convert_to('K').value.must_equal 295.15
|
24
|
+
end
|
25
|
+
it "must convert base units to special units" do
|
26
|
+
k.convert_to('Cel').value.must_equal 100
|
27
|
+
end
|
28
|
+
it "must convert special units to special units" do
|
29
|
+
f.convert_to('Cel').value.must_almost_equal 37
|
30
|
+
end
|
31
|
+
it "must convert special units to non-special units" do
|
32
|
+
cel.convert_to("[degR]").value.must_almost_equal(531.27)
|
33
|
+
end
|
34
|
+
it "must convert derived units to special units" do
|
35
|
+
r.convert_to("Cel").value.must_almost_equal(0)
|
36
|
+
end
|
37
|
+
it "must convert to a unit of another measurement" do
|
38
|
+
mph.convert_to(kmh).value.must_almost_equal(96.56064)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#*" do
|
43
|
+
it "must multiply by scalars" do
|
44
|
+
mult = mph * 4
|
45
|
+
mult.value.must_equal 240
|
46
|
+
mult.unit.must_equal Unitwise::Unit.new("[mi_i]/h")
|
47
|
+
end
|
48
|
+
it "must multiply similar units" do
|
49
|
+
mult = mph * kmh
|
50
|
+
mult.value.must_almost_equal 3728.22715342
|
51
|
+
mult.unit.must_equal Unitwise::Unit.new("([mi_i]/h).([mi_i]/h)")
|
52
|
+
end
|
53
|
+
it "must multiply unsimilar units" do
|
54
|
+
mult = mph * mile
|
55
|
+
mult.value.must_equal 180
|
56
|
+
mult.unit.must_equal Unitwise::Unit.new("[mi_i]2/h")
|
57
|
+
end
|
58
|
+
it "must multiply canceling units" do
|
59
|
+
mult = mph * hpm
|
60
|
+
mult.value.must_equal 360
|
61
|
+
mult.unit.to_s.must_equal "1"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#/" do
|
66
|
+
it "must divide by scalars" do
|
67
|
+
div = kmh / 4
|
68
|
+
div.value.must_equal 25
|
69
|
+
div.unit.must_equal kmh.unit
|
70
|
+
end
|
71
|
+
it "must divide by the value of similar units" do
|
72
|
+
div = kmh / mph
|
73
|
+
div.value.must_almost_equal 1.03561865
|
74
|
+
div.unit.to_s.must_equal '1'
|
75
|
+
end
|
76
|
+
it "must divide dissimilar units" do
|
77
|
+
div = mph / hpm
|
78
|
+
div.value.must_equal 10
|
79
|
+
div.unit.to_s.must_equal "[mi_i]2/h2"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#+" do
|
84
|
+
it "must add values when units are similar" do
|
85
|
+
added = mph + kmh
|
86
|
+
added.value.must_almost_equal 122.13711922
|
87
|
+
added.unit.must_equal mph.unit
|
88
|
+
end
|
89
|
+
it "must raise an error when units are not similar" do
|
90
|
+
assert_raises(TypeError) { mph + hpm}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#-" do
|
95
|
+
it "must add values when units are similar" do
|
96
|
+
added = mph - kmh
|
97
|
+
added.value.must_almost_equal(-2.1371192)
|
98
|
+
added.unit.must_equal mph.unit
|
99
|
+
end
|
100
|
+
it "must raise an error when units are not similar" do
|
101
|
+
assert_raises(TypeError) { mph - hpm}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#**" do
|
106
|
+
it "must raise to a power" do
|
107
|
+
exp = mile ** 3
|
108
|
+
exp.value.must_equal 27
|
109
|
+
exp.unit.to_s.must_equal "[mi_i]3"
|
110
|
+
end
|
111
|
+
it "must raise to a negative power" do
|
112
|
+
exp = mile ** -3
|
113
|
+
exp.value.must_equal 0.037037037037037035
|
114
|
+
exp.unit.to_s.must_equal "1/[mi_i]3"
|
115
|
+
end
|
116
|
+
it "must not raise to a weird power" do
|
117
|
+
lambda { mile ** 'weird' }.must_raise TypeError
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#coerce" do
|
122
|
+
let(:meter) { Unitwise::Measurement.new(1, 'm') }
|
123
|
+
it "must coerce numerics" do
|
124
|
+
(5 * meter).must_equal Unitwise::Measurement.new(5, 'm')
|
125
|
+
end
|
126
|
+
it "should raise an error for other crap" do
|
127
|
+
lambda { meter.coerce("foo") }.must_raise TypeError
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "equality" do
|
132
|
+
let(:m) { Unitwise::Measurement.new(1,'m') }
|
133
|
+
let(:feet) { Unitwise::Measurement.new(20, 'foot') }
|
134
|
+
let(:mm) { Unitwise::Measurement.new(1000,'mm') }
|
135
|
+
let(:foot) { Unitwise::Measurement.new(1,'foot') }
|
136
|
+
let(:g) { Unitwise::Measurement.new(1,'gram') }
|
137
|
+
it "should be ==" do
|
138
|
+
assert m == m
|
139
|
+
assert m == mm
|
140
|
+
refute m == foot
|
141
|
+
refute m == g
|
142
|
+
end
|
143
|
+
it "should be ===" do
|
144
|
+
assert m == m
|
145
|
+
assert m === mm
|
146
|
+
refute m === foot
|
147
|
+
refute m == g
|
148
|
+
end
|
149
|
+
it "should be equal?" do
|
150
|
+
assert m.equal?(m)
|
151
|
+
refute m.equal?(mm)
|
152
|
+
refute m.equal?(foot)
|
153
|
+
refute m.equal?(g)
|
154
|
+
end
|
155
|
+
it "should be eql?" do
|
156
|
+
assert m.eql?(m)
|
157
|
+
refute m.equal?(mm)
|
158
|
+
refute m.equal?(foot)
|
159
|
+
refute m.equal?(g)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "#method_missing" do
|
164
|
+
let(:meter) { Unitwise::Measurement.new(1, 'm')}
|
165
|
+
it "must convert 'to_mm'" do
|
166
|
+
convert = meter.to_mm
|
167
|
+
convert.must_be_instance_of Unitwise::Measurement
|
168
|
+
convert.value.must_equal 1000
|
169
|
+
end
|
170
|
+
|
171
|
+
it "must convert 'to_foot'" do
|
172
|
+
convert = meter.to_foot
|
173
|
+
convert.must_be_instance_of Unitwise::Measurement
|
174
|
+
convert.value.must_almost_equal 3.280839895
|
175
|
+
end
|
176
|
+
|
177
|
+
it "must not convert 'foo'" do
|
178
|
+
lambda { meter.foo }.must_raise NoMethodError
|
179
|
+
end
|
180
|
+
|
181
|
+
it "must not convert 'to_foo'" do
|
182
|
+
lambda { meter.to_foo }.must_raise NoMethodError
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
describe "#round" do
|
188
|
+
it "must round Floats to Integers" do
|
189
|
+
result = Unitwise::Measurement.new(98.6, "[degF]").round
|
190
|
+
result.value.must_equal(99)
|
191
|
+
result.value.must_be_kind_of(Integer)
|
192
|
+
end
|
193
|
+
it "must round Floats to Floats" do
|
194
|
+
if RUBY_VERSION > '1.8.7'
|
195
|
+
result = Unitwise::Measurement.new(17.625, "J").round(2)
|
196
|
+
result.value.must_equal(17.63)
|
197
|
+
result.value.must_be_kind_of(Float)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
describe "#to_f" do
|
202
|
+
it "must convert to a float" do
|
203
|
+
f.to_f.must_be_kind_of(Float)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "#to_i" do
|
208
|
+
it "must convert to an integer" do
|
209
|
+
k.to_i.must_be_kind_of(Integer)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "#to_r" do
|
214
|
+
it "must convert to a rational" do
|
215
|
+
cel.to_r.must_be_kind_of(Rational)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "#to_s" do
|
220
|
+
it "should include the simplified value and use the mode it was created with" do
|
221
|
+
foot = described_class.new(7.00, "foot")
|
222
|
+
foot.to_s.must_equal "7 foot"
|
223
|
+
meter = described_class.new(BigDecimal("3.142"), "m")
|
224
|
+
meter.to_s.must_equal("3.142 m")
|
225
|
+
end
|
226
|
+
it "should accept a mode and print that mode string" do
|
227
|
+
temp = described_class.new(25, "degree Celsius")
|
228
|
+
temp.to_s(:primary_code).must_equal("25 Cel")
|
229
|
+
temp.to_s(:symbol).must_equal("25 °C")
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|