buren/honey_format

View on GitHub
lib/honey_format/converters/header_column_converter.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module HoneyFormat
  # Header column converter
  module HeaderColumnConverter
    # Bracket character matcher
    BRACKETS = /\(|\[|\{|\)|\]|\}/.freeze

    # Separator characters
    SEPS = /'|"|\||\*|\^|\&|%|\$|€|£|#/.freeze

    # Space characters
    SPACES = /[[:space:]]+/.freeze

    # Non-printable characters
    NON_PRINT = /[^[:print:]]/.freeze

    # zero-width characters - see https://stackoverflow.com/q/50647999
    ZERO_WIDTH = /[\u200B-\u200D\uFEFF]/.freeze

    # Replace map
    REPLACE_MAP = [
      [/\\/, '/'],       # replace "\" with "/"
      [/ \(/, '('],      # replace " (" with "("
      [/ \[/, '['],      # replace " [" with "["
      [/ \{/, '{'],      # replace " {" with "{"
      [/ \{/, '{'],      # replace " {" with "{"
      [/\) /, ')'],      # replace ") " with ")"
      [/\] /, ']'],      # replace "] " with "]"
      [/\} /, '}'],      # replace "} " with "}"
      [/@/, '_at_'],     # replace "@' with "_at_"
      [BRACKETS, '_'],   # replace (, [, {, ), ] and } with "_"
      [SPACES, '_'],     # replace one or more space chars with "_"
      [/-/, '_'],        # replace "-" with "_"
      [/\.|,/, '_'],     # replace "." and "," with "_"
      [/::/, '_'],       # replace "::" with "_"
      [%r{/}, '_'],      # replace "/" with "_"
      [SEPS, '_'],       # replace separator chars with "_"
      [/_+/, '_'],       # replace one or more "_" with single "_"
      [NON_PRINT, ''],   # remove non-printable characters
      [ZERO_WIDTH, ''],  # remove zero-width characters
      [/\A_+/, ''],      # remove leading "_"
      [/_+\z/, ''],      # remove trailing "_"
    ].map { |e| e.map(&:freeze).freeze }.freeze

    # Returns converted value and mutates the argument.
    # @return [Symbol] the cleaned header column.
    # @param [String, Symbol] column the string to be cleaned.
    # @param [Integer] index the column index.
    # @example Convert simple header
    #     HeaderColumnConverter.call("  User name ") #=> "user_name"
    # @example Convert complex header
    #     HeaderColumnConverter.call(" First name (user)") #=> :'first_name(user)'
    def self.call(column, index = nil)
      if column.nil? || column.empty?
        raise(ArgumentError, "column and column index can't be blank/nil") unless index

        return :"column#{index}"
      end

      column = column.to_s.dup
      column.strip!
      column.downcase!
      REPLACE_MAP.each do |data|
        from, to = data
        column.gsub!(from, to)
      end
      column.to_sym
    end
  end
end