amee-data-abstraction 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +3 -0
- data/README.txt +26 -14
- data/VERSION +1 -1
- data/amee-data-abstraction.gemspec +7 -6
- data/lib/amee-data-abstraction/calculation.rb +1 -1
- data/lib/amee-data-abstraction/calculation_set.rb +152 -10
- data/lib/amee-data-abstraction/input.rb +10 -0
- data/lib/amee-data-abstraction/ongoing_calculation.rb +1 -1
- data/lib/amee-data-abstraction/term.rb +31 -13
- data/spec/amee-data-abstraction/calculation_set_spec.rb +247 -9
- data/spec/amee-data-abstraction/calculation_spec.rb +24 -19
- data/spec/amee-data-abstraction/drill_spec.rb +14 -9
- data/spec/amee-data-abstraction/input_spec.rb +113 -73
- data/spec/amee-data-abstraction/metadatum_spec.rb +1 -1
- data/spec/amee-data-abstraction/ongoing_calculation_spec.rb +38 -30
- data/spec/amee-data-abstraction/profile_spec.rb +4 -2
- data/spec/amee-data-abstraction/prototype_calculation_spec.rb +13 -8
- data/spec/amee-data-abstraction/term_spec.rb +45 -4
- data/spec/amee-data-abstraction/terms_list_spec.rb +23 -12
- data/spec/config/amee_units_spec.rb +1 -2
- data/spec/core-extensions/class_spec.rb +18 -18
- data/spec/core-extensions/hash_spec.rb +1 -2
- data/spec/core-extensions/ordered_hash_spec.rb +1 -2
- data/spec/core-extensions/proc_spec.rb +1 -1
- data/spec/fixtures/config/calculations/electricity.rb +35 -0
- data/spec/fixtures/config/calculations/electricity_and_transport.rb +53 -0
- data/spec/fixtures/{transport.rb → config/calculations/transport.rb} +2 -2
- data/spec/fixtures/{electricity.rb → config/electricity.rb} +1 -1
- data/spec/spec_helper.rb +30 -2
- metadata +28 -27
- data/spec/fixtures/electricity_and_transport.rb +0 -55
@@ -1,16 +1,18 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Profile do
|
4
|
+
|
4
5
|
it 'defaults to be a text-box' do
|
5
6
|
i=Profile.new
|
6
7
|
i.text_box?.should be_true
|
7
8
|
end
|
9
|
+
|
8
10
|
it 'can know if it belongs to a particular usage' do
|
9
11
|
mocker=AMEEMocker.new self,:path=>'transport/car/generic'
|
10
12
|
mocker.item_value_definitions.
|
11
13
|
item_definition.data_category.
|
12
14
|
item_value_definition('distance',['someusage'],['someotherusage'])
|
13
|
-
t=
|
15
|
+
t=CalculationSet.find("transport")[:transport].clone
|
14
16
|
t[:distance].compulsory?('someusage').should eql true
|
15
17
|
t[:distance].compulsory?('someotherusage').should eql false
|
16
18
|
t[:distance].optional?('someotherusage').should eql true
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class PrototypeCalculation
|
4
4
|
def call_me
|
@@ -10,8 +10,13 @@ class PrototypeCalculation
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
describe PrototypeCalculation do
|
13
|
+
|
14
|
+
before :all do
|
15
|
+
@calc = CalculationSet.find("transport")[:transport]
|
16
|
+
end
|
17
|
+
|
13
18
|
it 'can create an instance' do
|
14
|
-
|
19
|
+
@calc.should be_a PrototypeCalculation
|
15
20
|
end
|
16
21
|
it 'can be initialized with a DSL block' do
|
17
22
|
PrototypeCalculation.new {call_me}
|
@@ -40,17 +45,17 @@ describe PrototypeCalculation do
|
|
40
45
|
pc[:alpha].should be_a Output
|
41
46
|
end
|
42
47
|
it 'can construct an ongoing calculation' do
|
43
|
-
|
48
|
+
@calc.begin_calculation.should be_a OngoingCalculation
|
44
49
|
end
|
45
50
|
it 'should make the terms of the ongoing calculation be their own instances' do
|
46
|
-
oc
|
51
|
+
oc=@calc.begin_calculation
|
47
52
|
oc[:distance].value :somevalue
|
48
53
|
oc[:distance].value.should eql :somevalue
|
49
|
-
|
54
|
+
@calc[:distance].value.should be_nil
|
50
55
|
end
|
51
56
|
it 'should copy name, path, label when cloning ongoing' do
|
52
57
|
[:path,:name,:label].each do |property|
|
53
|
-
|
58
|
+
@calc.begin_calculation.send(property).should eql @calc.send(property)
|
54
59
|
end
|
55
60
|
end
|
56
61
|
it 'can autogenerate drill terms for itself, based on talking to amee' do
|
@@ -229,7 +234,7 @@ describe PrototypeCalculation do
|
|
229
234
|
pc.terms.default_per_units.compact.map(&:name).should include 'hour'
|
230
235
|
end
|
231
236
|
it 'transfers memoised amee information to constructed ongoing calculations' do
|
232
|
-
t
|
237
|
+
t=@calc.clone
|
233
238
|
flexmock(AMEE::Data::Category).should_receive(:get).
|
234
239
|
with(AMEE::DataAbstraction.connection,'/data/transport/car/generic').
|
235
240
|
once.and_return(true)
|
@@ -237,7 +242,7 @@ describe PrototypeCalculation do
|
|
237
242
|
t.begin_calculation.send(:amee_data_category)
|
238
243
|
end
|
239
244
|
it 'can auto-create start and end date metadata' do
|
240
|
-
t
|
245
|
+
t=@calc.clone
|
241
246
|
t.instance_eval{
|
242
247
|
start_and_end_dates
|
243
248
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class Term
|
4
4
|
def call_me
|
@@ -11,6 +11,11 @@ class Term
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe Term do
|
14
|
+
|
15
|
+
before :all do
|
16
|
+
@calc = CalculationSet.find("transport")[:transport]
|
17
|
+
end
|
18
|
+
|
14
19
|
it 'can be initialized via DSL block' do
|
15
20
|
Term.new {call_me}
|
16
21
|
Term.called.should be_true
|
@@ -32,8 +37,12 @@ describe Term do
|
|
32
37
|
Term.new {note 'hello'}.note.should eql 'hello'
|
33
38
|
end
|
34
39
|
|
40
|
+
it "has note with no '\"' character" do
|
41
|
+
Term.new {note 'hello "some quote"'}.note.should eql "hello 'some quote'"
|
42
|
+
end
|
43
|
+
|
35
44
|
it 'has parent' do
|
36
|
-
|
45
|
+
@calc[:distance].parent.should eql @calc
|
37
46
|
end
|
38
47
|
it "has name defaulting to label" do
|
39
48
|
Term.new {label :hello}.name.should eql 'Hello'
|
@@ -87,10 +96,10 @@ describe Term do
|
|
87
96
|
t.hidden?.should be_false
|
88
97
|
end
|
89
98
|
it 'knows which terms come before or after it' do
|
90
|
-
|
99
|
+
@calc.terms.
|
91
100
|
select{|x|x.before?(:distance)}.map(&:label).
|
92
101
|
should eql [:fuel,:size]
|
93
|
-
|
102
|
+
@calc.terms.
|
94
103
|
select{|x|x.after?(:distance)}.map(&:label).
|
95
104
|
should eql [:co2]
|
96
105
|
end
|
@@ -137,6 +146,26 @@ describe Term do
|
|
137
146
|
per_units.should include "joule", "british thermal unit", "megawatt hour"
|
138
147
|
end
|
139
148
|
|
149
|
+
it "has unit choices which include default and alternative" do
|
150
|
+
term = Term.new {path :hello; default_unit :kg; default_per_unit :kWh}
|
151
|
+
units = term.alternative_units.map(&:name)
|
152
|
+
units.should include "gigagram", "pound", "tonne"
|
153
|
+
units.should_not include "kilogram", "kelvin"
|
154
|
+
|
155
|
+
units = term.unit_choices.map(&:name)
|
156
|
+
units.first.should eql "kilogram"
|
157
|
+
units.should include "kilogram", "gigagram", "pound", "tonne"
|
158
|
+
units.should_not include "kelvin"
|
159
|
+
|
160
|
+
per_units = term.alternative_per_units.map(&:name)
|
161
|
+
per_units.should include "joule", "british thermal unit", "megawatt hour"
|
162
|
+
per_units.should_not include "kilowatt hour"
|
163
|
+
|
164
|
+
per_units = term.per_unit_choices.map(&:name)
|
165
|
+
per_units.first.should eql "kilowatt hour"
|
166
|
+
per_units.should include "kilowatt hour", "joule", "british thermal unit", "megawatt hour"
|
167
|
+
end
|
168
|
+
|
140
169
|
it "has limited set of alternative units if specified" do
|
141
170
|
term = Term.new {path :hello; default_unit :kg; alternative_units :t, :ton_us, :lb}
|
142
171
|
units = term.alternative_units.map(&:name)
|
@@ -144,6 +173,18 @@ describe Term do
|
|
144
173
|
units.should_not include "gigagram", "ounce", "gram"
|
145
174
|
end
|
146
175
|
|
176
|
+
it "has unit choices which include default and alternative with limited set of alternative units" do
|
177
|
+
term = Term.new {path :hello; default_unit :kg; alternative_units :t, :ton_us, :lb}
|
178
|
+
units = term.alternative_units.map(&:name)
|
179
|
+
units.should include "tonne", "pound", "short ton"
|
180
|
+
units.should_not include "kilogram", "gigagram", "ounce", "gram"
|
181
|
+
|
182
|
+
units = term.unit_choices.map(&:name)
|
183
|
+
units.first.should eql "kilogram"
|
184
|
+
units.should include "kilogram", "tonne", "pound", "short ton"
|
185
|
+
units.should_not include "gigagram", "ounce", "gram"
|
186
|
+
end
|
187
|
+
|
147
188
|
it "should raise error when specifying incompatible alternative units" do
|
148
189
|
lambda{Term.new {path :hello; default_unit :kg; alternative_units :kWh, :km}}.should raise_error
|
149
190
|
end
|
@@ -1,46 +1,57 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe TermsList do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@calc = CalculationSet.find("transport")[:transport]
|
7
|
+
end
|
8
|
+
|
4
9
|
it 'should be returned from calculations' do
|
5
|
-
|
10
|
+
@calc.terms.should be_a TermsList
|
6
11
|
end
|
12
|
+
|
7
13
|
it 'should give properties' do
|
8
|
-
|
9
|
-
|
10
|
-
|
14
|
+
@calc.terms.labels.should eql [:fuel,:size,:distance,:co2]
|
15
|
+
@calc.terms.paths.should eql ['fuel','size','distance','default']
|
16
|
+
@calc.terms.names.should eql ['Fuel Type','Vehicle Size','Distance Driven','Carbon Dioxide']
|
11
17
|
end
|
18
|
+
|
12
19
|
it 'should select by class' do
|
13
|
-
|
14
|
-
|
15
|
-
|
20
|
+
@calc.terms.drills.labels.should eql [:fuel,:size]
|
21
|
+
@calc.terms.profiles.labels.should eql [:distance]
|
22
|
+
@calc.terms.outputs.labels.should eql [:co2]
|
16
23
|
end
|
24
|
+
|
17
25
|
it 'should select by property' do
|
18
|
-
t
|
26
|
+
t=@calc.begin_calculation
|
19
27
|
t[:distance].value 5
|
20
28
|
t.terms.set.labels.should eql [:distance]
|
21
29
|
t.terms.unset.labels.should eql [:fuel,:size,:co2]
|
22
30
|
end
|
31
|
+
|
23
32
|
it 'should select by chain' do
|
24
|
-
t
|
33
|
+
t=@calc.begin_calculation
|
25
34
|
t[:fuel].value 'diesel'
|
26
35
|
t.terms.drills.set.labels.should eql [:fuel]
|
27
36
|
t.terms.drills.unset.labels.should eql [:size]
|
28
37
|
t.terms.set.drills.labels.should eql [:fuel]
|
29
38
|
t.terms.unset.drills.labels.should eql [:size]
|
30
39
|
end
|
40
|
+
|
31
41
|
it 'should select by order' do
|
32
|
-
t
|
42
|
+
t=@calc.clone
|
33
43
|
t.terms.before(:distance).labels.
|
34
44
|
should eql [:fuel,:size]
|
35
45
|
t.terms.after(:distance).labels.
|
36
46
|
should eql [:co2]
|
37
47
|
end
|
48
|
+
|
38
49
|
it 'can select terms by usage' do
|
39
50
|
mocker=AMEEMocker.new self,:path=>'transport/car/generic'
|
40
51
|
mocker.item_value_definitions.
|
41
52
|
item_definition.data_category.
|
42
53
|
item_value_definition('distance',['usage1'],['usage2'],['usage3'])
|
43
|
-
t
|
54
|
+
t=@calc.clone
|
44
55
|
t.profiles.compulsory('usage1').labels.should eql [:distance]
|
45
56
|
t.profiles.optional('usage2').labels.should eql [:distance]
|
46
57
|
t.profiles.compulsory('usage2').labels.should be_empty
|
@@ -1,25 +1,25 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
class Myclass
|
4
|
+
attr_property :prop
|
5
|
+
end
|
6
6
|
|
7
7
|
describe Class do
|
8
8
|
before :all do
|
9
9
|
@it=Myclass.new
|
10
10
|
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
it 'can have a property defined' do
|
12
|
+
@it.prop 5
|
13
|
+
@it.prop.should eql 5
|
14
|
+
end
|
15
|
+
it 'can have a prop unset' do
|
16
|
+
@it.prop 5
|
17
|
+
@it.prop nil
|
18
|
+
@it.prop.should be_nil
|
19
|
+
end
|
20
|
+
it 'does not unset by query' do
|
21
|
+
@it.prop 5
|
22
|
+
@it.prop
|
23
|
+
@it.prop.should_not be_nil
|
24
|
+
end
|
25
25
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
calculation { # The application has support for an electricity calculation. :electricity is the internal label used to refer to it
|
2
|
+
label :electricity
|
3
|
+
name "Electricity Consumption"
|
4
|
+
path '/business/energy/electricity/grid'
|
5
|
+
|
6
|
+
drill {
|
7
|
+
fixed 'argentina' #Not to be unset, value pre-given
|
8
|
+
label :country #Name will default to label.humanize if not given
|
9
|
+
path 'country' #Some of the fields on the form are drill-downs, but the application doesn't need to display these differently
|
10
|
+
#type :autocompleting_text_box #default for a drill with entries is probably a dropdown
|
11
|
+
}
|
12
|
+
|
13
|
+
profile {
|
14
|
+
label :energy_used
|
15
|
+
# Symbol provided here is used in generating html ids for elements etc
|
16
|
+
path 'energyPerTime' #The amee profile item value corresponding to the field
|
17
|
+
name "Energy Used" #The display name used on the form
|
18
|
+
unit "kWh" #Default unit choice
|
19
|
+
interface :text_box #Probably not needed, as likely to be the default for profile item value unsets
|
20
|
+
validation lambda{|x|x.is_a? Float} #Probably not needed, as default can be deduced from PIV TYPE in API. Here as illustrative.
|
21
|
+
alternative_units :MWh, :MBTU, :BTU # If these are explcitly specified then the alternatives are limited to only these units. Otherwise all dimensionally equivalent units are available as alternatives by default
|
22
|
+
}
|
23
|
+
|
24
|
+
# Alternatively, the drill might be fixed
|
25
|
+
#permanent :country {
|
26
|
+
# drill_path 'country'
|
27
|
+
# value 'Argentina'
|
28
|
+
|
29
|
+
output { #A marv output value
|
30
|
+
label :co2
|
31
|
+
path 'default' #It's not a marv, use the default output
|
32
|
+
name "Carbon Dioxide"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
all_calculations {
|
2
|
+
metadatum {
|
3
|
+
label :department
|
4
|
+
choices %w{stuff things more_stuff meta_things}
|
5
|
+
}
|
6
|
+
}
|
7
|
+
|
8
|
+
calculation{
|
9
|
+
name 'electricity'
|
10
|
+
label :electricity
|
11
|
+
path '/business/energy/electricity/grid'
|
12
|
+
profile {
|
13
|
+
label :usage
|
14
|
+
name 'Electricity Used'
|
15
|
+
path 'energyPerTime'
|
16
|
+
}
|
17
|
+
drill {
|
18
|
+
label :country
|
19
|
+
path 'country'
|
20
|
+
fixed 'Argentina'
|
21
|
+
}
|
22
|
+
output {
|
23
|
+
label :co2
|
24
|
+
path 'default'
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
calculation {
|
29
|
+
name 'transport'
|
30
|
+
label :transport
|
31
|
+
path '/transport/car/generic'
|
32
|
+
|
33
|
+
drill {
|
34
|
+
path 'fuel'
|
35
|
+
label :fuel
|
36
|
+
name 'Fuel Type'
|
37
|
+
}
|
38
|
+
drill {
|
39
|
+
path 'size'
|
40
|
+
label :size
|
41
|
+
name 'Vehicle Size'
|
42
|
+
}
|
43
|
+
profile {
|
44
|
+
path 'distance'
|
45
|
+
label :distance
|
46
|
+
name 'Distance Driven'
|
47
|
+
}
|
48
|
+
output {
|
49
|
+
label :co2
|
50
|
+
path 'default'
|
51
|
+
name 'Carbon Dioxide'
|
52
|
+
}
|
53
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
calculation {
|
2
2
|
name 'transport'
|
3
3
|
label :transport
|
4
4
|
path '/transport/car/generic'
|
@@ -20,7 +20,7 @@ Transport=AMEE::DataAbstraction::PrototypeCalculation.new{
|
|
20
20
|
}
|
21
21
|
output {
|
22
22
|
label :co2
|
23
|
-
path
|
23
|
+
path 'default'
|
24
24
|
name 'Carbon Dioxide'
|
25
25
|
}
|
26
26
|
}
|
@@ -28,7 +28,7 @@ Electricity=AMEE::DataAbstraction::PrototypeCalculation.new { # The application
|
|
28
28
|
|
29
29
|
output { #A marv output value
|
30
30
|
label :co2
|
31
|
-
path
|
31
|
+
path 'default' #It's not a marv, use the default output
|
32
32
|
name "Carbon Dioxide"
|
33
33
|
}
|
34
34
|
}
|
data/spec/spec_helper.rb
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rspec'
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
3
5
|
require 'amee-data-abstraction'
|
4
6
|
|
7
|
+
# Fake up Rails.root to be fixtures directory
|
8
|
+
class Rails
|
9
|
+
def self.root
|
10
|
+
File.dirname(__FILE__) + '/fixtures'
|
11
|
+
end
|
12
|
+
def self.logger
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
5
17
|
RSpec.configure do |config|
|
6
18
|
config.mock_with :flexmock
|
19
|
+
config.after(:each) do
|
20
|
+
delete_lock_files
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete_lock_files
|
25
|
+
config_dir = Dir.new("#{Rails.root}/config/calculations")
|
26
|
+
config_dir.each do |file|
|
27
|
+
File.delete("#{config_dir.path}/#{file}") if file =~ /lock/
|
28
|
+
end
|
7
29
|
end
|
8
30
|
|
9
31
|
AMEE::DataAbstraction.connection=FlexMock.new('connection') #Global connection mock, shouldn't receive anything, as we mock the individual amee-ruby calls in the tests
|
10
32
|
|
11
|
-
|
12
|
-
|
33
|
+
# Fake up Rails.root to be fixtures directory
|
34
|
+
class Rails
|
35
|
+
def self.root
|
36
|
+
File.dirname(__FILE__) + '/fixtures'
|
37
|
+
end
|
38
|
+
def self.logger
|
39
|
+
nil
|
40
|
+
end
|
13
41
|
end
|
14
42
|
|
15
43
|
include AMEE::DataAbstraction
|