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 CHANGED
@@ -9,3 +9,4 @@ cruddo.rdoc
9
9
  gli.wiki
10
10
  Gemfile.lock
11
11
  results.html
12
+ .rbx
@@ -1,9 +1,14 @@
1
+ notifications:
2
+ email:
3
+ on_success: always
1
4
  script: 'bundle exec rake test features'
2
5
  rvm:
3
6
  - 1.9.2
4
7
  - 1.9.3
5
8
  - 1.8.7
6
9
  - ree
10
+ - ruby-head
11
+ - rbx
7
12
  branches:
8
13
  only:
9
14
  - 'master'
@@ -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 'gli allows you to create the scaffolding for a GLI-powered application'
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 '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'
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 - gli allows you to create the scaffolding for a GLI-powered application
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
@@ -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
@@ -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
- = <tt>gli</tt>
1
+ == gli - gli allows you to create the scaffolding for a GLI-powered application
2
2
 
3
- gli allows you to create the scaffolding for a GLI-powered application
4
- gli [global options] command_name [command-specific options] [--] arguments...
3
+ v2.0.0.rc5
5
4
 
6
- * Use the command +help+ to get a summary of commands
7
- * Use the command <tt>help command_name</tt> to get a help for +command_name+
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
- == Global Options
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
- [<tt>-n</tt>] Dry run; dont change the disk
14
- [<tt>-r, --root=arg</tt>] Root dir of project <i>( default: <tt>.</tt>)</i>
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
- 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
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
- Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
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
- *Aliases*
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
@@ -16,6 +16,8 @@ require 'gli/version.rb'
16
16
  require 'gli/commands/help'
17
17
  require 'gli/commands/compound_command'
18
18
  require 'gli/commands/initconfig'
19
+ require 'gli/commands/rdoc_document_listener'
20
+ require 'gli/commands/doc'
19
21
 
20
22
  module GLI
21
23
  end
@@ -138,6 +138,7 @@ module GLI
138
138
  # +version+:: String containing the version of your application.
139
139
  def version(version)
140
140
  @version = version
141
+ switch :version, :negatable => false
141
142
  end
142
143
 
143
144
  # Call this with +true+ will cause the +global_options+ and
@@ -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
- @commands = command_names.map { |name| self.class.find_command(base,name) }
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
- @commands.each do |command|
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