amee-data-persistence 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|