gli 2.0.0.rc5 → 2.0.0.rc6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/README.rdoc +3 -0
- data/bin/gli +7 -2
- data/features/gli_executable.feature +2 -1
- data/features/gli_init.feature +2 -0
- data/features/todo.feature +15 -2
- data/gli.rdoc +56 -29
- data/lib/gli.rb +2 -0
- data/lib/gli/app.rb +1 -0
- data/lib/gli/app_support.rb +6 -1
- data/lib/gli/commands/compound_command.rb +2 -2
- data/lib/gli/commands/doc.rb +201 -0
- data/lib/gli/commands/initconfig.rb +15 -13
- data/lib/gli/commands/rdoc_document_listener.rb +112 -0
- data/lib/gli/commands/scaffold.rb +0 -1
- data/lib/gli/options.rb +3 -0
- data/lib/gli/switch.rb +1 -0
- data/lib/gli/version.rb +1 -1
- data/test/roodi.yaml +1 -1
- data/test/tc_doc.rb +315 -0
- data/test/tc_help.rb +7 -1
- data/test/tc_options.rb +13 -0
- metadata +373 -259
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -103,3 +103,6 @@ License:: Distributes under the Apache License, see LICENSE.txt in the source di
|
|
103
103
|
* [http://www.github.com/davetron5000/gli/wiki] - Documentation Wiki
|
104
104
|
* [http://www.github.com/davetron5000/gli/wiki/Changelog] - Changelog
|
105
105
|
|
106
|
+
= <code>gli</code> CLI documentation
|
107
|
+
|
108
|
+
:include:gli.rdoc
|
data/bin/gli
CHANGED
@@ -5,7 +5,7 @@ require 'gli/commands/scaffold'
|
|
5
5
|
|
6
6
|
include GLI::App
|
7
7
|
|
8
|
-
program_desc '
|
8
|
+
program_desc 'create scaffolding for a GLI-powered application'
|
9
9
|
|
10
10
|
version GLI::VERSION
|
11
11
|
|
@@ -14,7 +14,12 @@ switch :v, :desc => 'Be verbose'
|
|
14
14
|
switch :n, :desc => 'Dry run; don''t change the disk'
|
15
15
|
|
16
16
|
desc 'Root dir of project'
|
17
|
-
long_desc
|
17
|
+
long_desc <<EOS
|
18
|
+
This is the directory where the project''s directory will be made, so if you
|
19
|
+
specify a project name ''foo'' and the root dir of ''.'', the directory
|
20
|
+
''./foo'' will be created'
|
21
|
+
EOS
|
22
|
+
|
18
23
|
flag :r,:root, :default_value => '.'
|
19
24
|
|
20
25
|
desc 'Create a new GLI-based project'
|
@@ -13,7 +13,7 @@ Feature: The GLI executable works as intended
|
|
13
13
|
And the output should contain:
|
14
14
|
"""
|
15
15
|
NAME
|
16
|
-
gli -
|
16
|
+
gli - create scaffolding for a GLI-powered application
|
17
17
|
|
18
18
|
SYNOPSIS
|
19
19
|
gli [global options] command [command options] [arguments...]
|
@@ -27,6 +27,7 @@ Feature: The GLI executable works as intended
|
|
27
27
|
-n - Dry run; dont change the disk
|
28
28
|
-r, --root=arg - Root dir of project (default: .)
|
29
29
|
-v - Be verbose
|
30
|
+
--version -
|
30
31
|
|
31
32
|
COMMANDS
|
32
33
|
help - Shows a list of commands or help for one command
|
data/features/gli_init.feature
CHANGED
@@ -66,6 +66,7 @@ Feature: The scaffold GLI generates works
|
|
66
66
|
the default)
|
67
67
|
--help - Show this message
|
68
68
|
-s, --[no-]switch - Describe some switch here
|
69
|
+
--version -
|
69
70
|
|
70
71
|
COMMANDS
|
71
72
|
add - Describe add here
|
@@ -91,6 +92,7 @@ Feature: The scaffold GLI generates works
|
|
91
92
|
the default)
|
92
93
|
--help - Show this message
|
93
94
|
-s, --[no-]switch - Describe some switch here
|
95
|
+
--version -
|
94
96
|
|
95
97
|
COMMANDS
|
96
98
|
add - Describe add here
|
data/features/todo.feature
CHANGED
@@ -8,8 +8,8 @@ Feature: The todo app has a nice user interface
|
|
8
8
|
And my terminal size is "80x24"
|
9
9
|
And todo's bin directory is in my path
|
10
10
|
|
11
|
-
Scenario: Getting Help for todo in general
|
12
|
-
When I successfully run `todo help
|
11
|
+
Scenario Outline: Getting Help for todo in general
|
12
|
+
When I successfully run `todo <help>`
|
13
13
|
Then the output should contain:
|
14
14
|
"""
|
15
15
|
NAME
|
@@ -26,6 +26,7 @@ Feature: The todo app has a nice user interface
|
|
26
26
|
--help - Show this message
|
27
27
|
--[no-]otherswitch -
|
28
28
|
--[no-]switch -
|
29
|
+
--version -
|
29
30
|
|
30
31
|
COMMANDS
|
31
32
|
chained -
|
@@ -38,6 +39,10 @@ Feature: The todo app has a nice user interface
|
|
38
39
|
ls - LS things, such as tasks or contexts
|
39
40
|
second -
|
40
41
|
"""
|
42
|
+
Examples:
|
43
|
+
| help |
|
44
|
+
| help |
|
45
|
+
| --version |
|
41
46
|
|
42
47
|
Scenario: Getting Help for a top level command of todo
|
43
48
|
When I successfully run `todo help list`
|
@@ -169,6 +174,14 @@ Feature: The todo app has a nice user interface
|
|
169
174
|
When I successfully run `todo --flag foo --switch --no-otherswitch initconfig`
|
170
175
|
Then the config file should contain a section for each command and subcommand
|
171
176
|
|
177
|
+
Scenario: Init Config makes a reasonable config file if one is there and we force it
|
178
|
+
Given a clean home directory
|
179
|
+
And I successfully run `todo --flag foo --switch --no-otherswitch initconfig`
|
180
|
+
When I run `todo --flag foo --switch --no-otherswitch initconfig`
|
181
|
+
Then the exit status should not be 0
|
182
|
+
When I run `todo --flag foo --switch --no-otherswitch initconfig --force`
|
183
|
+
Then the exit status should be 0
|
184
|
+
|
172
185
|
Scenario: Configuration percolates to the app
|
173
186
|
Given a clean home directory
|
174
187
|
And a config file that specifies defaults for some commands with subcommands
|
data/gli.rdoc
CHANGED
@@ -1,51 +1,78 @@
|
|
1
|
-
|
1
|
+
== gli - gli allows you to create the scaffolding for a GLI-powered application
|
2
2
|
|
3
|
-
|
4
|
-
gli [global options] command_name [command-specific options] [--] arguments...
|
3
|
+
v2.0.0.rc5
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
* Use <tt>--</tt> to stop command line argument processing; useful if your arguments have dashes in them
|
5
|
+
=== Global Options
|
6
|
+
=== -r arg
|
9
7
|
|
10
|
-
|
11
|
-
These options are available for any command and are specified before the name of the command
|
8
|
+
Root dir of project
|
12
9
|
|
13
|
-
[
|
14
|
-
[
|
10
|
+
[Aliases] --root
|
11
|
+
[Default Value] .
|
12
|
+
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
|
15
13
|
|
16
|
-
|
14
|
+
=== --help
|
15
|
+
Show this message
|
17
16
|
|
18
|
-
[<tt>-v</tt>] Be verbose
|
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
17
|
|
23
|
-
=== <tt>help [command]</tt>
|
24
18
|
|
25
|
-
Shows list of commands or help for one command
|
26
19
|
|
27
|
-
|
20
|
+
=== -n
|
21
|
+
Dry run; dont change the disk
|
28
22
|
|
29
|
-
==== Options
|
30
|
-
These options are specified *after* the command.
|
31
23
|
|
32
|
-
[<tt>-c, --completion</tt>] List all commands one line at a time, for use with shell completion ([command] argument is partial command to match)
|
33
|
-
=== <tt>init project_name [command[ command]*]</tt>
|
34
24
|
|
25
|
+
|
26
|
+
=== -v
|
27
|
+
Be verbose
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
=== --version
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
=== Commands
|
39
|
+
==== help command
|
40
|
+
Shows a list of commands or help for one command
|
41
|
+
|
42
|
+
|
43
|
+
Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
|
44
|
+
==== init project_name [command[ command]*]
|
35
45
|
Create a new GLI-based project
|
36
46
|
|
37
|
-
|
38
|
-
* <tt><b>scaffold</b></tt>
|
47
|
+
[Aliases] scaffold
|
39
48
|
|
40
49
|
This will create a scaffold command line project that uses GLI
|
41
50
|
for command line processing. Specifically, this will create
|
42
51
|
an executable ready to go, as well as a lib and test directory, all
|
43
52
|
inside the directory named for your project
|
53
|
+
===== Options
|
54
|
+
===== -e
|
55
|
+
Create an ext dir
|
56
|
+
|
57
|
+
[Aliases] --[no-]ext
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
===== --[no-]force
|
62
|
+
Overwrite/ignore existing files and directories
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
===== --notest
|
68
|
+
Do not create a test or features dir
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
===== --[no-]rvmrc
|
74
|
+
Create an .rvmrc based on your current RVM setup
|
75
|
+
|
44
76
|
|
45
77
|
|
46
|
-
==== Options
|
47
|
-
These options are specified *after* the command.
|
48
78
|
|
49
|
-
[<tt>-e, --ext</tt>] Create an ext dir
|
50
|
-
[<tt>--force</tt>] Overwrite/ignore existing files and directories
|
51
|
-
[<tt>--notest</tt>] Do not create a test dir
|
data/lib/gli.rb
CHANGED
data/lib/gli/app.rb
CHANGED
data/lib/gli/app_support.rb
CHANGED
@@ -32,6 +32,11 @@ module GLI
|
|
32
32
|
@version
|
33
33
|
end
|
34
34
|
|
35
|
+
# Get the default command for the entire app
|
36
|
+
def get_default_command
|
37
|
+
@default_command
|
38
|
+
end
|
39
|
+
|
35
40
|
# Runs whatever command is needed based on the arguments.
|
36
41
|
#
|
37
42
|
# +args+:: the command line ARGV array
|
@@ -113,7 +118,7 @@ module GLI
|
|
113
118
|
end
|
114
119
|
|
115
120
|
def commands # :nodoc:
|
116
|
-
@commands ||= {:help => GLI::Commands::Help.new(self)}
|
121
|
+
@commands ||= { :help => GLI::Commands::Help.new(self), :_doc => GLI::Commands::Doc.new(self) }
|
117
122
|
end
|
118
123
|
|
119
124
|
def pre_block
|
@@ -13,11 +13,11 @@ module GLI
|
|
13
13
|
|
14
14
|
check_for_unknown_commands!(base,command_names)
|
15
15
|
|
16
|
-
@
|
16
|
+
@wrapped_commands = command_names.map { |name| self.class.find_command(base,name) }
|
17
17
|
end
|
18
18
|
|
19
19
|
def execute(global_options,options,arguments) #:nodoc:
|
20
|
-
@
|
20
|
+
@wrapped_commands.each do |command|
|
21
21
|
command.execute(global_options,options,arguments)
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
module GLI
|
2
|
+
module Commands
|
3
|
+
# Takes a DocListener which will be called with all of the meta-data and documentation
|
4
|
+
# about your app, so as to create documentation in whatever format you want
|
5
|
+
class Doc < Command
|
6
|
+
FORMATS = {
|
7
|
+
'rdoc' => GLI::Commands::RdocDocumentListener,
|
8
|
+
}
|
9
|
+
# Create the Doc generator based on the GLI app passed in
|
10
|
+
def initialize(app)
|
11
|
+
super(:names => "_doc",
|
12
|
+
:description => "Generate documentation of your application's UI",
|
13
|
+
:long_desc => "Introspects your application's UI meta-data to generate documentation in a variety of formats. This is intended to be extensible via the DocumentListener interface, so that you can provide your own documentation formats without them being a part of GLI",
|
14
|
+
:skips_pre => true, :skips_post => true, :skips_around => true, :hidden => true)
|
15
|
+
|
16
|
+
@app = app
|
17
|
+
|
18
|
+
desc 'The format name of the documentation to generate or the class name to use to generate it'
|
19
|
+
default_value 'rdoc'
|
20
|
+
arg_name 'name_or_class'
|
21
|
+
flag :format
|
22
|
+
|
23
|
+
action do |global_options,options,arguments|
|
24
|
+
self.document(format_class(options[:format]).new(global_options,options,arguments))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def nodoc
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generates documentation using the listener
|
33
|
+
def document(document_listener)
|
34
|
+
document_listener.beginning
|
35
|
+
document_listener.program_desc(@app.program_desc)
|
36
|
+
document_listener.version(@app.version_string)
|
37
|
+
if any_options?(@app)
|
38
|
+
document_listener.options
|
39
|
+
end
|
40
|
+
document_flags_and_switches(document_listener,
|
41
|
+
@app.flags.values.sort(&by_name),
|
42
|
+
@app.switches.values.sort(&by_name))
|
43
|
+
if any_options?(@app)
|
44
|
+
document_listener.end_options
|
45
|
+
end
|
46
|
+
document_listener.commands
|
47
|
+
document_commands(document_listener,@app)
|
48
|
+
document_listener.end_commands
|
49
|
+
document_listener.ending
|
50
|
+
end
|
51
|
+
|
52
|
+
# Interface for a listener that is called during various parts of the doc process
|
53
|
+
class DocumentListener
|
54
|
+
# Called before processing begins
|
55
|
+
def beginning
|
56
|
+
abstract!
|
57
|
+
end
|
58
|
+
|
59
|
+
# Called when processing has completed
|
60
|
+
def ending
|
61
|
+
abstract!
|
62
|
+
end
|
63
|
+
|
64
|
+
# Gives you the program description
|
65
|
+
def program_desc(desc)
|
66
|
+
abstract!
|
67
|
+
end
|
68
|
+
|
69
|
+
# Gives you the program version
|
70
|
+
def version(version)
|
71
|
+
abstract!
|
72
|
+
end
|
73
|
+
|
74
|
+
# Called at the start of options for the current context
|
75
|
+
def options
|
76
|
+
abstract!
|
77
|
+
end
|
78
|
+
|
79
|
+
# Called when all options for the current context have been vended
|
80
|
+
def end_options
|
81
|
+
abstract!
|
82
|
+
end
|
83
|
+
|
84
|
+
# Called at the start of commands for the current context
|
85
|
+
def commands
|
86
|
+
abstract!
|
87
|
+
end
|
88
|
+
|
89
|
+
# Called when all commands for the current context have been vended
|
90
|
+
def end_commands
|
91
|
+
abstract!
|
92
|
+
end
|
93
|
+
|
94
|
+
# Gives you a flag in the current context
|
95
|
+
def flag(name,aliases,desc,long_desc,default_value,arg_name,must_match,type)
|
96
|
+
abstract!
|
97
|
+
end
|
98
|
+
|
99
|
+
# Gives you a switch in the current context
|
100
|
+
def switch(name,aliases,desc,long_desc,negetable)
|
101
|
+
abstract!
|
102
|
+
end
|
103
|
+
|
104
|
+
# Gives you the name of the current command in the current context
|
105
|
+
def default_command(name)
|
106
|
+
abstract!
|
107
|
+
end
|
108
|
+
|
109
|
+
# Gives you a command in the current context and creates a new context of this command
|
110
|
+
def command(name,aliases,desc,long_desc,arg_name)
|
111
|
+
abstract!
|
112
|
+
end
|
113
|
+
|
114
|
+
# Ends a command, and "pops" you back up one context
|
115
|
+
def end_command(name)
|
116
|
+
abstract!
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def abstract!
|
121
|
+
raise "Subclass must implement"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def format_class(format_name)
|
128
|
+
FORMATS.fetch(format_name) {
|
129
|
+
begin
|
130
|
+
return format_name.split(/::/).reduce(Kernel) { |context,part| context.const_get(part) }
|
131
|
+
rescue => ex
|
132
|
+
raise IndexError,"Couldn't find formatter or class named #{format_name}"
|
133
|
+
end
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def document_commands(document_listener,context)
|
138
|
+
context.commands.values.reject {|_| _.nodoc }.sort(&by_name).each do |command|
|
139
|
+
document_listener.command(command.name,
|
140
|
+
Array(command.aliases),
|
141
|
+
command.description,
|
142
|
+
command.long_description,
|
143
|
+
command.arguments_description)
|
144
|
+
document_listener.options if any_options?(command)
|
145
|
+
document_flags_and_switches(document_listener,command_flags(command),command_switches(command))
|
146
|
+
document_listener.end_options if any_options?(command)
|
147
|
+
document_listener.commands if any_commands?(command)
|
148
|
+
document_commands(document_listener,command)
|
149
|
+
document_listener.end_commands if any_commands?(command)
|
150
|
+
document_listener.end_command(command.name)
|
151
|
+
end
|
152
|
+
document_listener.default_command(context.get_default_command)
|
153
|
+
end
|
154
|
+
|
155
|
+
def by_name
|
156
|
+
lambda { |a,b| a.name.to_s <=> b.name.to_s }
|
157
|
+
end
|
158
|
+
|
159
|
+
def command_flags(command)
|
160
|
+
command.topmost_ancestor.flags.values.select { |flag| flag.associated_command == command }.sort(&by_name)
|
161
|
+
end
|
162
|
+
|
163
|
+
def command_switches(command)
|
164
|
+
command.topmost_ancestor.switches.values.select { |switch| switch.associated_command == command }.sort(&by_name)
|
165
|
+
end
|
166
|
+
|
167
|
+
def document_flags_and_switches(document_listener,flags,switches)
|
168
|
+
flags.each do |flag|
|
169
|
+
document_listener.flag(flag.name,
|
170
|
+
Array(flag.aliases),
|
171
|
+
flag.description,
|
172
|
+
flag.long_description,
|
173
|
+
flag.default_value,
|
174
|
+
flag.argument_name,
|
175
|
+
flag.must_match,
|
176
|
+
flag.type)
|
177
|
+
end
|
178
|
+
switches.each do |switch|
|
179
|
+
document_listener.switch(switch.name,
|
180
|
+
Array(switch.aliases),
|
181
|
+
switch.description,
|
182
|
+
switch.long_description,
|
183
|
+
switch.negatable)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def any_options?(context)
|
188
|
+
options = if context.kind_of?(Command)
|
189
|
+
command_flags(context) + command_switches(context)
|
190
|
+
else
|
191
|
+
context.flags.values + context.switches.values
|
192
|
+
end
|
193
|
+
!options.empty?
|
194
|
+
end
|
195
|
+
|
196
|
+
def any_commands?(command)
|
197
|
+
!command.commands.empty?
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|