lib/ampere/model.rb in ampere-0.1.0 vs lib/ampere/model.rb in ampere-0.1.2

- old
+ new

@@ -3,10 +3,11 @@ attr_reader :id @fields = [] @field_defaults = {} @indices = [] + @field_types = {} ### Instance methods # Compares this model with another one. If they are literally the same object # or have been stored and have the same ID, then they are equal. @@ -43,16 +44,16 @@ end # Initialize an instance like this: # # Post.new :title => "Kitties: Are They Awesome?" - def initialize(hash = {}) + def initialize(hash = {}, unmarshal = false) hash.each do |k, v| if k == 'id' then - @id = v + @id = unmarshal ? Marshal.load(v) : v else - self.send("#{k}=", v) + self.send("#{k}=", (unmarshal and not k =~ /_id$/) ? Marshal.load(v) : v) end end end # Returns true if this record has not yet been saved. @@ -65,11 +66,16 @@ if self.new? then raise "Can't reload a new record" end self.class.fields.each do |k| - self.send("#{k}=", Ampere.connection.hget(@id, k)) + v = Ampere.connection.hget(@id, k) + if k =~ /_id$/ then + self.send("#{k}=", v) + else + self.send("#{k}=", Marshal.load(v)) + end end self end # Saves this record to the database. @@ -78,11 +84,11 @@ if @id.nil? then @id = "#{self.class.to_s.downcase}.#{Ampere.connection.incr('__guid')}" end self.attributes.each do |k, v| - Ampere.connection.hset(@id, k, v) + Ampere.connection.hset(@id, k, k =~ /_id$/ ? v : Marshal.dump(v)) end self.class.indices.each do |index| if index.class == String or index.class == Symbol then Ampere.connection.hset( @@ -106,11 +112,11 @@ end def update_attribute(key, value) raise "Cannot update a nonexistent field!" unless self.class.fields.include?(key) self.send("#{key}=", value) - Ampere.connection.hset(@id, key, value) + Ampere.connection.hset(@id, key, Marshal.dump(value)) end def update_attributes(hash = {}) # The efficient way, that I haven't figured out how to do yet: # Ampere.connection.hmset(@id, hash) @@ -156,36 +162,54 @@ # Declares a field. See the README for more details. def self.field(name, options = {}) @fields ||= [] @field_defaults ||= {} @indices ||= [] + @field_types ||= {} @fields << name - attr_accessor :"#{name}" + # attr_accessor :"#{name}" # Handle default value @field_defaults[name] = options[:default] + # Handle type, if any + if options[:type] then + @field_types[:"#{name}"] = options[:type].to_s + end + define_method :"#{name}" do instance_variable_get("@#{name}") or self.class.field_defaults[name] end + + define_method :"#{name}=" do |val| + if not self.class.field_types[:"#{name}"] or val.is_a?(eval(self.class.field_types[:"#{name}"])) then + instance_variable_set("@#{name}", val) + else + raise "Cannot set field of type #{self.class.field_types[name.to_sym]} with #{val.class} value" + end + end end def self.fields @fields end def self.field_defaults @field_defaults end + def self.field_types + @field_types + end + # Finds the record with the given ID, or the first that matches the given conditions def self.find(options = {}) if options.class == String then if Ampere.connection.exists(options) then - new(Ampere.connection.hgetall(options)) + new(Ampere.connection.hgetall(options), true) else nil end else # TODO Write a handler for this case, even if it's an exception @@ -237,10 +261,11 @@ # Defines an index. See the README for more details. def self.index(field_name, options = {}) @fields ||= [] @field_defaults ||= {} @indices ||= [] + @field_types ||= {} if field_name.class == String or field_name.class == Symbol then raise "Can't index a nonexistent field!" unless @fields.include?(field_name) elsif field_name.class == Array then field_name.each{|f| raise "Can't index a nonexistent field!" unless @fields.include?(f)} field_name.sort! @@ -288,12 +313,14 @@ } end unless nonindexed_fields.empty? results = all if results.nil? - results.map!{|r| r.class == String ? find(r) : r} + results = results.to_a.map{|r| r.class == String ? find(r) : r} nonindexed_fields.each do |key| - results.select!{|r| r.send(key) == options[key]} + results.select!{|r| + r.send(key) == options[key] + } end end # TODO The eval(to_s) trick seems a little... ghetto. Ampere::Collection.new(eval(to_s), results.reverse)