gli 2.0.0.rc5 → 2.0.0.rc6
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/.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
|