class VipnetParser::Struct

Constants

DEFAULT_PARSE_ARGS

Attributes

hash[RW]
string[RW]

Public Instance Methods

parse(args = DEFAULT_PARSE_ARGS) click to toggle source
# File lib/vipnet_parser/struct.rb, line 12
def parse(args = DEFAULT_PARSE_ARGS)
  args = DEFAULT_PARSE_ARGS.merge(args)
  format, encoding = args.values_at(
    :format, :encoding, :normalize_names,
  )

  # Change encoding to utf8.
  string = self.string
    .force_encoding(encoding)
    .encode("utf-8", replace: nil)

  sign_aliases = { "+" => true, "-" => false }

  case format
  when :hash
    @hash = { nodes: [] }

    current_node_id = nil
    previous_node = nil
    current_usergroups = []
    current_users = []
    lines = string.split("\r\n")
    lines.each_with_index do |line, line_index|
      line_hash = _line_hash(line)
      next unless line_hash

      # Normalize data.
      line_hash.each do |_, higher_name_hash|
        next unless higher_name_hash.class == Hash

        parsed_ids = VipnetParser.id(higher_name_hash[:id])
        id =
          if parsed_ids.size > 0
            parsed_ids.first
          else
            nil
          end
        higher_name_hash[:id] = id

        higher_name_hash[:name].rstrip!
        if higher_name_hash[:name].size == 0
          higher_name_hash[:name] = nil
        end
      end
      line_hash[:node][:network_address].rstrip!
      line_hash[:user][:sign] = sign_aliases[line_hash[:user][:sign]]
      line_hash[:usergroup] = nil if (!line_hash[:usergroup][:id] && !line_hash[:usergroup][:name])

      # first id
      if !current_node_id && line_hash[:node][:id]
        current_node_id = line_hash[:node][:id]
      end

      # initial previous node
      if !previous_node
        previous_node = line_hash[:node]
      end

      next_node_appears = (line_hash[:node][:id] && current_node_id != line_hash[:node][:id])
      this_is_the_last_line = (line_index == lines.size - 1)

      if this_is_the_last_line
        current_usergroups.push(line_hash[:usergroup]) if line_hash[:usergroup]
        current_users.push(line_hash[:user])
      end

      if next_node_appears || this_is_the_last_line
        final_hash = previous_node
        final_hash[:usergroups] = current_usergroups.dup
        final_hash[:users] = current_users.dup
        @hash[:nodes].push(final_hash)
      end

      if next_node_appears
        current_node_id = line_hash[:node][:id]
        previous_node = line_hash[:node]
        current_usergroups = []
        current_users = []
      end

      current_usergroups.push(line_hash[:usergroup]) if line_hash[:usergroup]
      current_users.push(line_hash[:user])
    end

    @hash
  end
end

Private Instance Methods

_line_hash(line) click to toggle source
# File lib/vipnet_parser/struct.rb, line 100
def _line_hash(line)
  # NOTE: could be done without regexp, but it seems easier with.
  line_regexp = /^
    (?<node>.{#{15 + 1 + 50 + 1 + 8}})│
    (?<usergroup>.{#{50 + 1 + 8}})│
    (?<user>.{#{56 + 1 + 8 + 1 + 1}})
  $/x
  node_regexp = /(?<network_address>.{15})│(?<name>.{50})│(?<id>.{8})/
  usergroup_regexp = /(?<name>.{50})│(?<id>.{8})/
  user_regexp = /(?<name>.{56})│(?<id>.{8})│(?<sign>.{1})/
  regexps_map = {
    node: node_regexp,
    usergroup: usergroup_regexp,
    user: user_regexp,
  }

  line_match = line_regexp.match(line)
  return unless line_match
  line_names = line_match.names.map { |name| name.to_sym }
  line_hash = Hash[line_names.zip(line_match.captures)]

  hash = {}
  regexps_map.each do |higher_name_component, regexp|
    match = regexp.match(line_hash[higher_name_component])
    next unless match
    names = match.names.map { |name| name.to_sym }
    higher_name_hash = Hash[names.zip(match.captures)]

    hash[higher_name_component] = higher_name_hash
  end

  hash
end