gli 2.12.3 → 2.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/gli/app.rb +12 -0
- data/lib/gli/app_support.rb +9 -3
- data/lib/gli/command_finder.rb +42 -25
- data/lib/gli/gli_option_parser.rb +21 -10
- data/lib/gli/version.rb +1 -1
- data/test/tc_command_finder.rb +54 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b949aa32e5bf3ec2a8c7f98c690c75ec7e2a1577
|
4
|
+
data.tar.gz: da3bb5140f7bd7297857a2f80019d693b0bcb59f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cdc67b6b99bc4f68075c5549a44a0cfd4e779697c071dce15c777bd6a743a78a540fc87cca4b91b5d59c363bc9c370645120a9013664cfd2d920ebfb05915c7
|
7
|
+
data.tar.gz: 5d5687cb17c78b7e66927e195e7ee2f27defb48292fc401066caf357c3aa0e6075c238afe1feffd7f115859b1e04c57ac57472237a61fedf1deed5eed519ede0
|
data/lib/gli/app.rb
CHANGED
@@ -302,6 +302,18 @@ module GLI
|
|
302
302
|
@argument_handling_strategy = handling_strategy
|
303
303
|
end
|
304
304
|
|
305
|
+
|
306
|
+
# Enables/Disables command autocomplete, where partially spelled commands are automatically expanded to their full form
|
307
|
+
#
|
308
|
+
# Example:
|
309
|
+
# When enabled, executing 'shake' would execute 'shake_hand' (if no 'shake' command is defined).
|
310
|
+
# When disabled, executing 'shake' would throw an UnknownCommand error
|
311
|
+
#
|
312
|
+
# +boolean+:: Boolean value to enable or disable autocomplete, respectively. True by default.
|
313
|
+
def autocomplete_commands(boolean)
|
314
|
+
@autocomplete = boolean
|
315
|
+
end
|
316
|
+
|
305
317
|
private
|
306
318
|
|
307
319
|
def load_commands(path)
|
data/lib/gli/app_support.rb
CHANGED
@@ -26,6 +26,7 @@ module GLI
|
|
26
26
|
@pre_block = false
|
27
27
|
@post_block = false
|
28
28
|
@default_command = :help
|
29
|
+
@autocomplete = false
|
29
30
|
@around_block = nil
|
30
31
|
@subcommand_option_handling_strategy = :legacy
|
31
32
|
@argument_handling_strategy = :loose
|
@@ -68,9 +69,10 @@ module GLI
|
|
68
69
|
flags,
|
69
70
|
switches,
|
70
71
|
accepts,
|
71
|
-
@default_command,
|
72
|
-
|
73
|
-
|
72
|
+
:default_command => @default_command,
|
73
|
+
:autocomplete => autocomplete,
|
74
|
+
:subcommand_option_handling_strategy => subcommand_option_handling_strategy,
|
75
|
+
:argument_handling_strategy => argument_handling_strategy)
|
74
76
|
|
75
77
|
parsing_result = gli_option_parser.parse_options(args)
|
76
78
|
parsing_result.convert_to_openstruct! if @use_openstruct
|
@@ -211,6 +213,10 @@ module GLI
|
|
211
213
|
@subcommand_option_handling_strategy || :legacy
|
212
214
|
end
|
213
215
|
|
216
|
+
def autocomplete
|
217
|
+
@autocomplete.nil? ? true : @autocomplete
|
218
|
+
end
|
219
|
+
|
214
220
|
private
|
215
221
|
|
216
222
|
def handle_exception(ex,command)
|
data/lib/gli/command_finder.rb
CHANGED
@@ -1,40 +1,57 @@
|
|
1
1
|
module GLI
|
2
2
|
class CommandFinder
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
attr_accessor :options
|
4
|
+
|
5
|
+
DEFAULT_OPTIONS = {
|
6
|
+
default_command: nil,
|
7
|
+
autocomplete: true
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(commands, options = {})
|
11
|
+
self.options = DEFAULT_OPTIONS.merge(options)
|
12
|
+
self.commands_with_aliases = expand_with_aliases(commands)
|
13
13
|
end
|
14
14
|
|
15
|
-
# Finds the command with the given name, allowing for partial matches. Returns the command named by
|
16
|
-
# the default command if no command with +name+ matched
|
17
15
|
def find_command(name)
|
18
|
-
name
|
19
|
-
|
20
|
-
raise UnknownCommand.new("No command name given nor default available") if String(name).strip == ''
|
16
|
+
name = String(name || options[:default_command]).strip
|
17
|
+
raise UnknownCommand.new("No command name given nor default available") if name == ''
|
21
18
|
|
22
|
-
command_found =
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
command_found = commands_with_aliases.fetch(name) do |command_to_match|
|
20
|
+
if options[:autocomplete]
|
21
|
+
found_match = find_command_by_partial_name(commands_with_aliases, command_to_match)
|
22
|
+
if found_match.kind_of? GLI::Command
|
23
|
+
if ENV["GLI_DEBUG"] == 'true'
|
24
|
+
$stderr.puts "Using '#{name}' as it's is short for #{found_match.name}."
|
25
|
+
$stderr.puts "Set autocomplete false for any command you don't want matched like this"
|
26
|
+
end
|
27
|
+
elsif found_match.kind_of?(Array) && !found_match.empty?
|
28
|
+
raise AmbiguousCommand.new("Ambiguous command '#{name}'. It matches #{found_match.sort.join(',')}")
|
29
|
+
end
|
30
|
+
found_match
|
31
|
+
end
|
29
32
|
end
|
33
|
+
|
34
|
+
raise UnknownCommand.new("Unknown command '#{name}'") if Array(command_found).empty?
|
30
35
|
command_found
|
31
36
|
end
|
32
37
|
|
33
38
|
private
|
39
|
+
attr_accessor :commands_with_aliases
|
40
|
+
|
41
|
+
def expand_with_aliases(commands)
|
42
|
+
expanded = {}
|
43
|
+
commands.each do |command_name, command|
|
44
|
+
expanded[command_name.to_s] = command
|
45
|
+
Array(command.aliases).each do |command_alias|
|
46
|
+
expanded[command_alias.to_s] = command
|
47
|
+
end
|
48
|
+
end
|
49
|
+
expanded
|
50
|
+
end
|
34
51
|
|
35
|
-
def find_command_by_partial_name(
|
36
|
-
partial_matches =
|
37
|
-
return
|
52
|
+
def find_command_by_partial_name(commands_with_aliases, command_to_match)
|
53
|
+
partial_matches = commands_with_aliases.keys.select { |command_name| command_name =~ /^#{command_to_match}/ }
|
54
|
+
return commands_with_aliases[partial_matches[0]] if partial_matches.size == 1
|
38
55
|
partial_matches
|
39
56
|
end
|
40
57
|
end
|
@@ -1,24 +1,35 @@
|
|
1
1
|
module GLI
|
2
2
|
# Parses the command-line options using an actual +OptionParser+
|
3
3
|
class GLIOptionParser
|
4
|
-
|
5
|
-
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
DEFAULT_OPTIONS = {
|
7
|
+
:default_command => nil,
|
8
|
+
:autocomplete => true,
|
9
|
+
:subcommand_option_handling_strategy => :legacy,
|
10
|
+
:argument_handling_strategy => :loose
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(commands,flags,switches,accepts, options={})
|
14
|
+
self.options = DEFAULT_OPTIONS.merge(options)
|
15
|
+
|
16
|
+
command_finder = CommandFinder.new(commands,
|
17
|
+
:default_command => (options[:default_command] || :help),
|
18
|
+
:autocomplete => options[:autocomplete])
|
6
19
|
@global_option_parser = GlobalOptionParser.new(OptionParserFactory.new(flags,switches,accepts),command_finder,flags)
|
7
20
|
@accepts = accepts
|
8
|
-
|
9
|
-
@argument_handling_strategy = argument_handling_strategy
|
10
|
-
if @argument_handling_strategy == :strict && @subcommand_option_handling_strategy != :normal
|
21
|
+
if options[:argument_handling_strategy] == :strict && options[:subcommand_option_handling_strategy] != :normal
|
11
22
|
raise ArgumentError, "To use strict argument handling, you must enable normal subcommand_option_handling, e.g. subcommand_option_handling :normal"
|
12
23
|
end
|
13
24
|
end
|
14
25
|
|
15
26
|
# Given the command-line argument array, returns an OptionParsingResult
|
16
27
|
def parse_options(args) # :nodoc:
|
17
|
-
option_parser_class = self.class.const_get("#{
|
28
|
+
option_parser_class = self.class.const_get("#{options[:subcommand_option_handling_strategy].to_s.capitalize}CommandOptionParser")
|
18
29
|
OptionParsingResult.new.tap { |parsing_result|
|
19
30
|
parsing_result.arguments = args
|
20
31
|
parsing_result = @global_option_parser.parse!(parsing_result)
|
21
|
-
option_parser_class.new(@accepts).parse!(parsing_result,
|
32
|
+
option_parser_class.new(@accepts).parse!(parsing_result, options[:argument_handling_strategy])
|
22
33
|
}
|
23
34
|
end
|
24
35
|
|
@@ -101,7 +112,7 @@ module GLI
|
|
101
112
|
end
|
102
113
|
|
103
114
|
def error_handler
|
104
|
-
lambda { |message,extra_error_context|
|
115
|
+
lambda { |message,extra_error_context|
|
105
116
|
raise UnknownCommandArgument.new(message,extra_error_context)
|
106
117
|
}
|
107
118
|
end
|
@@ -120,7 +131,7 @@ module GLI
|
|
120
131
|
arguments = option_block_parser.parse!(arguments)
|
121
132
|
|
122
133
|
parsed_command_options[command] = option_parser_factory.options_hash_with_defaults_set!
|
123
|
-
command_finder = CommandFinder.new(command.commands,command.get_default_command)
|
134
|
+
command_finder = CommandFinder.new(command.commands, :default_command => command.get_default_command)
|
124
135
|
next_command_name = arguments.shift
|
125
136
|
|
126
137
|
verify_required_options!(command.flags, command, parsed_command_options[command])
|
@@ -193,7 +204,7 @@ module GLI
|
|
193
204
|
end
|
194
205
|
|
195
206
|
default_command = command.get_default_command
|
196
|
-
finder = CommandFinder.new(command.commands,default_command.to_s)
|
207
|
+
finder = CommandFinder.new(command.commands, :default_command => default_command.to_s)
|
197
208
|
|
198
209
|
begin
|
199
210
|
results = [finder.find_command(command_name),arguments[1..-1]]
|
data/lib/gli/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TC_testCommandFinder < Clean::Test::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@app = CLIApp.new
|
8
|
+
[:status, :deployable, :some_command, :some_similar_command].each do |command|
|
9
|
+
@app.commands[command] = GLI::Command.new(:names => command)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_unknown_command_name
|
17
|
+
assert_raise(GLI::UnknownCommand) do
|
18
|
+
GLI::CommandFinder.new(@app.commands, :default_command => :status).find_command(:unfindable_command)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_no_command_name_without_default
|
23
|
+
assert_raise(GLI::UnknownCommand) do
|
24
|
+
GLI::CommandFinder.new(@app.commands).find_command(nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_no_command_name_with_default
|
29
|
+
actual = GLI::CommandFinder.new(@app.commands, :default_command => :status).find_command(nil)
|
30
|
+
expected = @app.commands[:status]
|
31
|
+
|
32
|
+
assert_equal(actual, expected)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_ambigous_command
|
36
|
+
assert_raise(GLI::AmbiguousCommand) do
|
37
|
+
GLI::CommandFinder.new(@app.commands, :default_command => :status).find_command(:some)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_partial_name_with_autocorrect_enabled
|
42
|
+
actual = GLI::CommandFinder.new(@app.commands, :default_command => :status).find_command(:deploy)
|
43
|
+
expected = @app.commands[:deployable]
|
44
|
+
|
45
|
+
assert_equal(actual, expected)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_partial_name_with_autocorrect_disabled
|
49
|
+
assert_raise(GLI::UnknownCommand) do
|
50
|
+
GLI::CommandFinder.new(@app.commands, :default_command => :status, :autocomplete => false)
|
51
|
+
.find_command(:deploy)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Copeland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -241,6 +241,7 @@ files:
|
|
241
241
|
- test/init_simplecov.rb
|
242
242
|
- test/option_test_helper.rb
|
243
243
|
- test/tc_command.rb
|
244
|
+
- test/tc_command_finder.rb
|
244
245
|
- test/tc_compound_command.rb
|
245
246
|
- test/tc_doc.rb
|
246
247
|
- test/tc_flag.rb
|
@@ -319,6 +320,7 @@ test_files:
|
|
319
320
|
- test/init_simplecov.rb
|
320
321
|
- test/option_test_helper.rb
|
321
322
|
- test/tc_command.rb
|
323
|
+
- test/tc_command_finder.rb
|
322
324
|
- test/tc_compound_command.rb
|
323
325
|
- test/tc_doc.rb
|
324
326
|
- test/tc_flag.rb
|