Class: AMEE::DataAbstraction::Term

Inherits:
Object
  • Object
show all
Defined in:
lib/amee-data-abstraction/term.rb

Overview

Base class for representing quantities which are inputs to, outputs of, or metadata associated with, calculations. Typically several instances of the Term class (or subclasses) will be associated with instances of the Calculation class or its subclasses (PrototypeCalculation, OngoingCalculation).

Instances of Term are represented by several primary attributes:

label::       Symbol representing the unique, machine-readable name for the
              term (<b>required</b>)

value::       In principle, any object which represent the desired value
              which the term represents

name::        String representing a human-readable name for the term

path::        String representing the AMEE platform path to the AMEE item
              value definition which is associated with <tt>self</tt>.
              This attribute is required only if the term represents an
              item value definition in the AMEE platform

Other available attribute-like methods include type, interface, note, unit, per_unit, default_unit, default_per_unit and parent.

Subclasses of the Term correspond to:

  • Input

    • Profile – corresponds to an AMEE profile item value

    • Drill – corresponds to an AMEE drill down choice

    • Usage – corresponds to a (runtime adjustable) AMEE usage choice

    • Metadatum – represents other arbitrary inputs

  • Output – corresponds to an AMEE return value

Direct Known Subclasses

Input, Output

Constant Summary collapse

Interfaces =

Valid choices for suggested interfaces for a term. Dynamic boolean methods (such as text_box?) are generated for checking which value is set.

my_term.drop_down?                #=> true
[:text_box,:drop_down,:date]
UnitFields =

Symbols representing the attributes of self which are concerned with quantity units.

Each symbol also represents <b>dynamically defined method<b> name for setting and retrieving the default and current units and per units. Units are initialized as instances of <i>Quantify::Unit::Base</tt> is required.

Set a unit attribute by passing an argument. Retrieve a value by calling without an argument. Unit attributes can be defined by any form which is accepted by the Quantify::Unit#for method (either an instance of Quantify::Unit::Base (or subclass) or a symbolized or string representation of the a unit symbol, name or label). E.g.,

my_term.unit :mi
my_term.unit                   #=> <Quantify::Unit::NonSI:0xb71cac48 @label="mi" ... >

my_term.default_unit 'feet'
my_term.default_unit           #=> <Quantify::Unit::NonSI:0xb71cac48 @label="ft" ... >

my_time_unit = Unit.hour       #=> <Quantify::Unit::NonSI:0xb71cac48 @label="h" ... >
my_term.default_per_unit my_time_unit
my_term.default_per_unit       #=> <Quantify::Unit::NonSI:0xb71cac48 @label="h" ... >

Dynamically defined methods are also available for setting and retrieving alternative units for the unit and per_unit attributes. If no alternative units are explicitly defined, they are instantiated by default to represent all dimensionally equivalent units available in the system of units defined by Quantify. E.g.

my_term.unit :kg
my_term.alternative_units     #=> [ <Quantify::Unit::NonSI:0xb71cac48 @label="mi" ... >,
                                    <Quantify::Unit::SI:0xb71cac48 @label="km" ... >,
                                    <Quantify::Unit::NonSI:0xb71cac48 @label="ft" ... >,
                                    ... ]

my_term.unit 'litre'
my_term.alternative_units :bbl, :gal
my_term.alternative_units     #=> [ <Quantify::Unit::NonSI:0xb71cac48 @label="bbl" ... >,
                                    <Quantify::Unit::NonSI:0xb71cac48 @label="gal" ... > ]
[:unit,:per_unit,:default_unit,:default_per_unit]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, &block) ⇒ Term

Initialize a new instance of Term.

The term can be configured in place by passing a block (evaluated in the context of the new instance) which defines the term properties using the macro-style instance helper methods.

my_term = Term.new {

  label :size
  path "vehicleSize"
  hide!
  ...
}

The parent calculation object associated with self can be assigned using the :parent hash key passed as an argument.

Unless otherwise configured within the passed block, several attributes attempt to take default configurations if possible using rules of thumb:

  • value => nil

  • enabled => true

  • visible => true

  • label => underscored, symbolized version of path

  • path => stringified version of label

  • name => stringified and humanised version of label

  • unit => default_unit

  • per_unit => default_per_unit



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/amee-data-abstraction/term.rb', line 131

def initialize(options={},&block)
  @parent=options[:parent]
  @value=nil
  @type=nil
  @enabled=true
  @visible=true
  instance_eval(&block) if block
  label path.to_s.underscore.to_sym unless path.blank?||label
  path label.to_s unless path
  name label.to_s.humanize unless name
  unit default_unit unless unit
  per_unit default_per_unit unless per_unit
end

Instance Attribute Details

#parentObject

Symbol representing the owning parent calculation of self. Set the owning calculation object by passing as an argument. Retrieve it by calling without an argument, e.g.,

my_calculation = <AMEE::DataAbstraction::OngoingCalculation ... >

my_term.parent my_calculation

my_term.parent            #=> <AMEE::DataAbstraction::OngoingCalculation ... >


97
98
99
# File 'lib/amee-data-abstraction/term.rb', line 97

def parent
  @parent
end

#value_before_castObject

Stores pre-cast value



100
101
102
# File 'lib/amee-data-abstraction/term.rb', line 100

def value_before_cast
  @value_before_cast
end

Class Method Details

.convert_value_to_type(value, type) ⇒ Object



512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
# File 'lib/amee-data-abstraction/term.rb', line 512

def self.convert_value_to_type(value, type)
  return nil if value.blank?
  type = type.downcase.to_sym if type.is_a?(String)
  
  case type
    when :string    then value.to_s
    when :text      then value.to_s
    when :integer   then value.to_i rescue 0
    when :fixnum    then value.to_i rescue 0
    when :float     then value.to_f rescue 0
    when :decimal   then value.to_s.to_d rescue 0
    when :double    then value.to_s.to_d rescue 0
    when :datetime  then DateTime.parse(value.to_s) rescue nil
    when :time      then Time.parse(value.to_s) rescue nil
    when :date      then Date.parse(value.to_s) rescue nil
    else value
  end
end

.validate_dimensional_equivalence?(*units) ⇒ Boolean

Checks that the units included in units are dimensionally equivalent, that is, that they represent the same physucal quantity

Returns:

  • (Boolean)


505
506
507
508
509
510
# File 'lib/amee-data-abstraction/term.rb', line 505

def self.validate_dimensional_equivalence?(*units)
  unless [units].flatten.all? {|unit| unit.dimensions == units[0].dimensions }
    raise AMEE::DataAbstraction::Exceptions::InvalidUnits,
      "The specified term units are not of equivalent dimensions: #{units.map(&:label).join(",")}"
  end
end

Instance Method Details

#==(other_term) ⇒ Object



361
362
363
364
365
# File 'lib/amee-data-abstraction/term.rb', line 361

def ==(other_term)
  !TermsList::TermProperties.inject(false) do |boolean,prop|
    boolean || self.send(prop) != other_term.send(prop)
  end
end

#after?(lab) ⇒ Boolean

Returns true if self occurs after the term with a label matching lab in the terms list of the parent calculation. Otherwise, returns false.

Returns:

  • (Boolean)


400
401
402
# File 'lib/amee-data-abstraction/term.rb', line 400

def after?(lab)
  parent.terms.labels.index(lab)<parent.terms.labels.index(label)
end

#before?(lab) ⇒ Boolean

Returns true if self occurs before the term with a label matching lab in the terms list of the parent calculation. Otherwise, returns false.

Returns:

  • (Boolean)


392
393
394
# File 'lib/amee-data-abstraction/term.rb', line 392

def before?(lab)
   parent.terms.labels.index(lab)>parent.terms.labels.index(label)
end

#convert_unit(options = {}) ⇒ Object

Return a new instance of Term, based on self but with a change of units, according to the options hash provided, and the value attribute updated to reflect the new units.

To specify a new unit, pass the required unit via the :unit key. To specify a new per_unit, pass the required per unit via the :per_unit key. E.g.,

my_term.convert_unit(:unit => :kg)

my_term.convert_unit(:unit => :kg, :per_unit => :h)

my_term.convert_unit(:unit => 'kilogram')

my_term.convert_unit(:per_unit => Quantify::Unit.h)

my_term.convert_unit(:unit => <Quantify::Unit::SI ... >)

If self does not hold a numeric value or either a unit or per unit attribute, self is returned.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/amee-data-abstraction/term.rb', line 433

def convert_unit(options={})
  return self unless is_numeric? && (unit || per_unit)

  new = clone
  if has_numeric_value?
    if options[:unit] && unit
      new_unit = Unit.for(options[:unit])
      Term.validate_dimensional_equivalence?(unit,new_unit)
      new.value Quantity.new(new.value,new.unit).to(new_unit).value
    end
    if options[:per_unit] && per_unit
      new_per_unit = Unit.for(options[:per_unit])
      Term.validate_dimensional_equivalence?(per_unit,new_per_unit)
      new.value Quantity.new(new.value,(1/new.per_unit)).to(Unit.for(new_per_unit)).value
    end
  end
  new.unit options[:unit] if options[:unit]
  new.per_unit options[:per_unit] if options[:per_unit]
  return new
end

#disable!Object

Declare that the term’s UI element should be disabled



314
315
316
# File 'lib/amee-data-abstraction/term.rb', line 314

def disable!
  @disabled=true
end

#disabled?Boolean

Returns true if the UI element of self is disabled. Otherwise, returns false.

Returns:

  • (Boolean)


326
327
328
# File 'lib/amee-data-abstraction/term.rb', line 326

def disabled?
  @disabled
end

#enable!Object

Declare that the term’s UI element should be enabled



319
320
321
# File 'lib/amee-data-abstraction/term.rb', line 319

def enable!
  @disabled=false
end

#enabled?Boolean

Returns true if the UI element of self is enabled. Otherwise, returns false.

Returns:

  • (Boolean)


333
334
335
# File 'lib/amee-data-abstraction/term.rb', line 333

def enabled?
  !disabled?
end

#has_numeric_value?Boolean

Returns true if self has a numeric value. That is, can it have statistics applied? This method permits handling of term summing,

averaging, etc. Otherwise, returns <tt>false</tt>.

Returns:

  • (Boolean)


371
372
373
# File 'lib/amee-data-abstraction/term.rb', line 371

def has_numeric_value?
  is_numeric? && set? && Float(value) rescue false
end

#hidden?Boolean

Returns true if self is configured as hidden. Otherwise, returns false.

Returns:

  • (Boolean)


347
348
349
# File 'lib/amee-data-abstraction/term.rb', line 347

def hidden?
  !visible?
end

#hide!Object

Declare that the term’s UI element should not be shown in generated UIs.



352
353
354
# File 'lib/amee-data-abstraction/term.rb', line 352

def hide!
  @visible=false
end

#initialize_copy(source) ⇒ Object



404
405
406
407
408
409
410
# File 'lib/amee-data-abstraction/term.rb', line 404

def initialize_copy(source)
  super
  UnitFields.each do |property|
    prop = send(property)
    self.send(property, prop.clone) unless prop.nil?
  end
end

#inspectObject

Returns a pretty print string representation of self



380
381
382
383
384
385
386
# File 'lib/amee-data-abstraction/term.rb', line 380

def inspect
  elements = {:label => label, :value => value, :unit => unit,
              :per_unit => per_unit, :type => type,
              :disabled => disabled?, :visible => visible?}
  attr_list = elements.map {|k,v| "#{k}: #{v.inspect}" } * ', '
  "<#{self.class.name} #{attr_list}>"
end

#interface(inf = nil) ⇒ Object

Symbolized attribute representing the expected interface type for self. Set a value by passing an argument. Retrieve a value by calling without an argument, e.g.,

my_term.interface :drop_down

my_term.interface                  #=> :drop_down

Must represent one of the valid choices defined in the Term::Interfaces constant

If the provided interface is not valid (as defined in Term::Interfaces)

an <i>InvalidInterface</i> exception is raised


173
174
175
176
177
178
179
# File 'lib/amee-data-abstraction/term.rb', line 173

def interface(inf=nil)
  if inf
    raise Exceptions::InvalidInterface unless Interfaces.include? inf
    @interface=inf
  end
  return @interface
end

#is_numeric?Boolean

Returns:

  • (Boolean)


375
376
377
# File 'lib/amee-data-abstraction/term.rb', line 375

def is_numeric?
  ![:string, :text, :datetime, :time, :date ].include?(type)
end

#note(string = nil) ⇒ Object

String representing an annotation for self. Set a value by passing an argument. Retrieve a value by calling without an argument, e.g.,

my_term.note 'Enter the mass of cement produced in the reporting period'

my_term.note                       #=> 'Enter the mass of cement ...'


213
214
215
216
# File 'lib/amee-data-abstraction/term.rb', line 213

def note(string=nil)
  instance_variable_set("@note",string.gsub('"',"'")) unless string.nil?
  instance_variable_get("@note")
end

#set?Boolean

Returns true if self has a populated value attribute. Otherwise, returns false.

Returns:

  • (Boolean)


302
303
304
# File 'lib/amee-data-abstraction/term.rb', line 302

def set?
  !value_before_cast.nil?
end

#show!Object

Declare that the term’s UI element should be shown in generated UIs.



357
358
359
# File 'lib/amee-data-abstraction/term.rb', line 357

def show!
  @visible=true
end

#to_quantityObject Also known as: to_q

Return an instance of Quantify::Quantity describing the quantity represented by self.

If self does not contain a numeric value, nil is returned.

If self contains a numeric value, but no unit or per unit, just the numeric value is returned



462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/amee-data-abstraction/term.rb', line 462

def to_quantity
  return nil unless has_numeric_value?
  if (unit.is_a? Quantify::Unit::Base) && (per_unit.is_a? Quantify::Unit::Base)
    quantity_unit = unit/per_unit
  elsif unit.is_a? Quantify::Unit::Base
    quantity_unit = unit
  elsif per_unit.is_a? Quantify::Unit::Base
    quantity_unit = 1/per_unit
  else
    return value
  end
  Quantity.new(value,quantity_unit)
end

#to_s(format = :symbol) ⇒ Object

Returns a string representation of term based on the term value and any units which are defined. The format of the unit representation follows that defined by format, which should represent any of the formats supported by the <i>Quantify::Unit::Base</tt> class (i.e. :name, :pluralized_name, :symbol and :label). Default behaviour uses the unit symbol atribute, i.e. if no format explcitly specified:

my_term.to_s                      #=> "12345 ton"

my_term.to_s :symbol              #=> "12345 ton"

my_term.to_s :name                #=> "12345 short ton"

my_term.to_s :pluralized_name     #=> "12345 tons"

my_term.to_s :label               #=> "12345 ton_us"


494
495
496
497
498
499
500
# File 'lib/amee-data-abstraction/term.rb', line 494

def to_s(format=:symbol)
  if has_numeric_value? && (unit || per_unit)
    self.to_quantity.to_s(format)
  else
    "#{value}"
  end
end

#unset?Boolean

Returns true if self does not have a populated value attribute. Otherwise, returns false.

Returns:

  • (Boolean)


309
310
311
# File 'lib/amee-data-abstraction/term.rb', line 309

def unset?
  value_before_cast.nil?
end

#value(*args) ⇒ Object

Object representing the value which self is considered to represent (e.g. the quantity or name of something). Set a value by passing an argument. Retrieve a value by calling without an argument, e.g.,

my_term.value 12
my_term.value                      #=> 12

my_term.value 'Ford Escort'
my_term.value                      #=> 'Ford Escort'

my_term.value DateTime.civil(2010,12,31)
my_term.value                      #=> <Date: 4911123/2,0,2299161>


197
198
199
200
201
202
203
# File 'lib/amee-data-abstraction/term.rb', line 197

def value(*args)
  unless args.empty?
    @value_before_cast = args.first
    @value = @type ? self.class.convert_value_to_type(args.first, @type) : args.first
  end
  @value
end

#visible?Boolean

Returns true if self is configured as visible. Otherwise, returns false.

Returns:

  • (Boolean)


340
341
342
# File 'lib/amee-data-abstraction/term.rb', line 340

def visible?
  @visible
end