lib/eco/api/common/people/person_entry.rb in eco-helpers-2.6.4 vs lib/eco/api/common/people/person_entry.rb in eco-helpers-2.7.0
- old
+ new
@@ -8,26 +8,39 @@
# This class is meant to provide a common interface to access entries of source data that come in different formats.
# @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).
- # @param data [Hash, Ecoportal::API::V1::Person] `Person` object to be serialized or hashed entry (`CSV::Row` is accepted).
- # @param person_parser [Common::People::PersonParser] parser/serializer of person attributes (it contains a set of attribute parsers).
- # @param attr_map [Eco::Data::Mapper] mapper to translate attribute names from _external_ to _internal_ names and _vice versa_.
- # @param dependencies [Hash] hash where _keys_ are internal attribute names. It is mostly used to deliver final dependencies to attribute parsers/serializers.
- # @param logger [Common::Session::Logger, ::Logger] object to manage logs.
+ # @param data [Hash, Ecoportal::API::V1::Person] `Person` object
+ # to be serialized or hashed entry (`CSV::Row` is accepted).
+ # @param person_parser [Common::People::PersonParser] parser/serializer
+ # of person attributes (it contains a set of attribute parsers).
+ # @param attr_map [Eco::Data::Mapper] mapper to translate attribute
+ # names from _external_ to _internal_ names and _vice versa_.
+ # @param dependencies [Hash] hash where _keys_ are internal attribute
+ # names. It is mostly used to deliver final dependencies
+ # to attribute parsers/serializers.
+ # @param logger [Common::Session::Logger, ::Logger] object to managelogs.
def initialize(data, person_parser:, attr_map:, dependencies: {}, 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)
+ msg = "Constructor needs a PersonParser. Given: #{person_parser.class}"
+ raise msg unless person_parser.is_a?(Eco::API::Common::People::PersonParser)
- @source = data
- @person_parser = person_parser
- @deps = dependencies
- @logger = logger
- @attr_map = attr_map
- @emap = PersonEntryAttributeMapper.new(@source, person_parser: @person_parser, attr_map: @attr_map, logger: @logger)
+ msg = "Expecting Mapper object. Given: #{attr_map.class}"
+ raise msg if attr_map && !attr_map.is_a?(Eco::Data::Mapper)
+ @source = data
+ @person_parser = person_parser
+ @deps = dependencies
+ @logger = logger
+ @attr_map = attr_map
+ @emap = PersonEntryAttributeMapper.new(
+ @source,
+ person_parser: @person_parser,
+ attr_map: @attr_map,
+ logger: @logger
+ )
+
if parsing?
@external_entry = __external_entry(data)
@mapped_entry = __mapped_entry(@external_entry)
@internal_entry = __internal_entry(@mapped_entry)
@final_entry = __final_entry(@internal_entry)
@@ -37,39 +50,45 @@
@internal_entry = __internal_entry(@final_entry)
@mapped_entry = __mapped_entry(@internal_entry)
@external_entry = __external_entry(@mapped_entry)
end
- (print_models; exit(1)) if DEBUG
+ (print_models; exit(1)) if DEBUG # rubocop:disable Style/Semicolon
end
# Generates a new entry
# @return [PersonEntry]
def new(data)
- self.class.new(data, person_parser: @person_parser, attr_map: @attr_map, dependencies: @deps, logger: @logger)
+ self.class.new(
+ data,
+ person_parser: @person_parser,
+ attr_map: @attr_map,
+ dependencies: @deps,
+ logger: @logger
+ )
end
# @note completely serialized entry.
# @return [Hash] entry `Hash` with **external** attribute names, and values and types thereof.
- def external_entry
+ def external_entry # rubocop:disable Style/TrivialAccessors
@external_entry
end
# @note just one step away from being completely parsed (only types parsing pending).
# @return [Hash] entry `Hash` with **internal** attribute names and values, but **external** types.
- def internal_entry
+ def internal_entry # rubocop:disable Style/TrivialAccessors
@internal_entry
end
# @return [Hash] entry `Hash` with **internal** attribute names, but **external** types and values.
- def mapped_entry
+ def mapped_entry # rubocop:disable Style/TrivialAccessors
@mapped_entry
end
# @note values ready to be set to a person.
# @return [Hash] entry `Hash` with **internal** attribute names, values and types.
- def final_entry
+ def final_entry # rubocop:disable Style/TrivialAccessors
@final_entry
end
# To know if currently the object is in parse or serialize mode.
# @return [Boolean] returns `true` if we are **parsing**, `false` otherwise.
@@ -171,12 +190,11 @@
# Provides a reference of this person entry.
# @return [String] string summary of this person identity.
def to_s(options)
options = into_a(options)
- case
- when options.include?(:identify)
+ if options.include?(:identify)
identify
else
final_entry.each.map do |k, v|
"'#{k}': '#{v.to_json}'"
end.join(" | ")
@@ -191,30 +209,25 @@
# @param person [Ecoportal::API::V1::Person] the person we want to set the core values to.
# @param exclude [String, Array<String>] core attributes that should not be set/changed to the person.
def set_core(person, exclude: nil)
scoped_attrs = @emap.core_attrs(@final_entry) - into_a(exclude)
@final_entry.slice(*scoped_attrs).each do |attr, value|
- begin
- set_part(person, attr, value)
- rescue Exception => e
- if attr == "email"
- logger.error(e.to_s + " - setting blank email instead.")
- set_part(person, attr, nil)
- else
- raise
- end
- end
+ set_part(person, attr, value)
+ rescue StandardError => e
+ raise unless attr == "email"
+ logger.error("#{e} - setting blank email instead.")
+ set_part(person, attr, nil)
end
end
# Setter to fill in the `account` properties of the `Person` that are present in the `Entry`.
# @note it only sets those account properties defined in the entry.
# Meaning that if an account property is not present in the entry, this will not be set on the target person.
# @param person [Ecoportal::API::Internal::Person] the person we want to set the account values to.
# @param exclude [String, Array<String>] account properties that should not be set/changed to the person.
def set_account(person, exclude: nil)
- person.account = {} if !person.account
+ person.account = {} unless person.account
scoped_attrs = @emap.account_attrs(@final_entry) - into_a(exclude)
@final_entry.slice(*scoped_attrs).each do |attr, value|
set_part(person.account, attr, value)
end
end
@@ -314,26 +327,27 @@
final_entry = final_entry.merge(_serialize_values(final_entry, :final))
core_account = @person_parser.target_attrs_account + @person_parser.target_attrs_core
core_account_hash = core_account.reduce({}) do |hash, attr|
hash.merge(hash_attr(attr, _serialize_type(attr, final_entry[attr])))
end
- details_hash = @person_parser.target_attrs_details.reduce({}) do |hash, attr|
+ details_hash = @person_parser.target_attrs_details.reduce({}) do |hash, attr|
hash.merge(hash_attr(attr, _serialize_type(attr, final_entry[attr], schema: @person_parser.schema)))
end
merging(core_account_hash, details_hash) do |internal_entry|
merge_missing_attrs(internal_entry, final_entry)
end
end
# Parsing helper where attributes with custom parsers are already parsed, but
# it finishes to parse the types (i.e. to `Array` if `multiple`)
- # @param internal_entry [Hash] the entry with the **internal** _attribute_ names and values but the **external** types.
+ # @param internal_entry [Hash] the entry with the **internal** _attribute_ names and values
+ # but the **external** types.
# @return [Hash] the `parsed entry` with the **internal** final attributes names, values and types.
def _final_parsing(internal_entry)
core_account_attrs = @emap.account_attrs(internal_entry) + @emap.core_attrs(internal_entry)
core_account_hash = internal_entry.slice(*core_account_attrs).each_with_object({}) do |(attr, value), hash|
- hash[attr] = _parse_type(attr, value)
+ hash[attr] = _parse_type(attr, value)
end
details_attrs = @emap.details_attrs(internal_entry)
details_hash = internal_entry.slice(*details_attrs).each_with_object({}) do |(attr, value), hash|
hash[attr] = _parse_type(attr, value, schema: @person_parser.schema)
@@ -352,21 +366,21 @@
# - to keep things consistent, the `internal entry` hash has keys in this order:
# - `core`, `account`, `details`.
# @param person [Ecoportal::API::V1::Person] the `Person` object to transform into a _parsed entry_.
# @return [Hash] the `parsed entry` with the **internal** attributes names and internal typed values.
def _final_serializing(person)
- core_hash = @person_parser.target_attrs_core.reduce({}) do |hash, attr|
+ core_hash = @person_parser.target_attrs_core.reduce({}) do |hash, attr|
hash.merge(hash_attr(attr, get_part(person, attr)))
end
account_hash = @person_parser.target_attrs_account.reduce({}) do |hash, attr|
hash.merge(hash_attr(attr, get_part(person.account, attr)))
end
details_hash = @person_parser.target_attrs_details.reduce({}) do |hash, attr|
hash.merge(hash_attr(attr, get_part(person.details, attr)))
end
merging(core_hash, account_hash, details_hash) do |final_entry|
- final_entry["Has account?"] = !!person.account
+ final_entry["Has account?"] = !person.account.nil?
final_entry.merge(_serialize_values(person, :person))
end
end
# HELPERS
@@ -385,82 +399,80 @@
end
end
# Transforms each **typed** value into its `String` version
def _serialize_type(attr, value, schema: nil)
- case
- when !!schema
- unless field = schema[attr]
+ if !!schema
+ unless (field = schema[attr])
fatal("Field '#{attr}' does not exist in details of schema: '#{schema.name}'")
end
value = @person_parser.serialize(:multiple, value) if field.multiple
if @person_parser.defined?(field.type.to_sym)
value = @person_parser.serialize(field.type.to_sym, value, deps: {"attr" => attr})
end
value
- when ["policy_group_ids", "filter_tags", "login_provider_ids", "starred_ids"].include?(attr)
+ elsif %w[policy_group_ids filter_tags login_provider_ids starred_ids].include?(attr)
@person_parser.serialize(:multiple, value)
- when ["freemium", "accept_eula"].include?(attr)
+ elsif %w[freemium accept_eula].include?(attr)
@person_parser.serialize(:boolean, value)
- when ["subordinates"].include?(attr)
+ elsif ["subordinates"].include?(attr)
@person_parser.serialize(:number, value)
else
value
end
end
# Transforms each `String` value into its **typed** version
- def _parse_type(attr, value, schema: nil)
+ def _parse_type(attr, value, schema: nil) # rubocop:disable Metrics/AbcSize
value = value.strip if value.is_a?(String)
value = nil if value.to_s.strip.empty?
- case
- when !!schema
- unless field = schema[attr]
+ if !!schema
+ unless (field = schema[attr])
fatal("Field '#{attr}' does not exist in details of schema: '#{schema.name}'")
end
value = @person_parser.parse(:multiple, value) if field.multiple
if @person_parser.defined?(field.type.to_sym)
value = @person_parser.parse(field.type.to_sym, value, deps: {"attr" => attr})
end
value
- when attr == "email"
+ elsif attr == "email"
value = value.strip.downcase if value
value
- when ["policy_group_ids", "filter_tags", "login_provider_ids", "starred_ids"].include?(attr)
+ elsif %w[policy_group_ids filter_tags login_provider_ids starred_ids].include?(attr)
value = @person_parser.parse(:multiple, value)
- value = (attr == "filter_tags")? value.compact.map(&:upcase) : value
+ value = value.compact.map(&:upcase) if attr == "filter_tags"
value
- when ["freemium", "accept_eula"].include?(attr)
+ elsif %w[freemium accept_eula].include?(attr)
@person_parser.parse(:boolean, value)
- when ["subordinates"].include?(attr)
+ elsif ["subordinates"].include?(attr)
@person_parser.parse(:number, value)
else
value
end
end
# Merges multiple hashes giving overriding perference to the first ones.
# @return [Hash] with well sorted keys, as they came in the order of the input hashes.
def merging(*hashes)
- sorted_keys = hashes.map {|h| h.keys}.flatten.uniq
+ sorted_keys = hashes.map(&:keys).flatten.uniq
rev_hash = hashes.reverse.each_with_object({}) {|h, out| out.merge!(h)}
merged = sorted_keys.each_with_object({}) do |k, h|
h[k] = rev_hash[k]
end
- merged = yield(merged) if block_given?
+ merged = yield(merged) if block_given?
merged
end
# Adds to `dest_entry` the `keys` it misses from `source_entry`
def merge_missing_attrs(dest_entry, source_entry)
keys_rest = source_entry.keys - dest_entry.keys
dest_entry.merge(source_entry.slice(*keys_rest))
end
def into_a(value)
- value = [] if value == nil
+ value = [] if value.nil?
value = [].push(value) unless value.is_a?(Array)
value
end
def get_part(obj, attr)
@@ -476,24 +488,23 @@
end
end
def set_part(obj, attr, value)
return unless obj
- begin
- case obj
- when Ecoportal::API::V1::PersonDetails
- unless field = obj.get_field(attr)
- fatal("Field '#{attr}' does not exist in details of schema: '#{obj.schema_id}'")
- end
- obj[attr] = value
- else
- obj.send("#{attr}=", value)
- end
- rescue Exception => e
- # add more info to the error
- raise e.append_message " -- Entry #{to_s(:identify)}"
+
+ case obj
+ when Ecoportal::API::V1::PersonDetails
+ msg = "Field '#{attr}' does not exist in details of schema: '#{obj.schema_id}'"
+ fatal msg unless obj.get_field(attr)
+
+ obj[attr] = value
+ else
+ obj.send("#{attr}=", value)
end
+ rescue StandardError => e
+ # add more info to the error
+ raise e.append_message " -- Entry #{to_s(:identify)}"
end
# @return [Hash] `value` if it was a `Hash`, and `{ attr => value}` otherwise
def hash_attr(attr, value)
return value if value.is_a?(Hash)
@@ -510,22 +521,22 @@
raise msg
end
# Function to debug faste
def print_models
- print_it = Proc.new do |name, model|
+ print_it = proc do |name, model|
puts "#{name}:"
pp model
puts "*" * 30
end
- fin = Proc.new {|x_| print_it.call("final_entry", @final_entry) }
- int = Proc.new {|x_| print_it.call("internal_entry", @internal_entry) }
- mad = Proc.new {|x_| print_it.call("mapped_entry", @mapped_entry) }
- ext = Proc.new {|x_| print_it.call("external_entry", @external_entry) }
+ fin = proc { print_it.call("final_entry", @final_entry) }
+ int = proc { print_it.call("internal_entry", @internal_entry) }
+ mad = proc { print_it.call("mapped_entry", @mapped_entry) }
+ ext = proc { print_it.call("external_entry", @external_entry) }
call_order = parsing? ? [ext, mad, int, fin] : [fin, int, mad, ext]
- call_order.each {|proc| proc.call}
+ call_order.each(&:call)
end
end
end
end
end