amee-data-abstraction 2.1.1 → 2.2.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 +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
|