evidanary/grepg

View on GitHub
lib/grepg/parser.rb

Summary

Maintainability
B
5 hrs
Test Coverage
require 'trollop'
require 'rest-client'
require 'yaml'

# This class parses commandline arguments
module GrepPage
  class Parser
    def initialize(args)
      default_config = self.class.get_default_config
      parser = Trollop::Parser.new do
        opt :user,
          "username",
          :type => :string,
          :default => default_config['user'],
          :short => "-u"
        opt :topic,
          "topic",
          :type => :string,
          :required => false,
          :short => "-t"
        opt :search,
          "text to search",
          :type => :string,
          :required => false,
          :short => "-s"
        opt :search_operator,
          "One of: OR, AND",
          :type => :string,
          :default => default_config['search_operator'],
          :short => "-o"
        opt :colorize,
          "colorize output",
          :type => :boolean,
          :default => default_config['colorize'],
          :short => "-c"
        version "grepg version #{GrepPage::VERSION}"
        banner <<-EOS

Usage:
  grepg -u user_name [-t topic_name -s search_term]

Examples:
  grepg -u evidanary -t css
  greppg -u evidanary -t css -s color

Defaults:
  To set defaults, create a file in ~/.grepg.yml with
  user: test
  colorize: true
        EOS
      end

      @opts = Trollop::with_standard_exception_handling parser do
        opts = parser.parse args
        # User is a required field, manually handling validation because
        # we fallback on defaults from the file
        raise Trollop::CommandlineError,
          "Missing --user parameter. e.g. --user evidanary" unless opts[:user]
        opts
      end

      @user = @opts[:user]
      @topic = @opts[:topic]
      @search_term = @opts[:search]
      @search_operator = (@opts[:search_operator] || "and").upcase.to_sym
      @colorize = @opts[:colorize].nil? ? true : @opts[:colorize]
    end

    def self.get_default_config
      file = self.default_file_name
      file ? YAML.load(IO.read(file)) : {}
    end

    def self.default_file_name
      file = ENV['HOME'] + '/.grepg.yml'
      File.exist?(file) ? file : nil
    end

    def get_all_topics(user)
      GrepPage::API.sheets(user)
    end

    def filter_topics(topics, topic_name = '')
      sheet = topics.find{|topic| topic[:name].downcase == topic_name.downcase}
      sheet = topics.find{|topic| topic[:name].downcase[topic_name.downcase]} unless sheet
      sheet
    end

    def get_cheats(user, sheet_id)
      GrepPage::API.cheats(user, sheet_id)
    end

    def filter_cheats(cheats, search_term, search_operator)
      cheats.select do |cheat|
        search_term.split(' ').map do |token|
          text_to_search = [ cheat[:description],
                             cheat[:command]
          ].join(' ').downcase
          text_to_search.include? token.downcase
        end.reduce {|a,b| search_operator == :AND ? a && b : a || b}
      end
    end

    def process_args
      headers = ["User: #{@user}"]
      headers << "Topic: #{@topic}" if @topic
      if(@search_term)
        label = "Search-Term: #{@search_term}"
        label += "(#{@search_operator})" if @search_term.split(' ').count > 1
        headers << label
      end
      puts headers.join(", ")

      begin
        topics = get_all_topics(@user)
      rescue RestClient::ResourceNotFound
        raise GrepPage::NotFoundError, "Unable to find user"
      end

      unless @topic
        # No topic specified so show all topics
        puts "Available Topics => "
        puts topics.map{|t| t[:name]}
        return
      end

      topic = filter_topics(topics, @topic)
      if topic.nil? || topic.empty?
        puts "Can't find that topic. Choose one of the following"
        puts topics.map{|t| t[:name]}
        raise GrepPage::NotFoundError, "Unable to find topic"
      end

      cheats = get_cheats(@user, topic[:id])
      cheats = filter_cheats(cheats, @search_term, @search_operator) if @search_term

      GrepPage::Formatter.cheat_rows(cheats, @search_term, @colorize)
    end

    def run!
      begin
        process_args
      rescue GrepPage::NotFoundError => ex
        abort "Error: #{ex.message}"
      end
    end
  end
end