In my app, I can calculate Result
s for a measurement. The result model uses Single Table Inheritance to define different result types, each of which implements a calculate
method. Now, I need to calculate some results before others. Example:
class Result < ActiveRecord::Base
belongs_to :measurement
def calculate
raise "#calculate is abstract. Implement this method in one of the subclasses."
end
def self.depends_on(args)
# what to do here?
end
end
One subclass could look like:
# The total duration in milliseconds
class TotalDuration < Result
depends_on :EventList # calculate the EventList result first
def calculate
# how do I find out what I depend on?
# only then do the actual calculation
end
end
As you can see, I've already included a depends_on
class method, with which I'd like to express that the TotalDuration
result needs the EventList
result calculated before.
But how do I access the information at runtime, eg when I'm inside calculate
? There for example I could calculate the dependency first, then continue.
I would assume that using class level attributes (eg, @@depends_on
) are not considered good style?
I would create a join model which allows any particular instance of Result
to have_many
dependent results.
Then in your calculate method for a result with dependencies you first ask for the calculations from the dependent results before continuing with your own calculation.
Through natural recursion, if any of those dependent results had further dependencies ... this would naturally filter up the chain.
I solved it like this:
def self.depends_on(*args)
define_method("calculate_dependencies") do
args.each do |arg|
measurement.results.where(type: arg.to_s).each { |result| result.calculate unless result.value }
end
end
end
This way, I only have to call
def calculate
calculate_dependencies
# other stuff
end
in my child models. I could even go as far as defining a new method with the name of the dependent result:
define_method("#{arg.to_s.underscore}") do
results = measurement.results.where(type: arg.to_s).limit(1)
result = results.first if results.any?
result.calculate if result.value.nil?
result
end
That way, I could do:
depends_on :EventList
def calculate
# no need for calculate_dependencies
event_list # <= this is the result I depend on, already calculated
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.