diff options
author | José Valim <jose.valim@gmail.com> | 2011-07-18 06:46:31 -0700 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2011-07-18 06:46:31 -0700 |
commit | 44e83ac341809ab0f4154c71fc5232380a95ec07 (patch) | |
tree | 49cf2943c6411123938ba32fd1459d7cc05ed52b | |
parent | 50941ec07ccea65757c0c9884bedfc9ff8af193a (diff) | |
parent | 52a096275a32c0c5d5125280f144e1e0d893d1f3 (diff) | |
download | rails-44e83ac341809ab0f4154c71fc5232380a95ec07.tar.gz rails-44e83ac341809ab0f4154c71fc5232380a95ec07.tar.bz2 rails-44e83ac341809ab0f4154c71fc5232380a95ec07.zip |
Merge pull request #2075 from lawrencepit/match_attribute_method
Optimization of ActiveModel's match_attribute_method?
-rw-r--r-- | activemodel/lib/active_model/attribute_methods.rb | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 6ee5e04267..bdc0eb4a0d 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -314,6 +314,7 @@ module ActiveModel end end end + attribute_method_matchers_cache.clear end # Removes all the previously dynamically defined methods from the class @@ -321,6 +322,7 @@ module ActiveModel generated_attribute_methods.module_eval do instance_methods.each { |m| undef_method(m) } end + attribute_method_matchers_cache.clear end # Returns true if the attribute methods defined have been generated. @@ -338,6 +340,29 @@ module ActiveModel end private + # The methods +method_missing+ and +respond_to?+ of this module are + # invoked often in a typical rails, both of which invoke the method + # +match_attribute_method?+. The latter method iterates through an + # array doing regular expression matches, which results in a lot of + # object creations. Most of the times it returns a +nil+ match. As the + # match result is always the same given a +method_name+, this cache is + # 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 + @attribute_method_matchers_cache ||= {} + end + + def attribute_method_matcher(method_name) + if attribute_method_matchers_cache.key?(method_name) + attribute_method_matchers_cache[method_name] + else + match = nil + attribute_method_matchers.detect { |method| match = method.match(method_name) } + attribute_method_matchers_cache[method_name] = match + end + end + class AttributeMethodMatcher attr_reader :prefix, :suffix, :method_missing_target @@ -411,12 +436,8 @@ module ActiveModel # Returns a struct representing the matching attribute method. # The struct's attributes are prefix, base and suffix. def match_attribute_method?(method_name) - self.class.attribute_method_matchers.each do |method| - if (match = method.match(method_name)) && attribute_method?(match.attr_name) - return match - end - end - nil + match = self.class.send(:attribute_method_matcher, method_name) + match && attribute_method?(match.attr_name) ? match : nil end # prevent method_missing from calling private methods with #send |