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
data/CHANGELOG.txt
CHANGED
data/README.txt
CHANGED
@@ -25,9 +25,9 @@ Documentation: http://rubydoc.info/gems/amee-data-abstraction
|
|
25
25
|
All gem requirements should be installed as part of the rubygems installation process
|
26
26
|
above, but are listed here for completeness.
|
27
27
|
|
28
|
-
* amee ~>
|
28
|
+
* amee ~> 4.1
|
29
29
|
* uuidtools = 2.1.2
|
30
|
-
* quantify =
|
30
|
+
* quantify = 2.0.0
|
31
31
|
|
32
32
|
== USAGE
|
33
33
|
|
@@ -117,16 +117,10 @@ Submit to AMEE for calculation
|
|
117
117
|
|
118
118
|
Typical practice is initialize the calculation prototypes required for an
|
119
119
|
application via a configuration file which creates the required calculation
|
120
|
-
templates within an instance of CalculationSet.
|
121
|
-
|
122
|
-
initializing new calculations and templating view structures (e.g. tables, forms)
|
123
|
-
from anywhere in the application.
|
120
|
+
templates within an instance of CalculationSet. Such a configuration file can
|
121
|
+
be structured the follow DSL:
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
# e.g. /config/initializers/calculations.rb
|
128
|
-
|
129
|
-
Calculations = AMEE::DataAbstraction::CalculationSet {
|
123
|
+
# e.g. /config/calculations/my_emissions_calculations.rb
|
130
124
|
|
131
125
|
calculation {
|
132
126
|
label :electricity
|
@@ -148,17 +142,35 @@ Adding a configuration to /config or /config/initializers may be appropriate
|
|
148
142
|
path "/some/fuel/associated/path/in/amee"
|
149
143
|
terms_from_amee
|
150
144
|
}
|
151
|
-
|
145
|
+
|
146
|
+
The default location for such files within Rails applications is under
|
147
|
+
/config/calculations. If such an approach is taken, the configuration can be
|
148
|
+
read and a calculation set generated by using the filename, thus:
|
149
|
+
|
150
|
+
CalculationSet.find('my_emissions_calculations')
|
151
|
+
|
152
|
+
#=> <AMEE::DataAbstraction::CalculationSet ... >
|
153
|
+
|
154
|
+
Otherwise, the path to the configuration file can be provided:
|
155
|
+
|
156
|
+
CalculationSet.find('some/directory/my_emissions_calculations')
|
157
|
+
|
158
|
+
#=> <AMEE::DataAbstraction::CalculationSet ... >
|
159
|
+
|
160
|
+
The calculation set is accessible as follow using the same argument as used
|
161
|
+
by the Find method (filename if conventional Rails location, path otherwise):
|
162
|
+
|
163
|
+
CalculationSet.sets['my_emissions_calculations']
|
152
164
|
|
153
165
|
#=> <AMEE::DataAbstraction::CalculationSet ... >
|
154
166
|
|
155
167
|
From this global calculation set, initialize a new calculation
|
156
168
|
|
157
|
-
my_fuel_calculation =
|
169
|
+
my_fuel_calculation = CalculationSet.sets['my_emissions_calcualtions'][:fuel].begin_calculation
|
158
170
|
|
159
171
|
#=> <AMEE::DataAbstraction::OngoingCalculation ... >
|
160
172
|
|
161
|
-
a_different_transport_calculation =
|
173
|
+
a_different_transport_calculation = CalculationSet.sets['my_emissions_calcualtions'][:transport].begin_calculation
|
162
174
|
|
163
175
|
#=> <AMEE::DataAbstraction::OngoingCalculation ... >
|
164
176
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.2.0
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{amee-data-abstraction}
|
8
|
-
s.version = "2.
|
8
|
+
s.version = "2.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["James Hetherington", "Andrew Berkeley", "James Smith", "George Palmer"]
|
12
|
-
s.date = %q{2011-10-
|
12
|
+
s.date = %q{2011-10-18}
|
13
13
|
s.description = %q{Part of the AMEEappkit this gem provides a data abstraction layer, decreasing the amount and detail of development required}
|
14
14
|
s.email = %q{help@amee.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -62,16 +62,17 @@ Gem::Specification.new do |s|
|
|
62
62
|
"spec/core-extensions/hash_spec.rb",
|
63
63
|
"spec/core-extensions/ordered_hash_spec.rb",
|
64
64
|
"spec/core-extensions/proc_spec.rb",
|
65
|
-
"spec/fixtures/electricity.rb",
|
66
|
-
"spec/fixtures/electricity_and_transport.rb",
|
67
|
-
"spec/fixtures/transport.rb",
|
65
|
+
"spec/fixtures/config/calculations/electricity.rb",
|
66
|
+
"spec/fixtures/config/calculations/electricity_and_transport.rb",
|
67
|
+
"spec/fixtures/config/calculations/transport.rb",
|
68
|
+
"spec/fixtures/config/electricity.rb",
|
68
69
|
"spec/spec.opts",
|
69
70
|
"spec/spec_helper.rb"
|
70
71
|
]
|
71
72
|
s.homepage = %q{http://github.com/AMEE/amee-data-abstraction}
|
72
73
|
s.licenses = ["BSD 3-Clause"]
|
73
74
|
s.require_paths = ["lib"]
|
74
|
-
s.rubygems_version = %q{1.
|
75
|
+
s.rubygems_version = %q{1.5.3}
|
75
76
|
s.summary = %q{Calculation and form building tool hiding details of AMEEconnect}
|
76
77
|
|
77
78
|
if s.respond_to? :specification_version then
|
@@ -132,7 +132,7 @@ module AMEE
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def explorer_url
|
135
|
-
::Rails.logger.info "#explorer_url method deprecated. Use #discover_url" if defined? Rails
|
135
|
+
::Rails.logger.info "#explorer_url method deprecated. Use #discover_url" if defined?(Rails) && ::Rails.logger.present?
|
136
136
|
discover_url
|
137
137
|
end
|
138
138
|
|
@@ -36,22 +36,95 @@ module AMEE
|
|
36
36
|
#
|
37
37
|
class CalculationSet
|
38
38
|
|
39
|
-
#
|
40
|
-
#
|
39
|
+
# Class variable holding all instantiated calculation sets keyed on the set
|
40
|
+
# name.
|
41
41
|
#
|
42
|
-
|
43
|
-
|
42
|
+
@@sets = {}
|
43
|
+
|
44
|
+
# Convenience method for accessing the @@sets class variable
|
45
|
+
def self.sets
|
46
|
+
@@sets
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieve a calculation set on the basis of a configuration file name or
|
50
|
+
# relatiev/absolute file path. If configuration files are location within
|
51
|
+
# the default Rails location under '/config/calculations' then the path and
|
52
|
+
# the .rb extenstion can be omitted from the name.
|
53
|
+
#
|
54
|
+
def self.find(name)
|
55
|
+
@@sets[name.to_sym] or load_set(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Regenerate a configuration lock file assocaited with the master
|
59
|
+
# configuration file <tt>name</tt>. Optionally set a custom path for the
|
60
|
+
# lock file as <tt>output_path</tt>, otherwise the lock file path and
|
61
|
+
# filename will be based upon the master file with the extension .lock.rb.
|
62
|
+
#
|
63
|
+
def self.regenerate_lock_file(name,output_path=nil)
|
64
|
+
set = CalculationSet.find(name)
|
65
|
+
set.generate_lock_file(output_path)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Find a specific prototype calculation instance without specifying the set
|
69
|
+
# to which it belongs.
|
70
|
+
#
|
71
|
+
def self.find_prototype_calculation(label)
|
72
|
+
@@sets.each_pair do |name,set|
|
73
|
+
set = find(name)
|
74
|
+
return set[label] if set[label]
|
75
|
+
end
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
# Load a calculation set based on a filename or full path.
|
82
|
+
def self.load_set(name)
|
83
|
+
CalculationSet.new(name,:file => name) do
|
84
|
+
instance_eval(File.open(self.config_path).read)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
DEFFAULT_RAILS_CONFIG_DIR = "config/calculations"
|
89
|
+
|
90
|
+
# Find the config file assocaited with <tt>name</tt>. The method first checks
|
91
|
+
# the default Rails configuration location (config/calculations) then the
|
92
|
+
# file path described by <tt>name</tt> relative to the Rails root and by
|
93
|
+
# absolute path.
|
94
|
+
def self.find_config_file(name)
|
95
|
+
default_config_dir = defined?(::Rails) ? "#{::Rails.root}/#{DEFFAULT_RAILS_CONFIG_DIR}" : nil
|
96
|
+
if defined?(::Rails) && File.exists?("#{default_config_dir}/#{name.to_s}.rb")
|
97
|
+
"#{default_config_dir}/#{name.to_s}.rb"
|
98
|
+
elsif defined?(::Rails) && File.exists?("#{default_config_dir}/#{name.to_s}")
|
99
|
+
"#{default_config_dir}/#{name.to_s}"
|
100
|
+
elsif defined?(::Rails) && File.exists?("#{::Rails.root}/#{name}")
|
101
|
+
"#{::Rails.root}/#{name}"
|
102
|
+
elsif File.exists?(name)
|
103
|
+
name
|
104
|
+
else
|
105
|
+
raise ArgumentError, "The config file '#{name}' could not be located"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
public
|
110
|
+
|
111
|
+
attr_accessor :calculations, :name, :file
|
112
|
+
|
113
|
+
# Initialise a new Calculation set. Specify the name of the calculation set
|
114
|
+
# as the first argument. This name is used as the set key within the class
|
115
|
+
# variable @@sets hash.
|
116
|
+
#
|
117
|
+
def initialize(name,options={},&block)
|
118
|
+
raise ArgumentError, "Calculation set must have a name" unless name
|
119
|
+
@name = name
|
120
|
+
@file = CalculationSet.find_config_file(options[:file]) if options[:file]
|
121
|
+
@calculations = ActiveSupport::OrderedHash.new
|
44
122
|
@all_blocks=[]
|
45
123
|
@all_options={}
|
46
124
|
instance_eval(&block) if block
|
125
|
+
@@sets[@name.to_sym] = self
|
47
126
|
end
|
48
127
|
|
49
|
-
# Access the @calculations instance variable ordered hash. Keys are labels
|
50
|
-
# assocaited with each prototype calculation; values are the instantiated
|
51
|
-
# <i>PrototypeCalculation</i> objects
|
52
|
-
#
|
53
|
-
attr_accessor :calculations
|
54
|
-
|
55
128
|
# Shorthand method for returning the prototype calculation which is represented
|
56
129
|
# by a label matching <tt>sym</tt>
|
57
130
|
#
|
@@ -94,8 +167,77 @@ module AMEE
|
|
94
167
|
instance_exec(usage,&dsl_block)
|
95
168
|
}
|
96
169
|
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the path to the configuration file for <tt>self</tt>. If a .lock
|
173
|
+
# file exists, this takes precedence, otherwise the master config file
|
174
|
+
# described by the <tt>#file</tt> attribute is returned.
|
175
|
+
#
|
176
|
+
def config_path
|
177
|
+
lock_file_exists? ? lock_file_path : @file
|
178
|
+
end
|
97
179
|
|
180
|
+
# Returns the path to the configuration lock file
|
181
|
+
def lock_file_path
|
182
|
+
@file.gsub(".rb",".lock.rb") rescue nil
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns <tt>true</tt> if a configuration lock file exists. Otherwise,
|
186
|
+
# returns <tt>false</tt>.
|
187
|
+
#
|
188
|
+
def lock_file_exists?
|
189
|
+
File.exists?(lock_file_path)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Generates a lock file for the calcuation set configuration. If no argument
|
193
|
+
# is provided the, the lock file is generated using the filename and path
|
194
|
+
# described by the <tt>#lock_file_path</tt> method. If a custom output
|
195
|
+
# location is required, this can be provided optionally as an argument.
|
196
|
+
#
|
197
|
+
def generate_lock_file(output_path=nil)
|
198
|
+
file = output_path || lock_file_path or raise ArgumentError,
|
199
|
+
"No path for lock file known. Either set path for the master config file using the #file accessor method or provide as an argument"
|
200
|
+
string = ""
|
201
|
+
@calculations.values.each do |prototype_calculation|
|
202
|
+
string += "calculation {\n\n"
|
203
|
+
string += " name \"#{prototype_calculation.name}\"\n"
|
204
|
+
string += " label :#{prototype_calculation.label}\n"
|
205
|
+
string += " path \"#{prototype_calculation.path}\"\n\n"
|
206
|
+
prototype_calculation.terms.each do |term|
|
207
|
+
string += " #{term.class.to_s.split("::").last.downcase} {\n"
|
208
|
+
string += " name \"#{term.name}\"\n" unless term.name.blank?
|
209
|
+
string += " label :#{term.label}\n" unless term.label.blank?
|
210
|
+
string += " path \"#{term.path}\"\n" unless term.path.blank?
|
211
|
+
string += " value \"#{term.value}\"\n" unless term.value.blank?
|
212
|
+
|
213
|
+
if term.is_a?(AMEE::DataAbstraction::Input)
|
214
|
+
string += " fixed \"#{term.value}\"\n" if term.fixed? && !term.value.blank?
|
215
|
+
if term.is_a?(AMEE::DataAbstraction::Drill)
|
216
|
+
string += " choices \"#{term.choices.join('","')}\"\n" if term.instance_variable_defined?("@choices") && !term.choices.blank?
|
217
|
+
elsif term.is_a?(AMEE::DataAbstraction::Profile)
|
218
|
+
string += " choices [\"#{term.choices.join('","')}\"]\n" if term.instance_variable_defined?("@choices") && !term.choices.blank?
|
219
|
+
end
|
220
|
+
string += " optional!\n" if term.optional?
|
221
|
+
end
|
222
|
+
|
223
|
+
string += " default_unit :#{term.default_unit.label}\n" unless term.default_unit.blank?
|
224
|
+
string += " default_per_unit :#{term.default_per_unit.label}\n" unless term.default_per_unit.blank?
|
225
|
+
string += " alternative_units :#{term.alternative_units.map(&:label).join(', :')}\n" unless term.alternative_units.blank?
|
226
|
+
string += " alternative_per_units :#{term.alternative_per_units.map(&:label).join(', :')}\n" unless term.alternative_per_units.blank?
|
227
|
+
string += " unit :#{term.unit.label}\n" unless term.unit.blank?
|
228
|
+
string += " per_unit :#{term.per_unit.label}\n" unless term.per_unit.blank?
|
229
|
+
string += " type :#{term.type}\n" unless term.type.blank?
|
230
|
+
string += " interface :#{term.interface}\n" unless term.interface.blank?
|
231
|
+
string += " note \"#{term.note}\"\n" unless term.note.blank?
|
232
|
+
string += " disable!\n" if !term.is_a?(AMEE::DataAbstraction::Drill) && term.disabled?
|
233
|
+
string += " hide!\n" if term.hidden?
|
234
|
+
string += " }\n\n"
|
235
|
+
end
|
236
|
+
string += "}\n\n"
|
237
|
+
end
|
238
|
+
File.open(file,'w') { |f| f.write string }
|
98
239
|
end
|
240
|
+
|
99
241
|
end
|
100
242
|
end
|
101
243
|
end
|
@@ -158,6 +158,16 @@ module AMEE
|
|
158
158
|
!optional?(usage)
|
159
159
|
end
|
160
160
|
|
161
|
+
# Manually set the term as optional
|
162
|
+
def optional!
|
163
|
+
@optional=true
|
164
|
+
end
|
165
|
+
|
166
|
+
# Manually set the term as compuslory
|
167
|
+
def compulsory!
|
168
|
+
@optional=false
|
169
|
+
end
|
170
|
+
|
161
171
|
# Check that the value of <tt>self</tt> is valid. If invalid, and is defined
|
162
172
|
# as part of a calculation, add the invalidity message to the parent
|
163
173
|
# calculation's error list. Otherwise, raise a <i>ChoiceValidation</i>
|
@@ -258,7 +258,7 @@ module AMEE
|
|
258
258
|
def load_outputs
|
259
259
|
outputs.each do |output|
|
260
260
|
res=nil
|
261
|
-
if output.path
|
261
|
+
if output.path.to_s=='default'
|
262
262
|
res= profile_item.amounts.find{|x| x[:default] == true}
|
263
263
|
else
|
264
264
|
res= profile_item.amounts.find{|x| x[:type] == output.path}
|
@@ -84,16 +84,6 @@ module AMEE
|
|
84
84
|
#
|
85
85
|
attr_property :path
|
86
86
|
|
87
|
-
# String representing an annotation for <tt>self</tt>. Set a value by
|
88
|
-
# passing an argument. Retrieve a value by calling without an argument,
|
89
|
-
# e.g.,
|
90
|
-
#
|
91
|
-
# my_term.note 'Enter the mass of cement produced in the reporting period'
|
92
|
-
#
|
93
|
-
# my_term.note #=> 'Enter the mass of cement ...'
|
94
|
-
#
|
95
|
-
attr_property :note
|
96
|
-
|
97
87
|
# Symbol representing the owning parent calculation of <tt>self</tt>. Set
|
98
88
|
# the owning calculation object by passing as an argument. Retrieve it by
|
99
89
|
# calling without an argument, e.g.,
|
@@ -211,6 +201,19 @@ module AMEE
|
|
211
201
|
end
|
212
202
|
@value
|
213
203
|
end
|
204
|
+
|
205
|
+
# String representing an annotation for <tt>self</tt>. Set a value by
|
206
|
+
# passing an argument. Retrieve a value by calling without an argument,
|
207
|
+
# e.g.,
|
208
|
+
#
|
209
|
+
# my_term.note 'Enter the mass of cement produced in the reporting period'
|
210
|
+
#
|
211
|
+
# my_term.note #=> 'Enter the mass of cement ...'
|
212
|
+
#
|
213
|
+
def note(string=nil)
|
214
|
+
instance_variable_set("@note",string.gsub('"',"'")) unless string.nil?
|
215
|
+
instance_variable_get("@note")
|
216
|
+
end
|
214
217
|
|
215
218
|
# Symbols representing the attributes of <tt>self</tt> which are concerned
|
216
219
|
# with quantity units.
|
@@ -264,19 +267,33 @@ module AMEE
|
|
264
267
|
end
|
265
268
|
|
266
269
|
[:unit,:per_unit].each do |field|
|
270
|
+
|
271
|
+
# If no argument provided, returns the alternative units which are valid
|
272
|
+
# for <tt>self</tt>. If a list of units are provided as an argument, these
|
273
|
+
# override the dynamically assigned alternative units for <tt>self</tt>.
|
274
|
+
#
|
267
275
|
define_method("alternative_#{field}s") do |*args|
|
268
276
|
ivar = "@alternative_#{field}s"
|
269
|
-
default = send("default_#{field}".to_sym)
|
270
277
|
unless args.empty?
|
271
|
-
args << default if default
|
272
278
|
units = args.map {|arg| Unit.for(arg) }
|
273
279
|
Term.validate_dimensional_equivalence?(*units)
|
274
280
|
instance_variable_set(ivar, units)
|
275
281
|
else
|
276
282
|
return instance_variable_get(ivar) if instance_variable_get(ivar)
|
277
|
-
|
283
|
+
default = send("default_#{field}".to_sym)
|
284
|
+
return instance_variable_set(ivar, (default.alternatives)) if default
|
278
285
|
end
|
279
286
|
end
|
287
|
+
|
288
|
+
# Returns the list of unit choices for <tt>self</tt>, including both the
|
289
|
+
# default unit and all alternative units.
|
290
|
+
#
|
291
|
+
define_method("#{field}_choices") do |*args|
|
292
|
+
choices = send("alternative_#{field}s".to_sym)
|
293
|
+
default = send("default_#{field}".to_sym)
|
294
|
+
choices = [default] + choices if default
|
295
|
+
return choices
|
296
|
+
end
|
280
297
|
end
|
281
298
|
|
282
299
|
# Returns <tt>true</tt> if <tt>self</tt> has a populated value attribute.
|
@@ -503,6 +520,7 @@ module AMEE
|
|
503
520
|
else value
|
504
521
|
end
|
505
522
|
end
|
523
|
+
|
506
524
|
end
|
507
525
|
end
|
508
526
|
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
|
+
|
2
3
|
class CalculationSet
|
3
4
|
def call_me
|
4
5
|
#stub, because flexmock doesn't work for new instances during constructor
|
@@ -8,25 +9,260 @@ class CalculationSet
|
|
8
9
|
@@called
|
9
10
|
end
|
10
11
|
end
|
12
|
+
|
11
13
|
describe CalculationSet do
|
12
|
-
|
13
|
-
|
14
|
+
|
15
|
+
before :all do
|
16
|
+
CalculationSet.sets.clear
|
17
|
+
@calc_set = CalculationSet.find("electricity_and_transport")
|
14
18
|
end
|
19
|
+
|
15
20
|
it 'can create an instance' do
|
16
|
-
|
21
|
+
@calc_set.calculations.should be_a ActiveSupport::OrderedHash
|
22
|
+
@calc_set.should be_a CalculationSet
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can create an instance and find calcs' do
|
26
|
+
@calc_set.calculations.should be_a ActiveSupport::OrderedHash
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can access class sets hash" do
|
30
|
+
CalculationSet.sets[:electricity_and_transport].should be_a CalculationSet
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is included in class sets hash if initialised by find method" do
|
34
|
+
CalculationSet.sets[:electricity_and_transport].should be_a CalculationSet
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has file attribute if initialised by find method" do
|
38
|
+
CalculationSet.sets[:electricity_and_transport].file.should eql "#{Rails.root}/config/calculations/electricity_and_transport.rb"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has name attribute if initialised by find method" do
|
42
|
+
CalculationSet.sets[:electricity_and_transport].name.should eql "electricity_and_transport"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "is included in class sets hash if initialised manually" do
|
46
|
+
CalculationSet.new('my_set') {calculation {label :mycalc}}
|
47
|
+
CalculationSet.sets[:my_set].should be_a CalculationSet
|
17
48
|
end
|
49
|
+
|
50
|
+
it "has name" do
|
51
|
+
CalculationSet.new('my_set') {calculation {label :mycalc}}.name.should eql "my_set"
|
52
|
+
end
|
53
|
+
|
18
54
|
it 'can access a calculation by key' do
|
19
|
-
|
55
|
+
@calc_set[:transport].should be_a PrototypeCalculation
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "initialising from file" do
|
59
|
+
|
60
|
+
after(:each) do
|
61
|
+
CalculationSet.sets.clear
|
62
|
+
delete_lock_files
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should find config file in default Rails location using just file name" do
|
66
|
+
CalculationSet.find_config_file("electricity").should eql "#{Rails.root}/config/calculations/electricity.rb"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should find config file in default Rails location using file name and extension" do
|
70
|
+
CalculationSet.find_config_file("electricity.rb").should eql "#{Rails.root}/config/calculations/electricity.rb"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should find config file in other Rails location using relative path" do
|
74
|
+
CalculationSet.find_config_file("config/electricity.rb").should eql "#{Rails.root}/config/electricity.rb"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise error if config file not found" do
|
78
|
+
lambda{CalculationSet.find_config_file("fuel")}.should raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call load_set if no set exists in class hash" do
|
82
|
+
CalculationSet.sets[:transport].should be_nil
|
83
|
+
flexmock(AMEE::DataAbstraction::CalculationSet) do |mock|
|
84
|
+
mock.should_receive(:load_set).once
|
85
|
+
end
|
86
|
+
set = CalculationSet.find('transport')
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not call load_set if set exists in class hash" do
|
90
|
+
CalculationSet.sets[:transport].should be_nil
|
91
|
+
set = CalculationSet.find('transport')
|
92
|
+
CalculationSet.sets[:transport].should be_a CalculationSet
|
93
|
+
flexmock(AMEE::DataAbstraction::CalculationSet) do |mock|
|
94
|
+
mock.should_receive(:load_set).never
|
95
|
+
end
|
96
|
+
set = CalculationSet.find('transport')
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should generate set from file name using find method" do
|
100
|
+
CalculationSet.sets[:transport].should be_nil
|
101
|
+
set = CalculationSet.find('transport')
|
102
|
+
set.should be_a CalculationSet
|
103
|
+
CalculationSet.sets[:transport].should be_a CalculationSet
|
104
|
+
set.name.should eql 'transport'
|
105
|
+
set.file.should eql "#{Rails.root}/config/calculations/transport.rb"
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should regenerate lock file at default location" do
|
109
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
110
|
+
File.exist?(lock_file).should be_false
|
111
|
+
CalculationSet.sets[:transport].should be_nil
|
112
|
+
set = CalculationSet.find('transport')
|
113
|
+
File.exist?(lock_file).should be_false
|
114
|
+
CalculationSet.sets[:transport].should be_a CalculationSet
|
115
|
+
|
116
|
+
set.generate_lock_file
|
117
|
+
File.exist?(lock_file).should be_true
|
118
|
+
|
119
|
+
# lock file content
|
120
|
+
content = File.open(lock_file).read
|
121
|
+
|
122
|
+
# clear lock file to test for regenerated data
|
123
|
+
File.open(lock_file,'w') {|file| file.write "overwrite content"}
|
124
|
+
File.open(lock_file).read.should eql "overwrite content"
|
125
|
+
File.exist?(lock_file).should be_true
|
126
|
+
|
127
|
+
# regenerate and test content matches original
|
128
|
+
CalculationSet.regenerate_lock_file('transport')
|
129
|
+
File.exist?(lock_file).should be_true
|
130
|
+
File.open(lock_file).read.should eql content
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should regenerate lock file at custom location" do
|
134
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
135
|
+
File.exist?(lock_file).should be_false
|
136
|
+
CalculationSet.sets[:transport].should be_nil
|
137
|
+
set = CalculationSet.find('transport')
|
138
|
+
|
139
|
+
File.exist?(lock_file).should be_false
|
140
|
+
CalculationSet.sets[:transport].should be_a CalculationSet
|
141
|
+
|
142
|
+
set.generate_lock_file
|
143
|
+
File.exist?(lock_file).should be_true
|
144
|
+
|
145
|
+
content = File.open(lock_file).read
|
146
|
+
File.open(lock_file,'w') {|file| file.write "overwrite content"}
|
147
|
+
File.open(lock_file).read.should eql "overwrite content"
|
148
|
+
File.exist?(lock_file).should be_true
|
149
|
+
|
150
|
+
CalculationSet.regenerate_lock_file('transport', "#{Rails.root}/transport.lock.rb")
|
151
|
+
File.exist?(lock_file).should be_true
|
152
|
+
File.exist?("#{Rails.root}/transport.lock.rb").should be_true
|
153
|
+
File.open(lock_file).read.should eql "overwrite content"
|
154
|
+
File.open("#{Rails.root}/transport.lock.rb").read.should eql content
|
155
|
+
|
156
|
+
File.delete("#{Rails.root}/transport.lock.rb")
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should return a lock file path based on master config file" do
|
160
|
+
set = CalculationSet.find('transport')
|
161
|
+
set.lock_file_path.should eql "#{Rails.root}/config/calculations/transport.lock.rb"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should return lock file path if lock file exists" do
|
165
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
166
|
+
File.exist?(lock_file).should be_false
|
167
|
+
set = CalculationSet.find('transport')
|
168
|
+
File.exist?(lock_file).should be_false
|
169
|
+
set.generate_lock_file
|
170
|
+
File.exist?(lock_file).should be_true
|
171
|
+
set.config_path.should eql lock_file
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should return master file path if lock file does not exist" do
|
175
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
176
|
+
File.exist?(lock_file).should be_false
|
177
|
+
set = CalculationSet.find('transport')
|
178
|
+
File.exist?(lock_file).should be_false
|
179
|
+
set.config_path.should eql "#{Rails.root}/config/calculations/transport.rb"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should know if lock file exists" do
|
183
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
184
|
+
File.exist?(lock_file).should be_false
|
185
|
+
set = CalculationSet.find('transport')
|
186
|
+
File.exist?(lock_file).should be_false
|
187
|
+
set.generate_lock_file
|
188
|
+
File.exist?(lock_file).should be_true
|
189
|
+
set.lock_file_exists?.should be_true
|
190
|
+
File.delete(lock_file)
|
191
|
+
File.exist?(lock_file).should be_false
|
192
|
+
set.lock_file_exists?.should be_false
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should generate lock file" do
|
196
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
197
|
+
File.exist?(lock_file).should be_false
|
198
|
+
|
199
|
+
set = CalculationSet.find('transport')
|
200
|
+
File.exist?(lock_file).should be_false
|
201
|
+
set.lock_file_exists?.should be_false
|
202
|
+
|
203
|
+
set.generate_lock_file
|
204
|
+
File.exist?(lock_file).should be_true
|
205
|
+
set.lock_file_exists?.should be_true
|
206
|
+
|
207
|
+
content = File.open(lock_file).read
|
208
|
+
|
209
|
+
File.delete(lock_file)
|
210
|
+
File.exist?(lock_file).should be_false
|
211
|
+
set.lock_file_exists?.should be_false
|
212
|
+
|
213
|
+
set.generate_lock_file
|
214
|
+
File.exist?(lock_file).should be_true
|
215
|
+
set.lock_file_exists?.should be_true
|
216
|
+
File.open(lock_file).read.should eql content
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should generate lock file at custom location" do
|
220
|
+
lock_file = "#{Rails.root}/config/calculations/transport.lock.rb"
|
221
|
+
File.exist?(lock_file).should be_false
|
222
|
+
|
223
|
+
set = CalculationSet.find('transport')
|
224
|
+
File.exist?(lock_file).should be_false
|
225
|
+
set.lock_file_exists?.should be_false
|
226
|
+
|
227
|
+
set.generate_lock_file("#{Rails.root}/transport.lock.rb")
|
228
|
+
File.exist?(lock_file).should be_false
|
229
|
+
set.lock_file_exists?.should be_false
|
230
|
+
File.exist?("#{Rails.root}/transport.lock.rb").should be_true
|
231
|
+
|
232
|
+
File.delete("#{Rails.root}/transport.lock.rb")
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
it "can find a prototype calc without calc set" do
|
238
|
+
CalculationSet.new('my_set') {
|
239
|
+
calculation {label :my_calc}
|
240
|
+
calculation {label :my_other_calc}
|
241
|
+
}
|
242
|
+
CalculationSet.new('your_set') {
|
243
|
+
calculation {label :your_calc}
|
244
|
+
calculation {label :your_other_calc}
|
245
|
+
}
|
246
|
+
CalculationSet.find_prototype_calculation(:transport).should be_a PrototypeCalculation
|
247
|
+
CalculationSet.find_prototype_calculation(:your_calc).should be_a PrototypeCalculation
|
248
|
+
CalculationSet.find_prototype_calculation(:my_other_calc).should be_a PrototypeCalculation
|
249
|
+
end
|
250
|
+
|
251
|
+
it "returns nil where no prototype calcualtion is found" do
|
252
|
+
CalculationSet.find_prototype_calculation(:fuel).should be_nil
|
20
253
|
end
|
254
|
+
|
21
255
|
it 'can construct a calculation' do
|
22
|
-
CalculationSet.new {calculation {label :mycalc}}[:mycalc].should be_a PrototypeCalculation
|
256
|
+
CalculationSet.new('my_set') {calculation {label :mycalc}}[:mycalc].should be_a PrototypeCalculation
|
23
257
|
end
|
258
|
+
|
24
259
|
it 'can be initialized with a DSL block' do
|
25
|
-
CalculationSet.new {call_me}
|
260
|
+
CalculationSet.new('my_set') {call_me}
|
26
261
|
CalculationSet.called.should be_true
|
27
262
|
end
|
263
|
+
|
28
264
|
it 'can have terms added to all calculations' do
|
29
|
-
cs=CalculationSet.new {
|
265
|
+
cs=CalculationSet.new('my_set') {
|
30
266
|
all_calculations {
|
31
267
|
drill {label :energetic}
|
32
268
|
}
|
@@ -37,6 +273,7 @@ describe CalculationSet do
|
|
37
273
|
}
|
38
274
|
cs[:mycalc].drills.labels.should eql [:remarkably,:energetic]
|
39
275
|
end
|
276
|
+
|
40
277
|
it 'can make multiple calculations quickly, one for each usage' do
|
41
278
|
mocker=AMEEMocker.new(self,:path=>'something')
|
42
279
|
mocker.item_value_definitions.usages(['bybob','byfrank']).
|
@@ -44,7 +281,7 @@ describe CalculationSet do
|
|
44
281
|
item_value_definition('first',['bybob'],[],'byfrank',[],nil,nil,true,false,nil,"TEXT").
|
45
282
|
item_value_definition('second',['bybob'],[],'byfrank',[],nil,nil,true,false,nil,"TEXT").
|
46
283
|
item_value_definition('third',['byfrank'],[],['bybob'],[],nil,nil,true,false,nil,"TEXT")
|
47
|
-
cs=CalculationSet.new {
|
284
|
+
cs=CalculationSet.new('my_set') {
|
48
285
|
calculations_all_usages('/something') { |usage|
|
49
286
|
label usage.to_sym
|
50
287
|
profiles_from_usage usage
|
@@ -53,4 +290,5 @@ describe CalculationSet do
|
|
53
290
|
cs[:bybob].profiles.labels.should eql [:first,:second]
|
54
291
|
cs[:byfrank].profiles.labels.should eql [:third]
|
55
292
|
end
|
293
|
+
|
56
294
|
end
|