From fc9b3e4a45a81b7526f8154049c825e3755903ad Mon Sep 17 00:00:00 2001 From: Taryn East Date: Sun, 20 Dec 2009 18:42:16 -0600 Subject: define_schema for Active Resource Signed-off-by: Joshua Peek --- activeresource/lib/active_resource/base.rb | 144 ++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 2 deletions(-) (limited to 'activeresource/lib/active_resource/base.rb') diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 18105e8887..60bd573911 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -13,6 +13,7 @@ require 'set' require 'uri' require 'active_resource/exceptions' +require 'active_resource/schema_definition' module ActiveResource # ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application. @@ -241,6 +242,127 @@ module ActiveResource cattr_accessor :logger class << self + # This will shortly disappear to be replaced by the migration-style + # usage of this for defining a schema. At that point, all the doc + # currenlty on schema= will move back here... + def schema # :nodoc: + @schema ||= nil + end + # 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 + # define_schema do |s| + # # define each attribute separately + # s.attribute 'name', :string + # + # # or use the convenience methods and pass >=1 attribute names + # s.string 'eye_colour', 'hair_colour' + # s.integer 'age' + # s.float 'height', 'weight' + # + # # unsupported types should be left as strings + # # overload the accessor methods if you need to convert them + # s.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 define_schema + schema_definition = SchemaDefinition.new + yield schema_definition if block_given? + + # 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 + end + + + # Alternative, direct way to specify a schema for this + # Resource. define_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 define_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 + + define_schema do |s| + the_schema.each {|k,v| s.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 @@ -776,6 +898,21 @@ module ActiveResource 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 fromthe 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. # @@ -1157,7 +1294,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 +1399,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 -- cgit v1.2.3 From 669c5eec445ff097b765c387b92ae1f174134f75 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 20 Dec 2009 18:44:13 -0600 Subject: Rename SchemaDefinition => Schema --- activeresource/lib/active_resource/base.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'activeresource/lib/active_resource/base.rb') diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 60bd573911..b39f8fbd48 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -13,7 +13,6 @@ require 'set' require 'uri' require 'active_resource/exceptions' -require 'active_resource/schema_definition' module ActiveResource # ActiveResource::Base is the main class for mapping RESTful resources as models in a Rails application. @@ -270,9 +269,9 @@ module ActiveResource # s.integer 'age' # s.float 'height', 'weight' # - # # unsupported types should be left as strings + # # unsupported types should be left as strings # # overload the accessor methods if you need to convert them - # s.attribute 'created_at', 'string' + # s.attribute 'created_at', 'string' # end # end # @@ -295,14 +294,14 @@ module ActiveResource # string, integer, float # # Note: at present the attribute-type doesn't do anything, but stay - # tuned... + # 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 define_schema - schema_definition = SchemaDefinition.new + schema_definition = Schema.new yield schema_definition if block_given? # skip out if we didn't define anything @@ -317,7 +316,7 @@ module ActiveResource end schema - end + end # Alternative, direct way to specify a schema for this @@ -326,7 +325,7 @@ module ActiveResource # # 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 define_schema) + # in define_schema) # # example: # @@ -342,7 +341,7 @@ module ActiveResource # purposefully nulling out the schema @schema = nil @known_attributes = [] - return + return end raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash -- cgit v1.2.3 From c0ad3f6cc618f42eae0c5d5ceefde32ff3342c20 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 20 Dec 2009 18:48:01 -0600 Subject: Rename define_schema => schema --- activeresource/lib/active_resource/base.rb | 43 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'activeresource/lib/active_resource/base.rb') diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index b39f8fbd48..d07571e1d7 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -241,12 +241,6 @@ module ActiveResource cattr_accessor :logger class << self - # This will shortly disappear to be replaced by the migration-style - # usage of this for defining a schema. At that point, all the doc - # currenlty on schema= will move back here... - def schema # :nodoc: - @schema ||= nil - end # Creates a schema for this resource - setting the attributes that are # known prior to fetching an instance from the remote system. # @@ -260,7 +254,7 @@ module ActiveResource # # example: # class Person < ActiveResource::Base - # define_schema do |s| + # schema do |s| # # define each attribute separately # s.attribute 'name', :string # @@ -300,32 +294,35 @@ module ActiveResource # j.age # => 34 # cast to an integer # j.weight # => '65' # still a string! # - def define_schema - schema_definition = Schema.new - yield schema_definition if block_given? + def schema(&block) + if block_given? + schema_definition = Schema.new + yield schema_definition - # skip out if we didn't define anything - return unless schema_definition.attrs.present? + # skip out if we didn't define anything + return unless schema_definition.attrs.present? - @schema ||= {}.with_indifferent_access - @known_attributes ||= [] + @schema ||= {}.with_indifferent_access + @known_attributes ||= [] - schema_definition.attrs.each do |k,v| - @schema[k] = v - @known_attributes << k - end + schema_definition.attrs.each do |k,v| + @schema[k] = v + @known_attributes << k + end - schema + schema + else + @schema ||= nil + end end - # Alternative, direct way to specify a schema for this - # Resource. define_schema is more flexible, but this is quick + # 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 define_schema) + # in schema) # # example: # @@ -346,7 +343,7 @@ module ActiveResource raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash - define_schema do |s| + schema do |s| the_schema.each {|k,v| s.attribute(k,v) } end end -- cgit v1.2.3 From 2e9c7759984573944592fb1bda5aeb7c58edba55 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 20 Dec 2009 19:03:22 -0600 Subject: Use instance_eval for schema block --- activeresource/lib/active_resource/base.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'activeresource/lib/active_resource/base.rb') diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index d07571e1d7..b833e9c8ce 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -254,18 +254,18 @@ module ActiveResource # # example: # class Person < ActiveResource::Base - # schema do |s| + # schema do # # define each attribute separately - # s.attribute 'name', :string + # attribute 'name', :string # # # or use the convenience methods and pass >=1 attribute names - # s.string 'eye_colour', 'hair_colour' - # s.integer 'age' - # s.float 'height', 'weight' + # 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 - # s.attribute 'created_at', 'string' + # attribute 'created_at', 'string' # end # end # @@ -297,7 +297,7 @@ module ActiveResource def schema(&block) if block_given? schema_definition = Schema.new - yield schema_definition + schema_definition.instance_eval(&block) # skip out if we didn't define anything return unless schema_definition.attrs.present? @@ -343,8 +343,8 @@ module ActiveResource raise ArgumentError, "Expected a hash" unless the_schema.kind_of? Hash - schema do |s| - the_schema.each {|k,v| s.attribute(k,v) } + schema do + the_schema.each {|k,v| attribute(k,v) } end end -- cgit v1.2.3