unitwise-193 1.0.4
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 +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
|