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.
Files changed (3) hide show
  1. data/README.markdown +54 -0
  2. data/lib/subcommander.rb +154 -0
  3. metadata +68 -0
@@ -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
+
@@ -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
+