module CouchPillow class Document class ValidationError < StandardError; end attr_reader :id @type = "default" PRESENCE_LAMBDA = lambda do |value| !value.nil? end def initialize hash = {}, id = SecureRandom.hex @data = self.class.symbolize(hash) @id = id @data[:created_at] and @data[:created_at] = Time.parse(@data[:created_at]) or @data[:created_at] = Time.now.utc @data[:updated_at] = Time.parse(@data[:updated_at]) if @data[:updated_at] raise TypeError if @data[:_type] && @data[:_type] != self.class._type @data[:_type] = self.class._type end def [] key @data[key.to_s.to_sym] end def []= key, value @data[key.to_s.to_sym] = value end # Map hash keys to methods # def method_missing m, *args, &block ms = m.to_s if ms.end_with?("=") ms.gsub!('=', '') @data[ms.to_sym] = args[0] else @data.has_key?(m) and @data[m] or super end end def respond_to? m ms = m.to_s return true if ms.end_with?("=") @data.has_key?(m) or super end def timestamp! @data[:updated_at] = Time.now.utc end # Save this document to the server def save! validate sort! timestamp! CouchPillow.db.set @id, @data end # Delete this document from the server. # def delete! CouchPillow.db.delete @id end # Sort keys on this document. # def sort! @data = @data.sort.to_h end # Attempt to update this Document. Fails if this Document does not yet # exist in the database. # def update! validate sort! timestamp! CouchPillow.db.replace @id, @data end def to_json *a h = { :_id => @id }.merge!(@data) h.to_json(*a) end def validate self.class.validate_keys.each do |k, msg, method| raise ValidationError, "#{k} #{msg}" unless @data.has_key?(k) && method.call(@data[k]) end end def self.get id new(CouchPillow.db.get(id), id) end def self.type value @type = value.to_s end def self._type @type end def self.design_doc value @ddoc = value end # Validate the presence of a particular key, and the value of that key # cannot be nil. # def self.validate_presence key validate key, "is missing", PRESENCE_LAMBDA end # Validate the presence of a particular key using a custom validation method. # Implies the Document must contain the key. # def self.validate key, message, block raise ValidationError, "Provide validation method for key #{key}" unless block validate_keys << [key, message, block] end private def self.validate_keys @validate_key ||= [] end def self.symbolize hash hash.inject({}) do |memo,(k,v)| memo[k.to_sym] = v memo end end end end