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)