diff --git a/lib/diaspora_federation/entity.rb b/lib/diaspora_federation/entity.rb index 17f69d4..7c34d2a 100644 --- a/lib/diaspora_federation/entity.rb +++ b/lib/diaspora_federation/entity.rb @@ -65,12 +65,21 @@ module DiasporaFederation validate end - # Returns a Hash representing this Entity (attributes => values) + # Returns a Hash representing this Entity (attributes => values). + # Nested entities are also converted to a Hash. # @return [Hash] entity data (mostly equal to the hash used for initialization). def to_h - self.class.class_props.keys.each_with_object({}) do |prop, hash| - hash[prop] = public_send(prop) - end + Hash[properties.map {|key, value| + type = self.class.class_props[key] + + if type == String || value.nil? + [key, value] + elsif type.instance_of?(Class) + [key, value.to_h] + elsif type.instance_of?(Array) + [key, value.map(&:to_h)] + end + }] end # Returns the XML representation for this entity constructed out of @@ -150,7 +159,7 @@ module DiasporaFederation end def setable_nested?(type, val) - type.is_a?(Class) && type.ancestors.include?(Entity) && val.is_a?(Entity) + type.instance_of?(Class) && type.ancestors.include?(Entity) && val.is_a?(Entity) end def setable_multi?(type, val) @@ -178,8 +187,15 @@ module DiasporaFederation "Failed validation for properties: #{errors.join(' | ')}" end + # @return [Hash] hash with all properties + def properties + self.class.class_props.keys.each_with_object({}) do |prop, hash| + hash[prop] = public_send(prop) + end + end + def xml_elements - Hash[to_h.map {|name, value| [name, self.class.class_props[name] == String ? value.to_s : value] }] + Hash[properties.map {|name, value| [name, self.class.class_props[name] == String ? value.to_s : value] }] end def add_property_to_xml(doc, root_element, name, value) diff --git a/spec/lib/diaspora_federation/entity_spec.rb b/spec/lib/diaspora_federation/entity_spec.rb index 9097ef9..c63457a 100644 --- a/spec/lib/diaspora_federation/entity_spec.rb +++ b/spec/lib/diaspora_federation/entity_spec.rb @@ -251,9 +251,16 @@ XML } } - it "gets returned by #to_h" do + it "gets returned as Hash by #to_h" do entity = Entities::TestNestedEntity.new(nested_data) - expect(entity.to_h).to eq(nested_data) + + nested_hash = { + asdf: nested_data[:asdf], + test: nested_data[:test].to_h, + multi: nested_data[:multi].map(&:to_h) + } + + expect(entity.to_h).to eq(nested_hash) end it "gets xml-ified by #to_xml" do diff --git a/spec/support/shared_entity_specs.rb b/spec/support/shared_entity_specs.rb index 4a1efbb..2e474ea 100644 --- a/spec/support/shared_entity_specs.rb +++ b/spec/support/shared_entity_specs.rb @@ -25,10 +25,18 @@ shared_examples "an Entity subclass" do |ignored_props=[]| end describe "#to_h" do - it "should resemble the input data" do - hash = instance.to_h - ignored_props.each {|key| data.delete(key) } - expect(hash).to eq(data) + it "should return a hash with nested data" do + expected_data = Hash[data.reject {|key, _| ignored_props.include?(key) }.map {|key, value| + if [String, TrueClass, FalseClass, Fixnum, Time, NilClass].include?(value.class) + [key, value] + elsif value.instance_of?(Array) + [key, value.map(&:to_h)] + else + [key, value.to_h] + end + }] + + expect(instance.to_h).to eq(expected_data) end end