<commit_before># encoding: utf-8

require "nori"

module RySafe::Import
  class KeePassXImporter < Importer
    def import
      root.each { |child| GroupNode.new(child, nil).import }
    end

    private

    def root
      file_to_hash[:database][:group]
    end

    def file_to_hash
      parser = Nori.new(:convert_tags_to => lambda { |tag| tag.snakecase.to_sym })
      parser.parse(file_content)
    end
  end

  GroupNode = Struct.new(:hash, :parent) do
    def import
      convert
      import_groups(to_array(hash[:group])) if hash[:group]
      import_entries(to_array(hash[:entry])) if hash[:entry]
    end

    def import_entries(entries)
      entries.each do |entry|
        node = EntryNode.new(entry, convert)
        node.to_entry.convert
      end
    end

    def import_groups(groups)
      groups.each do |group|
        node = GroupNode.new(group, convert)
        node.import
      end
    end

    def to_group
      Group.new(hash[:title], parent)
    end

    private

    def convert
      @converted ||= to_group.convert
    end

    def to_array(array_or_hash)
      array_or_hash.is_a?(Array) ? array_or_hash : [array_or_hash]
    end
  end

  EntryNode = Struct.new(:hash, :parent) do
    def to_entry
      Entry.new(hash[:title], hash[:username], hash[:password], hash[:url], hash[:comment], hash[:creation], hash[:lastaccess], hash[:lastmod], hash[:expire], parent)
    end
  end

  module ConvertionHelper
    module_function

    def try_convertion(title, number = 1, &block)
      title = (title.nil? || title.to_s.strip.empty?) ? 'no_name' : title.to_s
      title = title.downcase.gsub(/ /, '_')
      new_title = [title, number == 1 ? nil : number].compact.join('_')

      node, parent = block.call(new_title)
      target = parent || Safe::Tree.root
      begin
        target << node
        node
      rescue Error::AlreadyExist => e
        try_convertion(title, number + 1, &block)
      end
    end
  end

  class Group
    attr_accessor :title, :parent
    def initialize(title, parent)
      @title = title
      @parent = parent
    end

    def convert
      ConvertionHelper.try_convertion(@title) do |new_title|
        dir = Safe::Dir.new(new_title)
        [dir, @parent]
      end
    end
  end

  class Entry
    attr_accessor :title, :username, :password, :url, :comment, :creation, :lastaccess, :lastmod, :expire, :parent
    def initialize(title, username, password, url, comment, creation, lastaccess, lastmod, expire, parent)
      @title = title
      @username = username
      @password = password
      @url = url
      @comment = comment
      @creation = creation
      @lastaccess = lastaccess
      @lastmod = lastmod
      @expire = expire
      @parent = parent
    end

    def convert
      ConvertionHelper.try_convertion(@title) do |new_title|
        entry = Safe::Entry.new(new_title)
        entry.username = @username.to_s
        entry.password = <PASSWORD>
        entry.password_confirmation = <PASSWORD>
        entry.comment = @comment.to_s
        entry.website = @url.to_s
        [entry, @parent]
      end
    end
  end
end
<commit_msg>Refactor keepassx importer<commit_after># encoding: utf-8

require "nori"

module RySafe::Import
  class KeePassXImporter < Importer
    def import
      root.each { |child| GroupNode.new(child, nil).import }
    end

    private

    def root
      file_to_hash[:database][:group]
    end

    def file_to_hash
      parser = Nori.new(:convert_tags_to => lambda { |tag| tag.snakecase.to_sym })
      parser.parse(file_content)
    end
  end

  GroupNode = Struct.new(:hash, :parent) do
    def import
      convert
      import_groups(to_array(hash[:group])) if hash[:group]
      import_entries(to_array(hash[:entry])) if hash[:entry]
    end

    def import_entries(entries)
      entries.each do |entry|
        node = EntryNode.new(entry, convert)
        node.to_entry.convert
      end
    end

    def import_groups(groups)
      groups.each do |group|
        node = GroupNode.new(group, convert)
        node.import
      end
    end

    def to_group
      Group.new(hash[:title], parent)
    end

    private

    def convert
      @converted ||= to_group.convert
    end

    def to_array(array_or_hash)
      array_or_hash.is_a?(Array) ? array_or_hash : [array_or_hash]
    end
  end

  EntryNode = Struct.new(:hash, :parent) do
    def to_entry
      Entry.new(hash[:title], hash[:username], hash[:password], hash[:url], hash[:comment], hash[:creation], hash[:lastaccess], hash[:lastmod], hash[:expire], parent)
    end
  end

  module ConvertionHelper
    module_function

    def try_convertion(title, parent, number = 1, &block)
      title = (title.nil? || title.to_s.strip.empty?) ? 'no_name' : title.to_s
      title = title.downcase.gsub(/ /, '_')
      new_title = [title, number == 1 ? nil : number].compact.join('_')

      node = block.call(new_title)
      target = parent || Safe::Tree.root
      begin
        target << node
        node
      rescue Error::AlreadyExist => e
        try_convertion(title, parent, number + 1, &block)
      end
    end
  end

  class Group
    attr_accessor :title, :parent
    def initialize(title, parent)
      @title = title
      @parent = parent
    end

    def convert
      ConvertionHelper.try_convertion(@title, @parent) do |new_title|
        Safe::Dir.new(new_title)
      end
    end
  end

  class Entry
    attr_accessor :title, :username, :password, :url, :comment, :creation, :lastaccess, :lastmod, :expire, :parent
    def initialize(title, username, password, url, comment, creation, lastaccess, lastmod, expire, parent)
      @title = title
      @username = username
      @password = password
      @url = url
      @comment = comment
      @creation = creation
      @lastaccess = lastaccess
      @lastmod = lastmod
      @expire = expire
      @parent = parent
    end

    def convert
      ConvertionHelper.try_convertion(@title, @parent) do |new_title|
        entry = Safe::Entry.new(new_title)
        entry.username = @username.to_s
        entry.password = <PASSWORD>
        entry.password_confirmation = <PASSWORD>
        entry.comment = @comment.to_s
        entry.website = @url.to_s
        entry
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.10874780105549336, 'fraction_numerical': 0.0012793858947705101, 'mean_word_length': 2.5635327635327636, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2481242', 'n_tokens_mistral': 2008, 'n_tokens_neox': 1953, 'n_words': 477}