unitfy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/.rspec +4 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +89 -0
- data/Guardfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README +0 -0
- data/Rakefile +3 -0
- data/lib/unity.rb +20 -0
- data/lib/unity/arithmetic.rb +64 -0
- data/lib/unity/comparison.rb +33 -0
- data/lib/unity/conversion.rb +46 -0
- data/lib/unity/dimension.rb +37 -0
- data/lib/unity/dimension/integer.rb +34 -0
- data/lib/unity/dimension/vector.rb +43 -0
- data/lib/unity/fraction.rb +118 -0
- data/lib/unity/lookup.rb +102 -0
- data/lib/unity/lookup/definitions.rb +50 -0
- data/lib/unity/lookup/derived_unit.rb +24 -0
- data/lib/unity/lookup/property.rb +21 -0
- data/lib/unity/lookup/simple_unit.rb +26 -0
- data/lib/unity/quantity.rb +20 -0
- data/lib/unity/version.rb +3 -0
- data/spec/arithmetic_spec.rb +6 -0
- data/spec/comparison_spec.rb +6 -0
- data/spec/conversion_spec.rb +8 -0
- data/spec/dimension/integer_spec.rb +7 -0
- data/spec/dimension/vector_spec.rb +7 -0
- data/spec/dimension_spec.rb +7 -0
- data/spec/fabricators/unit_fabricator.rb +14 -0
- data/spec/fraction_spec.rb +7 -0
- data/spec/lookup/derived_unit_spec.rb +44 -0
- data/spec/lookup/property_spec.rb +18 -0
- data/spec/lookup/simple_unit_spec.rb +41 -0
- data/spec/lookup_spec.rb +135 -0
- data/spec/quantity_spec.rb +16 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/load_debugger.rb +7 -0
- data/spec/support/shared_examples/units/arithmetic.rb +127 -0
- data/spec/support/shared_examples/units/comparison.rb +69 -0
- data/spec/support/shared_examples/units/conversion.rb +49 -0
- data/spec/support/shared_examples/units/dimension/integer.rb +41 -0
- data/spec/support/shared_examples/units/dimension/vector.rb +10 -0
- data/spec/support/shared_examples/units/fractions.rb +131 -0
- data/unitfy.gemspec +24 -0
- metadata +133 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'unity/lookup/derived_unit.rb'
|
4
|
+
|
5
|
+
module Unity
|
6
|
+
describe DerivedUnit do
|
7
|
+
it { should validate_presence_of(:name)}
|
8
|
+
|
9
|
+
%w{ F J Hz N }.each do |unit|
|
10
|
+
it "should allow valid unit #{unit}" do
|
11
|
+
Fabricate.build(:derived_unit, :name => unit).should be_valid
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
%w{km^3 m/g km*tonne}.each do |unit|
|
16
|
+
it "should not allow invalid unit #{unit}" do
|
17
|
+
Fabricate.build(:derived_unit, :name => unit).should_not be_valid
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'based off of simple units' do
|
22
|
+
subject { DerivedUnit.new(:name => "J", :expression => 'kg*m^2/s^2') }
|
23
|
+
|
24
|
+
its(:dimension_vector) { should == [2, -2, 0, 1, 0, 0, 0, 0] }
|
25
|
+
its(:property_name) { should == :energy }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'based off of other derived unit' do
|
29
|
+
|
30
|
+
subject { DerivedUnit.new(:name => "kWh", :expression => '3.6e5*J') }
|
31
|
+
|
32
|
+
its(:dimension_vector) { should == [2, -2, 0, 1, 0, 0, 0, 0] }
|
33
|
+
its(:property_name) { should == :energy }
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
include_examples "comparable unit"
|
38
|
+
include_examples "dimension integer"
|
39
|
+
include_examples "convertable value"
|
40
|
+
include_examples "dimension vectors"
|
41
|
+
include_examples "unit fractions"
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'unity/lookup/property.rb'
|
4
|
+
|
5
|
+
module Unity
|
6
|
+
describe Property do
|
7
|
+
it { should validate_presence_of(:name)}
|
8
|
+
|
9
|
+
|
10
|
+
include_examples "comparable unit"
|
11
|
+
include_examples "dimension integer"
|
12
|
+
include_examples "convertable value"
|
13
|
+
include_examples "dimension vectors"
|
14
|
+
include_examples "unit fractions"
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'unity/lookup/simple_unit.rb'
|
4
|
+
|
5
|
+
module Unity
|
6
|
+
describe SimpleUnit do
|
7
|
+
it { should ensure_inclusion_of(:dimension).in_array(Dimension::LIST) }
|
8
|
+
it { should validate_presence_of(:si_factor)}
|
9
|
+
it { should validate_presence_of(:name)}
|
10
|
+
it { should validate_presence_of(:dimension)}
|
11
|
+
|
12
|
+
%w{ $ £ € m }.each do |unit|
|
13
|
+
it "should allow valid unit #{unit}" do
|
14
|
+
Fabricate.build(:simple_unit, :name => unit).should be_valid
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
%w{km^3 m/g km*tonne}.each do |unit|
|
19
|
+
it "should not allow invalid unit #{unit}" do
|
20
|
+
Fabricate.build(:simple_unit, :name => unit).should_not be_valid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "instance methods" do
|
25
|
+
let(:dimension) { :length }
|
26
|
+
subject { Fabricate.build :simple_unit, :name => "m", :si_factor => 1, :dimension => :length }
|
27
|
+
|
28
|
+
its(:dimension_vector) { should == Dimension::LIST.map{|d| d == dimension ? 1 : 0}}
|
29
|
+
its(:property_name) { should == :distance }
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "class methods" do
|
34
|
+
subject { SimpleUnit }
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
include_examples "dimension integer"
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/spec/lookup_spec.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module Unity
|
5
|
+
describe Lookup do
|
6
|
+
subject { Lookup }
|
7
|
+
|
8
|
+
|
9
|
+
describe "adding and finding" do
|
10
|
+
|
11
|
+
def unit_stub stubs_hash
|
12
|
+
stub({:valid? => true, :errors => {} , :dimension_int => 30}.merge(stubs_hash))
|
13
|
+
end
|
14
|
+
|
15
|
+
def property_stub stubs_hash
|
16
|
+
stub({:name => :quasar, :expression => 'qu', :valid? => true, :errors => {} , :dimension_int => 30}.merge(stubs_hash))
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
after do
|
21
|
+
subject.reload!
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "units" do
|
25
|
+
let(:name) { 'scott' }
|
26
|
+
let(:unit_object) { unit_stub(:valid? => valid, :name => name) }
|
27
|
+
context "with invalid object" do
|
28
|
+
let(:valid) { false }
|
29
|
+
|
30
|
+
it "should raise an error" do
|
31
|
+
lambda { subject.add(unit_object) }.should raise_exception(Lookup::Invalid)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with valid object" do
|
37
|
+
let(:valid) { true }
|
38
|
+
before do
|
39
|
+
subject.add(unit_object)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should be able to find the unit by name' do
|
43
|
+
subject.find!(name).should == unit_object
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
it "should raise not found if unit is undefined" do
|
48
|
+
lambda { subject.find!(name+"undefined") }.should raise_exception(Lookup::Undefined)
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with non uniq name" do
|
52
|
+
let(:duplicate_name) { name }
|
53
|
+
let(:duplicate_unit_object) { unit_stub(:name => duplicate_name) }
|
54
|
+
|
55
|
+
it "should raise an error" do
|
56
|
+
lambda { subject.add(duplicate_unit_object) }.should raise_exception(Lookup::Duplicate)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "compatible units" do
|
61
|
+
let(:compatible_unit_object) { unit_stub(:name => "unit_name1", :dimension_int => unit_object.dimension_int) }
|
62
|
+
let(:incompatible_unit_object) { unit_stub(:name => "unit_name2", :dimension_int => (unit_object.dimension_int + 10)) }
|
63
|
+
|
64
|
+
before do
|
65
|
+
subject.add(compatible_unit_object)
|
66
|
+
subject.add(incompatible_unit_object)
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "by integer" do
|
70
|
+
it "should find compatible units" do
|
71
|
+
subject.compatible_units(unit_object.dimension_int).should =~ [compatible_unit_object, unit_object]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "by property" do
|
76
|
+
let(:property_object) { property_stub(:dimension_int => unit_object.dimension_int) }
|
77
|
+
before do
|
78
|
+
subject.add_property(property_object)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should find compatible units" do
|
82
|
+
subject.compatible_units(property_object.name).should =~ [compatible_unit_object, unit_object]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "property" do
|
92
|
+
let(:propert_object) { property_stub(:name => :quasar, :expression => 'qu', :valid? => valid)}
|
93
|
+
|
94
|
+
context 'with invalid object' do
|
95
|
+
let(:valid) { false }
|
96
|
+
it "should raise an error" do
|
97
|
+
lambda { subject.add_property(propert_object) }.should raise_exception(Lookup::Invalid)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with valid object' do
|
102
|
+
let(:valid) { true }
|
103
|
+
before do
|
104
|
+
subject.add_property(propert_object)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should give a list of properties" do
|
108
|
+
subject.property_names.should include(propert_object.name)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return nil if not found" do
|
112
|
+
subject.find_property("undefined#{propert_object.name}").should == nil
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should raise exception if already defined" do
|
116
|
+
lambda {subject.add_property(propert_object)}.should raise_exception Lookup::Duplicate
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should be able to find by dimension id' do
|
120
|
+
subject.find_property(propert_object.dimension_int).should == propert_object
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should be able to find by name' do
|
124
|
+
subject.find_property(propert_object.name).should == propert_object
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module Unity
|
5
|
+
describe Quantity do
|
6
|
+
|
7
|
+
subject { Quantity.new :expression => expression }
|
8
|
+
|
9
|
+
include_examples "unit arithmetic"
|
10
|
+
include_examples "comparable unit"
|
11
|
+
include_examples "dimension integer"
|
12
|
+
include_examples "convertable value"
|
13
|
+
include_examples "dimension vectors"
|
14
|
+
include_examples "unit fractions"
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
require 'rspec'
|
8
|
+
require 'shoulda/matchers/active_model'
|
9
|
+
require 'mocha'
|
10
|
+
require 'unity'
|
11
|
+
require 'fabrication'
|
12
|
+
|
13
|
+
# Requires supporting files with custom matchers and macros, etc,
|
14
|
+
# in ./support/ and its subdirectories.
|
15
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
|
19
|
+
config.mock_with :mocha
|
20
|
+
|
21
|
+
config.before(:each) do
|
22
|
+
end
|
23
|
+
|
24
|
+
config.include(Shoulda::Matchers::ActiveModel)
|
25
|
+
|
26
|
+
config.filter_run :focus => true
|
27
|
+
config.run_all_when_everything_filtered = true
|
28
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
shared_examples "unit arithmetic" do
|
3
|
+
|
4
|
+
shared_examples "addition operation" do
|
5
|
+
|
6
|
+
context "addition result" do
|
7
|
+
subject { object1 + object2 }
|
8
|
+
let(:addition_value) { addition_result.first }
|
9
|
+
let(:addition_unit) { addition_result.last }
|
10
|
+
|
11
|
+
its(:value) { should == addition_value }
|
12
|
+
its(:unit) { should == addition_unit }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
shared_examples "subtraction operation" do
|
17
|
+
|
18
|
+
context "subtraction result" do
|
19
|
+
subject { object1 - object2 }
|
20
|
+
let(:subtraction_value) { subtraction_result.first }
|
21
|
+
let(:subtraction_unit) { subtraction_result.last }
|
22
|
+
|
23
|
+
its(:value) { should == subtraction_value }
|
24
|
+
its(:unit) { should == subtraction_unit }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
shared_examples "multiplication operation" do
|
29
|
+
|
30
|
+
context "multiplication result" do
|
31
|
+
subject { object1 * object2 }
|
32
|
+
let(:multiplication_value) { multiplication_result.first }
|
33
|
+
let(:multiplication_unit) { multiplication_result.last }
|
34
|
+
|
35
|
+
its(:value) { should == multiplication_value }
|
36
|
+
its(:unit) { should == multiplication_unit }
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
shared_examples "division operation" do
|
41
|
+
|
42
|
+
context "division result" do
|
43
|
+
subject { object1 / object2 }
|
44
|
+
let(:division_value) { division_result.first }
|
45
|
+
let(:division_unit) { division_result.last }
|
46
|
+
|
47
|
+
its(:value) { should == division_value }
|
48
|
+
its(:unit) { should == division_unit }
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "arithmetic" do
|
54
|
+
describe 'with no units' do
|
55
|
+
let(:expression1) { 100.0 }
|
56
|
+
let(:expression2) { 10.0 }
|
57
|
+
|
58
|
+
let(:addition_result) { [110.0, ''] }
|
59
|
+
let(:subtraction_result) { [90.0, ''] }
|
60
|
+
let(:division_result) { [10.0, ''] }
|
61
|
+
let(:multiplication_result) { [1000.0, ''] }
|
62
|
+
|
63
|
+
context "with an numeric as the first object" do
|
64
|
+
let(:object1) { expression1.to_f }
|
65
|
+
let(:object2) { described_class.new :expression => expression2.to_s }
|
66
|
+
|
67
|
+
include_examples "addition operation"
|
68
|
+
include_examples "subtraction operation"
|
69
|
+
include_examples "multiplication operation"
|
70
|
+
include_examples "division operation"
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
context "with an numeric as the second object" do
|
75
|
+
let(:object1) { described_class.new :expression => expression1.to_s }
|
76
|
+
let(:object2) { expression2.to_f }
|
77
|
+
|
78
|
+
include_examples "addition operation"
|
79
|
+
include_examples "subtraction operation"
|
80
|
+
include_examples "multiplication operation"
|
81
|
+
include_examples "division operation"
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
context "with units" do
|
87
|
+
let(:object1) { described_class.new :expression => expression1 }
|
88
|
+
let(:object2) { described_class.new :expression => expression2 }
|
89
|
+
|
90
|
+
context "that are compatible" do
|
91
|
+
let(:expression1) { "10*km" }
|
92
|
+
let(:expression2) { "1000*m" }
|
93
|
+
|
94
|
+
let(:addition_result) { [11.0, 'km'] }
|
95
|
+
let(:subtraction_result) { [9.0, 'km'] }
|
96
|
+
let(:division_result) { [10.0, ''] }
|
97
|
+
let(:multiplication_result) { [10.0, 'km^2'] }
|
98
|
+
|
99
|
+
include_examples "addition operation"
|
100
|
+
include_examples "subtraction operation"
|
101
|
+
include_examples "multiplication operation"
|
102
|
+
include_examples "division operation"
|
103
|
+
end
|
104
|
+
|
105
|
+
context "that are incompatible " do
|
106
|
+
let(:expression1) { "10*kg" }
|
107
|
+
let(:expression2) { "10*m" }
|
108
|
+
|
109
|
+
let(:division_result) { [1.0, 'kg/m'] }
|
110
|
+
let(:multiplication_result) { [100.0, 'kg*m'] }
|
111
|
+
|
112
|
+
include_examples "multiplication operation"
|
113
|
+
include_examples "division operation"
|
114
|
+
|
115
|
+
it "should raise error for subtraction" do
|
116
|
+
lambda { object1 - object2 }.should raise_exception Unity::IncompatibleError
|
117
|
+
end
|
118
|
+
it "should raise error for addition" do
|
119
|
+
lambda { object1 + object2 }.should raise_exception Unity::IncompatibleError
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
shared_examples_for "comparable unit" do
|
3
|
+
let(:comparible1) { described_class.new :expression => expression1 }
|
4
|
+
let(:comparible2) { described_class.new :expression => expression2 }
|
5
|
+
|
6
|
+
describe "#compatible?" do
|
7
|
+
subject { comparible1.compatible? comparible2 }
|
8
|
+
|
9
|
+
context "with compatible units" do
|
10
|
+
let(:expression1) { "km" }
|
11
|
+
let(:expression2) { "m" }
|
12
|
+
|
13
|
+
it { should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
context "with non compatible units" do
|
18
|
+
let(:expression1) { "km" }
|
19
|
+
let(:expression2) { "g" }
|
20
|
+
|
21
|
+
it { should be_false }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#compatible!" do
|
26
|
+
subject { comparible1.compatible! comparible2 }
|
27
|
+
|
28
|
+
context "with compatible units" do
|
29
|
+
let(:expression1) { "km" }
|
30
|
+
let(:expression2) { "m" }
|
31
|
+
|
32
|
+
it { should be_true }
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
context "with non compatible units" do
|
37
|
+
let(:expression1) { "km" }
|
38
|
+
let(:expression2) { "g" }
|
39
|
+
|
40
|
+
it "should raise exception" do
|
41
|
+
lambda { subject }.should raise_exception Unity::IncompatibleError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "equality #==" do
|
47
|
+
subject { comparible1 == comparible2 }
|
48
|
+
|
49
|
+
context "with comparible units" do
|
50
|
+
let(:expression1) { "1*km" }
|
51
|
+
|
52
|
+
context "and same value" do
|
53
|
+
let(:expression2) { "1000*m" }
|
54
|
+
it { should be_true }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "and different value" do
|
58
|
+
let(:expression2) { "1*m" }
|
59
|
+
it { should be_false }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "with non comparible units" do
|
64
|
+
let(:expression1) { "1*m" }
|
65
|
+
let(:expression2) { "1*g" }
|
66
|
+
it { should be_false }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|