aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model/attribute_methods.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2011-11-14 20:12:17 +0100
committerJosé Valim <jose.valim@gmail.com>2011-11-14 20:12:17 +0100
commit9fa329b7544b15cdf5751d518e380abc82468df0 (patch)
treefacb557553e13712a87acaca21dae1220fda885e /activemodel/lib/active_model/attribute_methods.rb
parent2088f1b3b4538fc7cac0d7bb23bdfba592438a1d (diff)
downloadrails-9fa329b7544b15cdf5751d518e380abc82468df0.tar.gz
rails-9fa329b7544b15cdf5751d518e380abc82468df0.tar.bz2
rails-9fa329b7544b15cdf5751d518e380abc82468df0.zip
Speed up attribute invocation by checking if both name and calls are compilable.
Diffstat (limited to 'activemodel/lib/active_model/attribute_methods.rb')
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb59
1 files changed, 32 insertions, 27 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index ef0b95424e..e69cb5c459 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -57,7 +57,8 @@ module ActiveModel
module AttributeMethods
extend ActiveSupport::Concern
- COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
+ NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
+ CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
included do
class_attribute :attribute_method_matchers, :instance_writer => false
@@ -112,7 +113,7 @@ module ActiveModel
# If we can compile the method name, do it. Otherwise use define_method.
# This is an important *optimization*, please don't change it. define_method
# has slower dispatch and consumes more memory.
- if name =~ COMPILABLE_REGEXP
+ if name =~ NAME_COMPILABLE_REGEXP
sing.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
RUBY
@@ -240,18 +241,7 @@ module ActiveModel
attribute_method_matchers.each do |matcher|
matcher_new = matcher.method_name(new_name).to_s
matcher_old = matcher.method_name(old_name).to_s
-
- if matcher_new =~ COMPILABLE_REGEXP && matcher_old =~ COMPILABLE_REGEXP
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{matcher_new}(*args)
- send(:#{matcher_old}, *args)
- end
- RUBY
- else
- define_method(matcher_new) do |*args|
- send(matcher_old, *args)
- end
- end
+ define_optimized_call self, matcher_new, matcher_old
end
end
@@ -293,17 +283,7 @@ module ActiveModel
if respond_to?(generate_method)
send(generate_method, attr_name)
else
- if method_name =~ COMPILABLE_REGEXP
- defn = "def #{method_name}(*args)"
- else
- defn = "define_method(:'#{method_name}') do |*args|"
- end
-
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{defn}
- send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
- end
- RUBY
+ define_optimized_call generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s
end
end
end
@@ -342,11 +322,11 @@ module ActiveModel
# used to alleviate the GC, which ultimately also speeds up the app
# significantly (in our case our test suite finishes 10% faster with
# this cache).
- def attribute_method_matchers_cache
+ def attribute_method_matchers_cache #:nodoc:
@attribute_method_matchers_cache ||= {}
end
- def attribute_method_matcher(method_name)
+ def attribute_method_matcher(method_name) #:nodoc:
if attribute_method_matchers_cache.key?(method_name)
attribute_method_matchers_cache[method_name]
else
@@ -359,6 +339,31 @@ module ActiveModel
end
end
+ # Define a method `name` in `mod` that dispatches to `send`
+ # using the given `extra` args. This fallbacks `define_method`
+ # and `send` if the given names cannot be compiled.
+ def define_optimized_call(mod, name, send, *extra) #:nodoc:
+ if name =~ NAME_COMPILABLE_REGEXP
+ defn = "def #{name}(*args)"
+ else
+ defn = "define_method(:'#{name}') do |*args|"
+ end
+
+ extra = (extra.map(&:inspect) << "*args").join(", ")
+
+ if send =~ CALL_COMPILABLE_REGEXP
+ target = "#{send}(#{extra})"
+ else
+ target = "send(:'#{send}', #{extra})"
+ end
+
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{defn}
+ #{target}
+ end
+ RUBY
+ end
+
class AttributeMethodMatcher
attr_reader :prefix, :suffix, :method_missing_target