gli 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc8b2ac1abb69495f8096899fbb4da56b2e85d32
4
- data.tar.gz: ce4f47438626b06fbd4fcf4b714a5257b63a2ec5
3
+ metadata.gz: 362815ed2ee02ae4318a321eca52acb7175f802f
4
+ data.tar.gz: 27dadfccc2e537d4ae9824cf1a75075020391d6c
5
5
  SHA512:
6
- metadata.gz: 1d9e77187528594f30d47c0dca4cdef47a1dc01fbc35657e0bfec3441a20b1d37d87dccecc4015957bf78c1055ff4ce9a0cb0b728b1e97305b6c8936ba82f2c2
7
- data.tar.gz: 81eb28d1e7b564fed156a69fa0159bd4236bffec82d51bf1c5874c6d6a521eb8f24ce1ee3f156ff9445a504311b9deb83deb059ab27120c079b04e8578b286cf
6
+ metadata.gz: 261bf4ac97f86f4b2b1d68aba7cb7396da8c6e2651504dfd8ce1a736215cca382b723db02820165b69c71e74721b4ac4588c45cfcf7014596c80e1225845a504
7
+ data.tar.gz: 4a12460017ee29eb4dd7f97111ee5cbb8b5112cd44db7dd933c7edc069b3f8053e0245417e4fa3ffaaeb108b4f85384ab2a86bf0483b7811ad52dbdafb9d6110
@@ -17,6 +17,7 @@ Feature: The todo app has a nice user interface
17
17
 
18
18
  Scenario Outline: Getting Help for todo in general
19
19
  When I successfully run `todo <help>`
20
+ Then the exit status should be 0
20
21
  Then the output should contain:
21
22
  """
22
23
  NAME
@@ -195,8 +196,9 @@ Feature: The todo app has a nice user interface
195
196
  stored in your todo databases.
196
197
 
197
198
  COMMAND OPTIONS
198
- -l, --[no-]long - Show long form
199
- --required_flag=arg - (required, default: none)
199
+ -l, --[no-]long - Show long form
200
+ --required_flag=arg - (required, default: none)
201
+ --required_flag2=arg - (required, default: none)
200
202
 
201
203
  COMMANDS
202
204
  contexts - List contexts
@@ -238,8 +240,9 @@ Feature: The todo app has a nice user interface
238
240
  List a whole lot of things that you might be keeping track of in your overall todo list. This is your go-to place or finding all of the things that you might have stored in your todo databases.
239
241
 
240
242
  COMMAND OPTIONS
241
- -l, --[no-]long - Show long form
242
- --required_flag=arg - (required, default: none)
243
+ -l, --[no-]long - Show long form
244
+ --required_flag=arg - (required, default: none)
245
+ --required_flag2=arg - (required, default: none)
243
246
 
244
247
  COMMANDS
245
248
  contexts - List contexts
@@ -270,8 +273,9 @@ Feature: The todo app has a nice user interface
270
273
 
271
274
 
272
275
  COMMAND OPTIONS
273
- -l, --[no-]long - Show long form
274
- --required_flag=arg - (required, default: none)
276
+ -l, --[no-]long - Show long form
277
+ --required_flag=arg - (required, default: none)
278
+ --required_flag2=arg - (required, default: none)
275
279
 
276
280
  COMMANDS
277
281
  contexts - List contexts
@@ -294,8 +298,9 @@ Feature: The todo app has a nice user interface
294
298
  List a whole lot of things that you might be keeping track of in your overall todo list. This is your go-to place or finding all of the things that you might have stored in your todo databases.
295
299
 
296
300
  COMMAND OPTIONS
297
- -l, --[no-]long - Show long form
298
- --required_flag=arg - (required, default: none)
301
+ -l, --[no-]long - Show long form
302
+ --required_flag=arg - (required, default: none)
303
+ --required_flag2=arg - (required, default: none)
299
304
 
300
305
  COMMANDS
301
306
  contexts - List contexts
@@ -336,21 +341,27 @@ Feature: The todo app has a nice user interface
336
341
  SYNOPSIS
337
342
  todo [global options] create
338
343
  todo [global options] create contexts [context_name]
344
+ todo [global options] create relation_1-1 first second [name]
345
+ todo [global options] create relation_1-n first second[, second]* [name]
346
+ todo [global options] create relation_n-1 first[, first]* second [name]
339
347
  todo [global options] create tasks task_name[, task_name]*
340
348
 
341
349
  COMMANDS
342
- <default> - Makes a new task
343
- contexts - Make a new context
344
- tasks - Make a new task
350
+ <default> - Makes a new task
351
+ contexts - Make a new context
352
+ relation_1-1 -
353
+ relation_1-n -
354
+ relation_n-1 -
355
+ tasks - Make a new task
345
356
  """
346
357
  And the output should not contain "COMMAND OPTIONS"
347
358
 
348
359
  Scenario: Running list w/out subcommand performs list tasks by default
349
- When I successfully run `todo list --required_flag=blah boo yay`
360
+ When I successfully run `todo list --required_flag=blah --required_flag2=bleh boo yay`
350
361
  Then the output should contain "list tasks: boo,yay"
351
362
 
352
363
  Scenario: Running list w/out subcommand or any arguments performs list tasks by default
353
- When I successfully run `todo list --required_flag=blah`
364
+ When I successfully run `todo list --required_flag=blah --required_flag2=bleh`
354
365
  Then the output should contain "list tasks:"
355
366
 
356
367
  Scenario: Running chained commands works
@@ -479,3 +490,57 @@ Feature: The todo app has a nice user interface
479
490
  todo [global options] ls [command options] contexts [subcommand options]
480
491
  todo [global options] ls [command options] tasks [subcommand options]
481
492
  """
493
+
494
+ Scenario: We get a clear error message when a required argument is missing
495
+ Given a clean home directory
496
+ When I run `todo list`
497
+ Then the exit status should not be 0
498
+ And the stderr should contain "error: required_flag is required, required_flag2 is required"
499
+ And the output should contain:
500
+ """
501
+ NAME
502
+ list - List things, such as tasks or contexts
503
+
504
+ SYNOPSIS
505
+ todo [global options] list [command options] [tasks] [subcommand options]
506
+ todo [global options] list [command options] contexts [subcommand options]
507
+
508
+ DESCRIPTION
509
+ List a whole lot of things that you might be keeping track of in your
510
+ overall todo list.
511
+
512
+ This is your go-to place or finding all of the things that you might have
513
+ stored in your todo databases.
514
+
515
+ COMMAND OPTIONS
516
+ -l, --[no-]long - Show long form
517
+ --required_flag=arg - (required, default: none)
518
+ --required_flag2=arg - (required, default: none)
519
+
520
+ COMMANDS
521
+ contexts - List contexts
522
+ tasks - List tasks (default)
523
+ """
524
+
525
+ Scenario: Getting help on a root command with an arg_name outputs the argument description
526
+ When I run `todo help first`
527
+ And the stdout should contain:
528
+ """
529
+ NAME
530
+ first -
531
+
532
+ SYNOPSIS
533
+ todo [global options] first [argument]
534
+ """
535
+
536
+ Scenario: Getting help on a root command with an arg outputs the argument description
537
+ When I run `todo help second`
538
+ And the stdout should contain:
539
+ """
540
+ NAME
541
+ second -
542
+
543
+ SYNOPSIS
544
+ todo [global options] second [argument]
545
+ """
546
+
data/lib/gli.rb CHANGED
@@ -13,6 +13,7 @@ require 'gli/exceptions.rb'
13
13
  require 'gli/flag.rb'
14
14
  require 'gli/options.rb'
15
15
  require 'gli/switch.rb'
16
+ require 'gli/argument.rb'
16
17
  require 'gli/dsl.rb'
17
18
  require 'gli/version.rb'
18
19
  require 'gli/commands/help'
@@ -210,7 +210,7 @@ module GLI
210
210
  def handle_exception(ex,command)
211
211
  if regular_error_handling?(ex)
212
212
  output_error_message(ex)
213
- if ex.kind_of?(OptionParser::ParseError) || ex.kind_of?(BadCommandLine)
213
+ if ex.kind_of?(OptionParser::ParseError) || ex.kind_of?(BadCommandLine) || ex.kind_of?(RequestHelp)
214
214
  if commands[:help]
215
215
  command_for_help = command.nil? ? [] : command.name_for_help
216
216
  commands[:help].execute({},{},command_for_help)
@@ -220,7 +220,7 @@ module GLI
220
220
  stderr.puts "Custom error handler exited false, skipping normal error handling"
221
221
  end
222
222
 
223
- raise ex if ENV['GLI_DEBUG'] == 'true'
223
+ raise ex if ENV['GLI_DEBUG'] == 'true' && !ex.kind_of?(RequestHelp)
224
224
 
225
225
  ex.extend(GLI::StandardException)
226
226
  ex.exit_code
@@ -0,0 +1,20 @@
1
+ module GLI
2
+ class Argument #:nodoc:
3
+
4
+ attr_reader :name
5
+ attr_reader :options
6
+
7
+ def initialize(name,options = [])
8
+ @name = name
9
+ @options = options
10
+ end
11
+
12
+ def optional?
13
+ @options.include? :optional
14
+ end
15
+
16
+ def multiple?
17
+ @options.include? :multiple
18
+ end
19
+ end
20
+ end
data/lib/gli/command.rb CHANGED
@@ -49,6 +49,7 @@ module GLI
49
49
  super(options[:names],options[:description],options[:long_desc])
50
50
  @arguments_description = options[:arguments_name] || ''
51
51
  @arguments_options = Array(options[:arguments_options]).flatten
52
+ @arguments = options[:arguments] || []
52
53
  @skips_pre = options[:skips_pre]
53
54
  @skips_post = options[:skips_post]
54
55
  @skips_around = options[:skips_around]
@@ -25,6 +25,10 @@ module GLI
25
25
  @arguments_options
26
26
  end
27
27
 
28
+ def arguments
29
+ @arguments
30
+ end
31
+
28
32
  # If true, this command doesn't want the pre block run before it executes
29
33
  def skips_pre
30
34
  @skips_pre
@@ -3,7 +3,34 @@ module GLI
3
3
  module HelpModules
4
4
  # Handles wrapping text
5
5
  class ArgNameFormatter
6
- def format(arguments_description,arguments_options)
6
+ def format(arguments_description,arguments_options,arguments)
7
+ # Select which format to use: argname or arguments
8
+ # Priority to old way: argname
9
+ desc = format_argname(arguments_description, arguments_options)
10
+ desc = format_arguments(arguments) if desc.strip == ''
11
+ desc
12
+ end
13
+
14
+ def format_arguments(arguments)
15
+ return '' if arguments.empty?
16
+ desc = ""
17
+
18
+ # Go through the arguments, building the description string
19
+ arguments.each do |arg|
20
+ arg_desc = "#{arg.name}"
21
+ if arg.optional?
22
+ arg_desc = "[#{arg_desc}]"
23
+ end
24
+ if arg.multiple?
25
+ arg_desc = "#{arg_desc}[, #{arg_desc}]*"
26
+ end
27
+ desc = desc + " " + arg_desc
28
+ end
29
+
30
+ desc
31
+ end
32
+
33
+ def format_argname(arguments_description,arguments_options)
7
34
  return '' if String(arguments_description).strip == ''
8
35
  desc = arguments_description
9
36
  if arguments_options.include? :optional
@@ -11,7 +11,7 @@ module GLI
11
11
  def synopses_for_command(command)
12
12
  synopses = []
13
13
  one_line_usage = basic_usage(command)
14
- one_line_usage << command.arguments_description
14
+ one_line_usage << ArgNameFormatter.new.format(command.arguments_description,command.arguments_options,command.arguments).strip
15
15
  if command.commands.empty?
16
16
  synopses << one_line_usage
17
17
  else
@@ -73,7 +73,7 @@ module GLI
73
73
  usage << ' '
74
74
  usage << sub_options_doc
75
75
  end
76
- arg_name_doc = ArgNameFormatter.new.format(sub.arguments_description,sub.arguments_options).strip
76
+ arg_name_doc = ArgNameFormatter.new.format(sub.arguments_description,sub.arguments_options,sub.arguments).strip
77
77
  if arg_name_doc.length > 0
78
78
  usage << ' '
79
79
  usage << arg_name_doc
data/lib/gli/dsl.rb CHANGED
@@ -36,6 +36,26 @@ module GLI
36
36
  @next_arg_options = options
37
37
  end
38
38
 
39
+ # Describes one of the arguments of the next command
40
+ #
41
+ # +name+:: A String that *briefly* describes the argument given to the following command.
42
+ # +options+:: Symbol or array of symbols to annotate this argument. This doesn't affect parsing, just
43
+ # the help output. Values recognized are:
44
+ # +:optional+:: indicates this argument is optional; will format it with square brackets
45
+ # +:multiple+:: indicates multiple values are accepted; will format appropriately
46
+ #
47
+ # Example:
48
+ # arg :output
49
+ # arg :input, :multiple
50
+ # command :pack do ...
51
+ #
52
+ # Produces the synopsis:
53
+ # app.rb [global options] pack output input[, input]*
54
+ def arg(name, options=[])
55
+ @next_arguments ||= []
56
+ @next_arguments << Argument.new(name, Array(options).flatten)
57
+ end
58
+
39
59
  # set the default value of the next flag or switch
40
60
  #
41
61
  # +val+:: The default value to be used for the following flag if the user doesn't specify one
@@ -152,6 +172,7 @@ module GLI
152
172
  :description => @next_desc,
153
173
  :arguments_name => @next_arg_name,
154
174
  :arguments_options => @next_arg_options,
175
+ :arguments => @next_arguments,
155
176
  :long_desc => @next_long_desc,
156
177
  :skips_pre => @skips_pre,
157
178
  :skips_post => @skips_post,
@@ -178,6 +199,7 @@ module GLI
178
199
  yield command
179
200
  end
180
201
  clear_nexts
202
+ @next_arguments = []
181
203
  end
182
204
  alias :c :command
183
205
 
@@ -5,6 +5,21 @@ module GLI
5
5
  module StandardException
6
6
  def exit_code; 1; end
7
7
  end
8
+
9
+ # Hack to request help from within a command
10
+ # Will *not* be rethrown when GLI_DEBUG is ON
11
+ class RequestHelp < StandardError
12
+ include StandardException
13
+ def exit_code; 0; end
14
+
15
+ # The command for which the argument was unknown
16
+ attr_reader :command_in_context
17
+
18
+ def initialize(command_in_context)
19
+ @command_in_context = command_in_context
20
+ end
21
+ end
22
+
8
23
  # Indicates that the command line invocation was bad
9
24
  class BadCommandLine < StandardError
10
25
  include StandardException
@@ -44,6 +59,17 @@ module GLI
44
59
  end
45
60
  end
46
61
 
62
+ class MissingRequiredArgumentsException < BadCommandLine
63
+ # The command for which the argument was unknown
64
+ attr_reader :command_in_context
65
+ # +message+:: the error message to show the user
66
+ # +command+:: the command we were using to parse command-specific options
67
+ def initialize(message,command)
68
+ super(message)
69
+ @command_in_context = command
70
+ end
71
+ end
72
+
47
73
  # Indicates the bad command line was an unknown command argument
48
74
  class UnknownCommandArgument < CommandException
49
75
  end
@@ -37,23 +37,24 @@ module GLI
37
37
  end
38
38
  parsing_result.command = @command_finder.find_command(command_name)
39
39
  unless command_name == 'help'
40
- verify_required_options!(@flags,parsing_result.global_options)
40
+ verify_required_options!(@flags, parsing_result.command, parsing_result.global_options)
41
41
  end
42
42
  parsing_result
43
43
  end
44
44
 
45
45
  protected
46
46
 
47
- def verify_required_options!(flags,options)
47
+ def verify_required_options!(flags, command, options)
48
48
  missing_required_options = flags.values.
49
49
  select(&:required?).
50
50
  reject { |option|
51
51
  options[option.name] != nil
52
52
  }
53
53
  unless missing_required_options.empty?
54
- raise BadCommandLine, missing_required_options.map { |option|
54
+ missing_required_options.sort!
55
+ raise MissingRequiredArgumentsException.new(missing_required_options.map { |option|
55
56
  "#{option.name} is required"
56
- }.join(' ')
57
+ }.join(', '), command)
57
58
  end
58
59
  end
59
60
  end
@@ -86,7 +87,7 @@ module GLI
86
87
  command_finder = CommandFinder.new(command.commands,command.get_default_command)
87
88
  next_command_name = arguments.shift
88
89
 
89
- verify_required_options!(command.flags,parsed_command_options[command])
90
+ verify_required_options!(command.flags, command, parsed_command_options[command])
90
91
 
91
92
  begin
92
93
  command = command_finder.find_command(next_command_name)
@@ -138,7 +139,7 @@ module GLI
138
139
  subcommand,args = find_subcommand(command,parsing_result.arguments)
139
140
  parsing_result.command = subcommand
140
141
  parsing_result.arguments = args
141
- verify_required_options!(command.flags,parsing_result.command_options)
142
+ verify_required_options!(command.flags, parsing_result.command, parsing_result.command_options)
142
143
  end
143
144
 
144
145
  private
@@ -71,7 +71,7 @@ module GLI
71
71
  unless help_args.empty?
72
72
  help_args << "Get help for #{command.name}"
73
73
  option_parser.on(*help_args) do
74
- raise CommandException.new(nil,command,0)
74
+ raise RequestHelp.new(command)
75
75
  end
76
76
  end
77
77
  end
data/lib/gli/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module GLI
2
2
  unless const_defined? :VERSION
3
- VERSION = '2.10.0'
3
+ VERSION = '2.11.0'
4
4
  end
5
5
  end
@@ -35,7 +35,10 @@ version Todo::VERSION
35
35
  commands_from 'todo/commands'
36
36
  commands_from File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'todo_plugins', 'commands'))
37
37
 
38
+ arg_name :argument, :optional
38
39
  command :first do |c| c.action { |g,o,a| puts "first: #{a.join(',')}" } end
40
+
41
+ arg :argument, :optional
39
42
  command :second do |c| c.action { |g,o,a| puts "second: #{a.join(',')}" } end
40
43
 
41
44
  command :chained => [ :first, :second ]
@@ -2,6 +2,7 @@ desc "Create a new task or context"
2
2
  command [:create,:new] do |c|
3
3
  c.desc "Make a new task"
4
4
  c.arg_name 'task_name', :multiple
5
+ c.arg :should_ignore_this
5
6
  c.command :tasks do |tasks|
6
7
  tasks.action do |global,options,args|
7
8
  puts "#{args}"
@@ -9,6 +10,7 @@ command [:create,:new] do |c|
9
10
  end
10
11
 
11
12
  c.desc "Make a new context"
13
+ c.arg :should_ignore_this
12
14
  c.arg_name 'context_name', :optional
13
15
  c.command :contexts do |contexts|
14
16
  contexts.action do |global,options,args|
@@ -20,5 +22,32 @@ command [:create,:new] do |c|
20
22
  c.action do
21
23
  puts "default action"
22
24
  end
25
+
26
+ c.arg "first"
27
+ c.arg "second"
28
+ c.arg "name", :optional
29
+ c.command :"relation_1-1" do |remote|
30
+ remote.action do |global,options,args|
31
+ puts "relation: #{args}"
32
+ end
33
+ end
34
+
35
+ c.arg "first", :multiple
36
+ c.arg "second"
37
+ c.arg "name", :optional
38
+ c.command :"relation_n-1" do |remote|
39
+ remote.action do |global,options,args|
40
+ puts "relation: #{args}"
41
+ end
42
+ end
43
+
44
+ c.arg "first"
45
+ c.arg "second", :multiple
46
+ c.arg "name", :optional
47
+ c.command :"relation_1-n" do |remote|
48
+ remote.action do |global,options,args|
49
+ puts "relation: #{args}"
50
+ end
51
+ end
23
52
  end
24
53
 
@@ -15,6 +15,7 @@ command [:list] do |c|
15
15
  c.switch [:l,:long]
16
16
 
17
17
  c.flag :required_flag, :required => true
18
+ c.flag :required_flag2, :required => true
18
19
 
19
20
  c.desc "List tasks"
20
21
  c.long_desc %(
data/test/tc_gli.rb CHANGED
@@ -84,6 +84,7 @@ class TC_testGLI < Clean::Test::TestCase
84
84
  assert_equal 64, @app.run(['foo']), "Expected exit status to be 64"
85
85
  assert @fake_stderr.contained?(/flag is required/), @fake_stderr.strings.inspect
86
86
  assert @fake_stderr.contained?(/other_flag is required/), @fake_stderr.strings.inspect
87
+ assert @fake_stderr.contained?(/flag is required, other_flag is required/), @fake_stderr.strings.inspect
87
88
  assert !@called
88
89
 
89
90
  assert_equal 0, @app.run(['foo','--flag=bar','--other_flag=blah']), "Expected exit status to be 0 #{@fake_stderr.strings.join(',')}"
@@ -104,6 +105,7 @@ class TC_testGLI < Clean::Test::TestCase
104
105
  assert_equal 64, @app.run(['foo']), "Expected exit status to be 64"
105
106
  assert @fake_stderr.contained?(/flag is required/), @fake_stderr.strings.inspect
106
107
  assert @fake_stderr.contained?(/other_flag is required/), @fake_stderr.strings.inspect
108
+ assert @fake_stderr.contained?(/flag is required, other_flag is required/), @fake_stderr.strings.inspect
107
109
  assert !@called
108
110
 
109
111
  assert_equal 0, @app.run(['--flag=bar','--other_flag=blah','foo']), "Expected exit status to be 0 #{@fake_stderr.strings.join(',')}"
@@ -663,6 +665,19 @@ class TC_testGLI < Clean::Test::TestCase
663
665
  assert_raises(GLI::CustomExit) { @app.run(['foo']) }
664
666
  end
665
667
 
668
+ def test_gli_help_does_not_raise_on_debug
669
+ ENV['GLI_DEBUG'] = 'true'
670
+
671
+ @app.reset
672
+ @app.command(:multiply) do |c|
673
+ c.action do |g,o,a|
674
+ # Nothing
675
+ end
676
+ end
677
+
678
+ assert_nothing_raised(GLI::CustomExit) { @app.run(['multiply', '--help']) }
679
+ end
680
+
666
681
  class ConvertMe
667
682
  attr_reader :value
668
683
  def initialize(value)
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.10.0
4
+ version: 2.11.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: 2014-04-22 00:00:00.000000000 Z
11
+ date: 2014-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -174,6 +174,7 @@ files:
174
174
  - lib/gli.rb
175
175
  - lib/gli/app.rb
176
176
  - lib/gli/app_support.rb
177
+ - lib/gli/argument.rb
177
178
  - lib/gli/command.rb
178
179
  - lib/gli/command_finder.rb
179
180
  - lib/gli/command_line_option.rb