0
- SPECIAL_MEMBERS = %w(attributes associations connection)
0
+ SPECIAL_MEMBERS = %w(attributes associations connection)
0
+ DEFAULT_ATTRIBUTES = %w(id rev)
0
def initialize(params = {})
0
# Object instance variable
0
@attributes, @associations, @connection, klass_atts, klass_assocs = {}, {}, self.class.connection, self.class.attributes, self.class.associations
0
# ActiveCouch::Connection object will be readable in every
0
# object instantiated from a subclass of ActiveCouch::Base
0
- SPECIAL_MEMBERS.each do |m|
0
- self.instance_eval "def #{m}; @#{m}; end"
0
+ SPECIAL_MEMBERS.each do |k|
0
+ self.instance_eval "def #{k}; @#{k}; end"
0
klass_atts.each_key do |k|
0
@@ -17,6 +18,11 @@ module ActiveCouch
0
self.instance_eval "def #{k}=(val); attributes[:#{k}].value = val; end"
0
+ DEFAULT_ATTRIBUTES.each do |x|
0
+ self.instance_eval "def #{x}; _#{x}; end"
0
+ self.instance_eval "def #{x}=(val); self._#{x}=(val); end"
0
klass_assocs.each_key do |k|
0
@associations[k] = HasManyAssociation.new(klass_assocs[k].name, :class => klass_assocs[k].klass)
0
self.instance_eval "def #{k}; associations[:#{k}].container; end"
0
@@ -28,78 +34,90 @@ module ActiveCouch
0
- # Returns the "_id" of the CouchDB document represented by this instance.
0
- @id ||= attributes[:_id]
0
- # Sets the "_id" of the CouchDB document represented by this instance.
0
- # This doesn't do anything unless this is a new document.
0
- attributes[:_id] = @id = new_id
0
- # Returns the "_rev" of the CouchDB document represented by this instance.
0
- @rev ||= attributes[:_rev]
0
- # Returns true if this is a new CouchDB document.
0
+ # Generates a JSON representation of an instance of a subclass of ActiveCouch::Base.
0
+ # Ignores attributes which have a nil value.
0
+ # class Person < ActiveCouch::Base
0
+ # has :name, :which_is => :text, :with_default_value => "McLovin"
0
+ # person.to_json # {"name":"McLovin"}
0
+ # class AgedPerson < ActiveCouch::Base
0
+ # has :age, :which_is => :decimal, :with_default_value => 3.5
0
+ # aged_person = AgedPerson.new
0
+ # aged_person.id = 'abc-def'
0
+ # aged_person.to_json # {"age":3.5, "_id":"abc-def"}
0
- # @attributes and @associations are hashes. Get all
0
- # attributes/associations and merge them into a single hash
0
- attributes.each_value { |v| hash.merge!(v.to_hash) }
0
+ attributes.each_value { |v| hash.merge!(v.to_hash) unless v.nil? }
0
associations.each_value { |v| hash.merge!(v.to_hash) }
0
# and by the Power of Grayskull, convert the hash to json
0
- # - Clean this up. Doesn't look very nice
0
- # - Raise errors if attribute/association is not present
0
- if v.is_a?(Array) # This means this is a has_many association
0
- unless (assoc = @associations[k]).nil?
0
- name, child_klass = assoc.name, assoc.klass
0
- child.is_a?(Hash) ? child_obj = child_klass.new(child) : child_obj = child
0
- self.send "add_#{Inflector.singularize(name)}", child_obj
0
- elsif v.is_a?(Hash) # This means this is a has_one association (which we might add later)
0
- # Do nothing for now. More later
0
- else # This means this is a normal attribute
0
- self.send("#{k}=", v) if @attributes.has_key?(k)
0
+ # Saves a document into a CouchDB database. A document can be saved in two ways.
0
+ # One if it has been set an ID by the user, in which case the connection object
0
+ # needs to use an HTTP PUT request to the URL /database/user_generated_id.
0
+ # For the document needs a CouchDB-generated ID, the connection object needs
0
+ # to use an HTTP POST request to the URL /database.
0
+ # class Person < ActiveCouch::Base
0
+ # has :name, :which_is => :text
0
+ # person = Person.new(:name => 'McLovin')
0
- # POST to database with a JSON representation of the object
0
- response = connection.post("/#{self.class.database_name}", self.to_json)
0
+ response = connection.put("/#{self.class.database_name}/#{id}", to_json)
0
+ response = connection.post("/#{self.class.database_name}", to_json)
0
+ # Parse the JSON obtained from the body...
0
+ results = JSON.parse(response.body)
0
+ # ...and set the default id and rev attributes
0
+ DEFAULT_ATTRIBUTES.each { |a| self.__send__("#{a}=", results[a]) }
0
# Response sent will be 201, if the save was successful [201 corresponds to 'created']
0
return response.code == '201'
0
+ # Checks to see if a document has been persisted in a CouchDB database.
0
+ # If a document has been retrieved from CouchDB, or has been persisted in
0
+ # a CouchDB database, the attribute _rev would not be nil.
0
+ # class Person < ActiveCouch::Base
0
+ # has :name, :which_is => :text
0
+ # person = Person.new(:name => 'McLovin')
0
class << self # Class methods
0
- # All classes inheriting from ActiveCouch::Base will have
0
- # class instance variables in SPECIAL_MEMBERS.
0
def inherited(subklass)
0
- SPECIAL_MEMBERS.each do |x|
0
- subklass.instance_variable_set "@#{x}", {}
0
- subklass.instance_eval "def #{x}; @#{x}; end"
0
+ # TODO: Need a cleaner way to do this
0
+ subklass.instance_variable_set "@attributes", { :_id => Attribute.new(:_id, :with_default_value => nil),
0
+ :_rev => Attribute.new(:_rev, :with_default_value => nil) }
0
+ subklass.instance_variable_set "@associations", {}
0
+ subklass.instance_variable_set "@connections", nil
0
+ SPECIAL_MEMBERS.each do |k|
0
+ subklass.instance_eval "def #{k}; @#{k}; end"
0
@@ -156,10 +174,43 @@ module ActiveCouch
0
alias :database_name= :set_database_name
0
+ # Sets the site which the ActiveCouch object has to connect to, which
0
+ # initializes an ActiveCouch::Connection object.
0
+ # class Person < ActiveCouch::Base
0
+ # site 'localhost:5984'
0
+ # Person.connection.nil? # false
0
@connection = Connection.new(site)
0
+ # Defines an attribute for a subclass of ActiveCouch::Base. The parameters
0
+ # for this method include name, which is the name of the attribute as well as
0
+ # The options hash can contain the key 'which_is' which can
0
+ # have possible values :text, :decimal, :number. It can also contain the key
0
+ # 'with_default_value' which can set a default value for each attribute defined
0
+ # in the subclass of ActiveCouch::Base
0
+ # class Person < ActiveCouch::Base
0
+ # p.name.methods.include?(:name) # true
0
+ # p.name.methods.include?(:name=) # false
0
+ # class AgedPerson < ActiveCouch::Base
0
+ # has :age, :which_is => :number, :with_default_value = 18
0
+ # person = AgedPerson.new
0
def has(name, options = {})
0
unless name.is_a?(String) || name.is_a?(Symbol)
0
raise ArgumentError, "#{name} is neither a String nor a Symbol"
0
@@ -167,6 +218,20 @@ module ActiveCouch
0
@attributes[name] = Attribute.new(name, options)
0
+ # Defines an array of objects which are 'children' of this class. The has_many
0
+ # function guesses the class of the child, based on the name of the association,
0
+ # but can be over-ridden by the :class key in the options hash.
0
+ # class Person < ActiveCouch::Base
0
+ # class GrandPerson < ActiveCouch::Base
0
+ # has_many :people # which will create an empty array which can contain
0
def has_many(name, options = {})
0
unless name.is_a?(String) || name.is_a?(Symbol)
0
raise ArgumentError, "#{name} is neither a String nor a Symbol"
0
@@ -174,17 +239,32 @@ module ActiveCouch
0
@associations[name] = HasManyAssociation.new(name, options)
0
+ # Initializes an object of a subclass of ActiveCouch::Base based on a JSON
0
+ # representation of the object.
0
+ # class Person < ActiveCouch::Base
0
+ # person = Person.from_json('{"name":"McLovin"}')
0
+ # person.name # "McLovin"
0
hash = JSON.parse(json)
0
# Create new based on parsed
0
- # Similar to ActiveResource convention, find operates with two different
0
- # retrieval approaches:
0
- # This method is stolen from ActiveResource::Base
0
+ # Retrieves one or more object(s) from a CouchDB database, based on the search
0
+ # class Person < ActiveCouch::Base
0
+ # people = Person.find(:first, :params => {:name => "McLovin"})
0
+ # person = Person.find(:all, :params => {:name => "McLovin"})
0
scope = arguments.slice!(0)
0
options = arguments.slice!(0) || {}
0
@@ -198,6 +278,15 @@ module ActiveCouch
0
# Initializes a new subclass of ActiveCouch::Base and saves in the CouchDB database
0
+ # class Person < ActiveCouch::Base
0
+ # person = Person.create(:name => "McLovin")
0
+ # person.id.nil? # false
0
unless arguments.is_a?(Hash)
0
raise ArgumentError, "The arguments must be a Hash"
0
@@ -273,15 +362,38 @@ module ActiveCouch
0
+ # First parse the JSON.
0
+ # As per the CouchDB Permanent View API, the result set will be contained
0
+ # within a JSON hash as an array, with the key 'rows'
0
+ # The actual CouchDB object which needs to be initialized is obtained with
0
def instantiate_collection(result)
0
- # First parse the JSON
0
hash = JSON.parse(result)
0
- # As per the CouchDB Permanent View API, the result set will be contained
0
- # within a JSON hash as an array, with the key 'rows'
0
- # The actual CouchDB object which needs to be initialized is obtained with
0
hash['rows'].collect { |row| self.new(row['value']) }
0
end # End class methods
0
+ # - Clean this up. Doesn't look very nice
0
+ # - Raise errors if attribute/association is not present
0
+ if v.is_a?(Array) # This means this is a has_many association
0
+ unless (assoc = @associations[k]).nil?
0
+ name, child_klass = assoc.name, assoc.klass
0
+ child.is_a?(Hash) ? child_obj = child_klass.new(child) : child_obj = child
0
+ self.send "add_#{Inflector.singularize(name)}", child_obj
0
+ elsif v.is_a?(Hash) # This means this is a has_one association (which we might add later)
0
+ # Do nothing for now. More later
0
+ else # This means this is a normal attribute
0
+ self.send("#{k}=", v) if @attributes.has_key?(k)
0
end # End module ActiveCouch
0
\ No newline at end of file
Comments
No one has commented yet.