class TaskList::Parser

Attributes

files[R]
github[R]
search_path[R]
tasks[R]

Public Class Methods

new(arguments: [], options: {}) click to toggle source
# File lib/task-list/parser.rb, line 8
def initialize(arguments: [], options: {})
  self.search_path = options[:search_path]
  @github = options[:github] if options[:github]
  @plain = options[:plain] if options[:plain]
  @type = options[:type].upcase if options[:type]
  @files = fuzzy_find_files queries: arguments
  @tasks = {}
  VALID_TASKS.each { |t| @tasks[t.to_sym] = [] }
end

Public Instance Methods

git_repo_root() click to toggle source
# File lib/task-list/parser.rb, line 74
def git_repo_root
  full_search_path = File.expand_path(self.search_path)
  root_path = full_search_path.dup
  repo_found = false

  begin
    if File.directory?(File.join(root_path, ".git"))
      repo_found = true
      break
    end

    directories = root_path.split(File::SEPARATOR)
    directories.pop
    root_path = File.join(*directories)
  end until repo_found

  unless repo_found
    # FIXME: Show an error message instead of raising an exception
    raise "No git repo found."
  end

  root_path
end
github?() click to toggle source
# File lib/task-list/parser.rb, line 98
def github?
  !!@github
end
parse!() click to toggle source

Parse all the collected files to find tasks and populate the tasks hash

# File lib/task-list/parser.rb, line 28
def parse!
  unless @type.nil? || VALID_TASKS.include?(@type)
    raise TaskList::Exceptions::InvalidTaskTypeError.new type: @type
  end

  @files.each { |f| parsef! file: f }
end
plain?() click to toggle source
# File lib/task-list/parser.rb, line 102
def plain?
  !!@plain
end
print!() click to toggle source
search_path=(value) click to toggle source
# File lib/task-list/parser.rb, line 18
def search_path=(value)
  if value.nil? || value.empty?
    @search_path = "."
  else
    @search_path = value
  end
end

Private Instance Methods

fuzzy_find_files(queries: []) click to toggle source
# File lib/task-list/parser.rb, line 108
def fuzzy_find_files(queries: [])
  patterns = regexify queries

  paths = []
  Find.find(File.expand_path(self.search_path)) do |path|
    paths << path unless FileTest.directory?(path)
  end

  paths.map! { |p| p.gsub(/\A\.\//, "") }

  EXCLUDED_DIRECTORIES.each do |d|
    paths.delete_if { |p| p =~ /\A#{Regexp.escape(d)}/ }
  end

  EXCLUDED_EXTENSIONS.each do |e|
    paths.delete_if { |p| File.file?(p) && File.extname(p) =~ /\A#{Regexp.escape(e)}/ }
  end

  EXCLUDED_GLOBS.each do |g|
    paths.delete_if { |p| p =~ /#{unglobify(g)}/ }
  end

  if queries.empty?
    paths
  else
    results = []

    patterns.each do |pattern|
      paths.each do |path|
        matches = path.match(/#{pattern}/).to_a

        results << path unless matches.empty?
      end
    end

    results
  end
end
parsef!(file: "") click to toggle source

Parse a file to find tasks

# File lib/task-list/parser.rb, line 234
def parsef!(file: "")
  types = @type ? [@type] : VALID_TASKS

  File.open(file, "r") do |f|
    line_number = 1
    while line = f.gets
      types.each do |type|
        result = line.match(/#{Regexp.escape(type)}[\s,:-]+(\S.*)\Z/) rescue nil

        unless result.nil?
          task = {
            file: file,
            line_number: line_number,
            task: result.to_a.last
          }

          @tasks[type.to_sym] << task
        end
      end

      line_number += 1
    end
  end
end
regexify(queries) click to toggle source
# File lib/task-list/parser.rb, line 147
def regexify(queries)
  patterns = []

  queries.each do |query|
    if query.include?("/")
      pattern = query.split("/").map { |p| p.split("").join(")[^\/]*?(").prepend("[^\/]*?(") + ")[^\/]*?" }.join("\/")
      pattern << "\/" if query[-1] == "/"
    else
      pattern = query.split("").join(").*?(").prepend(".*?(") + ").*?"
    end

    patterns << pattern
  end

  patterns
end
smoosh(chars) click to toggle source
# File lib/task-list/parser.rb, line 215
def smoosh(chars)
  out = []

  until chars.empty?
    char = chars.shift

    if char == "*" && chars.first == "*"
      chars.shift
      chars.shift if chars.first == "/"
      out.push("**")
    else
      out.push(char)
    end
  end

  out
end
unglobify(glob) click to toggle source

NOTE: This is actually a glob-to-regex method

# File lib/task-list/parser.rb, line 165
def unglobify(glob)
  chars = glob.split("")

  chars = smoosh(chars)

  curlies = 0
  escaping = false
  string = chars.map do |char|
    if escaping
      escaping = false
      char
    else
      case char
        when "**"
          "([^/]+/)*"
        when '*'
          ".*"
        when "?"
          "."
        when "."
          "\."

        when "{"
          curlies += 1
          "("
        when "}"
          if curlies > 0
            curlies -= 1
            ")"
          else
            char
          end
        when ","
          if curlies > 0
            "|"
          else
            char
          end
        when "\\"
          escaping = true
          "\\"
        else
          char
      end
    end
  end

  '(\A|\/)' + string.join + '\Z'
end