2006-06-25 10:44:22 -04:00
|
|
|
require 'active_resource/connection'
|
|
|
|
|
|
|
|
module ActiveResource
|
|
|
|
class Base
|
|
|
|
class << self
|
2006-08-31 21:15:10 -04:00
|
|
|
attr_reader :site
|
2006-08-31 03:55:31 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
def site=(site)
|
|
|
|
@site = site.is_a?(URI) ? site : URI.parse(site)
|
2006-09-04 06:04:23 -04:00
|
|
|
@connection = nil
|
|
|
|
@site
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def connection(refresh = false)
|
|
|
|
@connection = Connection.new(site) if refresh || @connection.nil?
|
|
|
|
@connection
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def element_name
|
|
|
|
self.to_s.underscore
|
|
|
|
end
|
|
|
|
|
|
|
|
def collection_name
|
|
|
|
element_name.pluralize
|
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
|
|
|
|
def prefix(options={})
|
|
|
|
default = site.path
|
|
|
|
default << '/' unless default[-1..-1] == '/'
|
2006-09-04 06:04:23 -04:00
|
|
|
self.prefix = default
|
2006-08-31 21:15:10 -04:00
|
|
|
prefix(options)
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-09-04 06:04:23 -04:00
|
|
|
def prefix=(value = '/')
|
2006-08-31 21:15:10 -04:00
|
|
|
prefix_call = value.gsub(/:\w+/) { |s| "\#{options[#{s}]}" }
|
|
|
|
method_decl = %(def self.prefix(options={}) "#{prefix_call}" end)
|
|
|
|
eval method_decl
|
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
alias_method :set_prefix, :prefix=
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-09-04 06:04:23 -04:00
|
|
|
def element_name=(value)
|
2006-08-31 21:15:10 -04:00
|
|
|
class << self ; attr_reader :element_name ; end
|
|
|
|
@element_name = value
|
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
alias_method :set_element_name, :element_name=
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-09-04 06:04:23 -04:00
|
|
|
def collection_name=(value)
|
2006-08-31 21:15:10 -04:00
|
|
|
class << self ; attr_reader :collection_name ; end
|
|
|
|
@collection_name = value
|
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
alias_method :set_collection_name, :collection_name=
|
2006-08-31 21:15:10 -04:00
|
|
|
|
|
|
|
def element_path(id, options = {})
|
|
|
|
"#{prefix(options)}#{collection_name}/#{id}.xml"
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
def collection_path(options = {})
|
|
|
|
"#{prefix(options)}#{collection_name}.xml"
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
def primary_key
|
2006-09-04 06:04:23 -04:00
|
|
|
self.primary_key = 'id'
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-09-04 06:04:23 -04:00
|
|
|
def primary_key=(value)
|
2006-08-31 21:15:10 -04:00
|
|
|
class << self ; attr_reader :primary_key ; end
|
|
|
|
@primary_key = value
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
alias_method :set_primary_key, :primary_key=
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
# Person.find(1) # => GET /people/1.xml
|
|
|
|
# StreetAddress.find(1, :person_id => 1) # => GET /people/1/street_addresses/1.xml
|
2006-06-25 10:44:22 -04:00
|
|
|
def find(*arguments)
|
2006-08-31 21:15:10 -04:00
|
|
|
scope = arguments.slice!(0)
|
|
|
|
options = arguments.slice!(0) || {}
|
2006-06-25 10:44:22 -04:00
|
|
|
|
|
|
|
case scope
|
2006-08-31 21:15:10 -04:00
|
|
|
when :all then find_every(options)
|
|
|
|
when :first then find_every(options).first
|
|
|
|
else find_single(scope, options)
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
|
|
|
|
private
|
|
|
|
# { :people => { :person => [ person1, person2 ] } }
|
|
|
|
def find_every(options)
|
|
|
|
connection.get(collection_path(options)).values.first.values.first.collect { |element| new(element, options) }
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
# { :person => person1 }
|
|
|
|
def find_single(scope, options)
|
|
|
|
new(connection.get(element_path(scope, options)).values.first, options)
|
|
|
|
end
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
attr_accessor :attributes
|
2006-08-31 21:15:10 -04:00
|
|
|
attr_accessor :prefix_options
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-08-31 21:15:10 -04:00
|
|
|
def initialize(attributes = {}, prefix_options = {})
|
2006-09-04 06:04:23 -04:00
|
|
|
@attributes = {}
|
|
|
|
self.load attributes
|
2006-08-31 21:15:10 -04:00
|
|
|
@prefix_options = prefix_options
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
|
2006-09-04 19:36:13 -04:00
|
|
|
def new?
|
2006-08-31 21:15:10 -04:00
|
|
|
id.nil?
|
|
|
|
end
|
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def id
|
2006-08-31 21:15:10 -04:00
|
|
|
attributes[self.class.primary_key]
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def id=(id)
|
2006-08-31 21:15:10 -04:00
|
|
|
attributes[self.class.primary_key] = id
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def save
|
2006-09-04 19:36:13 -04:00
|
|
|
new? ? create : update
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def destroy
|
2006-09-13 00:14:18 -04:00
|
|
|
connection.delete(self.class.element_path(id, prefix_options))
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def to_xml
|
|
|
|
attributes.to_xml(:root => self.class.element_name)
|
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
|
|
|
|
# Reloads the attributes of this object from the remote web service.
|
|
|
|
def reload
|
2006-09-04 06:04:23 -04:00
|
|
|
self.load self.class.find(id, @prefix_options).attributes
|
|
|
|
end
|
|
|
|
|
|
|
|
# Manually load attributes from a hash. Recursively loads collections of
|
|
|
|
# resources.
|
|
|
|
def load(attributes)
|
2006-09-04 20:02:17 -04:00
|
|
|
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
|
2006-09-04 06:04:23 -04:00
|
|
|
attributes.each do |key, value|
|
|
|
|
@attributes[key.to_s] =
|
|
|
|
case value
|
|
|
|
when Array
|
|
|
|
resource = find_or_create_resource_for_collection(key)
|
|
|
|
value.map { |attrs| resource.new(attrs) }
|
|
|
|
when Hash
|
2006-09-22 17:29:54 -04:00
|
|
|
# Workaround collections loaded as Hash
|
|
|
|
# :persons => { :person => [
|
|
|
|
# { :id => 1, :name => 'a' },
|
|
|
|
# { :id => 2, :name => 'b' } ]}
|
|
|
|
if value.keys.size == 1 and value.values.first.is_a?(Array)
|
|
|
|
resource = find_or_create_resource_for(value.keys.first)
|
|
|
|
value.values.first.map { |attrs| resource.new(attrs) }
|
|
|
|
else
|
|
|
|
resource = find_or_create_resource_for(key)
|
|
|
|
resource.new(value)
|
|
|
|
end
|
2006-09-04 06:04:23 -04:00
|
|
|
when ActiveResource::Base
|
|
|
|
value.class.new(value.attributes)
|
|
|
|
else
|
|
|
|
value.dup rescue value
|
|
|
|
end
|
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
self
|
|
|
|
end
|
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
protected
|
|
|
|
def connection(refresh = false)
|
|
|
|
self.class.connection(refresh)
|
|
|
|
end
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def update
|
2006-09-13 00:14:18 -04:00
|
|
|
connection.put(self.class.element_path(id, prefix_options), to_xml)
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
2006-08-31 21:15:10 -04:00
|
|
|
|
|
|
|
def create
|
2006-09-13 00:14:18 -04:00
|
|
|
returning connection.post(self.class.collection_path(prefix_options), to_xml) do |resp|
|
2006-09-20 15:31:17 -04:00
|
|
|
self.id = id_from_response(resp)
|
2006-08-31 21:15:10 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-09-20 15:31:17 -04:00
|
|
|
# takes a response from a typical create post and pulls the ID out
|
|
|
|
def id_from_response(response)
|
|
|
|
response['Location'][/\/([^\/]*?)(\.\w+)?$/, 1]
|
|
|
|
end
|
|
|
|
|
2006-09-04 06:04:23 -04:00
|
|
|
private
|
|
|
|
def find_or_create_resource_for_collection(name)
|
|
|
|
find_or_create_resource_for(name.to_s.singularize)
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_or_create_resource_for(name)
|
|
|
|
resource_name = name.to_s.camelize
|
|
|
|
resource_name.constantize
|
|
|
|
rescue NameError
|
|
|
|
resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
|
|
|
|
resource.prefix = self.class.prefix
|
|
|
|
resource.site = self.class.site
|
|
|
|
resource
|
|
|
|
end
|
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
def method_missing(method_symbol, *arguments)
|
|
|
|
method_name = method_symbol.to_s
|
2006-09-22 17:29:54 -04:00
|
|
|
|
2006-06-25 10:44:22 -04:00
|
|
|
case method_name.last
|
|
|
|
when "="
|
|
|
|
attributes[method_name.first(-1)] = arguments.first
|
|
|
|
when "?"
|
2006-08-31 21:15:10 -04:00
|
|
|
attributes[method_name.first(-1)] == true
|
2006-06-25 10:44:22 -04:00
|
|
|
else
|
2006-08-31 21:15:10 -04:00
|
|
|
attributes.has_key?(method_name) ? attributes[method_name] : super
|
2006-06-25 10:44:22 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-08-31 03:55:31 -04:00
|
|
|
end
|