Class: Simple::CLI::Runner

Inherits:
Object
  • Object
show all
Includes:
Autocompletion
Defined in:
lib/simple/cli/runner.rb,
lib/simple/cli/runner.rb

Overview

A Runner object manages running a CLI application module with a set of string arguments (usually taken from ARGV)

Defined Under Namespace

Modules: Autocompletion Classes: CommandHelp

Constant Summary

Constants included from Autocompletion

Autocompletion::AUTOCOMPLETE_SHELL_CODE, Autocompletion::CommandHelp

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Autocompletion

#autocomplete, #autocomplete_bash, #autocomplete_help, #autocomplete_subcommand_options, #autocomplete_subcommands, #filter_completions

Constructor Details

#initialize(app) ⇒ Runner

Returns a new instance of Runner.



16
17
18
# File 'lib/simple/cli/runner.rb', line 16

def initialize(app)
  @app = app
end

Class Method Details

.run(app, *args) ⇒ Object



12
13
14
# File 'lib/simple/cli/runner.rb', line 12

def self.run(app, *args)
  new(app).run(*args)
end

Instance Method Details

#args_with_options(args) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/simple/cli/runner.rb', line 90

def args_with_options(args)
  r = []
  options = {}
  while arg = args.shift
    case arg
    when /^--(.*)=(.*)/ then options[$1.to_sym] = $2
    when /^--no-(.*)/   then options[$1.to_sym] = false
    when /^--(.*)/      then options[$1.to_sym] = true
    else r << arg
    end
  end

  r << options unless options.empty?
  r
end

#binary_name ⇒ Object



128
129
130
# File 'lib/simple/cli/runner.rb', line 128

def binary_name
  $0.gsub(/.*\//, "")
end

#command_to_string(sym) ⇒ Object



106
107
108
# File 'lib/simple/cli/runner.rb', line 106

def command_to_string(sym)
  sym.to_s.gsub("_", ":")
end

#commands ⇒ Object



114
115
116
# File 'lib/simple/cli/runner.rb', line 114

def commands
  @app.public_instance_methods(false).grep(/^[_a-zA-Z0-9]+$/) + [:help]
end

#do_help!(subcommand = nil) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/simple/cli/runner.rb', line 53

def do_help!(subcommand = nil)
  if !subcommand
    help!
  else
    help_subcommand!(subcommand)
  end
end

#extract_default_flags!(args) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/simple/cli/runner.rb', line 20

def extract_default_flags!(args)
  args.reject! do |arg|
    case arg
    when "-v", "--verbose" then
      logger.level = Logger::DEBUG
    when "-q", "--quiet" then
      logger.level = Logger::WARN
    end
  end
end

#help! ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/simple/cli/runner.rb', line 132

def help!
  STDERR.puts "Usage:\n\n"
  command_helps = commands.inject({}) do |hsh, sym|
    hsh.update sym => help_for_command(sym)
  end
  max_command_helps_length = command_helps.values.map(&:length).max

  commands.sort.each do |sym|
    command_help = command_helps.fetch(sym)
    command_help = "%-#{max_command_helps_length}s" % command_help
    edoc = CommandHelp.new(@app, sym)
    head = "# #{edoc.head}" if edoc.head
    STDERR.puts "    #{command_help}    #{ head }"
  end

  STDERR.puts "\n"

  STDERR.puts <<~DOC
  Default options include:

      #{binary_name} [ --verbose | -v ]         # run on DEBUG log level
      #{binary_name} [ --quiet | -q ]           # run on WARN log level
      #{binary_name} help autocomplete          # print information on autocompletion.

  DOC

  exit 1
end

#help_for_command(sym) ⇒ Object



118
119
120
121
122
123
124
125
126
# File 'lib/simple/cli/runner.rb', line 118

def help_for_command(sym)
  if sym == "autocomplete"
    autocomplete_help
    return
  end

  command_name = command_to_string(sym)
  CommandHelp.new(@app, sym).interface(binary_name, command_name)
end

#help_subcommand!(subcommand) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/simple/cli/runner.rb', line 61

def help_subcommand!(subcommand)
  edoc = CommandHelp.new(@app, subcommand)

  puts <<~MSG
    #{help_for_command(subcommand)}

    #{edoc.full}
   MSG
end

#logger ⇒ Object



71
72
73
# File 'lib/simple/cli/runner.rb', line 71

def logger
  Simple::CLI.logger
end

#on_exception(e) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/simple/cli/runner.rb', line 75

def on_exception(e)
  raise(e) if Simple::CLI::DEBUG

  case e
  when ArgumentError
    logger.error "#{e}\n\n"
    help!
  else
    msg = e.to_s
    msg += " (#{e.class.name})" unless $!.class.name == "RuntimeError"
    logger.error msg
    exit 2
  end
end

#run(*args) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/simple/cli/runner.rb', line 31

def run(*args)
  extract_default_flags!(args)

  @instance = Object.new.extend(@app)
  command_name = args.shift || help!
  command = string_to_command(command_name)

  if command == :help
    do_help!(*args)
  elsif command == :autocomplete
    autocomplete *args
  elsif command == :autocomplete_bash
    autocomplete_bash *args
  elsif commands.include?(command)
    @instance.run! command, *args_with_options(args)
  else
    help!
  end
rescue StandardError => e
  on_exception(e)
end

#string_to_command(s) ⇒ Object



110
111
112
# File 'lib/simple/cli/runner.rb', line 110

def string_to_command(s)
  s.gsub(":", "_").to_sym
end