add xml_name option to properties_dsl

also:
* only allow symbols as name and xml_name
* use public_send instead of send
This commit is contained in:
Benjamin Neff 2015-07-24 02:05:02 +02:00
parent 0deb74c103
commit 71b1d6dc1e
7 changed files with 84 additions and 29 deletions

View file

@ -8,10 +8,9 @@ module DiasporaFederation
property :guid
# @!attribute [r] diaspora_id
# @todo refactoring with properties_dsl, xml name should be diaspora_handle
# The diaspora ID of the person
# @return [String] diaspora ID
property :diaspora_id
property :diaspora_id, xml_name: :diaspora_handle
# @!attribute [r] url
# @see WebFinger#seed_url

View file

@ -3,11 +3,10 @@ module DiasporaFederation
# this entity contains all the profile data of a person
class Profile < Entity
# @!attribute [r] diaspora_id
# @todo refactoring with properties_dsl, xml name should be diaspora_handle
# The diaspora ID of the person
# @see Person#diaspora_id
# @return [String] diaspora ID
property :diaspora_id
property :diaspora_id, xml_name: :diaspora_handle
# @!attribute [r] first_name
# @deprecated

View file

@ -15,6 +15,7 @@ module DiasporaFederation
# property :prop
# property :optional, default: false
# property :dynamic_default, default: -> { Time.now }
# property :another_prop, xml_name: :another_name
# entity :nested, NestedEntity
# entity :multiple, [OtherEntity]
# end
@ -59,7 +60,7 @@ module DiasporaFederation
# @return [Hash] entity data (mostly equal to the hash used for initialization).
def to_h
self.class.class_prop_names.each_with_object({}) do |prop, hash|
hash[prop] = send(prop)
hash[prop] = public_send(prop)
end
end
@ -120,24 +121,28 @@ module DiasporaFederation
doc = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new)
Nokogiri::XML::Element.new(self.class.entity_name, doc).tap do |root_element|
self.class.class_props.each do |prop_def|
name = prop_def[:name]
add_property_to_xml(doc, prop_def, root_element)
end
end
end
def add_property_to_xml(doc, prop_def, root_element)
property = prop_def[:name]
type = prop_def[:type]
if type == String
root_element << simple_node(doc, name)
root_element << simple_node(doc, prop_def[:xml_name], property)
else
# call #to_xml for each item and append to root
[*send(name)].compact.each do |item|
[*public_send(property)].compact.each do |item|
root_element << item.to_xml
end
end
end
end
end
# create simple node, fill it with text and append to root
def simple_node(doc, name)
def simple_node(doc, name, property)
Nokogiri::XML::Element.new(name.to_s, doc).tap do |node|
data = send(name).to_s
data = public_send(property).to_s
node.content = data unless data.empty?
end
end

View file

@ -6,6 +6,7 @@ module DiasporaFederation
# property :prop
# property :optional, default: false
# property :dynamic_default, default: -> { Time.now }
# property :another_prop, xml_name: :another_name
# entity :nested, NestedEntity
# entity :multiple, [OtherEntity]
module PropertiesDSL
@ -19,6 +20,7 @@ module DiasporaFederation
# @param [Hash] opts further options
# @option opts [Object, #call] :default a default value, making the
# property optional
# @option opts [Symbol] :xml_name another name used for xml generation
def property(name, opts={})
define_property name, String, opts
end
@ -69,7 +71,14 @@ module DiasporaFederation
def define_property(name, type, opts={})
raise InvalidName unless name_valid?(name)
class_props << {name: name, type: type}
xml_name = name
if opts.has_key? :xml_name
raise ArgumentError, "xml_name is not supported for nested entities" unless type == String
xml_name = opts[:xml_name]
raise InvalidName, "invalid xml_name" unless name_valid?(xml_name)
end
class_props << {name: name, xml_name: xml_name, type: type}
default_props[name] = opts[:default] if opts.has_key? :default
instance_eval { attr_reader name }
@ -79,7 +88,7 @@ module DiasporaFederation
# @param [String, Symbol] name the name to check
# @return [Boolean]
def name_valid?(name)
name.instance_of?(Symbol) || name.instance_of?(String)
name.instance_of?(Symbol)
end
# checks if the type extends {Entity}

View file

@ -20,5 +20,10 @@ module DiasporaFederation
entity :test, TestEntity
entity :multi, [OtherEntity]
end
class TestEntityWithXmlName < DiasporaFederation::Entity
property :test
property :qwer, xml_name: :asdf
end
end
end

View file

@ -61,7 +61,9 @@ module DiasporaFederation
it "contains nodes for each of the properties" do
entity = Entities::TestDefaultEntity.new(data)
entity.to_xml.children.each do |node|
xml_children = entity.to_xml.children
expect(xml_children).to have_exactly(4).items
xml_children.each do |node|
expect(%w(test1 test2 test3 test4)).to include(node.name)
end
end
@ -92,6 +94,7 @@ module DiasporaFederation
it "gets xml-ified by #to_xml" do
entity = Entities::TestNestedEntity.new(nested_data)
xml = entity.to_xml
expect(xml.children).to have_exactly(4).items
xml.children.each do |node|
expect(%w(asdf test_entity other_entity)).to include(node.name)
end
@ -99,5 +102,23 @@ module DiasporaFederation
expect(xml.xpath("other_entity")).to have_exactly(2).items
end
end
context "xml_name" do
let(:hash) { {test: "test", qwer: "qwer"} }
it "uses xml_name for the #to_xml" do
entity = Entities::TestEntityWithXmlName.new(hash)
xml_children = entity.to_xml.children
expect(xml_children).to have_exactly(2).items
xml_children.each do |node|
expect(%w(test asdf)).to include(node.name)
end
end
it "should not use the xml_name for the #to_h" do
entity = Entities::TestEntityWithXmlName.new(hash)
expect(entity.to_h).to eq(hash)
end
end
end
end

View file

@ -8,19 +8,12 @@ module DiasporaFederation
properties = dsl.class_props
expect(properties).to have(1).item
expect(properties.first[:name]).to eq(:test)
expect(properties.first[:type]).to eq(String)
end
it "can name simple properties by string" do
dsl.property "test"
properties = dsl.class_props
expect(properties).to have(1).item
expect(properties.first[:name]).to eq("test")
expect(properties.first[:xml_name]).to eq(:test)
expect(properties.first[:type]).to eq(String)
end
it "will not accept other types for names" do
[1234, true, {}].each do |val|
["test", 1234, true, {}].each do |val|
expect {
dsl.property val
}.to raise_error PropertiesDSL::InvalidName
@ -34,8 +27,26 @@ module DiasporaFederation
properties = dsl.class_props
expect(properties).to have(3).items
expect(properties.map {|e| e[:name] }).to include(:test, :asdf, :zzzz)
expect(properties.map {|e| e[:xml_name] }).to include(:test, :asdf, :zzzz)
properties.each {|e| expect(e[:type]).to eq(String) }
end
it "can add an xml name to simple properties with a symbol" do
dsl.property :test, xml_name: :xml_test
properties = dsl.class_props
expect(properties).to have(1).item
expect(properties.first[:name]).to eq(:test)
expect(properties.first[:xml_name]).to eq(:xml_test)
expect(properties.first[:type]).to eq(String)
end
it "will not accept other types for xml names" do
["test", 1234, true, {}].each do |val|
expect {
dsl.property :test, xml_name: val
}.to raise_error PropertiesDSL::InvalidName, "invalid xml_name"
end
end
end
context "nested entities" do
@ -75,6 +86,12 @@ module DiasporaFederation
}.to raise_error PropertiesDSL::InvalidType
end
end
it "can not add an xml name to a nested entity" do
expect {
dsl.entity :other, Entities::TestEntity, xml_name: :other_name
}.to raise_error ArgumentError, "xml_name is not supported for nested entities"
end
end
describe ".default_values" do