lib/eco/api/common/people/entry_factory.rb in eco-helpers-2.6.4 vs lib/eco/api/common/people/entry_factory.rb in eco-helpers-2.7.0

- old
+ new

@@ -1,28 +1,42 @@ module Eco module API module Common module People - # TODO: EntryFactory should suppport multiple schemas itself (rather that being done on `Session`) - # => currently, it's through session.entry_factory(schema: id), but this is wrong - # => This way, Entries and PersonEntry will be able to refer to attr_map and person_parser linked to schema_id - # => "schema_id" should be an optional column in the input file, or parsable via a custom parser to scope the schema + # TODO: EntryFactory should suppport multiple schemas itself + # (rather that being done on `Session`) + # => currently, it's through session.entry_factory(schema: id), + # but this is wrong + # => This way, Entries and PersonEntry will be able to refer to attr_map + # and person_parser linked to schema_id + # => "schema_id" should be an optional column in the input file, + # or parsable via a custom parser to scope the schema # Helper factory class to generate entries (input entries). - # @attr_reader schema [Ecoportal::API::V1::PersonSchema] person schema to be used in this entry factory + # @attr_reader schema [Ecoportal::API::V1::PersonSchema] person schema to + # be used in this entry factory class EntryFactory < Eco::API::Common::Session::BaseSession include Eco::Data::Files - attr_reader :schema, :person_parser + attr_reader :schema - # @param e [Eco::API::Common::Session::Environment] requires a session environment, as any child of `Eco::API::Common::Session::BaseSession` - # @param schema [Ecoportal::API::V1::PersonSchema] schema of person details that the parser will be based upon. - # @param person_parser [nil, Eco::API::Common::People::PersonParser] set of attribute, type and format parsers/serializers. - # @param attr_map [nil, Eco::Data::Mapper] attribute names mapper to translate external names into internal ones and _vice versa_. + # @param e [Eco::API::Common::Session::Environment] requires a session environment, + # as any child of `Eco::API::Common::Session::BaseSession` + # @param schema [Ecoportal::API::V1::PersonSchema] schema of person details that + # the parser will be based upon. + # @param person_parser [nil, Eco::API::Common::People::PersonParser] + # set of attribute, type and format parsers/serializers. + # @param attr_map [nil, Eco::Data::Mapper] attribute names mapper + # to translate external names into internal ones and _vice versa_. def initialize(e, schema:, person_parser: nil, default_parser: nil, attr_map: nil) - fatal "Constructor needs a PersonSchema. Given: #{schema}" if !schema.is_a?(Ecoportal::API::V1::PersonSchema) - fatal "Expecting PersonParser. Given: #{person_parser}" if person_parser && !person_parser.is_a?(Eco::API::Common::People::PersonParser) - fatal "Expecting Mapper object. Given: #{fields_mapper}" if attr_map && !attr_map.is_a?(Eco::Data::Mapper) + msg = "Constructor needs a PersonSchema. Given: #{schema.class}" + fatal msg unless schema.is_a?(Ecoportal::API::V1::PersonSchema) + + msg = "Expecting PersonParser. Given: #{person_parser.class}" + fatal msg if person_parser && !person_parser.is_a?(Eco::API::Common::People::PersonParser) + + msg = "Expecting Mapper object. Given: #{attr_map.class}" + fatal msg if attr_map && !attr_map.is_a?(Eco::Data::Mapper) super(e) @schema = Ecoportal::API::V1::PersonSchema.new(JSON.parse(schema.doc.to_json)) @source_person_parser = person_parser @@ -33,21 +47,20 @@ @person_parser = @source_person_parser.new(schema: @schema).merge(base_parser) @person_parser_patch_version = @source_person_parser.patch_version @attr_map = attr_map end - def newFactory(schema: nil) + def newFactory(schema: nil) # rubocop:disable Naming/MethodName self.class.new( environment, - schema: schema, - person_parser: @source_person_parser, + schema: schema, + person_parser: @source_person_parser, default_parser: @default_parser, - attr_map: @attr_map + attr_map: @attr_map ) end - # provides with a Eco::API::Common::People::PersonParser object (collection of attribute parsers) # @note if the custom person parser has changed, it updates the copy of this EntryFactory instance # @return [Eco::API::Common::People::PersonParser] set of attribute, type and format parsers/serializers. def person_parser if @person_parser_patch_version < @source_person_parser.patch_version @@ -55,13 +68,16 @@ @person_parser_patch_version = @source_person_parser.patch_version end @person_parser end - # key method to generate objects of `PersonEntry` that share dependencies via this `EntryFactory` environment. - # @note this method is necessary to make the factory object work as a if it was a class `PersonEntry` you can call `new` on. - # @param data [Hash, Person] data to be parsed/serialized. Parsed: the external hashed entry. Serialized: a Person object. + # key method to generate objects of `PersonEntry` that share dependencies + # via this `EntryFactory` environment. + # @note this method is necessary to make the factory object work + # as a if it was a class `PersonEntry` you can call `new` on. + # @param data [Hash, Person] data to be parsed/serialized. + # Parsed: the external hashed entry. Serialized: a Person object. # @return [Eco::API::Common::People::PersonEntry] def new(data, dependencies: {}) PersonEntry.new( data, person_parser: person_parser, @@ -69,11 +85,12 @@ dependencies: dependencies, logger: logger ) end - # Helper that provides a collection of `Entries`, which in turn provides with further helpers to find and exclude entries. + # Helper that provides a collection of `Entries`, which in turn provides + # with further helpers to find and exclude entries. # It accepts a `file:` and `format:` or `data:` but not both options together. # @raise Exception # - if you try to provide `data:` and `file:` at the same time. # - if you provide `file:` but omit `format:`. # - if the `format:` you provide is not a `Symbol`. @@ -83,25 +100,31 @@ # @param format [Symbol] it must be used when you use the option `file:` (i.e. `:xml`, `:csv`), as it specifies the format of the input `file:`. # @param options [Hash] further options. # @option options [String] :encoding optional parameter to read `file:` by expecting certain encoding. # @option options [Boolean] :check_headers signals if the `csv` file headers should be expected. # @return [Eco::API::Common::People::Entries] collection of `Eco::API::Common::People::PersonEntry`. - def entries(data: (no_data = true; nil), file: (no_file = true; nil), format: (no_format = true; nil), **options) - fatal("You should at least use data: or file:, but not both") if no_data == no_file - fatal("You must specify a valid format: (symbol) when you use file.") if file && no_format - fatal("Format should be a Symbol. Given '#{format}'") if format && !format.is_a?(Symbol) - fatal("There is no parser/serializer for format ':#{format.to_s}'") unless no_format || @person_parser.defined?(format) + def entries(data: (no_data = true; nil), file: (no_file = true; nil), format: (no_format = true; nil), **options) # rubocop:disable Style/Semicolon + msg = "You should at least use data: or file:, but not both" + fatal msg if no_data == no_file + msg = "You must specify a valid format: (symbol) when you use file." + fatal msg if file && no_format + + msg = "Format should be a Symbol. Given '#{format}'" + fatal msg if format && !format.is_a?(Symbol) + + msg = "There is no parser/serializer for format ':#{format}'" + fatal msg unless no_format || @person_parser.defined?(format) + options.merge!(content: data) unless no_data options.merge!(file: file) unless no_file options.merge!(format: format) unless no_format Entries.new(to_array_of_hashes(**options), klass: PersonEntry, factory: self) end - def to_array_of_hashes(**kargs) - data = [] + def to_array_of_hashes(**kargs) # rubocop:disable Metrics/AbcSize content, file, encoding, format = kargs.values_at(:content, :file, :encoding, :format) # Support for multiple file if file.is_a?(Array) return file.each_with_object([]) do |f, out| @@ -110,11 +133,11 @@ out.concat(curr) end end # Get content only when it's not :xls # note: even if content was provided, file takes precedence - if (format != :xls) && file + if (format != :xls) && file # rubocop:disable Style/IfUnlessModifier content = get_file_content(file, encoding: encoding) end case content when Hash @@ -154,37 +177,45 @@ # - if you `file:` is empty. # - if the `format:` you provide is not a `Symbol`. # - if there is no _parser/serializer_ defined for `format:`. # @param data [Eco::API::Organization::People] data to be parsed. # @param file [String] absolute or relative path to the ouput file. - # @param format [Symbol] it specifies the format of the output `file:` (i.e. `:xml`, `:csv`). There must be a parser/serializer defined for it. + # @param format [Symbol] it specifies the format of the output `file:` (i.e. `:xml`, `:csv`). + # There must be a parser/serializer defined for it. # @param encoding [String] optional parameter to geneate `file:` content by unsing certain encoding. # @return [Void]. def export(data:, file: "export", format: :csv, encoding: "utf-8", internal_names: false) - fatal("data: Expected Eco::API::Organization::People object. Given: #{data.class}") unless data.is_a?(Eco::API::Organization::People) - fatal("A file should be specified.") unless !file.to_s.strip.empty? - fatal("Format should be a Symbol. Given '#{format}'") if format && !format.is_a?(Symbol) - fatal("There is no parser/serializer for format ':#{format.to_s}'") unless @person_parser.defined?(format) + msg = "data: Expected Eco::API::Organization::People object. Given: #{data.class}" + fatal msg unless data.is_a?(Eco::API::Organization::People) + fatal "A file should be specified." if file.to_s.strip.empty? + fatal "Format should be a Symbol. Given '#{format}'" if format && !format.is_a?(Symbol) + + msg = "There is no parser/serializer for format ':#{format}'" + fatal msg unless @person_parser.defined?(format) + run = true if self.class.file_exists?(file) - prompt_user("Do you want to overwrite it? (Y/n):", explanation: "The file '#{file}' already exists.", default: "Y") do |response| + prompt_user( + "Do you want to overwrite it? (Y/n):", + explanation: "The file '#{file}' already exists.", + default: "Y" + ) do |response| run = (response == "") || response.upcase.start_with?("Y") end end - if run - deps = {"supervisor_id" => {people: data}} + return unless run - data_entries = data.map do |person| - self.new(person, dependencies: deps).yield_self do |entry| - internal_names ? entry.mapped_entry : entry.external_entry - end + deps = {"supervisor_id" => {people: data}} + data_entries = data.map do |person| + new(person, dependencies: deps).then do |entry| + internal_names ? entry.mapped_entry : entry.external_entry end + end - File.open(file, "w", enconding: encoding) do |fd| - fd.write(person_parser.serialize(format, data_entries)) - end + File.open(file, "w", enconding: encoding) do |fd| + fd.write(person_parser.serialize(format, data_entries)) end end private