aboutsummaryrefslogtreecommitdiffstats
path: root/activeresource/lib/active_resource/base.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2009-12-21 11:21:27 +0100
committerJosé Valim <jose.valim@gmail.com>2009-12-21 11:21:27 +0100
commit5f34421c77b4cd873baadbbca877a93de5a4d602 (patch)
tree8182bb1c53864ab06079e14116a61d66e9617f7d /activeresource/lib/active_resource/base.rb
parentcf7b94c013d4e824433a018001474e71ddd81a99 (diff)
parentf09ad263cabe2e781c1994b85375fee8deba4317 (diff)
downloadrails-5f34421c77b4cd873baadbbca877a93de5a4d602.tar.gz
rails-5f34421c77b4cd873baadbbca877a93de5a4d602.tar.bz2
rails-5f34421c77b4cd873baadbbca877a93de5a4d602.zip
Merge branch 'master' of git://github.com/rails/rails
Diffstat (limited to 'activeresource/lib/active_resource/base.rb')
-rw-r--r--activeresource/lib/active_resource/base.rb140
1 files changed, 138 insertions, 2 deletions
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 18105e8887..b833e9c8ce 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -241,6 +241,124 @@ module ActiveResource
cattr_accessor :logger
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 <tt>known_attributes</tt> of the
+ # current resource.
+ #
+ # There is no need to specify a schema for your Active Resource. If
+ # you do not, the <tt>known_attributes</tt> 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') # <person><name>John</name><age>34</age><num_children>3</num_children></person>
+ # 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 <tt>schema</tt> for this
+ # Resource. <tt>schema</tt> 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 <tt>schema</tt>)
+ #
+ # 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 <tt>schema</tt>
+ # Attributes that are known will cause your resource to return 'true'
+ # when <tt>respond_to?</tt> is called on them. A known attribute will
+ # return nil if not set (rather than <t>MethodNotFound</tt>); thus
+ # known attributes can be used with <tt>validates_presence_of</tt>
+ # 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
@@ -776,6 +894,21 @@ module ActiveResource
attr_accessor :attributes #:nodoc:
attr_accessor :prefix_options #:nodoc:
+ # If no schema has been defined for the class (see
+ # <tt>ActiveResource::schema=</tt>), 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 fromthe provided <tt>schema</tt>, 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.
#
@@ -1157,7 +1290,7 @@ module ActiveResource
method_name = method.to_s
if attributes.nil?
super
- elsif attributes.has_key?(method_name)
+ elsif known_attributes.include?(method_name)
true
elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
true
@@ -1262,7 +1395,10 @@ module ActiveResource
attributes[$`]
end
else
- attributes.include?(method_name) ? attributes[method_name] : super
+ 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