Class: Eco::API::Common::People::PersonParser

Inherits:
Object
  • Object
show all
Extended by:
Language::Klass::AutoLoader
Defined in:
lib/eco/api/common/people/person_parser.rb

Overview

Class to define/group a set of parsers/serializers.

Direct Known Subclasses

DefaultParsers

Constant Summary collapse

CORE_ATTRS =
%w[
  id external_id email name
  phone_number
  supervisor_id filter_tags
  archived
  contractor_organization_id
  brand_id
  freemium
].freeze
ACCOUNT_ATTRS =
%w[
  policy_group_ids default_tag
  send_invites landing_page_id
  login_provider_ids
].freeze
TYPE =
%i[
  select text date
  number phone_number
  boolean multiple
].freeze
FORMAT =
%i[csv xml json xls].freeze

Instance Attribute Summary collapse

selection options of all select attributes collapse

Scopping attributes (identifying, presence & active) collapse

Defining attributes collapse

Launching parser/serializer collapse

Instance Method Summary collapse

Methods included from Language::Klass::AutoLoader

_autoload_namespace, autoload_children!, autoload_class?, autoload_namespace, autoload_namespace_ignore, autoloaded_children, autoloaded_class, autoloaded_namespaces, autoloads_children_of, known_class!, known_classes, new_classes, unloaded_children

Methods included from Language::Klass::Hierarchy

#descendants, #descendants?

Methods included from Language::Klass::Resolver

#class_resolver, #resolve_class

Constructor Details

#initialize(schema: nil) ⇒ PersonParser

Returns a new instance of PersonParser.

Examples:

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

Parameters:

  • schema (Ecoportal::API::V1::PersonSchema, nil) (defaults to: nil)

    schema of person details that this parser will be based upon.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/eco/api/common/people/person_parser.rb', line 56

def initialize(schema: nil)
  msg = "Constructor needs a PersonSchema. Given: #{schema.class}"
  raise msg 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(&:alt_id)
  end

  @all_model_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
  self.class.autoload_children!(self)
end

Instance Attribute Details

#all_model_attrsArray<String> (readonly)

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

Returns:

  • (Array<String>)

    the current value of all_model_attrs



13
14
15
# File 'lib/eco/api/common/people/person_parser.rb', line 13

def all_model_attrs
  @all_model_attrs
end

#details_attrsArray<String> (readonly)

internal names of chema details attributes.

Returns:

  • (Array<String>)

    the current value of details_attrs



13
14
15
# File 'lib/eco/api/common/people/person_parser.rb', line 13

def details_attrs
  @details_attrs
end

#patch_versionObject (readonly)

Returns the value of attribute patch_version.



41
42
43
# File 'lib/eco/api/common/people/person_parser.rb', line 41

def patch_version
  @patch_version
end

#schemaEcoportal::API::V1::PersonSchema? (readonly)

schema of person details that this parser will be based upon.

Returns:

  • (Ecoportal::API::V1::PersonSchema, nil)

    the current value of schema



13
14
15
# File 'lib/eco/api/common/people/person_parser.rb', line 13

def schema
  @schema
end

Instance Method Details

#active_attrs(source_data, phase = :any, process: :parse) ⇒ Array<String>

Returns a list of all the internal attributes of the model that have a parser defined & that should be active. Can be [:internal, :final, :person]

Parameters:

  • source_data (Hash, Array<String>)

    the data that we scope for parsing

  • phase (Symbol) (defaults to: :any)

    the phase when the attr parser is expected to be called.

  • process (Symbol) (defaults to: :parse)

    either :parse or :serialize, depending if we want to parse or serialize the attr.

Returns:

  • (Array<String>)

    list of all attribute defined parsers that should be active for the given source_data.



200
201
202
203
204
205
206
207
208
# File 'lib/eco/api/common/people/person_parser.rb', line 200

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) ⇒ Object

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



115
116
117
118
119
# File 'lib/eco/api/common/people/person_parser.rb', line 115

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: {}) {|parser| ... } ⇒ Eco::API::Common::People::PersonParser

Helper to define and associate a parser/serializer to a type or attribute.

Parameters:

  • attr (String)

    type (Symbol) or attribute (String) to define the parser/serializer to.

  • dependencies (Hash) (defaults to: {})

    dependencies to be used when calling the parser/serializer.

Yields:

  • (parser)

    the definition of the parser.

Yield Parameters:

Returns:

Raises:

  • (Exception)

    if trying to define a parser/serializer for:

    • an unknown attribute (String)
    • an unrecognized type or format (Symbol)


251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/eco/api/common/people/person_parser.rb', line 251

def define_attribute(attr, dependencies: {}, &definition)
  unless valid?(attr)
    msg =  "The attribute '#{attr_to_str(attr)}' is not part of "
    msg << 'core, account or target schema, or does '
    msg << "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) ⇒ Boolean

Returns true if the attribute attr has parser defined, and false otherwise.

Parameters:

  • attr (String)

    internal name of an attribute.

Returns:

  • (Boolean)

    true if the attribute attr has parser defined, and false otherwise.



219
220
221
# File 'lib/eco/api/common/people/person_parser.rb', line 219

def defined?(attr)
  @parsers.key?(attr)
end

#defined_attrsArray<String>

Note:

These attributes do not necessarily belong to the model. They could be virtual attributes

Returns a list of all the internal attributes that have a parser defined.

Returns:

  • (Array<String>)

    list of all attribute defined parsers.



166
167
168
# File 'lib/eco/api/common/people/person_parser.rb', line 166

def defined_attrs
  defined_list - symbol_keys
end

#defined_listArray<String>

Lists all defined attributes, types and formats.

Returns:

  • (Array<String>)

    the list of defined parsers/serializers.



159
160
161
# File 'lib/eco/api/common/people/person_parser.rb', line 159

def defined_list
  @parsers.keys
end

#defined_model_attrsArray<String>

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

Returns a list of all the internal attributes of the model that have a parser defined.

Returns:

  • (Array<String>)

    list of all attribute defined parsers in the model.



175
176
177
178
179
180
# File 'lib/eco/api/common/people/person_parser.rb', line 175

def defined_model_attrs
  defined = @parsers.keys
  defined = (all_model_attrs | defined) & defined

  defined - symbol_keys
end

#merge(parser) ⇒ Eco::API::Common::People::PersonParser

Note:

if there are parsers with same name, it overrides the ones of the current object with them.

Helper to merge a set of parsers of another PersonParser into the current object.

Parameters:

Returns:



230
231
232
233
234
235
236
237
238
239
240
# File 'lib/eco/api/common/people/person_parser.rb', line 230

def merge(parser)
  return self unless parser

  msg = "Expected a PersonParser object. Given #{parser.class}"
  raise msg unless parser.is_a?(PersonParser)

  to_h.merge!(parser.to_h)
  patched!

  self
end

#new(schema: nil) ⇒ Object



79
80
81
82
83
# File 'lib/eco/api/common/people/person_parser.rb', line 79

def new(schema: nil)
  self.class.new(
    schema: schema || self.schema
  ).merge(self)
end

#parse(attr, source, phase = :internal, deps: {}) ⇒ Any

Note:

dependencies introduced on parse call will be merged with those defined during the initialization of the parser attr.

Call to parser source value of attribute or type attr into an internal valid value.

Parameters:

  • attr (String)

    target attribute or type to parse.

  • source (Any)

    source value to be parsed.

  • phase (Symbol) (defaults to: :internal)

    the phase when the attr parser is expected to be called. Must be [:internal, :final]

  • deps (Hash) (defaults to: {})

    key-value pairs of call dependencies.

Returns:

  • (Any)

    a valid internal value.

Raises:

  • (Exception)

    if there is no parser for attribute or type attr.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/eco/api/common/people/person_parser.rb', line 288

def parse(attr, source, phase = :internal, deps: {})
  msg = "There is no parser for attribute '#{attr}'"
  raise msg unless self.defined?(attr)

  @parsers[attr].parse(
    source,
    phase,
    dependencies: deps
  ) do |_dkey, dval|
    next dval unless dval.is_a?(Proc)

    dval.call(self)
  end
end

#patched!Object



75
76
77
# File 'lib/eco/api/common/people/person_parser.rb', line 75

def patched!
  @patch_version += 1
end

#required_attrsArray<Eco::API::Common::Loaders::Parser::RequiredAttrs>



108
109
110
111
112
# File 'lib/eco/api/common/people/person_parser.rb', line 108

def required_attrs
  @parsers.values_at(*all_attrs(
    include_defined_parsers: true
  )).compact.map(&:required_attrs).compact
end

#select_tablesObject

Select Options



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/eco/api/common/people/person_parser.rb', line 88

def select_tables
  return unless @schema

  @select_tables ||= @schema.fields.select do |fld|
    fld.type == 'select'
  end.to_h do |fld|
    msg = "The schema selection field '#{fld.name}' is missing selection options."
    raise msg unless fld.options&.any?

    options_hash = fld.options.to_h { |v| [v.downcase.strip, v] }

    [fld.alt_id, options_hash]
  end
end

#serialize(attr, object, phase = :person, deps: {}) ⇒ Object

Note:

dependencies introduced on serialise call will be merged with those defined during the initialization of the parser/serialiser attr.

Call to serialise object value of attribute or type attr into an external valid value.

Parameters:

  • attr (String)

    target attribute or type to serialize.

  • object (Any)

    object value to be serialized.

  • phase (Symbol) (defaults to: :person)

    the phase when the attr serializer is expected to be called. Must be [:internal, :final, :person]

  • deps (Hash) (defaults to: {})

    key-value pairs of call dependencies.

Returns:

  • a valid external value.

Raises:

  • (Exception)

    if there is no serialiser for attribute or type attr.



313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/eco/api/common/people/person_parser.rb', line 313

def serialize(attr, object, phase = :person, deps: {})
  msg = "There is no parser for attribute '#{attr}'"
  raise msg unless self.defined?(attr)

  @parsers[attr].serialize(
    object,
    phase,
    dependencies: deps
  ) do |_dkey, dval|
    next dval unless dval.is_a?(Proc)

    dval.call(self)
  end
end

#symbol_keysArray<Symbol>

Note:

this was introduced to boost virtual fields to treat in different phases of the parsing process

Symbol keys are type or import parsers (that do not belong to the model)

Returns:

  • (Array<Symbol>)

    all the parsers defined as Symbol



185
186
187
# File 'lib/eco/api/common/people/person_parser.rb', line 185

def symbol_keys
  @parsers.keys.select {|k| k.is_a?(Symbol)}
end

#target_attrs_account(source_attrs = nil) ⇒ Array<String>

Note:

use this helper to know which among your attributes are account ones.

Scopes source_attrs using the schema account attributes.

Parameters:

  • source_attrs (Array<String>) (defaults to: nil)

Returns:

  • (Array<String>)

    the scoped account attributes, if source_attrs is not nil. All the account attributes, otherwise.



151
152
153
154
155
# File 'lib/eco/api/common/people/person_parser.rb', line 151

def (source_attrs = nil)
  return ACCOUNT_ATTRS unless source_attrs

  scoped_attrs(source_attrs, ACCOUNT_ATTRS)
end

#target_attrs_core(source_attrs = nil) ⇒ Array<String>

Note:

use this helper to know which among your attributes are core ones.

Scopes source_attrs using the core attributes.

Parameters:

  • source_attrs (Array<String>) (defaults to: nil)

Returns:

  • (Array<String>)

    the scoped core attributes, if source_attrs is not nil. All the core attributes, otherwise.



127
128
129
130
131
# File 'lib/eco/api/common/people/person_parser.rb', line 127

def target_attrs_core(source_attrs = nil)
  return CORE_ATTRS unless source_attrs

  scoped_attrs(source_attrs, CORE_ATTRS)
end

#target_attrs_details(source_attrs = nil) ⇒ Array<String>

Note:

use this helper to know which among your attributes are schema details ones.

Scopes source_attrs using the schema details attributes.

Parameters:

  • source_attrs (Array<String>) (defaults to: nil)

Returns:

  • (Array<String>)

    the scoped details attributes, if source_attrs is not nil. All the details attributes, otherwise.



139
140
141
142
143
# File 'lib/eco/api/common/people/person_parser.rb', line 139

def target_attrs_details(source_attrs = nil)
  return @details_attrs unless source_attrs

  scoped_attrs(source_attrs, @details_attrs)
end

#undefined_model_attrsArray<String>

Note:

it excludes any parser that is not in the model, such as type parsers (i.e. :boolean, :multiple)

Returns a list of all the internal attributes of the model that do not have a parser defined.

Returns:

  • (Array<String>)

    list of all attributes without a defined parser.



213
214
215
# File 'lib/eco/api/common/people/person_parser.rb', line 213

def undefined_model_attrs
  all_model_attrs - defined_model_attrs
end