deliveroo/routemaster-client

View on GitHub
routemaster/cli/base.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'routemaster/cli/helper'
require 'optparse'
require 'hashie'

module Routemaster
  module CLI
    class Base
      def self.inherited(by)
        by.extend(ClassMethods)
      end

      module ClassMethods
        def prefix(ary = nil)
          @prefix ||= ary
        end

        def syntax(string = nil)
          string ? (@syntax = string) : ['rtm', *@prefix, @syntax, '[options]'].compact.join(' ')
        end

        def descr(string = nil)
          string ? (@descr = string) : @descr
        end

        def defaults(hash = nil)
          hash ? (@defaults = hash) : (@defaults || {})
        end

        def options(&block)
          block_given? ? (@options = block) : @options
        end

        def action(&block)
          block_given? ? (@action = block) : @action || lambda { |*| }
        end
      end

      def initialize(stderr:, stdout:)
        @stderr = stderr
        @stdout = stdout
      end

      def run(argv)
        @argv = argv
        _parser.parse!(@argv)
        instance_eval(&self.class.action)
      rescue Exit
        raise
      rescue StandardError => e
        log "#{e.class.name}: #{e.message}"
        if config.verbose
          e.backtrace.each { |l| log "\t#{l}" }
        end
        raise Exit, 2
      end

      protected

      def argv
        @argv || []
      end

      def config
        @config ||= Hashie::Mash.new(_default_options).merge(self.class.defaults)
      end

      def helper
        Helper.new(config)
      end

      def log(message)
        @stderr.puts(message)
      end

      def puts(message)
        @stdout.puts(message)
      end

      def usage!
        log "Usage:"
        log _parser
        raise Exit, 1
      end

      def bad_argc!
        log "Wrong number of arguments."
        usage!
      end

      private

      def _default_options
        { verbose: false }
      end

      def _parser
        @parser ||= OptionParser.new do |p|
          p.banner = self.class.syntax
          p.separator self.class.descr

          if self.class.options
            p.separator 'Options:'
            instance_exec(p, &self.class.options)
          end

          p.separator 'Common options:'

          p.on('-b', '--bus DOMAIN|@NAME', %{
            The domain name of the bus to interact with, or a reference (`NAME`)
            to global configuration.
          }) do |v|
            config.bus = v
          end

          p.on('-t', '--token TOKEN', %{
            An API token to use when querying the bus.
          }) do |v|
            config.token = v
          end

          p.on('-v', '--verbose', %{
            Increase logging verbosity
          }) do
            config.verbose = true
          end
        end
      end

      def _description
        self.class.descr.split(/\n/).map(&:strip).reject(&:empty?).join("\n")
      end
    end
  end
end