subcommander 1.0.0
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.
- data/README.markdown +54 -0
- data/lib/subcommander.rb +154 -0
- metadata +68 -0
data/README.markdown
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
Subcommander is a wrapper around Ruby's OptionParser class that allows you to have sub-commands like we see in Git and other tools. To get help for your tool, just type in the tool name with no sub-command (or the word "help" as a sub-command). To get help for a sub-command type:
|
2
|
+
|
3
|
+
your-tool help sub-command
|
4
|
+
|
5
|
+
More description coming... this is basically a placeholder for now.
|
6
|
+
|
7
|
+
### Simple Example:
|
8
|
+
|
9
|
+
require 'subcommander'
|
10
|
+
include Subcommander
|
11
|
+
|
12
|
+
subcommander.version = '1.0.0'
|
13
|
+
subcommander.desc = "SimpleTool is ephemeral and only here to demonstrate Subcommander."
|
14
|
+
|
15
|
+
subcommand :run, "Runs the simple tool" do |sc|
|
16
|
+
sc.opt :just_kidding, '-k', '--just-kidding', "Don't really run the simple tool"
|
17
|
+
sc.exec {
|
18
|
+
# This is where the subcommand has its implementation
|
19
|
+
if sc[:just_kidding]
|
20
|
+
puts "Not really running"
|
21
|
+
else
|
22
|
+
puts "Running!"
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
subcommander.go!
|
28
|
+
|
29
|
+
---------------------------
|
30
|
+
|
31
|
+
# subcommander #
|
32
|
+
|
33
|
+
Properties you can set:
|
34
|
+
|
35
|
+
__version__ - The version of the tool you're making. It's printed at the bottom of help.
|
36
|
+
|
37
|
+
__desc__ - A description of the tool you're using. It's printed at the beginning of help.
|
38
|
+
|
39
|
+
|
40
|
+
---------------------------
|
41
|
+
# subcommand #
|
42
|
+
|
43
|
+
Properties you can set:
|
44
|
+
|
45
|
+
__arity__ - This says how many arguemnts are expected to be passed to this sub-command, excluding options and their arguemnts.
|
46
|
+
|
47
|
+
__help__ - Help that shows up when the user asks for help about the sub-command
|
48
|
+
|
49
|
+
__usage__ - The typical usage pattern like "simple-tool [options] args"
|
50
|
+
|
51
|
+
__opt__ - These are exactly the same as OptionParser opt.on() argument lists except the first argument is a token. When the option is invoked, it will put any option arguemnts that were passed into the subcommand keyed by that token. So subcommand[:yoursymbol] is where you'll find it when you're looking for it in your exec block.
|
52
|
+
|
53
|
+
__exec__ - The implementation for your sub-command should be in a block that's passed to this method.
|
54
|
+
|
data/lib/subcommander.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module Subcommander
|
5
|
+
|
6
|
+
def pop! stack
|
7
|
+
[stack[0], stack[1..-1]]
|
8
|
+
end
|
9
|
+
|
10
|
+
class Subcommander
|
11
|
+
attr_accessor :desc,
|
12
|
+
:args,
|
13
|
+
:version
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@commands = {}
|
17
|
+
@descriptions = {}
|
18
|
+
@file_order = []
|
19
|
+
unless ARGV.empty?
|
20
|
+
args = ARGV.clone
|
21
|
+
@sub_cmd, @args = pop!(args)
|
22
|
+
else
|
23
|
+
@args = []
|
24
|
+
end
|
25
|
+
@desc = "This command needs a description"
|
26
|
+
end
|
27
|
+
|
28
|
+
def subcommand cmd_name, desc, &block
|
29
|
+
name = cmd_name.to_s
|
30
|
+
sub_cmd = Subcommand.new(@args.clone, cmd_name, desc, &block)
|
31
|
+
@commands[name] = sub_cmd
|
32
|
+
@file_order << name
|
33
|
+
end
|
34
|
+
|
35
|
+
def go!
|
36
|
+
if @sub_cmd && @sub_cmd == "help"
|
37
|
+
print_help()
|
38
|
+
end
|
39
|
+
sub_cmd = @commands[@sub_cmd]
|
40
|
+
unless sub_cmd # no subcommand
|
41
|
+
print_usage()
|
42
|
+
end
|
43
|
+
sub_cmd.go!
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def print_usage
|
48
|
+
puts "\n#{@desc}\n\n"
|
49
|
+
puts " Subcommands:"
|
50
|
+
@file_order.each do |cmd|
|
51
|
+
puts " #{slop(cmd)} #{@commands[cmd].desc}"
|
52
|
+
end
|
53
|
+
puts "\nv " + @version if @version
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
def slop cmd_name
|
58
|
+
cmd_name + ' ' * (@file_order.max.length - cmd_name.length)
|
59
|
+
end
|
60
|
+
|
61
|
+
def print_help
|
62
|
+
if @args.empty?
|
63
|
+
print_usage
|
64
|
+
else
|
65
|
+
sub_cmd = @commands[@args[0]]
|
66
|
+
if sub_cmd
|
67
|
+
sub_cmd.print_help()
|
68
|
+
end
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def subcommander
|
75
|
+
unless defined?(@@subcommander)
|
76
|
+
@@subcommander = Subcommander.new
|
77
|
+
end
|
78
|
+
@@subcommander
|
79
|
+
end
|
80
|
+
|
81
|
+
def subcommand name, desc, &block
|
82
|
+
@@subcommander.subcommand(name, desc, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
class Subcommand
|
86
|
+
attr_accessor :arity,
|
87
|
+
:name,
|
88
|
+
:desc,
|
89
|
+
:help,
|
90
|
+
:usage,
|
91
|
+
:block
|
92
|
+
|
93
|
+
def initialize args, cmd_name, desc, &block
|
94
|
+
@args = args
|
95
|
+
@name = cmd_name
|
96
|
+
@desc = desc
|
97
|
+
@opts = OptionParser.new
|
98
|
+
@opts.banner = ""
|
99
|
+
@arity = -1 # Don't care how many args
|
100
|
+
@props = {}
|
101
|
+
block.call(self)
|
102
|
+
end
|
103
|
+
|
104
|
+
def [] key
|
105
|
+
@props[key]
|
106
|
+
end
|
107
|
+
|
108
|
+
def banner= str
|
109
|
+
@opts.banner = "Usage: #{str}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def opt *orig_args
|
113
|
+
args = orig_args.clone()
|
114
|
+
prop, args = pop!(args)
|
115
|
+
@opts.on *args do |arg|
|
116
|
+
@props[prop] = arg
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def exec &block
|
121
|
+
@block = block
|
122
|
+
end
|
123
|
+
|
124
|
+
def go!
|
125
|
+
parse_args()
|
126
|
+
num_remaining = @props[:remaining_args].length
|
127
|
+
if @arity > -1 && num_remaining != @arity
|
128
|
+
puts "We expected #{@arity} arguments and #{num_remaining} were provided."
|
129
|
+
exit
|
130
|
+
end
|
131
|
+
@block.call if @block
|
132
|
+
end
|
133
|
+
|
134
|
+
def print_help
|
135
|
+
if @help
|
136
|
+
puts
|
137
|
+
puts @help
|
138
|
+
end
|
139
|
+
if (@usage)
|
140
|
+
@opts.banner = "Usage: #{@usage}"
|
141
|
+
puts
|
142
|
+
end
|
143
|
+
puts @opts.to_s
|
144
|
+
puts
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
def parse_args
|
149
|
+
@props[:remaining_args] = @opts.parse(@args)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 autoindent smartindent:
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: subcommander
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Tom Santos
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-12 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A library for cleanly handling subcommands (and options)
|
23
|
+
email: santos.tom@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- README.markdown
|
32
|
+
- lib/subcommander.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/tsantos/subcommander
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 3
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
version: "0"
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.3.7
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: A library for cleanly handling subcommands (and options)
|
67
|
+
test_files: []
|
68
|
+
|