Module: ActsAsLookupClassMethods

Defined in:
lib/acts_as_lookup.rb

Overview

contains methods and logic to be added to classes that call the acts_as_lookup method


Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(klass) ⇒ Object



5
6
7
8
9
10
11
# File 'lib/acts_as_lookup.rb', line 5

def self.extended(klass)
  klass.send(:instance_variable_set, :@acts_as_lookup_options, nil)
  klass.send(:instance_variable_set, :@acts_as_lookup_by_id, {})
  klass.send(:instance_variable_set, :@acts_as_lookup_by_name, {})
  klass.send(:instance_variable_set, :@acts_as_lookup_initialized, false)
  klass.send(:instance_variable_set, :@acts_as_lookup_values, [])
end

Instance Method Details

#acts_as_lookup_add_query_method(lookup_name) ⇒ Object

adds an instance method of the form [lookup_value_name]? to check the identity of a lookup object




148
149
150
151
152
153
154
155
156
# File 'lib/acts_as_lookup.rb', line 148

def acts_as_lookup_add_query_method(lookup_name)
  method_name = "#{get_method_name(lookup_name)}?"
  if respond_to?(method_name.to_sym)
    raise "Cannot create method '#{method_name}?' to #{self.inspect} " +
          "as it conflicts with existing method with same name"
  end

  define_method(method_name) { self.name == lookup_name }
end

#acts_as_lookup_add_shortcut(name) ⇒ Object

adds a class method to access a particular lookup value via a shortcut method

FUTURE: will allow for any column to be used here; for now, hardcoded

to lookup by name



135
136
137
138
139
140
141
142
143
# File 'lib/acts_as_lookup.rb', line 135

def acts_as_lookup_add_shortcut(name)
  method_name = get_method_name(name)
  if respond_to?(method_name.to_sym)
    raise "Cannot create method '#{method_name}' to #{self.inspect} " +
          "as it conflicts with existing method with same name"
  end

  instance_eval "def #{method_name}; self.lookup_by_name '#{name}'; end"
end

#acts_as_lookup_fetch_valuesObject

fetches existing records from the db and merges them into the cached values only called if :sync_with_db option is true

FUTURE: if this gem is to be used outside of a Rails’ ActiveRecord::Base descendant, will need to allow calling class to specify an alternative implementation (maybe add a config value that specifies a method to call)




81
82
83
84
# File 'lib/acts_as_lookup.rb', line 81

def acts_as_lookup_fetch_values
  @acts_as_lookup_values = self.all
  self.acts_as_lookup_refresh_caches
end

#acts_as_lookup_initializeObject

initialize the current lookup class for lookup use if it isn’t already

NOTE: early edition of this gem assumes id, name columns. FUTURE will allow

more flexibility through configuration



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
# File 'lib/acts_as_lookup.rb', line 43

def acts_as_lookup_initialize
  Thread.exclusive do
    # double-check in case of race condition in calling code
    unless self.acts_as_lookup_initialized?
      if acts_as_lookup_options[:sync_with_db]
        acts_as_lookup_fetch_values
        if acts_as_lookup_options[:write_to_db]
          acts_as_lookup_write_missing_values
        end
      else
        @acts_as_lookup_values = acts_as_lookup_options[:values]
        self.acts_as_lookup_refresh_caches
      end

      @acts_as_lookup_initialized = true
    end

    # FUTURE: allow for a different column to be used for generating class
    #         accessor methods
    @acts_as_lookup_by_name.each_pair do |name,val|
      if acts_as_lookup_options[:add_query_methods]
        self.acts_as_lookup_add_query_method name
      end
      self.acts_as_lookup_add_shortcut name
    end

  end
end

#acts_as_lookup_initialized?Boolean

check if the current lookup class has been initialized for lookup use


Returns:

  • (Boolean)


33
34
35
# File 'lib/acts_as_lookup.rb', line 33

def acts_as_lookup_initialized?
  @acts_as_lookup_initialized
end

#acts_as_lookup_optionsObject



16
17
18
# File 'lib/acts_as_lookup.rb', line 16

def acts_as_lookup_options
  @acts_as_lookup_options
end

#acts_as_lookup_options=(options) ⇒ Object



13
14
15
# File 'lib/acts_as_lookup.rb', line 13

def acts_as_lookup_options=(options)
  @acts_as_lookup_options = options
end

#acts_as_lookup_refresh_cachesObject

updates the lookup cache hashes from @@acts_as_lookup_values




119
120
121
122
123
124
125
126
# File 'lib/acts_as_lookup.rb', line 119

def acts_as_lookup_refresh_caches
  # FUTURE: this will get cleaned up, and will dynamically select which
  #         columns to establish lookup caches for.
  @acts_as_lookup_values.each do |val|
    @acts_as_lookup_by_id.merge!(val.id => val) unless @acts_as_lookup_by_id.include?(val.id)
    @acts_as_lookup_by_name.merge!(val.name => val) unless @acts_as_lookup_by_name.include?(val.name)
  end
end

#acts_as_lookup_write_missing_valuesObject

writes any missing values to the db only called if :sync_with_db and :write_to_db options are both true

NOTE: does NOT overwrite any values found in the db, so it is possible for

the values specified in the class to be superceded by values in the
database



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/acts_as_lookup.rb', line 94

def acts_as_lookup_write_missing_values
  # FUTURE: if :ids aren't provided, use the uniqueness_column to determine
  #         which values are missing from existing caches
  acts_as_lookup_options[:values].each do |val|
    next if @acts_as_lookup_by_id.include?(val[:id])

    # bypass attr_accessible protection, assign attributes one-by-one
    new_val = self.new
    val.each_pair do |attr,value|
      setter = "#{attr.to_s}=".to_sym
      if new_val.respond_to?(setter)
        new_val.send(setter, value)
      end
    end
    new_val.save!

    @acts_as_lookup_values << new_val
  end

  self.acts_as_lookup_refresh_caches
end

#lookup_by_id(id) ⇒ Object

FUTURE: allow for dynamically specifying which columns can be used for

cache lookups



23
24
25
# File 'lib/acts_as_lookup.rb', line 23

def lookup_by_id(id)
  @acts_as_lookup_by_id[id]
end

#lookup_by_name(name) ⇒ Object



26
27
28
# File 'lib/acts_as_lookup.rb', line 26

def lookup_by_name(name)
  @acts_as_lookup_by_name[name]
end