Module: Encoder::ClassMethods

Defined in:
lib/encoder.rb

Instance Method Summary collapse

Instance Method Details

#code(attribute_name, &block) ⇒ Object

Creates getter and setter methods for an attribute. The getter returns a ‘decodable’ string that provides more meaning.

Example:

class Task

include Encoder
code :priority do
  Priority::Low = "L"
end

end

t = Task.new t.priority = Priority::Low t.priority # => “L” t.priority.decode # => “Low”



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/encoder.rb', line 35

def code(attribute_name, &block)
  
  # Create a 'namespace' for constants 
  namespace = const_set(attribute_name.to_s.camelcase, Module.new)
  
  # Expecting constants to be assigned values.
  yield
  
  # Add methods for obtaining namespaced constants and their values.
  namespace.module_eval do
    def self.values
      constants.map { |c| self.const_get(c) }
    end
    def self.mapping
      constants.inject(Hash.new) do |memo, const|
        memo[const] = self.const_get(const)
        memo
      end
    end
  end
  
  
  # create setter for attribute
  self.send(:define_method, "#{attribute_name}=") do |arg|
    
    # At the end of this method, the underlying attribute will be set
    # to the value of this variable.
    encoded_value = nil
    
    # Retrieve the module where the constants for this attribute are defined.
    namespace = self.class.const_get(attribute_name.to_s.camelcase)
    
    # Since the given value might not match the constant name exactly
    # (because of case sensitivity or white space variations) we
    # normalize it a bit.
    normalized = arg && arg.to_s.gsub(/\s+/,'').downcase
    
    # Now we look for a constant whose name or actual value match the
    # normalized argument.  We 'tap' whatever constant name is found
    # and lookup the actual value.
    namespace.constants.find do |const_name|
      normalized == const_name.to_s.downcase ||
      normalized == namespace.const_get(const_name).to_s.downcase
    end.tap do |match|
      encoded_value = namespace.const_get(match) if match
    end
    
    # Set the value to whatever we found, possibly nil
    self.write_attribute(attribute_name, encoded_value)
  end
  
  # create getter for attribute
  self.send(:define_method, attribute_name) do
  
    encoded_attribute = self.read_attribute(attribute_name)
    
    namespace = self.class.const_get(attribute_name.to_s.camelcase)
  
    decoded_value = namespace.constants.select do |constant|
      namespace.const_get(constant) == encoded_attribute
    end.first
  
    if decoded_value.is_a?(Fixnum)
      encoded_attribute.instance_variable_set(:@decode, decoded_value)
    elsif ! decoded_value.nil?
      encoded_attribute.instance_variable_set(:@decode, decoded_value.underscore.titleize)
    else
      encoded_attribute.instance_variable_set(:@decode, nil)
    end
  
    return encoded_attribute
  end # -- dynamic getter method 
    
end