aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-12-14 14:49:02 +0000
committerJon Leighton <j@jonathanleighton.com>2011-12-14 14:51:57 +0000
commitbb44e5a80ac62f87a40122a213038a746f2bc289 (patch)
treefd897babdffa9e8e5a08d5dd45bfdea0b5f58078
parenta5589db063e0f527357f6be338adecf4716e6b47 (diff)
downloadrails-bb44e5a80ac62f87a40122a213038a746f2bc289.tar.gz
rails-bb44e5a80ac62f87a40122a213038a746f2bc289.tar.bz2
rails-bb44e5a80ac62f87a40122a213038a746f2bc289.zip
Use a separate module for 'external' attribute methods.
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb14
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb23
3 files changed, 26 insertions, 17 deletions
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 3c9fafb1ca..47f625039b 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -33,6 +33,20 @@ module ActiveRecord
@generated_attribute_methods ||= (base_class == self ? super : base_class.generated_attribute_methods)
end
+ def generated_external_attribute_methods
+ @generated_external_attribute_methods ||= begin
+ if base_class == self
+ # We will define the methods as instance methods, but will call them as singleton
+ # methods. This allows us to use method_defined? to check if the method exists,
+ # which is fast and won't give any false positives from the ancestors (because
+ # there are no ancestors).
+ Module.new { extend self }
+ else
+ base_class.generated_external_attribute_methods
+ end
+ end
+ end
+
def undefine_attribute_methods
if base_class == self
super
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 746682393e..e3c7344f59 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -30,10 +30,10 @@ module ActiveRecord
if attr_name == primary_key && attr_name != 'id'
generated_attribute_methods.send(:alias_method, :id, primary_key)
- generated_attribute_methods.module_eval <<-CODE, __FILE__, __LINE__
- def self.attribute_id(v, attributes, attributes_cache, attr_name)
+ generated_external_attribute_methods.module_eval <<-CODE, __FILE__, __LINE__
+ def id(v, attributes, attributes_cache, attr_name)
attr_name = '#{primary_key}'
- send(:'attribute_#{attr_name}', attributes[attr_name], attributes, attributes_cache, attr_name)
+ send(attr_name, attributes[attr_name], attributes, attributes_cache, attr_name)
end
CODE
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 25c998e857..0ca627638a 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -31,10 +31,8 @@ module ActiveRecord
def undefine_attribute_methods
if base_class == self
- generated_attribute_methods.module_eval do
- public_methods(false).each do |m|
- singleton_class.send(:undef_method, m) if m.to_s =~ /^attribute_/
- end
+ generated_external_attribute_methods.module_eval do
+ instance_methods.each { |m| undef_method(m) }
end
end
@@ -52,22 +50,20 @@ module ActiveRecord
# rename it to what we want.
def define_method_attribute(attr_name)
cast_code = attribute_cast_code(attr_name)
- internal = internal_attribute_access_code(attr_name, cast_code)
- external = external_attribute_access_code(attr_name, cast_code)
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
def __temp__
- #{internal}
+ #{internal_attribute_access_code(attr_name, cast_code)}
end
alias_method '#{attr_name}', :__temp__
undef_method :__temp__
STR
- generated_attribute_methods.singleton_class.module_eval <<-STR, __FILE__, __LINE__ + 1
+ generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
def __temp__(v, attributes, attributes_cache, attr_name)
- #{external}
+ #{external_attribute_access_code(attr_name, cast_code)}
end
- alias_method 'attribute_#{attr_name}', :__temp__
+ alias_method '#{attr_name}', :__temp__
undef_method :__temp__
STR
end
@@ -110,12 +106,11 @@ module ActiveRecord
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
attr_name = attr_name.to_s
- accessor = "attribute_#{attr_name}"
- methods = self.class.generated_attribute_methods
+ methods = self.class.generated_external_attribute_methods
- if methods.respond_to?(accessor)
+ if methods.method_defined?(attr_name)
if @attributes.has_key?(attr_name) || attr_name == 'id'
- methods.send(accessor, @attributes[attr_name], @attributes, @attributes_cache, attr_name)
+ methods.send(attr_name, @attributes[attr_name], @attributes, @attributes_cache, attr_name)
end
elsif !self.class.attribute_methods_generated?
# If we haven't generated the caster methods yet, do that and