maxim/menu_txt

View on GitHub
lib/menu_txt.rb

Summary

Maintainability
A
45 mins
Test Coverage
require 'menu_txt/version'
require 'menu_txt/node'
require 'menu_txt/simple_node'

module MenuTxt
  module_function

  LINE_REGEXP = /\A(-*)\s*([^\|]+)\s*\|\s*(.+)\Z/.freeze
  BLANK_REGEXP = /\A[[:space:]]*\z/.freeze

  def parse_path(path, root = SimpleNode.new(nil))
    File.open(path, 'r') { |file| parse(file, root) }
  end

  def parse(io, root = SimpleNode.new(nil))
    current_node = root

    io.each_line do |line|
      next if BLANK_REGEXP === line
      indent, name, url = line.match(LINE_REGEXP).captures.map(&:strip)
      current_node_indent_size = current_node.level + 1

      if (indent.size - current_node_indent_size) > 1
        raise "Can only nest submenus 1 level at a time: (#{line})"
      elsif indent.size > current_node_indent_size
        current_node = current_node.children.last
        current_node.add_child(name, url)
      elsif indent.size < current_node_indent_size
        unindents_count = current_node_indent_size - indent.size
        unindents_count.times { current_node = current_node.parent }
        current_node.add_child(name, url)
      else
        current_node.add_child(name, url)
      end
    end

    root
  end
end