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.
@@ -1,6 +1,6 @@
1
1
  = Git-Like Interface Command Line Parser
2
2
 
3
- <b>This describes the forthcoming GLI2 and might not be 100% accurate</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
 
@@ -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
@@ -14,7 +14,7 @@ module GLI
14
14
  def reset # :nodoc:
15
15
  switches.clear
16
16
  flags.clear
17
- commands.clear
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
@@ -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
 
@@ -30,6 +30,11 @@ module GLI
30
30
  @skips_post
31
31
  end
32
32
 
33
+ # If true, this command doesn't want the around block called
34
+ def skips_around
35
+ @skips_around
36
+ end
37
+
33
38
  # Return the Array of the command's names
34
39
  def names
35
40
  all_forms
@@ -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)
@@ -140,6 +140,7 @@ module GLI
140
140
  :long_desc => @next_long_desc,
141
141
  :skips_pre => @skips_pre,
142
142
  :skips_post => @skips_post,
143
+ :skips_around => @skips_around,
143
144
  }
144
145
  if names.first.kind_of? Hash
145
146
  command = GLI::Commands::CompoundCommand.new(self,
@@ -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 = name.to_s
91
- return names_to_commands[name] if names_to_commands[name]
92
- # Now try to match on partial names
93
- partial_matches = names_to_commands.keys.select { |command_name| command_name =~ /^#{name}/ }
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
@@ -1,5 +1,5 @@
1
1
  module GLI
2
2
  unless const_defined? :VERSION
3
- VERSION = '2.0.0.rc3' #:nodoc:
3
+ VERSION = '2.0.0.rc4' #:nodoc:
4
4
  end
5
5
  end
@@ -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 tear_down
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
@@ -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
@@ -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.rc3
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-05-28 00:00:00.000000000 Z
12
+ date: 2012-06-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake