mercenary 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/History.markdown +19 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -0
- data/examples/help_dialogue.rb +45 -0
- data/examples/logging.rb +39 -0
- data/examples/trace.rb +21 -0
- data/lib/mercenary.rb +4 -2
- data/lib/mercenary/command.rb +85 -22
- data/lib/mercenary/option.rb +80 -0
- data/lib/mercenary/presenter.rb +80 -0
- data/lib/mercenary/program.rb +11 -17
- data/lib/mercenary/version.rb +1 -1
- data/script/cibuild +3 -0
- data/script/console +3 -0
- data/script/examples +17 -0
- data/spec/command_spec.rb +20 -4
- data/spec/option_spec.rb +83 -0
- data/spec/presenter_spec.rb +38 -0
- data/spec/program_spec.rb +19 -0
- metadata +25 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9ebb7e735aa1147cbcc69420fa3a934830c0415
|
4
|
+
data.tar.gz: 120e555e1d05e2af4e674b42cd9143195310b92e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: becf09d037cb3f6475239595c42deba5c89791ccc13f5d2c622d1a88769d91e89c7da2685f1c238f2e41d0308b81cd81679f7ac7352fffa93d36cf7d989a7975
|
7
|
+
data.tar.gz: 2ca3a69a6039ab31343002957dec0c8753181c17817d3d6b59afaa7dc6186e3d78f501979ffae98e3ecb4ba730bdbd46e4d8d5974f653f25fedf603fc9c75cde
|
data/.travis.yml
CHANGED
data/History.markdown
CHANGED
@@ -8,6 +8,25 @@
|
|
8
8
|
|
9
9
|
### Development Fixes
|
10
10
|
|
11
|
+
## 0.3.0 / 2014-02-20
|
12
|
+
|
13
|
+
### Major Enhancements
|
14
|
+
|
15
|
+
* Officially drop 1.8.7 support (#14)
|
16
|
+
* Allow Commands to set their own versions (#17)
|
17
|
+
* Show subcommands, options and usage in help and attach to all commands (#18)
|
18
|
+
* Add `-t, --trace` to allow full exception backtrace to print, otherwise print
|
19
|
+
just the error message (#19)
|
20
|
+
|
21
|
+
### Minor Enhancements
|
22
|
+
|
23
|
+
* Logging state is maintained throughout process (#12)
|
24
|
+
* Tidy up Command#logger output (#21)
|
25
|
+
|
26
|
+
### Development Fixes
|
27
|
+
|
28
|
+
* Added specs for `Program` (#13)
|
29
|
+
|
11
30
|
## 0.2.1 / 2013-12-25
|
12
31
|
|
13
32
|
### Bug Fixes
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
|
4
|
+
|
5
|
+
require "mercenary"
|
6
|
+
|
7
|
+
# This example sets the logging mode of mercenary to
|
8
|
+
# debug. Logging messages from "p.logger.debug" will
|
9
|
+
# be output to STDOUT.
|
10
|
+
|
11
|
+
Mercenary.program(:help_dialogue) do |p|
|
12
|
+
|
13
|
+
p.version "2.0.1"
|
14
|
+
p.description 'An example of the help dialogue in Mercenary'
|
15
|
+
p.syntax 'help_dialogue <subcommand>'
|
16
|
+
|
17
|
+
p.command(:some_subcommand) do |c|
|
18
|
+
c.version '1.4.2'
|
19
|
+
c.syntax 'some_subcommand <subcommand> [options]'
|
20
|
+
c.description 'Some subcommand to do something'
|
21
|
+
c.option 'an_option', '-o', '--option', 'Some option'
|
22
|
+
|
23
|
+
c.command(:yet_another_sub) do |f|
|
24
|
+
f.syntax 'yet_another_sub [options]'
|
25
|
+
f.description 'Do amazing things'
|
26
|
+
f.option 'blah', '-b', '--blah', 'Trigger blah flag'
|
27
|
+
f.option 'heh', '-H ARG', '--heh ARG', 'Give a heh'
|
28
|
+
|
29
|
+
f.action do |args, options|
|
30
|
+
print "Args: "
|
31
|
+
p args
|
32
|
+
print "Opts: "
|
33
|
+
p options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
p.command(:another_subcommand) do |c|
|
39
|
+
c.syntax 'another_subcommand <subcommand> [options]'
|
40
|
+
c.description 'Another subcommand to do something different.'
|
41
|
+
c.option 'an_option', '-O', '--option', 'Some option'
|
42
|
+
c.option 'another_options', '--pluginzzz', 'Set where the plugins should be found from'
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/examples/logging.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
|
4
|
+
|
5
|
+
require "mercenary"
|
6
|
+
|
7
|
+
# This example sets the logging mode of mercenary to
|
8
|
+
# debug. Logging messages from "p.logger.debug" will
|
9
|
+
# be output to STDOUT.
|
10
|
+
|
11
|
+
Mercenary.program(:logger_output) do |p|
|
12
|
+
|
13
|
+
p.version "5.2.6"
|
14
|
+
p.description 'An example of turning on logging for Mercenary.'
|
15
|
+
p.syntax 'logger_output'
|
16
|
+
|
17
|
+
|
18
|
+
p.logger.info "The default log level is INFO. So this will output."
|
19
|
+
p.logger.debug "Since DEBUG is below INFO, this will not output."
|
20
|
+
|
21
|
+
p.logger(Logger::DEBUG)
|
22
|
+
p.logger.debug "Logger level now set to DEBUG. So everything will output."
|
23
|
+
|
24
|
+
p.logger.debug "Example of DEBUG level message."
|
25
|
+
p.logger.info "Example of INFO level message."
|
26
|
+
p.logger.warn "Example of WARN level message."
|
27
|
+
p.logger.error "Example of ERROR level message."
|
28
|
+
p.logger.fatal "Example of FATAL level message."
|
29
|
+
p.logger.unknown "Example of UNKNOWN level message."
|
30
|
+
|
31
|
+
p.action do |args, options|
|
32
|
+
|
33
|
+
p.logger(Logger::INFO)
|
34
|
+
p.logger.debug "Logger level back to INFO. This line will not output."
|
35
|
+
p.logger.info "This INFO message will output."
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/examples/trace.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
|
4
|
+
|
5
|
+
require "mercenary"
|
6
|
+
|
7
|
+
# This example sets the logging mode of mercenary to
|
8
|
+
# debug. Logging messages from "p.logger.debug" will
|
9
|
+
# be output to STDOUT.
|
10
|
+
|
11
|
+
Mercenary.program(:trace) do |p|
|
12
|
+
|
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.new("YOU DID SOMETHING TERRIBLE YOU BUFFOON")
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/mercenary.rb
CHANGED
@@ -6,8 +6,10 @@ require "optparse"
|
|
6
6
|
require "logger"
|
7
7
|
|
8
8
|
module Mercenary
|
9
|
-
autoload :Command,
|
10
|
-
autoload :
|
9
|
+
autoload :Command, "mercenary/command"
|
10
|
+
autoload :Option, "mercenary/option"
|
11
|
+
autoload :Presenter, "mercenary/presenter"
|
12
|
+
autoload :Program, "mercenary/program"
|
11
13
|
|
12
14
|
# Public: Instantiate a new program and execute.
|
13
15
|
#
|
data/lib/mercenary/command.rb
CHANGED
@@ -8,6 +8,7 @@ module Mercenary
|
|
8
8
|
attr_accessor :actions
|
9
9
|
attr_reader :map
|
10
10
|
attr_accessor :parent
|
11
|
+
attr_reader :trace
|
11
12
|
|
12
13
|
# Public: Creates a new Command
|
13
14
|
#
|
@@ -17,12 +18,23 @@ module Mercenary
|
|
17
18
|
#
|
18
19
|
# Returns nothing
|
19
20
|
def initialize(name, parent = nil)
|
20
|
-
@name
|
21
|
-
@options
|
22
|
-
@commands =
|
23
|
-
@actions
|
24
|
-
@map
|
25
|
-
@parent
|
21
|
+
@name = name
|
22
|
+
@options = []
|
23
|
+
@commands = {}
|
24
|
+
@actions = []
|
25
|
+
@map = {}
|
26
|
+
@parent = parent
|
27
|
+
@trace = false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Sets or gets the command version
|
31
|
+
#
|
32
|
+
# version - the command version (optional)
|
33
|
+
#
|
34
|
+
# Returns the version and sets it if an argument is non-nil
|
35
|
+
def version(version = nil)
|
36
|
+
@version = version if version
|
37
|
+
@version
|
26
38
|
end
|
27
39
|
|
28
40
|
# Public: Sets or gets the syntax string
|
@@ -32,7 +44,12 @@ module Mercenary
|
|
32
44
|
# Returns the syntax string and sets it if an argument is present
|
33
45
|
def syntax(syntax = nil)
|
34
46
|
@syntax = syntax if syntax
|
35
|
-
|
47
|
+
syntax_list = []
|
48
|
+
if parent
|
49
|
+
syntax_list << parent.syntax.to_s.gsub(/<[\w\s-]+>/, '').gsub(/\[[\w\s-]+\]/, '').strip
|
50
|
+
end
|
51
|
+
syntax_list << (@syntax || name.to_s)
|
52
|
+
syntax_list.join(" ")
|
36
53
|
end
|
37
54
|
|
38
55
|
# Public: Sets or gets the command description
|
@@ -71,8 +88,9 @@ module Mercenary
|
|
71
88
|
#
|
72
89
|
# Returns nothing
|
73
90
|
def option(sym, *options)
|
74
|
-
|
75
|
-
@
|
91
|
+
new_option = Option.new(sym, options)
|
92
|
+
@options << new_option
|
93
|
+
@map[new_option.hash] = sym
|
76
94
|
end
|
77
95
|
|
78
96
|
# Public: Adds a subcommand
|
@@ -112,15 +130,16 @@ module Mercenary
|
|
112
130
|
# level - the logger level (a Logger constant, see docs for more info)
|
113
131
|
#
|
114
132
|
# Returns the instance of Logger
|
115
|
-
def logger(level =
|
133
|
+
def logger(level = nil)
|
116
134
|
unless @logger
|
117
135
|
@logger = Logger.new(STDOUT)
|
136
|
+
@logger.level = level || Logger::INFO
|
118
137
|
@logger.formatter = proc do |severity, datetime, progname, msg|
|
119
|
-
"#{
|
138
|
+
"#{identity} | " << "#{severity.downcase.capitalize}:".ljust(7) << " #{msg}\n"
|
120
139
|
end
|
121
140
|
end
|
122
141
|
|
123
|
-
@logger.level = level
|
142
|
+
@logger.level = level unless level.nil?
|
124
143
|
@logger
|
125
144
|
end
|
126
145
|
|
@@ -134,6 +153,7 @@ module Mercenary
|
|
134
153
|
def go(argv, opts, config)
|
135
154
|
opts.banner = "Usage: #{syntax}"
|
136
155
|
process_options(opts, config)
|
156
|
+
add_default_options(opts)
|
137
157
|
|
138
158
|
if argv[0] && cmd = commands[argv[0].to_sym]
|
139
159
|
logger.debug "Found subcommand '#{cmd.name}'"
|
@@ -153,13 +173,36 @@ module Mercenary
|
|
153
173
|
#
|
154
174
|
# Returns nothing
|
155
175
|
def process_options(opts, config)
|
156
|
-
options.each do |
|
157
|
-
opts.on(*
|
158
|
-
config[map[
|
176
|
+
options.each do |option|
|
177
|
+
opts.on(*option.for_option_parser) do |x|
|
178
|
+
config[map[option.hash]] = x
|
159
179
|
end
|
160
180
|
end
|
161
181
|
end
|
162
182
|
|
183
|
+
# Public: Add version and help options to the command
|
184
|
+
#
|
185
|
+
# opts - instance of OptionParser
|
186
|
+
#
|
187
|
+
# Returns nothing
|
188
|
+
def add_default_options(opts)
|
189
|
+
option 'show_help', '-h', '--help', 'Show this message'
|
190
|
+
option 'show_version', '-v', '--version', 'Print the name and version'
|
191
|
+
opts.on("-v", "--version", "Print the version") do
|
192
|
+
puts "#{name} #{version}"
|
193
|
+
abort
|
194
|
+
end
|
195
|
+
|
196
|
+
opts.on('-t', '--trace', 'Show full backtrace if an error occurs') do
|
197
|
+
@trace = true
|
198
|
+
end
|
199
|
+
|
200
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
201
|
+
puts self
|
202
|
+
exit
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
163
206
|
# Public: Execute all actions given the inputted args and options
|
164
207
|
#
|
165
208
|
# argv - (optional) command-line args (sans opts)
|
@@ -188,19 +231,39 @@ module Mercenary
|
|
188
231
|
#
|
189
232
|
# Returns a string which identifies this command
|
190
233
|
def ident
|
191
|
-
"<Command name=#{
|
234
|
+
"<Command name=#{identity}>"
|
235
|
+
end
|
236
|
+
|
237
|
+
# Public: Get the full identity (name & version) of this command
|
238
|
+
#
|
239
|
+
# Returns a string containing the name and version if it exists
|
240
|
+
def identity
|
241
|
+
"#{full_name} #{version if version}".strip
|
242
|
+
end
|
243
|
+
|
244
|
+
# Public: Get the name of the current command plus that of
|
245
|
+
# its parent commands
|
246
|
+
#
|
247
|
+
# Returns the full name of the command
|
248
|
+
def full_name
|
249
|
+
the_name = []
|
250
|
+
the_name << parent.full_name if parent && parent.full_name
|
251
|
+
the_name << name
|
252
|
+
the_name.join(" ")
|
253
|
+
end
|
254
|
+
|
255
|
+
# Public: Build a string containing a summary of the command
|
256
|
+
#
|
257
|
+
# Returns a one-line summary of the command.
|
258
|
+
def summarize
|
259
|
+
" #{name.to_s.ljust(20)} #{description}"
|
192
260
|
end
|
193
261
|
|
194
262
|
# Public: Build a string containing the command name, options and any subcommands
|
195
263
|
#
|
196
264
|
# Returns the string identifying this command, its options and its subcommands
|
197
265
|
def to_s
|
198
|
-
|
199
|
-
msg += "Command: #{name}\n"
|
200
|
-
options.each { |o| msg += " " + o.inspect + "\n"}
|
201
|
-
msg += "\n"
|
202
|
-
commands.each { |k, v| msg += commands[k].inspect }
|
203
|
-
msg
|
266
|
+
Presenter.new(self).print_command
|
204
267
|
end
|
205
268
|
end
|
206
269
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Mercenary
|
2
|
+
class Option
|
3
|
+
attr_reader :config_key, :description, :switches
|
4
|
+
|
5
|
+
# Public: Create a new Option
|
6
|
+
#
|
7
|
+
# config_key - the key in the config hash to which the value of this option will map
|
8
|
+
# info - an array containing first the switches, then a description of the option
|
9
|
+
#
|
10
|
+
# Returns nothing
|
11
|
+
def initialize(config_key, info)
|
12
|
+
@config_key = config_key
|
13
|
+
@description = info.last unless info.last.start_with?("-")
|
14
|
+
set_switches(info.take(info.size - [@description].reject(&:nil?).size))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Fetch the array containing the info OptionParser is interested in
|
18
|
+
#
|
19
|
+
# Returns the array which OptionParser#on wants
|
20
|
+
def for_option_parser
|
21
|
+
[switches.reject(&:empty?), description].reject{ |o| o.nil? || o.empty? }.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
# Public: Build a string representation of this option including the
|
25
|
+
# switches and description
|
26
|
+
#
|
27
|
+
# Returns a string representation of this option
|
28
|
+
def to_s
|
29
|
+
"#{formatted_switches} #{description}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Build a beautifully-formatted string representation of the switches
|
33
|
+
#
|
34
|
+
# Returns a formatted string representation of the switches
|
35
|
+
def formatted_switches
|
36
|
+
[
|
37
|
+
switches.first.rjust(10),
|
38
|
+
switches.last.ljust(13)
|
39
|
+
].join(", ").gsub(/ , /, ' ').gsub(/, /, ' ')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Hash based on the hash value of instance variables
|
43
|
+
#
|
44
|
+
# Returns a Fixnum which is unique to this Option based on the instance variables
|
45
|
+
def hash
|
46
|
+
instance_variables.map do |var|
|
47
|
+
instance_variable_get(var).hash
|
48
|
+
end.reduce(:&)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Check equivalence of two Options based on equivalence of their
|
52
|
+
# instance variables
|
53
|
+
#
|
54
|
+
# Returns true if all the instance variables are equal, false otherwise
|
55
|
+
def eql?(other)
|
56
|
+
return false unless self.class.eql?(other.class)
|
57
|
+
instance_variables.map do |var|
|
58
|
+
instance_variable_get(var).eql?(other.instance_variable_get(var))
|
59
|
+
end.all?
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Private: Set the full switches array, ensuring the first element is the
|
65
|
+
# short switch and the second element is the long switch
|
66
|
+
#
|
67
|
+
# Returns the corrected switches array
|
68
|
+
def set_switches(switches)
|
69
|
+
if switches.size < 2
|
70
|
+
if switches.first.start_with?("--")
|
71
|
+
switches.unshift ""
|
72
|
+
else
|
73
|
+
switches << ""
|
74
|
+
end
|
75
|
+
end
|
76
|
+
@switches = switches
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Mercenary
|
2
|
+
class Presenter
|
3
|
+
attr_accessor :command
|
4
|
+
|
5
|
+
# Public: Make a new Presenter
|
6
|
+
#
|
7
|
+
# command - a Mercenary::Command to present
|
8
|
+
#
|
9
|
+
# Returns nothing
|
10
|
+
def initialize(command)
|
11
|
+
@command = command
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Builds a string representation of the command usage
|
15
|
+
#
|
16
|
+
# Returns the string representation of the command usage
|
17
|
+
def usage_presentation
|
18
|
+
" #{command.syntax}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Builds a string representation of the options
|
22
|
+
#
|
23
|
+
# Returns the string representation of the options
|
24
|
+
def options_presentation
|
25
|
+
return nil unless command.options.size > 0
|
26
|
+
command.options.map(&:to_s).join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: Builds a string representation of the subcommands
|
30
|
+
#
|
31
|
+
# Returns the string representation of the subcommands
|
32
|
+
def subcommands_presentation
|
33
|
+
return nil unless command.commands.size > 0
|
34
|
+
command.commands.values.map(&:summarize).join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: Builds the command header, including the command identity and description
|
38
|
+
#
|
39
|
+
# Returns the command header as a String
|
40
|
+
def command_header
|
41
|
+
header = "#{command.identity}"
|
42
|
+
header << " -- #{command.description}" if command.description
|
43
|
+
header
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public: Builds a string representation of the whole command
|
47
|
+
#
|
48
|
+
# Returns the string representation of the whole command
|
49
|
+
def command_presentation
|
50
|
+
msg = []
|
51
|
+
msg << command_header
|
52
|
+
msg << "Usage:"
|
53
|
+
msg << usage_presentation
|
54
|
+
|
55
|
+
if opts = options_presentation
|
56
|
+
msg << "Options:\n#{opts}"
|
57
|
+
end
|
58
|
+
if subcommands = subcommands_presentation
|
59
|
+
msg << "Subcommands:\n#{subcommands_presentation}"
|
60
|
+
end
|
61
|
+
msg.join("\n\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Public: Turn a print_* into a *_presentation or freak out
|
65
|
+
#
|
66
|
+
# meth - the method being called
|
67
|
+
# args - an array of arguments passed to the missing method
|
68
|
+
# block - the block passed to the missing method
|
69
|
+
#
|
70
|
+
# Returns the value of whatever function is called
|
71
|
+
def method_missing(meth, *args, &block)
|
72
|
+
if meth.to_s =~ /^print_(.+)$/
|
73
|
+
send("#{$1.downcase}_presentation")
|
74
|
+
else
|
75
|
+
super # You *must* call super if you don't handle the method,
|
76
|
+
# otherwise you'll mess up Ruby's method lookup.
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/mercenary/program.rb
CHANGED
@@ -13,19 +13,9 @@ module Mercenary
|
|
13
13
|
super(name)
|
14
14
|
end
|
15
15
|
|
16
|
-
# Public: Sets or gets the program version
|
17
|
-
#
|
18
|
-
# version - the program version (optional)
|
19
|
-
#
|
20
|
-
# Returns the version and sets it if an argument is present
|
21
|
-
def version(version = nil)
|
22
|
-
@version = version if version
|
23
|
-
@version
|
24
|
-
end
|
25
|
-
|
26
16
|
# Public: Run the program
|
27
17
|
#
|
28
|
-
# argv
|
18
|
+
# argv - an array of string args (usually ARGV)
|
29
19
|
#
|
30
20
|
# Returns nothing
|
31
21
|
def go(argv)
|
@@ -35,18 +25,22 @@ module Mercenary
|
|
35
25
|
|
36
26
|
@optparse = OptionParser.new do |opts|
|
37
27
|
cmd = super(argv, opts, @config)
|
38
|
-
|
39
|
-
opts.on('-v', '--version', 'Print the version') do
|
40
|
-
puts "#{name} #{version}"
|
41
|
-
abort
|
42
|
-
end
|
43
28
|
end
|
44
29
|
|
45
30
|
@optparse.parse!(argv)
|
46
31
|
|
47
32
|
logger.debug("Parsed config: #{@config.inspect}")
|
48
33
|
|
49
|
-
|
34
|
+
begin
|
35
|
+
cmd.execute(argv, @config)
|
36
|
+
rescue => e
|
37
|
+
if cmd.trace
|
38
|
+
raise e
|
39
|
+
else
|
40
|
+
logger.error e.message
|
41
|
+
abort
|
42
|
+
end
|
43
|
+
end
|
50
44
|
end
|
51
45
|
end
|
52
46
|
end
|
data/lib/mercenary/version.rb
CHANGED
data/script/cibuild
CHANGED
data/script/console
ADDED
data/script/examples
ADDED
@@ -0,0 +1,17 @@
|
|
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 help_dialogue.rb -h
|
14
|
+
run help_dialogue.rb some_subcommand -h
|
15
|
+
run help_dialogue.rb another_subcommand -h
|
16
|
+
run help_dialogue.rb some_subcommand yet_another_sub -h
|
17
|
+
run help_dialogue.rb some_subcommand yet_another_sub -b
|
data/spec/command_spec.rb
CHANGED
@@ -35,6 +35,12 @@ describe(Mercenary::Command) do
|
|
35
35
|
expect(add_sub.call(command).parent).to eq(command)
|
36
36
|
end
|
37
37
|
|
38
|
+
it "can set its version" do
|
39
|
+
version = "1.4.2"
|
40
|
+
command.version version
|
41
|
+
expect(command.version).to eq(version)
|
42
|
+
end
|
43
|
+
|
38
44
|
it "can set its syntax" do
|
39
45
|
syntax_string = "my_name [options]"
|
40
46
|
cmd = described_class.new(:my_name)
|
@@ -50,10 +56,20 @@ describe(Mercenary::Command) do
|
|
50
56
|
|
51
57
|
it "can set its options" do
|
52
58
|
name = "show_drafts"
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
expect(command.
|
59
|
+
opts = ['--drafts', 'Render posts in the _drafts folder']
|
60
|
+
option = Mercenary::Option.new(name, opts)
|
61
|
+
command.option name, *opts
|
62
|
+
expect(command.options).to eql([option])
|
63
|
+
expect(command.map).to include({option.hash => name})
|
64
|
+
end
|
65
|
+
|
66
|
+
it "knows its full name" do
|
67
|
+
expect(command_with_parent.full_name).to eql("my_parent i_have_parent")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "knows its identity" do
|
71
|
+
command_with_parent.version '1.8.7'
|
72
|
+
expect(command_with_parent.identity).to eql("my_parent i_have_parent 1.8.7")
|
57
73
|
end
|
58
74
|
|
59
75
|
it "raises an ArgumentError if I specify a default_command that isn't there" do
|
data/spec/option_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe(Mercenary::Option) do
|
4
|
+
let(:config_key) { "largo" }
|
5
|
+
let(:description) { "This is a description" }
|
6
|
+
let(:switches) { ['-l', '--largo'] }
|
7
|
+
let(:option) { described_class.new(config_key, [switches, description].flatten.reject(&:nil?)) }
|
8
|
+
|
9
|
+
it "knows its config key" do
|
10
|
+
expect(option.config_key).to eql(config_key)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "knows its description" do
|
14
|
+
expect(option.description).to eql(description)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "knows its switches" do
|
18
|
+
expect(option.switches).to eql(switches)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "knows how to present itself" do
|
22
|
+
expect(option.to_s).to eql(" -l, --largo #{description}")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has an OptionParser representation" do
|
26
|
+
expect(option.for_option_parser).to eql([switches, description].flatten)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "compares itself with other options well" do
|
30
|
+
new_option = described_class.new(config_key, ['-l', '--largo', description])
|
31
|
+
expect(option.eql?(new_option)).to be_true
|
32
|
+
expect(option.hash.eql?(new_option.hash)).to be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has a custom #hash" do
|
36
|
+
expect(option.hash.to_s).to match(/\d+/)
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with just the long switch" do
|
40
|
+
let(:switches) { ['--largo'] }
|
41
|
+
|
42
|
+
it "adds an empty string in place of the short switch" do
|
43
|
+
expect(option.switches).to eql(['', '--largo'])
|
44
|
+
end
|
45
|
+
|
46
|
+
it "sets its description properly" do
|
47
|
+
expect(option.description).to eql(description)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "knows how to present the switch" do
|
51
|
+
expect(option.formatted_switches).to eql(" --largo ")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with just the short switch" do
|
56
|
+
let(:switches) { ['-l'] }
|
57
|
+
|
58
|
+
it "adds an empty string in place of the long switch" do
|
59
|
+
expect(option.switches).to eql(['-l', ''])
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets its description properly" do
|
63
|
+
expect(option.description).to eql(description)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "knows how to present the switch" do
|
67
|
+
expect(option.formatted_switches).to eql(" -l ")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "without a description" do
|
72
|
+
let(:description) { nil }
|
73
|
+
|
74
|
+
it "knows there is no description" do
|
75
|
+
expect(option.description).to be_nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it "knows both inputs are switches" do
|
79
|
+
expect(option.switches).to eql(switches)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe(Mercenary::Presenter) do
|
4
|
+
let(:supercommand) { Mercenary::Command.new(:script_name) }
|
5
|
+
let(:command) { Mercenary::Command.new(:subcommand, supercommand) }
|
6
|
+
let(:presenter) { described_class.new(command) }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
command.version '1.4.2'
|
10
|
+
command.description 'Do all the things.'
|
11
|
+
command.option 'one', '-1', '--one', 'The first option'
|
12
|
+
command.option 'two', '-2', '--two', 'The second option'
|
13
|
+
supercommand.commands[command.name] = command
|
14
|
+
end
|
15
|
+
|
16
|
+
it "knows how to present the command" do
|
17
|
+
expect(presenter.command_presentation).to eql("script_name subcommand 1.4.2 -- Do all the things.\n\nUsage:\n\n script_name subcommand\n\nOptions:\n -1, --one The first option\n -2, --two The second option")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "knows how to present the subcommands" do
|
21
|
+
expect(described_class.new(supercommand).subcommands_presentation).to eql(" subcommand Do all the things.")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "knows how to present the usage" do
|
25
|
+
expect(presenter.usage_presentation).to eql(" script_name subcommand")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "knows how to present the options" do
|
29
|
+
expect(presenter.options_presentation).to eql(" -1, --one The first option\n -2, --two The second option")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows you to say print_* instead of *_presentation" do
|
33
|
+
expect(presenter.print_usage).to eql(presenter.usage_presentation)
|
34
|
+
expect(presenter.print_subcommands).to eql(presenter.subcommands_presentation)
|
35
|
+
expect(presenter.print_options).to eql(presenter.options_presentation)
|
36
|
+
expect(presenter.print_command).to eql(presenter.command_presentation)
|
37
|
+
end
|
38
|
+
end
|
data/spec/program_spec.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe(Mercenary::Program) do
|
4
|
+
|
5
|
+
context "a basic program" do
|
6
|
+
let(:program) { Mercenary::Program.new(:my_name) }
|
7
|
+
|
8
|
+
it "can be created with just a name" do
|
9
|
+
expect(program.name).to eql(:my_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can set its version" do
|
13
|
+
version = Mercenary::VERSION
|
14
|
+
program.version version
|
15
|
+
expect(program.version).to eq(version)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mercenary
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Preston-Werner
|
@@ -9,48 +9,48 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-02-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ~>
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.3'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.3'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rspec
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - ~>
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '2.14'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ~>
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '2.14'
|
56
56
|
description: Lightweight and flexible library for writing command-line apps in Ruby.
|
@@ -61,22 +61,31 @@ executables: []
|
|
61
61
|
extensions: []
|
62
62
|
extra_rdoc_files: []
|
63
63
|
files:
|
64
|
-
-
|
65
|
-
-
|
66
|
-
-
|
64
|
+
- .gitignore
|
65
|
+
- .rspec
|
66
|
+
- .travis.yml
|
67
67
|
- Gemfile
|
68
68
|
- History.markdown
|
69
69
|
- LICENSE.txt
|
70
70
|
- README.md
|
71
71
|
- Rakefile
|
72
|
+
- examples/help_dialogue.rb
|
73
|
+
- examples/logging.rb
|
74
|
+
- examples/trace.rb
|
72
75
|
- lib/mercenary.rb
|
73
76
|
- lib/mercenary/command.rb
|
77
|
+
- lib/mercenary/option.rb
|
78
|
+
- lib/mercenary/presenter.rb
|
74
79
|
- lib/mercenary/program.rb
|
75
80
|
- lib/mercenary/version.rb
|
76
81
|
- mercenary.gemspec
|
77
82
|
- script/bootstrap
|
78
83
|
- script/cibuild
|
84
|
+
- script/console
|
85
|
+
- script/examples
|
79
86
|
- spec/command_spec.rb
|
87
|
+
- spec/option_spec.rb
|
88
|
+
- spec/presenter_spec.rb
|
80
89
|
- spec/program_spec.rb
|
81
90
|
- spec/spec_helper.rb
|
82
91
|
homepage: https://github.com/jekyll/mercenary
|
@@ -89,21 +98,23 @@ require_paths:
|
|
89
98
|
- lib
|
90
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
100
|
requirements:
|
92
|
-
- -
|
101
|
+
- - '>='
|
93
102
|
- !ruby/object:Gem::Version
|
94
103
|
version: '0'
|
95
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
105
|
requirements:
|
97
|
-
- -
|
106
|
+
- - '>='
|
98
107
|
- !ruby/object:Gem::Version
|
99
108
|
version: '0'
|
100
109
|
requirements: []
|
101
110
|
rubyforge_project:
|
102
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.0.14
|
103
112
|
signing_key:
|
104
113
|
specification_version: 4
|
105
114
|
summary: Lightweight and flexible library for writing command-line apps in Ruby.
|
106
115
|
test_files:
|
107
116
|
- spec/command_spec.rb
|
117
|
+
- spec/option_spec.rb
|
118
|
+
- spec/presenter_spec.rb
|
108
119
|
- spec/program_spec.rb
|
109
120
|
- spec/spec_helper.rb
|