gli 2.12.3 → 2.13.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 84a063f077612bd68999d7ab4771655577b9f66e
4
- data.tar.gz: 1c12e2ce024650ac44bff39eaba6a4df7f28f77c
3
+ metadata.gz: b949aa32e5bf3ec2a8c7f98c690c75ec7e2a1577
4
+ data.tar.gz: da3bb5140f7bd7297857a2f80019d693b0bcb59f
5
5
  SHA512:
6
- metadata.gz: d417534ed4728c1a95b03069dd965f9cc9b74bac4edcbdfc6087712ba13e6a55084c71d6c58e21af237dfc8685dc8208a3b9371a6320ba3d31c54804007251f3
7
- data.tar.gz: 01fb54aa5de01661ef48dfb2d359fa396db13bbc9bb16fb20d75f1f71cda9197047f925d63754b831b4661c94ff8c3849ba1c3cf0e578074ab843eab8ae3ffa6
6
+ metadata.gz: 7cdc67b6b99bc4f68075c5549a44a0cfd4e779697c071dce15c777bd6a743a78a540fc87cca4b91b5d59c363bc9c370645120a9013664cfd2d920ebfb05915c7
7
+ data.tar.gz: 5d5687cb17c78b7e66927e195e7ee2f27defb48292fc401066caf357c3aa0e6075c238afe1feffd7f115859b1e04c57ac57472237a61fedf1deed5eed519ede0
@@ -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)
@@ -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
- self.subcommand_option_handling_strategy,
73
- self.argument_handling_strategy)
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)
@@ -1,40 +1,57 @@
1
1
  module GLI
2
2
  class CommandFinder
3
- # Initialize a finder on the given list of commands, using default_command as the default if none found
4
- def initialize(commands,default_command)
5
- @default_command = default_command
6
- @names_to_commands = {}
7
- commands.each do |command_name,command|
8
- @names_to_commands[command_name.to_s] = command
9
- Array(command.aliases).each do |command_alias|
10
- @names_to_commands[command_alias.to_s] = command
11
- end
12
- end
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 ||= @default_command
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 = @names_to_commands.fetch(name.to_s) do |command_to_match|
23
- find_command_by_partial_name(@names_to_commands, command_to_match)
24
- end
25
- if Array(command_found).empty?
26
- raise UnknownCommand.new("Unknown command '#{name}'")
27
- elsif command_found.kind_of? Array
28
- raise AmbiguousCommand.new("Ambiguous command '#{name}'. It matches #{command_found.sort.join(',')}")
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(names_to_commands, command_to_match)
36
- partial_matches = names_to_commands.keys.select { |command_name| command_name =~ /^#{command_to_match}/ }
37
- return names_to_commands[partial_matches[0]] if partial_matches.size == 1
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
- def initialize(commands,flags,switches,accepts,default_command = nil,subcommand_option_handling_strategy=:legacy,argument_handling_strategy=:loose)
5
- command_finder = CommandFinder.new(commands,default_command || "help")
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
- @subcommand_option_handling_strategy = subcommand_option_handling_strategy
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("#{@subcommand_option_handling_strategy.to_s.capitalize}CommandOptionParser")
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, @argument_handling_strategy)
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]]
@@ -1,5 +1,5 @@
1
1
  module GLI
2
2
  unless const_defined? :VERSION
3
- VERSION = '2.12.3'
3
+ VERSION = '2.13.0'
4
4
  end
5
5
  end
@@ -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.12.3
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-02-21 00:00:00.000000000 Z
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