lib/eco/api/common/people/person_parser.rb in eco-helpers-0.6.17 vs lib/eco/api/common/people/person_parser.rb in eco-helpers-0.7.1

- old
+ new

@@ -1,97 +1,168 @@ module Eco module API module Common module People + + # Class to define/group a set of parsers/serializers. + # + # @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon. + # @attr_reader details_attrs [Array<String>] internal names of schema details attributes. + # @attr_reader all_attrs [Array<String>] all the internal name attributes, including _core_, _account_ and _details_. class PersonParser CORE_ATTRS = ["id", "external_id", "email", "name", "supervisor_id"] ACCOUNT_ATTRS = ["policy_group_ids", "filter_tags", "default_tag"] TYPE = [:select, :text, :date, :number, :phone_number, :boolean, :multiple] + FORMAT = [:csv, :xml, :json] attr_reader :schema attr_reader :details_attrs, :all_attrs attr_reader :defined_attrs - def initialize(schema: nil) #), logger: nil) - #self.schema = schema + # @example Example of usage: + # person_parser = PersonParser.new(schema: schema) + # person_parser.define_attribute("example") do |parser| + # parser.def_parser do |str, deps| + # i = value.to_i rescue 0 + # i +=5 if deps.dig(:sum_5) + # i + # end.def_serializer do |value| + # value.to_s + # end + # end + # @param schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon. + def initialize(schema: nil) raise "Constructor needs a PersonSchema. Given: #{schema}" if schema && !schema.is_a?(Ecoportal::API::V1::PersonSchema) @details_attrs = [] @parsers = {} if schema @schema = Ecoportal::API::Internal::PersonSchema.new(JSON.parse(schema.doc.to_json)) @details_attrs = @schema&.fields.map { |fld| fld.alt_id } end @all_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs - #init_default_parsers if @schema end + # Lists all defined attributes, types and formats. + # @return [Array<String>] the list of defined parsers/serializers. + def list_defined + @parsers.keys + end + + # Scopes `source_attrs` using the _**core** attributes_. + # @note use this helper to know which among your attributes are **core** ones. + # @param source_attrs [Array<String>] + # @return [Array<String>] the scoped **core** attributes, if `source_attrs` is not `nil`. All the _core attributes_, otherwise. def target_attrs_core(source_attrs = nil) return CORE_ATTRS if !source_attrs scoped_attrs(source_attrs, CORE_ATTRS) end + # Scopes `source_attrs` using the schema _**details** attributes_. + # @note use this helper to know which among your attributes are schema **details** ones. + # @param source_attrs [Array<String>] + # @return [Array<String>] the scoped **details** attributes, if `source_attrs` is not `nil`. All the _details attributes_, otherwise. def target_attrs_details(source_attrs = nil) return @details_attrs if ! source_attrs scoped_attrs(source_attrs, @details_attrs) end + # Scopes `source_attrs` using the schema _**account** attributes_. + # @note use this helper to know which among your attributes are **account** ones. + # @param source_attrs [Array<String>] + # @return [Array<String>] the scoped **account** attributes, if `source_attrs` is not `nil`. All the _account attributes_, otherwise. def target_attrs_account(source_attrs = nil) return ACCOUNT_ATTRS if !source_attrs scoped_attrs(source_attrs, ACCOUNT_ATTRS) end - def defined - @parsers.keys - end - - def list - @parsers.keys - end - + # Returns a list of all the internal attributes of the model that have a parser defined. + # @note it excludes any parser that is not in the model, such as type parsers (i.e. ``:boolean`, ``:multiple`) + # @return [Array<String>] list of all attribute defined parsers. def defined_attrs + defined = @parsers.keys defined - (defined - all_attrs) end + # Returns a list of all the internal attributes of the model that do **not** have a parser defined. + # @note it excludes any parser that is **not** in the model, such as type parsers (i.e. :boolean, :multiple) + # @return [Array<String>] list of all attributes without a defined parser. def undefined_attrs all_attrs - defined_attrs end + # @param attr [String] internal name of an attribute. + # @return [Boolean] `true` if the attribute `attr` has parser defined, and `false` otherwise. def defined?(attr) - !!@parsers[attr] + @parsers.key?(attr) end - #def append(attr, dependencies: {}, &bloc) - # @parsers[attr] = into_a(parsers[attr]).push(define_parser(attr, dependencies, &bloc)) - #end - - # merges parser overriding self for exisint parsers + # Helper to **merge** a set of parsers of another `PersonParser` into the current object. + # @note if there are parsers with same name, it **overrides** the ones of the current object with them. + # @param parser [Eco::API::Common::People::PersonParser] a `PersonParser` containing defined parsers. + # @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig). def merge(parser) return self if !parser raise "Expected a PersonParser object. Given #{parser}" if !parser.is_a?(PersonParser) @parsers.merge!(parser.hash) self end - def define_attribute(attr, dependencies: {}, &bloc) - @parsers[attr] = define_parser(attr, dependencies, &bloc) + + # Helper to define and associate a parser/serializer to a type or attribute. + # @raise [Exception] if trying to define a parser/serializer for: + # - an unkown attribute (`String`) + # - an unrecognized type or format (`Symbol`) + # @param attr [String] type (`Symbol`) or attribute (`String`) to define the parser/serializer to. + # @param dependencies [Hash] dependencies to be used when calling the parser/serializer. + # @yield [parser] the definition of the parser. + # @yieldparam parser [Eco::Language::Models::ParserSerializer] parser to define. + # @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig). + def define_attribute(attr, dependencies: {}, &definition) + if !valid?(attr) + msg = "The attribute '#{attr_to_str(attr)}' is not part of core, account or target schema, or does not match any type: #{@details_attrs}" + raise msg + end + + Eco::Language::Models::ParserSerializer.new(attr, dependencies: dependencies).tap do |parser| + @parsers[attr] = parser + definition.call(parser) + end + self end + # Call to parser `source` value of attribute or type `attr` into an internal valid value. + # @note dependencies introduced on `parse` call will be merged with those defined during the + # initialization of the parser `attr`. + # @raise [Exception] if there is **no** parser for attribute or type `attr`. + # @param attr [String] target attribute or type to **parse**. + # @param source [Any] source value to be parsed. + # @param deps [Hash] key-value pairs of call dependencies. + # @return [Any] a valid internal value. def parse(attr, source, deps: {}) raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr) @parsers[attr].parse(source, dependencies: deps) end + # Call to serialise `object` value of attribute or type `attr` into an external valid value. + # @note dependencies introduced on `serialise` call will be merged with those defined during the + # initialization of the parser/serialiser `attr`. + # @raise [Exception] if there is **no** serialiser for attribute or type `attr`. + # @param attr [String] target attribute or type to **serialize**. + # @param object [Any] object value to be serialized. + # @param deps [Hash] key-value pairs of call dependencies. + # @return a valid external value. def serialize(attr, object, deps: {}) raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr) @parsers[attr].serialize(object, dependencies: deps) end protected + # @return [Hash] attr-parser pairs with all the defined type and attribute parsers/serializers. def hash @parsers end private @@ -100,38 +171,27 @@ direct_attrs = source_attrs & section_attrs parsed_attrs = @parsers.keys & section_attrs (source_attrs + parsed_attrs) & (direct_attrs + parsed_attrs) end - def define_parser(attr, dependencies = {}, &definition) - if !valid?(attr) - str_attr = (attr.is_a?(Symbol) ? ":" : "") + attr.to_s - msg = "The attribute '#{str_attr}' is not part of core, account or target schema, or does not match any type: #{@details_attrs}" - raise msg - end - parser = Eco::Language::Models::AttributeParser.new(attr, dependencies: dependencies) - #yield(parser) - definition.call(parser) - parser + def attr_to_str(attr) + attr.is_a?(Symbol)? ":#{attr.to_s}" : "#{attr.to_s}" end def valid?(attr) - (attr.is_a?(Symbol) && valid_type?(attr)) || - (attr.is_a?(String) && (!@schema || valid_attr?(attr))) + valid_attr?(attr) || valid_type?(attr) || valid_format?(attr) end def valid_attr?(attr) - @all_attrs.include?(attr) + attr.is_a?(String) && (!@schema || @all_attrs.include?(attr)) end def valid_type?(attr) - TYPE.include?(attr) + attr.is_a?(Symbol) && TYPE.include?(attr) end - def into_a(value) - value = [] if value == nil - value = [].push(value) unless value.is_a?(Array) - value + def valid_format?(attr) + attr.is_a?(Symbol) && FORMAT.include?(attr) end end end end