Module: AMEE::Analytics::TermsListAnalyticsSupport
- Defined in:
- lib/amee/analytics/terms_list_analytics_support.rb
Overview
Mixin module for the AMEE::DataAbstraction::Term class, providing methods for handling collections of calculations.
Instance Method Summary collapse
- #+(other_list) ⇒ Object
- #-(other_list) ⇒ Object
-
#all_numeric? ⇒ Boolean
Returns
true
if all terms in the list have numeric values. -
#analogous? ⇒ Boolean
Returns
true
if all terms within the list have the same label. - #first_of_each_type ⇒ Object
-
#heterogeneous? ⇒ Boolean
Returns
true
if TermsList is NOT homogeneous, i.e. -
#homogeneous? ⇒ Boolean
Returns
true
if all terms within the list have the same label AND contain consistent units. -
#homogeneous_per_units? ⇒ Boolean
Returns
true
if all terms within the list are represented by the same PER unit or are allnil
. -
#homogeneous_units? ⇒ Boolean
Returns
true
if all terms within the list are represented by the same unit or are allnil
. -
#initialize_result(label, value, unit = nil, per_unit = nil) ⇒ Object
Convenience method for initializing instances of the Result class.
-
#label ⇒ Object
Returns the label which defines all terms in contained within
self
, if they are all the same. -
#mean(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of Result which represents the mean of all term values within the list.
-
#median ⇒ Object
Returns a representation of the term with median value in
self
. -
#method_missing(method, *args, &block) ⇒ Object
Syntactic sugar for several instance methods.
-
#mode ⇒ Object
Returns a representation of the term with most prevalent value in
self
, i.e. -
#move_by(attr, value, index) ⇒ Object
Move an individual term to a specified location (index) within the list.
- #name ⇒ Object
-
#numeric_terms ⇒ Object
Returns a new instance of TermsList comprising only those terms belongong to
self
which have numeric values. -
#predominant_per_unit ⇒ Object
Returns the label of the per unit which is predominantly used across all terms in the list, e.g.
-
#predominant_unit ⇒ Object
Returns the label of the unit which is predominantly used across all terms in the list, e.g.
- #respond_to?(method) ⇒ Boolean
-
#rotate ⇒ Object
Rotate the list terms by one element - shifts the first-placed term to the end of the list, advancing all terms forward by one place.
-
#sort_by(attr) ⇒ Object
Similar to
#sort_by!
but returns a new instance of TermsList arranged according to the values on the attributeattr
. -
#sort_by!(attr) ⇒ Object
Sorts the terms list in place according to the term attribute indicated by
attr
, returningself
. -
#standardize_units(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of TermsList with all units standardized and the respective term values adjusted accordingly.
-
#sum(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of Result which represents the sum of all term values within the list.
-
#type ⇒ Object
Return an instance of TermsList containing only terms labelled :type.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
Syntactic sugar for several instance methods.
Call a method on self
which named after a specific term label contained within self
and return a new instance of the TermsList
class containing each of those terms. E.g.,
my_terms = my_terms_list.type #=> <AMEE::DataAbstraction::TermsList>
my_terms.label #=> :type
my_terms = my_terms_list.mass #=> <AMEE::DataAbstraction::TermsList>
my_terms.label #=> :mass
my_terms = my_terms_list.co2 #=> <AMEE::DataAbstraction::TermsList>
my_terms.label #=> :co2
Call either the #sort_by
or #sort_by!
methods including the argument term as part of the method name, e.g.,
my_calculation_collection.sort_by_value
#=> <AMEE::DataAbstraction::TermsList ... >
my_calculation_collection.sort_by_name!
#=> <AMEE::DataAbstraction::TermsList ... >
376 377 378 379 380 381 382 383 384 385 386 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 376 def method_missing(method, *args, &block) if labels.include? method AMEE::DataAbstraction::TermsList.new select{ |x| x.label == method } elsif method.to_s =~ /sort_by_(.*)!/ and self.class::TermProperties.include? $1.to_sym sort_by! $1.to_sym elsif method.to_s =~ /sort_by_(.*)/ and self.class::TermProperties.include? $1.to_sym sort_by $1.to_sym else super end end |
Instance Method Details
#+(other_list) ⇒ Object
75 76 77 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 75 def +(other_list) self.class.new(self.to_a + other_list.to_a) end |
#-(other_list) ⇒ Object
79 80 81 82 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 79 def -(other_list) other_list = [other_list].flatten self.delete_if { |term| other_list.include?(term) } end |
#all_numeric? ⇒ Boolean
Returns true
if all terms in the list have numeric values. Otherwise, returns false
.
125 126 127 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 125 def all_numeric? all? { |term| term.has_numeric_value? } end |
#analogous? ⇒ Boolean
Returns true
if all terms within the list have the same label. Otherwise, returns false
.
This enables a check as to whether all terms represent the same thing, i.e. same calculation component (i.e. the same drill choice, or profile item value, or return value, or metadata type).
26 27 28 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 26 def analogous? labels.uniq.size == (1 or nil) end |
#first_of_each_type ⇒ Object
84 85 86 87 88 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 84 def first_of_each_type labels = self.labels.uniq terms = labels.map {|label| find { |term| term.label == label } } AMEE::DataAbstraction::TermsList.new(terms) end |
#heterogeneous? ⇒ Boolean
Returns true
if TermsList is NOT homogeneous, i.e. it does NOT contain all analogous terms with corresponding units. Otherwise, returns false
.
44 45 46 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 44 def heterogeneous? !homogeneous? end |
#homogeneous? ⇒ Boolean
Returns true
if all terms within the list have the same label AND contain consistent units. Otherwise, returns false
.
This enables a term list to be manipulated numerically, for example, by producing a sum or a mean across all terms.
36 37 38 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 36 def homogeneous? analogous? and homogeneous_units? and homogeneous_per_units? end |
#homogeneous_per_units? ⇒ Boolean
Returns true
if all terms within the list are represented by the same PER unit or are all nil
. Otherwise, returns false
.
61 62 63 64 65 66 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 61 def homogeneous_per_units? return true if all? { |term| term.per_unit.nil? } or ( all? { |term| term.per_unit.is_a? Quantity::Unit::Base } and map { |term| term.per_unit.label }.uniq.size == 1 ) return false end |
#homogeneous_units? ⇒ Boolean
Returns true
if all terms within the list are represented by the same unit or are all nil
. Otherwise, returns false
.
51 52 53 54 55 56 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 51 def homogeneous_units? return true if all? { |term| term.unit.nil? } or ( all? { |term| term.unit.is_a? Quantity::Unit::Base } and map { |term| term.unit.label }.uniq.size == 1 ) return false end |
#initialize_result(label, value, unit = nil, per_unit = nil) ⇒ Object
Convenience method for initializing instances of the Result class. Intialize the new object with the attributes described by label
, value
, unit
and per_unit
. The unit and per_unit attributes default to nil
if left unspecified.
249 250 251 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 249 def initialize_result(label,value,unit=nil,per_unit=nil) Result.new { label label; value value; unit unit; per_unit per_unit } end |
#label ⇒ Object
Returns the label which defines all terms in contained within self
, if they are all the same. Otherwise, returns nil
.
71 72 73 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 71 def label first.label if analogous? end |
#mean(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of Result which represents the mean of all term values within the list.
Any terms within self which contain non-numeric values are ignored.
If the terms within self
do not contain consistent units, they are standardized by default to the unit (and per unit) which predominate in the list. Alternatively, the required unit and per units can be specified as arguments using the same conventions as the #standardize_units
method.
197 198 199 200 201 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 197 def mean(unit=nil,per_unit=nil) list = numeric_terms sum = list.sum(unit,per_unit) Result.new { label sum.label; value (sum.value/list.size); unit sum.unit; per_unit sum.per_unit; name sum.name } end |
#median ⇒ Object
Returns a representation of the term with median value in self
. This method considers both numerical and text values.
If self
has an even-numbered size, the median is caluclated as the mean of the values of the two centrally placed terms (having been sorted according to their value attributes).
231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 231 def median new_list = standardize_units midpoint = new_list.size/2 if new_list.size % 2.0 == 1 median_term = new_list.sort_by_value[midpoint] elsif new_list.size % 2.0 == 0 median_term = new_list.sort_by_value[midpoint-1, 2].mean else raise end median_term.to_result end |
#mode ⇒ Object
Returns a representation of the term with most prevalent value in self
, i.e. the modal value. This method considers both numerical and text values.
If only a single modal value is discovered an instance of the class Result is returning representing the modal value. Where multiple modal values occur a new instance of TermsList is returned containing Result representations of each modal value.
212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 212 def mode groups = standardize_units.reject { |term| term.value.nil? }. group_by { |term| term.value }.map(&:last) max_group_size = groups.max {|a,b| a.size <=> b.size }.size max_groups = groups.select {|a| a.size == max_group_size} if max_groups.size == 1 max_groups.first.first.to_result else AMEE::DataAbstraction::TermsList.new max_groups.map { |group| group.first.to_result } end end |
#move_by(attr, value, index) ⇒ Object
Move an individual term to a specified location (index) within the list. The specific term is selected on the basis of one of it’s attributes values, with the attribute to use (e.g. :value, :unit) given by attr</attr> and value by <tt>value
. The location within the list to move the term is given as an index integer value as the final argument.
259 260 261 262 263 264 265 266 267 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 259 def move_by(attr,value,index) if attr == :unit || attr == :per_unit value = Unit.for value end term = find {|t| t.send(attr) == value } return if term.nil? delete(term) insert(index, term) end |
#name ⇒ Object
15 16 17 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 15 def name first.name if analogous? end |
#numeric_terms ⇒ Object
Returns a new instance of TermsList comprising only those terms belongong to self
which have numeric values.
This is useful for establishing which terms in a list to perform numerical operations on
135 136 137 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 135 def numeric_terms AMEE::DataAbstraction::TermsList.new select { |term| term.has_numeric_value? } end |
#predominant_per_unit ⇒ Object
Returns the label of the per unit which is predominantly used across all terms in the list, e.g.
list.predominant_per_unit #=> h
list.predominant_per_unit #=> kWh
Returns nil if all per units are blank
115 116 117 118 119 120 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 115 def predominant_per_unit terms = reject { |term| term.per_unit.nil? } unit = terms.group_by { |term| term.per_unit.label }. max {|a,b| a.last.size <=> b.last.size }.first unless terms.blank? return unit end |
#predominant_unit ⇒ Object
Returns the label of the unit which is predominantly used across all terms in the list, e.g.
list.predominant_unit #=> kg
list.predominant_unit #=> kWh
Returns nil if all units are blank
99 100 101 102 103 104 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 99 def predominant_unit terms = reject { |term| term.unit.nil? } unit = terms.group_by { |term| term.unit.label }. max {|a,b| a.last.size <=> b.last.size }.first unless terms.blank? return unit end |
#respond_to?(method) ⇒ Boolean
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 334 def respond_to?(method) if labels.include? method.to_sym return true elsif method.to_s =~ /sort_by_(.*)!/ and self.class::TermProperties.include? $1.to_sym return true elsif method.to_s =~ /sort_by_(.*)/ and self.class::TermProperties.include? $1.to_sym return true else super end end |
#rotate ⇒ Object
Rotate the list terms by one element - shifts the first-placed term to the end of the list, advancing all terms forward by one place.
271 272 273 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 271 def rotate push(self.shift) end |
#sort_by(attr) ⇒ Object
Similar to #sort_by!
but returns a new instance of TermsList arranged according to the values on the attribute attr
.
If differences in units exist between terms, sorting occur based on the absolute quantities implied.
E.g.
my_terms_list.sort_by :value
#=> <AMEE::DataAbstraction::TermsList ... >
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 303 def sort_by(attr) # 1. Remove unset terms before sort and append at end # # 2. Establish set terms # # 3. Zip together with corresponding standardized units list creating a # list of Term pairs # # 4. Sort list according to standardized Terms # # 5. Return map of original (now sorted) Terms unset_terms, set_terms = self.partition { |term| term.unset? || term.value.nil? } standardized_set_terms = AMEE::DataAbstraction::TermsList.new(set_terms).standardize_units ordered_set_terms = set_terms.zip(standardized_set_terms).sort! do |term,other_term| term[1].send(attr) <=> other_term[1].send(attr) end.map {|term_array| term_array[0]} AMEE::DataAbstraction::TermsList.new(ordered_set_terms + unset_terms) end |
#sort_by!(attr) ⇒ Object
Sorts the terms list in place according to the term attribute indicated by attr
, returning self
.
If differences in units exist between terms, sorting occur based on the absolute quantities implied.
my_terms_list.sort_by! :value
#=> <AMEE::DataAbstraction::TermsList ... >
285 286 287 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 285 def sort_by!(attr) replace(sort_by(attr)) end |
#standardize_units(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of TermsList with all units standardized and the respective term values adjusted accordingly.
The unit and per units to be standardized to can be specified as the first and second arguments respectively. Either the unit name, symbol or label (as defined in the Quantify gem) can be used. If no arguments are specified, the standardized units represent those which are predominant in the list, e.g.
list.standardize_units #=> <TermsList>
list.standardize_units(:t,:kWh) #=> <TermsList>
list.standardize_units('pound') #=> <TermsList>
list.standardize_units(nil, 'BTU') #=> <TermsList>
156 157 158 159 160 161 162 163 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 156 def standardize_units(unit=nil,per_unit=nil) return self if homogeneous? && ((unit.nil? or (first.unit && first.unit.label == unit)) && (per_unit.nil? || (first.per_unit && first.per_unit.label == per_unit))) unit = predominant_unit if unit.nil? per_unit = predominant_per_unit if per_unit.nil? new_terms = map { |term| term.convert_unit(:unit => unit, :per_unit => per_unit) } AMEE::DataAbstraction::TermsList.new new_terms end |
#sum(unit = nil, per_unit = nil) ⇒ Object
Returns a new instance of Result which represents the sum of all term values within the list.
Any terms within self which contain non-numeric values are ignored.
If the terms within self
do not contain consistent units, they are standardized by default to the unit (and per unit) which predominate in the list. Alternatively, the required unit and per units can be specified as arguments using the same conventions as the #standardize_units
method.
176 177 178 179 180 181 182 183 184 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 176 def sum(unit=nil,per_unit=nil) unit = predominant_unit if unit.nil? per_unit = predominant_per_unit if per_unit.nil? value = numeric_terms.standardize_units(unit,per_unit).inject(0.0) do |sum,term| sum + term.value end template = self Result.new { label template.label; value value; unit unit; per_unit per_unit; name template.name } end |
#type ⇒ Object
Return an instance of TermsList containing only terms labelled :type.
This method overrides the standard #type method (which is deprecated) and mimics the functionality provied by the first #method_missing method in dynamically retrieving a subset of terms according their labels.
330 331 332 |
# File 'lib/amee/analytics/terms_list_analytics_support.rb', line 330 def type AMEE::DataAbstraction::TermsList.new select{ |x| x.label == :type } end |