From c96369b36e39804da7e0c087c888f69345e5ac26 Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Thu, 11 Feb 2016 03:31:57 +0100 Subject: [PATCH] add alias functionality to entities * add diaspora_id alias to Person and Profile for Discovery * also diaspora_id for AccountDeletion --- .../entities/account_deletion.rb | 6 +++- lib/diaspora_federation/entities/person.rb | 6 +++- lib/diaspora_federation/entities/profile.rb | 6 +++- lib/diaspora_federation/entity.rb | 7 ++-- lib/diaspora_federation/properties_dsl.rb | 34 +++++++++++++++++++ .../properties_dsl_spec.rb | 29 ++++++++++++++++ 6 files changed, 82 insertions(+), 6 deletions(-) diff --git a/lib/diaspora_federation/entities/account_deletion.rb b/lib/diaspora_federation/entities/account_deletion.rb index 1bbfffa..ed4a0bb 100644 --- a/lib/diaspora_federation/entities/account_deletion.rb +++ b/lib/diaspora_federation/entities/account_deletion.rb @@ -8,7 +8,11 @@ module DiasporaFederation # The diaspora ID of the deleted account # @see Person#author # @return [String] diaspora ID - property :author, xml_name: :diaspora_handle + # @!attribute [r] diaspora_id + # Alias for author + # @see AccountDeletion#author + # @return [String] diaspora ID + property :author, alias: :diaspora_id, xml_name: :diaspora_handle end end end diff --git a/lib/diaspora_federation/entities/person.rb b/lib/diaspora_federation/entities/person.rb index fef3a73..3844fb0 100644 --- a/lib/diaspora_federation/entities/person.rb +++ b/lib/diaspora_federation/entities/person.rb @@ -15,7 +15,11 @@ module DiasporaFederation # The diaspora ID of the person # @see Validation::Rule::DiasporaId # @return [String] diaspora ID - property :author, xml_name: :diaspora_handle + # @!attribute [r] diaspora_id + # Alias for author + # @see Person#author + # @return [String] diaspora ID + property :author, alias: :diaspora_id, xml_name: :diaspora_handle # @!attribute [r] url # @see Discovery::WebFinger#seed_url diff --git a/lib/diaspora_federation/entities/profile.rb b/lib/diaspora_federation/entities/profile.rb index 248dd19..2a37afd 100644 --- a/lib/diaspora_federation/entities/profile.rb +++ b/lib/diaspora_federation/entities/profile.rb @@ -8,7 +8,11 @@ module DiasporaFederation # The diaspora ID of the person # @see Person#author # @return [String] diaspora ID - property :author, xml_name: :diaspora_handle + # @!attribute [r] diaspora_id + # Alias for author + # @see Profile#author + # @return [String] diaspora ID + property :author, alias: :diaspora_id, xml_name: :diaspora_handle # @!attribute [r] first_name # @deprecated We decided to only use one name field, these should be removed diff --git a/lib/diaspora_federation/entity.rb b/lib/diaspora_federation/entity.rb index 0f5a819..4831dff 100644 --- a/lib/diaspora_federation/entity.rb +++ b/lib/diaspora_federation/entity.rb @@ -56,15 +56,16 @@ module DiasporaFederation # @return [Entity] new instance def initialize(data, additional_xml_elements=nil) raise ArgumentError, "expected a Hash" unless data.is_a?(Hash) - missing_props = self.class.missing_props(data) + entity_data = self.class.resolv_aliases(data) + missing_props = self.class.missing_props(entity_data) unless missing_props.empty? raise ArgumentError, "missing required properties: #{missing_props.join(', ')}" end @additional_xml_elements = nilify(additional_xml_elements) - self.class.default_values.merge(data).each do |k, v| - instance_variable_set("@#{k}", nilify(v)) if setable?(k, v) + self.class.default_values.merge(entity_data).each do |name, value| + instance_variable_set("@#{name}", nilify(value)) if setable?(name, value) end freeze diff --git a/lib/diaspora_federation/properties_dsl.rb b/lib/diaspora_federation/properties_dsl.rb index ade42ef..dbd259f 100644 --- a/lib/diaspora_federation/properties_dsl.rb +++ b/lib/diaspora_federation/properties_dsl.rb @@ -7,6 +7,7 @@ module DiasporaFederation # property :optional, default: false # property :dynamic_default, default: -> { Time.now } # property :another_prop, xml_name: :another_name + # property :original_prop, alias: :alias_prop # entity :nested, NestedEntity # entity :multiple, [OtherEntity] module PropertiesDSL @@ -66,6 +67,20 @@ module DiasporaFederation @class_prop_names ||= class_props.map {|p| p[:name] } end + # @param [Hash] data entity data + # @return [Hash] hash with resolved aliases + def resolv_aliases(data) + Hash[data.map {|name, value| + if class_prop_aliases.has_key? name + prop_name = class_prop_aliases[name] + raise InvalidData, "only use '#{name}' OR '#{prop_name}'" if data.has_key? prop_name + [prop_name, value] + else + [name, value] + end + }] + end + # finds a property by +xml_name+ or +name+ # @param [String] xml_name name of the property from the received xml # @return [Hash] the property data @@ -99,6 +114,8 @@ module DiasporaFederation default_props[name] = opts[:default] if opts.has_key? :default instance_eval { attr_reader name } + + define_alias(name, opts[:alias]) if opts.has_key? :alias end # checks if the name is a +Symbol+ or a +String+ @@ -121,6 +138,19 @@ module DiasporaFederation @default_props ||= {} end + # Returns all alias mappings + # @return [Hash] alias properties + def class_prop_aliases + @class_prop_aliases ||= {} + end + + # @param [Symbol] name property name + # @param [Symbol] alias_name alias name + def define_alias(name, alias_name) + class_prop_aliases[alias_name] = name + instance_eval { alias_method alias_name, name } + end + # Raised, if the name is of an unexpected type class InvalidName < RuntimeError end @@ -128,5 +158,9 @@ module DiasporaFederation # Raised, if the type is of an unexpected type class InvalidType < RuntimeError end + + # Raised, if the data contains property twice (with name AND alias) + class InvalidData < RuntimeError + end end end diff --git a/spec/lib/diaspora_federation/properties_dsl_spec.rb b/spec/lib/diaspora_federation/properties_dsl_spec.rb index 90a51bd..c121223 100644 --- a/spec/lib/diaspora_federation/properties_dsl_spec.rb +++ b/spec/lib/diaspora_federation/properties_dsl_spec.rb @@ -124,6 +124,35 @@ module DiasporaFederation end end + describe ".resolv_aliases" do + it "resolves the defined alias" do + dsl.property :test, alias: :test_alias + data = dsl.resolv_aliases(test_alias: "foo") + expect(data[:test]).to eq("foo") + expect(data).not_to have_key(:test_alias) + end + + it "raises when alias and original property are present" do + dsl.property :test, alias: :test_alias + expect { + dsl.resolv_aliases(test_alias: "foo", test: "bar") + }.to raise_error PropertiesDSL::InvalidData, "only use 'test_alias' OR 'test'" + end + + it "returns original data if no alias is defined" do + dsl.property :test, alias: :test_alias + data = dsl.resolv_aliases(test: "foo") + expect(data[:test]).to eq("foo") + end + + it "returns original data if alias is defined, but not present" do + dsl.property :test + data = dsl.resolv_aliases(test: "foo") + expect(data[:test]).to eq("foo") + expect(data).not_to have_key(:test_alias) + end + end + describe ".find_property_for_xml_name" do it "finds property by xml_name" do dsl.property :test, xml_name: :xml_test