pedrozath-mercenary 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rubocop.yml +174 -0
- data/.travis.yml +17 -0
- data/Gemfile +6 -0
- data/History.markdown +115 -0
- data/LICENSE.txt +22 -0
- data/README.md +249 -0
- data/Rakefile +3 -0
- data/examples/help_dialogue.rb +45 -0
- data/examples/logging.rb +35 -0
- data/examples/trace.rb +20 -0
- data/lib/mercenary/command.rb +283 -0
- data/lib/mercenary/option.rb +88 -0
- data/lib/mercenary/presenter.rb +97 -0
- data/lib/mercenary/program.rb +65 -0
- data/lib/mercenary/version.rb +5 -0
- data/lib/mercenary.rb +23 -0
- data/mercenary.gemspec +26 -0
- data/script/bootstrap +7 -0
- data/script/cibuild +7 -0
- data/script/console +3 -0
- data/script/examples +18 -0
- data/script/fmt +4 -0
- data/spec/command_spec.rb +98 -0
- data/spec/option_spec.rb +84 -0
- data/spec/presenter_spec.rb +41 -0
- data/spec/program_spec.rb +19 -0
- data/spec/spec_helper.rb +16 -0
- metadata +136 -0
data/examples/trace.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.join(__dir__, "..", "lib")
|
5
|
+
|
6
|
+
require "mercenary"
|
7
|
+
|
8
|
+
# This example sets the logging mode of mercenary to
|
9
|
+
# debug. Logging messages from "p.logger.debug" will
|
10
|
+
# be output to STDOUT.
|
11
|
+
|
12
|
+
Mercenary.program(:trace) do |p|
|
13
|
+
p.version "2.0.1"
|
14
|
+
p.description "An example of traces in Mercenary"
|
15
|
+
p.syntax "trace <subcommand>"
|
16
|
+
|
17
|
+
p.action do |_, _|
|
18
|
+
raise ArgumentError, "YOU DID SOMETHING TERRIBLE YOU BUFFOON"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Mercenary
|
4
|
+
class Command
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :description
|
7
|
+
attr_reader :syntax
|
8
|
+
attr_accessor :options
|
9
|
+
attr_accessor :commands
|
10
|
+
attr_accessor :actions
|
11
|
+
attr_reader :map
|
12
|
+
attr_accessor :parent
|
13
|
+
attr_reader :trace
|
14
|
+
attr_reader :aliases
|
15
|
+
|
16
|
+
# Public: Creates a new Command
|
17
|
+
#
|
18
|
+
# name - the name of the command
|
19
|
+
# parent - (optional) the instancce of Mercenary::Command which you wish to
|
20
|
+
# be the parent of this command
|
21
|
+
#
|
22
|
+
# Returns nothing
|
23
|
+
def initialize(name, parent = nil)
|
24
|
+
@name = name
|
25
|
+
@options = []
|
26
|
+
@commands = {}
|
27
|
+
@actions = []
|
28
|
+
@map = {}
|
29
|
+
@parent = parent
|
30
|
+
@trace = false
|
31
|
+
@aliases = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Sets or gets the command version
|
35
|
+
#
|
36
|
+
# version - the command version (optional)
|
37
|
+
#
|
38
|
+
# Returns the version and sets it if an argument is non-nil
|
39
|
+
def version(version = nil)
|
40
|
+
@version = version if version
|
41
|
+
@version
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: Sets or gets the syntax string
|
45
|
+
#
|
46
|
+
# syntax - the string which describes this command's usage syntax (optional)
|
47
|
+
#
|
48
|
+
# Returns the syntax string and sets it if an argument is present
|
49
|
+
def syntax(syntax = nil)
|
50
|
+
@syntax = syntax if syntax
|
51
|
+
syntax_list = []
|
52
|
+
if parent
|
53
|
+
syntax_list << parent.syntax.to_s.gsub(%r!<[\w\s-]+>!, "").gsub(%r!\[[\w\s-]+\]!, "").strip
|
54
|
+
end
|
55
|
+
syntax_list << (@syntax || name.to_s)
|
56
|
+
syntax_list.join(" ")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Public: Sets or gets the command description
|
60
|
+
#
|
61
|
+
# description - the description of what the command does (optional)
|
62
|
+
#
|
63
|
+
# Returns the description and sets it if an argument is present
|
64
|
+
def description(desc = nil)
|
65
|
+
@description = desc if desc
|
66
|
+
@description
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: Sets the default command
|
70
|
+
#
|
71
|
+
# command_name - the command name to be executed in the event no args are
|
72
|
+
# present
|
73
|
+
#
|
74
|
+
# Returns the default command if there is one, `nil` otherwise
|
75
|
+
def default_command(command_name = nil)
|
76
|
+
if command_name
|
77
|
+
if commands.key?(command_name)
|
78
|
+
@default_command = commands[command_name] if command_name
|
79
|
+
@default_command
|
80
|
+
else
|
81
|
+
raise ArgumentError, "'#{command_name}' couldn't be found in this command's list of commands."
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@default_command
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Public: Adds an option switch
|
89
|
+
#
|
90
|
+
# sym - the variable key which is used to identify the value of the switch
|
91
|
+
# at runtime in the options hash
|
92
|
+
#
|
93
|
+
# Returns nothing
|
94
|
+
def option(sym, *options)
|
95
|
+
new_option = Option.new(sym, options)
|
96
|
+
@options << new_option
|
97
|
+
@map[new_option] = sym
|
98
|
+
end
|
99
|
+
|
100
|
+
# Public: Adds a subcommand
|
101
|
+
#
|
102
|
+
# cmd_name - the name of the command
|
103
|
+
# block - a block accepting the new instance of Mercenary::Command to be
|
104
|
+
# modified (optional)
|
105
|
+
#
|
106
|
+
# Returns nothing
|
107
|
+
def command(cmd_name)
|
108
|
+
cmd = Command.new(cmd_name, self)
|
109
|
+
yield cmd
|
110
|
+
@commands[cmd_name] = cmd
|
111
|
+
end
|
112
|
+
|
113
|
+
# Public: Add an alias for this command's name to be attached to the parent
|
114
|
+
#
|
115
|
+
# cmd_name - the name of the alias
|
116
|
+
#
|
117
|
+
# Returns nothing
|
118
|
+
def alias(cmd_name)
|
119
|
+
logger.debug "adding alias to parent for self: '#{cmd_name}'"
|
120
|
+
aliases << cmd_name
|
121
|
+
@parent.commands[cmd_name] = self
|
122
|
+
end
|
123
|
+
|
124
|
+
# Public: Add an action Proc to be executed at runtime
|
125
|
+
#
|
126
|
+
# block - the Proc to be executed at runtime
|
127
|
+
#
|
128
|
+
# Returns nothing
|
129
|
+
def action(&block)
|
130
|
+
@actions << block
|
131
|
+
end
|
132
|
+
|
133
|
+
# Public: Fetch a Logger (stdlib)
|
134
|
+
#
|
135
|
+
# level - the logger level (a Logger constant, see docs for more info)
|
136
|
+
#
|
137
|
+
# Returns the instance of Logger
|
138
|
+
|
139
|
+
def logger(level = nil)
|
140
|
+
unless @logger
|
141
|
+
@logger = Logger.new(STDOUT)
|
142
|
+
@logger.level = level || Logger::INFO
|
143
|
+
@logger.formatter = proc do |severity, _datetime, _progname, msg|
|
144
|
+
"#{identity} | " << "#{severity.downcase.capitalize}:".ljust(7) << " #{msg}\n"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
@logger.level = level unless level.nil?
|
149
|
+
@logger
|
150
|
+
end
|
151
|
+
|
152
|
+
# Public: Run the command
|
153
|
+
#
|
154
|
+
# argv - an array of string args
|
155
|
+
# opts - the instance of OptionParser
|
156
|
+
# config - the output config hash
|
157
|
+
#
|
158
|
+
# Returns the command to be executed
|
159
|
+
def go(argv, opts, config)
|
160
|
+
opts.banner = "Usage: #{syntax}"
|
161
|
+
process_options(opts, config)
|
162
|
+
add_default_options(opts)
|
163
|
+
|
164
|
+
if argv[0] && cmd = commands[argv[0].to_sym]
|
165
|
+
logger.debug "Found subcommand '#{cmd.name}'"
|
166
|
+
argv.shift
|
167
|
+
cmd.go(argv, opts, config)
|
168
|
+
else
|
169
|
+
logger.debug "No additional command found, time to exec"
|
170
|
+
self
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Public: Add this command's options to OptionParser and set a default
|
175
|
+
# action of setting the value of the option to the inputted hash
|
176
|
+
#
|
177
|
+
# opts - instance of OptionParser
|
178
|
+
# config - the Hash in which the option values should be placed
|
179
|
+
#
|
180
|
+
# Returns nothing
|
181
|
+
def process_options(opts, config)
|
182
|
+
options.each do |option|
|
183
|
+
opts.on(*option.for_option_parser) do |x|
|
184
|
+
config[map[option]] = x
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Public: Add version and help options to the command
|
190
|
+
#
|
191
|
+
# opts - instance of OptionParser
|
192
|
+
#
|
193
|
+
# Returns nothing
|
194
|
+
def add_default_options(opts)
|
195
|
+
option "show_help", "-h", "--help", "Show this message"
|
196
|
+
option "show_version", "-v", "--version", "Print the name and version"
|
197
|
+
option "show_backtrace", "-t", "--trace", "Show the full backtrace when an error occurs"
|
198
|
+
opts.on("-v", "--version", "Print the version") do
|
199
|
+
puts "#{name} #{version}"
|
200
|
+
exit(0)
|
201
|
+
end
|
202
|
+
|
203
|
+
opts.on("-t", "--trace", "Show full backtrace if an error occurs") do
|
204
|
+
@trace = true
|
205
|
+
end
|
206
|
+
|
207
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
208
|
+
puts self
|
209
|
+
exit
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Public: Execute all actions given the inputted args and options
|
214
|
+
#
|
215
|
+
# argv - (optional) command-line args (sans opts)
|
216
|
+
# config - (optional) the Hash configuration of string key to value
|
217
|
+
#
|
218
|
+
# Returns nothing
|
219
|
+
def execute(argv = [], config = {})
|
220
|
+
if actions.empty? && !default_command.nil?
|
221
|
+
default_command.execute
|
222
|
+
else
|
223
|
+
actions.each { |a| a.call(argv, config) }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Public: Check if this command has a subcommand
|
228
|
+
#
|
229
|
+
# sub_command - the name of the subcommand
|
230
|
+
#
|
231
|
+
# Returns true if this command is the parent of a command of name
|
232
|
+
# 'sub_command' and false otherwise
|
233
|
+
def has_command?(sub_command)
|
234
|
+
commands.keys.include?(sub_command)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Public: Identify this command
|
238
|
+
#
|
239
|
+
# Returns a string which identifies this command
|
240
|
+
def ident
|
241
|
+
"<Command name=#{identity}>"
|
242
|
+
end
|
243
|
+
|
244
|
+
# Public: Get the full identity (name & version) of this command
|
245
|
+
#
|
246
|
+
# Returns a string containing the name and version if it exists
|
247
|
+
def identity
|
248
|
+
"#{full_name} #{version if version}".strip
|
249
|
+
end
|
250
|
+
|
251
|
+
# Public: Get the name of the current command plus that of
|
252
|
+
# its parent commands
|
253
|
+
#
|
254
|
+
# Returns the full name of the command
|
255
|
+
def full_name
|
256
|
+
the_name = []
|
257
|
+
the_name << parent.full_name if parent && parent.full_name
|
258
|
+
the_name << name
|
259
|
+
the_name.join(" ")
|
260
|
+
end
|
261
|
+
|
262
|
+
# Public: Return all the names and aliases for this command.
|
263
|
+
#
|
264
|
+
# Returns a comma-separated String list of the name followed by its aliases
|
265
|
+
def names_and_aliases
|
266
|
+
([name.to_s] + aliases).compact.join(", ")
|
267
|
+
end
|
268
|
+
|
269
|
+
# Public: Build a string containing a summary of the command
|
270
|
+
#
|
271
|
+
# Returns a one-line summary of the command.
|
272
|
+
def summarize
|
273
|
+
" #{names_and_aliases.ljust(20)} #{description}"
|
274
|
+
end
|
275
|
+
|
276
|
+
# Public: Build a string containing the command name, options and any subcommands
|
277
|
+
#
|
278
|
+
# Returns the string identifying this command, its options and its subcommands
|
279
|
+
def to_s
|
280
|
+
Presenter.new(self).print_command
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mercenary
|
4
|
+
class Option
|
5
|
+
attr_reader :config_key, :description, :short, :long, :return_type
|
6
|
+
|
7
|
+
# Public: Create a new Option
|
8
|
+
#
|
9
|
+
# config_key - the key in the config hash to which the value of this option
|
10
|
+
# will map
|
11
|
+
# info - an array containing first the switches, then an optional
|
12
|
+
# return type (e.g. Array), then a description of the option
|
13
|
+
#
|
14
|
+
# Returns nothing
|
15
|
+
def initialize(config_key, info)
|
16
|
+
@config_key = config_key
|
17
|
+
while arg = info.shift
|
18
|
+
begin
|
19
|
+
@return_type = Object.const_get(arg.to_s)
|
20
|
+
next
|
21
|
+
rescue NameError
|
22
|
+
end
|
23
|
+
if arg.start_with?("-")
|
24
|
+
if arg.start_with?("--")
|
25
|
+
@long = arg
|
26
|
+
else
|
27
|
+
@short = arg
|
28
|
+
end
|
29
|
+
next
|
30
|
+
end
|
31
|
+
@description = arg
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: Fetch the array containing the info OptionParser is interested in
|
36
|
+
#
|
37
|
+
# Returns the array which OptionParser#on wants
|
38
|
+
def for_option_parser
|
39
|
+
[short, long, return_type, description].flatten.reject { |o| o.to_s.empty? }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Build a string representation of this option including the
|
43
|
+
# switches and description
|
44
|
+
#
|
45
|
+
# Returns a string representation of this option
|
46
|
+
def to_s
|
47
|
+
"#{formatted_switches} #{description}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Public: Build a beautifully-formatted string representation of the switches
|
51
|
+
#
|
52
|
+
# Returns a formatted string representation of the switches
|
53
|
+
def formatted_switches
|
54
|
+
[
|
55
|
+
switches.first.rjust(10),
|
56
|
+
switches.last.ljust(13),
|
57
|
+
].join(", ").gsub(%r! , !, " ").gsub(%r!, !, " ")
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Hash based on the hash value of instance variables
|
61
|
+
#
|
62
|
+
# Returns a Fixnum which is unique to this Option based on the instance variables
|
63
|
+
def hash
|
64
|
+
instance_variables.map do |var|
|
65
|
+
instance_variable_get(var).hash
|
66
|
+
end.reduce(:^)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: Check equivalence of two Options based on equivalence of their
|
70
|
+
# instance variables
|
71
|
+
#
|
72
|
+
# Returns true if all the instance variables are equal, false otherwise
|
73
|
+
def eql?(other)
|
74
|
+
return false unless self.class.eql?(other.class)
|
75
|
+
instance_variables.map do |var|
|
76
|
+
instance_variable_get(var).eql?(other.instance_variable_get(var))
|
77
|
+
end.all?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Fetch an array of switches, including the short and long versions
|
81
|
+
#
|
82
|
+
# Returns an array of two strings. An empty string represents no switch in
|
83
|
+
# that position.
|
84
|
+
def switches
|
85
|
+
[short, long].map(&:to_s)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mercenary
|
4
|
+
class Presenter
|
5
|
+
attr_accessor :command
|
6
|
+
|
7
|
+
# Public: Make a new Presenter
|
8
|
+
#
|
9
|
+
# command - a Mercenary::Command to present
|
10
|
+
#
|
11
|
+
# Returns nothing
|
12
|
+
def initialize(command)
|
13
|
+
@command = command
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Builds a string representation of the command usage
|
17
|
+
#
|
18
|
+
# Returns the string representation of the command usage
|
19
|
+
def usage_presentation
|
20
|
+
" #{command.syntax}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Builds a string representation of the options
|
24
|
+
#
|
25
|
+
# Returns the string representation of the options
|
26
|
+
def options_presentation
|
27
|
+
return nil unless command_options_presentation || parent_command_options_presentation
|
28
|
+
[command_options_presentation, parent_command_options_presentation].compact.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
def command_options_presentation
|
32
|
+
return nil if command.options.empty?
|
33
|
+
command.options.map(&:to_s).join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Builds a string representation of the options for parent
|
37
|
+
# commands
|
38
|
+
#
|
39
|
+
# Returns the string representation of the options for parent commands
|
40
|
+
def parent_command_options_presentation
|
41
|
+
return nil unless command.parent
|
42
|
+
Presenter.new(command.parent).options_presentation
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public: Builds a string representation of the subcommands
|
46
|
+
#
|
47
|
+
# Returns the string representation of the subcommands
|
48
|
+
def subcommands_presentation
|
49
|
+
return nil if command.commands.empty?
|
50
|
+
command.commands.values.uniq.map(&:summarize).join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Builds the command header, including the command identity and description
|
54
|
+
#
|
55
|
+
# Returns the command header as a String
|
56
|
+
def command_header
|
57
|
+
header = command.identity.to_s
|
58
|
+
header << " -- #{command.description}" if command.description
|
59
|
+
header
|
60
|
+
end
|
61
|
+
|
62
|
+
# Public: Builds a string representation of the whole command
|
63
|
+
#
|
64
|
+
# Returns the string representation of the whole command
|
65
|
+
def command_presentation
|
66
|
+
msg = []
|
67
|
+
msg << command_header
|
68
|
+
msg << "Usage:"
|
69
|
+
msg << usage_presentation
|
70
|
+
|
71
|
+
if opts = options_presentation
|
72
|
+
msg << "Options:\n#{opts}"
|
73
|
+
end
|
74
|
+
if subcommands = subcommands_presentation
|
75
|
+
msg << "Subcommands:\n#{subcommands_presentation}"
|
76
|
+
end
|
77
|
+
msg.join("\n\n")
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Turn a print_* into a *_presentation or freak out
|
81
|
+
#
|
82
|
+
# meth - the method being called
|
83
|
+
# args - an array of arguments passed to the missing method
|
84
|
+
# block - the block passed to the missing method
|
85
|
+
#
|
86
|
+
# Returns the value of whatever function is called
|
87
|
+
def method_missing(meth, *args, &block)
|
88
|
+
if meth.to_s =~ %r!^print_(.+)$!
|
89
|
+
send("#{Regexp.last_match(1).downcase}_presentation")
|
90
|
+
else
|
91
|
+
# You *must* call super if you don't handle the method,
|
92
|
+
# otherwise you'll mess up Ruby's method lookup.
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mercenary
|
4
|
+
class Program < Command
|
5
|
+
attr_reader :optparse
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
# Public: Creates a new Program
|
9
|
+
#
|
10
|
+
# name - the name of the program
|
11
|
+
#
|
12
|
+
# Returns nothing
|
13
|
+
def initialize(name)
|
14
|
+
@config = {}
|
15
|
+
super(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Public: Run the program
|
19
|
+
#
|
20
|
+
# argv - an array of string args (usually ARGV)
|
21
|
+
#
|
22
|
+
# Returns nothing
|
23
|
+
def go(argv)
|
24
|
+
if argv.empty?
|
25
|
+
default_command.execute
|
26
|
+
abort
|
27
|
+
end
|
28
|
+
|
29
|
+
logger.debug("Using args passed in: #{argv.inspect}")
|
30
|
+
|
31
|
+
cmd = nil
|
32
|
+
|
33
|
+
@optparse = OptionParser.new do |opts|
|
34
|
+
cmd = super(argv, opts, @config)
|
35
|
+
end
|
36
|
+
|
37
|
+
if cmd.actions.compact.empty?
|
38
|
+
logger.error 'Invalid command.'
|
39
|
+
abort
|
40
|
+
end
|
41
|
+
|
42
|
+
begin
|
43
|
+
@optparse.parse!(argv)
|
44
|
+
rescue OptionParser::InvalidOption => e
|
45
|
+
logger.error "Whoops, we can't understand your command."
|
46
|
+
logger.error e.message.to_s
|
47
|
+
logger.error "Run your command again with the --help switch to see available options."
|
48
|
+
abort
|
49
|
+
end
|
50
|
+
|
51
|
+
logger.debug("Parsed config: #{@config.inspect}")
|
52
|
+
|
53
|
+
begin
|
54
|
+
cmd.execute(argv, @config)
|
55
|
+
rescue => e
|
56
|
+
if cmd.trace
|
57
|
+
raise e
|
58
|
+
else
|
59
|
+
logger.error e.message
|
60
|
+
abort
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/mercenary.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("mercenary/version", __dir__)
|
4
|
+
require "optparse"
|
5
|
+
require "logger"
|
6
|
+
|
7
|
+
module Mercenary
|
8
|
+
autoload :Command, File.expand_path("mercenary/command", __dir__)
|
9
|
+
autoload :Option, File.expand_path("mercenary/option", __dir__)
|
10
|
+
autoload :Presenter, File.expand_path("mercenary/presenter", __dir__)
|
11
|
+
autoload :Program, File.expand_path("mercenary/program", __dir__)
|
12
|
+
|
13
|
+
# Public: Instantiate a new program and execute.
|
14
|
+
#
|
15
|
+
# name - the name of your program
|
16
|
+
#
|
17
|
+
# Returns nothing.
|
18
|
+
def self.program(name)
|
19
|
+
program = Program.new(name)
|
20
|
+
yield program
|
21
|
+
program.go(ARGV)
|
22
|
+
end
|
23
|
+
end
|
data/mercenary.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "mercenary/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "pedrozath-mercenary"
|
9
|
+
spec.version = Mercenary::VERSION
|
10
|
+
spec.authors = ["Tom Preston-Werner", "Parker Moore"]
|
11
|
+
spec.email = ["tom@mojombo.com", "parkrmoore@gmail.com"]
|
12
|
+
spec.description = "Lightweight and flexible library for writing command-line apps in Ruby."
|
13
|
+
spec.summary = "Lightweight and flexible library for writing command-line apps in Ruby."
|
14
|
+
spec.homepage = "https://github.com/jekyll/mercenary"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
18
|
+
spec.executables = spec.files.grep(%r!^bin/!) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r!^(test|spec|features)/!)
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
spec.add_development_dependency "rubocop", "~> 0.51"
|
26
|
+
end
|
data/script/bootstrap
ADDED
data/script/cibuild
ADDED
data/script/console
ADDED
data/script/examples
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
function run () {
|
6
|
+
echo "+ ruby ./examples/$@"
|
7
|
+
ruby -e "puts '=' * 79"
|
8
|
+
ruby ./examples/$@
|
9
|
+
ruby -e "puts '=' * 79"
|
10
|
+
}
|
11
|
+
|
12
|
+
run logging.rb
|
13
|
+
run logging.rb -v
|
14
|
+
run help_dialogue.rb -h
|
15
|
+
run help_dialogue.rb some_subcommand -h
|
16
|
+
run help_dialogue.rb another_subcommand -h
|
17
|
+
run help_dialogue.rb some_subcommand yet_another_sub -h
|
18
|
+
run help_dialogue.rb some_subcommand yet_another_sub -b
|
data/script/fmt
ADDED