amee-data-persistence 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/.rvmrc +1 -0
- data/CHANGELOG.txt +4 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +27 -0
- data/README.txt +89 -0
- data/Rakefile +102 -0
- data/VERSION +1 -0
- data/amee-data-persistence.gemspec +93 -0
- data/amee-data-persistence.tmproj +27 -0
- data/generators/persistence/persistence_generator.rb +97 -0
- data/generators/persistence/templates/config/persistence.yml.erb +1 -0
- data/generators/persistence/templates/db/migrate/001_create_persistence_tables.rb +29 -0
- data/generators/persistence/templates/db/migrate/002_add_unit_columns.rb +15 -0
- data/generators/persistence/templates/db/migrate/003_add_value_types.rb +9 -0
- data/init.rb +1 -0
- data/lib/amee-data-persistence.rb +12 -0
- data/lib/amee/data_abstraction/calculation_collection.rb +22 -0
- data/lib/amee/data_abstraction/persistence_support.rb +274 -0
- data/lib/amee/db/calculation.rb +156 -0
- data/lib/amee/db/config.rb +54 -0
- data/lib/amee/db/term.rb +72 -0
- data/rails/init.rb +31 -0
- data/spec/amee/db/calculation_spec.rb +176 -0
- data/spec/amee/db/config_spec.rb +92 -0
- data/spec/amee/db/persistence_support_spec.rb +356 -0
- data/spec/amee/db/term_spec.rb +147 -0
- data/spec/database.yml +4 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +136 -0
- metadata +239 -0
@@ -0,0 +1 @@
|
|
1
|
+
method: <%= method %>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class CreatePersistenceTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :calculations do |t|
|
4
|
+
t.string "profile_uid"
|
5
|
+
t.string "profile_item_uid"
|
6
|
+
t.string "calculation_type"
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :terms do |t|
|
12
|
+
t.integer "calculation_id"
|
13
|
+
t.string "label"
|
14
|
+
t.string "value"
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :calculations, :calculation_type
|
20
|
+
add_index :calculations, :profile_item_uid
|
21
|
+
add_index :terms, [:calculation_id, :label], :name => "calc_id_label_index"
|
22
|
+
add_index :terms, [:label, :value, :calculation_id], :name => "label_name_calc_id_index"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.down
|
26
|
+
drop_table :calculations
|
27
|
+
drop_table :terms
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class AddUnitColumns < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
|
4
|
+
add_column :terms, :unit, :string
|
5
|
+
add_column :terms, :per_unit, :string
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
|
11
|
+
remove_column :terms, :unit, :string
|
12
|
+
remove_column :terms, :per_unit
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
|
2
|
+
# Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'activerecord', "~> 2.3.9"
|
6
|
+
require 'active_record'
|
7
|
+
require 'quantify'
|
8
|
+
|
9
|
+
require 'amee/data_abstraction/calculation_collection'
|
10
|
+
require 'amee/db/calculation'
|
11
|
+
require 'amee/db/term'
|
12
|
+
require 'amee/db/config'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
|
2
|
+
# Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
|
3
|
+
|
4
|
+
# :title: Class: AMEE::DataAbstraction::CalculationCollection
|
5
|
+
|
6
|
+
module AMEE
|
7
|
+
module DataAbstraction
|
8
|
+
|
9
|
+
# Class for containing a collection of instances of the class
|
10
|
+
# <i>OngoingCalculation</i>. This class is used to return mutliple
|
11
|
+
# ongoing calculation objects using the <i>OngoingCalculation.find</i>
|
12
|
+
# class method.
|
13
|
+
#
|
14
|
+
# This class is extended by the amee-reporting gem to provide analytical
|
15
|
+
# methods which can be applied across collections of caluclations (e.g.
|
16
|
+
# averages and summations of terms, sorting, etc.)
|
17
|
+
#
|
18
|
+
class CalculationCollection < Array
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
# Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
|
2
|
+
# Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
|
3
|
+
|
4
|
+
# :title: Module AMEE::DataAbstraction::PersistenceSupport
|
5
|
+
|
6
|
+
module AMEE
|
7
|
+
module DataAbstraction
|
8
|
+
|
9
|
+
# This module provides a number of class and instance methods which are
|
10
|
+
# added to the <i>AMEE::DataAbstraction::OngoingCalculation</i> class if
|
11
|
+
# the amee-data-persistence gem is required. These methods provide an
|
12
|
+
# interface between the <i>AMEE::DataAbstraction::OngoingCalculation</i>
|
13
|
+
# class (and its instances) and the the <i>AMEE::Db::Calculation</i> class
|
14
|
+
# which provides database persistence for calculations.
|
15
|
+
#
|
16
|
+
module PersistenceSupport
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.extend ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
# Represents the instance of <i>AMEE::Db::Calculation</i> which is
|
23
|
+
# associated with <tt>self</tt>.
|
24
|
+
#
|
25
|
+
attr_accessor :db_calculation
|
26
|
+
|
27
|
+
# Represents the primary key of the associated database record (instance of
|
28
|
+
# <i>AMEE::Db::Calculation</i>) if a database record for <tt>self</tt> is
|
29
|
+
# defined.
|
30
|
+
#
|
31
|
+
def id
|
32
|
+
db_calculation.nil? ? nil : db_calculation.id
|
33
|
+
end
|
34
|
+
|
35
|
+
# Same as <i>save</i> but raises an exception on error
|
36
|
+
def save!
|
37
|
+
validate!
|
38
|
+
record = db_calculation || get_db_calculation
|
39
|
+
record.update_calculation!(to_hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Saves a representation of <tt>self<tt> to the database. Returns
|
43
|
+
# <tt>true</tt> if successful, otherwise <tt>false</tt>.
|
44
|
+
#
|
45
|
+
def save
|
46
|
+
save!
|
47
|
+
true
|
48
|
+
rescue ActiveRecord::RecordNotSaved
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Deletes the database record for <tt>self</tt> and any associated profile
|
53
|
+
# item value in the AMEE platform.
|
54
|
+
#
|
55
|
+
def delete
|
56
|
+
record = db_calculation || get_db_calculation
|
57
|
+
AMEE::Db::Calculation.delete record.id
|
58
|
+
self.db_calculation = nil
|
59
|
+
delete_profile_item
|
60
|
+
end
|
61
|
+
|
62
|
+
# As <i>calculate_and_save</i> but raises an exception on error
|
63
|
+
def calculate_and_save!
|
64
|
+
calculate!
|
65
|
+
save!
|
66
|
+
end
|
67
|
+
|
68
|
+
# Performs the calculation against AMEE and saves it to the database
|
69
|
+
def calculate_and_save
|
70
|
+
calculate_and_save!
|
71
|
+
true
|
72
|
+
rescue ActiveRecord::RecordNotFound, AMEE::DataAbstraction::Exceptions::DidNotCreateProfileItem
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
# Finds the instance of database record associated with <tt>self</tt> based
|
77
|
+
# on the <tt>profile_item_uid</tt> attribute of <tt>self</tt> and sets the
|
78
|
+
# <tt>db_calculation</tt> attribute of <tt>self</tt> to the associated
|
79
|
+
# instance of <i>AMEE::Db::Calculation</i>.
|
80
|
+
#
|
81
|
+
def get_db_calculation
|
82
|
+
self.db_calculation = AMEE::Db::Calculation.find_or_initialize_by_profile_item_uid(send :profile_item_uid)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the subset of terms associated with <tt>self</tt> which should be
|
86
|
+
# passed for database persistence, based on the configuration set in
|
87
|
+
# <i>AMEE::Db::Config#storage_method</i>.
|
88
|
+
#
|
89
|
+
def stored_terms
|
90
|
+
stored_terms = []
|
91
|
+
stored_terms += metadata if OngoingCalculation.store_metadata?
|
92
|
+
stored_terms += inputs if OngoingCalculation.store_inputs?
|
93
|
+
stored_terms += outputs if OngoingCalculation.store_outputs?
|
94
|
+
stored_terms
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns a hash representation of <tt>self</tt>. By default, only the terms
|
98
|
+
# which are configured for persistence (according to
|
99
|
+
# <i>AMEE::Db::Config#storage_method</i>) are included. All terms can be
|
100
|
+
# explicitly required by passing the symbol <tt>:full</tt> as an argument.
|
101
|
+
# E.g.
|
102
|
+
#
|
103
|
+
# # Set storage to include everything
|
104
|
+
# AMEE::Db::Config.storage_method=:everything
|
105
|
+
#
|
106
|
+
# my_calculation.to_hash #=> { :calculation_type => :fuel,
|
107
|
+
# :profile_item_uid => nil,
|
108
|
+
# :profile_uid => "A8D8R95EE7DH",
|
109
|
+
# :type => { :value => 'coal'},
|
110
|
+
# :location => { :value => 'facility' },
|
111
|
+
# :mass => { :value => 250,
|
112
|
+
# :unit => <Quantify::Unit ... > },
|
113
|
+
# :co2 => { :value => 60.5,
|
114
|
+
# :unit => <Quantify::Unit ... > }}
|
115
|
+
#
|
116
|
+
# # Set storage to include only oputputs and metadata
|
117
|
+
# AMEE::Db::Config.storage_method=:outputs
|
118
|
+
#
|
119
|
+
# my_calculation.to_hash #=> { :calculation_type => :fuel,
|
120
|
+
# :profile_item_uid => nil,
|
121
|
+
# :profile_uid => "A8D8R95EE7DH",
|
122
|
+
# :location => { :value => 'facility' },
|
123
|
+
# :co2 => { :value => 60.5,
|
124
|
+
# :unit => <Quantify::Unit ... > }}
|
125
|
+
#
|
126
|
+
# # Set storage to include only metadata
|
127
|
+
# AMEE::Db::Config.storage_method=:metadata
|
128
|
+
#
|
129
|
+
# my_calculation.to_hash #=> { :calculation_type => :fuel,
|
130
|
+
# :profile_item_uid => nil,
|
131
|
+
# :profile_uid => "A8D8R95EE7DH",
|
132
|
+
# :location => { :value => 'facility' },
|
133
|
+
#
|
134
|
+
# # Get full hash represenation regardless of storage level
|
135
|
+
# my_calculation.to_hash :full #=> { :calculation_type => :fuel,
|
136
|
+
# :profile_item_uid => nil,
|
137
|
+
# :profile_uid => "A8D8R95EE7DH",
|
138
|
+
# :type => { :value => 'coal'},
|
139
|
+
# :location => { :value => 'facility' },
|
140
|
+
# :mass => { :value => 250,
|
141
|
+
# :unit => <Quantify::Unit ... > },
|
142
|
+
# :co2 => { :value => 60.5,
|
143
|
+
# :unit => <Quantify::Unit ... > }}
|
144
|
+
#
|
145
|
+
def to_hash(representation=:stored_terms_only)
|
146
|
+
hash = {}
|
147
|
+
hash[:calculation_type] = label
|
148
|
+
hash[:profile_item_uid] = send :profile_item_uid
|
149
|
+
hash[:profile_uid] = send :profile_uid
|
150
|
+
(representation == :full ? terms : stored_terms ).each do |term|
|
151
|
+
sub_hash = {}
|
152
|
+
sub_hash[:value] = term.value
|
153
|
+
sub_hash[:unit] = term.unit if term.unit
|
154
|
+
sub_hash[:per_unit] = term.per_unit if term.per_unit
|
155
|
+
hash[term.label.to_sym] = sub_hash
|
156
|
+
end
|
157
|
+
return hash
|
158
|
+
end
|
159
|
+
|
160
|
+
module ClassMethods
|
161
|
+
|
162
|
+
|
163
|
+
# Find and initialize instance(s) of <i>OngoingCalculation</i> from the
|
164
|
+
# database using standard <i>ActiveRecord</i> <tt>find</tt> options.
|
165
|
+
# Returns <tt>nil</tt> if no records are found. If multiple records are
|
166
|
+
# found they are returned via an instance of the
|
167
|
+
# <i>CalculationCollection</i> class. E.g.,
|
168
|
+
#
|
169
|
+
# OngoingCalculation.find(:first)
|
170
|
+
#
|
171
|
+
# #=> <AMEE::DataAbstraction::OngoingCalculation ... >
|
172
|
+
#
|
173
|
+
# OngoingCalculation.find(:first,
|
174
|
+
# :conditions => {:profile_item_uid => "K588DH47SMN5"})
|
175
|
+
#
|
176
|
+
# #=> <AMEE::DataAbstraction::OngoingCalculation ... >
|
177
|
+
#
|
178
|
+
# OngoingCalculation.find(:all)
|
179
|
+
#
|
180
|
+
# #=> <AMEE::DataAbstraction::CalculationCollection ... >
|
181
|
+
#
|
182
|
+
def find(*args)
|
183
|
+
unless args.last.is_a? Symbol or args.last.is_a? Integer
|
184
|
+
raise ActiveRecord::ActiveRecordError.new("Using :include with terms and then conditioning on terms doesn't work due to rails caching. Use the :joins option instead.") if args.last[:include].to_s.match(/terms/) && args.last[:conditions].to_s.match(/terms/)
|
185
|
+
args.last[:include] = "terms" if args.last[:joins].to_s.match(/terms/)
|
186
|
+
end
|
187
|
+
result = AMEE::Db::Calculation.find(*args)
|
188
|
+
return nil unless result
|
189
|
+
if result.respond_to?(:map)
|
190
|
+
CalculationCollection.new(result.compact.map { |calc| initialize_from_db_record(calc) })
|
191
|
+
else
|
192
|
+
initialize_from_db_record(result)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Find calculations of type <tt>type</tt> in the database and initialize
|
197
|
+
# as instances of <i>OngoingCalculation</i>. Returns <tt>nil</tt> if no
|
198
|
+
# records are found. If multiple records are found they are returned via
|
199
|
+
# an instance of the <i>CalculationCollection</i> class.
|
200
|
+
#
|
201
|
+
# Specify that either the first or all records should be returns by passing
|
202
|
+
# <tt>:first</tt> or <tt>:all</tt> as the first argument. The unique label
|
203
|
+
# of the calcualtion type required should be passed as the second argument.
|
204
|
+
# Standard options associated with the <i>ActiveRecord</i> <tt>find</tt>
|
205
|
+
# class method can be passed as the third argument. E.g.,
|
206
|
+
#
|
207
|
+
# OngoingCalculation.find_by_type(:first,:electricity)
|
208
|
+
#
|
209
|
+
# #=> <AMEE::DataAbstraction::OngoingCalculation ... >
|
210
|
+
#
|
211
|
+
# OngoingCalculation.find_by_type(:all,:fuel)
|
212
|
+
#
|
213
|
+
# #=> <AMEE::DataAbstraction::CalculationCollection ... >
|
214
|
+
#
|
215
|
+
def find_by_type(ordinality,type,options={})
|
216
|
+
OngoingCalculation.find(ordinality, options.merge(:conditions => {:calculation_type => type.to_s}))
|
217
|
+
end
|
218
|
+
|
219
|
+
# Initialize and return an instance of <i>OngoingCalculation</i> based
|
220
|
+
# on the database record represented by <tt>record</tt>.
|
221
|
+
#
|
222
|
+
def initialize_from_db_record(record)
|
223
|
+
unless record.is_a? AMEE::Db::Calculation
|
224
|
+
raise ArgumentError.new("Argument is not of class AMEE::Db::Calculation")
|
225
|
+
end
|
226
|
+
calc = Calculations.calculations[record.type].begin_calculation
|
227
|
+
calc.db_calculation = record
|
228
|
+
# Means that validation needs to occur before calcs are saved
|
229
|
+
calc.choose_without_validation!(record.to_hash)
|
230
|
+
return calc
|
231
|
+
end
|
232
|
+
|
233
|
+
# Returns a new instance of the <i>AMEE::Db::BaseConfig</i> class
|
234
|
+
def storage_config
|
235
|
+
AMEE::Db::BaseConfig.new
|
236
|
+
end
|
237
|
+
|
238
|
+
# Returns the currently configured storage level for database persistence,
|
239
|
+
# i.e. whether all terms should be persisted versus outputs and/or
|
240
|
+
# metadata only.
|
241
|
+
#
|
242
|
+
def storage_method
|
243
|
+
storage_config.storage_method
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns <tt>true</tt> if all terms should be persisted within the
|
247
|
+
# database according to the currently configured storage level (See
|
248
|
+
# <i>AMEE::Db::BaseConfig</i>). Otherwise, returns <tt>false</tt>.
|
249
|
+
#
|
250
|
+
def store_inputs?
|
251
|
+
storage_config.store_everything?
|
252
|
+
end
|
253
|
+
|
254
|
+
# Returns <tt>true</tt> if output terms should be persisted within the
|
255
|
+
# database according to the currently configured storage level (See
|
256
|
+
# <i>AMEE::Db::BaseConfig</i>). Otherwise, returns <tt>false</tt>.
|
257
|
+
#
|
258
|
+
def store_outputs?
|
259
|
+
storage_config.store_outputs?
|
260
|
+
end
|
261
|
+
|
262
|
+
# Returns <tt>true</tt> if metadata terms should be persisted within the
|
263
|
+
# database according to the currently configured storage level (See
|
264
|
+
# <i>AMEE::Db::BaseConfig</i>). Otherwise, returns <tt>false</tt>.
|
265
|
+
#
|
266
|
+
def store_metadata?
|
267
|
+
storage_config.store_metadata?
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com
|
2
|
+
# Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details.
|
3
|
+
|
4
|
+
# :title: Class: AMEE::Db::Calculation
|
5
|
+
|
6
|
+
module AMEE
|
7
|
+
module Db
|
8
|
+
|
9
|
+
# This class represents a database record for a calculation performed using
|
10
|
+
# the <i>AMEE:DataAbstraction::OngoingCalculation</i> class. This class stores
|
11
|
+
# the primary calculation level attributes such as the calculation
|
12
|
+
# <tt>calculation_type</tt>, <tt>profile_uid</tt> and <tt>profile_item_uid</tt>.
|
13
|
+
#
|
14
|
+
# The values and attributes of specific calculation terms are stored via the
|
15
|
+
# related class <i>AMEE::Db::Term</i>.
|
16
|
+
#
|
17
|
+
# This class is typically used by proxy, via the <tt>find</tt>,
|
18
|
+
# <tt>find_by_type</tt>, <tt>#save</tt>, <tt>#delete</tt>, and
|
19
|
+
# <tt>#get_db_calculation</tt> methods associated with the
|
20
|
+
# <i>AMEE:DataAbstraction::OngoingCalculation</i> class.
|
21
|
+
#
|
22
|
+
class Calculation < ActiveRecord::Base
|
23
|
+
|
24
|
+
has_many :terms, :class_name => "AMEE::Db::Term", :dependent => :destroy
|
25
|
+
validates_presence_of :calculation_type
|
26
|
+
validates_format_of :profile_item_uid, :with => /\A([A-Z0-9]{12})\z/, :allow_nil => true, :allow_blank => true
|
27
|
+
validates_format_of :profile_uid, :with => /\A([A-Z0-9]{12})\z/, :allow_nil => true, :allow_blank => true
|
28
|
+
before_save :validate_calculation_type
|
29
|
+
|
30
|
+
# Standardize the <tt>calculation_type</tt> attribute to <i>String</i>
|
31
|
+
# format. Called using before filter prior to record saving to ensure
|
32
|
+
# string serialization.
|
33
|
+
#
|
34
|
+
def validate_calculation_type
|
35
|
+
self.calculation_type = calculation_type.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convenience method for returning the <tt>calculation_type</tt> attribute
|
39
|
+
# of <tt>self</tt> in canonical symbol form.
|
40
|
+
#
|
41
|
+
def type
|
42
|
+
calculation_type.to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the subset of all instance attributes which should be editable via
|
46
|
+
# mass update methods and which should be included in hash representations of
|
47
|
+
# self, i.e. those passed in explcitly as data rather than added by
|
48
|
+
# <i>ActiveRecord</i> (e.g. <tt>id</tt>, <tt>created_at</tt>, etc.).
|
49
|
+
#
|
50
|
+
def primary_calculation_attributes
|
51
|
+
attributes.keys.reject {|attr| ['id','created_at','updated_at'].include? attr }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Update the attributes of <tt>self</tt> and those of any related terms,
|
55
|
+
# according to the passed <tt>options</tt> hash. Any associated terms which
|
56
|
+
# are not represented in <tt>options</tt> are deleted.
|
57
|
+
#
|
58
|
+
# Term attributes provided in <tt>options</tt> should be keyed with the
|
59
|
+
# term label and include a sub-hash with keys represent one or more of
|
60
|
+
# :value, :unit and :per_unit. E.g.,
|
61
|
+
#
|
62
|
+
# options = { :profile_item_uid => "W93UEY573U4E8",
|
63
|
+
# :mass => { :value => 23 },
|
64
|
+
# :distance => { :value => 1400,
|
65
|
+
# :unit => <Quantify::Unit::SI ... > }}
|
66
|
+
#
|
67
|
+
# my_calculation.update_calculation!(options)
|
68
|
+
#
|
69
|
+
def update_calculation!(options)
|
70
|
+
primary_calculation_attributes.each do |attr|
|
71
|
+
if options.keys.include? attr.to_sym
|
72
|
+
update_calculation_attribute!(attr,options.delete(attr.to_sym),false)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
save!
|
76
|
+
options.each_pair do |attribute,value|
|
77
|
+
add_or_update_term!(attribute,value)
|
78
|
+
end
|
79
|
+
delete_unspecified_terms(options)
|
80
|
+
reload
|
81
|
+
end
|
82
|
+
|
83
|
+
# Update the attribute of <tt>self</tt> represented by the label
|
84
|
+
# <tt>key</tt> with the value of <tt>value</tt>. By default,
|
85
|
+
# the <tt>#save!</tt> method is called, in turn calling the class
|
86
|
+
# validations.
|
87
|
+
#
|
88
|
+
# Specify that the record should not be saved by passing <tt>false</tt>
|
89
|
+
# as the final argument.
|
90
|
+
#
|
91
|
+
def update_calculation_attribute!(key,value,save=true)
|
92
|
+
# use attr_accessor (via #send) method rather than
|
93
|
+
# #update_attribute so that validations are performed
|
94
|
+
#
|
95
|
+
send("#{key}=", (value.nil? ? nil : value.to_s))
|
96
|
+
save! if save
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add, or update an existing, associated term represented by the label
|
100
|
+
# <tt>label</tt> and value, unit and/or per_unit attributes defined by
|
101
|
+
# <tt>data</tt>. The <tt>data</tt> argument should be a hash with keys
|
102
|
+
# represent one or more of :value, :unit and :per_unit. E.g.,
|
103
|
+
#
|
104
|
+
# data = { :value => 1400,
|
105
|
+
# :unit => <Quantify::Unit::SI ... > }
|
106
|
+
#
|
107
|
+
# my_calculation.add_or_update_term!(:distance, data)
|
108
|
+
#
|
109
|
+
# This method is called as part of the <tt>#update_calculation!</tt>
|
110
|
+
# method
|
111
|
+
#
|
112
|
+
def add_or_update_term!(label,data)
|
113
|
+
term = Term.find_or_initialize_by_calculation_id_and_label(id,label.to_s)
|
114
|
+
term.update_attributes!(data)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Delete all of the terms which are not explicitly referenced in the
|
118
|
+
# <tt>options</tt> hash.
|
119
|
+
#
|
120
|
+
# This method is called as part of the <tt>#update_calculation!</tt>
|
121
|
+
# method
|
122
|
+
#
|
123
|
+
def delete_unspecified_terms(options)
|
124
|
+
terms.each do |term|
|
125
|
+
Term.delete(term.id) unless options.keys.include? term.label.to_sym
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns a <i>Hash</i> representation of <tt>self</tt> including a only
|
130
|
+
# the data explicitly passed in (those added by <i>ActiveRecord</i> -
|
131
|
+
# <tt>created</tt>, <tt>updated</tt>, <tt>id</tt> - are ignored) as well
|
132
|
+
# as sub-hashes for all associated terms. E.g.,
|
133
|
+
#
|
134
|
+
# my_calculation.to_hash #=> { :profile_uid => "EYR758EY36WY",
|
135
|
+
# :profile_item_uid => "W83URT48DY3W",
|
136
|
+
# :type => { :value => 'car' },
|
137
|
+
# :distance => { :value => 1600,
|
138
|
+
# :unit => <Quantify::Unit::SI> },
|
139
|
+
# :co2 => { :value => 234.1,
|
140
|
+
# :unit => <Quantify::Unit::NonSI> }}
|
141
|
+
#
|
142
|
+
# This method can be used to initialize instances of the class
|
143
|
+
# <tt>OngoingCalculation</tt> by providing the hashed options for any of
|
144
|
+
# the <tt>choose...</tt> methods.
|
145
|
+
#
|
146
|
+
def to_hash
|
147
|
+
hash = {}
|
148
|
+
terms.each { |term| hash.merge!(term.to_hash) }
|
149
|
+
[ :profile_item_uid, :profile_uid ].each do |attr|
|
150
|
+
hash[attr] = self.send(attr)
|
151
|
+
end
|
152
|
+
return hash
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|