aboutsummaryrefslogtreecommitdiffstats
path: root/activeresource
diff options
context:
space:
mode:
Diffstat (limited to 'activeresource')
-rw-r--r--activeresource/examples/performance.rb70
-rw-r--r--activeresource/lib/active_resource/base.rb39
-rw-r--r--activeresource/lib/active_resource/http_mock.rb14
-rw-r--r--activeresource/lib/active_resource/observing.rb8
-rw-r--r--activeresource/lib/active_resource/validations.rb10
-rw-r--r--activeresource/lib/active_resource/version.rb2
-rw-r--r--activeresource/test/connection_test.rb2
7 files changed, 118 insertions, 27 deletions
diff --git a/activeresource/examples/performance.rb b/activeresource/examples/performance.rb
new file mode 100644
index 0000000000..e4df7a38a4
--- /dev/null
+++ b/activeresource/examples/performance.rb
@@ -0,0 +1,70 @@
+require 'rubygems'
+require 'active_resource'
+require 'benchmark'
+
+TIMES = (ENV['N'] || 10_000).to_i
+
+# deep nested resource
+attrs = {
+ :id => 1,
+ :name => 'Luis',
+ :age => 21,
+ :friends => [
+ {
+ :name => 'JK',
+ :age => 24,
+ :colors => ['red', 'green', 'blue'],
+ :brothers => [
+ {
+ :name => 'Mateo',
+ :age => 35,
+ :children => [{ :name => 'Edith', :age => 5 }, { :name => 'Martha', :age => 4 }]
+ },
+ {
+ :name => 'Felipe',
+ :age => 33,
+ :children => [{ :name => 'Bryan', :age => 1 }, { :name => 'Luke', :age => 0 }]
+ }
+ ]
+ },
+ {
+ :name => 'Eduardo',
+ :age => 20,
+ :colors => [],
+ :brothers => [
+ {
+ :name => 'Sebas',
+ :age => 23,
+ :children => [{ :name => 'Andres', :age => 0 }, { :name => 'Jorge', :age => 2 }]
+ },
+ {
+ :name => 'Elsa',
+ :age => 19,
+ :children => [{ :name => 'Natacha', :age => 1 }]
+ },
+ {
+ :name => 'Milena',
+ :age => 16,
+ :children => []
+ }
+ ]
+ }
+ ]
+}
+
+class Customer < ActiveResource::Base
+ self.site = "http://37s.sunrise.i:3000"
+end
+
+module Nested
+ class Customer < ActiveResource::Base
+ self.site = "http://37s.sunrise.i:3000"
+ end
+end
+
+Benchmark.bm(40) do |x|
+ x.report('Model.new (instantiation)') { TIMES.times { Customer.new } }
+ x.report('Nested::Model.new (instantiation)') { TIMES.times { Nested::Customer.new } }
+ x.report('Model.new (setting attributes)') { TIMES.times { Customer.new attrs } }
+ x.report('Nested::Model.new (setting attributes)') { TIMES.times { Nested::Customer.new attrs } }
+end
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
diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb
index e085a05f6d..3bfd536b29 100644
--- a/activeresource/lib/active_resource/http_mock.rb
+++ b/activeresource/lib/active_resource/http_mock.rb
@@ -9,8 +9,8 @@ module ActiveResource
# requests.
#
# To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to
- # method with an attached block. The block declares a set of URIs with expected input, and the output
- # each request should return. The passed in block has any number of entries in the following generalized
+ # method with an attached block. The block declares a set of URIs with expected input, and the output
+ # each request should return. The passed in block has any number of entries in the following generalized
# format:
#
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
@@ -29,7 +29,7 @@ module ActiveResource
# <tt>request_headers</tt> listed above.
#
# In order for a mock to deliver its content, the incoming request must match by the <tt>http_method</tt>,
- # +path+ and <tt>request_headers</tt>. If no match is found an InvalidRequestError exception
+ # +path+ and <tt>request_headers</tt>. If no match is found an +InvalidRequestError+ exception
# will be raised showing you what request it could not find a response for and also what requests and response
# pairs have been recorded so you can create a new mock for that request.
#
@@ -80,7 +80,7 @@ module ActiveResource
class << self
- # Returns an array of all request objects that have been sent to the mock. You can use this to check
+ # Returns an array of all request objects that have been sent to the mock. You can use this to check
# if your model actually sent an HTTP request.
#
# ==== Example
@@ -105,7 +105,7 @@ module ActiveResource
end
# Returns the list of requests and their mocked responses. Look up a
- # response for a request using responses.assoc(request).
+ # response for a request using <tt>responses.assoc(request)</tt>.
def responses
@@responses ||= []
end
@@ -299,6 +299,8 @@ module ActiveResource
end
end
+ # Returns true if code is 2xx,
+ # false otherwise.
def success?
code.in?(200..299)
end
@@ -311,6 +313,8 @@ module ActiveResource
headers[key] = value
end
+ # Returns true if the other is a Response with an equal body, equal message
+ # and equal headers. Otherwise it returns false.
def ==(other)
if (other.is_a?(Response))
other.body == body && other.message == message && other.headers == headers
diff --git a/activeresource/lib/active_resource/observing.rb b/activeresource/lib/active_resource/observing.rb
index 3c74d49c80..1bfceb8dc8 100644
--- a/activeresource/lib/active_resource/observing.rb
+++ b/activeresource/lib/active_resource/observing.rb
@@ -5,6 +5,14 @@ module ActiveResource
included do
%w( create save update destroy ).each do |method|
+ # def create_with_notifications(*args, &block)
+ # notify_observers(:before_create)
+ # if result = create_without_notifications(*args, &block)
+ # notify_observers(:after_create)
+ # end
+ # result
+ # end
+ # alias_method_chain(create, :notifications)
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{method}_with_notifications(*args, &block)
notify_observers(:before_#{method})
diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb
index a373e53f11..ca265d053e 100644
--- a/activeresource/lib/active_resource/validations.rb
+++ b/activeresource/lib/active_resource/validations.rb
@@ -8,9 +8,9 @@ module ActiveResource
# Active Resource validation is reported to and from this object, which is used by Base#save
# to determine whether the object in a valid state to be saved. See usage example in Validations.
class Errors < ActiveModel::Errors
- # Grabs errors from an array of messages (like ActiveRecord::Validations)
+ # Grabs errors from an array of messages (like ActiveRecord::Validations).
# The second parameter directs the errors cache to be cleared (default)
- # or not (by passing true)
+ # or not (by passing true).
def from_array(messages, save_cache = false)
clear unless save_cache
humanized_attributes = Hash[@base.attributes.keys.map { |attr_name| [attr_name.humanize, attr_name] }]
@@ -73,7 +73,7 @@ module ActiveResource
# clear the remote validations so they don't interfere with the local
# ones. Otherwise we get an endless loop and can never change the
- # fields so as to make the resource valid
+ # fields so as to make the resource valid.
@remote_errors = nil
if perform_validation && valid? || !perform_validation
save_without_validation
@@ -84,7 +84,7 @@ module ActiveResource
rescue ResourceInvalid => error
# cache the remote errors because every call to <tt>valid?</tt> clears
# all errors. We must keep a copy to add these back after local
- # validations
+ # validations.
@remote_errors = error
load_remote_errors(@remote_errors, true)
false
@@ -92,7 +92,7 @@ module ActiveResource
# Loads the set of remote errors into the object's Errors based on the
- # content-type of the error-block received
+ # content-type of the error-block received.
def load_remote_errors(remote_errors, save_cache = false ) #:nodoc:
case self.class.format
when ActiveResource::Formats[:xml]
diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb
index 82dcb5d575..f26e2312b9 100644
--- a/activeresource/lib/active_resource/version.rb
+++ b/activeresource/lib/active_resource/version.rb
@@ -3,7 +3,7 @@ module ActiveResource
MAJOR = 3
MINOR = 1
TINY = 0
- PRE = "beta"
+ PRE = "beta1"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
diff --git a/activeresource/test/connection_test.rb b/activeresource/test/connection_test.rb
index 6e79845aa0..7c36393cf2 100644
--- a/activeresource/test/connection_test.rb
+++ b/activeresource/test/connection_test.rb
@@ -50,7 +50,7 @@ class ConnectionTest < Test::Unit::TestCase
# 404 is a missing resource.
assert_response_raises ActiveResource::ResourceNotFound, 404
- # 405 is a missing not allowed error
+ # 405 is a method not allowed error
assert_response_raises ActiveResource::MethodNotAllowed, 405
# 409 is an optimistic locking error