resync from rails_port 11795:12304
[rails.git] / vendor / gems / composite_primary_keys-1.1.0 / lib / composite_primary_keys / attribute_methods.rb
1 module CompositePrimaryKeys
2   module ActiveRecord
3     module AttributeMethods #:nodoc:
4       def self.append_features(base)
5         super
6         base.send(:extend, ClassMethods)
7       end
8
9       module ClassMethods
10         # Define an attribute reader method.  Cope with nil column.
11         def define_read_method(symbol, attr_name, column)
12           cast_code = column.type_cast_code('v') if column
13           cast_code = "::#{cast_code}" if cast_code && cast_code.match('ActiveRecord::.*')
14           access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']"
15
16           unless self.primary_keys.include?(attr_name.to_sym)
17             access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
18           end
19
20           if cache_attribute?(attr_name)
21             access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
22           end
23
24           evaluate_attribute_method attr_name, "def #{symbol}; #{access_code}; end"
25         end
26
27         # Evaluate the definition for an attribute related method
28         def evaluate_attribute_method(attr_name, method_definition, method_name=attr_name)
29           unless primary_keys.include?(method_name.to_sym)
30             generated_methods << method_name
31           end
32
33           begin
34             class_eval(method_definition, __FILE__, __LINE__)
35           rescue SyntaxError => err
36             generated_methods.delete(attr_name)
37             if logger
38               logger.warn "Exception occurred during reader method compilation."
39               logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
40               logger.warn "#{err.message}"
41             end
42           end
43         end
44       end
45
46       # Allows access to the object attributes, which are held in the @attributes hash, as though they
47       # were first-class methods. So a Person class with a name attribute can use Person#name and
48       # Person#name= and never directly use the attributes hash -- except for multiple assigns with
49       # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
50       # the completed attribute is not nil or 0.
51       #
52       # It's also possible to instantiate related objects, so a Client class belonging to the clients
53       # table with a master_id foreign key can instantiate master through Client#master.
54       def method_missing(method_id, *args, &block)
55         method_name = method_id.to_s
56
57         # If we haven't generated any methods yet, generate them, then
58         # see if we've created the method we're looking for.
59         if !self.class.generated_methods?
60           self.class.define_attribute_methods
61
62           if self.class.generated_methods.include?(method_name)
63             return self.send(method_id, *args, &block)
64           end
65         end
66
67         if self.class.primary_keys.include?(method_name.to_sym)
68           ids[self.class.primary_keys.index(method_name.to_sym)]
69         elsif md = self.class.match_attribute_method?(method_name)
70           attribute_name, method_type = md.pre_match, md.to_s
71           if @attributes.include?(attribute_name)
72             __send__("attribute#{method_type}", attribute_name, *args, &block)
73           else
74             super
75           end
76         elsif @attributes.include?(method_name)
77           read_attribute(method_name)
78         else
79           super
80         end
81       end
82     end
83   end
84 end