Permalink
Browse files

Key the attributes hash with symbols

This is a performance/GC optimisation.

In theory, this could be optimised by the implementation (last time I
checked, this would have no effect on JRuby). But in practise, this make
attribute access faster.
  • Loading branch information...
1 parent e96558f commit 86c3dfbd47cb96af02daaa655963292b1a1b110e @jonleighton jonleighton committed Aug 31, 2012
@@ -45,7 +45,7 @@ def cache_attribute?(attr_name)
def define_method_attribute(attr_name)
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
def __temp__
- read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) }
+ read_attribute(:'#{attr_name}') { |n| missing_attribute(n, caller) }
end
alias_method '#{attr_name}', :__temp__
undef_method :__temp__
@@ -68,11 +68,16 @@ def cacheable_column?(column)
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
+ return unless attr_name
+ name_sym = attr_name.to_sym
+
# If it's cached, just return it
- @attributes_cache.fetch(attr_name.to_s) { |name|
+ @attributes_cache.fetch(name_sym) {
+ name = attr_name.to_s
+
column = @columns_hash.fetch(name) {
return @attributes.fetch(name) {
- if name == 'id' && self.class.primary_key != name
+ if name_sym == :id && self.class.primary_key != name
read_attribute(self.class.primary_key)
end
}
@@ -83,7 +88,7 @@ def read_attribute(attr_name)
}
if self.class.cache_attribute?(name)
- @attributes_cache[name] = column.type_cast(value)
+ @attributes_cache[name_sym] = column.type_cast(value)
else
column.type_cast value
end
@@ -65,7 +65,7 @@ def #{attr_name}=(original_time)
if (rounded_value != rounded_time) || (!rounded_value && original_time)
write_attribute("#{attr_name}", original_time)
#{attr_name}_will_change!
- @attributes_cache["#{attr_name}"] = zoned_time
+ @attributes_cache[:"#{attr_name}"] = zoned_time
end
end
EOV
@@ -25,13 +25,13 @@ def define_method_attribute=(attr_name)
def write_attribute(attr_name, value)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
- @attributes_cache.delete(attr_name)
+ @attributes_cache.delete(attr_name.to_sym)
column = column_for_attribute(attr_name)
# If we're dealing with a binary column, write the data to the cache
# so we don't attempt to typecast multiple times.
if column && column.binary?
- @attributes_cache[attr_name] = value
+ @attributes_cache[attr_name.to_sym] = value
end
if column || @attributes.has_key?(attr_name)
@@ -542,10 +542,10 @@ def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_els
val = t.send attr_name unless attr_name == "type"
if attribute_gets_cached
assert cached_columns.include?(attr_name)
- assert_equal val, cache[attr_name]
+ assert_equal val, cache[attr_name.to_sym]
else
assert uncached_columns.include?(attr_name)
- assert !cache.include?(attr_name)
+ assert !cache.include?(attr_name.to_sym)
end
end
end

3 comments on commit 86c3dfb

Contributor

andreacampi replied Aug 31, 2012

I was wondering, why the mix of var.to_sym and :"#{var}" ?

Member

jonleighton replied Sep 1, 2012

:'#{var}' is used in generated code.

Contributor

andreacampi replied Sep 1, 2012

Oh, got it. My bad for looking at just the diff instead of the whole file.

Please sign in to comment.