gli 2.0.0.rc3 → 2.0.0.rc4
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/README.rdoc +2 -2
- data/lib/gli/app.rb +26 -0
- data/lib/gli/app_support.rb +16 -4
- data/lib/gli/command.rb +2 -0
- data/lib/gli/command_support.rb +5 -0
- data/lib/gli/commands/help.rb +2 -1
- data/lib/gli/dsl.rb +1 -0
- data/lib/gli/gli_option_parser.rb +9 -5
- data/lib/gli/version.rb +1 -1
- data/test/tc_command.rb +86 -9
- data/test/tc_gli.rb +33 -1
- data/test/tc_subcommands.rb +13 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Git-Like Interface Command Line Parser
|
2
2
|
|
3
|
-
<b>
|
3
|
+
<b>GLI2 is currently in Release Candidate, so this might change before the official release</b>
|
4
4
|
|
5
5
|
The best way to make a "command-suite" command-line application (for the best way to make a
|
6
6
|
simpler command-line application, check out methadone[http://www.github.com/davetron5000/methadone]).
|
@@ -10,7 +10,7 @@ of syntax, but without restricting you in any way from the power of +OptionParse
|
|
10
10
|
|
11
11
|
* {Overview}[http://davetron5000.github.com/gli]
|
12
12
|
* {Source on Github}[http://github.com/davetron5000/gli]
|
13
|
-
* RDoc[http://davetron5000.github.com/gli]
|
13
|
+
* RDoc[http://davetron5000.github.com/gli/rdoc/index.html]
|
14
14
|
|
15
15
|
== Use
|
16
16
|
|
data/lib/gli/app.rb
CHANGED
@@ -58,6 +58,13 @@ module GLI
|
|
58
58
|
@skips_post = true
|
59
59
|
end
|
60
60
|
|
61
|
+
# Use this if the following command should not have the around block executed.
|
62
|
+
# By default, the around block is executed, but for commands that might not want the
|
63
|
+
# setup to happen, this can be handy
|
64
|
+
def skips_around
|
65
|
+
@skips_around = true
|
66
|
+
end
|
67
|
+
|
61
68
|
# Sets that this app uses a config file as well as the name of the config file.
|
62
69
|
#
|
63
70
|
# +filename+:: A String representing the path to the file to use for the config file. If it's an absolute
|
@@ -90,6 +97,25 @@ module GLI
|
|
90
97
|
@post_block = a_proc
|
91
98
|
end
|
92
99
|
|
100
|
+
# This inverts the pre/post concept. This is useful when you have a global shared resource that is governed by a block
|
101
|
+
# instead of separate open/close methods. The block you pass here will be given four parameters:
|
102
|
+
#
|
103
|
+
# global options:: the parsed global options
|
104
|
+
# command:: The GLI::Command that the user is going to invoke
|
105
|
+
# options:: the command specific options
|
106
|
+
# args:: unparsed command-line args
|
107
|
+
# code:: a block that you must +call+ to execute the command.
|
108
|
+
#
|
109
|
+
# #help_now! and #exit_now! work as expected; you can abort the command call by simply not calling it
|
110
|
+
#
|
111
|
+
# Note that if you declare an #around block, #pre and #post blocks will still work. The #pre is called first, followed by
|
112
|
+
# the around, followed by the #post.
|
113
|
+
#
|
114
|
+
# Call #skips_around before a command that should not have this hook fired
|
115
|
+
def around(&a_proc)
|
116
|
+
@around_block = a_proc
|
117
|
+
end
|
118
|
+
|
93
119
|
# Define a block to run if an error occurs.
|
94
120
|
# The block will receive any Exception that was caught.
|
95
121
|
# It should evaluate to false to avoid the built-in error handling (which basically just
|
data/lib/gli/app_support.rb
CHANGED
@@ -14,7 +14,7 @@ module GLI
|
|
14
14
|
def reset # :nodoc:
|
15
15
|
switches.clear
|
16
16
|
flags.clear
|
17
|
-
commands
|
17
|
+
@commands = nil
|
18
18
|
@version = nil
|
19
19
|
@config_file = nil
|
20
20
|
@use_openstruct = false
|
@@ -23,6 +23,7 @@ module GLI
|
|
23
23
|
@pre_block = false
|
24
24
|
@post_block = false
|
25
25
|
@default_command = :help
|
26
|
+
@around_block = nil
|
26
27
|
clear_nexts
|
27
28
|
end
|
28
29
|
|
@@ -43,7 +44,7 @@ module GLI
|
|
43
44
|
|
44
45
|
add_help_switch_if_needed(switches)
|
45
46
|
|
46
|
-
global_options,command,options,arguments = GLIOptionParser.new(commands,flags,switches,accepts).parse_options(args)
|
47
|
+
global_options,command,options,arguments = GLIOptionParser.new(commands,flags,switches,accepts,@default_command).parse_options(args)
|
47
48
|
|
48
49
|
copy_options_to_aliased_versions(global_options,command,options)
|
49
50
|
|
@@ -51,7 +52,6 @@ module GLI
|
|
51
52
|
options = convert_to_openstruct_if_needed(options)
|
52
53
|
|
53
54
|
if proceed?(global_options,command,options,arguments)
|
54
|
-
command ||= commands[:help]
|
55
55
|
call_command(command,global_options,options,arguments)
|
56
56
|
end
|
57
57
|
0
|
@@ -93,6 +93,7 @@ module GLI
|
|
93
93
|
super
|
94
94
|
@skips_post = false
|
95
95
|
@skips_pre = false
|
96
|
+
@skips_around = false
|
96
97
|
end
|
97
98
|
|
98
99
|
def stderr
|
@@ -126,6 +127,12 @@ module GLI
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
130
|
+
def around_block
|
131
|
+
@around_block ||= Proc.new do |global,command,options,args,code|
|
132
|
+
code.call
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
129
136
|
# Sets the default values for flags based on the configuration
|
130
137
|
def override_defaults_based_on_config(config)
|
131
138
|
override_default(flags,config)
|
@@ -216,7 +223,12 @@ module GLI
|
|
216
223
|
|
217
224
|
def call_command(command,global_options,options,arguments)
|
218
225
|
arguments = arguments.map { |arg| arg.dup } # unfreeze
|
219
|
-
command.execute(global_options,options,arguments)
|
226
|
+
code = lambda { command.execute(global_options,options,arguments) }
|
227
|
+
if command.skips_around
|
228
|
+
code.call
|
229
|
+
else
|
230
|
+
around_block.call(global_options,command,options,arguments,code)
|
231
|
+
end
|
220
232
|
unless command.skips_post
|
221
233
|
post_block.call(global_options,command,options,arguments)
|
222
234
|
end
|
data/lib/gli/command.rb
CHANGED
@@ -42,11 +42,13 @@ module GLI
|
|
42
42
|
# as a paragraph break. No other formatting is respected, though inner whitespace is maintained.
|
43
43
|
# +skips_pre+:: if true, this command advertises that it doesn't want the pre block called first
|
44
44
|
# +skips_post+:: if true, this command advertises that it doesn't want the post block called after it
|
45
|
+
# +skips_around+:: if true, this command advertises that it doesn't want the around block called
|
45
46
|
def initialize(options)
|
46
47
|
super(options[:names],options[:description],options[:long_desc])
|
47
48
|
@arguments_description = options[:arguments_name] || ''
|
48
49
|
@skips_pre = options[:skips_pre]
|
49
50
|
@skips_post = options[:skips_post]
|
51
|
+
@skips_around = options[:skips_around]
|
50
52
|
clear_nexts
|
51
53
|
end
|
52
54
|
|
data/lib/gli/command_support.rb
CHANGED
data/lib/gli/commands/help.rb
CHANGED
@@ -17,7 +17,8 @@ module GLI
|
|
17
17
|
:arguments_name => 'command',
|
18
18
|
: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',
|
19
19
|
:skips_pre => true,
|
20
|
-
:skips_post => true
|
20
|
+
:skips_post => true,
|
21
|
+
:skips_around => true)
|
21
22
|
@app = app
|
22
23
|
action do |global_options,options,arguments|
|
23
24
|
show_help(global_options,options,arguments,output,error)
|
data/lib/gli/dsl.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module GLI
|
2
2
|
# Parses the command-line options using an actual +OptionParser+
|
3
3
|
class GLIOptionParser
|
4
|
-
def initialize(commands,flags,switches,accepts)
|
4
|
+
def initialize(commands,flags,switches,accepts,default_command = nil)
|
5
5
|
@commands = commands
|
6
6
|
@flags = flags
|
7
7
|
@switches = switches
|
8
8
|
@accepts = accepts
|
9
|
+
@default_command = default_command
|
9
10
|
end
|
10
11
|
|
11
12
|
# Given the command-line argument array, returns and array of size 4:
|
@@ -87,10 +88,13 @@ module GLI
|
|
87
88
|
names_to_commands[command_alias.to_s] = command
|
88
89
|
end
|
89
90
|
end
|
90
|
-
name
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
names_to_commands.fetch(name.to_s) do |command_to_match|
|
92
|
+
find_command_by_partial_name(names_to_commands, command_to_match)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_command_by_partial_name(names_to_commands, command_to_match)
|
97
|
+
partial_matches = names_to_commands.keys.select { |command_name| command_name =~ /^#{command_to_match}/ }
|
94
98
|
return names_to_commands[partial_matches[0]] if partial_matches.size == 1
|
95
99
|
partial_matches
|
96
100
|
end
|
data/lib/gli/version.rb
CHANGED
data/test/tc_command.rb
CHANGED
@@ -4,7 +4,15 @@ require 'tempfile'
|
|
4
4
|
class TC_testCommand < Clean::Test::TestCase
|
5
5
|
include TestHelper
|
6
6
|
def setup
|
7
|
+
@fake_stdout = FakeStdOut.new
|
8
|
+
@fake_stderr = FakeStdOut.new
|
9
|
+
@original_stdout = $stdout
|
10
|
+
$stdout = @fake_stdout
|
11
|
+
@original_stderr = $stderr
|
12
|
+
$stderr = @fake_stderr
|
7
13
|
@app = CLIApp.new
|
14
|
+
@app.error_device=@fake_stderr
|
15
|
+
ENV.delete('GLI_DEBUG')
|
8
16
|
@app.reset
|
9
17
|
@app.program_desc 'A super awesome program'
|
10
18
|
@app.desc 'Some Global Option'
|
@@ -50,17 +58,9 @@ class TC_testCommand < Clean::Test::TestCase
|
|
50
58
|
@app.command [:test_wrap] do |c|
|
51
59
|
c.action {}
|
52
60
|
end
|
53
|
-
@fake_stdout = FakeStdOut.new
|
54
|
-
@fake_stderr = FakeStdOut.new
|
55
|
-
@app.error_device=@fake_stderr
|
56
|
-
ENV.delete('GLI_DEBUG')
|
57
|
-
@original_stdout = $stdout
|
58
|
-
$stdout = @fake_stdout
|
59
|
-
@original_stderr = $stderr
|
60
|
-
$stderr = @fake_stderr
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def teardown
|
64
64
|
$stdout = @original_stdout
|
65
65
|
$stderr = @original_stderr
|
66
66
|
FileUtils.rm_f "cruddo.rdoc"
|
@@ -100,6 +100,83 @@ class TC_testCommand < Clean::Test::TestCase
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
def test_around_filter
|
104
|
+
@around_block_called = false
|
105
|
+
@app.around do |global_options, command, options, arguments, code|
|
106
|
+
@around_block_called = true
|
107
|
+
code.call
|
108
|
+
end
|
109
|
+
@app.run(['bs'])
|
110
|
+
assert(@around_block_called, "Wrapper block should have been called")
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_around_filter_can_be_skipped
|
114
|
+
# Given
|
115
|
+
@around_block_called = false
|
116
|
+
@action_called = false
|
117
|
+
@app.skips_around
|
118
|
+
@app.command :skips_around_filter do |c|
|
119
|
+
c.action do |g,o,a|
|
120
|
+
@action_called = true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
@app.command :uses_around_filter do |c|
|
125
|
+
c.action do |g,o,a|
|
126
|
+
@action_called = true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
@app.around do |global_options, command, options, arguments, code|
|
131
|
+
@around_block_called = true
|
132
|
+
code.call
|
133
|
+
end
|
134
|
+
|
135
|
+
# When
|
136
|
+
exit_status = @app.run(['skips_around_filter'])
|
137
|
+
|
138
|
+
# Then
|
139
|
+
assert_equal 0,exit_status
|
140
|
+
assert(!@around_block_called, "Wrapper block should have been skipped")
|
141
|
+
assert(@action_called,"Action should have been called")
|
142
|
+
|
143
|
+
# When
|
144
|
+
@around_block_called = false
|
145
|
+
@action_called = false
|
146
|
+
exit_status = @app.run(['uses_around_filter'])
|
147
|
+
|
148
|
+
# Then
|
149
|
+
assert_equal 0,exit_status
|
150
|
+
assert(@around_block_called, "Wrapper block should have been called")
|
151
|
+
assert(@action_called,"Action should have been called")
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_around_filter_handles_exit_now
|
155
|
+
@around_block_called = false
|
156
|
+
@error_message = "OH NOES"
|
157
|
+
@app.around do |global_options, command, options, arguments, code|
|
158
|
+
@app.exit_now! @error_message
|
159
|
+
code.call
|
160
|
+
end
|
161
|
+
exit_code = @app.run(['bs'])
|
162
|
+
assert exit_code != 0
|
163
|
+
assert_contained(@fake_stderr,/#{@error_message}/)
|
164
|
+
assert_not_contained(@fake_stdout,/SYNOPSIS/)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_around_filter_handles_help_now
|
168
|
+
@around_block_called = false
|
169
|
+
@error_message = "OH NOES"
|
170
|
+
@app.around do |global_options, command, options, arguments, code|
|
171
|
+
@app.help_now! @error_message
|
172
|
+
code.call
|
173
|
+
end
|
174
|
+
exit_code = @app.run(['bs'])
|
175
|
+
assert exit_code != 0
|
176
|
+
assert_contained(@fake_stderr,/#{@error_message}/)
|
177
|
+
assert_contained(@fake_stdout,/SYNOPSIS/)
|
178
|
+
end
|
179
|
+
|
103
180
|
def test_command_skips_pre
|
104
181
|
@app.skips_pre
|
105
182
|
@app.skips_post
|
data/test/tc_gli.rb
CHANGED
@@ -17,10 +17,15 @@ class TC_testGLI < Clean::Test::TestCase
|
|
17
17
|
include GLI
|
18
18
|
|
19
19
|
def setup
|
20
|
+
@fake_stdout = FakeStdOut.new
|
21
|
+
@fake_stderr = FakeStdOut.new
|
22
|
+
@original_stdout = $stdout
|
23
|
+
$stdout = @fake_stdout
|
24
|
+
@original_stderr = $stderr
|
25
|
+
$stderr = @fake_stderr
|
20
26
|
@app = CLIApp.new
|
21
27
|
@config_file = File.expand_path(File.dirname(File.realpath(__FILE__)) + '/new_config.yaml')
|
22
28
|
@gli_debug = ENV['GLI_DEBUG']
|
23
|
-
@fake_stderr = FakeStdOut.new
|
24
29
|
@app.error_device=@fake_stderr
|
25
30
|
ENV.delete('GLI_DEBUG')
|
26
31
|
end
|
@@ -29,6 +34,8 @@ class TC_testGLI < Clean::Test::TestCase
|
|
29
34
|
File.delete(@config_file) if File.exist?(@config_file)
|
30
35
|
ENV['GLI_DEBUG'] = @gli_debug
|
31
36
|
@app.error_device=$stderr
|
37
|
+
$stdout = @original_stdout
|
38
|
+
$stderr = @original_stderr
|
32
39
|
end
|
33
40
|
|
34
41
|
def test_flag_create
|
@@ -51,6 +58,19 @@ class TC_testGLI < Clean::Test::TestCase
|
|
51
58
|
assert @app.switches[:s].aliases.include? :'some-switch'
|
52
59
|
end
|
53
60
|
|
61
|
+
def test_default_command
|
62
|
+
@app.reset
|
63
|
+
@called = false
|
64
|
+
@app.command :foo do |c|
|
65
|
+
c.action do |global, options, arguments|
|
66
|
+
@called = true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@app.default_command(:foo)
|
70
|
+
assert_equal 0, @app.run([]), "Expected exit status to be 0"
|
71
|
+
assert @called, "Expected default command to be executed"
|
72
|
+
end
|
73
|
+
|
54
74
|
def test_flag_with_space_barfs
|
55
75
|
@app.reset
|
56
76
|
assert_raises(ArgumentError) { @app.flag ['some flag'] }
|
@@ -214,6 +234,18 @@ class TC_testGLI < Clean::Test::TestCase
|
|
214
234
|
do_test_switch_create_twice(@app)
|
215
235
|
do_test_switch_create_twice(Command.new(:names => :f))
|
216
236
|
end
|
237
|
+
|
238
|
+
def test_non_negatable_negative_switch
|
239
|
+
@app.reset
|
240
|
+
@app.on_error { |ex| raise ex }
|
241
|
+
@app.switch 'no-color', :negatable => false
|
242
|
+
@app.command :smth do |c|
|
243
|
+
c.action do |global, *args|
|
244
|
+
assert global[:"no-color"], "Expected :'no-color' switch to be true"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
@app.run(%w(--no-color smth))
|
248
|
+
end
|
217
249
|
|
218
250
|
def test_all_aliases_in_options
|
219
251
|
@app.reset
|
data/test/tc_subcommands.rb
CHANGED
@@ -4,13 +4,25 @@ class TC_testSubCommand < Clean::Test::TestCase
|
|
4
4
|
include TestHelper
|
5
5
|
|
6
6
|
def setup
|
7
|
+
@fake_stdout = FakeStdOut.new
|
8
|
+
@fake_stderr = FakeStdOut.new
|
9
|
+
|
10
|
+
@original_stdout = $stdout
|
11
|
+
$stdout = @fake_stdout
|
12
|
+
@original_stderr = $stderr
|
13
|
+
$stderr = @fake_stderr
|
14
|
+
|
7
15
|
@app = CLIApp.new
|
8
16
|
@app.reset
|
9
|
-
@fake_stderr = FakeStdOut.new
|
10
17
|
@app.error_device=@fake_stderr
|
11
18
|
ENV.delete('GLI_DEBUG')
|
12
19
|
end
|
13
20
|
|
21
|
+
def teardown
|
22
|
+
$stdout = @original_stdout
|
23
|
+
$stderr = @original_stderr
|
24
|
+
end
|
25
|
+
|
14
26
|
['add','new'].each do |name|
|
15
27
|
test_that "We run the 'add' subcommand using '#{name}'" do
|
16
28
|
Given we_have_a_command_with_two_subcommands
|
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: 2.0.0.
|
4
|
+
version: 2.0.0.rc4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|