Class: Eco::API::Common::People::PersonEntryAttributeMapper

Inherits:
Object
  • Object
show all
Includes:
Language::AuxiliarLogger
Defined in:
lib/eco/api/common/people/person_entry_attribute_mapper.rb

Constant Summary collapse

DEBUG =
false
@@cached_warnings =

rubocop:disable Style/ClassVars

{}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Language::AuxiliarLogger

#log

Constructor Details

#initialize(data, person_parser:, attr_map:, logger: ::Logger.new(IO::NULL)) ⇒ PersonEntryAttributeMapper

Note:
  • if data is a Person object, its behaviour is serialise.
  • if data is not a Person object, it does a parse.
  • currently in rework, so there may be subtle differences that make it temporarily unstable (yet it is reliable).

Helper class tied to PersonEntry that allows to track which attributes of a person entry are present and how they should be mapped between internal and external names if applicable. This class is meant to help in providing a common interface to access entries of source data that come in different formats.

Parameters:

  • data (Hash, Ecoportal::API::V1::Person)

    Person object to be serialized or hashed entry to be parsed (note: CSV::Row is accepted).

  • person_parser (Common::People::PersonParser)

    parser/serializer of person attributes (it contains a set of attribute parsers).

  • attr_map (Eco::Data::Mapper)

    mapper to translate attribute names from external to internal names and vice versa.

  • logger (Common::Session::Logger, ::Logger) (defaults to: ::Logger.new(IO::NULL))

    object to manage logs.

Raises:

  • (ArgumentError)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 32

def initialize(data, person_parser:, attr_map:, logger: ::Logger.new(IO::NULL))
  msg = "Constructor needs a PersonParser. Given: #{person_parser.class}"
  raise ArgumentError, msg unless person_parser.is_a?(Eco::API::Common::People::PersonParser)

  msg = "Expecting Mapper object. Given: #{attr_map.class}"
  raise ArgumentError, msg if attr_map && !attr_map.is_a?(Eco::Data::Mapper)

  @source         = data
  @person_parser  = person_parser
  @attr_map       = attr_map
  @logger         = logger

  if parsing?
    @external_entry = data
  else  # SERIALIZING
    @person = data
  end
end

Instance Attribute Details

#direct_attrsArray<String> (readonly)

only those internal attributes present in the person entry that do not have an internal/external name mapping.

Returns:

  • (Array<String>)

    the current value of direct_attrs



8
9
10
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 8

def direct_attrs
  @direct_attrs
end

Instance Method Details

#account_attrs(data = nil) ⇒ Array<String>

Returns account attributes that are present in the person entry.

Returns:

  • (Array<String>)

    account attributes that are present in the person entry.



99
100
101
102
103
104
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 99

def (data = nil)
  return @account_attrs unless data || !@account_attrs
  @person_parser.(internal_attrs(data)).tap do ||
    @account_attrs ||= 
  end
end

#aliased_attrsArray<String>

Returns only those internal attributes present in the person entry that have an internal/external name mapping.

Returns:

  • (Array<String>)

    only those internal attributes present in the person entry that have an internal/external name mapping.



54
55
56
57
58
59
60
61
62
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 54

def aliased_attrs
  return @aliased_attrs if @aliased_attrs
  if parsing?
    init_attr_trackers
  else
    @aliased_attrs = @attr_map.list(:internal)
  end
  @aliased_attrs
end

#all_model_attrs(data = nil) ⇒ Array<String>

Returns all the attrs that are present in the person entry.

Returns:

  • (Array<String>)

    all the attrs that are present in the person entry.



78
79
80
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 78

def all_model_attrs(data = nil)
  core_attrs(data) | (data) | details_attrs(data)
end

#core_attrs(data = nil) ⇒ Array<String>

Returns core attributes that are present in the person entry.

Returns:

  • (Array<String>)

    core attributes that are present in the person entry.



83
84
85
86
87
88
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 83

def core_attrs(data = nil)
  return @core_attrs unless data || !@core_attrs
  @person_parser.target_attrs_core(internal_attrs(data)).tap do |core_attrs|
    @core_attrs ||= core_attrs
  end
end

#details_attrs(data = nil) ⇒ Array<String>

Returns schema details attributes that are present in the person entry.

Returns:

  • (Array<String>)

    schema details attributes that are present in the person entry.



91
92
93
94
95
96
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 91

def details_attrs(data = nil)
  return @details_attrs unless data || !@details_attrs
  @person_parser.target_attrs_details(internal_attrs(data)).tap do |details_attrs|
    @details_attrs ||= details_attrs
  end
end

#internal_attrs(data = nil) ⇒ Array<String>

Returns all the internally named attributes that the person entry has.

Returns:

  • (Array<String>)

    all the internally named attributes that the person entry has.



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 65

def internal_attrs(data = nil)
  return @internal_attrs unless data || !@internal_attrs
  if parsing?
    init_attr_trackers unless @internal_attrs

    return data.keys & @person_parser.all_model_attrs if data
  else
    @internal_attrs = @person_parser.all_model_attrs
  end
  @internal_attrs
end

#parsing?Boolean

To know if currently the object is in parse or serialize mode.

Returns:

  • (Boolean)

    returns true if we are parsing, false otherwise.



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

def parsing?
  !@source.is_a?(Ecoportal::API::V1::Person)
end

#serializing?Boolean

To know if currently the object is in parse or serialize mode.

Returns:

  • (Boolean)

    returns true if we are serializing, false otherwise.



114
115
116
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 114

def serializing?
  !parsing?
end

#to_external(value) ⇒ String, ...

Note:
  1. the scope of attributes is based on all the attributes defined in the current entry.
  2. the attributes recognized by the person parser are those of of the Person model (where details attributes depend on the schema).

Serializing helper also used to do a reverse mapping when parsing:

  • as there could be internal attributes that shared external attributes,
  • when parsing, you use this helper to recognize the source external attribute of each internal one. If there no mapper defined for the object, it mirrors value. If there is a mapper defined for the object:
  • if the value exists as internal-, translates it into an _external one.
  • if it doesn't exist, returns nil.

Parameters:

  • value (String, Array<String>)

    value(s) to be translated or aliased into external ones.

Returns:

  • (String, nil, Array<String] the external name(s) of `value`.)

    String, nil, Array<String] the external name(s) of value.



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 176

def to_external(value)
  return value unless @attr_map

  attr = value
  case value
  when Array
    return value.map do |v|
      to_external(v)
    end.compact
  when String
    if @attr_map.internal?(value)
      attr = @attr_map.to_external(value)
    elsif @attr_map.internal?(value.strip)
      unless cached_warning("internal", "spaces", value)
        msg  = "The internal person field name '#{value}' contains "
        msg << "additional spaces in the reference file"
        log(:warn) { msg }
      end
      attr = @attr_map.to_external(value.strip)
    elsif [value, value.strip, value.strip.downcase].any? {|val| @attr_map.external?(val)}
      unless cached_warning("internal", "reversed", value)
        msg  = "The mapper [external, internal] attribute names "
        msg << "may be declared reversedly for "
        msg << "INTERNAL attribute: '#{value}'"
        log(:info) { msg }
      end
    end
  end

  return unless !@external_entry || attributes(@external_entry).include?(attr)
  attr
end

#to_internal(value) ⇒ String, ...

Note:
  1. the scope of attributes is based on all the attributes recognized by the person parser.
  2. the attributes recognized by the person parser are those of of the Person model (where details attributes depend on the schema).

If there no mapper defined for the object, it mirrors value. If there is a mapper defined for the object:

  1. if the value exists as external, translates it into an internal one.
  2. if it doesn't exist, returns nil.

Parameters:

  • value (String, Array<String>)

    value(s) to be translated into internal names.

Returns:

  • (String, nil, Array<String] the internal name(s) of `value`.)

    String, nil, Array<String] the internal name(s) of value.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 128

def to_internal(value)
  # TODO: check PersonEntry#to_internal and #to_external in init_attr_trackers
  # => when attr_map is avoided, it doesn't work as it should
  return value unless @attr_map

  attr = value
  case value
  when Array
    return value.map do |v|
      to_internal(v)
    end.compact
  when String
    if @attr_map.external?(value)
      attr = @attr_map.to_internal(value)
    elsif @attr_map.external?(value.strip)
      unless cached_warning("external", "spaces", value)
        msg  = "The external person field name '#{value}' contains "
        msg << "additional spaces in the reference file"
        log(:warn) { msg }
      end

      attr = @attr_map.to_internal(value.strip)
    elsif [value, value.strip, value.strip.downcase].any? {|val| @attr_map.internal?(val)}
      unless cached_warning("external", "reversed", value)
        msg  = "The mapper [external, internal] attribute names "
        msg << "may be declared reversedly for EXTERNAL attribute: '#{value}'"
        log(:info) { msg }
      end
    end
  end

  return unless @person_parser.all_model_attrs.include?(attr)
  attr
end