pry 0.9.8pre2 → 0.9.8pre3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,317 @@
1
+ require 'helper'
2
+
3
+ describe "Pry::Command" do
4
+
5
+ before do
6
+ @set = Pry::CommandSet.new
7
+ end
8
+
9
+ describe 'call_safely' do
10
+
11
+ it 'should display a message if gems are missing' do
12
+ cmd = @set.command_class "ford-prefect", "From a planet near Beetlegeuse", :requires_gem => %w(ghijkl) do
13
+ #
14
+ end
15
+
16
+ mock_command(cmd, %w(hello world)).output.should =~ /install-command ford-prefect/
17
+ end
18
+
19
+ it 'should abort early if arguments are required' do
20
+ cmd = @set.command_class 'arthur-dent', "Doesn't understand Thursdays", :argument_required => true do
21
+ #
22
+ end
23
+
24
+ lambda {
25
+ mock_command(cmd, %w())
26
+ }.should.raise(Pry::CommandError)
27
+ end
28
+
29
+ it 'should return VOID without keep_retval' do
30
+ cmd = @set.command_class 'zaphod-beeblebrox', "Likes pan-Galactic Gargle Blasters" do
31
+ def process
32
+ 3
33
+ end
34
+ end
35
+
36
+ mock_command(cmd).return.should == Pry::Command::VOID_VALUE
37
+ end
38
+
39
+ it 'should return the return value with keep_retval' do
40
+ cmd = @set.command_class 'tricia-mcmillian', "a.k.a Trillian", :keep_retval => true do
41
+ def process
42
+ 5
43
+ end
44
+ end
45
+
46
+ mock_command(cmd).return.should == 5
47
+ end
48
+
49
+ it 'should call hooks in the right order' do
50
+ cmd = @set.command_class 'marvin', "Pained by the diodes in his left side" do
51
+ def process
52
+ output.puts 3 + args[0].to_i
53
+ end
54
+ end
55
+
56
+ @set.before_command 'marvin' do |i|
57
+ output.puts 2 + i.to_i
58
+ end
59
+ @set.before_command 'marvin' do |i|
60
+ output.puts 1 + i.to_i
61
+ end
62
+
63
+ @set.after_command 'marvin' do |i|
64
+ output.puts 4 + i.to_i
65
+ end
66
+
67
+ @set.after_command 'marvin' do |i|
68
+ output.puts 5 + i.to_i
69
+ end
70
+
71
+ mock_command(cmd, %w(2)).output.should == "3\n4\n5\n6\n7\n"
72
+ end
73
+
74
+ # TODO: This strikes me as rather silly...
75
+ it 'should return the value from the last hook with keep_retval' do
76
+ cmd = @set.command_class 'slartibartfast', "Designs Fjords", :keep_retval => true do
77
+ def process
78
+ 22
79
+ end
80
+ end
81
+
82
+ @set.after_command 'slartibartfast' do
83
+ 10
84
+ end
85
+
86
+ mock_command(cmd).return.should == 10
87
+ end
88
+ end
89
+
90
+ describe 'help' do
91
+ it 'should default to the description for blocky commands' do
92
+ @set.command 'oolon-colluphid', "Raving Atheist" do
93
+ #
94
+ end
95
+
96
+ mock_command(@set.commands['help'], %w(oolon-colluphid), :command_set => @set).output.should =~ /Raving Atheist/
97
+ end
98
+
99
+ it 'should use slop to generate the help for classy commands' do
100
+ @set.command_class 'eddie', "The ship-board computer" do
101
+ def options(opt)
102
+ opt.banner "Over-cheerful, and makes a ticking noise."
103
+ end
104
+ end
105
+
106
+ mock_command(@set.commands['help'], %w(eddie), :command_set => @set).output.should =~ /Over-cheerful/
107
+ end
108
+
109
+ it 'should provide --help for classy commands' do
110
+ cmd = @set.command_class 'agrajag', "Killed many times by Arthur" do
111
+ def options(opt)
112
+ opt.on :r, :retaliate, "Try to get Arthur back"
113
+ end
114
+ end
115
+
116
+ mock_command(cmd, %w(--help)).output.should =~ /--retaliate/
117
+ end
118
+
119
+ it 'should provide a -h for classy commands' do
120
+ cmd = @set.command_class 'zarniwoop', "On an intergalactic cruise, in his office." do
121
+ def options(opt)
122
+ opt.on :e, :escape, "Help zaphod escape the Total Perspective Vortex"
123
+ end
124
+ end
125
+
126
+ mock_command(cmd, %w(--help)).output.should =~ /Total Perspective Vortex/
127
+ end
128
+
129
+ it 'should use the banner provided' do
130
+ cmd = @set.command_class 'deep-thought', "The second-best computer ever" do
131
+ banner <<-BANNER
132
+ Who's merest operational parameters, I am not worthy to compute.
133
+ BANNER
134
+ end
135
+
136
+ mock_command(cmd, %w(--help)).output.should =~ /Who\'s merest/
137
+ end
138
+ end
139
+
140
+
141
+ describe 'context' do
142
+ context = {
143
+ :target => binding,
144
+ :output => StringIO.new,
145
+ :eval_string => "eval-string",
146
+ :command_set => @set,
147
+ :pry_instance => Object.new
148
+ }
149
+
150
+ it 'should capture lots of stuff from the hash passed to new before setup' do
151
+ cmd = @set.command_class 'fenchurch', "Floats slightly off the ground" do
152
+ define_method(:setup) do
153
+ self.context.should == context
154
+ target.should == context[:target]
155
+ target_self.should == context[:target].eval('self')
156
+ output.should == context[:output]
157
+ end
158
+
159
+ define_method(:process) do
160
+ eval_string.should == "eval-string"
161
+ command_set.should == @set
162
+ _pry_.should == context[:pry_instance]
163
+ end
164
+ end
165
+
166
+ cmd.new(context).call
167
+ end
168
+ end
169
+
170
+ describe 'classy api' do
171
+
172
+ it 'should call setup, then options, then process' do
173
+ cmd = @set.command_class 'rooster', "Has a tasty towel" do
174
+ def setup
175
+ output.puts "setup"
176
+ end
177
+
178
+ def options(opt)
179
+ output.puts "options"
180
+ end
181
+
182
+ def process
183
+ output.puts "process"
184
+ end
185
+ end
186
+
187
+ mock_command(cmd).output.should == "setup\noptions\nprocess\n"
188
+ end
189
+
190
+ it 'should raise a command error if process is not overridden' do
191
+ cmd = @set.command_class 'jeltz', "Commander of a Vogon constructor fleet" do
192
+ def proccces
193
+ #
194
+ end
195
+ end
196
+
197
+ lambda {
198
+ mock_command(cmd)
199
+ }.should.raise(Pry::CommandError)
200
+ end
201
+
202
+ it 'should work if neither options, nor setup is overridden' do
203
+ cmd = @set.command_class 'wowbagger', "Immortal, insulting.", :keep_retval => true do
204
+ def process
205
+ 5
206
+ end
207
+ end
208
+
209
+ mock_command(cmd).return.should == 5
210
+ end
211
+
212
+ it 'should provide opts and args as provided by slop' do
213
+ cmd = @set.command_class 'lintilla', "One of 800,000,000 clones" do
214
+ def options(opt)
215
+ opt.on :f, :four, "A numeric four", :as => Integer, :optional => true
216
+ end
217
+
218
+ def process
219
+ args.should == ['four']
220
+ opts[:f].should == 4
221
+ end
222
+ end
223
+
224
+ mock_command(cmd, %w(--four 4 four))
225
+ end
226
+ end
227
+
228
+ describe 'tokenize' do
229
+ it 'should interpolate string with #{} in them' do
230
+ cmd = @set.command 'random-dent' do |*args|
231
+ args.should == ["3", "8"]
232
+ end
233
+
234
+ foo = 5
235
+
236
+ cmd.new(:target => binding).process_line 'random-dent #{1 + 2} #{3 + foo}'
237
+ end
238
+
239
+ it 'should not fail if interpolation is not needed and target is not set' do
240
+ cmd = @set.command 'the-book' do |*args|
241
+ args.should == ['--help']
242
+ end
243
+
244
+ cmd.new.process_line 'the-book --help'
245
+ end
246
+
247
+ it 'should not interpolate commands with :interpolate => false' do
248
+ cmd = @set.command 'thor', 'norse god', :interpolate => false do |*args|
249
+ args.should == ['%(#{foo})']
250
+ end
251
+
252
+ cmd.new.process_line 'thor %(#{foo})'
253
+ end
254
+
255
+ it 'should use shell-words to split strings' do
256
+ cmd = @set.command 'eccentrica' do |*args|
257
+ args.should == ['gallumbits', 'eroticon', '6']
258
+ end
259
+
260
+ cmd.new.process_line %(eccentrica "gallumbits" 'erot''icon' 6)
261
+ end
262
+
263
+ it 'should split on spaces if shellwords is not used' do
264
+ cmd = @set.command 'bugblatter-beast', 'would eat its grandmother', :shellwords => false do |*args|
265
+ args.should == ['"of', 'traal"']
266
+ end
267
+
268
+ cmd.new.process_line %(bugblatter-beast "of traal")
269
+ end
270
+
271
+ it 'should add captures to arguments for regex commands' do
272
+ cmd = @set.command /perfectly (normal)( beast)?/i do |*args|
273
+ args.should == ['Normal', ' Beast', '(honest!)']
274
+ end
275
+
276
+ cmd.new.process_line %(Perfectly Normal Beast (honest!))
277
+ end
278
+ end
279
+
280
+ describe 'process_line' do
281
+ it 'should check for command name collisions if configured' do
282
+ old = Pry.config.collision_warning
283
+ Pry.config.collision_warning = true
284
+
285
+ cmd = @set.command 'frankie' do
286
+
287
+ end
288
+
289
+ frankie = 'boyle'
290
+ output = StringIO.new
291
+ cmd.new(:target => binding, :output => output).process_line %(frankie mouse)
292
+
293
+ output.string.should =~ /Command name collision/
294
+
295
+ Pry.config.collision_warning = old
296
+ end
297
+
298
+ it "should set the commands' arg_string and captures" do
299
+
300
+ cmd = @set.command /benj(ie|ei)/ do |*args|
301
+ self.arg_string.should == "mouse"
302
+ self.captures.should == ['ie']
303
+ args.should == ['ie', 'mouse']
304
+ end
305
+
306
+ cmd.new.process_line %(benjie mouse)
307
+ end
308
+
309
+ it "should raise an error if the line doesn't match the command" do
310
+ cmd = @set.command 'grunthos', 'the flatulent'
311
+
312
+ lambda {
313
+ cmd.new.process_line %(grumpos)
314
+ }.should.raise(Pry::CommandError)
315
+ end
316
+ end
317
+ end
@@ -3,7 +3,10 @@ require 'helper'
3
3
  describe Pry::CommandSet do
4
4
  before do
5
5
  @set = Pry::CommandSet.new
6
- @ctx = Pry::CommandContext.new
6
+ @ctx = {
7
+ :target => binding,
8
+ :command_set => @set
9
+ }
7
10
  end
8
11
 
9
12
  it 'should call the block used for the command when it is called' do
@@ -24,11 +27,11 @@ describe Pry::CommandSet do
24
27
  @set.run_command @ctx, 'foo', 1, 2, 3
25
28
  end
26
29
 
27
- it 'should use the first argument as self' do
30
+ it 'should use the first argument as context' do
28
31
  ctx = @ctx
29
32
 
30
33
  @set.command 'foo' do
31
- self.should == ctx
34
+ self.context.should == ctx
32
35
  end
33
36
 
34
37
  @set.run_command @ctx, 'foo'
@@ -159,9 +162,9 @@ describe Pry::CommandSet do
159
162
  @set.desc('foo').should == 'bar'
160
163
  end
161
164
 
162
- it 'should return Pry::CommandContext::VOID_VALUE for commands by default' do
165
+ it 'should return Pry::Command::VOID_VALUE for commands by default' do
163
166
  @set.command('foo') { 3 }
164
- @set.run_command(@ctx, 'foo').should == Pry::CommandContext::VOID_VALUE
167
+ @set.run_command(@ctx, 'foo').should == Pry::Command::VOID_VALUE
165
168
  end
166
169
 
167
170
  it 'should be able to keep return values' do
@@ -184,7 +187,7 @@ describe Pry::CommandSet do
184
187
  end
185
188
 
186
189
  @set.run_command(@ctx, 'foo')
187
- Pry::CommandContext.new.should.not.respond_to :my_helper
190
+ Pry::Command.subclass('foo', '', {}, Module.new).new({:target => binding}).should.not.respond_to :my_helper
188
191
  end
189
192
 
190
193
  it 'should not recreate a new helper module when helpers is called' do
@@ -241,8 +244,8 @@ describe Pry::CommandSet do
241
244
  end
242
245
 
243
246
  it "should provide a 'help' command" do
244
- @ctx.command_set = @set
245
- @ctx.output = StringIO.new
247
+ @ctx[:command_set] = @set
248
+ @ctx[:output] = StringIO.new
246
249
 
247
250
  lambda {
248
251
  @set.run_command(@ctx, 'help')
@@ -255,12 +258,12 @@ describe Pry::CommandSet do
255
258
  @set.command 'moo', "Mooerizes" do; end
256
259
  @set.command 'boo', "Booerizes" do; end
257
260
 
258
- @ctx.command_set = @set
259
- @ctx.output = StringIO.new
261
+ @ctx[:command_set] = @set
262
+ @ctx[:output] = StringIO.new
260
263
 
261
264
  @set.run_command(@ctx, 'help')
262
265
 
263
- doc = @ctx.output.string
266
+ doc = @ctx[:output].string
264
267
 
265
268
  order = [doc.index("boo"),
266
269
  doc.index("foo"),
@@ -331,15 +334,15 @@ describe Pry::CommandSet do
331
334
  end
332
335
 
333
336
  it 'should share the context with the original command' do
334
- @ctx.target = "test target string"
337
+ @ctx[:target] = "test target string".__binding__
335
338
  before_val = nil
336
339
  orig_val = nil
337
340
  @set.command('foo') { orig_val = target }
338
341
  @set.before_command('foo') { before_val = target }
339
342
  @set.run_command(@ctx, 'foo')
340
343
 
341
- before_val.should == @ctx.target
342
- orig_val.should == @ctx.target
344
+ before_val.should == @ctx[:target]
345
+ orig_val.should == @ctx[:target]
343
346
  end
344
347
 
345
348
  it 'should work when applied multiple times' do
@@ -375,15 +378,15 @@ describe Pry::CommandSet do
375
378
  end
376
379
 
377
380
  it 'should share the context with the original command' do
378
- @ctx.target = "test target string"
379
- after_val = nil
381
+ @ctx[:target] = "test target string".__binding__
382
+ after_val = nil
380
383
  orig_val = nil
381
384
  @set.command('foo') { orig_val = target }
382
385
  @set.after_command('foo') { after_val = target }
383
386
  @set.run_command(@ctx, 'foo')
384
387
 
385
- after_val.should == @ctx.target
386
- orig_val.should == @ctx.target
388
+ after_val.should == @ctx[:target]
389
+ orig_val.should == @ctx[:target]
387
390
  end
388
391
 
389
392
  it 'should determine the return value for the command' do
@@ -418,4 +421,135 @@ describe Pry::CommandSet do
418
421
  end
419
422
 
420
423
  end
424
+
425
+ describe 'find_command' do
426
+ it 'should find commands with the right string' do
427
+ cmd = @set.command('rincewind'){ }
428
+ @set.find_command('rincewind').should == cmd
429
+ end
430
+
431
+ it 'should not find commands with spaces before' do
432
+ cmd = @set.command('luggage'){ }
433
+ @set.find_command(' luggage').should == nil
434
+ end
435
+
436
+ it 'should find commands with arguments after' do
437
+ cmd = @set.command('vetinari'){ }
438
+ @set.find_command('vetinari --knock 3').should == cmd
439
+ end
440
+
441
+ it 'should find commands with names containing spaces' do
442
+ cmd = @set.command('nobby nobbs'){ }
443
+ @set.find_command('nobby nobbs --steal petty-cash').should == cmd
444
+ end
445
+
446
+ it 'should find command defined by regex' do
447
+ cmd = @set.command(/(capt|captain) vimes/i){ }
448
+ @set.find_command('Capt Vimes').should == cmd
449
+ end
450
+
451
+ it 'should find commands defined by regex with arguments' do
452
+ cmd = @set.command(/(cpl|corporal) Carrot/i){ }
453
+ @set.find_command('cpl carrot --write-home').should == cmd
454
+ end
455
+
456
+ it 'should not find commands by listing' do
457
+ cmd = @set.command(/werewol(f|ve)s?/, 'only once a month', :listing => "angua"){ }
458
+ @set.find_command('angua').should == nil
459
+ end
460
+
461
+ it 'should not find commands without command_prefix' do
462
+ Pry.config.command_prefix = '%'
463
+ cmd = @set.command('detritus'){ }
464
+ @set.find_command('detritus').should == nil
465
+ Pry.config.command_prefix = ''
466
+ end
467
+
468
+ it "should find commands that don't use the prefix" do
469
+ Pry.config.command_prefix = '%'
470
+ cmd = @set.command('colon', 'Sergeant Fred', :use_prefix => false){ }
471
+ @set.find_command('colon').should == cmd
472
+ Pry.config.command_prefix = ''
473
+ end
474
+ end
475
+
476
+ describe '.valid_command?' do
477
+ it 'should be true for commands that can be found' do
478
+ cmd = @set.command('archchancellor')
479
+ @set.valid_command?('archchancellor of_the?(:University)').should == true
480
+ end
481
+
482
+ it 'should be false for commands that can\'' do
483
+ @set.valid_command?('def monkey(ape)').should == false
484
+ end
485
+
486
+ it 'should not cause argument interpolation' do
487
+ cmd = @set.command('hello')
488
+ lambda {
489
+ @set.valid_command?('hello #{raise "futz"}')
490
+ }.should.not.raise
491
+ end
492
+ end
493
+
494
+ describe '.process_line' do
495
+
496
+ it 'should return Result.new(false) if there is no matching command' do
497
+ result = @set.process_line('1 + 42')
498
+ result.command?.should == false
499
+ result.void_command?.should == false
500
+ result.retval.should == nil
501
+ end
502
+
503
+ it 'should return Result.new(true, VOID) if the command is not keep_retval' do
504
+ @set.command_class('mrs-cake') do
505
+ def process; 42; end
506
+ end
507
+
508
+ result = @set.process_line('mrs-cake')
509
+ result.command?.should == true
510
+ result.void_command?.should == true
511
+ result.retval.should == Pry::Command::VOID_VALUE
512
+ end
513
+
514
+ it 'should return Result.new(true, retval) if the command is keep_retval' do
515
+ @set.command_class('magrat', 'the maiden', :keep_retval => true) do
516
+ def process; 42; end
517
+ end
518
+
519
+ result = @set.process_line('magrat')
520
+ result.command?.should == true
521
+ result.void_command?.should == false
522
+ result.retval.should == 42
523
+ end
524
+
525
+ it 'should pass through context' do
526
+ ctx = {
527
+ :eval_string => "bloomers",
528
+ :pry_instance => Object.new,
529
+ :output => StringIO.new,
530
+ :target => binding
531
+ }
532
+ @set.command_class('agnes') do
533
+ define_method(:process) do
534
+ eval_string.should == ctx[:eval_string]
535
+ output.should == ctx[:output]
536
+ target.should == ctx[:target]
537
+ _pry_.should == ctx[:pry_instance]
538
+ end
539
+ end
540
+
541
+ @set.process_line('agnes', ctx)
542
+ end
543
+
544
+ it 'should add command_set to context' do
545
+ set = @set
546
+ @set.command_class(/nann+y ogg+/) do
547
+ define_method(:process) do
548
+ command_set.should == set
549
+ end
550
+ end
551
+
552
+ @set.process_line('nannnnnny oggggg')
553
+ end
554
+ end
421
555
  end