aboutsummaryrefslogtreecommitdiffstats
path: root/activeresource/lib/active_resource
diff options
context:
space:
mode:
authorRick Olson <technoweenie@gmail.com>2007-01-16 06:34:10 +0000
committerRick Olson <technoweenie@gmail.com>2007-01-16 06:34:10 +0000
commit932e7b003ce77d9265e910cff63a17589b8c02a2 (patch)
treeabded6f5df11f28310449591d4aca83c81c04c6f /activeresource/lib/active_resource
parent56c55354661fcadecb1927fb62fb9038d16e9be1 (diff)
downloadrails-932e7b003ce77d9265e910cff63a17589b8c02a2.tar.gz
rails-932e7b003ce77d9265e910cff63a17589b8c02a2.tar.bz2
rails-932e7b003ce77d9265e910cff63a17589b8c02a2.zip
Mega documentation patches. #7025, #7069 [rwdaigle]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5962 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activeresource/lib/active_resource')
-rw-r--r--activeresource/lib/active_resource/base.rb62
-rw-r--r--activeresource/lib/active_resource/connection.rb19
-rw-r--r--activeresource/lib/active_resource/http_mock.rb2
-rw-r--r--activeresource/lib/active_resource/struct.rb9
-rw-r--r--activeresource/lib/active_resource/validations.rb36
5 files changed, 104 insertions, 24 deletions
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 8babc18507..f530923224 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -8,6 +8,7 @@ module ActiveResource
cattr_accessor :logger
class << self
+ # Gets the URI of the resource's site
def site
if defined?(@site)
@site
@@ -16,20 +17,24 @@ module ActiveResource
end
end
+ # Set the URI for the REST resources
def site=(site)
@connection = nil
@site = create_site_uri_from(site)
end
+ # Base connection to remote service
def connection(refresh = false)
@connection = Connection.new(site) if refresh || @connection.nil?
@connection
end
- attr_accessor_with_default(:element_name) { to_s.underscore }
- attr_accessor_with_default(:collection_name) { element_name.pluralize }
- attr_accessor_with_default(:primary_key, 'id')
-
+ attr_accessor_with_default(:element_name) { to_s.underscore } #:nodoc:
+ attr_accessor_with_default(:collection_name) { element_name.pluralize } #:nodoc:
+ attr_accessor_with_default(:primary_key, 'id') #:nodoc:
+
+ # Gets the resource prefix
+ # prefix/collectionname/1.xml
def prefix(options={})
default = site.path
default << '/' unless default[-1..-1] == '/'
@@ -37,6 +42,8 @@ module ActiveResource
prefix(options)
end
+ # Sets the resource prefix
+ # prefix/collectionname/1.xml
def prefix=(value = '/')
prefix_call = value.gsub(/:\w+/) { |key| "\#{options[#{key}]}" }
instance_eval <<-end_eval, __FILE__, __LINE__
@@ -48,23 +55,24 @@ module ActiveResource
raise
end
- alias_method :set_prefix, :prefix=
+ alias_method :set_prefix, :prefix= #:nodoc:
- alias_method :set_element_name, :element_name=
- alias_method :set_collection_name, :collection_name=
+ alias_method :set_element_name, :element_name= #:nodoc:
+ alias_method :set_collection_name, :collection_name= #:nodoc:
def element_path(id, options = {})
"#{prefix(options)}#{collection_name}/#{id}.xml#{query_string(options)}"
end
- def collection_path(options = {})
+ def collection_path(options = {})
"#{prefix(options)}#{collection_name}.xml#{query_string(options)}"
end
- alias_method :set_primary_key, :primary_key=
+ alias_method :set_primary_key, :primary_key= #:nodoc:
- # Person.find(1) # => GET /people/1.xml
- # StreetAddress.find(1, :person_id => 1) # => GET /people/1/street_addresses/1.xml
+ # Core method for finding resources. Used similarly to ActiveRecord's find method.
+ # Person.find(1) # => GET /people/1.xml
+ # StreetAddress.find(1, :person_id => 1) # => GET /people/1/street_addresses/1.xml
def find(*arguments)
scope = arguments.slice!(0)
options = arguments.slice!(0) || {}
@@ -80,7 +88,7 @@ module ActiveResource
connection.delete(element_path(id))
end
- # True if the resource is found.
+ # Evalutes to <tt>true</tt> if the resource is found.
def exists?(id, options = {})
id && !find_single(id, options).nil?
rescue ActiveResource::ResourceNotFound
@@ -88,16 +96,19 @@ module ActiveResource
end
private
+ # Find every resource.
def find_every(options)
collection = connection.get(collection_path(options)) || []
collection.collect! { |element| new(element, options) }
end
- # { :person => person1 }
+ # Find a single resource.
+ # { :person => person1 }
def find_single(scope, options)
new(connection.get(element_path(scope, options)), options)
end
+ # 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)
end
@@ -106,6 +117,7 @@ module ActiveResource
@prefix_parameters ||= prefix_source.scan(/:\w+/).map { |key| key[1..-1].to_sym }.to_set
end
+ # Builds the query string for the request.
def query_string(options)
# Omit parameters which appear in the URI path.
query_params = options.reject { |key, value| prefix_parameters.include?(key) }
@@ -129,8 +141,8 @@ module ActiveResource
end
end
- attr_accessor :attributes
- attr_accessor :prefix_options
+ attr_accessor :attributes #:nodoc:
+ attr_accessor :prefix_options #:nodoc:
def initialize(attributes = {}, prefix_options = {})
@attributes = {}
@@ -138,19 +150,22 @@ module ActiveResource
@prefix_options = prefix_options
end
+ # Is the resource a new object?
def new?
id.nil?
end
+ # Get the id of the object.
def id
attributes[self.class.primary_key]
end
+ # Set the id of the object.
def id=(id)
attributes[self.class.primary_key] = id
end
- # True 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.
+ # True 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+.
def ==(other)
other.equal?(self) || (other.instance_of?(self.class) && !other.new? && other.id == id)
end
@@ -166,19 +181,22 @@ module ActiveResource
id.hash
end
+ # Delegates to +create+ if a new object, +update+ if its old.
def save
new? ? create : update
end
+ # Delete the resource.
def destroy
connection.delete(element_path)
end
- # True if this resource is found.
+ # Evaluates to <tt>true</tt> if this resource is found.
def exists?
!new? && self.class.exists?(id, prefix_options)
end
+ # Convert the resource to an XML string
def to_xml(options={})
attributes.to_xml({:root => self.class.element_name}.merge(options))
end
@@ -215,17 +233,19 @@ module ActiveResource
self.class.connection(refresh)
end
+ # Update the resource on the remote service.
def update
connection.put(element_path, to_xml)
end
+ # Create (i.e., save to the remote service) the new resource.
def create
returning connection.post(collection_path, to_xml) do |response|
self.id = id_from_response(response)
end
end
- # takes a response from a typical create post and pulls the ID out
+ # Takes a response from a typical create post and pulls the ID out
def id_from_response(response)
response['Location'][/\/([^\/]*?)(\.\w+)?$/, 1]
end
@@ -239,10 +259,12 @@ module ActiveResource
end
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)
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
resource_name.constantize
@@ -253,7 +275,7 @@ module ActiveResource
resource
end
- def method_missing(method_symbol, *arguments)
+ def method_missing(method_symbol, *arguments) #:nodoc:
method_name = method_symbol.to_s
case method_name.last
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index c52d4d4839..528a7cc678 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -24,7 +24,7 @@ module ActiveResource
class ServerError < ConnectionError; end # 5xx Server Error
-
+ # Class to handle connections to remote services.
class Connection
attr_reader :site
@@ -44,27 +44,37 @@ module ActiveResource
self.site = site
end
+ # Set URI for remote service.
def site=(site)
@site = site.is_a?(URI) ? site : URI.parse(site)
end
+ # Execute a GET request.
+ # Used to get (find) resources.
def get(path)
from_xml_data(Hash.from_xml(request(:get, path, build_request_headers).body).values.first)
end
+ # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
+ # Used to delete resources.
def delete(path)
request(:delete, path, build_request_headers)
end
+ # Execute a PUT request (see HTTP protocol documentation if unfamiliar).
+ # Used to update resources.
def put(path, body = '')
request(:put, path, body, build_request_headers)
end
+ # Execute a POST request.
+ # Used to create new resources.
def post(path, body = '')
request(:post, path, body, build_request_headers)
end
private
+ # Makes request to remote service.
def request(method, path, *arguments)
logger.info "#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
result = nil
@@ -73,6 +83,7 @@ module ActiveResource
handle_response(result)
end
+ # Handles response and error codes from remote service.
def handle_response(response)
case response.code.to_i
when 200...400
@@ -92,6 +103,8 @@ module ActiveResource
end
end
+ # Creates new (or uses currently instantiated) Net::HTTP instance for communication with
+ # remote service and resources.
def http
unless @http
@http = Net::HTTP.new(@site.host, @site.port)
@@ -102,15 +115,17 @@ module ActiveResource
@http
end
+ # Builds headers for request to remote service.
def build_request_headers
authorization_header.update(self.class.default_header)
end
+ # Sets authorization header; authentication information is pulled from credentials provided with site URI.
def authorization_header
(@site.user || @site.password ? { 'Authorization' => 'Basic ' + ["#{@site.user}:#{ @site.password}"].pack('m').delete("\r\n") } : {})
end
- def logger
+ def logger #:nodoc:
ActiveResource::Base.logger
end
diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb
index f37bc7d2ad..3ce31a50ea 100644
--- a/activeresource/lib/active_resource/http_mock.rb
+++ b/activeresource/lib/active_resource/http_mock.rb
@@ -1,7 +1,7 @@
require 'active_resource/connection'
module ActiveResource
- class InvalidRequestError < StandardError; end
+ class InvalidRequestError < StandardError; end #:nodoc:
class HttpMock
class Responder
diff --git a/activeresource/lib/active_resource/struct.rb b/activeresource/lib/active_resource/struct.rb
index 6f4ffecc20..ee1f15d781 100644
--- a/activeresource/lib/active_resource/struct.rb
+++ b/activeresource/lib/active_resource/struct.rb
@@ -1,4 +1,13 @@
module ActiveResource
+ # Class that allows a connection to a remote resource.
+ # Person = ActiveResource::Struct.new do |p|
+ # p.uri "http://www.mypeople.com/people"
+ # p.credentials :username => "mycreds", :password => "wordofpassage"
+ # end
+ #
+ # person = Person.find(1)
+ # person.name = "David"
+ # person.save!
class Struct
def self.create
Class.new(Base)
diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb
index c45655d1ea..76aa7d2f00 100644
--- a/activeresource/lib/active_resource/validations.rb
+++ b/activeresource/lib/active_resource/validations.rb
@@ -1,7 +1,9 @@
module ActiveResource
- class ResourceInvalid < ClientError
+ 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
@@ -100,6 +102,38 @@ module ActiveResource
end
end
+ # Module to allow validation of ActiveResource objects, which are implemented by overriding +Base#validate+ or its variants.
+ # Each of these methods can inspect the state of the object, which usually means ensuring that a number of
+ # attributes have a certain value (such as not empty, within a given range, matching a certain regular expression). For example:
+ #
+ # class Person < ActiveResource::Base
+ # self.site = "http://www.localhost.com:3000/"
+ # protected
+ # def validate
+ # errors.add_on_empty %w( first_name last_name )
+ # errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
+ # end
+ #
+ # def validate_on_create # is only run the first time a new object is saved
+ # unless valid_member?(self)
+ # errors.add("membership_discount", "has expired")
+ # end
+ # end
+ #
+ # def validate_on_update
+ # errors.add_to_base("No changes have occurred") if unchanged_attributes?
+ # end
+ # end
+ #
+ # person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.")
+ # person.save # => false (and doesn't do the save)
+ # person.errors.empty? # => false
+ # person.errors.count # => 2
+ # person.errors.on "last_name" # => "can't be empty"
+ # person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" }
+ # person.save # => true (and person is now saved to the remote service)
+ #
+ # An Errors object is automatically created for every resource.
module Validations
def self.included(base) # :nodoc:
base.class_eval do