class Eco::API::Common::People::PersonParser

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_model_attrs [Array<String>] all the internal name attributes, including core, account and details.

Constants

ACCOUNT_ATTRS
CORE_ATTRS
FORMAT
TYPE

Attributes

all_model_attrs[R]
details_attrs[R]
patch_version[R]
schema[R]

Public Class Methods

new(schema: nil) click to toggle source

@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.

# File lib/eco/api/common/people/person_parser.rb, line 37
def initialize(schema: nil)
  raise "Constructor needs a PersonSchema. Given: #{schema}" if schema && !schema.is_a?(Ecoportal::API::V1::PersonSchema)
  @details_attrs = []
  @parsers       = {}
  @patch_version = 0

  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_model_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
  self.class.autoload_children(self)
end

Public Instance Methods

active_attrs(source_data, phase = :any, process: :parse) click to toggle source

Returns a list of all the internal attributes of the model that have a parser defined & that should be active. @param source_data [Hash, Array<String>] the data that we scope for parsing @param phase [Symbol] the phase when the attr parser is expected to be called. Can be [:internal, :final, :person] @param process [Symbol] either `:parse` or `:serialize`, depending if we want to parse or serialize the `attr`. @return [Array<String>] list of all attribute defined parsers that should be active for the given `source_data`.

# File lib/eco/api/common/people/person_parser.rb, line 137
def active_attrs(source_data, phase = :any, process: :parse)
  defined_model_attrs.select do |attr|
    if process == :serialize
      @parsers[attr].serializer_active?(phase)
    else
      @parsers[attr].parser_active?(source_data, phase)
    end
  end
end
all_attrs(include_defined_parsers: false) click to toggle source

All the internal name attributes, including core, account and details.

# File lib/eco/api/common/people/person_parser.rb, line 68
def all_attrs(include_defined_parsers: false)
  return all_model_attrs | defined_model_attrs if include_defined_parsers
  all_model_attrs
end
define_attribute(attr, dependencies: {}, &definition) click to toggle source

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).

# File lib/eco/api/common/people/person_parser.rb, line 184
def define_attribute(attr, dependencies: {}, &definition)
  unless 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::API::Common::People::PersonAttributeParser.new(attr, dependencies: dependencies).tap do |parser|
    @parsers[attr] = parser
    definition.call(parser)
  end
  patched!
  self
end
defined?(attr) click to toggle source

@param attr [String] internal name of an attribute. @return [Boolean] `true` if the attribute `attr` has parser defined, and `false` otherwise.

# File lib/eco/api/common/people/person_parser.rb, line 156
def defined?(attr)
  @parsers.key?(attr)
end
defined_attrs() click to toggle source

Returns a list of all the internal attributes that have a parser defined. @note These attributes do not necessarily belong to the model. They could be virtual attributes @return [Array<String>] list of all attribute defined parsers.

# File lib/eco/api/common/people/person_parser.rb, line 109
def defined_attrs
  defined_list - symbol_keys
end
defined_list() click to toggle source

Lists all defined attributes, types and formats. @return [Array<String>] the list of defined parsers/serializers.

# File lib/eco/api/common/people/person_parser.rb, line 102
def defined_list
  @parsers.keys
end
defined_model_attrs() click to toggle source

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`)
- the list is sorted according `CORE_ATTRS` + `ACCOUNT_ATTRS` + schema attrs

@return [Array<String>] list of all attribute defined parsers in the model.

# File lib/eco/api/common/people/person_parser.rb, line 118
def defined_model_attrs
  defined     = @parsers.keys
  defined     = (all_model_attrs | defined) & defined
  defined - symbol_keys
end
merge(parser) click to toggle source

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).

# File lib/eco/api/common/people/person_parser.rb, line 167
def merge(parser)
  return self if !parser
  raise "Expected a PersonParser object. Given #{parser}" if !parser.is_a?(PersonParser)
  to_h.merge!(parser.to_h)
  patched!
  self
end
new(schema: nil) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 56
def new(schema: nil)
  self.class.new(schema: schema || self.schema).merge(self)
end
parse(attr, source, phase = :internal, deps: {}) click to toggle source

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 phase [Symbol] the phase when the attr parser is expected to be called.

Must be [:internal, :final]

@param deps [Hash] key-value pairs of call dependencies. @return [Any] a valid internal value.

# File lib/eco/api/common/people/person_parser.rb, line 210
def parse(attr, source, phase = :internal, deps: {})
  raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr)
  @parsers[attr].parse(source, phase, dependencies: deps)
end
patched!() click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 52
def patched!
  @patch_version += 1
end
required_attrs() click to toggle source

@return [Array<Eco::API::Common::Loaders::Parser::RequiredAttrs>]

# File lib/eco/api/common/people/person_parser.rb, line 63
def required_attrs
  @parsers.values_at(*all_attrs(include_defined_parsers: true)).compact.map(&:required_attrs).compact
end
serialize(attr, object, phase = :person, deps: {}) click to toggle source

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 phase [Symbol] the phase when the attr serializer is expected to be called.

Must be [:internal, :final, :person]

@param deps [Hash] key-value pairs of call dependencies. @return a valid external value.

# File lib/eco/api/common/people/person_parser.rb, line 225
def serialize(attr, object, phase = :person, deps: {})
  raise "There is no parser for attribute '#{attr}'" if !self.defined?(attr)
  @parsers[attr].serialize(object, phase, dependencies: deps)
end
symbol_keys() click to toggle source

Symbol keys are type or import parsers (that do not belong to the model) @note this was introduced to boost virtual fields to treat in different phases of the parsing process @return [Array<Symbol>] all the parsers defined as Symbol

# File lib/eco/api/common/people/person_parser.rb, line 127
def symbol_keys
  @parsers.keys.select {|k| k.is_a?(Symbol)}
end
target_attrs_account(source_attrs = nil) click to toggle source

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.

# File lib/eco/api/common/people/person_parser.rb, line 95
def target_attrs_account(source_attrs = nil)
  return ACCOUNT_ATTRS if !source_attrs
  scoped_attrs(source_attrs, ACCOUNT_ATTRS)
end
target_attrs_core(source_attrs = nil) click to toggle source

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.

# File lib/eco/api/common/people/person_parser.rb, line 77
def target_attrs_core(source_attrs = nil)
  return CORE_ATTRS if !source_attrs
  scoped_attrs(source_attrs, CORE_ATTRS)
end
target_attrs_details(source_attrs = nil) click to toggle source

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.

# File lib/eco/api/common/people/person_parser.rb, line 86
def target_attrs_details(source_attrs = nil)
  return @details_attrs if !source_attrs
  scoped_attrs(source_attrs, @details_attrs)
end
undefined_model_attrs() click to toggle source

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.

# File lib/eco/api/common/people/person_parser.rb, line 150
def undefined_model_attrs
  all_model_attrs - defined_model_attrs
end

Protected Instance Methods

to_h() click to toggle source

@return [Hash] attr-parser pairs with all the defined type and attribute parsers/serializers.

# File lib/eco/api/common/people/person_parser.rb, line 234
def to_h
  self.class.autoload_children(self)
  @parsers
end

Private Instance Methods

attr_to_str(attr) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 249
def attr_to_str(attr)
  attr.is_a?(Symbol)? ":#{attr.to_s}" : "#{attr.to_s}"
end
scoped_attrs(source_attrs, section_attrs) click to toggle source

Some attribute parsers are inactive, and therefore out of scope @param source_attrs [Array<String>] the attrs we want to filter from to only those in scope. @param section_attrs [Array<String>] the attrs of reference to scope `source_attrs`. @return [Array<String>] the `source_attrs` in `section_attrs` + the `section_attrs` with active parser

# File lib/eco/api/common/people/person_parser.rb, line 245
def scoped_attrs(source_attrs, section_attrs)
  (source_attrs | active_attrs(source_attrs)) & section_attrs
end
valid?(attr) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 253
def valid?(attr)
  valid_attr?(attr) || valid_type?(attr) || valid_format?(attr)
end
valid_attr?(attr) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 257
def valid_attr?(attr)
  attr.is_a?(String) && (!@schema || @all_model_attrs.include?(attr))
end
valid_format?(attr) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 265
def valid_format?(attr)
  attr.is_a?(Symbol) && FORMAT.include?(attr)
end
valid_type?(attr) click to toggle source
# File lib/eco/api/common/people/person_parser.rb, line 261
def valid_type?(attr)
  attr.is_a?(Symbol) && TYPE.include?(attr)
end