diff -Nru ruby-activeresource-2.3.14/CHANGELOG ruby-activeresource-3.1.0/CHANGELOG
--- ruby-activeresource-2.3.14/CHANGELOG 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/CHANGELOG 2011-09-29 12:26:03.000000000 +0000
@@ -1,27 +1,50 @@
-*2.3.11 (February 9, 2011)*
-*2.3.10 (October 15, 2010)*
-*2.3.9 (September 4, 2010)*
-*2.3.8 (May 24, 2010)*
-*2.3.7 (May 24, 2010)*
+*Rails 3.1.0 (unreleased)*
-* Version bump.
+* The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set `self.format = :xml` in the class. eg.
+class User < ActiveResource::Base
+ self.format = :xml
+end
-*2.3.6 (May 23, 2010)*
-* No changes, just a version bump.
+*Rails 3.0.7 (April 18, 2011)*
+* No changes.
-*2.3.5 (November 25, 2009)*
-* Minor Bug Fixes and deprecation warnings
+*Rails 3.0.6 (April 5, 2011)
-* More flexible content type handling when parsing responses.
-
- Ensures that ARes will handle responses like test/xml, or content types
- with charsets included.
+* No changes.
-*2.3.4 (September 4, 2009)*
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
+
+* No changes
+
+
+*Rails 3.0.1 (October 15, 2010)*
+
+* No Changes, just a version bump.
+
+
+*Rails 3.0.0 (August 29, 2010)*
+
+* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. [Santiago Pastorino]
* Add support for errors in JSON format. #1956 [Fabien Jakimowicz]
@@ -32,11 +55,6 @@
* HTTP proxy support. #2133 [Marshall Huss, Sébastien Dabet]
-*2.3.3 (July 12, 2009)*
-
-* No changes, just a version bump.
-
-
*2.3.2 [Final] (March 15, 2009)*
* Nothing new, just included in 2.3.2
@@ -81,14 +99,14 @@
* Ruby 1.9 compatibility. [Jeremy Kemper]
-*2.0.2* (December 16th, 2007)
+*2.0.2 (December 16th, 2007)*
* Added more specific exceptions for 400, 401, and 403 (all descending from ClientError so existing rescues will work) #10326 [trek]
* Correct empty response handling. #10445 [seangeo]
-*2.0.1* (December 7th, 2007)
+*2.0.1 (December 7th, 2007)*
* Don't cache net/http object so that ActiveResource is more thread-safe. Closes #10142 [kou]
@@ -100,7 +118,7 @@
ActiveResource::HttpMock.respond_to do |mock|
mock.get "/people/1.xml", {}, "David"
end
-
+
Now:
ActiveResource::HttpMock.respond_to.get "/people/1.xml", {}, "David"
@@ -110,14 +128,14 @@
self.site = "http://app/"
self.format = :json
end
-
+
person = Person.find(1) # => GET http://app/people/1.json
person.name = "David"
person.save # => PUT http://app/people/1.json {name: "David"}
-
+
Person.format = :xml
person.name = "Mary"
- person.save # => PUT http://app/people/1.json Mary
+ person.save # => PUT http://app/people/1.json Mary
* Fix reload error when path prefix is used. #8727 [Ian Warshak]
@@ -146,7 +164,7 @@
class Project
headers['X-Token'] = 'foo'
end
-
+
# makes the GET request with the custom X-Token header
Project.find(:all)
@@ -169,7 +187,7 @@
end
assert_kind_of Highrise::Comment, Note.find(1).comments.first
-
+
* Added load_attributes_from_response as a way of loading attributes from other responses than just create [David Heinemeier Hansson]
@@ -261,8 +279,8 @@
* Basic validation support [Rick Olson]
- Parses the xml response of ActiveRecord::Errors#to_xml with a similar interface to ActiveRecord::Errors.
-
+ Parses the xml response of ActiveRecord::Errors#to_xml with a similar interface to ActiveRecord::Errors.
+
render :xml => @person.errors.to_xml, :status => '400 Validation Error'
* Deep hashes are converted into collections of resources. [Jeremy Kemper]
@@ -280,12 +298,12 @@
* Add support for specifying prefixes.
* Allow overriding of element_name, collection_name, and primary key
* Provide simpler HTTP mock interface for testing
-
+
# rails routing code
map.resources :posts do |post|
post.resources :comments
end
-
+
# ActiveResources
class Post < ActiveResource::Base
self.site = "http://37s.sunrise.i:3000/"
@@ -294,7 +312,7 @@
class Comment < ActiveResource::Base
self.site = "http://37s.sunrise.i:3000/posts/:post_id/"
end
-
+
@post = Post.find 5
@comments = Comment.find :all, :post_id => @post.id
diff -Nru ruby-activeresource-2.3.14/debian/changelog ruby-activeresource-3.1.0/debian/changelog
--- ruby-activeresource-2.3.14/debian/changelog 2011-09-29 15:00:39.000000000 +0000
+++ ruby-activeresource-3.1.0/debian/changelog 2011-09-29 15:07:08.000000000 +0000
@@ -1,6 +1,7 @@
-ruby-activeresource (2.3.14-1) oneiric; urgency=low
+ruby-activeresource (3.1.0-1) oneiric; urgency=low
* Initial release (Closes: #nnnn)
*
- -- Mark Mims Thu, 29 Sep 2011 09:00:15 -0600
+
+ -- Mark Mims Thu, 29 Sep 2011 09:07:01 -0600
diff -Nru ruby-activeresource-2.3.14/debian/control ruby-activeresource-3.1.0/debian/control
--- ruby-activeresource-2.3.14/debian/control 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/debian/control 2011-09-29 12:26:03.000000000 +0000
@@ -15,6 +15,6 @@
Architecture: all
XB-Ruby-Versions: ${ruby:Versions}
Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter
-# activesupport (= 2.3.14)
-Description: Think Active Record for web resources.
- Wraps web resources in model classes that can be manipulated through XML over REST.
+# activesupport (= 3.1.0), activemodel (= 3.1.0)
+Description: REST modeling framework (part of Rails).
+ REST on Rails. Wrap your RESTful web app with Ruby classes and work with them like Active Record models.
diff -Nru ruby-activeresource-2.3.14/debian/ruby-activeresource.docs ruby-activeresource-3.1.0/debian/ruby-activeresource.docs
--- ruby-activeresource-2.3.14/debian/ruby-activeresource.docs 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/debian/ruby-activeresource.docs 2011-09-29 12:26:03.000000000 +0000
@@ -1,2 +1,2 @@
# FIXME: READMEs found
-# README
+# README.rdoc
diff -Nru ruby-activeresource-2.3.14/debian/ruby-activeresource.examples ruby-activeresource-3.1.0/debian/ruby-activeresource.examples
--- ruby-activeresource-2.3.14/debian/ruby-activeresource.examples 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/debian/ruby-activeresource.examples 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,3 @@
+# FIXME: examples/ dir found in source. Consider installing the examples.
+# Examples:
+# examples/*
diff -Nru ruby-activeresource-2.3.14/debian/ruby-tests.rb ruby-activeresource-3.1.0/debian/ruby-tests.rb
--- ruby-activeresource-2.3.14/debian/ruby-tests.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/debian/ruby-tests.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-# FIXME
-# there's a spec/ or a test/ directory in the upstream source, but
-# no test suite was defined in the Gem specification. It would be
-# a good idea to define it here so the package gets tested at build time.
-# Examples:
-# $: << 'lib' << '.'
-# Dir['{spec,test}/**/*.rb'].each { |f| require f }
-#
-# require 'test/ts_foo.rb'
-#
-# require 'rbconfig'
-# ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
-# exec("#{ruby} -I. test/runtests.rb")
diff -Nru ruby-activeresource-2.3.14/examples/performance.rb ruby-activeresource-3.1.0/examples/performance.rb
--- ruby-activeresource-2.3.14/examples/performance.rb 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/examples/performance.rb 2011-09-29 12:26:03.000000000 +0000
@@ -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 -Nru ruby-activeresource-2.3.14/lib/active_resource/base.rb ruby-activeresource-3.1.0/lib/active_resource/base.rb
--- ruby-activeresource-2.3.14/lib/active_resource/base.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/base.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,11 +1,27 @@
-require 'active_resource/connection'
-require 'cgi'
+require 'active_support'
+require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/hash/indifferent_access'
+require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/module/delegation'
+require 'active_support/core_ext/module/aliasing'
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/to_query'
+require 'active_support/core_ext/object/duplicable'
require 'set'
+require 'uri'
+
+require 'active_support/core_ext/uri'
+require 'active_resource/exceptions'
+require 'active_resource/connection'
+require 'active_resource/formats'
+require 'active_resource/schema'
+require 'active_resource/log_subscriber'
module ActiveResource
# ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application.
#
- # For an outline of what Active Resource is capable of, see link:files/vendor/rails/activeresource/README.html.
+ # For an outline of what Active Resource is capable of, see its {README}[link:files/activeresource/README_rdoc.html].
#
# == Automated mapping
#
@@ -19,7 +35,7 @@
# end
#
# Now the Person class is mapped to RESTful resources located at http://api.people.com:3000/people/, and
- # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
+ # you can now use Active Resource's life cycle methods to manipulate resources. In the case where you already have
# an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
#
# class PersonResource < ActiveResource::Base
@@ -27,8 +43,15 @@
# self.element_name = "person"
# end
#
+ # If your Active Resource object is required to use an HTTP proxy you can set the +proxy+ value which holds a URI.
+ #
+ # class PersonResource < ActiveResource::Base
+ # self.site = "http://api.people.com:3000/"
+ # self.proxy = "http://user:password@proxy.people.com:8080"
+ # end
+ #
#
- # == Lifecycle methods
+ # == Life cycle methods
#
# Active Resource exposes methods for creating, finding, updating, and deleting resources
# from REST web services.
@@ -47,29 +70,29 @@
#
# ryan.destroy # => true
#
- # As you can see, these are very similar to Active Record's lifecycle methods for database records.
+ # As you can see, these are very similar to Active Record's life cycle methods for database records.
# You can read more about each of these methods in their respective documentation.
#
# === Custom REST methods
#
- # Since simple CRUD/lifecycle methods can't accomplish every task, Active Resource also supports
+ # Since simple CRUD/life cycle methods can't accomplish every task, Active Resource also supports
# defining your own custom REST methods. To invoke them, Active Resource provides the get,
# post, put and \delete methods where you can specify a custom REST method
# name to invoke.
#
- # # POST to the custom 'register' REST method, i.e. POST /people/new/register.xml.
+ # # POST to the custom 'register' REST method, i.e. POST /people/new/register.json.
# Person.new(:name => 'Ryan').post(:register)
# # => { :id => 1, :name => 'Ryan', :position => 'Clerk' }
#
- # # PUT an update by invoking the 'promote' REST method, i.e. PUT /people/1/promote.xml?position=Manager.
+ # # PUT an update by invoking the 'promote' REST method, i.e. PUT /people/1/promote.json?position=Manager.
# Person.find(1).put(:promote, :position => 'Manager')
# # => { :id => 1, :name => 'Ryan', :position => 'Manager' }
#
- # # GET all the positions available, i.e. GET /people/positions.xml.
+ # # GET all the positions available, i.e. GET /people/positions.json.
# Person.get(:positions)
# # => [{:name => 'Manager'}, {:name => 'Clerk'}]
#
- # # DELETE to 'fire' a person, i.e. DELETE /people/1/fire.xml.
+ # # DELETE to 'fire' a person, i.e. DELETE /people/1/fire.json.
# Person.find(1).delete(:fire)
#
# For more information on using custom REST methods, see the
@@ -127,6 +150,7 @@
# :verify_mode => OpenSSL::SSL::VERIFY_PEER}
# end
#
+ #
# == Errors & Validation
#
# Error handling and validation is handled in much the same manner as you're used to seeing in
@@ -139,12 +163,13 @@
# response code will be returned from the server which will raise an ActiveResource::ResourceNotFound
# exception.
#
- # # GET http://api.people.com:3000/people/999.xml
+ # # GET http://api.people.com:3000/people/999.json
# ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
#
+ #
# 404 is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
# following HTTP response codes will also result in these exceptions:
- #
+ #
# * 200..399 - Valid response, no exception (other than 301, 302)
# * 301, 302 - ActiveResource::Redirection
# * 400 - ActiveResource::BadRequest
@@ -170,9 +195,19 @@
# redirect_to :action => 'new'
# end
#
+ # When a GET is requested for a nested resource and you don't provide the prefix_param
+ # an ActiveResource::MissingPrefixParam will be raised.
+ #
+ # class Comment < ActiveResource::Base
+ # self.site = "http://someip.com/posts/:post_id/"
+ # end
+ #
+ # Comment.find(1)
+ # # => ActiveResource::MissingPrefixParam: post_id prefix_option is missing
+ #
# === Validation errors
#
- # Active Resource supports validations on resources and will return errors if any these validations fail
+ # Active Resource supports validations on resources and will return errors if any of these validations fail
# (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
# a response code of 422 and an XML or JSON representation of the validation errors. The save operation will
# then fail (with a false return value) and the validation errors can be accessed on the resource in question.
@@ -182,13 +217,13 @@
# ryan.save # => false
#
# # When
- # # PUT http://api.people.com:3000/people/1.xml
+ # # PUT http://api.people.com:3000/people/1.json
# # or
# # PUT http://api.people.com:3000/people/1.json
# # is requested with invalid values, the response is:
# #
# # Response (422):
- # # First cannot be empty
+ # # First cannot be empty
# # or
# # {"errors":["First cannot be empty"]}
# #
@@ -227,10 +262,127 @@
# The logger for diagnosing and tracing Active Resource calls.
cattr_accessor :logger
- # Controls the top-level behavior of JSON serialization
- cattr_accessor :include_root_in_json, :instance_writer => false
+ class_attribute :_format
class << self
+ # Creates a schema for this resource - setting the attributes that are
+ # known prior to fetching an instance from the remote system.
+ #
+ # The schema helps define the set of known_attributes of the
+ # current resource.
+ #
+ # There is no need to specify a schema for your Active Resource. If
+ # you do not, the known_attributes will be guessed from the
+ # instance attributes returned when an instance is fetched from the
+ # remote system.
+ #
+ # example:
+ # class Person < ActiveResource::Base
+ # schema do
+ # # define each attribute separately
+ # attribute 'name', :string
+ #
+ # # or use the convenience methods and pass >=1 attribute names
+ # string 'eye_colour', 'hair_colour'
+ # integer 'age'
+ # float 'height', 'weight'
+ #
+ # # unsupported types should be left as strings
+ # # overload the accessor methods if you need to convert them
+ # attribute 'created_at', 'string'
+ # end
+ # end
+ #
+ # p = Person.new
+ # p.respond_to? :name # => true
+ # p.respond_to? :age # => true
+ # p.name # => nil
+ # p.age # => nil
+ #
+ # j = Person.find_by_name('John') # John343
+ # j.respond_to? :name # => true
+ # j.respond_to? :age # => true
+ # j.name # => 'John'
+ # j.age # => '34' # note this is a string!
+ # j.num_children # => '3' # note this is a string!
+ #
+ # p.num_children # => NoMethodError
+ #
+ # Attribute-types must be one of:
+ # string, integer, float
+ #
+ # Note: at present the attribute-type doesn't do anything, but stay
+ # tuned...
+ # Shortly it will also *cast* the value of the returned attribute.
+ # ie:
+ # j.age # => 34 # cast to an integer
+ # j.weight # => '65' # still a string!
+ #
+ def schema(&block)
+ if block_given?
+ schema_definition = Schema.new
+ schema_definition.instance_eval(&block)
+
+ # skip out if we didn't define anything
+ return unless schema_definition.attrs.present?
+
+ @schema ||= {}.with_indifferent_access
+ @known_attributes ||= []
+
+ schema_definition.attrs.each do |k,v|
+ @schema[k] = v
+ @known_attributes << k
+ end
+
+ schema
+ else
+ @schema ||= nil
+ end
+ end
+
+ # Alternative, direct way to specify a schema for this
+ # Resource. schema is more flexible, but this is quick
+ # for a very simple schema.
+ #
+ # Pass the schema as a hash with the keys being the attribute-names
+ # and the value being one of the accepted attribute types (as defined
+ # in schema)
+ #
+ # example:
+ #
+ # class Person < ActiveResource::Base
+ # schema = {'name' => :string, 'age' => :integer }
+ # end
+ #
+ # The keys/values can be strings or symbols. They will be converted to
+ # strings.
+ #
+ def schema=(the_schema)
+ unless the_schema.present?
+ # purposefully nulling out the schema
+ @schema = nil
+ @known_attributes = []
+ return
+ end
+
+ raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash
+
+ schema do
+ the_schema.each {|k,v| attribute(k,v) }
+ end
+ end
+
+ # Returns the list of known attributes for this resource, gathered
+ # from the provided schema
+ # Attributes that are known will cause your resource to return 'true'
+ # when respond_to? is called on them. A known attribute will
+ # return nil if not set (rather than MethodNotFound); thus
+ # known attributes can be used with validates_presence_of
+ # without a getter-method.
+ def known_attributes
+ @known_attributes ||= []
+ end
+
# Gets the URI of the REST resources to map for this class. The site variable is required for
# Active Resource's mapping to work.
def site
@@ -243,7 +395,7 @@
# Subclass.site.user = 'david'
# Parent.site # => 'http://david@test.com'
#
- # Without superclass_delegating_reader (expected behaviour)
+ # Without superclass_delegating_reader (expected behavior)
#
# Parent.site = 'http://anonymous@test.com'
# Subclass.site # => 'http://anonymous@test.com'
@@ -264,8 +416,8 @@
@site = nil
else
@site = create_site_uri_from(site)
- @user = URI.decode(@site.user) if @site.user
- @password = URI.decode(@site.password) if @site.password
+ @user = URI.parser.unescape(@site.user) if @site.user
+ @password = URI.parser.unescape(@site.password) if @site.password
end
end
@@ -317,6 +469,17 @@
@password = password
end
+ def auth_type
+ if defined?(@auth_type)
+ @auth_type
+ end
+ end
+
+ def auth_type=(auth_type)
+ @connection = nil
+ @auth_type = auth_type
+ end
+
# Sets the format that attributes are sent and received in from a mime type reference:
#
# Person.format = :json
@@ -325,18 +488,18 @@
# Person.format = ActiveResource::Formats::XmlFormat
# Person.find(1) # => GET /people/1.xml
#
- # Default format is :xml.
+ # Default format is :json.
def format=(mime_type_reference_or_format)
format = mime_type_reference_or_format.is_a?(Symbol) ?
ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
- write_inheritable_attribute(:format, format)
+ self._format = format
connection.format = format if site
end
- # Returns the current format, default is ActiveResource::Formats::XmlFormat.
+ # Returns the current format, default is ActiveResource::Formats::JsonFormat.
def format
- read_inheritable_attribute(:format) || ActiveResource::Formats[:xml]
+ self._format || ActiveResource::Formats::JsonFormat
end
# Sets the number of seconds after which requests to the REST API should time out.
@@ -358,9 +521,9 @@
#
# * :key - An OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
# * :cert - An OpenSSL::X509::Certificate object as client certificate
- # * :ca_file - Path to a CA certification file in PEM format. The file can contrain several CA certificates.
+ # * :ca_file - Path to a CA certification file in PEM format. The file can contain several CA certificates.
# * :ca_path - Path of a CA certification directory containing certifications in PEM format.
- # * :verify_mode - Flags for server the certification verification at begining of SSL/TLS session. (OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable)
+ # * :verify_mode - Flags for server the certification verification at beginning of SSL/TLS session. (OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable)
# * :verify_callback - The verify callback for the server certification verification.
# * :verify_depth - The maximum depth for the certificate chain verification.
# * :cert_store - OpenSSL::X509::Store to verify peer certificate.
@@ -388,6 +551,7 @@
@connection.proxy = proxy if proxy
@connection.user = user if user
@connection.password = password if password
+ @connection.auth_type = auth_type if auth_type
@connection.timeout = timeout if timeout
@connection.ssl_options = ssl_options if ssl_options
@connection
@@ -400,14 +564,25 @@
@headers ||= {}
end
- # Do not include any modules in the default element name. This makes it easier to seclude ARes objects
- # in a separate namespace without having to set element_name repeatedly.
- attr_accessor_with_default(:element_name) { to_s.split("::").last.underscore } #:nodoc:
-
- attr_accessor_with_default(:collection_name) { element_name.pluralize } #:nodoc:
- attr_accessor_with_default(:primary_key, 'id') #:nodoc:
-
- # Gets the \prefix for a resource's nested URL (e.g., prefix/collectionname/1.xml)
+ attr_writer :element_name
+
+ def element_name
+ @element_name ||= model_name.element
+ end
+
+ attr_writer :collection_name
+
+ def collection_name
+ @collection_name ||= ActiveSupport::Inflector.pluralize(element_name)
+ end
+
+ attr_writer :primary_key
+
+ def primary_key
+ @primary_key ||= 'id'
+ end
+
+ # Gets the \prefix for a resource's nested URL (e.g., prefix/collectionname/1.json)
# This method is regenerated at runtime based on what the \prefix is set to.
def prefix(options={})
default = site.path
@@ -424,23 +599,24 @@
prefix_source
end
- # Sets the \prefix for a resource's nested URL (e.g., prefix/collectionname/1.xml).
+ # Sets the \prefix for a resource's nested URL (e.g., prefix/collectionname/1.json).
# Default value is site.path.
def prefix=(value = '/')
# Replace :placeholders with '#{embedded options[:lookups]}'
- prefix_call = value.gsub(/:\w+/) { |key| "\#{options[#{key}]}" }
+ prefix_call = value.gsub(/:\w+/) { |key| "\#{URI.parser.escape options[#{key}].to_s}" }
# Clear prefix parameters in case they have been cached
@prefix_parameters = nil
- # Redefine the new methods.
- code, line = <<-end_code, __LINE__ + 1
- def prefix_source() "#{value}" end
- def prefix(options={}) "#{prefix_call}" end
- end_code
- silence_warnings { instance_eval code, __FILE__, line }
- rescue
- logger.error "Couldn't set prefix: #{$!}\n #{code}"
+ silence_warnings do
+ # Redefine the new methods.
+ instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def prefix_source() "#{value}" end
+ def prefix(options={}) "#{prefix_call}" end
+ RUBY_EVAL
+ end
+ rescue Exception => e
+ logger.error "Couldn't set prefix: #{e}\n #{code}" if logger
raise
end
@@ -454,55 +630,87 @@
#
# ==== Options
# +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., :account_id => 19
- # would yield a URL like /accounts/19/purchases.xml).
+ # would yield a URL like /accounts/19/purchases.json).
# +query_options+ - A \hash to add items to the query string for the request.
#
# ==== Examples
# Post.element_path(1)
- # # => /posts/1.xml
+ # # => /posts/1.json
#
# Comment.element_path(1, :post_id => 5)
- # # => /posts/5/comments/1.xml
+ # # => /posts/5/comments/1.json
#
# Comment.element_path(1, :post_id => 5, :active => 1)
- # # => /posts/5/comments/1.xml?active=1
+ # # => /posts/5/comments/1.json?active=1
#
# Comment.element_path(1, {:post_id => 5}, {:active => 1})
- # # => /posts/5/comments/1.xml?active=1
+ # # => /posts/5/comments/1.json?active=1
#
def element_path(id, prefix_options = {}, query_options = nil)
+ check_prefix_options(prefix_options)
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
- "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
+ "#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}.#{format.extension}#{query_string(query_options)}"
+ end
+
+ # Gets the new element path for REST resources.
+ #
+ # ==== Options
+ # * +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., :account_id => 19
+ # would yield a URL like /accounts/19/purchases/new.json).
+ #
+ # ==== Examples
+ # Post.new_element_path
+ # # => /posts/new.json
+ #
+ # Comment.collection_path(:post_id => 5)
+ # # => /posts/5/comments/new.json
+ def new_element_path(prefix_options = {})
+ "#{prefix(prefix_options)}#{collection_name}/new.#{format.extension}"
end
# Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
# will split from the +prefix_options+.
#
# ==== Options
- # * +prefix_options+ - A hash to add a prefix to the request for nested URL's (e.g., :account_id => 19
- # would yield a URL like /accounts/19/purchases.xml).
+ # * +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., :account_id => 19
+ # would yield a URL like /accounts/19/purchases.json).
# * +query_options+ - A hash to add items to the query string for the request.
#
# ==== Examples
# Post.collection_path
- # # => /posts.xml
+ # # => /posts.json
#
# Comment.collection_path(:post_id => 5)
- # # => /posts/5/comments.xml
+ # # => /posts/5/comments.json
#
# Comment.collection_path(:post_id => 5, :active => 1)
- # # => /posts/5/comments.xml?active=1
+ # # => /posts/5/comments.json?active=1
#
# Comment.collection_path({:post_id => 5}, {:active => 1})
- # # => /posts/5/comments.xml?active=1
+ # # => /posts/5/comments.json?active=1
#
def collection_path(prefix_options = {}, query_options = nil)
+ check_prefix_options(prefix_options)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
end
alias_method :set_primary_key, :primary_key= #:nodoc:
+ # Builds a new, unsaved record using the default values from the remote server so
+ # that it can be used with RESTful forms.
+ #
+ # ==== Options
+ # * +attributes+ - A hash that overrides the default values from the server.
+ #
+ # Returns the new resource instance.
+ #
+ def build(attributes = {})
+ attrs = self.format.decode(connection.get("#{new_element_path}").body).merge(attributes)
+ self.new(attrs)
+ end
+
# Creates a new resource instance and makes a request to the remote service
# that it be saved, making it equivalent to the following simultaneous calls:
#
@@ -549,34 +757,47 @@
#
# ==== Examples
# Person.find(1)
- # # => GET /people/1.xml
+ # # => GET /people/1.json
#
# Person.find(:all)
- # # => GET /people.xml
+ # # => GET /people.json
#
# Person.find(:all, :params => { :title => "CEO" })
- # # => GET /people.xml?title=CEO
+ # # => GET /people.json?title=CEO
#
# Person.find(:first, :from => :managers)
- # # => GET /people/managers.xml
+ # # => GET /people/managers.json
#
# Person.find(:last, :from => :managers)
- # # => GET /people/managers.xml
+ # # => GET /people/managers.json
#
- # Person.find(:all, :from => "/companies/1/people.xml")
- # # => GET /companies/1/people.xml
+ # Person.find(:all, :from => "/companies/1/people.json")
+ # # => GET /companies/1/people.json
#
# Person.find(:one, :from => :leader)
- # # => GET /people/leader.xml
+ # # => GET /people/leader.json
#
# Person.find(:all, :from => :developers, :params => { :language => 'ruby' })
- # # => GET /people/developers.xml?language=ruby
+ # # => GET /people/developers.json?language=ruby
#
- # Person.find(:one, :from => "/companies/1/manager.xml")
- # # => GET /companies/1/manager.xml
+ # Person.find(:one, :from => "/companies/1/manager.json")
+ # # => GET /companies/1/manager.json
#
# StreetAddress.find(1, :params => { :person_id => 1 })
- # # => GET /people/1/street_addresses/1.xml
+ # # => GET /people/1/street_addresses/1.json
+ #
+ # == Failure or missing data
+ # A failure to find the requested object raises a ResourceNotFound
+ # exception if the find was called with an id.
+ # With any other scope, find returns nil when no data is returned.
+ #
+ # Person.find(1)
+ # # => raises ResourceNotFound
+ #
+ # Person.find(:all)
+ # Person.find(:first)
+ # Person.find(:last)
+ # # => nil
def find(*arguments)
scope = arguments.slice!(0)
options = arguments.slice!(0) || {}
@@ -590,6 +811,28 @@
end
end
+
+ # A convenience wrapper for find(:first, *args). You can pass
+ # in all the same arguments to this method as you can to
+ # find(:first).
+ def first(*args)
+ find(:first, *args)
+ end
+
+ # A convenience wrapper for find(:last, *args). You can pass
+ # in all the same arguments to this method as you can to
+ # find(:last).
+ def last(*args)
+ find(:last, *args)
+ end
+
+ # This is an alias for find(:all). You can pass in all the same
+ # arguments to this method as you can to find(:all)
+ def all(*args)
+ find(:all, *args)
+ end
+
+
# Deletes the resources with the ID in the +id+ parameter.
#
# ==== Options
@@ -602,7 +845,7 @@
# my_event = Event.find(:first) # let's assume this is event with ID 7
# Event.delete(my_event.id) # sends DELETE /events/7
#
- # # Let's assume a request to events/5/cancel.xml
+ # # Let's assume a request to events/5/cancel.json
# Event.delete(params[:id]) # sends DELETE /events/5
def delete(id, options = {})
connection.delete(element_path(id, options))
@@ -628,18 +871,32 @@
end
private
+
+ def check_prefix_options(prefix_options)
+ p_options = HashWithIndifferentAccess.new(prefix_options)
+ prefix_parameters.each do |p|
+ raise(MissingPrefixParam, "#{p} prefix_option is missing") if p_options[p].blank?
+ end
+ end
+
# Find every resource
def find_every(options)
- case from = options[:from]
- when Symbol
- instantiate_collection(get(from, options[:params]))
- when String
- path = "#{from}#{query_string(options[:params])}"
- instantiate_collection(connection.get(path, headers) || [])
- else
- prefix_options, query_options = split_options(options[:params])
- path = collection_path(prefix_options, query_options)
- instantiate_collection( (connection.get(path, headers) || []), prefix_options )
+ begin
+ case from = options[:from]
+ when Symbol
+ instantiate_collection(get(from, options[:params]))
+ when String
+ path = "#{from}#{query_string(options[:params])}"
+ instantiate_collection(format.decode(connection.get(path, headers).body) || [])
+ else
+ prefix_options, query_options = split_options(options[:params])
+ path = collection_path(prefix_options, query_options)
+ instantiate_collection( (format.decode(connection.get(path, headers).body) || []), prefix_options )
+ end
+ rescue ActiveResource::ResourceNotFound
+ # Swallowing ResourceNotFound exceptions and return nil - as per
+ # ActiveRecord.
+ nil
end
end
@@ -650,7 +907,7 @@
instantiate_record(get(from, options[:params]))
when String
path = "#{from}#{query_string(options[:params])}"
- instantiate_record(connection.get(path, headers))
+ instantiate_record(format.decode(connection.get(path, headers).body))
end
end
@@ -658,7 +915,7 @@
def find_single(scope, options)
prefix_options, query_options = split_options(options[:params])
path = element_path(scope, prefix_options, query_options)
- instantiate_record(connection.get(path, headers), prefix_options)
+ instantiate_record(format.decode(connection.get(path, headers).body), prefix_options)
end
def instantiate_collection(collection, prefix_options = {})
@@ -666,7 +923,7 @@
end
def instantiate_record(record, prefix_options = {})
- new(record).tap do |resource|
+ new(record, true).tap do |resource|
resource.prefix_options = prefix_options
end
end
@@ -674,12 +931,12 @@
# Accepts a URI and creates the site URI from that.
def create_site_uri_from(site)
- site.is_a?(URI) ? site.dup : URI.parse(site)
+ site.is_a?(URI) ? site.dup : URI.parser.parse(site)
end
# Accepts a URI and creates the proxy URI from that.
def create_proxy_uri_from(proxy)
- proxy.is_a?(URI) ? proxy.dup : URI.parse(proxy)
+ proxy.is_a?(URI) ? proxy.dup : URI.parser.parse(proxy)
end
# contains a set of the current prefix parameters.
@@ -709,6 +966,21 @@
attr_accessor :attributes #:nodoc:
attr_accessor :prefix_options #:nodoc:
+ # If no schema has been defined for the class (see
+ # ActiveResource::schema=), the default automatic schema is
+ # generated from the current instance's attributes
+ def schema
+ self.class.schema || self.attributes
+ end
+
+ # This is a list of known attributes for this resource. Either
+ # gathered from the provided schema, or from the attributes
+ # set on this instance after it has been fetched from the remote system.
+ def known_attributes
+ self.class.known_attributes + self.attributes.keys.map(&:to_s)
+ end
+
+
# Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
# of attributes for the \new resource.
#
@@ -720,9 +992,10 @@
#
# my_other_course = Course.new(:name => "Philosophy: Reason and Being", :lecturer => "Ralph Cling")
# my_other_course.save
- def initialize(attributes = {})
- @attributes = {}
+ def initialize(attributes = {}, persisted = false)
+ @attributes = {}.with_indifferent_access
@prefix_options = {}
+ @persisted = persisted
load(attributes)
end
@@ -748,10 +1021,7 @@
# not_ryan.hash # => {:not => "an ARes instance"}
def clone
# Clone all attributes except the pk and any nested ARes
- cloned = attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)|
- attrs[k] = v.clone
- attrs
- end
+ cloned = Hash[attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.map { |k, v| [k, v.clone] }]
# Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
# attempts to convert hashes into member objects and arrays into collections of objects. We want
# the raw objects to be cloned so we bypass load by directly setting the attributes hash.
@@ -762,7 +1032,7 @@
end
- # A method to determine if the resource a \new object (i.e., it has not been POSTed to the remote service yet).
+ # Returns +true+ if this object hasn't yet been saved, otherwise, returns +false+.
#
# ==== Examples
# not_new = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
@@ -775,10 +1045,26 @@
# is_new.new? # => false
#
def new?
- id.nil?
+ !persisted?
end
alias :new_record? :new?
+ # Returns +true+ if this object has been saved, otherwise returns +false+.
+ #
+ # ==== Examples
+ # persisted = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
+ # persisted.persisted? # => true
+ #
+ # not_persisted = Computer.new(:brand => 'IBM', :make => 'Thinkpad', :vendor => 'IBM')
+ # not_persisted.persisted? # => false
+ #
+ # not_persisted.save
+ # not_persisted.persisted? # => true
+ #
+ def persisted?
+ @persisted
+ end
+
# Gets the \id attribute of the resource.
def id
attributes[self.class.primary_key]
@@ -789,11 +1075,6 @@
attributes[self.class.primary_key] = id
end
- # Allows Active Resource objects to be used as parameters in Action Pack URL generation.
- def to_param
- id && id.to_s
- end
-
# Test for equality. Resource are equal if and only if +other+ is the same object or
# is an instance of the same class, is not new?, and has the same +id+.
#
@@ -826,12 +1107,12 @@
end
# Delegates to id in order to allow two resources of the same type and \id to work with something like:
- # [Person.find(1), Person.find(2)] & [Person.find(1), Person.find(4)] # => [Person.find(1)]
+ # [(a = Person.find 1), (b = Person.find 2)] & [(c = Person.find 1), (d = Person.find 4)] # => [a]
def hash
id.hash
end
- # Duplicate the current resource without saving it.
+ # Duplicates the current resource without saving it.
#
# ==== Examples
# my_invoice = Invoice.create(:customer => 'That Company')
@@ -850,9 +1131,9 @@
end
end
- # A method to \save (+POST+) or \update (+PUT+) a resource. It delegates to +create+ if a \new object,
- # +update+ if it is existing. If the response to the \save includes a body, it will be assumed that this body
- # is XML for the final object as it looked after the \save (which would include attributes like +created_at+
+ # Saves (+POST+) or \updates (+PUT+) a resource. Delegates to +create+ if the object is \new,
+ # +update+ if it exists. If the response to the \save includes a body, it will be assumed that this body
+ # is Json for the final object as it looked after the \save (which would include attributes like +created_at+
# that weren't part of the original submit).
#
# ==== Examples
@@ -867,6 +1148,23 @@
new? ? create : update
end
+ # Saves the resource.
+ #
+ # If the resource is new, it is created via +POST+, otherwise the
+ # existing resource is updated via +PUT+.
+ #
+ # With save! validations always run. If any of them fail
+ # ActiveResource::ResourceInvalid gets raised, and nothing is POSTed to
+ # the remote system.
+ # See ActiveResource::Validations for more information.
+ #
+ # There's a series of callbacks associated with save!. If any
+ # of the before_* callbacks return +false+ the action is
+ # cancelled and save! raises ActiveResource::ResourceInvalid.
+ def save!
+ save || raise(ResourceInvalid.new(self))
+ end
+
# Deletes the resource from the remote service.
#
# ==== Examples
@@ -903,86 +1201,11 @@
!new? && self.class.exists?(to_param, :params => prefix_options)
end
- # Converts the resource to an XML string representation.
- #
- # ==== Options
- # The +options+ parameter is handed off to the +to_xml+ method on each
- # attribute, so it has the same options as the +to_xml+ methods in
- # Active Support.
- #
- # * :indent - Set the indent level for the XML output (default is +2+).
- # * :dasherize - Boolean option to determine whether or not element names should
- # replace underscores with dashes. Default is true. The default can be set to false
- # by setting the module attribute ActiveSupport.dasherize_xml = false in an initializer. Because save
- # uses this method, and there are no options on save, then you will have to set the default if you don't
- # want underscores in element names to become dashes when the resource is saved. This is important when
- # integrating with non-Rails applications.
- # * :camelize - Boolean option to determine whether or not element names should be converted
- # to camel case, e.g some_name to SomeName. Default is false. Like :dasherize you can
- # change the default by setting the module attribute ActiveSupport.camelise_xml = true in an initializer.
- # * :skip_instruct - Toggle skipping the +instruct!+ call on the XML builder
- # that generates the XML declaration (default is false).
- #
- # ==== Examples
- # my_group = SubsidiaryGroup.find(:first)
- # my_group.to_xml
- # # =>
- # # [...]
- #
- # my_group.to_xml(:dasherize => true)
- # # =>
- # # [...]
- #
- # my_group.to_xml(:skip_instruct => true)
- # # => [...]
- def to_xml(options={})
- attributes.to_xml({:root => self.class.element_name}.merge(options))
- end
-
- # Coerces to a hash for JSON encoding.
- #
- # ==== Options
- # The +options+ are passed to the +to_json+ method on each
- # attribute, so the same options as the +to_json+ methods in
- # Active Support.
- #
- # * :only - Only include the specified attribute or list of
- # attributes in the serialized output. Attribute names must be specified
- # as strings.
- # * :except - Do not include the specified attribute or list of
- # attributes in the serialized output. Attribute names must be specified
- # as strings.
- #
- # ==== Examples
- # person = Person.new(:first_name => "Jim", :last_name => "Smith")
- # person.to_json
- # # => {"first_name": "Jim", "last_name": "Smith"}
- #
- # person.to_json(:only => ["first_name"])
- # # => {"first_name": "Jim"}
- #
- # person.to_json(:except => ["first_name"])
- # # => {"last_name": "Smith"}
- def as_json(options = nil)
- attributes.as_json(options)
- end
-
# Returns the serialized string representation of the resource in the configured
# serialization format specified in ActiveResource::Base.format. The options
# applicable depend on the configured encoding format.
def encode(options={})
- case self.class.format
- when ActiveResource::Formats[:xml]
- self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
- when ActiveResource::Formats::JsonFormat
- if ActiveResource::Base.include_root_in_json
- self.class.format.encode({self.class.element_name => attributes}, options)
- else
- self.class.format.encode(attributes, options)
- end
- else
- self.class.format.encode(attributes, options)
- end
+ send("to_#{self.class.format.extension}", options)
end
# A method to \reload the attributes of this object from the remote web service.
@@ -1021,31 +1244,69 @@
# your_supplier = Supplier.new
# your_supplier.load(my_attrs)
# your_supplier.save
- def load(attributes)
+ def load(attributes, remove_root = false)
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
@prefix_options, attributes = split_options(attributes)
+
+ if attributes.keys.size == 1
+ remove_root = self.class.element_name == attributes.keys.first.to_s
+ end
+
+ attributes = Formats.remove_root(attributes) if remove_root
+
attributes.each do |key, value|
@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?(String) || attrs.is_a?(Numeric)
- attrs.duplicable? ? attrs.dup : attrs
- else
+ if attrs.is_a?(Hash)
+ resource ||= find_or_create_resource_for_collection(key)
resource.new(attrs)
+ else
+ attrs.duplicable? ? attrs.dup : attrs
end
end
when Hash
resource = find_or_create_resource_for(key)
resource.new(value)
else
- value.dup rescue value
+ value.duplicable? ? value.dup : value
end
end
self
end
+ # Updates a single attribute and then saves the object.
+ #
+ # Note: Unlike ActiveRecord::Base.update_attribute, this method is
+ # subject to normal validation routines as an update sends the whole body
+ # of the resource in the request. (See Validations).
+ #
+ # As such, this method is equivalent to calling update_attributes with a single attribute/value pair.
+ #
+ # If the saving fails because of a connection or remote service error, an
+ # exception will be raised. If saving fails because the resource is
+ # invalid then false will be returned.
+ def update_attribute(name, value)
+ self.send("#{name}=".to_sym, value)
+ self.save
+ end
+
+ # Updates this resource with all the attributes from the passed-in Hash
+ # and requests that the record be saved.
+ #
+ # If the saving fails because of a connection or remote service error, an
+ # exception will be raised. If saving fails because the resource is
+ # invalid then false will be returned.
+ #
+ # Note: Though this request can be made with a partial set of the
+ # resource's attributes, the full body of the request will still be sent
+ # in the save request to the remote service.
+ def update_attributes(attributes)
+ load(attributes, false) && save
+ end
+
# For checking respond_to? without searching the attributes (which is faster).
alias_method :respond_to_without_attributes?, :respond_to?
@@ -1055,17 +1316,25 @@
def respond_to?(method, include_priv = false)
method_name = method.to_s
if attributes.nil?
- return super
- elsif attributes.has_key?(method_name)
- return true
- elsif ['?','='].include?(method_name.last) && attributes.has_key?(method_name.first(-1))
- return true
- end
- # super must be called at the end of the method, because the inherited respond_to?
- # would return true for generated readers, even if the attribute wasn't present
- super
+ super
+ elsif known_attributes.include?(method_name)
+ true
+ elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
+ true
+ else
+ # super must be called at the end of the method, because the inherited respond_to?
+ # would return true for generated readers, even if the attribute wasn't present
+ super
+ end
end
+ def to_json(options={})
+ super({ :root => self.class.element_name }.merge(options))
+ end
+
+ def to_xml(options={})
+ super({ :root => self.class.element_name }.merge(options))
+ end
protected
def connection(refresh = false)
@@ -1088,8 +1357,9 @@
end
def load_attributes_from_response(response)
- if response['Content-Length'] != "0" && response.body.strip.size > 0
- load(self.class.format.decode(response.body))
+ if !response['Content-Length'].blank? && response['Content-Length'] != "0" && !response.body.nil? && response.body.strip.size > 0
+ load(self.class.format.decode(response.body), true)
+ @persisted = true
end
end
@@ -1102,6 +1372,10 @@
self.class.element_path(to_param, options || prefix_options)
end
+ def new_element_path
+ self.class.new_element_path(prefix_options)
+ end
+
def collection_path(options = nil)
self.class.collection_path(options || prefix_options)
end
@@ -1109,38 +1383,48 @@
private
# Tries to find a resource for a given collection name; if it fails, then the resource is created
def find_or_create_resource_for_collection(name)
- find_or_create_resource_for(name.to_s.singularize)
+ find_or_create_resource_for(ActiveSupport::Inflector.singularize(name.to_s))
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
- if namespace = namespaces.reverse.detect { |ns| ns.const_defined?(resource_name) }
- return namespace.const_get(resource_name)
+ const_args = RUBY_VERSION < "1.9" ? [resource_name] : [resource_name, false]
+ if namespace = namespaces.reverse.detect { |ns| ns.const_defined?(*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
- if self.class.const_defined?(resource_name)
- resource = self.class.const_get(resource_name)
+
+ const_args = RUBY_VERSION < "1.9" ? [resource_name] : [resource_name, false]
+ if self.class.const_defined?(*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
@@ -1153,14 +1437,27 @@
def method_missing(method_symbol, *arguments) #:nodoc:
method_name = method_symbol.to_s
- case method_name.last
+ if method_name =~ /(=|\?)$/
+ case $1
when "="
- attributes[method_name.first(-1)] = arguments.first
+ attributes[$`] = arguments.first
when "?"
- attributes[method_name.first(-1)]
- else
- attributes.has_key?(method_name) ? attributes[method_name] : super
+ attributes[$`]
+ end
+ else
+ return attributes[method_name] if attributes.include?(method_name)
+ # not set right now but we know about it
+ return nil if known_attributes.include?(method_name)
+ super
end
end
end
+
+ class Base
+ extend ActiveModel::Naming
+ include CustomMethods, Observing, Validations
+ include ActiveModel::Conversion
+ include ActiveModel::Serializers::JSON
+ include ActiveModel::Serializers::Xml
+ end
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/connection.rb ruby-activeresource-3.1.0/lib/active_resource/connection.rb
--- ruby-activeresource-2.3.14/lib/active_resource/connection.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/connection.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,75 +1,12 @@
+require 'active_support/core_ext/benchmark'
+require 'active_support/core_ext/uri'
+require 'active_support/core_ext/object/inclusion'
require 'net/https'
require 'date'
require 'time'
require 'uri'
-require 'benchmark'
module ActiveResource
- class ConnectionError < StandardError # :nodoc:
- attr_reader :response
-
- def initialize(response, message = nil)
- @response = response
- @message = message
- end
-
- def to_s
- "Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
- end
- end
-
- # Raised when a Timeout::Error occurs.
- class TimeoutError < ConnectionError
- def initialize(message)
- @message = message
- end
- def to_s; @message ;end
- end
-
- # Raised when a OpenSSL::SSL::SSLError occurs.
- class SSLError < ConnectionError
- def initialize(message)
- @message = message
- end
- def to_s; @message ;end
- end
-
- # 3xx Redirection
- class Redirection < ConnectionError # :nodoc:
- def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
- end
-
- # 4xx Client Error
- class ClientError < ConnectionError; end # :nodoc:
-
- # 400 Bad Request
- class BadRequest < ClientError; end # :nodoc
-
- # 401 Unauthorized
- class UnauthorizedAccess < ClientError; end # :nodoc
-
- # 403 Forbidden
- class ForbiddenAccess < ClientError; end # :nodoc
-
- # 404 Not Found
- class ResourceNotFound < ClientError; end # :nodoc:
-
- # 409 Conflict
- class ResourceConflict < ClientError; end # :nodoc:
-
- # 410 Gone
- class ResourceGone < ClientError; end # :nodoc:
-
- # 5xx Server Error
- class ServerError < ConnectionError; end # :nodoc:
-
- # 405 Method Not Allowed
- class MethodNotAllowed < ClientError # :nodoc:
- def allowed_methods
- @response['Allow'].split(',').map { |verb| verb.strip.downcase.to_sym }
- end
- end
-
# Class to handle connections to remote web services.
# This class is used by ActiveResource::Base to interface with REST
# services.
@@ -82,7 +19,7 @@
:head => 'Accept'
}
- attr_reader :site, :user, :password, :timeout, :proxy, :ssl_options
+ attr_reader :site, :user, :password, :auth_type, :timeout, :proxy, :ssl_options
attr_accessor :format
class << self
@@ -93,7 +30,7 @@
# The +site+ parameter is required and will set the +site+
# attribute to the URI for the remote resource service.
- def initialize(site, format = ActiveResource::Formats[:xml])
+ def initialize(site, format = ActiveResource::Formats::JsonFormat)
raise ArgumentError, 'Missing site URI' unless site
@user = @password = nil
self.site = site
@@ -102,27 +39,32 @@
# Set URI for remote service.
def site=(site)
- @site = site.is_a?(URI) ? site : URI.parse(site)
- @user = URI.decode(@site.user) if @site.user
- @password = URI.decode(@site.password) if @site.password
+ @site = site.is_a?(URI) ? site : URI.parser.parse(site)
+ @user = URI.parser.unescape(@site.user) if @site.user
+ @password = URI.parser.unescape(@site.password) if @site.password
end
# Set the proxy for remote service.
def proxy=(proxy)
- @proxy = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
+ @proxy = proxy.is_a?(URI) ? proxy : URI.parser.parse(proxy)
end
- # Set the user for remote service.
+ # Sets the user for remote service.
def user=(user)
@user = user
end
- # Set password for remote service.
+ # Sets the password for remote service.
def password=(password)
@password = password
end
- # Set the number of seconds after which HTTP requests to the remote service should time out.
+ # Sets the auth type for remote service.
+ def auth_type=(auth_type)
+ @auth_type = legitimize_auth_type(auth_type)
+ end
+
+ # Sets the number of seconds after which HTTP requests to the remote service should time out.
def timeout=(timeout)
@timeout = timeout
end
@@ -132,44 +74,44 @@
@ssl_options = opts
end
- # Execute a GET request.
+ # Executes a GET request.
# Used to get (find) resources.
def get(path, headers = {})
- format.decode(request(:get, path, build_request_headers(headers, :get)).body)
+ with_auth { request(:get, path, build_request_headers(headers, :get, self.site.merge(path))) }
end
- # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
+ # Executes a DELETE request (see HTTP protocol documentation if unfamiliar).
# Used to delete resources.
def delete(path, headers = {})
- request(:delete, path, build_request_headers(headers, :delete))
+ with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
end
- # Execute a PUT request (see HTTP protocol documentation if unfamiliar).
+ # Executes a PUT request (see HTTP protocol documentation if unfamiliar).
# Used to update resources.
def put(path, body = '', headers = {})
- request(:put, path, body.to_s, build_request_headers(headers, :put))
+ with_auth { request(:put, path, body.to_s, build_request_headers(headers, :put, self.site.merge(path))) }
end
- # Execute a POST request.
+ # Executes a POST request.
# Used to create new resources.
def post(path, body = '', headers = {})
- request(:post, path, body.to_s, build_request_headers(headers, :post))
+ with_auth { request(:post, path, body.to_s, build_request_headers(headers, :post, self.site.merge(path))) }
end
- # Execute a HEAD request.
+ # Executes a HEAD request.
# Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
def head(path, headers = {})
- request(:head, path, build_request_headers(headers, :head))
+ with_auth { request(:head, path, build_request_headers(headers, :head, self.site.merge(path))) }
end
-
private
- # Makes request to remote service.
+ # Makes a request to the remote service.
def request(method, path, *arguments)
- logger.info "#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
- result = nil
- ms = Benchmark.ms { result = http.send(method, path, *arguments) }
- logger.info "--> %d %s (%d %.0fms)" % [result.code, result.message, result.body ? result.body.length : 0, ms] if logger
+ result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload|
+ payload[:method] = method
+ payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
+ payload[:result] = http.send(method, path, *arguments)
+ end
handle_response(result)
rescue Timeout::Error => e
raise TimeoutError.new(e.message)
@@ -177,7 +119,7 @@
raise SSLError.new(e.message)
end
- # Handles response and error codes from remote service.
+ # Handles response and error codes from the remote service.
def handle_response(response)
case response.code.to_i
when 301,302
@@ -209,7 +151,7 @@
end
end
- # Creates new Net::HTTP instance for communication with
+ # Creates new Net::HTTP instance for communication with the
# remote service and resources.
def http
configure_http(new_http)
@@ -263,21 +205,80 @@
end
# Builds headers for request to remote service.
- def build_request_headers(headers, http_method=nil)
- authorization_header.update(default_header).update(http_format_header(http_method)).update(headers)
+ def build_request_headers(headers, http_method, uri)
+ authorization_header(http_method, uri).update(default_header).update(http_format_header(http_method)).update(headers)
+ end
+
+ def response_auth_header
+ @response_auth_header ||= ""
+ end
+
+ def with_auth
+ retried ||= false
+ yield
+ rescue UnauthorizedAccess => e
+ raise if retried || auth_type != :digest
+ @response_auth_header = e.response['WWW-Authenticate']
+ retried = true
+ retry
+ end
+
+ def authorization_header(http_method, uri)
+ if @user || @password
+ if auth_type == :digest
+ { 'Authorization' => digest_auth_header(http_method, uri) }
+ else
+ { 'Authorization' => 'Basic ' + ["#{@user}:#{@password}"].pack('m').delete("\r\n") }
+ end
+ else
+ {}
+ end
+ end
+
+ def digest_auth_header(http_method, uri)
+ params = extract_params_from_response
+
+ ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}")
+ ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{uri.path}")
+
+ params.merge!('cnonce' => client_nonce)
+ request_digest = Digest::MD5.hexdigest([ha1, params['nonce'], "0", params['cnonce'], params['qop'], ha2].join(":"))
+ "Digest #{auth_attributes_for(uri, request_digest, params)}"
+ end
+
+ def client_nonce
+ Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535)))
+ end
+
+ def extract_params_from_response
+ params = {}
+ if response_auth_header =~ /^(\w+) (.*)/
+ $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
+ end
+ params
end
- # Sets authorization header
- def authorization_header
- (@user || @password ? { 'Authorization' => 'Basic ' + ["#{@user}:#{ @password}"].pack('m').delete("\r\n") } : {})
+ def auth_attributes_for(uri, request_digest, params)
+ [
+ %Q(username="#{@user}"),
+ %Q(realm="#{params['realm']}"),
+ %Q(qop="#{params['qop']}"),
+ %Q(uri="#{uri.path}"),
+ %Q(nonce="#{params['nonce']}"),
+ %Q(nc="0"),
+ %Q(cnonce="#{params['cnonce']}"),
+ %Q(opaque="#{params['opaque']}"),
+ %Q(response="#{request_digest}")].join(", ")
end
def http_format_header(http_method)
{HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
end
- def logger #:nodoc:
- Base.logger
+ def legitimize_auth_type(auth_type)
+ return :basic if auth_type.nil?
+ auth_type = auth_type.to_sym
+ auth_type.in?([:basic, :digest]) ? auth_type : :basic
end
end
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/custom_methods.rb ruby-activeresource-3.1.0/lib/active_resource/custom_methods.rb
--- ruby-activeresource-2.3.14/lib/active_resource/custom_methods.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/custom_methods.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveResource
# A module to support custom REST methods and sub-resources, allowing you to break out
# of the "default" REST methods with your own custom resource requests. For example,
@@ -9,10 +11,10 @@
#
# This route set creates routes for the following HTTP requests:
#
- # POST /people/new/register.xml # PeopleController.register
- # PUT /people/1/promote.xml # PeopleController.promote with :id => 1
- # DELETE /people/1/deactivate.xml # PeopleController.deactivate with :id => 1
- # GET /people/active.xml # PeopleController.active
+ # POST /people/new/register.json # PeopleController.register
+ # PUT /people/1/promote.json # PeopleController.promote with :id => 1
+ # DELETE /people/1/deactivate.json # PeopleController.deactivate with :id => 1
+ # GET /people/active.json # PeopleController.active
#
# Using this module, Active Resource can use these custom REST methods just like the
# standard methods.
@@ -21,57 +23,56 @@
# self.site = "http://37s.sunrise.i:3000"
# end
#
- # Person.new(:name => 'Ryan).post(:register) # POST /people/new/register.xml
+ # Person.new(:name => 'Ryan).post(:register) # POST /people/new/register.json
# # => { :id => 1, :name => 'Ryan' }
#
- # Person.find(1).put(:promote, :position => 'Manager') # PUT /people/1/promote.xml
- # Person.find(1).delete(:deactivate) # DELETE /people/1/deactivate.xml
+ # Person.find(1).put(:promote, :position => 'Manager') # PUT /people/1/promote.json
+ # Person.find(1).delete(:deactivate) # DELETE /people/1/deactivate.json
#
- # Person.get(:active) # GET /people/active.xml
+ # Person.get(:active) # GET /people/active.json
# # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
#
module CustomMethods
- def self.included(base)
- base.class_eval do
- extend ActiveResource::CustomMethods::ClassMethods
- include ActiveResource::CustomMethods::InstanceMethods
-
- class << self
- alias :orig_delete :delete
-
- # Invokes a GET to a given custom REST method. For example:
- #
- # Person.get(:active) # GET /people/active.xml
- # # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
- #
- # Person.get(:active, :awesome => true) # GET /people/active.xml?awesome=true
- # # => [{:id => 1, :name => 'Ryan'}]
- #
- # Note: the objects returned from this method are not automatically converted
- # into ActiveResource::Base instances - they are ordinary Hashes. If you are expecting
- # ActiveResource::Base instances, use the find class method with the
- # :from option. For example:
- #
- # Person.find(:all, :from => :active)
- def get(custom_method_name, options = {})
- connection.get(custom_method_collection_url(custom_method_name, options), headers)
- end
+ extend ActiveSupport::Concern
- def post(custom_method_name, options = {}, body = '')
- connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
- end
+ included do
+ class << self
+ alias :orig_delete :delete
+
+ # Invokes a GET to a given custom REST method. For example:
+ #
+ # Person.get(:active) # GET /people/active.json
+ # # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
+ #
+ # Person.get(:active, :awesome => true) # GET /people/active.json?awesome=true
+ # # => [{:id => 1, :name => 'Ryan'}]
+ #
+ # Note: the objects returned from this method are not automatically converted
+ # into ActiveResource::Base instances - they are ordinary Hashes. If you are expecting
+ # ActiveResource::Base instances, use the find class method with the
+ # :from option. For example:
+ #
+ # Person.find(:all, :from => :active)
+ def get(custom_method_name, options = {})
+ hashified = format.decode(connection.get(custom_method_collection_url(custom_method_name, options), headers).body)
+ derooted = Formats.remove_root(hashified)
+ derooted.is_a?(Array) ? derooted.map { |e| Formats.remove_root(e) } : derooted
+ end
- def put(custom_method_name, options = {}, body = '')
- connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
- end
+ def post(custom_method_name, options = {}, body = '')
+ connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
+ end
+
+ def put(custom_method_name, options = {}, body = '')
+ connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
+ end
- def delete(custom_method_name, options = {})
- # Need to jump through some hoops to retain the original class 'delete' method
- if custom_method_name.is_a?(Symbol)
- connection.delete(custom_method_collection_url(custom_method_name, options), headers)
- else
- orig_delete(custom_method_name, options)
- end
+ def delete(custom_method_name, options = {})
+ # Need to jump through some hoops to retain the original class 'delete' method
+ if custom_method_name.is_a?(Symbol)
+ connection.delete(custom_method_collection_url(custom_method_name, options), headers)
+ else
+ orig_delete(custom_method_name, options)
end
end
end
@@ -86,7 +87,7 @@
module InstanceMethods
def get(method_name, options = {})
- connection.get(custom_method_element_url(method_name, options), self.class.headers)
+ self.class.format.decode(connection.get(custom_method_element_url(method_name, options), self.class.headers).body)
end
def post(method_name, options = {}, body = nil)
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/exceptions.rb ruby-activeresource-3.1.0/lib/active_resource/exceptions.rb
--- ruby-activeresource-2.3.14/lib/active_resource/exceptions.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/exceptions.rb 2011-09-29 12:26:03.000000000 +0000
@@ -8,7 +8,10 @@
end
def to_s
- "Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
+ message = "Failed."
+ message << " Response code = #{response.code}." if response.respond_to?(:code)
+ message << " Response message = #{response.message}." if response.respond_to?(:message)
+ message
end
end
@@ -33,6 +36,9 @@
def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
end
+ # Raised when ...
+ class MissingPrefixParam < ArgumentError; end # :nodoc:
+
# 4xx Client Error
class ClientError < ConnectionError; end # :nodoc:
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/formats/json_format.rb ruby-activeresource-3.1.0/lib/active_resource/formats/json_format.rb
--- ruby-activeresource-2.3.14/lib/active_resource/formats/json_format.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/formats/json_format.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,3 +1,5 @@
+require 'active_support/json'
+
module ActiveResource
module Formats
module JsonFormat
@@ -16,7 +18,7 @@
end
def decode(json)
- ActiveSupport::JSON.decode(json)
+ Formats.remove_root(ActiveSupport::JSON.decode(json))
end
end
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/formats/xml_format.rb ruby-activeresource-3.1.0/lib/active_resource/formats/xml_format.rb
--- ruby-activeresource-2.3.14/lib/active_resource/formats/xml_format.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/formats/xml_format.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/hash/conversions'
+
module ActiveResource
module Formats
module XmlFormat
@@ -16,19 +18,8 @@
end
def decode(xml)
- from_xml_data(Hash.from_xml(xml))
+ Formats.remove_root(Hash.from_xml(xml))
end
-
- private
- # Manipulate from_xml Hash, because xml_simple is not exactly what we
- # want for Active Resource.
- def from_xml_data(data)
- if data.is_a?(Hash) && data.keys.size == 1
- data.values.first
- else
- data
- end
- end
end
end
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/formats.rb ruby-activeresource-3.1.0/lib/active_resource/formats.rb
--- ruby-activeresource-2.3.14/lib/active_resource/formats.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/formats.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,14 +1,22 @@
module ActiveResource
module Formats
+ autoload :XmlFormat, 'active_resource/formats/xml_format'
+ autoload :JsonFormat, 'active_resource/formats/json_format'
+
# Lookup the format class from a mime type reference symbol. Example:
#
# ActiveResource::Formats[:xml] # => ActiveResource::Formats::XmlFormat
# ActiveResource::Formats[:json] # => ActiveResource::Formats::JsonFormat
def self.[](mime_type_reference)
- ActiveResource::Formats.const_get(mime_type_reference.to_s.camelize + "Format")
+ ActiveResource::Formats.const_get(ActiveSupport::Inflector.camelize(mime_type_reference.to_s) + "Format")
+ end
+
+ def self.remove_root(data)
+ if data.is_a?(Hash) && data.keys.size == 1
+ data.values.first
+ else
+ data
+ end
end
end
end
-
-require 'active_resource/formats/xml_format'
-require 'active_resource/formats/json_format'
\ No newline at end of file
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/http_mock.rb ruby-activeresource-3.1.0/lib/active_resource/http_mock.rb
--- ruby-activeresource-2.3.14/lib/active_resource/http_mock.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/http_mock.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,4 +1,5 @@
-require 'active_resource/connection'
+require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/object/inclusion'
module ActiveResource
class InvalidRequestError < StandardError; end #:nodoc:
@@ -8,8 +9,8 @@
# 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 = {})
@@ -19,30 +20,30 @@
# * path - A string, starting with a "/", defining the URI that is expected to be
# called.
# * request_headers - Headers that are expected along with the request. This argument uses a
- # hash format, such as { "Content-Type" => "application/xml" }. This mock will only trigger
+ # hash format, such as { "Content-Type" => "application/json" }. This mock will only trigger
# if your tests sends a request with identical headers.
# * body - The data to be returned. This should be a string of Active Resource parseable content,
- # such as XML.
+ # such as Json.
# * status - The HTTP response code, as an integer, to return with the response.
# * response_headers - Headers to be returned with the response. Uses the same hash format as
# request_headers listed above.
#
# In order for a mock to deliver its content, the incoming request must match by the http_method,
- # +path+ and request_headers. If no match is found an InvalidRequestError exception
+ # +path+ and request_headers. 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.
#
# ==== Example
# def setup
- # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
+ # @matz = { :person => { :id => 1, :name => "Matz" } }.to_json
# ActiveResource::HttpMock.respond_to do |mock|
- # mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml"
- # mock.get "/people/1.xml", {}, @matz
- # mock.put "/people/1.xml", {}, nil, 204
- # mock.delete "/people/1.xml", {}, nil, 200
+ # mock.post "/people.json", {}, @matz, 201, "Location" => "/people/1.json"
+ # mock.get "/people/1.json", {}, @matz
+ # mock.put "/people/1.json", {}, nil, 204
+ # mock.delete "/people/1.json", {}, nil, 200
# end
# end
- #
+ #
# def test_get_matz
# person = Person.find(1)
# assert_equal "Matz", person.name
@@ -60,31 +61,42 @@
# end
module_eval <<-EOE, __FILE__, __LINE__ + 1
def #{method}(path, request_headers = {}, body = nil, status = 200, response_headers = {})
- @responses << [Request.new(:#{method}, path, nil, request_headers), Response.new(body || "", status, response_headers)]
+ request = Request.new(:#{method}, path, nil, request_headers)
+ response = Response.new(body || "", status, response_headers)
+
+ delete_duplicate_responses(request)
+
+ @responses << [request, response]
end
EOE
end
+
+ private
+
+ def delete_duplicate_responses(request)
+ @responses.delete_if {|r| r[0] == request }
+ end
end
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
# def setup
- # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
+ # @matz = { :person => { :id => 1, :name => "Matz" } }.to_json
# ActiveResource::HttpMock.respond_to do |mock|
- # mock.get "/people/1.xml", {}, @matz
+ # mock.get "/people/1.json", {}, @matz
# end
# end
- #
+ #
# def test_should_request_remote_service
# person = Person.find(1) # Call the remote service
- #
+ #
# # This request object has the same HTTP method and path as declared by the mock
- # expected_request = ActiveResource::Request.new(:get, "/people/1.xml")
- #
+ # expected_request = ActiveResource::Request.new(:get, "/people/1.json")
+ #
# # Assert that the mock received, and responded to, the expected request from the model
# assert ActiveResource::HttpMock.requests.include?(expected_request)
# end
@@ -93,92 +105,110 @@
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 responses.assoc(request).
def responses
@@responses ||= []
end
# Accepts a block which declares a set of requests and responses for the HttpMock to respond to in
# the following format:
- #
+ #
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
- #
+ #
# === Example
- #
- # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
+ #
+ # @matz = { :person => { :id => 1, :name => "Matz" } }.to_json
# ActiveResource::HttpMock.respond_to do |mock|
- # mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml"
- # mock.get "/people/1.xml", {}, @matz
- # mock.put "/people/1.xml", {}, nil, 204
- # mock.delete "/people/1.xml", {}, nil, 200
+ # mock.post "/people.json", {}, @matz, 201, "Location" => "/people/1.json"
+ # mock.get "/people/1.json", {}, @matz
+ # mock.put "/people/1.json", {}, nil, 204
+ # mock.delete "/people/1.json", {}, nil, 200
# end
- #
+ #
# Alternatively, accepts a hash of {Request => Response} pairs allowing you to generate
# these the following format:
- #
+ #
# ActiveResource::Request.new(method, path, body, request_headers)
# ActiveResource::Response.new(body, status, response_headers)
- #
+ #
# === Example
- #
+ #
# Request.new(:#{method}, path, nil, request_headers)
- #
- # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
#
- # create_matz = ActiveResource::Request.new(:post, '/people.xml', @matz, {})
- # created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.xml"})
- # get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
+ # @matz = { :person => { :id => 1, :name => "Matz" } }.to_json
+ #
+ # create_matz = ActiveResource::Request.new(:post, '/people.json', @matz, {})
+ # created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.json"})
+ # get_matz = ActiveResource::Request.new(:get, '/people/1.json', nil)
# ok_response = ActiveResource::Response.new("", 200, {})
- #
+ #
# pairs = {create_matz => created_response, get_matz => ok_response}
- #
+ #
# ActiveResource::HttpMock.respond_to(pairs)
#
# Note, by default, every time you call +respond_to+, any previous request and response pairs stored
# in HttpMock will be deleted giving you a clean slate to work on.
- #
- # If you want to override this behaviour, pass in +false+ as the last argument to +respond_to+
- #
+ #
+ # If you want to override this behavior, pass in +false+ as the last argument to +respond_to+
+ #
# === Example
- #
+ #
# ActiveResource::HttpMock.respond_to do |mock|
- # mock.send(:get, "/people/1", {}, "XML1")
+ # mock.send(:get, "/people/1", {}, "JSON1")
# end
# ActiveResource::HttpMock.responses.length #=> 1
- #
+ #
# ActiveResource::HttpMock.respond_to(false) do |mock|
- # mock.send(:get, "/people/2", {}, "XML2")
+ # mock.send(:get, "/people/2", {}, "JSON2")
# end
# ActiveResource::HttpMock.responses.length #=> 2
- #
+ #
# This also works with passing in generated pairs of requests and responses, again, just pass in false
# as the last argument:
- #
+ #
# === Example
- #
+ #
# ActiveResource::HttpMock.respond_to do |mock|
- # mock.send(:get, "/people/1", {}, "XML1")
+ # mock.send(:get, "/people/1", {}, "JSON1")
# end
# ActiveResource::HttpMock.responses.length #=> 1
- #
- # get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
+ #
+ # get_matz = ActiveResource::Request.new(:get, '/people/1.json', nil)
# ok_response = ActiveResource::Response.new("", 200, {})
- #
+ #
# pairs = {get_matz => ok_response}
#
# ActiveResource::HttpMock.respond_to(pairs, false)
# ActiveResource::HttpMock.responses.length #=> 2
+ #
+ # # If you add a response with an existing request, it will be replaced
+ #
+ # fail_response = ActiveResource::Response.new("", 404, {})
+ # pairs = {get_matz => fail_response}
+ #
+ # ActiveResource::HttpMock.respond_to(pairs, false)
+ # ActiveResource::HttpMock.responses.length #=> 2
+ #
def respond_to(*args) #:yields: mock
pairs = args.first || {}
reset! if args.last.class != FalseClass
- responses.concat pairs.to_a
+
if block_given?
yield Responder.new(responses)
else
+ delete_responses_to_replace pairs.to_a
+ responses.concat pairs.to_a
Responder.new(responses)
end
end
+ def delete_responses_to_replace(new_responses)
+ new_responses.each{|nr|
+ request_to_remove = nr[0]
+ @@responses = responses.delete_if{|r| r[0] == request_to_remove}
+ }
+ end
+
# Deletes all logged requests and responses.
def reset!
requests.clear
@@ -248,7 +278,6 @@
headers.dup.merge(format_header => req.headers[format_header]) == req.headers
end
end
-
end
class Response
@@ -270,8 +299,10 @@
end
end
+ # Returns true if code is 2xx,
+ # false otherwise.
def success?
- (200..299).include?(code)
+ code.in?(200..299)
end
def [](key)
@@ -282,6 +313,8 @@
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 -Nru ruby-activeresource-2.3.14/lib/active_resource/log_subscriber.rb ruby-activeresource-3.1.0/lib/active_resource/log_subscriber.rb
--- ruby-activeresource-2.3.14/lib/active_resource/log_subscriber.rb 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/log_subscriber.rb 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,15 @@
+module ActiveResource
+ class LogSubscriber < ActiveSupport::LogSubscriber
+ def request(event)
+ result = event.payload[:result]
+ info "#{event.payload[:method].to_s.upcase} #{event.payload[:request_uri]}"
+ info "--> %d %s %d (%.1fms)" % [result.code, result.message, result.body.to_s.length, event.duration]
+ end
+
+ def logger
+ ActiveResource::Base.logger
+ end
+ end
+end
+
+ActiveResource::LogSubscriber.attach_to :active_resource
\ No newline at end of file
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/observing.rb ruby-activeresource-3.1.0/lib/active_resource/observing.rb
--- ruby-activeresource-2.3.14/lib/active_resource/observing.rb 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/observing.rb 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,29 @@
+module ActiveResource
+ module Observing
+ extend ActiveSupport::Concern
+ include ActiveModel::Observing
+
+ 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})
+ if result = #{method}_without_notifications(*args, &block)
+ notify_observers(:after_#{method})
+ end
+ result
+ end
+ EOS
+ alias_method_chain(method, :notifications)
+ end
+ end
+ end
+end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/railtie.rb ruby-activeresource-3.1.0/lib/active_resource/railtie.rb
--- ruby-activeresource-2.3.14/lib/active_resource/railtie.rb 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/railtie.rb 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,14 @@
+require "active_resource"
+require "rails"
+
+module ActiveResource
+ class Railtie < Rails::Railtie
+ config.active_resource = ActiveSupport::OrderedOptions.new
+
+ initializer "active_resource.set_configs" do |app|
+ app.config.active_resource.each do |k,v|
+ ActiveResource::Base.send "#{k}=", v
+ end
+ end
+ end
+end
\ No newline at end of file
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/schema.rb ruby-activeresource-3.1.0/lib/active_resource/schema.rb
--- ruby-activeresource-2.3.14/lib/active_resource/schema.rb 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/schema.rb 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,59 @@
+require 'active_resource/exceptions'
+
+module ActiveResource # :nodoc:
+ class Schema # :nodoc:
+ # attributes can be known to be one of these types. They are easy to
+ # cast to/from.
+ KNOWN_ATTRIBUTE_TYPES = %w( string text integer float decimal datetime timestamp time date binary boolean )
+
+ # An array of attribute definitions, representing the attributes that
+ # have been defined.
+ attr_accessor :attrs
+
+ # The internals of an Active Resource Schema are very simple -
+ # unlike an Active Record TableDefinition (on which it is based).
+ # It provides a set of convenience methods for people to define their
+ # schema using the syntax:
+ # schema do
+ # string :foo
+ # integer :bar
+ # end
+ #
+ # The schema stores the name and type of each attribute. That is then
+ # read out by the schema method to populate the schema of the actual
+ # resource.
+ def initialize
+ @attrs = {}
+ end
+
+ def attribute(name, type, options = {})
+ raise ArgumentError, "Unknown Attribute type: #{type.inspect} for key: #{name.inspect}" unless type.nil? || Schema::KNOWN_ATTRIBUTE_TYPES.include?(type.to_s)
+
+ the_type = type.to_s
+ # TODO: add defaults
+ #the_attr = [type.to_s]
+ #the_attr << options[:default] if options.has_key? :default
+ @attrs[name.to_s] = the_type
+ self
+ end
+
+ # The following are the attribute types supported by Active Resource
+ # migrations.
+ KNOWN_ATTRIBUTE_TYPES.each do |attr_type|
+ # def string(*args)
+ # options = args.extract_options!
+ # attr_names = args
+ #
+ # attr_names.each { |name| attribute(name, 'string', options) }
+ # end
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
+ def #{attr_type.to_s}(*args)
+ options = args.extract_options!
+ attr_names = args
+
+ attr_names.each { |name| attribute(name, '#{attr_type}', options) }
+ end
+ EOV
+ end
+ end
+end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/validations.rb ruby-activeresource-3.1.0/lib/active_resource/validations.rb
--- ruby-activeresource-2.3.14/lib/active_resource/validations.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/validations.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,240 +1,51 @@
+require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/object/blank'
+
module ActiveResource
class ResourceInvalid < ClientError #:nodoc:
end
# 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
- include Enumerable
- attr_reader :errors
-
- delegate :empty?, :to => :errors
-
- def initialize(base) # :nodoc:
- @base, @errors = base, {}
- end
-
- # Add an error to the base Active Resource object rather than an attribute.
- #
- # ==== Examples
- # my_folder = Folder.find(1)
- # my_folder.errors.add_to_base("You can't edit an existing folder")
- # my_folder.errors.on_base
- # # => "You can't edit an existing folder"
- #
- # my_folder.errors.add_to_base("This folder has been tagged as frozen")
- # my_folder.valid?
- # # => false
- # my_folder.errors.on_base
- # # => ["You can't edit an existing folder", "This folder has been tagged as frozen"]
- #
- def add_to_base(msg)
- add(:base, msg)
- end
-
- # Adds an error to an Active Resource object's attribute (named for the +attribute+ parameter)
- # with the error message in +msg+.
- #
- # ==== Examples
- # my_resource = Node.find(1)
- # my_resource.errors.add('name', 'can not be "base"') if my_resource.name == 'base'
- # my_resource.errors.on('name')
- # # => 'can not be "base"!'
- #
- # my_resource.errors.add('desc', 'can not be blank') if my_resource.desc == ''
- # my_resource.valid?
- # # => false
- # my_resource.errors.on('desc')
- # # => 'can not be blank!'
- #
- def add(attribute, msg)
- @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
- @errors[attribute.to_s] << msg
- end
-
- # Returns true if the specified +attribute+ has errors associated with it.
- #
- # ==== Examples
- # my_resource = Disk.find(1)
- # my_resource.errors.add('location', 'must be Main') unless my_resource.location == 'Main'
- # my_resource.errors.on('location')
- # # => 'must be Main!'
- #
- # my_resource.errors.invalid?('location')
- # # => true
- # my_resource.errors.invalid?('name')
- # # => false
- def invalid?(attribute)
- !@errors[attribute.to_s].nil?
- end
-
- # A method to return the errors associated with +attribute+, which returns nil, if no errors are
- # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
- # or an array of error messages if more than one error is associated with the specified +attribute+.
- #
- # ==== Examples
- # my_person = Person.new(params[:person])
- # my_person.errors.on('login')
- # # => nil
- #
- # my_person.errors.add('login', 'can not be empty') if my_person.login == ''
- # my_person.errors.on('login')
- # # => 'can not be empty'
- #
- # my_person.errors.add('login', 'can not be longer than 10 characters') if my_person.login.length > 10
- # my_person.errors.on('login')
- # # => ['can not be empty', 'can not be longer than 10 characters']
- def on(attribute)
- errors = @errors[attribute.to_s]
- return nil if errors.nil?
- errors.size == 1 ? errors.first : errors
- end
-
- alias :[] :on
-
- # A method to return errors assigned to +base+ object through add_to_base, which returns nil, if no errors are
- # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
- # or an array of error messages if more than one error is associated with the specified +attribute+.
- #
- # ==== Examples
- # my_account = Account.find(1)
- # my_account.errors.on_base
- # # => nil
- #
- # my_account.errors.add_to_base("This account is frozen")
- # my_account.errors.on_base
- # # => "This account is frozen"
- #
- # my_account.errors.add_to_base("This account has been closed")
- # my_account.errors.on_base
- # # => ["This account is frozen", "This account has been closed"]
- #
- def on_base
- on(:base)
- end
-
- # Yields each attribute and associated message per error added.
- #
- # ==== Examples
- # my_person = Person.new(params[:person])
- #
- # my_person.errors.add('login', 'can not be empty') if my_person.login == ''
- # my_person.errors.add('password', 'can not be empty') if my_person.password == ''
- # messages = ''
- # my_person.errors.each {|attr, msg| messages += attr.humanize + " " + msg + "
"}
- # messages
- # # => "Login can not be empty
Password can not be empty
"
- #
- def each
- @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
- end
-
- # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned
- # through iteration as "First name can't be empty".
- #
- # ==== Examples
- # my_person = Person.new(params[:person])
- #
- # my_person.errors.add('login', 'can not be empty') if my_person.login == ''
- # my_person.errors.add('password', 'can not be empty') if my_person.password == ''
- # messages = ''
- # my_person.errors.each_full {|msg| messages += msg + "
"}
- # messages
- # # => "Login can not be empty
Password can not be empty
"
- #
- def each_full
- full_messages.each { |msg| yield msg }
- end
-
- # Returns all the full error messages in an array.
- #
- # ==== Examples
- # my_person = Person.new(params[:person])
- #
- # my_person.errors.add('login', 'can not be empty') if my_person.login == ''
- # my_person.errors.add('password', 'can not be empty') if my_person.password == ''
- # messages = ''
- # my_person.errors.full_messages.each {|msg| messages += msg + "
"}
- # messages
- # # => "Login can not be empty
Password can not be empty
"
- #
- def full_messages
- full_messages = []
-
- @errors.each_key do |attr|
- @errors[attr].each do |msg|
- next if msg.nil?
-
- if attr == "base"
- full_messages << msg
- else
- full_messages << [attr.humanize, msg].join(' ')
- end
- end
- end
- full_messages
- end
-
- def clear
- @errors = {}
- end
-
- # Returns the total number of errors added. Two errors added to the same attribute will be counted as such
- # with this as well.
- #
- # ==== Examples
- # my_person = Person.new(params[:person])
- # my_person.errors.size
- # # => 0
- #
- # my_person.errors.add('login', 'can not be empty') if my_person.login == ''
- # my_person.errors.add('password', 'can not be empty') if my_person.password == ''
- # my_person.error.size
- # # => 2
- #
- def size
- @errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
- end
-
- alias_method :count, :size
- alias_method :length, :size
-
- # Grabs errors from an array of messages (like ActiveRecord::Validations)
- def from_array(messages)
- clear
- humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
+ # 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).
+ # The second parameter directs the errors cache to be cleared (default)
+ # 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] }]
messages.each do |message|
attr_message = humanized_attributes.keys.detect do |attr_name|
if message[0, attr_name.size + 1] == "#{attr_name} "
add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
end
end
-
- add_to_base message if attr_message.nil?
+
+ self[:base] << message if attr_message.nil?
end
end
- # Grabs errors from the json response.
- def from_json(json)
- array = ActiveSupport::JSON.decode(json)['errors'] rescue []
- from_array array
+ # Grabs errors from a json response.
+ def from_json(json, save_cache = false)
+ array = Array.wrap(ActiveSupport::JSON.decode(json)['errors']) rescue []
+ from_array array, save_cache
end
- # Grabs errors from the XML response.
- def from_xml(xml)
+ # Grabs errors from an XML response.
+ def from_xml(xml, save_cache = false)
array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
- from_array array
+ from_array array, save_cache
end
end
-
+
# Module to support validation and errors with Active Resource objects. The module overrides
- # Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
- # in the web service response. The module also adds an +errors+ collection that mimics the interface
+ # Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
+ # in the web service response. The module also adds an +errors+ collection that mimics the interface
# of the errors provided by ActiveRecord::Errors.
#
# ==== Example
#
- # Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a
+ # Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a
# validates_presence_of :first_name, :last_name declaration in the model:
#
# person = Person.new(:first_name => "Jim", :last_name => "")
@@ -243,33 +54,63 @@
# person.errors.empty? # => false
# person.errors.count # => 1
# person.errors.full_messages # => ["Last name can't be empty"]
- # person.errors.on(:last_name) # => "can't be empty"
- # person.last_name = "Halpert"
+ # person.errors[:last_name] # => ["can't be empty"]
+ # person.last_name = "Halpert"
# person.save # => true (and person is now saved to the remote service)
#
module Validations
- def self.included(base) # :nodoc:
- base.class_eval do
- alias_method_chain :save, :validation
- end
+ extend ActiveSupport::Concern
+ include ActiveModel::Validations
+
+ included do
+ alias_method_chain :save, :validation
end
# Validate a resource and save (POST) it to the remote web service.
- def save_with_validation
- save_without_validation
- true
+ # If any local validations fail - the save (POST) will not be attempted.
+ def save_with_validation(options={})
+ perform_validation = options[:validate] != false
+
+ # 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.
+ @remote_errors = nil
+ if perform_validation && valid? || !perform_validation
+ save_without_validation
+ true
+ else
+ false
+ end
rescue ResourceInvalid => error
+ # cache the remote errors because every call to valid? clears
+ # all errors. We must keep a copy to add these back after local
+ # validations.
+ @remote_errors = error
+ load_remote_errors(@remote_errors, true)
+ false
+ end
+
+
+ # Loads the set of remote errors into the object's Errors based on the
+ # 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]
- errors.from_xml(error.response.body)
+ errors.from_xml(remote_errors.response.body, save_cache)
when ActiveResource::Formats[:json]
- errors.from_json(error.response.body)
+ errors.from_json(remote_errors.response.body, save_cache)
end
- false
end
# Checks for errors on an object (i.e., is resource.errors empty?).
- #
+ #
+ # Runs all the specified local validations and returns true if no errors
+ # were added, otherwise false.
+ # Runs local validations (eg those on your Active Resource model), and
+ # also any errors returned from the remote system the last time we
+ # saved.
+ # Remote errors can only be cleared by trying to re-save the resource.
+ #
# ==== Examples
# my_person = Person.create(params[:person])
# my_person.valid?
@@ -278,7 +119,10 @@
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
# my_person.valid?
# # => false
+ #
def valid?
+ super
+ load_remote_errors(@remote_errors, true) if defined?(@remote_errors) && @remote_errors.present?
errors.empty?
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource/version.rb ruby-activeresource-3.1.0/lib/active_resource/version.rb
--- ruby-activeresource-2.3.14/lib/active_resource/version.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource/version.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,9 +1,10 @@
module ActiveResource
module VERSION #:nodoc:
- MAJOR = 2
- MINOR = 3
- TINY = 14
+ MAJOR = 3
+ MINOR = 1
+ TINY = 0
+ PRE = nil
- STRING = [MAJOR, MINOR, TINY].join('.')
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end
end
diff -Nru ruby-activeresource-2.3.14/lib/active_resource.rb ruby-activeresource-3.1.0/lib/active_resource.rb
--- ruby-activeresource-2.3.14/lib/active_resource.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/active_resource.rb 2011-09-29 12:26:03.000000000 +0000
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2006 David Heinemeier Hansson
+# Copyright (c) 2006-2011 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -21,24 +21,25 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-begin
- require 'active_support'
-rescue LoadError
- activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
- if File.directory?(activesupport_path)
- $:.unshift activesupport_path
- require 'active_support'
- end
-end
+activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
+$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-require 'active_resource/formats'
-require 'active_resource/base'
-require 'active_resource/validations'
-require 'active_resource/custom_methods'
+require 'active_support'
+require 'active_model'
+require 'active_resource/version'
module ActiveResource
- Base.class_eval do
- include Validations
- include CustomMethods
- end
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Connection
+ autoload :CustomMethods
+ autoload :Formats
+ autoload :HttpMock
+ autoload :Observing
+ autoload :Schema
+ autoload :Validations
end
diff -Nru ruby-activeresource-2.3.14/lib/activeresource.rb ruby-activeresource-3.1.0/lib/activeresource.rb
--- ruby-activeresource-2.3.14/lib/activeresource.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/lib/activeresource.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-require 'active_resource'
-ActiveSupport::Deprecation.warn 'require "activeresource" is deprecated and will be removed in Rails 3. Use require "active_resource" instead.'
diff -Nru ruby-activeresource-2.3.14/metadata.yml ruby-activeresource-3.1.0/metadata.yml
--- ruby-activeresource-2.3.14/metadata.yml 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/metadata.yml 2011-09-29 12:26:03.000000000 +0000
@@ -1,13 +1,13 @@
--- !ruby/object:Gem::Specification
name: activeresource
version: !ruby/object:Gem::Version
- hash: 31
+ hash: 3
prerelease:
segments:
- - 2
- 3
- - 14
- version: 2.3.14
+ - 1
+ - 0
+ version: 3.1.0
platform: ruby
authors:
- David Heinemeier Hansson
@@ -15,7 +15,7 @@
bindir: bin
cert_chain: []
-date: 2011-08-16 00:00:00 Z
+date: 2011-08-31 00:00:00 Z
dependencies:
- !ruby/object:Gem::Dependency
name: activesupport
@@ -25,26 +25,42 @@
requirements:
- - "="
- !ruby/object:Gem::Version
- hash: 31
+ hash: 3
segments:
- - 2
- 3
- - 14
- version: 2.3.14
+ - 1
+ - 0
+ version: 3.1.0
type: :runtime
version_requirements: *id001
-description: Wraps web resources in model classes that can be manipulated through XML over REST.
+- !ruby/object:Gem::Dependency
+ name: activemodel
+ prerelease: false
+ requirement: &id002 !ruby/object:Gem::Requirement
+ none: false
+ requirements:
+ - - "="
+ - !ruby/object:Gem::Version
+ hash: 3
+ segments:
+ - 3
+ - 1
+ - 0
+ version: 3.1.0
+ type: :runtime
+ version_requirements: *id002
+description: REST on Rails. Wrap your RESTful web app with Ruby classes and work with them like Active Record models.
email: david@loudthinking.com
executables: []
extensions: []
extra_rdoc_files:
-- README
+- README.rdoc
files:
-- Rakefile
-- README
- CHANGELOG
+- README.rdoc
+- examples/performance.rb
- lib/active_resource/base.rb
- lib/active_resource/connection.rb
- lib/active_resource/custom_methods.rb
@@ -53,33 +69,20 @@
- lib/active_resource/formats/xml_format.rb
- lib/active_resource/formats.rb
- lib/active_resource/http_mock.rb
+- lib/active_resource/log_subscriber.rb
+- lib/active_resource/observing.rb
+- lib/active_resource/railtie.rb
+- lib/active_resource/schema.rb
- lib/active_resource/validations.rb
- lib/active_resource/version.rb
- lib/active_resource.rb
-- lib/activeresource.rb
-- test/abstract_unit.rb
-- test/authorization_test.rb
-- test/base/custom_methods_test.rb
-- test/base/equality_test.rb
-- test/base/load_test.rb
-- test/base_errors_test.rb
-- test/base_test.rb
-- test/connection_test.rb
-- test/fixtures/beast.rb
-- test/fixtures/customer.rb
-- test/fixtures/person.rb
-- test/fixtures/proxy.rb
-- test/fixtures/street_address.rb
-- test/format_test.rb
-- test/http_mock_test.rb
-- test/setter_trap.rb
homepage: http://www.rubyonrails.org
licenses: []
post_install_message:
rdoc_options:
- --main
-- README
+- README.rdoc
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
@@ -87,10 +90,12 @@
requirements:
- - ">="
- !ruby/object:Gem::Version
- hash: 3
+ hash: 57
segments:
- - 0
- version: "0"
+ - 1
+ - 8
+ - 7
+ version: 1.8.7
required_rubygems_version: !ruby/object:Gem::Requirement
none: false
requirements:
@@ -102,10 +107,10 @@
version: "0"
requirements: []
-rubyforge_project: activeresource
+rubyforge_project:
rubygems_version: 1.8.8
signing_key:
specification_version: 3
-summary: Think Active Record for web resources.
+summary: REST modeling framework (part of Rails).
test_files: []
diff -Nru ruby-activeresource-2.3.14/Rakefile ruby-activeresource-3.1.0/Rakefile
--- ruby-activeresource-2.3.14/Rakefile 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/Rakefile 1970-01-01 00:00:00.000000000 +0000
@@ -1,137 +0,0 @@
-require 'rubygems'
-require 'rake'
-require 'rake/testtask'
-require 'rdoc/task'
-require 'rake/packagetask'
-require 'rubygems/package_task'
-
-require File.join(File.dirname(__FILE__), 'lib', 'active_resource', 'version')
-
-PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
-PKG_NAME = 'activeresource'
-PKG_VERSION = ActiveResource::VERSION::STRING + PKG_BUILD
-PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
-
-RELEASE_NAME = "REL #{PKG_VERSION}"
-
-RUBY_FORGE_PROJECT = "activerecord"
-RUBY_FORGE_USER = "webster132"
-
-PKG_FILES = FileList[
- "lib/**/*", "test/**/*", "[A-Z]*", "Rakefile"
-].exclude(/\bCVS\b|~$/)
-
-desc "Default Task"
-task :default => [ :test ]
-
-# Run the unit tests
-
-Rake::TestTask.new { |t|
- activesupport_path = "#{File.dirname(__FILE__)}/../activesupport/lib"
- t.libs << activesupport_path if File.directory?(activesupport_path)
- t.libs << "test"
- t.pattern = 'test/**/*_test.rb'
- t.verbose = true
- t.warning = true
-}
-
-
-# Generate the RDoc documentation
-
-RDoc::Task.new { |rdoc|
- rdoc.rdoc_dir = 'doc'
- rdoc.title = "Active Resource -- Object-oriented REST services"
- rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
- rdoc.options << '--charset' << 'utf-8'
- rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'CHANGELOG')
- rdoc.rdoc_files.include('lib/**/*.rb')
- rdoc.rdoc_files.exclude('lib/activeresource.rb')
-}
-
-
-# Create compressed packages
-
-dist_dirs = [ "lib", "test", "examples", "dev-utils" ]
-
-spec = Gem::Specification.new do |s|
- s.platform = Gem::Platform::RUBY
- s.name = PKG_NAME
- s.version = PKG_VERSION
- s.summary = "Think Active Record for web resources."
- s.description = %q{Wraps web resources in model classes that can be manipulated through XML over REST.}
-
- s.files = [ "Rakefile", "README", "CHANGELOG" ]
- dist_dirs.each do |dir|
- s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
- end
-
- s.add_dependency('activesupport', '= 2.3.14' + PKG_BUILD)
-
- s.require_path = 'lib'
-
- s.extra_rdoc_files = %w( README )
- s.rdoc_options.concat ['--main', 'README']
-
- s.author = "David Heinemeier Hansson"
- s.email = "david@loudthinking.com"
- s.homepage = "http://www.rubyonrails.org"
- s.rubyforge_project = "activeresource"
-end
-
-Gem::PackageTask.new(spec) do |p|
- p.gem_spec = spec
- p.need_tar = true
- p.need_zip = true
-end
-
-task :lines do
- lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
-
- for file_name in FileList["lib/active_resource/**/*.rb"]
- next if file_name =~ /vendor/
- f = File.open(file_name)
-
- while line = f.gets
- lines += 1
- next if line =~ /^\s*$/
- next if line =~ /^\s*#/
- codelines += 1
- end
- puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
-
- total_lines += lines
- total_codelines += codelines
-
- lines, codelines = 0, 0
- end
-
- puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
-end
-
-
-# Publishing ------------------------------------------------------
-
-desc "Publish the beta gem"
-task :pgem => [:package] do
- require 'rake/contrib/sshpublisher'
- Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
- `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
-end
-
-desc "Publish the API documentation"
-task :pdoc => [:rdoc] do
- require 'rake/contrib/sshpublisher'
- Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ar", "doc").upload
-end
-
-desc "Publish the release files to RubyForge."
-task :release => [ :package ] do
- `rubyforge login`
-
- for ext in %w( gem tgz zip )
- release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
- puts release_command
- system(release_command)
- end
-end
diff -Nru ruby-activeresource-2.3.14/README ruby-activeresource-3.1.0/README
--- ruby-activeresource-2.3.14/README 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/README 1970-01-01 00:00:00.000000000 +0000
@@ -1,165 +0,0 @@
-= Active Resource
-
-Active Resource (ARes) connects business objects and Representational State Transfer (REST)
-web services. It implements object-relational mapping for REST webservices to provide transparent
-proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
-in ActionController::Resources).
-
-== Philosophy
-
-Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
-web services. It follows the same philosophy as Active Record, in that one of its prime aims
-is to reduce the amount of code needed to map to these resources. This is made possible
-by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
-to infer complex relations and structures. These conventions are outlined in detail in the documentation
-for ActiveResource::Base.
-
-== Overview
-
-Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database
-tables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result
-received and serialized into a usable Ruby object.
-
-=== Configuration and Usage
-
-Putting ActiveResource to use is very similar to ActiveRecord. It's as simple as creating a model class
-that inherits from ActiveResource::Base and providing a site class variable to it:
-
- class Person < ActiveResource::Base
- self.site = "http://api.people.com:3000/"
- end
-
-Now the Person class is REST enabled and can invoke REST services very similarly to how ActiveRecord invokes
-lifecycle methods that operate against a persistent store.
-
- # Find a person with id = 1
- ryan = Person.find(1)
- Person.exists?(1) #=> true
-
-As you can see, the methods are quite similar to Active Record's methods for dealing with database
-records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
-
-==== Protocol
-
-Active Resource is built on a standard XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
-built into ActionController but will also work with any other REST service that properly implements the protocol.
-REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
-
-* GET requests are used for finding and retrieving resources.
-* POST requests are used to create new resources.
-* PUT requests are used to update existing resources.
-* DELETE requests are used to delete resources.
-
-For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation;
-for more general information on REST web services, see the article here[http://en.wikipedia.org/wiki/Representational_State_Transfer].
-
-==== Find
-
-GET Http requests expect the XML form of whatever resource/resources is/are being requested. So,
-for a request for a single element - the XML of that item is expected in response:
-
- # Expects a response of
- #
- # 1value1..
- #
- # for GET http://api.people.com:3000/people/1.xml
- #
- ryan = Person.find(1)
-
-The XML document that is received is used to build a new object of type Person, with each
-XML element becoming an attribute on the object.
-
- ryan.is_a? Person #=> true
- ryan.attribute1 #=> 'value1'
-
-Any complex element (one that contains other elements) becomes its own object:
-
- # With this response:
- #
- # 1value1value2
- #
- # for GET http://api.people.com:3000/people/1.xml
- #
- ryan = Person.find(1)
- ryan.complex #=>
- ryan.complex.attribute2 #=> 'value2'
-
-Collections can also be requested in a similar fashion
-
- # Expects a response of
- #
- #
- # 1Ryan
- # 2Jim
- #
- #
- # for GET http://api.people.com:3000/people.xml
- #
- people = Person.find(:all)
- people.first #=> 'Ryan' ...>
- people.last #=> 'Jim' ...>
-
-==== Create
-
-Creating a new resource submits the xml form of the resource as the body of the request and expects
-a 'Location' header in the response with the RESTful URL location of the newly created resource. The
-id of the newly created resource is parsed out of the Location response header and automatically set
-as the id of the ARes object.
-
- # Ryan
- #
- # is submitted as the body on
- #
- # POST http://api.people.com:3000/people.xml
- #
- # when save is called on a new Person object. An empty response is
- # is expected with a 'Location' header value:
- #
- # Response (201): Location: http://api.people.com:3000/people/2
- #
- ryan = Person.new(:first => 'Ryan')
- ryan.new? #=> true
- ryan.save #=> true
- ryan.new? #=> false
- ryan.id #=> 2
-
-==== Update
-
-'save' is also used to update an existing resource - and follows the same protocol as creating a resource
-with the exception that no response headers are needed - just an empty response when the update on the
-server side was successful.
-
- # Ryan
- #
- # is submitted as the body on
- #
- # PUT http://api.people.com:3000/people/1.xml
- #
- # when save is called on an existing Person object. An empty response is
- # is expected with code (204)
- #
- ryan = Person.find(1)
- ryan.first #=> 'Ryan'
- ryan.first = 'Rizzle'
- ryan.save #=> true
-
-==== Delete
-
-Destruction of a resource can be invoked as a class and instance method of the resource.
-
- # A request is made to
- #
- # DELETE http://api.people.com:3000/people/1.xml
- #
- # for both of these forms. An empty response with
- # is expected with response code (200)
- #
- ryan = Person.find(1)
- ryan.destroy #=> true
- ryan.exists? #=> false
- Person.delete(2) #=> true
- Person.exists?(2) #=> false
-
-
-You can find more usage information in the ActiveResource::Base documentation.
-
diff -Nru ruby-activeresource-2.3.14/README.rdoc ruby-activeresource-3.1.0/README.rdoc
--- ruby-activeresource-2.3.14/README.rdoc 1970-01-01 00:00:00.000000000 +0000
+++ ruby-activeresource-3.1.0/README.rdoc 2011-09-29 12:26:03.000000000 +0000
@@ -0,0 +1,165 @@
+= Active Resource
+
+Active Resource (ARes) connects business objects and Representational State Transfer (REST)
+web services. It implements object-relational mapping for REST web services to provide transparent
+proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
+in ActionController::Resources).
+
+== Philosophy
+
+Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
+web services. It follows the same philosophy as Active Record, in that one of its prime aims
+is to reduce the amount of code needed to map to these resources. This is made possible
+by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
+to infer complex relations and structures. These conventions are outlined in detail in the documentation
+for ActiveResource::Base.
+
+== Overview
+
+Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database
+tables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result
+received and serialized into a usable Ruby object.
+
+=== Configuration and Usage
+
+Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class
+that inherits from ActiveResource::Base and providing a site class variable to it:
+
+ class Person < ActiveResource::Base
+ self.site = "http://api.people.com:3000"
+ end
+
+Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes
+life cycle methods that operate against a persistent store.
+
+ # Find a person with id = 1
+ ryan = Person.find(1)
+ Person.exists?(1) # => true
+
+As you can see, the methods are quite similar to Active Record's methods for dealing with database
+records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
+
+==== Protocol
+
+Active Resource is built on a standard XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
+built into Action Controller but will also work with any other REST service that properly implements the protocol.
+REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
+
+* GET requests are used for finding and retrieving resources.
+* POST requests are used to create new resources.
+* PUT requests are used to update existing resources.
+* DELETE requests are used to delete resources.
+
+For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation;
+for more general information on REST web services, see the article here[http://en.wikipedia.org/wiki/Representational_State_Transfer].
+
+==== Find
+
+Find requests use the GET method and expect the XML form of whatever resource/resources is/are being requested. So,
+for a request for a single element, the XML of that item is expected in response:
+
+ # Expects a response of
+ #
+ # 1value1..
+ #
+ # for GET http://api.people.com:3000/people/1.xml
+ #
+ ryan = Person.find(1)
+
+The XML document that is received is used to build a new object of type Person, with each
+XML element becoming an attribute on the object.
+
+ ryan.is_a? Person # => true
+ ryan.attribute1 # => 'value1'
+
+Any complex element (one that contains other elements) becomes its own object:
+
+ # With this response:
+ #
+ # 1value1value2
+ #
+ # for GET http://api.people.com:3000/people/1.xml
+ #
+ ryan = Person.find(1)
+ ryan.complex # =>
+ ryan.complex.attribute2 # => 'value2'
+
+Collections can also be requested in a similar fashion
+
+ # Expects a response of
+ #
+ #
+ # 1Ryan
+ # 2Jim
+ #
+ #
+ # for GET http://api.people.com:3000/people.xml
+ #
+ people = Person.all
+ people.first # => 'Ryan' ...>
+ people.last # => 'Jim' ...>
+
+==== Create
+
+Creating a new resource submits the XML form of the resource as the body of the request and expects
+a 'Location' header in the response with the RESTful URL location of the newly created resource. The
+id of the newly created resource is parsed out of the Location response header and automatically set
+as the id of the ARes object.
+
+ # Ryan
+ #
+ # is submitted as the body on
+ #
+ # POST http://api.people.com:3000/people.xml
+ #
+ # when save is called on a new Person object. An empty response is
+ # is expected with a 'Location' header value:
+ #
+ # Response (201): Location: http://api.people.com:3000/people/2
+ #
+ ryan = Person.new(:first => 'Ryan')
+ ryan.new? # => true
+ ryan.save # => true
+ ryan.new? # => false
+ ryan.id # => 2
+
+==== Update
+
+'save' is also used to update an existing resource - and follows the same protocol as creating a resource
+with the exception that no response headers are needed - just an empty response when the update on the
+server side was successful.
+
+ # Ryan
+ #
+ # is submitted as the body on
+ #
+ # PUT http://api.people.com:3000/people/1.xml
+ #
+ # when save is called on an existing Person object. An empty response is
+ # is expected with code (204)
+ #
+ ryan = Person.find(1)
+ ryan.first # => 'Ryan'
+ ryan.first = 'Rizzle'
+ ryan.save # => true
+
+==== Delete
+
+Destruction of a resource can be invoked as a class and instance method of the resource.
+
+ # A request is made to
+ #
+ # DELETE http://api.people.com:3000/people/1.xml
+ #
+ # for both of these forms. An empty response with
+ # is expected with response code (200)
+ #
+ ryan = Person.find(1)
+ ryan.destroy # => true
+ ryan.exists? # => false
+ Person.delete(2) # => true
+ Person.exists?(2) # => false
+
+
+You can find more usage information in the ActiveResource::Base documentation.
+
diff -Nru ruby-activeresource-2.3.14/test/abstract_unit.rb ruby-activeresource-3.1.0/test/abstract_unit.rb
--- ruby-activeresource-2.3.14/test/abstract_unit.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/abstract_unit.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,21 +0,0 @@
-require 'rubygems'
-require 'test/unit'
-require 'active_support/test_case'
-
-$:.unshift File.expand_path('../../lib', __FILE__)
-$:.unshift File.expand_path('../../../activesupport/lib', __FILE__)
-require 'active_resource'
-require 'active_resource/http_mock'
-
-$:.unshift "#{File.dirname(__FILE__)}/../test"
-require 'setter_trap'
-
-ActiveResource::Base.logger = Logger.new("#{File.dirname(__FILE__)}/debug.log")
-
-def uses_gem(gem_name, test_name, version = '> 0')
- gem gem_name.to_s, version
- require gem_name.to_s
- yield
-rescue LoadError
- $stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
-end
diff -Nru ruby-activeresource-2.3.14/test/authorization_test.rb ruby-activeresource-3.1.0/test/authorization_test.rb
--- ruby-activeresource-2.3.14/test/authorization_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/authorization_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,122 +0,0 @@
-require 'abstract_unit'
-
-class AuthorizationTest < Test::Unit::TestCase
- Response = Struct.new(:code)
-
- def setup
- @conn = ActiveResource::Connection.new('http://localhost')
- @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
- @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
- @authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost")
- @authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' }
-
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/2.xml", @authorization_request_header, @david
- mock.put "/people/2.xml", @authorization_request_header, nil, 204
- mock.delete "/people/2.xml", @authorization_request_header, nil, 200
- mock.post "/people/2/addresses.xml", @authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5'
- end
- end
-
- def test_authorization_header
- authorization_header = @authenticated_conn.__send__(:authorization_header)
- assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization']
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_with_username_but_no_password
- @conn = ActiveResource::Connection.new("http://david:@localhost")
- authorization_header = @conn.__send__(:authorization_header)
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["david"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_with_password_but_no_username
- @conn = ActiveResource::Connection.new("http://:test123@localhost")
- authorization_header = @conn.__send__(:authorization_header)
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_with_decoded_credentials_from_url
- @conn = ActiveResource::Connection.new("http://my%40email.com:%31%32%33@localhost")
- authorization_header = @conn.__send__(:authorization_header)
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["my@email.com", "123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_explicitly_setting_username_and_password
- @authenticated_conn = ActiveResource::Connection.new("http://@localhost")
- @authenticated_conn.user = 'david'
- @authenticated_conn.password = 'test123'
- authorization_header = @authenticated_conn.__send__(:authorization_header)
- assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization']
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["david", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_explicitly_setting_username_but_no_password
- @conn = ActiveResource::Connection.new("http://@localhost")
- @conn.user = "david"
- authorization_header = @conn.__send__(:authorization_header)
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["david"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_authorization_header_explicitly_setting_password_but_no_username
- @conn = ActiveResource::Connection.new("http://@localhost")
- @conn.password = "test123"
- authorization_header = @conn.__send__(:authorization_header)
- authorization = authorization_header["Authorization"].to_s.split
-
- assert_equal "Basic", authorization[0]
- assert_equal ["", "test123"], ActiveSupport::Base64.decode64(authorization[1]).split(":")[0..1]
- end
-
- def test_get
- david = @authenticated_conn.get("/people/2.xml")
- assert_equal "David", david["name"]
- end
-
- def test_post
- response = @authenticated_conn.post("/people/2/addresses.xml")
- assert_equal "/people/1/addresses/5", response["Location"]
- end
-
- def test_put
- response = @authenticated_conn.put("/people/2.xml")
- assert_equal 204, response.code
- end
-
- def test_delete
- response = @authenticated_conn.delete("/people/2.xml")
- assert_equal 200, response.code
- end
-
- def test_raises_invalid_request_on_unauthorized_requests
- assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2.xml") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.xml") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.xml") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.xml") }
- end
-
- protected
- def assert_response_raises(klass, code)
- assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
- @conn.__send__(:handle_response, Response.new(code))
- end
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/base/custom_methods_test.rb ruby-activeresource-3.1.0/test/base/custom_methods_test.rb
--- ruby-activeresource-2.3.14/test/base/custom_methods_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/base/custom_methods_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,100 +0,0 @@
-require 'abstract_unit'
-require 'fixtures/person'
-require 'fixtures/street_address'
-
-class CustomMethodsTest < Test::Unit::TestCase
- def setup
- @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
- @matz_deep = { :id => 1, :name => 'Matz', :other => 'other' }.to_xml(:root => 'person')
- @matz_array = [{ :id => 1, :name => 'Matz' }].to_xml(:root => 'people')
- @ryan = { :name => 'Ryan' }.to_xml(:root => 'person')
- @addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
- @addy_deep = { :id => 1, :street => '12345 Street', :zip => "27519" }.to_xml(:root => 'address')
-
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, @matz
- mock.get "/people/1/shallow.xml", {}, @matz
- mock.get "/people/1/deep.xml", {}, @matz_deep
- mock.get "/people/retrieve.xml?name=Matz", {}, @matz_array
- mock.get "/people/managers.xml", {}, @matz_array
- mock.post "/people/hire.xml?name=Matz", {}, nil, 201
- mock.put "/people/1/promote.xml?position=Manager", {}, nil, 204
- mock.put "/people/promote.xml?name=Matz", {}, nil, 204, {}
- mock.put "/people/sort.xml?by=name", {}, nil, 204
- mock.delete "/people/deactivate.xml?name=Matz", {}, nil, 200
- mock.delete "/people/1/deactivate.xml", {}, nil, 200
- mock.post "/people/new/register.xml", {}, @ryan, 201, 'Location' => '/people/5.xml'
- mock.post "/people/1/register.xml", {}, @matz, 201
- mock.get "/people/1/addresses/1.xml", {}, @addy
- mock.get "/people/1/addresses/1/deep.xml", {}, @addy_deep
- mock.put "/people/1/addresses/1/normalize_phone.xml?locale=US", {}, nil, 204
- mock.put "/people/1/addresses/sort.xml?by=name", {}, nil, 204
- mock.post "/people/1/addresses/new/link.xml", {}, { :street => '12345 Street' }.to_xml(:root => 'address'), 201, 'Location' => '/people/1/addresses/2.xml'
- end
-
- Person.user = nil
- Person.password = nil
- end
-
- def teardown
- ActiveResource::HttpMock.reset!
- end
-
- def test_custom_collection_method
- # GET
- assert_equal([{ "id" => 1, "name" => 'Matz' }], Person.get(:retrieve, :name => 'Matz'))
-
- # POST
- assert_equal(ActiveResource::Response.new("", 201, {}), Person.post(:hire, :name => 'Matz'))
-
- # PUT
- assert_equal ActiveResource::Response.new("", 204, {}),
- Person.put(:promote, {:name => 'Matz'}, 'atestbody')
- assert_equal ActiveResource::Response.new("", 204, {}), Person.put(:sort, :by => 'name')
-
- # DELETE
- Person.delete :deactivate, :name => 'Matz'
-
- # Nested resource
- assert_equal ActiveResource::Response.new("", 204, {}), StreetAddress.put(:sort, :person_id => 1, :by => 'name')
- end
-
- def test_custom_element_method
- # Test GET against an element URL
- assert_equal Person.find(1).get(:shallow), {"id" => 1, "name" => 'Matz'}
- assert_equal Person.find(1).get(:deep), {"id" => 1, "name" => 'Matz', "other" => 'other'}
-
- # Test PUT against an element URL
- assert_equal ActiveResource::Response.new("", 204, {}), Person.find(1).put(:promote, {:position => 'Manager'}, 'body')
-
- # Test DELETE against an element URL
- assert_equal ActiveResource::Response.new("", 200, {}), Person.find(1).delete(:deactivate)
-
- # With nested resources
- assert_equal StreetAddress.find(1, :params => { :person_id => 1 }).get(:deep),
- { "id" => 1, "street" => '12345 Street', "zip" => "27519" }
- assert_equal ActiveResource::Response.new("", 204, {}),
- StreetAddress.find(1, :params => { :person_id => 1 }).put(:normalize_phone, :locale => 'US')
- end
-
- def test_custom_new_element_method
- # Test POST against a new element URL
- ryan = Person.new(:name => 'Ryan')
- assert_equal ActiveResource::Response.new(@ryan, 201, {'Location' => '/people/5.xml'}), ryan.post(:register)
- expected_request = ActiveResource::Request.new(:post, '/people/new/register.xml', @ryan)
- assert_equal expected_request.body, ActiveResource::HttpMock.requests.first.body
-
- # Test POST against a nested collection URL
- addy = StreetAddress.new(:street => '123 Test Dr.', :person_id => 1)
- assert_equal ActiveResource::Response.new({ :street => '12345 Street' }.to_xml(:root => 'address'),
- 201, {'Location' => '/people/1/addresses/2.xml'}),
- addy.post(:link)
-
- matz = Person.new(:id => 1, :name => 'Matz')
- assert_equal ActiveResource::Response.new(@matz, 201), matz.post(:register)
- end
-
- def test_find_custom_resources
- assert_equal 'Matz', Person.find(:all, :from => :managers).first.name
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/base/equality_test.rb ruby-activeresource-3.1.0/test/base/equality_test.rb
--- ruby-activeresource-2.3.14/test/base/equality_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/base/equality_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-require 'abstract_unit'
-require "fixtures/person"
-require "fixtures/street_address"
-
-class BaseEqualityTest < Test::Unit::TestCase
- def setup
- @new = Person.new
- @one = Person.new(:id => 1)
- @two = Person.new(:id => 2)
- @street = StreetAddress.new(:id => 2)
- end
-
- def test_should_equal_self
- assert @new == @new, '@new == @new'
- assert @one == @one, '@one == @one'
- end
-
- def test_shouldnt_equal_new_resource
- assert @new != @one, '@new != @one'
- assert @one != @new, '@one != @new'
- end
-
- def test_shouldnt_equal_different_class
- assert @two != @street, 'person != street_address with same id'
- assert @street != @two, 'street_address != person with same id'
- end
-
- def test_eql_should_alias_equals_operator
- assert_equal @new == @new, @new.eql?(@new)
- assert_equal @new == @one, @new.eql?(@one)
-
- assert_equal @one == @one, @one.eql?(@one)
- assert_equal @one == @new, @one.eql?(@new)
-
- assert_equal @one == @street, @one.eql?(@street)
- end
-
- def test_hash_should_be_id_hash
- [@new, @one, @two, @street].each do |resource|
- assert_equal resource.id.hash, resource.hash
- end
- end
-
- def test_with_prefix_options
- assert_equal @one == @one, @one.eql?(@one)
- assert_equal @one == @one.dup, @one.eql?(@one.dup)
- new_one = @one.dup
- new_one.prefix_options = {:foo => 'bar'}
- assert_not_equal @one, new_one
- end
-
-end
diff -Nru ruby-activeresource-2.3.14/test/base/load_test.rb ruby-activeresource-3.1.0/test/base/load_test.rb
--- ruby-activeresource-2.3.14/test/base/load_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/base/load_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,161 +0,0 @@
-require 'abstract_unit'
-require "fixtures/person"
-require "fixtures/street_address"
-
-module Highrise
- class Note < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
- end
-
- class Comment < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
- end
-
- module Deeply
- module Nested
-
- class Note < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
- end
-
- class Comment < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
- end
-
- module TestDifferentLevels
-
- class Note < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
- end
-
- end
-
- end
- end
-
-end
-
-
-class BaseLoadTest < Test::Unit::TestCase
- def setup
- @matz = { :id => 1, :name => 'Matz' }
-
- @first_address = { :id => 1, :street => '12345 Street' }
- @addresses = [@first_address, { :id => 2, :street => '67890 Street' }]
- @addresses_from_xml = { :street_addresses => @addresses }
- @addresses_from_xml_single = { :street_addresses => [ @first_address ] }
-
- @deep = { :id => 1, :street => {
- :id => 1, :state => { :id => 1, :name => 'Oregon',
- :notable_rivers => [
- { :id => 1, :name => 'Willamette' },
- { :id => 2, :name => 'Columbia', :rafted_by => @matz }],
- :postal_codes => [ 97018, 1234567890 ],
- :places => [ "Columbia City", "Unknown" ]}}}
-
- @person = Person.new
- end
-
- def test_load_expects_hash
- assert_raise(ArgumentError) { @person.load nil }
- assert_raise(ArgumentError) { @person.load '' }
- end
-
- def test_load_simple_hash
- assert_equal Hash.new, @person.attributes
- assert_equal @matz.stringify_keys, @person.load(@matz).attributes
- end
-
- def test_load_one_with_existing_resource
- address = @person.load(:street_address => @first_address).street_address
- assert_kind_of StreetAddress, address
- assert_equal @first_address.stringify_keys, address.attributes
- end
-
- def test_load_one_with_unknown_resource
- address = silence_warnings { @person.load(:address => @first_address).address }
- assert_kind_of Person::Address, address
- assert_equal @first_address.stringify_keys, address.attributes
- end
-
- def test_load_collection_with_existing_resource
- addresses = @person.load(@addresses_from_xml).street_addresses
- assert_kind_of Array, addresses
- addresses.each { |address| assert_kind_of StreetAddress, address }
- assert_equal @addresses.map(&:stringify_keys), addresses.map(&:attributes)
- end
-
- def test_load_collection_with_unknown_resource
- Person.__send__(:remove_const, :Address) if Person.const_defined?(:Address)
- assert !Person.const_defined?(:Address), "Address shouldn't exist until autocreated"
- addresses = silence_warnings { @person.load(:addresses => @addresses).addresses }
- assert Person.const_defined?(:Address), "Address should have been autocreated"
- addresses.each { |address| assert_kind_of Person::Address, address }
- assert_equal @addresses.map(&:stringify_keys), addresses.map(&:attributes)
- end
-
- def test_load_collection_with_single_existing_resource
- addresses = @person.load(@addresses_from_xml_single).street_addresses
- assert_kind_of Array, addresses
- addresses.each { |address| assert_kind_of StreetAddress, address }
- assert_equal [ @first_address ].map(&:stringify_keys), addresses.map(&:attributes)
- end
-
- def test_load_collection_with_single_unknown_resource
- Person.__send__(:remove_const, :Address) if Person.const_defined?(:Address)
- assert !Person.const_defined?(:Address), "Address shouldn't exist until autocreated"
- addresses = silence_warnings { @person.load(:addresses => [ @first_address ]).addresses }
- assert Person.const_defined?(:Address), "Address should have been autocreated"
- addresses.each { |address| assert_kind_of Person::Address, address }
- assert_equal [ @first_address ].map(&:stringify_keys), addresses.map(&:attributes)
- end
-
- def test_recursively_loaded_collections
- person = @person.load(@deep)
- assert_equal @deep[:id], person.id
-
- street = person.street
- assert_kind_of Person::Street, street
- assert_equal @deep[:street][:id], street.id
-
- state = street.state
- assert_kind_of Person::Street::State, state
- assert_equal @deep[:street][:state][:id], state.id
-
- rivers = state.notable_rivers
- assert_kind_of Array, rivers
- assert_kind_of Person::Street::State::NotableRiver, rivers.first
- assert_equal @deep[:street][:state][:notable_rivers].first[:id], rivers.first.id
- assert_equal @matz[:id], rivers.last.rafted_by.id
-
- postal_codes = state.postal_codes
- assert_kind_of Array, postal_codes
- assert_equal 2, postal_codes.size
- assert_kind_of Fixnum, postal_codes.first
- assert_equal @deep[:street][:state][:postal_codes].first, postal_codes.first
- assert_kind_of Numeric, postal_codes.last
- assert_equal @deep[:street][:state][:postal_codes].last, postal_codes.last
-
- places = state.places
- assert_kind_of Array, places
- assert_kind_of String, places.first
- assert_equal @deep[:street][:state][:places].first, places.first
- end
-
- def test_nested_collections_within_the_same_namespace
- n = Highrise::Note.new(:comments => [{ :name => "1" }])
- assert_kind_of Highrise::Comment, n.comments.first
- end
-
- def test_nested_collections_within_deeply_nested_namespace
- n = Highrise::Deeply::Nested::Note.new(:comments => [{ :name => "1" }])
- assert_kind_of Highrise::Deeply::Nested::Comment, n.comments.first
- end
-
- def test_nested_collections_in_different_levels_of_namespaces
- n = Highrise::Deeply::Nested::TestDifferentLevels::Note.new(:comments => [{ :name => "1" }])
- assert_kind_of Highrise::Deeply::Nested::Comment, n.comments.first
- end
-
-
-end
diff -Nru ruby-activeresource-2.3.14/test/base_errors_test.rb ruby-activeresource-3.1.0/test/base_errors_test.rb
--- ruby-activeresource-2.3.14/test/base_errors_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/base_errors_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,98 +0,0 @@
-require 'abstract_unit'
-require "fixtures/person"
-
-class BaseErrorsTest < Test::Unit::TestCase
- def setup
- ActiveResource::HttpMock.respond_to do |mock|
- mock.post "/people.xml", {}, %q(Age can't be blankName can't be blankName must start with a letterPerson quota full for today.), 422, {'Content-Type' => 'application/xml; charset=utf-8'}
- mock.post "/people.json", {}, %q({"errors":["Age can't be blank","Name can't be blank","Name must start with a letter","Person quota full for today."]}), 422, {'Content-Type' => 'application/json; charset=utf-8'}
- end
- @person = Person.new(:name => '', :age => '')
- assert_equal @person.save, false
- end
-
- def test_should_mark_as_invalid
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- assert !@person.valid?
- end
- end
- end
-
- def test_should_parse_xml_errors
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- assert_kind_of ActiveResource::Errors, @person.errors
- assert_equal 4, @person.errors.size
- end
- end
- end
-
- def test_should_parse_errors_to_individual_attributes
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- assert @person.errors[:name].any?
- assert_equal "can't be blank", @person.errors[:age]
- assert_equal ["can't be blank", "must start with a letter"], @person.errors[:name]
- assert_equal "Person quota full for today.", @person.errors[:base]
- end
- end
- end
-
- def test_should_iterate_over_errors
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- errors = []
- @person.errors.each { |attribute, message| errors << [attribute, message] }
- assert errors.include?(['name', "can't be blank"])
- end
- end
- end
-
- def test_should_iterate_over_full_errors
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- errors = []
- @person.errors.to_a.each { |message| errors << message }
- assert errors.include?(["name", "can't be blank"])
- end
- end
- end
-
- def test_should_format_full_errors
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- full = @person.errors.full_messages
- assert full.include?("Age can't be blank")
- assert full.include?("Name can't be blank")
- assert full.include?("Name must start with a letter")
- assert full.include?("Person quota full for today.")
- end
- end
- end
-
- def test_should_mark_as_invalid_when_content_type_is_unavailable_in_response_header
- ActiveResource::HttpMock.respond_to do |mock|
- mock.post "/people.xml", {}, %q(Age can't be blankName can't be blankName must start with a letterPerson quota full for today.), 422, {}
- mock.post "/people.json", {}, %q({"errors":["Age can't be blank","Name can't be blank","Name must start with a letter","Person quota full for today."]}), 422, {}
- end
-
- [ :json, :xml ].each do |format|
- invalid_user_using_format(format) do
- assert !@person.valid?
- end
- end
- end
-
- private
- def invalid_user_using_format(mime_type_reference)
- previous_format = Person.format
- Person.format = mime_type_reference
- @person = Person.new(:name => '', :age => '')
- assert_equal false, @person.save
-
- yield
- ensure
- Person.format = previous_format
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/base_test.rb ruby-activeresource-3.1.0/test/base_test.rb
--- ruby-activeresource-2.3.14/test/base_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/base_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,1087 +0,0 @@
-require 'abstract_unit'
-require "fixtures/person"
-require "fixtures/customer"
-require "fixtures/street_address"
-require "fixtures/beast"
-require "fixtures/proxy"
-require 'active_support/json'
-
-class BaseTest < Test::Unit::TestCase
- def setup
- @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
- @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
- @greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
- @addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
- @default_request_headers = { 'Content-Type' => 'application/xml' }
- @rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
- @joe = {'person' => { :id => 6, :name => 'Joe' }}.to_json
- @people = [{ :id => 1, :name => 'Matz' }, { :id => 2, :name => 'David' }].to_xml(:root => 'people')
- @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people')
- @addresses = [{ :id => 1, :street => '12345 Street' }].to_xml(:root => 'addresses')
-
- # - deep nested resource -
- # - Luis (Customer)
- # - JK (Customer::Friend)
- # - Mateo (Customer::Friend::Brother)
- # - Edith (Customer::Friend::Brother::Child)
- # - Martha (Customer::Friend::Brother::Child)
- # - Felipe (Customer::Friend::Brother)
- # - Bryan (Customer::Friend::Brother::Child)
- # - Luke (Customer::Friend::Brother::Child)
- # - Eduardo (Customer::Friend)
- # - Sebas (Customer::Friend::Brother)
- # - Andres (Customer::Friend::Brother::Child)
- # - Jorge (Customer::Friend::Brother::Child)
- # - Elsa (Customer::Friend::Brother)
- # - Natacha (Customer::Friend::Brother::Child)
- # - Milena (Customer::Friend::Brother)
- #
- @luis = {:id => 1, :name => 'Luis',
- :friends => [{:name => 'JK',
- :brothers => [{:name => 'Mateo',
- :children => [{:name => 'Edith'},{:name => 'Martha'}]},
- {:name => 'Felipe',
- :children => [{:name => 'Bryan'},{:name => 'Luke'}]}]},
- {:name => 'Eduardo',
- :brothers => [{:name => 'Sebas',
- :children => [{:name => 'Andres'},{:name => 'Jorge'}]},
- {:name => 'Elsa',
- :children => [{:name => 'Natacha'}]},
- {:name => 'Milena',
- :children => []}]}]}.to_xml(:root => 'customer')
- # - resource with yaml array of strings; for ActiveRecords using serialize :bar, Array
- @marty = <<-eof.strip
-
-
- 5
- Marty
- ---
- - \"red\"
- - \"green\"
- - \"blue\"
-
-
- eof
-
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, @matz
- mock.get "/people/2.xml", {}, @david
- mock.get "/people/6.json", {}, @joe
- mock.get "/people/5.xml", {}, @marty
- mock.get "/people/Greg.xml", {}, @greg
- mock.get "/people/4.xml", {'key' => 'value'}, nil, 404
- mock.put "/people/1.xml", {}, nil, 204
- mock.delete "/people/1.xml", {}, nil, 200
- mock.delete "/people/2.xml", {}, nil, 400
- mock.get "/people/99.xml", {}, nil, 404
- mock.post "/people.xml", {}, @rick, 201, 'Location' => '/people/5.xml'
- mock.get "/people.xml", {}, @people
- mock.get "/people/1/addresses.xml", {}, @addresses
- mock.get "/people/1/addresses/1.xml", {}, @addy
- mock.get "/people/1/addresses/2.xml", {}, nil, 404
- mock.get "/people/2/addresses/1.xml", {}, nil, 404
- mock.get "/people/Greg/addresses/1.xml", {}, @addy
- mock.put "/people/1/addresses/1.xml", {}, nil, 204
- mock.delete "/people/1/addresses/1.xml", {}, nil, 200
- mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5'
- mock.get "/people//addresses.xml", {}, nil, 404
- mock.get "/people//addresses/1.xml", {}, nil, 404
- mock.put "/people//addresses/1.xml", {}, nil, 404
- mock.delete "/people//addresses/1.xml", {}, nil, 404
- mock.post "/people//addresses.xml", {}, nil, 404
- mock.head "/people/1.xml", {}, nil, 200
- mock.head "/people/Greg.xml", {}, nil, 200
- mock.head "/people/99.xml", {}, nil, 404
- mock.head "/people/1/addresses/1.xml", {}, nil, 200
- mock.head "/people/1/addresses/2.xml", {}, nil, 404
- mock.head "/people/2/addresses/1.xml", {}, nil, 404
- mock.head "/people/Greg/addresses/1.xml", {}, nil, 200
- # customer
- mock.get "/customers/1.xml", {}, @luis
- end
-
- Person.user = nil
- Person.password = nil
- end
-
-
- def test_site_accessor_accepts_uri_or_string_argument
- site = URI.parse('http://localhost')
-
- assert_nothing_raised { Person.site = 'http://localhost' }
- assert_equal site, Person.site
-
- assert_nothing_raised { Person.site = site }
- assert_equal site, Person.site
- end
-
- def test_should_use_site_prefix_and_credentials
- assert_equal 'http://foo:bar@beast.caboo.se', Forum.site.to_s
- assert_equal 'http://foo:bar@beast.caboo.se/forums/:forum_id', Topic.site.to_s
- end
-
- def test_site_variable_can_be_reset
- actor = Class.new(ActiveResource::Base)
- assert_nil actor.site
- actor.site = 'http://localhost:31337'
- actor.site = nil
- assert_nil actor.site
- end
-
- def test_proxy_accessor_accepts_uri_or_string_argument
- proxy = URI.parse('http://localhost')
-
- assert_nothing_raised { Person.proxy = 'http://localhost' }
- assert_equal proxy, Person.proxy
-
- assert_nothing_raised { Person.proxy = proxy }
- assert_equal proxy, Person.proxy
- end
-
- def test_should_use_proxy_prefix_and_credentials
- assert_equal 'http://user:password@proxy.local:3000', ProxyResource.proxy.to_s
- end
-
- def test_proxy_variable_can_be_reset
- actor = Class.new(ActiveResource::Base)
- assert_nil actor.site
- actor.proxy = 'http://localhost:31337'
- actor.proxy = nil
- assert_nil actor.site
- end
-
- def test_should_accept_setting_user
- Forum.user = 'david'
- assert_equal('david', Forum.user)
- assert_equal('david', Forum.connection.user)
- end
-
- def test_should_accept_setting_password
- Forum.password = 'test123'
- assert_equal('test123', Forum.password)
- assert_equal('test123', Forum.connection.password)
- end
-
- def test_should_accept_setting_timeout
- Forum.timeout = 5
- assert_equal(5, Forum.timeout)
- assert_equal(5, Forum.connection.timeout)
- end
-
- def test_should_accept_setting_ssl_options
- expected = {:verify => 1}
- Forum.ssl_options= expected
- assert_equal(expected, Forum.ssl_options)
- assert_equal(expected, Forum.connection.ssl_options)
- end
-
- def test_user_variable_can_be_reset
- actor = Class.new(ActiveResource::Base)
- actor.site = 'http://cinema'
- assert_nil actor.user
- actor.user = 'username'
- actor.user = nil
- assert_nil actor.user
- assert_nil actor.connection.user
- end
-
- def test_password_variable_can_be_reset
- actor = Class.new(ActiveResource::Base)
- actor.site = 'http://cinema'
- assert_nil actor.password
- actor.password = 'username'
- actor.password = nil
- assert_nil actor.password
- assert_nil actor.connection.password
- end
-
- def test_timeout_variable_can_be_reset
- actor = Class.new(ActiveResource::Base)
- actor.site = 'http://cinema'
- assert_nil actor.timeout
- actor.timeout = 5
- actor.timeout = nil
- assert_nil actor.timeout
- assert_nil actor.connection.timeout
- end
-
- def test_ssl_options_hash_can_be_reset
- actor = Class.new(ActiveResource::Base)
- actor.site = 'https://cinema'
- assert_nil actor.ssl_options
- actor.ssl_options = {:foo => 5}
- actor.ssl_options = nil
- assert_nil actor.ssl_options
- assert_nil actor.connection.ssl_options
- end
-
- def test_credentials_from_site_are_decoded
- actor = Class.new(ActiveResource::Base)
- actor.site = 'http://my%40email.com:%31%32%33@cinema'
- assert_equal("my@email.com", actor.user)
- assert_equal("123", actor.password)
- end
-
- def test_site_reader_uses_superclass_site_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.site
- assert_nil Class.new(ActiveResource::Base).site
-
- # Subclass uses superclass site.
- actor = Class.new(Person)
- assert_equal Person.site, actor.site
-
- # Subclass returns frozen superclass copy.
- assert !Person.site.frozen?
- assert actor.site.frozen?
-
- # Changing subclass site doesn't change superclass site.
- actor.site = 'http://localhost:31337'
- assert_not_equal Person.site, actor.site
-
- # Changed subclass site is not frozen.
- assert !actor.site.frozen?
-
- # Changing superclass site doesn't overwrite subclass site.
- Person.site = 'http://somewhere.else'
- assert_not_equal Person.site, actor.site
-
- # Changing superclass site after subclassing changes subclass site.
- jester = Class.new(actor)
- actor.site = 'http://nomad'
- assert_equal actor.site, jester.site
- assert jester.site.frozen?
-
- # Subclasses are always equal to superclass site when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.site = 'http://market'
- assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
-
- fruit.site = 'http://supermarket'
- assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
- end
-
- def test_proxy_reader_uses_superclass_site_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.proxy
- assert_nil Class.new(ActiveResource::Base).proxy
-
- # Subclass uses superclass proxy.
- actor = Class.new(Person)
- assert_equal Person.proxy, actor.proxy
-
- # Subclass returns frozen superclass copy.
- assert !Person.proxy.frozen?
- assert actor.proxy.frozen?
-
- # Changing subclass proxy doesn't change superclass site.
- actor.proxy = 'http://localhost:31337'
- assert_not_equal Person.proxy, actor.proxy
-
- # Changed subclass proxy is not frozen.
- assert !actor.proxy.frozen?
-
- # Changing superclass proxy doesn't overwrite subclass site.
- Person.proxy = 'http://somewhere.else'
- assert_not_equal Person.proxy, actor.proxy
-
- # Changing superclass proxy after subclassing changes subclass site.
- jester = Class.new(actor)
- actor.proxy = 'http://nomad'
- assert_equal actor.proxy, jester.proxy
- assert jester.proxy.frozen?
-
- # Subclasses are always equal to superclass proxy when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.proxy = 'http://market'
- assert_equal fruit.proxy, apple.proxy, 'subclass did not adopt changes from parent class'
-
- fruit.proxy = 'http://supermarket'
- assert_equal fruit.proxy, apple.proxy, 'subclass did not adopt changes from parent class'
- end
-
- def test_user_reader_uses_superclass_user_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.user
- assert_nil Class.new(ActiveResource::Base).user
- Person.user = 'anonymous'
-
- # Subclass uses superclass user.
- actor = Class.new(Person)
- assert_equal Person.user, actor.user
-
- # Subclass returns frozen superclass copy.
- assert !Person.user.frozen?
- assert actor.user.frozen?
-
- # Changing subclass user doesn't change superclass user.
- actor.user = 'david'
- assert_not_equal Person.user, actor.user
-
- # Changing superclass user doesn't overwrite subclass user.
- Person.user = 'john'
- assert_not_equal Person.user, actor.user
-
- # Changing superclass user after subclassing changes subclass user.
- jester = Class.new(actor)
- actor.user = 'john.doe'
- assert_equal actor.user, jester.user
-
- # Subclasses are always equal to superclass user when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.user = 'manager'
- assert_equal fruit.user, apple.user, 'subclass did not adopt changes from parent class'
-
- fruit.user = 'client'
- assert_equal fruit.user, apple.user, 'subclass did not adopt changes from parent class'
- end
-
- def test_password_reader_uses_superclass_password_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.password
- assert_nil Class.new(ActiveResource::Base).password
- Person.password = 'my-password'
-
- # Subclass uses superclass password.
- actor = Class.new(Person)
- assert_equal Person.password, actor.password
-
- # Subclass returns frozen superclass copy.
- assert !Person.password.frozen?
- assert actor.password.frozen?
-
- # Changing subclass password doesn't change superclass password.
- actor.password = 'secret'
- assert_not_equal Person.password, actor.password
-
- # Changing superclass password doesn't overwrite subclass password.
- Person.password = 'super-secret'
- assert_not_equal Person.password, actor.password
-
- # Changing superclass password after subclassing changes subclass password.
- jester = Class.new(actor)
- actor.password = 'even-more-secret'
- assert_equal actor.password, jester.password
-
- # Subclasses are always equal to superclass password when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.password = 'mega-secret'
- assert_equal fruit.password, apple.password, 'subclass did not adopt changes from parent class'
-
- fruit.password = 'ok-password'
- assert_equal fruit.password, apple.password, 'subclass did not adopt changes from parent class'
- end
-
- def test_timeout_reader_uses_superclass_timeout_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.timeout
- assert_nil Class.new(ActiveResource::Base).timeout
- Person.timeout = 5
-
- # Subclass uses superclass timeout.
- actor = Class.new(Person)
- assert_equal Person.timeout, actor.timeout
-
- # Changing subclass timeout doesn't change superclass timeout.
- actor.timeout = 10
- assert_not_equal Person.timeout, actor.timeout
-
- # Changing superclass timeout doesn't overwrite subclass timeout.
- Person.timeout = 15
- assert_not_equal Person.timeout, actor.timeout
-
- # Changing superclass timeout after subclassing changes subclass timeout.
- jester = Class.new(actor)
- actor.timeout = 20
- assert_equal actor.timeout, jester.timeout
-
- # Subclasses are always equal to superclass timeout when not overridden.
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.timeout = 25
- assert_equal fruit.timeout, apple.timeout, 'subclass did not adopt changes from parent class'
-
- fruit.timeout = 30
- assert_equal fruit.timeout, apple.timeout, 'subclass did not adopt changes from parent class'
- end
-
- def test_ssl_options_reader_uses_superclass_ssl_options_until_written
- # Superclass is Object so returns nil.
- assert_nil ActiveResource::Base.ssl_options
- assert_nil Class.new(ActiveResource::Base).ssl_options
- Person.ssl_options = {:foo => 'bar'}
-
- # Subclass uses superclass ssl_options.
- actor = Class.new(Person)
- assert_equal Person.ssl_options, actor.ssl_options
-
- # Changing subclass ssl_options doesn't change superclass ssl_options.
- actor.ssl_options = {:baz => ''}
- assert_not_equal Person.ssl_options, actor.ssl_options
-
- # Changing superclass ssl_options doesn't overwrite subclass ssl_options.
- Person.ssl_options = {:color => 'blue'}
- assert_not_equal Person.ssl_options, actor.ssl_options
-
- # Changing superclass ssl_options after subclassing changes subclass ssl_options.
- jester = Class.new(actor)
- actor.ssl_options = {:color => 'red'}
- assert_equal actor.ssl_options, jester.ssl_options
-
- # Subclasses are always equal to superclass ssl_options when not overridden.
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.ssl_options = {:alpha => 'betas'}
- assert_equal fruit.ssl_options, apple.ssl_options, 'subclass did not adopt changes from parent class'
-
- fruit.ssl_options = {:omega => 'moos'}
- assert_equal fruit.ssl_options, apple.ssl_options, 'subclass did not adopt changes from parent class'
- end
-
- def test_updating_baseclass_site_object_wipes_descendent_cached_connection_objects
- # Subclasses are always equal to superclass site when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
-
- fruit.site = 'http://market'
- assert_equal fruit.connection.site, apple.connection.site
- first_connection = apple.connection.object_id
-
- fruit.site = 'http://supermarket'
- assert_equal fruit.connection.site, apple.connection.site
- second_connection = apple.connection.object_id
- assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
- end
-
- def test_updating_baseclass_user_wipes_descendent_cached_connection_objects
- # Subclasses are always equal to superclass user when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
- fruit.site = 'http://market'
-
- fruit.user = 'david'
- assert_equal fruit.connection.user, apple.connection.user
- first_connection = apple.connection.object_id
-
- fruit.user = 'john'
- assert_equal fruit.connection.user, apple.connection.user
- second_connection = apple.connection.object_id
- assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
- end
-
- def test_updating_baseclass_password_wipes_descendent_cached_connection_objects
- # Subclasses are always equal to superclass password when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
- fruit.site = 'http://market'
-
- fruit.password = 'secret'
- assert_equal fruit.connection.password, apple.connection.password
- first_connection = apple.connection.object_id
-
- fruit.password = 'supersecret'
- assert_equal fruit.connection.password, apple.connection.password
- second_connection = apple.connection.object_id
- assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
- end
-
- def test_updating_baseclass_timeout_wipes_descendent_cached_connection_objects
- # Subclasses are always equal to superclass timeout when not overridden
- fruit = Class.new(ActiveResource::Base)
- apple = Class.new(fruit)
- fruit.site = 'http://market'
-
- fruit.timeout = 5
- assert_equal fruit.connection.timeout, apple.connection.timeout
- first_connection = apple.connection.object_id
-
- fruit.timeout = 10
- assert_equal fruit.connection.timeout, apple.connection.timeout
- second_connection = apple.connection.object_id
- assert_not_equal(first_connection, second_connection, 'Connection should be re-created')
- end
-
- def test_collection_name
- assert_equal "people", Person.collection_name
- end
-
- def test_collection_path
- assert_equal '/people.xml', Person.collection_path
- end
-
- def test_collection_path_with_parameters
- assert_equal '/people.xml?gender=male', Person.collection_path(:gender => 'male')
- assert_equal '/people.xml?gender=false', Person.collection_path(:gender => false)
- assert_equal '/people.xml?gender=', Person.collection_path(:gender => nil)
-
- assert_equal '/people.xml?gender=male', Person.collection_path('gender' => 'male')
-
- # Use includes? because ordering of param hash is not guaranteed
- assert Person.collection_path(:gender => 'male', :student => true).include?('/people.xml?')
- assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
- assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
-
- assert_equal '/people.xml?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
-
- assert_equal '/people.xml?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
- end
-
- def test_custom_element_path
- assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, :person_id => 1)
- assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 1)
- assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg')
- end
-
- def test_custom_element_path_with_redefined_to_param
- Person.module_eval do
- alias_method :original_to_param_element_path, :to_param
- def to_param
- name
- end
- end
-
- # Class method.
- assert_equal '/people/Greg.xml', Person.element_path('Greg')
-
- # Protected Instance method.
- assert_equal '/people/Greg.xml', Person.find('Greg').send(:element_path)
-
- ensure
- # revert back to original
- Person.module_eval do
- # save the 'new' to_param so we don't get a warning about discarding the method
- alias_method :element_path_to_param, :to_param
- alias_method :to_param, :original_to_param_element_path
- end
- end
-
- def test_custom_element_path_with_parameters
- assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work')
- assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work')
- assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1)
- assert_equal '/people/1/addresses/1.xml?type%5B%5D=work&type%5B%5D=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time'])
- end
-
- def test_custom_element_path_with_prefix_and_parameters
- assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, {:person_id => 1}, {:type => 'work'})
- end
-
- def test_custom_collection_path
- assert_equal '/people/1/addresses.xml', StreetAddress.collection_path(:person_id => 1)
- assert_equal '/people/1/addresses.xml', StreetAddress.collection_path('person_id' => 1)
- end
-
- def test_custom_collection_path_with_parameters
- assert_equal '/people/1/addresses.xml?type=work', StreetAddress.collection_path(:person_id => 1, :type => 'work')
- assert_equal '/people/1/addresses.xml?type=work', StreetAddress.collection_path('person_id' => 1, :type => 'work')
- end
-
- def test_custom_collection_path_with_prefix_and_parameters
- assert_equal '/people/1/addresses.xml?type=work', StreetAddress.collection_path({:person_id => 1}, {:type => 'work'})
- end
-
- def test_custom_element_name
- assert_equal 'address', StreetAddress.element_name
- end
-
- def test_custom_collection_name
- assert_equal 'addresses', StreetAddress.collection_name
- end
-
- def test_prefix
- assert_equal "/", Person.prefix
- assert_equal Set.new, Person.__send__(:prefix_parameters)
- end
-
- def test_set_prefix
- SetterTrap.rollback_sets(Person) do |person_class|
- person_class.prefix = "the_prefix"
- assert_equal "the_prefix", person_class.prefix
- end
- end
-
- def test_set_prefix_with_inline_keys
- SetterTrap.rollback_sets(Person) do |person_class|
- person_class.prefix = "the_prefix:the_param"
- assert_equal "the_prefixthe_param_value", person_class.prefix(:the_param => "the_param_value")
- end
- end
-
- def test_set_prefix_twice_should_clear_params
- SetterTrap.rollback_sets(Person) do |person_class|
- person_class.prefix = "the_prefix/:the_param1"
- assert_equal Set.new([:the_param1]), person_class.prefix_parameters
- person_class.prefix = "the_prefix/:the_param2"
- assert_equal Set.new([:the_param2]), person_class.prefix_parameters
- end
- end
-
- def test_set_prefix_with_default_value
- SetterTrap.rollback_sets(Person) do |person_class|
- person_class.set_prefix
- assert_equal "/", person_class.prefix
- end
- end
-
- def test_custom_prefix
- assert_equal '/people//', StreetAddress.prefix
- assert_equal '/people/1/', StreetAddress.prefix(:person_id => 1)
- assert_equal [:person_id].to_set, StreetAddress.__send__(:prefix_parameters)
- end
-
- def test_find_by_id
- matz = Person.find(1)
- assert_kind_of Person, matz
- assert_equal "Matz", matz.name
- assert matz.name?
- end
-
- def test_respond_to
- matz = Person.find(1)
- assert matz.respond_to?(:name)
- assert matz.respond_to?(:name=)
- assert matz.respond_to?(:name?)
- assert !matz.respond_to?(:super_scalable_stuff)
- end
-
- def test_find_by_id_with_custom_prefix
- addy = StreetAddress.find(1, :params => { :person_id => 1 })
- assert_kind_of StreetAddress, addy
- assert_equal '12345 Street', addy.street
- end
-
- def test_find_all
- all = Person.find(:all)
- assert_equal 2, all.size
- assert_kind_of Person, all.first
- assert_equal "Matz", all.first.name
- assert_equal "David", all.last.name
- end
-
- def test_find_first
- matz = Person.find(:first)
- assert_kind_of Person, matz
- assert_equal "Matz", matz.name
- end
-
- def test_find_last
- david = Person.find(:last)
- assert_kind_of Person, david
- assert_equal 'David', david.name
- end
-
- def test_custom_header
- Person.headers['key'] = 'value'
- assert_raise(ActiveResource::ResourceNotFound) { Person.find(4) }
- ensure
- Person.headers.delete('key')
- end
-
- def test_find_by_id_not_found
- assert_raise(ActiveResource::ResourceNotFound) { Person.find(99) }
- assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1) }
- end
-
- def test_find_all_by_from
- ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
-
- people = Person.find(:all, :from => "/companies/1/people.xml")
- assert_equal 1, people.size
- assert_equal "David", people.first.name
- end
-
- def test_find_all_by_from_with_options
- ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
-
- people = Person.find(:all, :from => "/companies/1/people.xml")
- assert_equal 1, people.size
- assert_equal "David", people.first.name
- end
-
- def test_find_all_by_symbol_from
- ActiveResource::HttpMock.respond_to { |m| m.get "/people/managers.xml", {}, @people_david }
-
- people = Person.find(:all, :from => :managers)
- assert_equal 1, people.size
- assert_equal "David", people.first.name
- end
-
- def test_find_single_by_from
- ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/manager.xml", {}, @david }
-
- david = Person.find(:one, :from => "/companies/1/manager.xml")
- assert_equal "David", david.name
- end
-
- def test_find_single_by_symbol_from
- ActiveResource::HttpMock.respond_to { |m| m.get "/people/leader.xml", {}, @david }
-
- david = Person.find(:one, :from => :leader)
- assert_equal "David", david.name
- end
-
- def test_save
- rick = Person.new
- assert_equal true, rick.save
- assert_equal '5', rick.id
- end
-
- def test_id_from_response
- p = Person.new
- resp = {'Location' => '/foo/bar/1'}
- assert_equal '1', p.__send__(:id_from_response, resp)
-
- resp['Location'] << '.xml'
- assert_equal '1', p.__send__(:id_from_response, resp)
- end
-
- def test_id_from_response_without_location
- p = Person.new
- resp = {}
- assert_equal nil, p.__send__(:id_from_response, resp)
- end
-
- def test_create_with_custom_prefix
- matzs_house = StreetAddress.new(:person_id => 1)
- matzs_house.save
- assert_equal '5', matzs_house.id
- end
-
- # Test that loading a resource preserves its prefix_options.
- def test_load_preserves_prefix_options
- address = StreetAddress.find(1, :params => { :person_id => 1 })
- ryan = Person.new(:id => 1, :name => 'Ryan', :address => address)
- assert_equal address.prefix_options, ryan.address.prefix_options
- end
-
- def test_reload_works_with_prefix_options
- address = StreetAddress.find(1, :params => { :person_id => 1 })
- assert_equal address, address.reload
- end
-
- def test_reload_with_redefined_to_param
- Person.module_eval do
- alias_method :original_to_param_reload, :to_param
- def to_param
- name
- end
- end
-
- person = Person.find('Greg')
- assert_equal person, person.reload
-
- ensure
- # revert back to original
- Person.module_eval do
- # save the 'new' to_param so we don't get a warning about discarding the method
- alias_method :reload_to_param, :to_param
- alias_method :to_param, :original_to_param_reload
- end
- end
-
- def test_reload_works_without_prefix_options
- person = Person.find(:first)
- assert_equal person, person.reload
- end
-
- def test_create
- rick = Person.create(:name => 'Rick')
- assert rick.valid?
- assert !rick.new?
- assert_equal '5', rick.id
-
- # test additional attribute returned on create
- assert_equal 25, rick.age
-
- # Test that save exceptions get bubbled up too
- ActiveResource::HttpMock.respond_to do |mock|
- mock.post "/people.xml", {}, nil, 409
- end
- assert_raise(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
- end
-
- def test_create_without_location
- ActiveResource::HttpMock.respond_to do |mock|
- mock.post "/people.xml", {}, nil, 201
- end
- person = Person.create(:name => 'Rick')
- assert_equal nil, person.id
- end
-
- def test_clone
- matz = Person.find(1)
- matz_c = matz.clone
- assert matz_c.new?
- matz.attributes.each do |k, v|
- assert_equal v, matz_c.send(k) if k != Person.primary_key
- end
- end
-
- def test_nested_clone
- addy = StreetAddress.find(1, :params => {:person_id => 1})
- addy_c = addy.clone
- assert addy_c.new?
- addy.attributes.each do |k, v|
- assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key
- end
- assert_equal addy.prefix_options, addy_c.prefix_options
- end
-
- def test_complex_clone
- matz = Person.find(1)
- matz.address = StreetAddress.find(1, :params => {:person_id => matz.id})
- matz.non_ar_hash = {:not => "an ARes instance"}
- matz.non_ar_arr = ["not", "ARes"]
- matz_c = matz.clone
- assert matz_c.new?
- assert_raise(NoMethodError) {matz_c.address}
- assert_equal matz.non_ar_hash, matz_c.non_ar_hash
- assert_equal matz.non_ar_arr, matz_c.non_ar_arr
-
- # Test that actual copy, not just reference copy
- matz.non_ar_hash[:not] = "changed"
- assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash
- end
-
- def test_update
- matz = Person.find(:first)
- matz.name = "David"
- assert_kind_of Person, matz
- assert_equal "David", matz.name
- assert_equal true, matz.save
- end
-
- def test_update_with_custom_prefix_with_specific_id
- addy = StreetAddress.find(1, :params => { :person_id => 1 })
- addy.street = "54321 Street"
- assert_kind_of StreetAddress, addy
- assert_equal "54321 Street", addy.street
- addy.save
- end
-
- def test_update_with_custom_prefix_without_specific_id
- addy = StreetAddress.find(:first, :params => { :person_id => 1 })
- addy.street = "54321 Lane"
- assert_kind_of StreetAddress, addy
- assert_equal "54321 Lane", addy.street
- addy.save
- end
-
- def test_update_conflict
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/2.xml", {}, @david
- mock.put "/people/2.xml", @default_request_headers, nil, 409
- end
- assert_raise(ActiveResource::ResourceConflict) { Person.find(2).save }
- end
-
- def test_destroy
- assert Person.find(1).destroy
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, nil, 404
- end
- assert_raise(ActiveResource::ResourceNotFound) { Person.find(1).destroy }
- end
-
- def test_destroy_with_custom_prefix
- assert StreetAddress.find(1, :params => { :person_id => 1 }).destroy
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1/addresses/1.xml", {}, nil, 404
- end
- assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1, :params => { :person_id => 1 }) }
- end
-
- def test_destroy_with_410_gone
- assert Person.find(1).destroy
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, nil, 410
- end
- assert_raise(ActiveResource::ResourceGone) { Person.find(1).destroy }
- end
-
- def test_delete
- assert Person.delete(1)
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, nil, 404
- end
- assert_raise(ActiveResource::ResourceNotFound) { Person.find(1) }
- end
-
- def test_delete_with_custom_prefix
- assert StreetAddress.delete(1, :person_id => 1)
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1/addresses/1.xml", {}, nil, 404
- end
- assert_raise(ActiveResource::ResourceNotFound) { StreetAddress.find(1, :params => { :person_id => 1 }) }
- end
-
- def test_delete_with_410_gone
- assert Person.delete(1)
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/1.xml", {}, nil, 410
- end
- assert_raise(ActiveResource::ResourceGone) { Person.find(1) }
- end
-
- def test_exists
- # Class method.
- assert !Person.exists?(nil)
- assert Person.exists?(1)
- assert !Person.exists?(99)
-
- # Instance method.
- assert !Person.new.exists?
- assert Person.find(1).exists?
- assert !Person.new(:id => 99).exists?
-
- # Nested class method.
- assert StreetAddress.exists?(1, :params => { :person_id => 1 })
- assert !StreetAddress.exists?(1, :params => { :person_id => 2 })
- assert !StreetAddress.exists?(2, :params => { :person_id => 1 })
-
- # Nested instance method.
- assert StreetAddress.find(1, :params => { :person_id => 1 }).exists?
- assert !StreetAddress.new({:id => 1, :person_id => 2}).exists?
- assert !StreetAddress.new({:id => 2, :person_id => 1}).exists?
- end
-
- def test_exists_with_redefined_to_param
- Person.module_eval do
- alias_method :original_to_param_exists, :to_param
- def to_param
- name
- end
- end
-
- # Class method.
- assert Person.exists?('Greg')
-
- # Instance method.
- assert Person.find('Greg').exists?
-
- # Nested class method.
- assert StreetAddress.exists?(1, :params => { :person_id => Person.find('Greg').to_param })
-
- # Nested instance method.
- assert StreetAddress.find(1, :params => { :person_id => Person.find('Greg').to_param }).exists?
-
- ensure
- # revert back to original
- Person.module_eval do
- # save the 'new' to_param so we don't get a warning about discarding the method
- alias_method :exists_to_param, :to_param
- alias_method :to_param, :original_to_param_exists
- end
- end
-
- def test_exists_without_http_mock
- http = Net::HTTP.new(Person.site.host, Person.site.port)
- ActiveResource::Connection.any_instance.expects(:http).returns(http)
- http.expects(:request).returns(ActiveResource::Response.new(""))
-
- assert Person.exists?('not-mocked')
- end
-
- def test_exists_with_410_gone
- ActiveResource::HttpMock.respond_to do |mock|
- mock.head "/people/1.xml", {}, nil, 410
- end
-
- assert !Person.exists?(1)
- end
-
- def test_to_xml
- matz = Person.find(1)
- xml = matz.encode
- assert xml.starts_with?('')
- assert xml.include?('Matz')
- assert xml.include?('1')
- end
-
- def test_to_xml_with_element_name
- old_elem_name = Person.element_name
- matz = Person.find(1)
- Person.element_name = 'ruby_creator'
- xml = matz.encode
-
- assert xml.include?('')
- assert xml.include?('')
- assert xml.include?('Matz')
- assert xml.include?('1')
- assert xml.include?('')
- ensure
- Person.element_name = old_elem_name
- end
-
- def test_to_json_including_root
- Person.include_root_in_json = true
- Person.format = :json
- joe = Person.find(6)
- json = joe.encode
- assert_match '{"person":{"person":{', json
- assert_match '"name":"Joe"', json
- assert_match '"id":6', json
- ensure
- Person.format = :xml
- Person.include_root_in_json = false
- end
-
- def test_to_json_with_element_name
- old_elem_name = Person.element_name
- Person.include_root_in_json = true
- Person.format = :json
- joe = Person.find(6)
- Person.element_name = 'ruby_creator'
- json = joe.encode
- Person.format = :xml
-
- assert_match %r{^\{"ruby_creator":\{"person":\{}, json
- assert_match %r{"id":6}, json
- assert_match %r{"name":"Joe"}, json
- assert_match %r{\}\}\}$}, json
- ensure
- Person.element_name = old_elem_name
- Person.include_root_in_json = false
- end
-
- def test_to_param_quacks_like_active_record
- new_person = Person.new
- assert_nil new_person.to_param
- matz = Person.find(1)
- assert_equal '1', matz.to_param
- end
-
- def test_parse_deep_nested_resources
- luis = Customer.find(1)
- assert_kind_of Customer, luis
- luis.friends.each do |friend|
- assert_kind_of Customer::Friend, friend
- friend.brothers.each do |brother|
- assert_kind_of Customer::Friend::Brother, brother
- brother.children.each do |child|
- assert_kind_of Customer::Friend::Brother::Child, child
- end
- end
- end
- end
-
- def test_load_yaml_array
- assert_nothing_raised do
- marty = Person.find(5)
- assert_equal 3, marty.colors.size
- marty.colors.each do |color|
- assert_kind_of String, color
- end
- end
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/connection_test.rb ruby-activeresource-3.1.0/test/connection_test.rb
--- ruby-activeresource-2.3.14/test/connection_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/connection_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,238 +0,0 @@
-require 'abstract_unit'
-
-class ConnectionTest < Test::Unit::TestCase
- ResponseCodeStub = Struct.new(:code)
-
- def setup
- @conn = ActiveResource::Connection.new('http://localhost')
- @matz = { :id => 1, :name => 'Matz' }
- @david = { :id => 2, :name => 'David' }
- @people = [ @matz, @david ].to_xml(:root => 'people')
- @people_single = [ @matz ].to_xml(:root => 'people-single-elements')
- @people_empty = [ ].to_xml(:root => 'people-empty-elements')
- @matz = @matz.to_xml(:root => 'person')
- @david = @david.to_xml(:root => 'person')
- @header = {'key' => 'value'}.freeze
-
- @default_request_headers = { 'Content-Type' => 'application/xml' }
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/2.xml", @header, @david
- mock.get "/people.xml", {}, @people
- mock.get "/people_single_elements.xml", {}, @people_single
- mock.get "/people_empty_elements.xml", {}, @people_empty
- mock.get "/people/1.xml", {}, @matz
- mock.put "/people/1.xml", {}, nil, 204
- mock.put "/people/2.xml", {}, @header, 204
- mock.delete "/people/1.xml", {}, nil, 200
- mock.delete "/people/2.xml", @header, nil, 200
- mock.post "/people.xml", {}, nil, 201, 'Location' => '/people/5.xml'
- mock.post "/members.xml", {}, @header, 201, 'Location' => '/people/6.xml'
- mock.head "/people/1.xml", {}, nil, 200
- end
- end
-
- def test_handle_response
- # 2xx and 3xx are valid responses.
- [200, 299, 300, 399].each do |code|
- expected = ResponseCodeStub.new(code)
- assert_equal expected, handle_response(expected)
- end
-
- # 400 is a bad request (e.g. malformed URI or missing request parameter)
- assert_response_raises ActiveResource::BadRequest, 400
-
- # 401 is an unauthorized request
- assert_response_raises ActiveResource::UnauthorizedAccess, 401
-
- # 403 is a forbidden requst (and authorizing will not help)
- assert_response_raises ActiveResource::ForbiddenAccess, 403
-
- # 404 is a missing resource.
- assert_response_raises ActiveResource::ResourceNotFound, 404
-
- # 405 is a missing not allowed error
- assert_response_raises ActiveResource::MethodNotAllowed, 405
-
- # 409 is an optimistic locking error
- assert_response_raises ActiveResource::ResourceConflict, 409
-
- # 410 is a removed resource
- assert_response_raises ActiveResource::ResourceGone, 410
-
- # 422 is a validation error
- assert_response_raises ActiveResource::ResourceInvalid, 422
-
- # 4xx are client errors.
- [402, 499].each do |code|
- assert_response_raises ActiveResource::ClientError, code
- end
-
- # 5xx are server errors.
- [500, 599].each do |code|
- assert_response_raises ActiveResource::ServerError, code
- end
-
- # Others are unknown.
- [199, 600].each do |code|
- assert_response_raises ActiveResource::ConnectionError, code
- end
- end
-
- ResponseHeaderStub = Struct.new(:code, :message, 'Allow')
- def test_should_return_allowed_methods_for_method_no_allowed_exception
- begin
- handle_response ResponseHeaderStub.new(405, "HTTP Failed...", "GET, POST")
- rescue ActiveResource::MethodNotAllowed => e
- assert_equal "Failed with 405 HTTP Failed...", e.message
- assert_equal [:get, :post], e.allowed_methods
- end
- end
-
- def test_initialize_raises_argument_error_on_missing_site
- assert_raise(ArgumentError) { ActiveResource::Connection.new(nil) }
- end
-
- def test_site_accessor_accepts_uri_or_string_argument
- site = URI.parse("http://localhost")
-
- assert_raise(URI::InvalidURIError) { @conn.site = nil }
-
- assert_nothing_raised { @conn.site = "http://localhost" }
- assert_equal site, @conn.site
-
- assert_nothing_raised { @conn.site = site }
- assert_equal site, @conn.site
- end
-
- def test_proxy_accessor_accepts_uri_or_string_argument
- proxy = URI.parse("http://proxy_user:proxy_password@proxy.local:4242")
-
- assert_nothing_raised { @conn.proxy = "http://proxy_user:proxy_password@proxy.local:4242" }
- assert_equal proxy, @conn.proxy
-
- assert_nothing_raised { @conn.proxy = proxy }
- assert_equal proxy, @conn.proxy
- end
-
- def test_timeout_accessor
- @conn.timeout = 5
- assert_equal 5, @conn.timeout
- end
-
- def test_get
- matz = @conn.get("/people/1.xml")
- assert_equal "Matz", matz["name"]
- end
-
- def test_head
- response = @conn.head("/people/1.xml")
- assert response.body.blank?
- assert_equal 200, response.code
- end
-
- def test_get_with_header
- david = @conn.get("/people/2.xml", @header)
- assert_equal "David", david["name"]
- end
-
- def test_get_collection
- people = @conn.get("/people.xml")
- assert_equal "Matz", people[0]["name"]
- assert_equal "David", people[1]["name"]
- end
-
- def test_get_collection_single
- people = @conn.get("/people_single_elements.xml")
- assert_equal "Matz", people[0]["name"]
- end
-
- def test_get_collection_empty
- people = @conn.get("/people_empty_elements.xml")
- assert_equal [], people
- end
-
- def test_post
- response = @conn.post("/people.xml")
- assert_equal "/people/5.xml", response["Location"]
- end
-
- def test_post_with_header
- response = @conn.post("/members.xml", @header)
- assert_equal "/people/6.xml", response["Location"]
- end
-
- def test_put
- response = @conn.put("/people/1.xml")
- assert_equal 204, response.code
- end
-
- def test_put_with_header
- response = @conn.put("/people/2.xml", @header)
- assert_equal 204, response.code
- end
-
- def test_delete
- response = @conn.delete("/people/1.xml")
- assert_equal 200, response.code
- end
-
- def test_delete_with_header
- response = @conn.delete("/people/2.xml", @header)
- assert_equal 200, response.code
- end
-
- def test_timeout
- @http = mock('new Net::HTTP')
- @conn.expects(:http).returns(@http)
- @http.expects(:get).raises(Timeout::Error, 'execution expired')
- assert_raise(ActiveResource::TimeoutError) { @conn.get('/people_timeout.xml') }
- end
-
- def test_setting_timeout
- http = Net::HTTP.new('')
-
- [10, 20].each do |timeout|
- @conn.timeout = timeout
- @conn.send(:configure_http, http)
- assert_equal timeout, http.open_timeout
- assert_equal timeout, http.read_timeout
- end
- end
-
- def test_accept_http_header
- @http = mock('new Net::HTTP')
- @conn.expects(:http).returns(@http)
- path = '/people/1.xml'
- @http.expects(:get).with(path, {'Accept' => 'application/xhtml+xml'}).returns(ActiveResource::Response.new(@matz, 200, {'Content-Type' => 'text/xhtml'}))
- assert_nothing_raised(Mocha::ExpectationError) { @conn.get(path, {'Accept' => 'application/xhtml+xml'}) }
- end
-
- def test_ssl_options_get_applied_to_http
- http = Net::HTTP.new('')
- @conn.site="https://secure"
- @conn.ssl_options={:verify_mode => OpenSSL::SSL::VERIFY_PEER}
- @conn.timeout = 10 # prevent warning about uninitialized.
- @conn.send(:configure_http, http)
-
- assert http.use_ssl?
- assert_equal http.verify_mode, OpenSSL::SSL::VERIFY_PEER
- end
-
- def test_ssl_error
- http = Net::HTTP.new('')
- @conn.expects(:http).returns(http)
- http.expects(:get).raises(OpenSSL::SSL::SSLError, 'Expired certificate')
- assert_raise(ActiveResource::SSLError) { @conn.get('/people/1.xml') }
- end
-
- protected
- def assert_response_raises(klass, code)
- assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
- handle_response ResponseCodeStub.new(code)
- end
- end
-
- def handle_response(response)
- @conn.__send__(:handle_response, response)
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/fixtures/beast.rb ruby-activeresource-3.1.0/test/fixtures/beast.rb
--- ruby-activeresource-2.3.14/test/fixtures/beast.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/fixtures/beast.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,14 +0,0 @@
-class BeastResource < ActiveResource::Base
- self.site = 'http://beast.caboo.se'
- site.user = 'foo'
- site.password = 'bar'
-end
-
-class Forum < BeastResource
- # taken from BeastResource
- # self.site = 'http://beast.caboo.se'
-end
-
-class Topic < BeastResource
- self.site += '/forums/:forum_id'
-end
diff -Nru ruby-activeresource-2.3.14/test/fixtures/customer.rb ruby-activeresource-3.1.0/test/fixtures/customer.rb
--- ruby-activeresource-2.3.14/test/fixtures/customer.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/fixtures/customer.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-class Customer < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
-end
diff -Nru ruby-activeresource-2.3.14/test/fixtures/person.rb ruby-activeresource-3.1.0/test/fixtures/person.rb
--- ruby-activeresource-2.3.14/test/fixtures/person.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/fixtures/person.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-class Person < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000"
-end
diff -Nru ruby-activeresource-2.3.14/test/fixtures/proxy.rb ruby-activeresource-3.1.0/test/fixtures/proxy.rb
--- ruby-activeresource-2.3.14/test/fixtures/proxy.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/fixtures/proxy.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-class ProxyResource < ActiveResource::Base
- self.site = "http://localhost"
- self.proxy = "http://user:password@proxy.local:3000"
-end
\ No newline at end of file
diff -Nru ruby-activeresource-2.3.14/test/fixtures/street_address.rb ruby-activeresource-3.1.0/test/fixtures/street_address.rb
--- ruby-activeresource-2.3.14/test/fixtures/street_address.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/fixtures/street_address.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-class StreetAddress < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000/people/:person_id/"
- self.element_name = 'address'
-end
diff -Nru ruby-activeresource-2.3.14/test/format_test.rb ruby-activeresource-3.1.0/test/format_test.rb
--- ruby-activeresource-2.3.14/test/format_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/format_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,112 +0,0 @@
-require 'abstract_unit'
-require "fixtures/person"
-require "fixtures/street_address"
-
-class FormatTest < Test::Unit::TestCase
- def setup
- @matz = { :id => 1, :name => 'Matz' }
- @david = { :id => 2, :name => 'David' }
-
- @programmers = [ @matz, @david ]
- end
-
- def test_http_format_header_name
- header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:get]
- assert_equal 'Accept', header_name
-
- headers_names = [ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:put], ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:post]]
- headers_names.each{ |name| assert_equal 'Content-Type', name }
- end
-
- def test_formats_on_single_element
- for format in [ :json, :xml ]
- using_format(Person, format) do
- ActiveResource::HttpMock.respond_to.get "/people/1.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
- assert_equal @david[:name], Person.find(1).name
- end
- end
- end
-
- def test_formats_on_collection
- for format in [ :json, :xml ]
- using_format(Person, format) do
- ActiveResource::HttpMock.respond_to.get "/people.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@programmers)
- remote_programmers = Person.find(:all)
- assert_equal 2, remote_programmers.size
- assert remote_programmers.select { |p| p.name == 'David' }
- end
- end
- end
-
- def test_formats_on_custom_collection_method
- for format in [ :json, :xml ]
- using_format(Person, format) do
- ActiveResource::HttpMock.respond_to.get "/people/retrieve.#{format}?name=David", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode([@david])
- remote_programmers = Person.get(:retrieve, :name => 'David')
- assert_equal 1, remote_programmers.size
- assert_equal @david[:id], remote_programmers[0]['id']
- assert_equal @david[:name], remote_programmers[0]['name']
- end
- end
- end
-
- def test_formats_on_custom_element_method
- for format in [ :json, :xml ]
- using_format(Person, format) do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.get "/people/2.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
- mock.get "/people/2/shallow.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
- end
- remote_programmer = Person.find(2).get(:shallow)
- assert_equal @david[:id], remote_programmer['id']
- assert_equal @david[:name], remote_programmer['name']
- end
- end
-
- for format in [ :json, :xml ]
- ryan = ActiveResource::Formats[format].encode({ :name => 'Ryan' })
- using_format(Person, format) do
- remote_ryan = Person.new(:name => 'Ryan')
- ActiveResource::HttpMock.respond_to.post "/people.#{format}", {'Content-Type' => ActiveResource::Formats[format].mime_type}, ryan, 201, {'Location' => "/people/5.#{format}"}
- remote_ryan.save
-
- remote_ryan = Person.new(:name => 'Ryan')
- ActiveResource::HttpMock.respond_to.post "/people/new/register.#{format}", {'Content-Type' => ActiveResource::Formats[format].mime_type}, ryan, 201, {'Location' => "/people/5.#{format}"}
- assert_equal ActiveResource::Response.new(ryan, 201, {'Location' => "/people/5.#{format}"}), remote_ryan.post(:register)
- end
- end
- end
-
- def test_setting_format_before_site
- resource = Class.new(ActiveResource::Base)
- resource.format = :json
- resource.site = 'http://37s.sunrise.i:3000'
- assert_equal ActiveResource::Formats[:json], resource.connection.format
- end
-
- def test_serialization_of_nested_resource
- address = { :street => '12345 Street' }
- person = { :name=> 'Rus', :address => address}
-
- [:json, :xml].each do |format|
- encoded_person = ActiveResource::Formats[format].encode(person)
- assert_match(/12345 Street/, encoded_person)
- remote_person = Person.new(person.update({:address => StreetAddress.new(address)}))
- assert_kind_of StreetAddress, remote_person.address
- using_format(Person, format) do
- ActiveResource::HttpMock.respond_to.post "/people.#{format}", {'Content-Type' => ActiveResource::Formats[format].mime_type}, encoded_person, 201, {'Location' => "/people/5.#{format}"}
- remote_person.save
- end
- end
- end
-
- private
- def using_format(klass, mime_type_reference)
- previous_format = klass.format
- klass.format = mime_type_reference
-
- yield
- ensure
- klass.format = previous_format
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/http_mock_test.rb ruby-activeresource-3.1.0/test/http_mock_test.rb
--- ruby-activeresource-2.3.14/test/http_mock_test.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/http_mock_test.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,155 +0,0 @@
-require 'abstract_unit'
-
-class HttpMockTest < ActiveSupport::TestCase
- def setup
- @http = ActiveResource::HttpMock.new("http://example.com")
- end
-
- FORMAT_HEADER = { :get => 'Accept',
- :put => 'Content-Type',
- :post => 'Content-Type',
- :delete => 'Accept',
- :head => 'Accept'
- }
-
- [:post, :put, :get, :delete, :head].each do |method|
- test "responds to simple #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "Response")
- end
-
- assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
- end
-
- test "adds format header by default to #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {}, "Response")
- end
-
- assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
- end
-
- test "respond only when headers match header by default to #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {"X-Header" => "X"}, "Response")
- end
-
- assert_equal "Response", request(method, "/people/1", "X-Header" => "X").body
- assert_raise(ActiveResource::InvalidRequestError) { request(method, "/people/1") }
- end
-
- test "does not overwrite format header to #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/json"}, "Response")
- end
-
- assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
- end
-
- test "ignores format header when there is only one response to same url in a #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {}, "Response")
- end
-
- assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
- assert_equal "Response", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
- end
-
- test "responds correctly when format header is given to #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "XML")
- mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/json"}, "Json")
- end
-
- assert_equal "XML", request(method, "/people/1", FORMAT_HEADER[method] => "application/xml").body
- assert_equal "Json", request(method, "/people/1", FORMAT_HEADER[method] => "application/json").body
- end
-
- test "raises InvalidRequestError if no response found for the #{method} request" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(method, "/people/1", {FORMAT_HEADER[method] => "application/xml"}, "XML")
- end
-
- assert_raise(::ActiveResource::InvalidRequestError) do
- request(method, "/people/1", FORMAT_HEADER[method] => "application/json")
- end
- end
-
- end
-
- test "allows you to send in pairs directly to the respond_to method" do
- matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
-
- create_matz = ActiveResource::Request.new(:post, '/people.xml', matz, {})
- created_response = ActiveResource::Response.new("", 201, {"Location" => "/people/1.xml"})
- get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
- ok_response = ActiveResource::Response.new(matz, 200, {})
-
- pairs = {create_matz => created_response, get_matz => ok_response}
-
- ActiveResource::HttpMock.respond_to(pairs)
- assert_equal 2, ActiveResource::HttpMock.responses.length
- assert_equal "", ActiveResource::HttpMock.responses.assoc(create_matz)[1].body
- assert_equal matz, ActiveResource::HttpMock.responses.assoc(get_matz)[1].body
- end
-
- test "resets all mocked responses on each call to respond_to with a block by default" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(:get, "/people/1", {}, "XML1")
- end
- assert_equal 1, ActiveResource::HttpMock.responses.length
-
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(:get, "/people/2", {}, "XML2")
- end
- assert_equal 1, ActiveResource::HttpMock.responses.length
- end
-
- test "resets all mocked responses on each call to respond_to by passing pairs by default" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(:get, "/people/1", {}, "XML1")
- end
- assert_equal 1, ActiveResource::HttpMock.responses.length
-
- matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
- get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
- ok_response = ActiveResource::Response.new(matz, 200, {})
- ActiveResource::HttpMock.respond_to({get_matz => ok_response})
-
- assert_equal 1, ActiveResource::HttpMock.responses.length
- end
-
- test "allows you to add new responses to the existing responses by calling a block" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(:get, "/people/1", {}, "XML1")
- end
- assert_equal 1, ActiveResource::HttpMock.responses.length
-
- ActiveResource::HttpMock.respond_to(false) do |mock|
- mock.send(:get, "/people/2", {}, "XML2")
- end
- assert_equal 2, ActiveResource::HttpMock.responses.length
- end
-
- test "allows you to add new responses to the existing responses by passing pairs" do
- ActiveResource::HttpMock.respond_to do |mock|
- mock.send(:get, "/people/1", {}, "XML1")
- end
- assert_equal 1, ActiveResource::HttpMock.responses.length
-
- matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person")
- get_matz = ActiveResource::Request.new(:get, '/people/1.xml', nil)
- ok_response = ActiveResource::Response.new(matz, 200, {})
- ActiveResource::HttpMock.respond_to({get_matz => ok_response}, false)
-
- assert_equal 2, ActiveResource::HttpMock.responses.length
- end
-
- def request(method, path, headers = {}, body = nil)
- if [:put, :post].include? method
- @http.send(method, path, body, headers)
- else
- @http.send(method, path, headers)
- end
- end
-end
diff -Nru ruby-activeresource-2.3.14/test/setter_trap.rb ruby-activeresource-3.1.0/test/setter_trap.rb
--- ruby-activeresource-2.3.14/test/setter_trap.rb 2011-09-29 12:36:10.000000000 +0000
+++ ruby-activeresource-3.1.0/test/setter_trap.rb 1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-class SetterTrap < ActiveSupport::BasicObject
- class << self
- def rollback_sets(obj)
- trapped = new(obj)
- yield(trapped).tap { trapped.rollback_sets }
- end
- end
-
- def initialize(obj)
- @cache = {}
- @obj = obj
- end
-
- def respond_to?(method)
- @obj.respond_to?(method)
- end
-
- def method_missing(method, *args, &proc)
- @cache[method] ||= @obj.send($`) if method.to_s =~ /=$/
- @obj.send method, *args, &proc
- end
-
- def rollback_sets
- @cache.each { |k, v| @obj.send k, v }
- end
-end