# Copyright (C) 2011 AMEE UK Ltd. - http://www.amee.com # Released as Open Source Software under the BSD 3-Clause license. See LICENSE.txt for details. # :title: Class: AMEE::DataAbstraction::Calculation module AMEE module DataAbstraction # Base class providing attributes and methods for representing a calculation # which can be made using the AMEE platform. An instance of Calculation # will typically be associated with a specific AMEE category. # # Instances of Calculation are represented by several primary attributes: # # label:: Symbol representing the unique, machine-readable name for the # calculation # # name:: String representing a human-readable name for the calculation # # path:: String representing the AMEE platform path to the data category # which is associated with self # # fixed_usage:: String representing the AMEE platform path for the usage to # be used by self, if defined # # An instance of Calculation also holds an arbitrary number of objects # of the class Term. These represent values associated with the # calculation, e.g. inputs, outputs, metadatum, etc. These can be accessed # using the #terms methods or the term subset methods provided by # the TermsList class (e.g. #profiles, #visible) # # Two classes inherit the Calculation class: # * PrototypeCalculation : provides a templating for a specific calculation # type with defined, but blank, terms (i.e. inputs, outputs, etc.) # # * OngoingCalculation : represents a particular calculation - possibly # incomplete - which can be updated, submitted for calculation, and saved # class Calculation public # Symbol representing the unique, machine-readable name for self. # Set a value by passing an argument. Retrieve a value by calling without # an argument, e.g., # # my_calculation.label :fuel # # my_calculation.label #=> :fuel # attr_property :label # String representing a human-readable name for self. Set a # value by passing an argument. Retrieve a value by calling without an # argument, e.g., # # my_calculation.name 'Domestic fuel consumption' # # my_calculation.name #=> 'Domestic fuel consumption' # attr_property :name # String representing the AMEE platform path to the data category which is # associated with self. Set a value by passing an argument. Retrieve # a value by calling without an argument, e.g., # # my_calculation.path '/some/path/in/amee/' # # my_calculation.path #=> '/some/path/in/amee/' # attr_property :path # String representing the AMEE platform path for the usage to be used by # self, if defined. Set a value by passing an argument. Retrieve # a value by calling without an argument, e.g., # # my_calculation.fixed_usage 'byMass' # # my_calculation.fixed_usage #=> 'byMass' # attr_property :fixed_usage # Calculations contain a list of "terms" of the base class Term, # representing inputs, outputs, metadatum, etc. which are associated with # self. # # Returns all associated terms as an instance of the TermsList class # def terms TermsList.new(@contents.values) end # Retrieve the terms associated with self as a hash from labels to terms. attr_accessor :contents # Shorthand method for retrieving the term assocaited with self which has a # label matching sym # def [](sym) @contents[sym.to_sym] end # Syntactic sugar to enable the return of a subset of associated terms according # to their type or status (e.g. drills, profiles, set, unset, visible). See # TermsList::Selectors for valid variants # TermsList::Selectors.each do |sel| delegate sel,:to=>:terms end # Prettyprint a string representation of self, together with associated terms def inspect elements = {:label => label.inspect, :terms => terms.map{|t| "<#{t.class.name.demodulize} label:#{t.label}, value:#{t.value.inspect}>"}} attr_list = elements.map {|k,v| "#{k}: #{v}" } * ', ' "<#{self.class.name} #{attr_list}>" end def initialize_copy(source) super @contents=ActiveSupport::OrderedHash.new source.contents.each do |k,v| @contents[k]=v.clone @contents[k].parent=self end end # Return a string representing the AMEE Explorer URL which is assocaited # with self # def discover_url "http://discover.amee.com/categories#{path}" end def explorer_url ::Rails.logger.info "#explorer_url method deprecated. Use #discover_url" if defined? Rails discover_url end protected def initialize @contents=ActiveSupport::OrderedHash.new end # Methods which will be memoized at application start, as they do not # change over application instance lifetime # AmeeMemoised=[:amee_data_category, :amee_item_definition, :amee_ivds, :amee_return_values, :amee_usages] # Return all the values of the memoized quantities def saved_amee AmeeMemoised.map{|x|instance_variable_get("@#{x.to_s}")} end # Save the memoized quantities def save_amee(values) AmeeMemoised.zip(values).each do |prop,val| instance_variable_set("@#{prop.to_s}",val) end end private # Return the global AMEE::Connection object. This is configured in # /config/amee.yml # def connection AMEE::DataAbstraction.connection end # Return the AMEE::Data::Category object associated with self def amee_data_category @amee_data_category||=AMEE::Data::Category.get(connection, "/data#{path}") end # Return the AMEE::Admin::ItemDefinition object associated with self def amee_item_definition @amee_item_definition||=amee_data_category.item_definition end # Return the AMEE::Admin::ReturnValueDefinitionList object associated # with self. This represents each of the return value definitions which are # associated with the calculation # def amee_return_values @amee_return_values||=AMEE::Admin::ReturnValueDefinitionList.new(connection,amee_item_definition.uid) end # Return the instance of Term class associated with self and contains # a path attribute matching path, e.g. # # my_calculation.by_path('distance') #=> # # my_calculation.by_path('type') #=> # def by_path(path) terms.detect { |v| v.path==path } end # Return the instance of Drill class associated with self and contains # a path attribute matching path, e.g. # # my_calculation.by_path('type') #=> # def drill_by_path(path) drills.detect { |v| v.path==path } end public # Return the AMEE::Admin::ItemValueDefinitionList object associated # with self. This represents each of the item value definitions which are # associated with the calculation # def amee_ivds @amee_ivds||=amee_item_definition.item_value_definition_list.select{|x|x.versions.include?("2.0")} end # Returns a String representing the AMEE platform path for the usage currently # used by self. If not usage is defined, returns nil # # my_calculation.current_usage #=> 'byMass' # def current_usage usages.empty? ? fixed_usage : usages.first.value end # Returns an Array containing the AMEE platform paths for all valid usage # available to self according to those defined under #item_definition. If # no usage(s) is defined, returns nil, e.g. # # my_calculation.amee_usages #=> [ 'byMass', 'byEnergy' ] # def amee_usages @amee_usages||=amee_item_definition.usages end end end end