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
@@ -11,24 +11,26 @@ module GLI
|
|
11
11
|
@filename = config_file_name
|
12
12
|
super(:names => :initconfig,
|
13
13
|
:description => "Initialize the config file using current global options",
|
14
|
-
:long_desc => 'Initializes a configuration file where you can set default options for command line flags, both globally and on a per-command basis. These defaults override the built-in defaults and allow you to omit commonly-used command line flags when invoking this program'
|
14
|
+
:long_desc => 'Initializes a configuration file where you can set default options for command line flags, both globally and on a per-command basis. These defaults override the built-in defaults and allow you to omit commonly-used command line flags when invoking this program',
|
15
|
+
:skips_pre => true,:skips_post => true, :skips_around => true)
|
16
|
+
|
17
|
+
@app_commands = commands
|
18
|
+
@app_flags = flags
|
19
|
+
@app_switches = switches
|
15
20
|
|
16
21
|
self.desc 'force overwrite of existing config file'
|
17
22
|
self.switch :force
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
if options[:force] || !File.exist?(@filename)
|
26
|
-
create_config(global_options,options,arguments)
|
27
|
-
else
|
28
|
-
raise "Not overwriting existing config file #{@filename}, use --force to override"
|
24
|
+
action do |global_options,options,arguments|
|
25
|
+
if options[:force] || !File.exist?(@filename)
|
26
|
+
create_config(global_options,options,arguments)
|
27
|
+
else
|
28
|
+
raise "Not overwriting existing config file #{@filename}, use --force to override"
|
29
|
+
end
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
33
|
+
|
32
34
|
private
|
33
35
|
|
34
36
|
def create_config(global_options,options,arguments)
|
@@ -40,10 +42,10 @@ module GLI
|
|
40
42
|
end
|
41
43
|
}]
|
42
44
|
config[COMMANDS_KEY] = {}
|
43
|
-
@
|
45
|
+
@app_commands.each do |name,command|
|
44
46
|
if (command != self) && (name != :rdoc) && (name != :help)
|
45
47
|
if command != self
|
46
|
-
config[COMMANDS_KEY][name.to_sym] = config_for_command(@
|
48
|
+
config[COMMANDS_KEY][name.to_sym] = config_for_command(@app_commands,name.to_sym)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
module GLI
|
3
|
+
module Commands
|
4
|
+
class RdocDocumentListener
|
5
|
+
|
6
|
+
def initialize(global_options,options,arguments)
|
7
|
+
@io = File.new(File.basename($0) + ".rdoc",'w')
|
8
|
+
@nest = ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def beginning
|
12
|
+
end
|
13
|
+
|
14
|
+
# Called when processing has completed
|
15
|
+
def ending
|
16
|
+
@io.close
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gives you the program description
|
20
|
+
def program_desc(desc)
|
21
|
+
@io.puts "== #{File.basename($0)} - #{desc}"
|
22
|
+
@io.puts
|
23
|
+
end
|
24
|
+
|
25
|
+
# Gives you the program version
|
26
|
+
def version(version)
|
27
|
+
@io.puts "v#{version}"
|
28
|
+
@io.puts
|
29
|
+
end
|
30
|
+
|
31
|
+
def options
|
32
|
+
if @nest.size == 0
|
33
|
+
@io.puts "=== Global Options"
|
34
|
+
else
|
35
|
+
@io.puts "#{@nest}=== Options"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Gives you a flag in the current context
|
40
|
+
def flag(name,aliases,desc,long_desc,default_value,arg_name,must_match,type)
|
41
|
+
usage = "#{add_dashes(name)} #{arg_name || 'arg'}"
|
42
|
+
@io.puts "#{@nest}=== #{usage}"
|
43
|
+
@io.puts
|
44
|
+
@io.puts String(desc).strip
|
45
|
+
@io.puts
|
46
|
+
@io.puts "[Aliases] #{aliases.map { |_| add_dashes(_) }.join(',')}" unless aliases.empty?
|
47
|
+
@io.puts "[Default Value] #{default_value || 'None'}"
|
48
|
+
@io.puts "[Must Match] #{must_match.to_s}" unless must_match.nil?
|
49
|
+
@io.puts String(long_desc).strip
|
50
|
+
@io.puts
|
51
|
+
end
|
52
|
+
|
53
|
+
# Gives you a switch in the current context
|
54
|
+
def switch(name,aliases,desc,long_desc,negetable)
|
55
|
+
if negetable
|
56
|
+
name = "[no-]#{name}" if name.length > 1
|
57
|
+
aliases = aliases.map { |_| _.length > 1 ? "[no-]#{_}" : _ }
|
58
|
+
end
|
59
|
+
@io.puts "#{@nest}=== #{add_dashes(name)}"
|
60
|
+
@io.puts String(desc).strip
|
61
|
+
@io.puts
|
62
|
+
@io.puts "[Aliases] #{aliases.map { |_| add_dashes(_) }.join(',')}\n" unless aliases.empty?
|
63
|
+
@io.puts
|
64
|
+
@io.puts String(long_desc).strip
|
65
|
+
@io.puts
|
66
|
+
end
|
67
|
+
|
68
|
+
def end_options
|
69
|
+
end
|
70
|
+
|
71
|
+
def commands
|
72
|
+
@io.puts "#{@nest}=== Commands"
|
73
|
+
@nest = "#{@nest}="
|
74
|
+
end
|
75
|
+
|
76
|
+
# Gives you a command in the current context and creates a new context of this command
|
77
|
+
def command(name,aliases,desc,long_desc,arg_name)
|
78
|
+
@io.puts "#{@nest}=== #{name} #{arg_name}"
|
79
|
+
@io.puts String(desc).strip
|
80
|
+
@io.puts
|
81
|
+
@io.puts "[Aliases] #{aliases.join(',')}\n" unless aliases.empty?
|
82
|
+
@io.puts
|
83
|
+
@io.puts String(long_desc).strip
|
84
|
+
@nest = "#{@nest}="
|
85
|
+
end
|
86
|
+
|
87
|
+
# Ends a command, and "pops" you back up one context
|
88
|
+
def end_command(name)
|
89
|
+
@nest.gsub!(/=$/,'')
|
90
|
+
end
|
91
|
+
|
92
|
+
# Gives you the name of the current command in the current context
|
93
|
+
def default_command(name)
|
94
|
+
@io.puts "[Default Command] #{name}" unless name.nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
def end_commands
|
98
|
+
@nest.gsub!(/=$/,'')
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def add_dashes(name)
|
104
|
+
name = "-#{name}"
|
105
|
+
name = "-#{name}" if name.length > 2
|
106
|
+
name
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/gli/options.rb
CHANGED
data/lib/gli/switch.rb
CHANGED
data/lib/gli/version.rb
CHANGED
data/test/roodi.yaml
CHANGED
data/test/tc_doc.rb
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class String
|
5
|
+
def blank?
|
6
|
+
self.strip.length == 0
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class NilClass
|
11
|
+
def blank?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Object
|
17
|
+
def blank?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class TC_testDoc < Clean::Test::TestCase
|
23
|
+
include TestHelper
|
24
|
+
|
25
|
+
class TestApp
|
26
|
+
include GLI::App
|
27
|
+
end
|
28
|
+
|
29
|
+
class TestListener
|
30
|
+
@@last = nil
|
31
|
+
def self.last
|
32
|
+
@@last
|
33
|
+
end
|
34
|
+
def initialize(*ignored)
|
35
|
+
@stringio = StringIO.new
|
36
|
+
@indent = ''
|
37
|
+
@@last = self
|
38
|
+
end
|
39
|
+
def options
|
40
|
+
end
|
41
|
+
def end_options
|
42
|
+
end
|
43
|
+
def commands
|
44
|
+
end
|
45
|
+
def end_commands
|
46
|
+
end
|
47
|
+
def beginning
|
48
|
+
@stringio << 'BEGIN' << "\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def ending
|
52
|
+
@stringio << 'END' << "\n"
|
53
|
+
end
|
54
|
+
|
55
|
+
def program_desc(desc)
|
56
|
+
@stringio << desc << "\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
def version(version)
|
60
|
+
@stringio << version << "\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
def default_command(name)
|
64
|
+
@stringio << @indent << "default_command: " << name << "\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
def flag(name,aliases,desc,long_desc,default_value,arg_name,must_match,type)
|
68
|
+
@stringio << @indent << "flag: " << name << "\n"
|
69
|
+
@indent += ' '
|
70
|
+
@stringio << @indent << "aliases: " << aliases.join(',') << "\n" unless aliases.empty?
|
71
|
+
@stringio << @indent << "desc: " << desc << "\n" unless desc.blank?
|
72
|
+
@stringio << @indent << "long_desc: " << long_desc << "\n" unless long_desc.blank?
|
73
|
+
@stringio << @indent << "default_value: " << default_value << "\n" unless default_value.blank?
|
74
|
+
@stringio << @indent << "arg_name: " << arg_name << "\n" unless arg_name.blank?
|
75
|
+
@indent.gsub!(/ $/,'')
|
76
|
+
end
|
77
|
+
|
78
|
+
def switch(name,aliases,desc,long_desc,negatable)
|
79
|
+
@stringio << @indent << "switch: " << name << "\n"
|
80
|
+
@indent += ' '
|
81
|
+
@stringio << @indent << "aliases: " << aliases.join(',') << "\n" unless aliases.empty?
|
82
|
+
@stringio << @indent << "desc: " << desc << "\n" unless desc.blank?
|
83
|
+
@stringio << @indent << "long_desc: " << long_desc << "\n" unless long_desc.blank?
|
84
|
+
@stringio << @indent << "negatable: " << negatable << "\n" unless negatable.blank?
|
85
|
+
@indent.gsub!(/ $/,'')
|
86
|
+
end
|
87
|
+
|
88
|
+
def command(name,aliases,desc,long_desc,arg_name)
|
89
|
+
@stringio << @indent << "command: " << name << "\n"
|
90
|
+
@indent += ' '
|
91
|
+
@stringio << @indent << "aliases: " << aliases.join(',') << "\n" unless aliases.empty?
|
92
|
+
@stringio << @indent << "desc: " << desc << "\n" unless desc.blank?
|
93
|
+
@stringio << @indent << "long_desc: " << long_desc << "\n" unless long_desc.blank?
|
94
|
+
@stringio << @indent << "arg_name: " << arg_name << "\n" unless arg_name.blank?
|
95
|
+
end
|
96
|
+
|
97
|
+
def end_command(name)
|
98
|
+
@indent.gsub!(/ $/,'')
|
99
|
+
@stringio << @indent << "end #{name}" << "\n"
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
@stringio.string
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def setup
|
108
|
+
@@counter = -1 # we pre-increment so this makes 0 first
|
109
|
+
end
|
110
|
+
|
111
|
+
test_that "a GLI app with documentation gets the callbacks for each element" do
|
112
|
+
Given :the_test_app
|
113
|
+
And :the_expected_output
|
114
|
+
And {
|
115
|
+
@documenter = GLI::Commands::Doc.new(@app)
|
116
|
+
@listener = TestListener.new
|
117
|
+
}
|
118
|
+
When {
|
119
|
+
@documenter.document(@listener)
|
120
|
+
}
|
121
|
+
Then {
|
122
|
+
lines_expected = @string.split(/\n/)
|
123
|
+
lines_got = @listener.to_s.split(/\n/)
|
124
|
+
lines_expected.zip(lines_got).each_with_index do |(expected,got),index|
|
125
|
+
assert_equal expected,got,"At index #{index}"
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
test_that "the doc command works as a GLI command" do
|
131
|
+
Given :the_test_app
|
132
|
+
And :the_expected_output
|
133
|
+
And {
|
134
|
+
@documenter = GLI::Commands::Doc.new(@app)
|
135
|
+
@listener = TestListener.new
|
136
|
+
}
|
137
|
+
When {
|
138
|
+
@documenter.execute({},{:format => "TC_testDoc::TestListener"},[])
|
139
|
+
}
|
140
|
+
Then {
|
141
|
+
lines_expected = @string.split(/\n/)
|
142
|
+
lines_got = TestListener.last.to_s.split(/\n/)
|
143
|
+
lines_expected.zip(lines_got).each_with_index do |(expected,got),index|
|
144
|
+
assert_equal expected,got,"At index #{index}"
|
145
|
+
end
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
@@counter = 1
|
152
|
+
def self.counter
|
153
|
+
@@counter += 1
|
154
|
+
@@counter
|
155
|
+
end
|
156
|
+
|
157
|
+
def the_test_app
|
158
|
+
@app = TestApp.new
|
159
|
+
@app.instance_eval do
|
160
|
+
program_desc "program desc"
|
161
|
+
version "1.3.4"
|
162
|
+
|
163
|
+
TC_testDoc.flag_with_everything_specified(self)
|
164
|
+
TC_testDoc.flag_with_everything_omitted(self)
|
165
|
+
TC_testDoc.switch_with_everything_specified(self)
|
166
|
+
TC_testDoc.switch_with_everything_omitted(self)
|
167
|
+
|
168
|
+
desc "command desc"
|
169
|
+
long_desc "command long desc"
|
170
|
+
arg_name "cmd_arg_name"
|
171
|
+
command [:command1,:com1] do |c|
|
172
|
+
TC_testDoc.flag_with_everything_specified(c)
|
173
|
+
TC_testDoc.flag_with_everything_omitted(c)
|
174
|
+
TC_testDoc.switch_with_everything_specified(c)
|
175
|
+
TC_testDoc.switch_with_everything_omitted(c)
|
176
|
+
|
177
|
+
c.desc "subcommand desc"
|
178
|
+
c.long_desc "subcommand long desc"
|
179
|
+
c.arg_name "subcmd_arg_name"
|
180
|
+
c.action { |g,o,a| }
|
181
|
+
c.command [:sub,:subcommand] do |sub|
|
182
|
+
TC_testDoc.flag_with_everything_specified(sub,:subflag)
|
183
|
+
TC_testDoc.flag_with_everything_omitted(sub,:subflag2)
|
184
|
+
TC_testDoc.switch_with_everything_specified(sub,:subswitch)
|
185
|
+
TC_testDoc.switch_with_everything_omitted(sub,:subswitch2)
|
186
|
+
sub.action { |g,o,a| }
|
187
|
+
end
|
188
|
+
c.command [:default] do |sub|
|
189
|
+
sub.action { |g,o,a| }
|
190
|
+
end
|
191
|
+
c.default_command :default
|
192
|
+
end
|
193
|
+
|
194
|
+
command [:command2,:com2] do |c|
|
195
|
+
c.action { |g,o,a| }
|
196
|
+
c.command [:sub2,:subcommand2] do |sub|
|
197
|
+
sub.action { |g,o,a| }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.flag_with_everything_specified(on,name=[:f,:flag])
|
204
|
+
on.flag name,:desc => "flag desc #{counter}",
|
205
|
+
:long_desc => "flag long_desc #{counter}",
|
206
|
+
:default_value => "flag default_value #{counter}",
|
207
|
+
:arg_name => "flag_arg_name_#{counter}",
|
208
|
+
:must_match => /foo.*bar/,
|
209
|
+
:type => Array
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.flag_with_everything_omitted(on,name=[:F,:flag2])
|
213
|
+
on.flag name
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.switch_with_everything_specified(on,name=[:s,:switch])
|
217
|
+
on.switch name, :desc => "switch desc #{counter}",
|
218
|
+
:long_desc => "switch long_desc #{counter}",
|
219
|
+
:negatable => false
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.switch_with_everything_omitted(on,name=[:S,:switch2])
|
223
|
+
on.switch name
|
224
|
+
end
|
225
|
+
def the_expected_output
|
226
|
+
# Oh yeah. Creating a string representing the structure of the calls.
|
227
|
+
@string =<<EOS
|
228
|
+
BEGIN
|
229
|
+
program desc
|
230
|
+
1.3.4
|
231
|
+
flag: F
|
232
|
+
aliases: flag2
|
233
|
+
arg_name: arg
|
234
|
+
flag: f
|
235
|
+
aliases: flag
|
236
|
+
desc: flag desc 0
|
237
|
+
long_desc: flag long_desc 1
|
238
|
+
default_value: flag default_value 2
|
239
|
+
arg_name: flag_arg_name_3
|
240
|
+
switch: S
|
241
|
+
aliases: switch2
|
242
|
+
negatable: true
|
243
|
+
switch: s
|
244
|
+
aliases: switch
|
245
|
+
desc: switch desc 4
|
246
|
+
long_desc: switch long_desc 5
|
247
|
+
negatable: false
|
248
|
+
switch: version
|
249
|
+
negatable: false
|
250
|
+
command: command1
|
251
|
+
aliases: com1
|
252
|
+
desc: command desc
|
253
|
+
long_desc: command long desc
|
254
|
+
arg_name: cmd_arg_name
|
255
|
+
flag: F
|
256
|
+
aliases: flag2
|
257
|
+
arg_name: arg
|
258
|
+
flag: f
|
259
|
+
aliases: flag
|
260
|
+
desc: flag desc 6
|
261
|
+
long_desc: flag long_desc 7
|
262
|
+
default_value: flag default_value 8
|
263
|
+
arg_name: flag_arg_name_9
|
264
|
+
switch: S
|
265
|
+
aliases: switch2
|
266
|
+
negatable: true
|
267
|
+
switch: s
|
268
|
+
aliases: switch
|
269
|
+
desc: switch desc 10
|
270
|
+
long_desc: switch long_desc 11
|
271
|
+
negatable: false
|
272
|
+
command: default
|
273
|
+
default_command:
|
274
|
+
end default
|
275
|
+
command: sub
|
276
|
+
aliases: subcommand
|
277
|
+
desc: subcommand desc
|
278
|
+
long_desc: subcommand long desc
|
279
|
+
arg_name: subcmd_arg_name
|
280
|
+
flag: subflag
|
281
|
+
desc: flag desc 12
|
282
|
+
long_desc: flag long_desc 13
|
283
|
+
default_value: flag default_value 14
|
284
|
+
arg_name: flag_arg_name_15
|
285
|
+
flag: subflag2
|
286
|
+
arg_name: arg
|
287
|
+
switch: subswitch
|
288
|
+
desc: switch desc 16
|
289
|
+
long_desc: switch long_desc 17
|
290
|
+
negatable: false
|
291
|
+
switch: subswitch2
|
292
|
+
negatable: true
|
293
|
+
default_command:
|
294
|
+
end sub
|
295
|
+
default_command: default
|
296
|
+
end command1
|
297
|
+
command: command2
|
298
|
+
aliases: com2
|
299
|
+
command: sub2
|
300
|
+
aliases: subcommand2
|
301
|
+
default_command:
|
302
|
+
end sub2
|
303
|
+
default_command:
|
304
|
+
end command2
|
305
|
+
command: help
|
306
|
+
desc: Shows a list of commands or help for one command
|
307
|
+
long_desc: Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
|
308
|
+
arg_name: command
|
309
|
+
default_command:
|
310
|
+
end help
|
311
|
+
default_command:
|
312
|
+
END
|
313
|
+
EOS
|
314
|
+
end
|
315
|
+
end
|