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

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

Constant Summary collapse

@@cached_warnings =
{}

Instance Attribute Summary collapse

Instance Method Summary collapse

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.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 23

def initialize(data, person_parser:, attr_map:, logger: ::Logger.new(IO::NULL))
  raise "Constructor needs a PersonParser. Given: #{parser}" if !person_parser.is_a?(Eco::API::Common::People::PersonParser)
  raise "Expecting Mapper object. Given: #{attr_map}" 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

#aliased_attrsArray<String> (readonly)

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.



40
41
42
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 40

def aliased_attrs
  @aliased_attrs
end

#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



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

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.



87
88
89
90
91
92
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 87

def (data = nil)
  return @account_attrs unless data || !@account_attrs
  @person_parser.(internal_attrs(data)).tap do ||
    @account_attrs ||= 
  end
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.



66
67
68
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 66

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.



71
72
73
74
75
76
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 71

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.



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

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.



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

def internal_attrs(data = nil)
  return @internal_attrs unless data || !@internal_attrs
  if parsing?
    init_attr_trackers unless @internal_attrs
    if data
      return data.keys & @person_parser.all_model_attrs
    end
  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.



96
97
98
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 96

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.



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

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.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 156

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

  return nil 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.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/eco/api/common/people/person_entry_attribute_mapper.rb', line 115

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 if !@attr_map
  attr = value
  case value
  when Array
    return value.map do |v|
      to_internal(v)
    end.compact
  when String
    case
    when @attr_map.external?(value)
      attr = @attr_map.to_internal(value)
    when @attr_map.external?(value.strip)
      unless cached_warning("external", "spaces", value)
        logger.warn("The external person field name '#{value}' contains additional spaces in the reference file")
      end
      attr = @attr_map.to_internal(value.strip)
    when @attr_map.internal?(value) || @attr_map.internal?(value.strip) || @attr_map.internal?(value.strip.downcase)
      unless cached_warning("external", "reversed", value)
        logger.warn("The mapper [external, internal] attribute names may be declared reversedly for EXTERNAL attribute: '#{value}'")
      end
    end
  end

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