gli 0.1.6 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +74 -26
- data/bin/gli +11 -8
- data/gli.rdoc +45 -0
- data/lib/gli.rb +25 -27
- data/lib/gli/command.rb +5 -2
- data/lib/gli/command_line_token.rb +7 -1
- data/lib/gli/flag.rb +4 -4
- data/lib/gli/switch.rb +2 -2
- data/lib/support/help.rb +8 -2
- data/lib/support/rdoc.rb +78 -0
- data/lib/support/scaffold.rb +103 -0
- metadata +10 -5
data/README.rdoc
CHANGED
@@ -1,18 +1,32 @@
|
|
1
|
-
|
1
|
+
= Git-Like Interface Command Line Parser
|
2
2
|
|
3
|
-
|
3
|
+
Author:: Dave Copeland (mailto:davetron5000 at g mail dot com)
|
4
|
+
Copyright:: Copyright (c) 2009 by Dave Copeland
|
5
|
+
License:: Distributes under the Apache License, see LICENSE.txt in the source distro
|
6
|
+
|
7
|
+
This is a DSL you can use to create a command line interface like git, gem or svn, in that the first argument is a command, and there are global and command specific flags.
|
8
|
+
|
9
|
+
== Use
|
10
|
+
|
11
|
+
Install if you need to:
|
12
|
+
|
13
|
+
sudo gem install gli
|
4
14
|
|
5
15
|
The simplest way to get started is to create a scaffold project
|
6
16
|
|
7
17
|
gli init my_proj command_name other_command_name
|
8
18
|
|
9
|
-
This will create a
|
10
|
-
main file in <tt>./my_proj/bin/my_proj</tt>. This file demonstrates most of what you need
|
11
|
-
to describe your command line interface
|
19
|
+
This will create a basic scaffold project in <tt>./my_proj</tt> with:
|
12
20
|
|
13
|
-
|
21
|
+
* executable in <tt>./my_proj/bin/my_proj</tt>. This file demonstrates most of what you need to describe your command line interface.
|
22
|
+
* an empty test in <tt>./my_proj/test/tc_nothing.rb</tt> that can bootstrap your tests
|
23
|
+
* a gemspec shell
|
24
|
+
* a README shell
|
25
|
+
* Rakefile that can generate RDoc, package your Gem and run tests
|
14
26
|
|
15
|
-
|
27
|
+
=== Example
|
28
|
+
|
29
|
+
This example demonstrates most of the features of GLI
|
16
30
|
|
17
31
|
#!/usr/bin/ruby
|
18
32
|
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
@@ -21,27 +35,31 @@ This sets you up to use the DSL that GLI defines:
|
|
21
35
|
|
22
36
|
include GLI
|
23
37
|
|
24
|
-
This
|
25
|
-
|
38
|
+
This sets you up to use the DSL that GLI defines:
|
39
|
+
|
40
|
+
|
41
|
+
program_description 'Support program for bootstrapping GLI-based programs'
|
42
|
+
|
43
|
+
This sets a description of your program. This can be as long as you want.
|
44
|
+
|
26
45
|
|
27
46
|
desc 'Dry run; don\'t change the disk'
|
28
47
|
switch :n
|
29
48
|
|
49
|
+
This describes a command line switch "-n" that is global to all commands and specified before
|
50
|
+
the command name on the command line.
|
30
51
|
|
31
|
-
This describes a command line flag that is global and has a default value of '<tt>.</tt>'. It also
|
32
|
-
specifies a short description of its argument. This is used to print command line help. Note that we
|
33
|
-
have specified two different aliases for this flag. <tt>-r</tt> (because it is listed first) is the default
|
34
|
-
one and <tt>--root</tt> (note two-dash syntax) is also supported. This means that <tt>-r some_dir</tt> and <tt>--root=some_dir</tt> mean
|
35
|
-
the same thing to the application.
|
36
52
|
|
37
53
|
desc 'Root dir in which to create project'
|
38
54
|
default_value '.'
|
39
55
|
arg_name 'root_dir'
|
40
56
|
flag [:r,:root]
|
41
57
|
|
42
|
-
|
43
|
-
|
44
|
-
|
58
|
+
The following describes a command line flag that is global and has a default value of '<tt>.</tt>'. It also
|
59
|
+
specifies a short description of its argument. This is used to print command line help. Note that we
|
60
|
+
have specified two different aliases for this flag. <tt>-r</tt> (because it is listed first) is the default
|
61
|
+
one and <tt>--root</tt> (note two-dash syntax) is also supported. This means that <tt>-r some_dir</tt> and <tt>--root=some_dir</tt> mean
|
62
|
+
the same thing to the application.
|
45
63
|
|
46
64
|
desc 'Create a new GLI-based project'
|
47
65
|
arg_name 'project_name [command[ command]*]'
|
@@ -53,18 +71,22 @@ here to describe the arguments this command accepts.
|
|
53
71
|
c.desc 'Overwrite/ignore existing files and directories'
|
54
72
|
c.switch [:force]
|
55
73
|
|
56
|
-
Here we specify the
|
57
|
-
|
58
|
-
|
74
|
+
Here we specify a command. Inside the block we can use the same sorts of things as we did above to define flags
|
75
|
+
and switches specific to the command. These must come after the command name. Also note that we use <tt>arg_name</tt>
|
76
|
+
here to describe the arguments this command accepts.
|
59
77
|
|
60
78
|
c.action do |global_options,options,args|
|
61
79
|
if args.length < 1
|
62
|
-
raise
|
80
|
+
raise 'You must specify the name of your project'
|
63
81
|
end
|
64
82
|
Scaffold.create_scaffold(g[:r],!o[:notest],o[:e],args[0],args[1..-1],o[:force],g[:n])
|
65
83
|
end
|
66
84
|
end
|
67
85
|
|
86
|
+
Here we specify the actual actions to take when the command is executed. We define a block that
|
87
|
+
will be given the global options (as a Hash), the command-specific options (as a hash) and the command
|
88
|
+
line arguments
|
89
|
+
|
68
90
|
You can also specify some global code to run before, after and on errors:
|
69
91
|
|
70
92
|
pre do |global_options,command,options,args|
|
@@ -87,6 +109,8 @@ Now, we run the program using the arguments the user provided on the command lin
|
|
87
109
|
|
88
110
|
run(ARGV)
|
89
111
|
|
112
|
+
Note that by using <tt>gli init</tt> you can create a shell with all of this already there.
|
113
|
+
|
90
114
|
What this gives you:
|
91
115
|
|
92
116
|
* A reasonably useful help system. <tt>your_program help</tt> will list all the global options and commands (along with command aliases) and <tt>your_program help command_name</tt> will list help for that given command.
|
@@ -99,8 +123,25 @@ What this doesn't give you:
|
|
99
123
|
* A way to indicate required flags
|
100
124
|
* A way to indicate a require argument or required number of arguments
|
101
125
|
* A way to do default switches to 'true' and therefore accept things like <tt>--no-force</tt>
|
102
|
-
|
103
|
-
|
126
|
+
|
127
|
+
== Reference
|
128
|
+
|
129
|
+
|
130
|
+
[+action+] Specify the action to take when a command is executed from the command line. This is only usable in a command block on the command object (e.g. <tt>c.action</tt>). This takes a block that yields three parameters: a hash of global options specified on the commandline, a hash of command-specific options specified on the command line, and an array of arguments parsed after the options were set on the command line. So, a command like <tt>git --git-dir=/tmp commit -a -m 'Foo bar' foo.c bar.c</tt> would result in the global hash containing <tt>:'git-dir' => '/tmp'</tt>, the options hash containing <tt>:a => true, :m => 'Foo bar'</tt> and the arguments array being <tt>['foo.c', 'bar.c']</tt>
|
131
|
+
[+arg_name+] Describe the name of the argument to the next flag or command. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.arg_name</tt>)
|
132
|
+
[+command+] Declare a command. This takes a symbol or array of symbols and a block. The block yields one argument, the command itself.
|
133
|
+
[+default_value+] Indicate the default value of the next flag. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.default_value</tt>)
|
134
|
+
[+desc+] Describe the next flag, switch, or command you will declare. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.desc</tt>)
|
135
|
+
[+flag+] Declare a flag, which is a command line switch that takes an argument. This takes either a symbol or an array of symbols. The first symbol decared is used in your program to determine the flag's value at runtime. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.flag</tt>)
|
136
|
+
[+long_desc+] Provide a more lengthy description of the next flag, switch, or command you will declare. This will appear in command line output for commands when you get help for a command. For flags and switches, this will only appear in the generated rdoc and *not* on the command line. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.long_desc</tt>)
|
137
|
+
[+on_error+] Declare an error handling routine that will be called if any command (or other GLI processing) encouters an exception. This is a block that will receive the exception that was caught. All exceptions are routed through this block. If the block evaluates to true, the built-in error handling will be called after, otherwise, nothing will happen.
|
138
|
+
[+post+] Declare code to run after every command that didn't experience an error. This is not available inside a command block. This takes a block that will receive four arguments: the global argument hash (as in <tt>action</tt>), the command (instance of Command), the command-specific options (as in <tt>action</tt>, and the parsed command line arguments (as in <tt>action</tt>).
|
139
|
+
[+pre+] Declare code to run before every command. This is not available inside a command block. This takes a block that will receive four arguments: the global argument hash (as in <tt>action</tt>), the command (instance of Command), the command-specific options (as in <tt>action</tt>, and the parsed command line arguments (as in <tt>action</tt>). If this block evaluates to false, the command will not be executed and the program will stop.
|
140
|
+
[+switch+] Declare a switch, which is a command-line switch taking no argument that indicates a boolean "true" when specified on the command line. This takes either a symbol or array of symbols. The first symbol declared is used in your program to determine if the switch was set. This can be used at the global level or inside a command block on the command object (e.g. <tt>c.switch</tt>)
|
141
|
+
|
142
|
+
== Interface Generated
|
143
|
+
|
144
|
+
The command line interface that is created with the GLI DSL is:
|
104
145
|
|
105
146
|
*executable* <i>global options and flags</i> *command* <i>command specific options and flags</i> `arguments`
|
106
147
|
|
@@ -109,7 +150,7 @@ What this doesn't give you:
|
|
109
150
|
[command] the command to execute. The <tt>rebase</tt> in <tt>git rebase</tt>
|
110
151
|
[arguments] Anything that's not a switch, flag, or command. The <tt>main.c</tt> in <tt>git add main.c</tt>
|
111
152
|
|
112
|
-
|
153
|
+
=== Switches
|
113
154
|
|
114
155
|
Switches can be specified one at a time in either a long or short format:
|
115
156
|
|
@@ -121,15 +162,22 @@ Switches can also be combined in their short form:
|
|
121
162
|
ls -l -a
|
122
163
|
ls -la
|
123
164
|
|
124
|
-
|
165
|
+
=== Flags
|
125
166
|
|
126
167
|
Flags can be specified in long or short form, and with or without an equals:
|
127
168
|
|
128
169
|
git merge -s resolve
|
129
170
|
git merge --strategy=resolve
|
130
171
|
|
131
|
-
|
172
|
+
=== Stop Switch
|
132
173
|
|
133
174
|
A <tt>--</tt> at any time stops processing and sends the rest of the argument to the command as arguments, even if
|
134
175
|
they start with a "--"
|
135
176
|
|
177
|
+
:include:gli.rdoc
|
178
|
+
|
179
|
+
== Links
|
180
|
+
|
181
|
+
* [http://davetron5000.github.com/gli] - RubyDoc
|
182
|
+
* [http://www.github.com/davetron5000/gli] - Source on GitHub
|
183
|
+
|
data/bin/gli
CHANGED
@@ -5,20 +5,28 @@ require 'gli'
|
|
5
5
|
require 'support/scaffold'
|
6
6
|
|
7
7
|
include GLI
|
8
|
+
|
8
9
|
desc 'Be verbose'
|
9
10
|
switch :v
|
10
11
|
|
11
|
-
desc '
|
12
|
+
desc 'Show version'
|
12
13
|
switch :version
|
13
14
|
|
14
|
-
desc 'Dry run; don
|
15
|
+
desc 'Dry run; don''t change the disk'
|
15
16
|
switch :n
|
16
17
|
|
17
18
|
desc 'Root dir of project'
|
19
|
+
long_desc 'This is the directory where the project''s directory will be made, so if you specify a project name ''foo'' and the root dir of ''.'', the directory ''./foo'' will be created'
|
18
20
|
default_value '.'
|
19
21
|
flag [:r,:root]
|
20
22
|
|
21
23
|
desc 'Create a new GLI-based project'
|
24
|
+
long_desc <<EOS
|
25
|
+
This will create a scaffold command line project that uses GLI
|
26
|
+
for command line processing. Specifically, this will create
|
27
|
+
an executable ready to go, as well as a lib and test directory, all
|
28
|
+
inside the directory named for your project
|
29
|
+
EOS
|
22
30
|
arg_name 'project_name [command[ command]*]'
|
23
31
|
command [:init,:scaffold] do |c|
|
24
32
|
|
@@ -33,7 +41,7 @@ command [:init,:scaffold] do |c|
|
|
33
41
|
|
34
42
|
c.action do |g,o,args|
|
35
43
|
if args.length < 1
|
36
|
-
raise
|
44
|
+
raise 'You must specify the name of your project'
|
37
45
|
end
|
38
46
|
Scaffold.create_scaffold(g[:r],!o[:notest],o[:e],args[0],args[1..-1],o[:force],g[:n])
|
39
47
|
end
|
@@ -53,9 +61,4 @@ post do |global,command,options,args|
|
|
53
61
|
puts "Executed #{command.name}" if global[:v]
|
54
62
|
end
|
55
63
|
|
56
|
-
#on_error do |global,command,options,args|
|
57
|
-
# puts "Got an error" if global[:v]
|
58
|
-
# true
|
59
|
-
#end
|
60
|
-
|
61
64
|
run(ARGV)
|
data/gli.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= <tt>gli</tt>
|
2
|
+
|
3
|
+
gli [global options] command_name [command-specific options] [--] arguments...
|
4
|
+
|
5
|
+
* Use the command +help+ to get a summary of commands
|
6
|
+
* Use the command <tt>help command_name</tt> to get a help for +command_name+
|
7
|
+
* Use <tt>--</tt> to stop command line argument processing; useful if your arguments have dashes in them
|
8
|
+
|
9
|
+
== Global Options
|
10
|
+
These options are available for any command and are specified before the name of the command
|
11
|
+
|
12
|
+
[<tt>-n</tt>] Dry run; dont change the disk
|
13
|
+
[<tt>-r, --root=arg</tt>] Root dir of project <i>( default: <tt>.</tt>)</i>
|
14
|
+
|
15
|
+
This is the directory where the projects directory will be made, so if you specify a project name foo and the root dir of ., the directory ./foo will be created
|
16
|
+
|
17
|
+
[<tt>-v</tt>] Be verbose
|
18
|
+
[<tt>--version</tt>] Show version
|
19
|
+
== Commands
|
20
|
+
[<tt>help</tt>] Shows list of commands or help for one command
|
21
|
+
[<tt>init</tt>] Create a new GLI-based project
|
22
|
+
|
23
|
+
=== <tt>help [command]</tt>
|
24
|
+
|
25
|
+
Shows list of commands or help for one command
|
26
|
+
|
27
|
+
=== <tt>init project_name [command[ command]*]</tt>
|
28
|
+
|
29
|
+
Create a new GLI-based project
|
30
|
+
|
31
|
+
*Aliases*
|
32
|
+
* <tt><b>scaffold</b></tt>
|
33
|
+
|
34
|
+
This will create a scaffold command line project that uses GLI
|
35
|
+
for command line processing. Specifically, this will create
|
36
|
+
an executable ready to go, as well as a lib and test directory, all
|
37
|
+
inside the directory named for your project
|
38
|
+
|
39
|
+
|
40
|
+
==== Options
|
41
|
+
These options are specified *after* the command.
|
42
|
+
|
43
|
+
[<tt>-e, --ext</tt>] Create an ext dir
|
44
|
+
[<tt>--force</tt>] Overwrite/ignore existing files and directories
|
45
|
+
[<tt>--notest</tt>] Do not create a test dir
|
data/lib/gli.rb
CHANGED
@@ -3,6 +3,7 @@ require 'gli/command.rb'
|
|
3
3
|
require 'gli/switch.rb'
|
4
4
|
require 'gli/flag.rb'
|
5
5
|
require 'support/help.rb'
|
6
|
+
require 'support/rdoc.rb'
|
6
7
|
|
7
8
|
# A means to define and parse a command line interface that works as
|
8
9
|
# Git's does, in that you specify global options, a command name, command
|
@@ -10,7 +11,7 @@ require 'support/help.rb'
|
|
10
11
|
module GLI
|
11
12
|
extend self
|
12
13
|
|
13
|
-
VERSION = '0.1
|
14
|
+
VERSION = '0.2.1'
|
14
15
|
|
15
16
|
@@program_name = $0.split(/\//)[-1]
|
16
17
|
@@post_block = nil
|
@@ -25,8 +26,14 @@ module GLI
|
|
25
26
|
clear_nexts
|
26
27
|
end
|
27
28
|
|
28
|
-
# describe the next switch, flag, or command
|
29
|
+
# describe the next switch, flag, or command. This should be a
|
30
|
+
# short, one-line description
|
29
31
|
def desc(description); @@next_desc = description; end
|
32
|
+
|
33
|
+
# Provide a longer, more detailed description. This
|
34
|
+
# will be reformatted and wrapped to fit in 80 columns
|
35
|
+
def long_desc(long_desc); @@next_long_desc = long_desc; end
|
36
|
+
|
30
37
|
# describe the argument name of the next flag
|
31
38
|
def arg_name(name); @@next_arg_name = name; end
|
32
39
|
# set the default value of the next flag
|
@@ -34,21 +41,21 @@ module GLI
|
|
34
41
|
|
35
42
|
# Create a flag, which is a switch that takes an argument
|
36
43
|
def flag(names)
|
37
|
-
flag = Flag.new(names,@@next_desc,@@next_arg_name,@@next_default_value)
|
44
|
+
flag = Flag.new(names,@@next_desc,@@next_arg_name,@@next_default_value,@@next_long_desc)
|
38
45
|
flags[flag.name] = flag
|
39
46
|
clear_nexts
|
40
47
|
end
|
41
48
|
|
42
49
|
# Create a switch
|
43
50
|
def switch(names)
|
44
|
-
switch = Switch.new(names,@@next_desc)
|
51
|
+
switch = Switch.new(names,@@next_desc,@@next_long_desc)
|
45
52
|
switches[switch.name] = switch
|
46
53
|
clear_nexts
|
47
54
|
end
|
48
55
|
|
49
56
|
# Define a command.
|
50
57
|
def command(names)
|
51
|
-
command = Command.new(names,@@next_desc,@@next_arg_name)
|
58
|
+
command = Command.new(names,@@next_desc,@@next_arg_name,@@next_long_desc)
|
52
59
|
commands[command.name] = command
|
53
60
|
yield command
|
54
61
|
clear_nexts
|
@@ -72,15 +79,18 @@ module GLI
|
|
72
79
|
end
|
73
80
|
|
74
81
|
# Define a block to run if an error occurs.
|
75
|
-
# The block will receive
|
76
|
-
# It should return false to avoid the built-in error handling
|
82
|
+
# The block will receive any Exception that was caught.
|
83
|
+
# It should return false to avoid the built-in error handling (which basically just
|
84
|
+
# prints out a message)
|
77
85
|
def on_error(&a_proc)
|
78
86
|
@@error_block = a_proc
|
79
87
|
end
|
80
88
|
|
81
89
|
# Runs whatever command is needed based on the arguments.
|
82
90
|
def run(args)
|
83
|
-
|
91
|
+
rdoc = RDocCommand.new
|
92
|
+
commands[:rdoc] = rdoc if !commands[:rdoc]
|
93
|
+
commands[:help] = DefaultHelpCommand.new(rdoc) if !commands[:help]
|
84
94
|
begin
|
85
95
|
global_options,command,options,arguments = parse_options(args)
|
86
96
|
proceed = true
|
@@ -90,15 +100,12 @@ module GLI
|
|
90
100
|
command.execute(global_options,options,arguments)
|
91
101
|
@@post_block.call(global_options,command,options,arguments) if @@post_block
|
92
102
|
end
|
93
|
-
rescue
|
103
|
+
rescue Exception => ex
|
94
104
|
regular_error_handling = true
|
95
105
|
regular_error_handling = @@error_block.call(ex) if @@error_block
|
96
106
|
|
97
107
|
if regular_error_handling
|
98
|
-
puts "error: #{ex}"
|
99
|
-
puts
|
100
|
-
help = commands[:help]
|
101
|
-
help.execute({},{},[])
|
108
|
+
puts "error: #{ex.message}"
|
102
109
|
end
|
103
110
|
end
|
104
111
|
end
|
@@ -141,6 +148,7 @@ module GLI
|
|
141
148
|
@@next_desc = nil
|
142
149
|
@@next_arg_name = nil
|
143
150
|
@@next_default_value = nil
|
151
|
+
@@next_long_desc = nil
|
144
152
|
end
|
145
153
|
|
146
154
|
clear_nexts
|
@@ -175,7 +183,7 @@ module GLI
|
|
175
183
|
if !command
|
176
184
|
command_name = args.shift
|
177
185
|
command = find_command(command_name)
|
178
|
-
raise
|
186
|
+
raise "Unknown command '#{command_name}'" if !command
|
179
187
|
return parse_options_helper(args,global_options,command,command_options,arguments)
|
180
188
|
else
|
181
189
|
return global_options,command,command_options,arguments | args
|
@@ -225,16 +233,16 @@ module GLI
|
|
225
233
|
try_me.delete arg
|
226
234
|
break
|
227
235
|
end
|
228
|
-
raise
|
236
|
+
raise "Unknown argument #{arg}" if arg =~ /^\-/
|
229
237
|
end
|
230
238
|
return [global_options,command,command_options,try_me | rest]
|
231
239
|
else
|
232
240
|
# Now we have our command name
|
233
241
|
command_name = try_me.shift
|
234
|
-
raise
|
242
|
+
raise "Unknown argument #{command_name}" if command_name =~ /^\-/
|
235
243
|
|
236
244
|
command = find_command(command_name)
|
237
|
-
raise
|
245
|
+
raise "Unknown command '#{command_name}'" if !command
|
238
246
|
|
239
247
|
return parse_options_helper(rest,global_options,command,command_options,arguments)
|
240
248
|
end
|
@@ -252,14 +260,4 @@ module GLI
|
|
252
260
|
nil
|
253
261
|
end
|
254
262
|
|
255
|
-
# Raise this if you get an argument you were not expecting
|
256
|
-
class UnknownArgumentException < Exception
|
257
|
-
end
|
258
|
-
|
259
|
-
class UnknownCommandException < Exception
|
260
|
-
end
|
261
|
-
|
262
|
-
# Raise this if your command doesn't get the number of arguments you were expecting
|
263
|
-
class MissingArgumentException < Exception
|
264
|
-
end
|
265
263
|
end
|
data/lib/gli/command.rb
CHANGED
@@ -9,13 +9,16 @@ module GLI
|
|
9
9
|
# [names] the name or names of this command (symbol or Array of symbols)
|
10
10
|
# [description] description of this command
|
11
11
|
# [arguments_name] description of the arguments, or nil if this command doesn't take arguments
|
12
|
+
# [long_desc] a longer description of the command, possibly with multiple lines and text formatting
|
12
13
|
#
|
13
|
-
def initialize(names,description,arguments_name=nil)
|
14
|
-
super(names,description)
|
14
|
+
def initialize(names,description,arguments_name=nil,long_desc=nil)
|
15
|
+
super(names,description,long_desc)
|
15
16
|
@arguments_description = arguments_name || ''
|
16
17
|
clear_nexts
|
17
18
|
end
|
18
19
|
|
20
|
+
def arguments_description; @arguments_description; end
|
21
|
+
|
19
22
|
def names
|
20
23
|
all_forms
|
21
24
|
end
|
@@ -5,9 +5,11 @@ module GLI
|
|
5
5
|
attr_reader :name
|
6
6
|
attr_reader :aliases
|
7
7
|
attr_reader :description
|
8
|
+
attr_reader :long_description
|
8
9
|
|
9
|
-
def initialize(names,description)
|
10
|
+
def initialize(names,description,long_description=nil)
|
10
11
|
@description = description
|
12
|
+
@long_description = long_description
|
11
13
|
@name,@aliases,@names = parse_names(names)
|
12
14
|
end
|
13
15
|
|
@@ -15,6 +17,10 @@ module GLI
|
|
15
17
|
all_forms
|
16
18
|
end
|
17
19
|
|
20
|
+
def <=>(other)
|
21
|
+
self.name.to_s <=> other.name.to_s
|
22
|
+
end
|
23
|
+
|
18
24
|
private
|
19
25
|
# Returns a string of all possible forms
|
20
26
|
# of this flag. Mostly intended for printing
|
data/lib/gli/flag.rb
CHANGED
@@ -6,8 +6,8 @@ module GLI
|
|
6
6
|
|
7
7
|
attr_reader :default_value
|
8
8
|
|
9
|
-
def initialize(names,description,argument_name=nil,default=nil)
|
10
|
-
super(names,description)
|
9
|
+
def initialize(names,description,argument_name=nil,default=nil,long_desc=nil)
|
10
|
+
super(names,description,long_desc)
|
11
11
|
@argument_name = argument_name || "arg"
|
12
12
|
@default_value = default
|
13
13
|
end
|
@@ -24,7 +24,7 @@ module GLI
|
|
24
24
|
args.delete_at index
|
25
25
|
return value
|
26
26
|
else
|
27
|
-
raise
|
27
|
+
raise "#{matched} requires an argument"
|
28
28
|
end
|
29
29
|
else
|
30
30
|
return value
|
@@ -38,7 +38,7 @@ module GLI
|
|
38
38
|
if @names[arg]
|
39
39
|
return [true,arg,nil] if arg.length == 2
|
40
40
|
# This means we matched the long-form, but there's no argument
|
41
|
-
raise
|
41
|
+
raise "#{arg} requires an argument via #{arg}=argument"
|
42
42
|
end
|
43
43
|
@names.keys.each() do |name|
|
44
44
|
match_string = "^#{name}=(.*)$"
|
data/lib/gli/switch.rb
CHANGED
@@ -4,8 +4,8 @@ module GLI
|
|
4
4
|
# Defines a command line switch
|
5
5
|
class Switch < CommandLineToken
|
6
6
|
|
7
|
-
def initialize(names,description)
|
8
|
-
super(names,description)
|
7
|
+
def initialize(names,description,long_desc=nil)
|
8
|
+
super(names,description,long_desc)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Given the argument list, scans it looking for this switch
|
data/lib/support/help.rb
CHANGED
@@ -3,7 +3,8 @@ require 'gli/command'
|
|
3
3
|
|
4
4
|
module GLI
|
5
5
|
class DefaultHelpCommand < Command
|
6
|
-
def initialize
|
6
|
+
def initialize(*omit_from_list)
|
7
|
+
@omit_from_list = omit_from_list
|
7
8
|
super(:help,'Shows list of commands or help for one command','[command]')
|
8
9
|
end
|
9
10
|
|
@@ -33,7 +34,8 @@ module GLI
|
|
33
34
|
|
34
35
|
def list_commands
|
35
36
|
puts 'Commands:'
|
36
|
-
|
37
|
+
commands_to_show = GLI.commands.reject{ |name,c| @omit_from_list.include?(c) }
|
38
|
+
output_command_tokens_for_help(commands_to_show,:names)
|
37
39
|
end
|
38
40
|
|
39
41
|
def list_one_command_help(command_name)
|
@@ -42,6 +44,10 @@ module GLI
|
|
42
44
|
puts command.usage
|
43
45
|
description = wrap(command.description,4)
|
44
46
|
puts " #{description}"
|
47
|
+
if command.long_description
|
48
|
+
puts
|
49
|
+
puts " #{wrap(command.long_description,4)}"
|
50
|
+
end
|
45
51
|
all_options = command.switches.merge(command.flags)
|
46
52
|
if !all_options.empty?
|
47
53
|
puts
|
data/lib/support/rdoc.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'gli'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module GLI
|
5
|
+
class RDocCommand < Command
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super(:rdoc,'Generates RDoc for your command line interface')
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(g,o,a)
|
12
|
+
File.open("#{GLI.program_name}.rdoc",'w') do |file|
|
13
|
+
file << "= <tt>#{GLI.program_name}</tt>\n\n"
|
14
|
+
file << " "
|
15
|
+
file << GLI.program_name
|
16
|
+
file << " "
|
17
|
+
global_options = GLI.switches.merge(GLI.flags)
|
18
|
+
if (global_options && global_options.length > 0)
|
19
|
+
file << "[global options] "
|
20
|
+
end
|
21
|
+
file << "command_name"
|
22
|
+
file << " [command-specific options]"
|
23
|
+
file << " [--] arguments...\n\n"
|
24
|
+
file << "* Use the command +help+ to get a summary of commands\n"
|
25
|
+
file << "* Use the command <tt>help command_name</tt> to get a help for +command_name+\n"
|
26
|
+
file << "* Use <tt>--</tt> to stop command line argument processing; useful if your arguments have dashes in them\n"
|
27
|
+
file << "\n"
|
28
|
+
if (global_options && global_options.length > 0)
|
29
|
+
file << "== Global Options\n"
|
30
|
+
file << "These options are available for any command and are specified before the name of the command\n\n"
|
31
|
+
output_flags(file,global_options)
|
32
|
+
end
|
33
|
+
file << "== Commands\n"
|
34
|
+
GLI.commands.values.sort.each do |command|
|
35
|
+
next if command == self
|
36
|
+
file << "[<tt>#{command.name}</tt>] #{command.description}\n"
|
37
|
+
end
|
38
|
+
file << "\n"
|
39
|
+
|
40
|
+
GLI.commands.values.sort.each do |command|
|
41
|
+
next if command == self
|
42
|
+
file << "=== <tt>#{command.name} #{command.arguments_description}</tt>\n\n"
|
43
|
+
file << "#{command.description}\n\n"
|
44
|
+
if command.aliases
|
45
|
+
file << "*Aliases*\n"
|
46
|
+
command.aliases.each do |al|
|
47
|
+
file << "* <tt><b>#{al}</b></tt>\n"
|
48
|
+
end
|
49
|
+
file << "\n"
|
50
|
+
end
|
51
|
+
all_options = command.switches.merge(command.flags)
|
52
|
+
if (all_options && all_options.length > 0)
|
53
|
+
file << "#{command.long_description}\n\n"
|
54
|
+
file << "==== Options\n"
|
55
|
+
file << "These options are specified *after* the command.\n\n"
|
56
|
+
output_flags(file,all_options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def output_flags(file,flags)
|
63
|
+
flags.values.sort.each do |flag|
|
64
|
+
file << "[<tt>#{flag.usage}</tt>] #{flag.description}"
|
65
|
+
if flag.kind_of? Flag
|
66
|
+
file << " <i>( default: <tt>#{flag.default_value}</tt>)</i>" if flag.default_value
|
67
|
+
end
|
68
|
+
file << "\n"
|
69
|
+
if flag.long_description
|
70
|
+
file << "\n"
|
71
|
+
# 12 is 4 for tt, 5 for /tt, 2 for the brackets and 1 for spacing
|
72
|
+
(flag.usage.length + 12).times { file << " " }
|
73
|
+
file << "#{flag.long_description}\n\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/support/scaffold.rb
CHANGED
@@ -12,6 +12,105 @@ module GLI
|
|
12
12
|
|
13
13
|
if mkdirs(dirs,force,dry_run)
|
14
14
|
mk_binfile(root_dir,create_ext_dir,force,dry_run,project_name,commands)
|
15
|
+
mk_readme(root_dir,dry_run,project_name)
|
16
|
+
mk_gemspec(root_dir,dry_run,project_name)
|
17
|
+
mk_rakefile(root_dir,dry_run,project_name,create_test_dir)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.mk_readme(root_dir,dry_run,project_name)
|
22
|
+
return if dry_run
|
23
|
+
File.open("#{root_dir}/#{project_name}/README.rdoc",'w') do |file|
|
24
|
+
file << "= #{project_name}\n\n"
|
25
|
+
file << "Describe your project here\n\n"
|
26
|
+
file << ":include:#{project_name}.rdoc\n\n"
|
27
|
+
end
|
28
|
+
File.open("#{root_dir}/#{project_name}/#{project_name}.rdoc",'w') do |file|
|
29
|
+
file << "= #{project_name}\n\n"
|
30
|
+
file << "Generate this with\n #{project_name} rdoc\nAfter you have described your command line interface"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.mk_gemspec(root_dir,dry_run,project_name)
|
35
|
+
return if dry_run
|
36
|
+
File.open("#{root_dir}/#{project_name}/#{project_name}.gemspec",'w') do |file|
|
37
|
+
file.puts <<EOS
|
38
|
+
spec = Gem::Specification.new do |s|
|
39
|
+
s.name = '#{project_name}'
|
40
|
+
s.version = '0.0.01'
|
41
|
+
s.author = 'Your Name Here'
|
42
|
+
s.email = 'your@email.address.com'
|
43
|
+
s.homepage = 'http://your.website.com'
|
44
|
+
s.platform = Gem::Platform::RUBY
|
45
|
+
s.summary = 'A description of your project'
|
46
|
+
# Add your other files here if you make them
|
47
|
+
s.files = %w(
|
48
|
+
bin/#{project_name}
|
49
|
+
)
|
50
|
+
s.require_paths << 'lib'
|
51
|
+
s.has_rdoc = true
|
52
|
+
s.extra_rdoc_files = ['README.rdoc','#{project_name}.rdoc']
|
53
|
+
s.rdoc_options << '--title' << 'Git Like Interface' << '--main' << 'README.rdoc' << '-ri'
|
54
|
+
s.bindir = 'bin'
|
55
|
+
s.executables << '#{project_name}'
|
56
|
+
end
|
57
|
+
EOS
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.mk_rakefile(root_dir,dry_run,project_name,create_test_dir)
|
62
|
+
return if dry_run
|
63
|
+
File.open("#{root_dir}/#{project_name}/Rakefile",'w') do |file|
|
64
|
+
file.puts <<EOS
|
65
|
+
require 'rake/clean'
|
66
|
+
require 'rubygems'
|
67
|
+
require 'rake/gempackagetask'
|
68
|
+
require 'rake/rdoctask'
|
69
|
+
|
70
|
+
Rake::RDocTask.new do |rd|
|
71
|
+
rd.main = "README.rdoc"
|
72
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
73
|
+
rd.title = 'Your application title'
|
74
|
+
end
|
75
|
+
|
76
|
+
spec = eval(File.read('#{project_name}.gemspec'))
|
77
|
+
|
78
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
79
|
+
end
|
80
|
+
|
81
|
+
EOS
|
82
|
+
if create_test_dir
|
83
|
+
file.puts <<EOS
|
84
|
+
require 'rake/testtask'
|
85
|
+
Rake::TestTask.new do |t|
|
86
|
+
t.libs << "test"
|
87
|
+
t.test_files = FileList['test/tc_*.rb']
|
88
|
+
end
|
89
|
+
|
90
|
+
task :default => :test
|
91
|
+
EOS
|
92
|
+
File.open("#{root_dir}/#{project_name}/test/tc_nothing.rb",'w') do |test_file|
|
93
|
+
test_file.puts <<EOS
|
94
|
+
require 'test/unit'
|
95
|
+
require 'test/unit/ui/console/testrunner'
|
96
|
+
|
97
|
+
class TC_testNothing < Test::Unit::TestCase
|
98
|
+
|
99
|
+
def setup
|
100
|
+
end
|
101
|
+
|
102
|
+
def teardown
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_the_truth
|
106
|
+
assert true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
EOS
|
110
|
+
end
|
111
|
+
else
|
112
|
+
file.puts "task :default => :package\n"
|
113
|
+
end
|
15
114
|
end
|
16
115
|
end
|
17
116
|
|
@@ -53,7 +152,11 @@ command :#{command} do |c|
|
|
53
152
|
c.default_value 'default'
|
54
153
|
c.flag :s
|
55
154
|
c.action do |global_options,options,args|
|
155
|
+
|
56
156
|
# Your command logic here
|
157
|
+
|
158
|
+
# If you have any errors, just raise them
|
159
|
+
# raise "that command made no sense"
|
57
160
|
end
|
58
161
|
end
|
59
162
|
EOS
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Copeland
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-12 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
16
|
+
description: An application and API for describing command line interfaces that can be used to quickly create a shell for executing command-line tasks. The command line user interface is similar to Gits, in that it takes global options, a command, command-specific options, and arguments
|
17
17
|
email: davidcopeland@naildrivin5.com
|
18
18
|
executables:
|
19
19
|
- gli
|
@@ -21,6 +21,7 @@ extensions: []
|
|
21
21
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README.rdoc
|
24
|
+
- gli.rdoc
|
24
25
|
files:
|
25
26
|
- lib/gli/command.rb
|
26
27
|
- lib/gli/command_line_token.rb
|
@@ -28,11 +29,15 @@ files:
|
|
28
29
|
- lib/gli/switch.rb
|
29
30
|
- lib/gli.rb
|
30
31
|
- lib/support/help.rb
|
32
|
+
- lib/support/rdoc.rb
|
31
33
|
- lib/support/scaffold.rb
|
32
34
|
- bin/gli
|
33
35
|
- README.rdoc
|
36
|
+
- gli.rdoc
|
34
37
|
has_rdoc: true
|
35
38
|
homepage: http://davetron5000.github.com/gli
|
39
|
+
licenses: []
|
40
|
+
|
36
41
|
post_install_message:
|
37
42
|
rdoc_options:
|
38
43
|
- --title
|
@@ -58,9 +63,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
63
|
requirements: []
|
59
64
|
|
60
65
|
rubyforge_project: gli
|
61
|
-
rubygems_version: 1.3.
|
66
|
+
rubygems_version: 1.3.4
|
62
67
|
signing_key:
|
63
|
-
specification_version:
|
68
|
+
specification_version: 3
|
64
69
|
summary: A Git Like Interface for building command line apps
|
65
70
|
test_files: []
|
66
71
|
|