mirror of
https://github.com/github/rails.git
synced 2026-04-04 03:00:58 -04:00
Added ActiveResource.format= which defaults to :xml but can also be set to :json [DHH]. Added one-off declarations of mock behavior [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7518 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,30 @@
|
||||
*SVN*
|
||||
|
||||
* Added one-off declarations of mock behavior [DHH]. Example:
|
||||
|
||||
Before:
|
||||
ActiveResource::HttpMock.respond_to do |mock|
|
||||
mock.get "/people/1.xml", {}, "<person><name>David</name></person>"
|
||||
end
|
||||
|
||||
Now:
|
||||
ActiveResource::HttpMock.respond_to.get "/people/1.xml", {}, "<person><name>David</name></person>"
|
||||
|
||||
* Added ActiveResource.format= which defaults to :xml but can also be set to :json [DHH]. Example:
|
||||
|
||||
class Person < ActiveResource::Base
|
||||
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 <person><name>Mary</name></person>
|
||||
|
||||
* Fix reload error when path prefix is used. #8727 [Ian Warshak]
|
||||
|
||||
* Remove ActiveResource::Struct because it hasn't proven very useful. Creating a new ActiveResource::Base subclass is often less code and always clearer. #8612 [Josh Peek]
|
||||
|
||||
@@ -34,6 +34,7 @@ unless defined?(ActiveSupport)
|
||||
end
|
||||
end
|
||||
|
||||
require 'active_resource/formats'
|
||||
require 'active_resource/base'
|
||||
require 'active_resource/validations'
|
||||
require 'active_resource/custom_methods'
|
||||
|
||||
@@ -155,7 +155,7 @@ module ActiveResource
|
||||
def site
|
||||
if defined?(@site)
|
||||
@site
|
||||
elsif superclass != Object and superclass.site
|
||||
elsif superclass != Object && superclass.site
|
||||
superclass.site.dup.freeze
|
||||
end
|
||||
end
|
||||
@@ -167,12 +167,34 @@ module ActiveResource
|
||||
@site = site.nil? ? nil : create_site_uri_from(site)
|
||||
end
|
||||
|
||||
# Sets the format that attributes are sent and received in from a mime type reference. Example:
|
||||
#
|
||||
# Person.format = :json
|
||||
# Person.find(1) # => GET /people/1.json
|
||||
#
|
||||
# Person.format = ActiveResource::Formats::XmlFormat
|
||||
# Person.find(1) # => GET /people/1.xml
|
||||
#
|
||||
# Default format is :xml.
|
||||
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)
|
||||
connection.format = format
|
||||
end
|
||||
|
||||
# Returns the current format, default is ActiveResource::Formats::XmlFormat
|
||||
def format # :nodoc:
|
||||
read_inheritable_attribute("format") || ActiveResource::Formats[:xml]
|
||||
end
|
||||
|
||||
# An instance of ActiveResource::Connection that is the base connection to the remote service.
|
||||
# The +refresh+ parameter toggles whether or not the connection is refreshed at every request
|
||||
# or not (defaults to +false+).
|
||||
def connection(refresh = false)
|
||||
if defined?(@connection) or superclass == Object
|
||||
@connection = Connection.new(site) if refresh || @connection.nil?
|
||||
if defined?(@connection) || superclass == Object
|
||||
@connection = Connection.new(site, format) if refresh || @connection.nil?
|
||||
@connection
|
||||
else
|
||||
superclass.connection
|
||||
@@ -252,7 +274,7 @@ module ActiveResource
|
||||
#
|
||||
def element_path(id, prefix_options = {}, query_options = nil)
|
||||
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
||||
"#{prefix(prefix_options)}#{collection_name}/#{id}.xml#{query_string(query_options)}"
|
||||
"#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
|
||||
end
|
||||
|
||||
# Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
|
||||
@@ -278,7 +300,7 @@ module ActiveResource
|
||||
#
|
||||
def collection_path(prefix_options = {}, query_options = nil)
|
||||
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
||||
"#{prefix(prefix_options)}#{collection_name}.xml#{query_string(query_options)}"
|
||||
"#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
|
||||
end
|
||||
|
||||
alias_method :set_primary_key, :primary_key= #:nodoc:
|
||||
@@ -781,7 +803,7 @@ module ActiveResource
|
||||
|
||||
def load_attributes_from_response(response)
|
||||
if response['Content-size'] != "0" && response.body.strip.size > 0
|
||||
load(connection.xml_from_response(response))
|
||||
load(self.class.format.decode(response.body))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -47,23 +47,20 @@ module ActiveResource
|
||||
# services.
|
||||
class Connection
|
||||
attr_reader :site
|
||||
attr_accessor :format
|
||||
|
||||
class << self
|
||||
def requests
|
||||
@@requests ||= []
|
||||
end
|
||||
|
||||
def default_header
|
||||
class << self ; attr_reader :default_header end
|
||||
@default_header = { 'Content-Type' => 'application/xml' }
|
||||
end
|
||||
end
|
||||
|
||||
# The +site+ parameter is required and will set the +site+
|
||||
# attribute to the URI for the remote resource service.
|
||||
def initialize(site)
|
||||
def initialize(site, format = ActiveResource::Formats[:xml])
|
||||
raise ArgumentError, 'Missing site URI' unless site
|
||||
self.site = site
|
||||
self.format = format
|
||||
end
|
||||
|
||||
# Set URI for remote service.
|
||||
@@ -74,7 +71,7 @@ module ActiveResource
|
||||
# Execute a GET request.
|
||||
# Used to get (find) resources.
|
||||
def get(path, headers = {})
|
||||
xml_from_response(request(:get, path, build_request_headers(headers)))
|
||||
format.decode(request(:get, path, build_request_headers(headers)).body)
|
||||
end
|
||||
|
||||
# Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
|
||||
@@ -95,9 +92,6 @@ module ActiveResource
|
||||
request(:post, path, body.to_s, build_request_headers(headers))
|
||||
end
|
||||
|
||||
def xml_from_response(response)
|
||||
from_xml_data(Hash.from_xml(response.body))
|
||||
end
|
||||
|
||||
private
|
||||
# Makes request to remote service.
|
||||
@@ -144,10 +138,14 @@ module ActiveResource
|
||||
|
||||
@http
|
||||
end
|
||||
|
||||
def default_header
|
||||
@default_header ||= { 'Content-Type' => format.mime_type }
|
||||
end
|
||||
|
||||
# Builds headers for request to remote service.
|
||||
def build_request_headers(headers)
|
||||
authorization_header.update(self.class.default_header).update(headers)
|
||||
authorization_header.update(default_header).update(headers)
|
||||
end
|
||||
|
||||
# Sets authorization header; authentication information is pulled from credentials provided with site URI.
|
||||
@@ -158,15 +156,5 @@ module ActiveResource
|
||||
def logger #:nodoc:
|
||||
ActiveResource::Base.logger
|
||||
end
|
||||
|
||||
# Manipulate from_xml Hash, because xml_simple is not exactly what we
|
||||
# want for ActiveResource.
|
||||
def from_xml_data(data)
|
||||
if data.is_a?(Hash) && data.keys.size == 1
|
||||
data.values.first
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
14
activeresource/lib/active_resource/formats.rb
Normal file
14
activeresource/lib/active_resource/formats.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module ActiveResource
|
||||
module Formats
|
||||
# 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")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'active_resource/formats/xml_format'
|
||||
require 'active_resource/formats/json_format'
|
||||
23
activeresource/lib/active_resource/formats/json_format.rb
Normal file
23
activeresource/lib/active_resource/formats/json_format.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
module ActiveResource
|
||||
module Formats
|
||||
module JsonFormat
|
||||
extend self
|
||||
|
||||
def extension
|
||||
"json"
|
||||
end
|
||||
|
||||
def mime_type
|
||||
"application/json"
|
||||
end
|
||||
|
||||
def encode(hash)
|
||||
hash.to_json
|
||||
end
|
||||
|
||||
def decode(json)
|
||||
ActiveSupport::JSON.decode(json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
34
activeresource/lib/active_resource/formats/xml_format.rb
Normal file
34
activeresource/lib/active_resource/formats/xml_format.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
module ActiveResource
|
||||
module Formats
|
||||
module XmlFormat
|
||||
extend self
|
||||
|
||||
def extension
|
||||
"xml"
|
||||
end
|
||||
|
||||
def mime_type
|
||||
"application/xml"
|
||||
end
|
||||
|
||||
def encode(hash)
|
||||
hash.to_xml
|
||||
end
|
||||
|
||||
def decode(xml)
|
||||
from_xml_data(Hash.from_xml(xml))
|
||||
end
|
||||
|
||||
private
|
||||
# Manipulate from_xml Hash, because xml_simple is not exactly what we
|
||||
# want for ActiveResource.
|
||||
def from_xml_data(data)
|
||||
if data.is_a?(Hash) && data.keys.size == 1
|
||||
data.values.first
|
||||
else
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -32,7 +32,12 @@ module ActiveResource
|
||||
pairs.each do |(path, response)|
|
||||
responses[path] = response
|
||||
end
|
||||
yield Responder.new(responses) if block_given?
|
||||
|
||||
if block_given?
|
||||
yield Responder.new(responses)
|
||||
else
|
||||
Responder.new(responses)
|
||||
end
|
||||
end
|
||||
|
||||
def reset!
|
||||
|
||||
42
activeresource/test/format_test.rb
Normal file
42
activeresource/test/format_test.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
require "#{File.dirname(__FILE__)}/abstract_unit"
|
||||
require "fixtures/person"
|
||||
|
||||
class FormatTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@matz = { :id => 1, :name => 'Matz' }
|
||||
@david = { :id => 2, :name => 'David' }
|
||||
|
||||
@programmers = [ @matz, @david ]
|
||||
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}", {}, 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}", {}, 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
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user