Skip to content

Commit

Permalink
Serialize arbitrary object within an Array key
Browse files Browse the repository at this point in the history
store and retrieve instances of Thing:
class Example
  include MongoMapper::Document
  key :things, Array, :serialize => Thing
end

example.things << Thing.new
  • Loading branch information
Dave Ott and Sandro Turriate authored and jnunemaker committed Oct 2, 2009
1 parent c560a91 commit 9ad5fe8
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
2 changes: 2 additions & 0 deletions lib/mongomapper/embedded_document.rb
Expand Up @@ -259,6 +259,8 @@ def mongodb_attributes
if key.native?
if key.type == Date and date = instance_variable_get("@#{key.name}")
key.normalize_date(date)
elsif key.type == Array && key.options[:serialize]
key.serialize(read_attribute(key.name))
else
read_attribute(key.name)
end
Expand Down
21 changes: 17 additions & 4 deletions lib/mongomapper/key.rb
Expand Up @@ -47,17 +47,30 @@ def normalize_date(value)
rescue
nil
end


def deserialize_array(value)
values = Array(value)
if klass = options[:serialize]
values.map {|attrs| klass.new attrs}
else
values
end
end

def serialize(values)
values.map {|o| o.attributes}
end

private
def typecast(value)
return value if type.nil?
return HashWithIndifferentAccess.new(value) if value.is_a?(Hash) && type == Hash
return value.utc if type == Time && value.kind_of?(type)
return value if value.kind_of?(type) || value.nil?
return value if (value.kind_of?(type) || value.nil?) && type != Array
begin
if type == String then value.to_s
elsif type == Float then value.to_f
elsif type == Array then value.to_a
elsif type == Array then deserialize_array(value)
elsif type == Time then Time.parse(value.to_s).utc
elsif type == Date then normalize_date(value)
elsif type == Boolean then Boolean.mm_typecast(value)
Expand All @@ -83,4 +96,4 @@ def typecast_embedded_document(value)
value.is_a?(type) ? value : type.new(value)
end
end
end
end
27 changes: 27 additions & 0 deletions test/functional/test_document.rb
Expand Up @@ -94,6 +94,33 @@ def setup
doc.tags.should == %w(foo bar)
@document.find(doc.id).tags.should == %w(foo bar)
end

should "serializes and deserializes the attributes" do
Thing = Class.new do
def initialize(hash={})
hash.each{|k,v| instance_variable_set("@#{k}", v)}
end

def attributes
instance_values
end

def ==(other)
attributes == other.attributes
end
end
@document.key :things, Array, :serialize => Thing

thing = Thing.new :name => 'foo'
doc = @document.new
doc.things << thing
doc.save
from_db = @document.find(doc.id)
from_db.things.should == [thing]
from_db.save
doc = @document.find(from_db.id)
doc.things.should == from_db.things
end
end

context "Using key with type Hash" do
Expand Down

0 comments on commit 9ad5fe8

Please sign in to comment.