diff --git a/lib/dm-serializer/common.rb b/lib/dm-serializer/common.rb index dbbd620..718d8f8 100644 --- a/lib/dm-serializer/common.rb +++ b/lib/dm-serializer/common.rb @@ -22,6 +22,19 @@ def properties_to_serialize(options) end end end + + # add properties as a result from the serialization callback + def invoke_serialization_callback + serialization_callback_result = {} + if respond_to?(:serialization_callback) + serialization_callback_result = serialization_callback + unless serialization_callback_result.is_a?(Hash) + raise "#serialization_callback should return a Hash, found #{serialization_callback_result.class}" + end + end + serialization_callback_result + end + end Model.append_inclusions(Serializer) diff --git a/lib/dm-serializer/to_csv.rb b/lib/dm-serializer/to_csv.rb index b85e979..6766a45 100644 --- a/lib/dm-serializer/to_csv.rb +++ b/lib/dm-serializer/to_csv.rb @@ -26,6 +26,9 @@ def to_csv(*args) row = properties_to_serialize(options).map do |property| __send__(property.name).to_s end + row += invoke_serialization_callback.map do |key, value| + value.to_s + end csv << row end end diff --git a/lib/dm-serializer/to_json.rb b/lib/dm-serializer/to_json.rb index b1efaf3..a17562e 100644 --- a/lib/dm-serializer/to_json.rb +++ b/lib/dm-serializer/to_json.rb @@ -31,6 +31,8 @@ def as_json(options = {}) result[method] = __send__(method) end + result.merge! invoke_serialization_callback + # Note: if you want to include a whole other model via relation, use # :methods: # diff --git a/lib/dm-serializer/to_xml.rb b/lib/dm-serializer/to_xml.rb index 2b572eb..3375387 100644 --- a/lib/dm-serializer/to_xml.rb +++ b/lib/dm-serializer/to_xml.rb @@ -59,6 +59,15 @@ def to_xml_document(opts={}, doc = nil) end end + invoke_serialization_callback.each do |key, value| + xml_key_name = key.to_s.gsub(/[^a-z0-9_]/, '') + if value.respond_to?(:to_xml_document) + xml.add_xml(root, value.to_xml_document) + else + xml.add_node(root, xml_key_name, value.to_s) + end + end + doc end diff --git a/lib/dm-serializer/to_yaml.rb b/lib/dm-serializer/to_yaml.rb index 3d2e8a1..19c747c 100644 --- a/lib/dm-serializer/to_yaml.rb +++ b/lib/dm-serializer/to_yaml.rb @@ -59,6 +59,10 @@ def encode_with(coder, options = {}) value = __send__(method) coder.add(method, value.is_a?(Class) ? value.to_s : value) end + + invoke_serialization_callback.each do |key, value| + coder.add(key.to_s, value.is_a?(Class) ? value.to_s : value) + end end private diff --git a/spec/public/to_csv_spec.rb b/spec/public/to_csv_spec.rb index 2a756e1..f36e1b5 100644 --- a/spec/public/to_csv_spec.rb +++ b/spec/public/to_csv_spec.rb @@ -64,8 +64,27 @@ george.to_csv.should match(/false/) end end + end + end + + describe DataMapper::Serialize, '#to_csv' do + + it "supports serialization_callbacks" do + class Horse + include DataMapper::Resource + property :id, Serial + property :name, String + + def serialization_callback + { :external_name => "#{name}_external" } + end + end + + horse = Horse.new(:name => 'legolas') + horse.to_csv.should match(/legolas_external/) end + end else warn "[WARNING] Cannot require 'faster_csv' or 'csv', not running #to_csv specs" diff --git a/spec/public/to_json_spec.rb b/spec/public/to_json_spec.rb index e3a8919..78c4650 100644 --- a/spec/public/to_json_spec.rb +++ b/spec/public/to_json_spec.rb @@ -73,3 +73,38 @@ def deserialize(result) Motorcycle.new.as_json[:type].should == "Motorcycle" end end + +describe DataMapper::Serializer, '#as_json' do + before(:each) do + class Horse + include DataMapper::Resource + + property :id, Serial + property :name, String + + def serialization_callback + { :external_name => "#{name}_external" } + end + end + end + + it "supports serialization_callbacks" do + horse = Horse.new(:name => 'legolas') + horse.as_json[:external_name].should == 'legolas_external' + end + + it "should raise an exception when the serialization_callback does not return a Hash" do + class Horse + def serialization_callback + name + end + end + + expect { Horse.new(:name => 'legolas').as_json }.to raise_error + end + + it "should not raise an exception when the serialization_callback returns a Hash" do + expect { Horse.new(:name => 'legolas').as_json }.to_not raise_error + end + +end diff --git a/spec/public/to_xml_spec.rb b/spec/public/to_xml_spec.rb index be0e054..92d69c3 100644 --- a/spec/public/to_xml_spec.rb +++ b/spec/public/to_xml_spec.rb @@ -107,4 +107,23 @@ def cast(value, type) end end end + + describe "adding properties from serialization_callback as well" do + it "should call the serialization_callback method and add the results" do + class Horse + include DataMapper::Resource + + property :id, Serial + property :name, String + + def serialization_callback + { :external_name => "#{name}_external" } + end + end + + horse = Horse.create(:name => 'legolas') + result = horse.to_xml + puts REXML::Document.new(result).elements[1].elements["external_name"].text == 'legolas_external' + end + end end diff --git a/spec/public/to_yaml_spec.rb b/spec/public/to_yaml_spec.rb index d828970..715eaf6 100644 --- a/spec/public/to_yaml_spec.rb +++ b/spec/public/to_yaml_spec.rb @@ -56,4 +56,20 @@ def deserialize(result) result[0]['name'].should == 'Berta' end + it "supports serialization_callbacks" do + class Horse + include DataMapper::Resource + + property :id, Serial + property :name, String + + def serialization_callback + { :external_name => "#{name}_external" } + end + end + + horse = Horse.create(:name => 'legolas') + result = @harness.deserialize(YAML.dump(horse)) + result['external_name'].should == 'legolas_external' + end end