From d3494903719682abc0948bef290af0d3d7b5a440 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 31 Oct 2012 17:04:08 +0100 Subject: Revert "Don't allocate new strings in compiled attribute methods" This reverts commit f1765019ce9b6292f2264b4601dad5daaffe3a89. --- .../lib/active_record/attribute_methods/read.rb | 39 +++++++--------------- .../lib/active_record/attribute_methods/write.rb | 20 +++++------ 2 files changed, 20 insertions(+), 39 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 07c8859496..90701938e5 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -32,36 +32,21 @@ module ActiveRecord protected - # We want to generate the methods via module_eval rather than - # define_method, because define_method is slower on dispatch and - # uses more memory (because it creates a closure). + # We want to generate the methods via module_eval rather than define_method, + # because define_method is slower on dispatch and uses more memory (because it + # creates a closure). # - # But sometimes the database might return columns with - # characters that are not allowed in normal method names (like - # 'my_column(omg)'. So to work around this we first define with - # the __temp__ identifier, and then use alias method to rename - # it to what we want. - # - # We are also defining a constant to hold the frozen string of - # the attribute name. Using a constant means that we do not have - # to allocate an object on each call to the attribute method. - # Making it frozen means that it doesn't get duped when used to - # key the @attributes_cache in read_attribute. - def define_method_attribute(name) - safe_name = name.unpack('h*').first + # But sometimes the database might return columns with characters that are not + # allowed in normal method names (like 'my_column(omg)'. So to work around this + # we first define with the __temp__ identifier, and then use alias method to + # rename it to what we want. + def define_method_attribute(attr_name) generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - module AttrNames - unless defined? ATTR_#{safe_name} - ATTR_#{safe_name} = #{name.inspect}.freeze - end + def __temp__ + read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) } end - - def __temp__#{safe_name} - read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) } - end - - alias_method #{name.inspect}, :__temp__#{safe_name} - undef_method :__temp__#{safe_name} + alias_method '#{attr_name}', :__temp__ + undef_method :__temp__ STR end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index cd33494cc3..fa9097db1f 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -9,19 +9,15 @@ module ActiveRecord module ClassMethods protected - - # See define_method_attribute in read.rb for an explanation of - # this code. - def define_method_attribute=(name) - safe_name = name.unpack('h*').first - generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - def __temp__#{safe_name}=(value) - write_attribute(AttrNames::ATTR_#{safe_name}, value) + def define_method_attribute=(attr_name) + if attr_name =~ ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP + generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__) + else + generated_attribute_methods.send(:define_method, "#{attr_name}=") do |new_value| + write_attribute(attr_name, new_value) + end end - alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= - undef_method :__temp__#{safe_name}= - STR - end + end end # Updates the attribute identified by attr_name with the -- cgit v1.2.3