提交 bb44e5a8 编写于 作者: J Jon Leighton

Use a separate module for 'external' attribute methods.

上级 a5589db0
......@@ -33,6 +33,20 @@ def generated_attribute_methods
@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
......
......@@ -30,10 +30,10 @@ def define_method_attribute(attr_name)
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
......
......@@ -31,10 +31,8 @@ def cache_attribute?(attr_name)
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 @@ def undefine_attribute_methods
# 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 @@ def attribute_cast_code(attr_name)
# "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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册