Module: HasAttributes

Overview

HasAttributes allows objects to have arbitrary attributes associated with it.

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

This method allows attributes to be defined on an instance without explicitly defining which attributes are allowed

The flow is:

  1. If the method receives a block, it will pass it to the `assign_block` method to be handled. By default this method will throw an error, but can be overridden by the class.

  2. If the method has one or more argument it will assume it is a setter and store the argument as an attribute.

  3. If the method has no arguments it will assume it is a getter and retrieve the value. If the retrieved value is a `Proc` it will execute it and store the returned value, this will allow for caching expensive calls and only calling if requested


75
76
77
78
79
80
81
82
83
84
85
# File 'lib/geoengineer/utils/has_attributes.rb', line 75

def method_missing(name, *args, &block)
  name = name.to_s
  if block_given?
    # A class can override a
    assign_block(name, *args, &block)
  elsif args.length >= 1
    assign_attribute(name, args)
  elsif args.empty?
    retrieve_attribute(name)
  end
end

Instance Method Details

#[](key) ⇒ Object


14
15
16
# File 'lib/geoengineer/utils/has_attributes.rb', line 14

def [](key)
  retrieve_attribute(key.to_s)
end

#[]=(key, val) ⇒ Object


18
19
20
# File 'lib/geoengineer/utils/has_attributes.rb', line 18

def []=(key, val)
  assign_attribute(key.to_s, [val])
end

#assign_attribute(name, args) ⇒ Object


30
31
32
33
34
35
36
# File 'lib/geoengineer/utils/has_attributes.rb', line 30

def assign_attribute(name, args)
  # this is a setter
  name = name[0...-1] if name.end_with?"="
  val = args.length == 1 ? args[0] : args
  attribute_procs[name] = val if val.is_a?(Proc)
  attributes[name] = val
end

#assign_block(name, *args, &block) ⇒ Object


26
27
28
# File 'lib/geoengineer/utils/has_attributes.rb', line 26

def assign_block(name, *args, &block)
  throw "#{self.class.inspect} cannot handle block"
end

#attribute_missing(name) ⇒ Object


60
61
62
# File 'lib/geoengineer/utils/has_attributes.rb', line 60

def attribute_missing(name)
  nil
end

#attribute_procsObject

Contains the procs used to calculate attributes


10
11
12
# File 'lib/geoengineer/utils/has_attributes.rb', line 10

def attribute_procs
  @_procs ||= {}
end

#attributesObject


5
6
7
# File 'lib/geoengineer/utils/has_attributes.rb', line 5

def attributes
  @_attributes ||= {}
end

#delete(key) ⇒ Object


22
23
24
# File 'lib/geoengineer/utils/has_attributes.rb', line 22

def delete(key)
  attributes.delete(key.to_s)
end

#eager_load_attributesObject


55
56
57
58
# File 'lib/geoengineer/utils/has_attributes.rb', line 55

def eager_load_attributes
  attribute_procs.each { |name, function| attributes[name] = function.call() }
  self
end

#reset_attributesObject

For any value that has been lazily calculated, recalculate it


50
51
52
53
# File 'lib/geoengineer/utils/has_attributes.rb', line 50

def reset_attributes
  attribute_procs.each { |name, function| attributes[name] = function }
  self
end

#retrieve_attribute(name) ⇒ Object


38
39
40
41
42
43
44
45
46
47
# File 'lib/geoengineer/utils/has_attributes.rb', line 38

def retrieve_attribute(name)
  # this is a getter
  val = if attributes.key?(name)
          attributes[name]
        else
          attribute_missing(name)
        end
  return val unless val.is_a?(Proc)
  attributes[name] = val.call() # cache the value to override the Proc
end

#terraform_attribute_ref(k) ⇒ Object


101
102
103
104
105
106
107
108
109
110
# File 'lib/geoengineer/utils/has_attributes.rb', line 101

def terraform_attribute_ref(k)
  v = retrieve_attribute(k)
  if v.is_a? GeoEngineer::Resource # convert Resource to reference for terraform
    v.to_ref
  elsif v.is_a? Array # map resources if attribute is an array
    v.map { |vi| vi.is_a?(GeoEngineer::Resource) ? vi.to_ref : vi }
  else
    v
  end
end

#terraform_attributesObject

This method creates a set of attributes for terraform to consume


93
94
95
96
97
98
99
# File 'lib/geoengineer/utils/has_attributes.rb', line 93

def terraform_attributes
  attributes
    .select { |k, v| !k.nil? && !k.start_with?('_') }
    .map { |k, v| [k, terraform_attribute_ref(k)] }
    .select { |k, v| !v.nil? }
    .to_h
end

#timeout(*args) ⇒ Object

must override because of Object#timeout


88
89
90
# File 'lib/geoengineer/utils/has_attributes.rb', line 88

def timeout(*args)
  method_missing(:timeout, *args)
end