amee-data-abstraction 1.2.0 → 1.3.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/CHANGELOG.txt +3 -0
- data/README.txt +28 -15
- data/Rakefile +1 -16
- data/VERSION +1 -1
- data/amee-data-abstraction.gemspec +6 -5
- data/lib/amee-data-abstraction/calculation.rb +1 -1
- data/lib/amee-data-abstraction/calculation_set.rb +152 -10
- data/lib/amee-data-abstraction/drill.rb +8 -2
- data/lib/amee-data-abstraction/input.rb +24 -0
- data/lib/amee-data-abstraction/ongoing_calculation.rb +13 -9
- data/lib/amee-data-abstraction/term.rb +31 -13
- data/spec/amee-data-abstraction/calculation_set_spec.rb +244 -8
- data/spec/amee-data-abstraction/calculation_spec.rb +23 -18
- data/spec/amee-data-abstraction/drill_spec.rb +34 -7
- 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 +45 -29
- data/spec/amee-data-abstraction/profile_spec.rb +2 -2
- data/spec/amee-data-abstraction/prototype_calculation_spec.rb +12 -8
- data/spec/amee-data-abstraction/term_spec.rb +49 -5
- data/spec/amee-data-abstraction/terms_list_spec.rb +16 -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/{electricity.rb → config/calculations/electricity.rb} +2 -2
- 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/config/electricity.rb +35 -0
- data/spec/spec_helper.rb +38 -6
- metadata +8 -7
- data/spec/fixtures/electricity_and_transport.rb +0 -55
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Profile do
|
4
4
|
it 'defaults to be a text-box' do
|
@@ -10,7 +10,7 @@ describe Profile do
|
|
10
10
|
mocker.item_value_definitions.
|
11
11
|
item_definition.data_category.
|
12
12
|
item_value_definition('distance',['someusage'],['someotherusage'])
|
13
|
-
t=
|
13
|
+
t=CalculationSet.find("transport")[:transport].clone
|
14
14
|
t[:distance].compulsory?('someusage').should eql true
|
15
15
|
t[:distance].compulsory?('someotherusage').should eql false
|
16
16
|
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
|
@@ -8,8 +8,12 @@ class PrototypeCalculation
|
|
8
8
|
cattr_accessor :called
|
9
9
|
end
|
10
10
|
describe PrototypeCalculation do
|
11
|
+
before :all do
|
12
|
+
@calc = CalculationSet.find("transport")[:transport]
|
13
|
+
end
|
14
|
+
|
11
15
|
it 'can create an instance' do
|
12
|
-
|
16
|
+
@calc.should be_a PrototypeCalculation
|
13
17
|
end
|
14
18
|
it 'can be initialized with a DSL block' do
|
15
19
|
PrototypeCalculation.new {call_me}
|
@@ -38,17 +42,17 @@ describe PrototypeCalculation do
|
|
38
42
|
pc[:alpha].should be_a Output
|
39
43
|
end
|
40
44
|
it 'can construct an ongoing calculation' do
|
41
|
-
|
45
|
+
@calc.begin_calculation.should be_a OngoingCalculation
|
42
46
|
end
|
43
47
|
it 'should make the terms of the ongoing calculation be their own instances' do
|
44
|
-
oc
|
48
|
+
oc=@calc.begin_calculation
|
45
49
|
oc[:distance].value :somevalue
|
46
50
|
oc[:distance].value.should eql :somevalue
|
47
|
-
|
51
|
+
@calc[:distance].value.should be_nil
|
48
52
|
end
|
49
53
|
it 'should copy name, path, label when cloning ongoing' do
|
50
54
|
[:path,:name,:label].each do |property|
|
51
|
-
|
55
|
+
@calc.begin_calculation.send(property).should eql @calc.send(property)
|
52
56
|
end
|
53
57
|
end
|
54
58
|
it 'can autogenerate drill terms for itself, based on talking to amee' do
|
@@ -227,7 +231,7 @@ describe PrototypeCalculation do
|
|
227
231
|
pc.terms.default_per_units.compact.map(&:name).should include 'hour'
|
228
232
|
end
|
229
233
|
it 'transfers memoised amee information to constructed ongoing calculations' do
|
230
|
-
t
|
234
|
+
t=@calc.clone
|
231
235
|
flexmock(AMEE::Data::Category).should_receive(:get).
|
232
236
|
with(AMEE::DataAbstraction.connection,'/data/transport/car/generic').
|
233
237
|
once.and_return(true)
|
@@ -235,7 +239,7 @@ describe PrototypeCalculation do
|
|
235
239
|
t.begin_calculation.send(:amee_data_category)
|
236
240
|
end
|
237
241
|
it 'can auto-create start and end date metadata' do
|
238
|
-
t
|
242
|
+
t=@calc.clone
|
239
243
|
t.instance_eval{
|
240
244
|
start_and_end_dates
|
241
245
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class Term
|
4
4
|
def call_me
|
@@ -9,6 +9,10 @@ class Term
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe Term do
|
12
|
+
before :all do
|
13
|
+
@calc = CalculationSet.find("transport")[:transport]
|
14
|
+
end
|
15
|
+
|
12
16
|
it 'can be initialized via DSL block' do
|
13
17
|
Term.new {call_me}
|
14
18
|
Term.called.should be_true
|
@@ -30,8 +34,13 @@ describe Term do
|
|
30
34
|
Term.new {note 'hello'}.note.should eql 'hello'
|
31
35
|
end
|
32
36
|
|
37
|
+
it "has note with no '\"' character" do
|
38
|
+
Term.new {note 'hello "some quote"'}.note.should eql "hello 'some quote'"
|
39
|
+
end
|
40
|
+
|
41
|
+
|
33
42
|
it 'has parent' do
|
34
|
-
|
43
|
+
@calc[:distance].parent.should eql @calc
|
35
44
|
end
|
36
45
|
it "has name defaulting to label" do
|
37
46
|
Term.new {label :hello}.name.should eql 'Hello'
|
@@ -85,17 +94,18 @@ describe Term do
|
|
85
94
|
t.hidden?.should be_false
|
86
95
|
end
|
87
96
|
it 'knows which terms come before or after it' do
|
88
|
-
|
97
|
+
@calc.terms.
|
89
98
|
select{|x|x.before?(:distance)}.map(&:label).
|
90
99
|
should eql [:fuel,:size]
|
91
|
-
|
100
|
+
@calc.terms.
|
92
101
|
select{|x|x.after?(:distance)}.map(&:label).
|
93
102
|
should eql [:co2]
|
94
103
|
end
|
95
104
|
|
96
105
|
it "should respond to unit methods" do
|
97
106
|
Term.new.methods.should include "unit","per_unit","default_unit","default_per_unit",
|
98
|
-
"alternative_units","alternative_per_units"
|
107
|
+
"alternative_units","alternative_per_units", "unit_choices",
|
108
|
+
"per_unit_choices"
|
99
109
|
end
|
100
110
|
|
101
111
|
it "has no default unit if none declared" do
|
@@ -131,14 +141,48 @@ describe Term do
|
|
131
141
|
term = Term.new {path :hello; default_unit :kg; default_per_unit :kWh}
|
132
142
|
units = term.alternative_units.map(&:name)
|
133
143
|
units.should include "gigagram", "pound", "tonne"
|
144
|
+
units.should_not include "kilogram", "kelvin"
|
134
145
|
per_units = term.alternative_per_units.map(&:name)
|
135
146
|
per_units.should include "joule", "british thermal unit", "megawatt hour"
|
147
|
+
per_units.should_not include "kilowatt hour"
|
148
|
+
end
|
149
|
+
|
150
|
+
it "has unit choices which include default and alternative" do
|
151
|
+
term = Term.new {path :hello; default_unit :kg; default_per_unit :kWh}
|
152
|
+
units = term.alternative_units.map(&:name)
|
153
|
+
units.should include "gigagram", "pound", "tonne"
|
154
|
+
units.should_not include "kilogram", "kelvin"
|
155
|
+
|
156
|
+
units = term.unit_choices.map(&:name)
|
157
|
+
units.first.should eql "kilogram"
|
158
|
+
units.should include "kilogram", "gigagram", "pound", "tonne"
|
159
|
+
units.should_not include "kelvin"
|
160
|
+
|
161
|
+
per_units = term.alternative_per_units.map(&:name)
|
162
|
+
per_units.should include "joule", "british thermal unit", "megawatt hour"
|
163
|
+
per_units.should_not include "kilowatt hour"
|
164
|
+
|
165
|
+
per_units = term.per_unit_choices.map(&:name)
|
166
|
+
per_units.first.should eql "kilowatt hour"
|
167
|
+
per_units.should include "kilowatt hour", "joule", "british thermal unit", "megawatt hour"
|
136
168
|
end
|
137
169
|
|
138
170
|
it "has limited set of alternative units if specified" do
|
139
171
|
term = Term.new {path :hello; default_unit :kg; alternative_units :t, :ton_us, :lb}
|
140
172
|
units = term.alternative_units.map(&:name)
|
141
173
|
units.should include "tonne", "pound", "short ton"
|
174
|
+
units.should_not include "kilogram", "gigagram", "ounce", "gram"
|
175
|
+
end
|
176
|
+
|
177
|
+
it "has unit choices which include default and alternative with limited set of alternative units" do
|
178
|
+
term = Term.new {path :hello; default_unit :kg; alternative_units :t, :ton_us, :lb}
|
179
|
+
units = term.alternative_units.map(&:name)
|
180
|
+
units.should include "tonne", "pound", "short ton"
|
181
|
+
units.should_not include "kilogram", "gigagram", "ounce", "gram"
|
182
|
+
|
183
|
+
units = term.unit_choices.map(&:name)
|
184
|
+
units.first.should eql "kilogram"
|
185
|
+
units.should include "kilogram", "tonne", "pound", "short ton"
|
142
186
|
units.should_not include "gigagram", "ounce", "gram"
|
143
187
|
end
|
144
188
|
|
@@ -1,27 +1,31 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe TermsList do
|
4
|
+
before :all do
|
5
|
+
@calc = CalculationSet.find("transport")[:transport]
|
6
|
+
end
|
7
|
+
|
4
8
|
it 'should be returned from calculations' do
|
5
|
-
|
9
|
+
@calc.terms.should be_a TermsList
|
6
10
|
end
|
7
11
|
it 'should give properties' do
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
@calc.terms.labels.should eql [:fuel,:size,:distance,:co2]
|
13
|
+
@calc.terms.paths.should eql ['fuel','size','distance','default']
|
14
|
+
@calc.terms.names.should eql ['Fuel Type','Vehicle Size','Distance Driven','Carbon Dioxide']
|
11
15
|
end
|
12
16
|
it 'should select by class' do
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
@calc.terms.drills.labels.should eql [:fuel,:size]
|
18
|
+
@calc.terms.profiles.labels.should eql [:distance]
|
19
|
+
@calc.terms.outputs.labels.should eql [:co2]
|
16
20
|
end
|
17
21
|
it 'should select by property' do
|
18
|
-
t
|
22
|
+
t=@calc.begin_calculation
|
19
23
|
t[:distance].value 5
|
20
24
|
t.terms.set.labels.should eql [:distance]
|
21
25
|
t.terms.unset.labels.should eql [:fuel,:size,:co2]
|
22
26
|
end
|
23
27
|
it 'should select by chain' do
|
24
|
-
t
|
28
|
+
t=@calc.begin_calculation
|
25
29
|
t[:fuel].value 'diesel'
|
26
30
|
t.terms.drills.set.labels.should eql [:fuel]
|
27
31
|
t.terms.drills.unset.labels.should eql [:size]
|
@@ -29,7 +33,7 @@ describe TermsList do
|
|
29
33
|
t.terms.unset.drills.labels.should eql [:size]
|
30
34
|
end
|
31
35
|
it 'should select by order' do
|
32
|
-
t
|
36
|
+
t=@calc.clone
|
33
37
|
t.terms.before(:distance).labels.
|
34
38
|
should eql [:fuel,:size]
|
35
39
|
t.terms.after(:distance).labels.
|
@@ -40,7 +44,7 @@ describe TermsList do
|
|
40
44
|
mocker.item_value_definitions.
|
41
45
|
item_definition.data_category.
|
42
46
|
item_value_definition('distance',['usage1'],['usage2'],['usage3'])
|
43
|
-
t
|
47
|
+
t=@calc.clone
|
44
48
|
t.profiles.compulsory('usage1').labels.should eql [:distance]
|
45
49
|
t.profiles.optional('usage2').labels.should eql [:distance]
|
46
50
|
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
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
calculation { # The application has support for an electricity calculation. :electricity is the internal label used to refer to it
|
2
2
|
label :electricity
|
3
3
|
name "Electricity Consumption"
|
4
4
|
path '/business/energy/electricity/grid'
|
@@ -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
|
}
|
@@ -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
|
}
|
@@ -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
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -2,20 +2,37 @@ require 'rubygems'
|
|
2
2
|
require 'spec'
|
3
3
|
require 'rspec_spinner'
|
4
4
|
require 'flexmock'
|
5
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
6
5
|
require 'amee'
|
6
|
+
|
7
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
7
8
|
require 'amee-data-abstraction'
|
8
9
|
|
10
|
+
# Fake up Rails.root to be fixtures directory
|
11
|
+
class Rails
|
12
|
+
def self.root
|
13
|
+
File.dirname(__FILE__) + '/fixtures'
|
14
|
+
end
|
15
|
+
def self.logger
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
Spec::Runner.configure do |config|
|
10
21
|
config.mock_with :flexmock
|
22
|
+
config.after(:each) do
|
23
|
+
delete_lock_files
|
24
|
+
end
|
11
25
|
end
|
12
26
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
27
|
+
def delete_lock_files
|
28
|
+
config_dir = Dir.new("#{Rails.root}/config/calculations")
|
29
|
+
config_dir.each do |file|
|
30
|
+
File.delete("#{config_dir.path}/#{file}") if file =~ /lock/
|
31
|
+
end
|
17
32
|
end
|
18
33
|
|
34
|
+
AMEE::DataAbstraction.connection=FlexMock.new('connection') #Global connection mock, shouldn't receive anything, as we mock the individual amee-ruby calls in the tests
|
35
|
+
|
19
36
|
include AMEE::DataAbstraction
|
20
37
|
|
21
38
|
class AMEEMocker
|
@@ -81,6 +98,21 @@ class AMEEMocker
|
|
81
98
|
return self
|
82
99
|
end
|
83
100
|
|
101
|
+
# This represents the skipping of drill choices which occur on an AMEE drill
|
102
|
+
# down when only one choice exists for a given drill - it skips to the next,
|
103
|
+
# offering the next set of choices or a uid. In these cases, the skipped drill
|
104
|
+
# is set as an automatic selection
|
105
|
+
def drill_with_skip(skipped_selections=[])
|
106
|
+
test.flexmock(AMEE::Data::DrillDown).
|
107
|
+
should_receive(:get).
|
108
|
+
with(connection,
|
109
|
+
"/data/#{path}/drill?#{selections.map{|k,v|"#{k}=#{v}"}.join('&')}").
|
110
|
+
at_least.once.
|
111
|
+
and_return(test.flexmock(:choices=>choices,:selections=>Hash[selections].merge(skipped_selections),
|
112
|
+
:data_item_uid=>dataitemuid))
|
113
|
+
return self
|
114
|
+
end
|
115
|
+
|
84
116
|
def profile_list
|
85
117
|
test.flexmock(AMEE::Profile::ProfileList).should_receive(:new).
|
86
118
|
with(connection).at_least.once.
|
@@ -251,7 +283,7 @@ class AMEEMocker
|
|
251
283
|
def update
|
252
284
|
test.flexmock(AMEE::Profile::Item).should_receive(:update).
|
253
285
|
with(connection,pipath,
|
254
|
-
{:get_item=>
|
286
|
+
{:get_item=>true}.merge(existing).merge(params)).
|
255
287
|
at_least.once
|
256
288
|
return self
|
257
289
|
end
|