From a962bfe47232200c20dce02047201247d24d77f7 Mon Sep 17 00:00:00 2001 From: Chris Griego Date: Sun, 1 May 2011 23:05:42 -0500 Subject: Optimize ActiveResource::Base.new(attributes) * Add performance benchmark similar to ActiveRecord * Lazily find_or_create_resource_for_collection to not incur the overhead for empty arrays and arrays of primatives * #duplicable? is faster than inline rescues when the object is not duplicable * Don't constantly raise and handle NameError, raising is expensive * Even when a resource is nested inside a module, always look inside the class first for the resource definition so we don't overwrite classes all the time Before: user system total real Model.new (instantiation) 0.120000 0.000000 0.120000 ( 0.119961) Nested::Model.new (instantiation) 0.150000 0.010000 0.160000 ( 0.151183) Model.new (setting attributes) 28.540000 0.680000 29.220000 ( 29.271775) Nested::Model.new (setting attributes) 29.740000 0.580000 30.320000 ( 30.486210) After: user system total real Model.new (instantiation) 0.120000 0.000000 0.120000 ( 0.121249) Nested::Model.new (instantiation) 0.150000 0.010000 0.160000 ( 0.152429) Model.new (setting attributes) 11.480000 0.170000 11.650000 ( 11.656163) Nested::Model.new (setting attributes) 11.510000 0.210000 11.720000 ( 11.724249) --- activeresource/lib/active_resource/base.rb | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'activeresource/lib') diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 160763779e..7f2a844723 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -1239,9 +1239,10 @@ module ActiveResource @attributes[key.to_s] = case value when Array - resource = find_or_create_resource_for_collection(key) + resource = nil value.map do |attrs| if attrs.is_a?(Hash) + resource ||= find_or_create_resource_for_collection(key) resource.new(attrs) else attrs.duplicable? ? attrs.dup : attrs @@ -1251,7 +1252,7 @@ module ActiveResource resource = find_or_create_resource_for(key) resource.new(value) else - value.dup rescue value + value.duplicable? ? value.dup : value end end self @@ -1367,36 +1368,44 @@ module ActiveResource end # Tries to find a resource in a non empty list of nested modules - # Raises a NameError if it was not found in any of the given nested modules - def find_resource_in_modules(resource_name, module_names) + # if it fails, then the resource is created + def find_or_create_resource_in_modules(resource_name, module_names) receiver = Object namespaces = module_names[0, module_names.size-1].map do |module_name| receiver = receiver.const_get(module_name) end const_args = RUBY_VERSION < "1.9" ? [resource_name] : [resource_name, false] if namespace = namespaces.reverse.detect { |ns| ns.const_defined?(*const_args) } - return namespace.const_get(*const_args) + namespace.const_get(*const_args) else - raise NameError + create_resource_for(resource_name) end end # Tries to find a resource for a given name; if it fails, then the resource is created def find_or_create_resource_for(name) resource_name = name.to_s.camelize - ancestors = self.class.name.split("::") - if ancestors.size > 1 - find_resource_in_modules(resource_name, ancestors) - else - self.class.const_get(resource_name) - end - rescue NameError + const_args = RUBY_VERSION < "1.9" ? [resource_name] : [resource_name, false] if self.class.const_defined?(*const_args) - resource = self.class.const_get(*const_args) + self.class.const_get(*const_args) else - resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) + ancestors = self.class.name.split("::") + if ancestors.size > 1 + find_or_create_resource_in_modules(resource_name, ancestors) + else + if Object.const_defined?(*const_args) + Object.const_get(*const_args) + else + create_resource_for(resource_name) + end + end end + end + + # Create and return a class definition for a resource inside the current resource + def create_resource_for(resource_name) + resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base)) resource.prefix = self.class.prefix resource.site = self.class.site resource -- cgit v1.2.3