bond 0.1.4 → 0.2.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.
Files changed (43) hide show
  1. data/CHANGELOG.rdoc +12 -0
  2. data/LICENSE.txt +1 -1
  3. data/README.rdoc +195 -173
  4. data/Rakefile +9 -45
  5. data/lib/bond.rb +62 -93
  6. data/lib/bond/agent.rb +39 -33
  7. data/lib/bond/completion.rb +15 -27
  8. data/lib/bond/completions/activerecord.rb +12 -0
  9. data/lib/bond/completions/array.rb +1 -0
  10. data/lib/bond/completions/bond.rb +2 -0
  11. data/lib/bond/completions/hash.rb +3 -0
  12. data/lib/bond/completions/kernel.rb +13 -0
  13. data/lib/bond/completions/module.rb +7 -0
  14. data/lib/bond/completions/object.rb +21 -0
  15. data/lib/bond/completions/struct.rb +1 -0
  16. data/lib/bond/input.rb +28 -0
  17. data/lib/bond/m.rb +95 -0
  18. data/lib/bond/mission.rb +109 -69
  19. data/lib/bond/missions/anywhere_mission.rb +18 -0
  20. data/lib/bond/missions/default_mission.rb +16 -6
  21. data/lib/bond/missions/method_mission.rb +194 -13
  22. data/lib/bond/missions/object_mission.rb +29 -32
  23. data/lib/bond/missions/operator_method_mission.rb +26 -0
  24. data/lib/bond/rawline.rb +3 -3
  25. data/lib/bond/rc.rb +48 -0
  26. data/lib/bond/readline.rb +9 -6
  27. data/lib/bond/search.rb +51 -12
  28. data/lib/bond/version.rb +3 -0
  29. data/test/agent_test.rb +168 -65
  30. data/test/anywhere_mission_test.rb +34 -0
  31. data/test/bacon_extensions.rb +26 -0
  32. data/test/bond_test.rb +38 -23
  33. data/test/completion_test.rb +123 -21
  34. data/test/completions_test.rb +96 -0
  35. data/test/method_mission_test.rb +246 -0
  36. data/test/mission_test.rb +30 -44
  37. data/test/object_mission_test.rb +28 -32
  38. data/test/operator_method_mission_test.rb +66 -0
  39. data/test/search_test.rb +106 -29
  40. data/test/test_helper.rb +20 -13
  41. metadata +37 -8
  42. data/VERSION.yml +0 -4
  43. data/lib/bond/actions.rb +0 -69
@@ -1,49 +1,46 @@
1
- # Represents a completion mission specified by :object in Bond.complete. Unlike other missions, this
2
- # one needs to both match the mission condition and have the current object being completed have
3
- # an ancestor specified by :object.
4
- class Bond::Missions::ObjectMission < Bond::Mission
1
+ # A mission which completes an object's methods. For this mission to match,
2
+ # the condition must match and the current object must have an ancestor that matches :object.
3
+ # Note: To access to the current object being completed on within an action, use the input's
4
+ # object attribute.
5
+ #
6
+ # ==== Bond.complete Options:
7
+ # [*:object*] String representing a module/class of object whose methods are completed.
8
+ # [*:action*] If an action is not specified, the default action is to complete an object's
9
+ # non-operator methods.
10
+ #
11
+ # ===== Example:
12
+ # Bond.complete(:object=>ActiveRecord::Base) {|input| input.object.class.instance_methods(false) }
13
+ class Bond::ObjectMission < Bond::Mission
5
14
  #:stopdoc:
6
- attr_reader :object_condition
7
-
15
+ OBJECTS = %w<\S+> + Bond::Mission::OBJECTS
16
+ CONDITION = '(OBJECTS)\.(\w*(?:\?|!)?)$'
8
17
  def initialize(options={})
9
- @object_condition = options.delete(:object)
10
- @object_condition = /^#{Regexp.escape(@object_condition.to_s)}$/ unless @object_condition.is_a?(Regexp)
11
- options[:on] ||= /(\S+|[^.]+)\.([^.\s]*)$/
12
- @eval_binding = options[:eval_binding]
18
+ @object_condition = /^#{options[:object]}$/
19
+ options[:on] ||= Regexp.new condition_with_objects
13
20
  super
14
21
  end
15
22
 
16
23
  def unique_id
17
- "#{@object_condition.inspect}+#{@condition.inspect}"
24
+ "#{@object_condition.inspect}+#{@on.inspect}"
18
25
  end
19
26
 
20
- def handle_valid_match(input)
21
- if (match = super)
22
- begin
23
- eval_object(match)
24
- rescue Exception
25
- return false
26
- end
27
- if (match = @evaled_object.class.ancestors.any? {|e| e.to_s =~ @object_condition })
28
- @completion_prefix = @matched[1] + "."
29
- @input = @matched[2]
30
- @input.instance_variable_set("@object", @evaled_object)
31
- @input.instance_eval("def self.object; @object ; end")
32
- @action ||= lambda {|e| default_action(e.object) }
33
- else
34
- match = false
35
- end
36
- end
37
- match
27
+ def do_match(input)
28
+ super && eval_object(@matched[1]) && @evaled_object.class.respond_to?(:ancestors) &&
29
+ @evaled_object.class.ancestors.any? {|e| e.to_s =~ @object_condition }
38
30
  end
39
31
 
40
- def eval_object(match)
41
- @matched = match
42
- @evaled_object = self.class.current_eval(match[1], @eval_binding)
32
+ def after_match(input)
33
+ @completion_prefix = @matched[1] + "."
34
+ @action ||= lambda {|e| default_action(e.object) }
35
+ create_input @matched[2], :object=>@evaled_object
43
36
  end
44
37
 
45
38
  def default_action(obj)
46
39
  obj.methods.map {|e| e.to_s} - OPERATORS
47
40
  end
41
+
42
+ def match_message
43
+ "Matches completion for object with ancestor matching #{@object_condition.inspect}."
44
+ end
48
45
  #:startdoc:
49
46
  end
@@ -0,0 +1,26 @@
1
+ module Bond
2
+ # A mission which completes arguments for any module/class method that is an operator i.e. '>' or '*'.
3
+ # Takes same Bond.complete options as MethodMission. The only operator method this mission doesn't
4
+ # complete is '[]='. The operator '[]' should cover the first argument completion of '[]=' anyways.
5
+ class OperatorMethodMission < MethodMission
6
+ OPERATORS = Mission::OPERATORS - ["[]", "[]="]
7
+ OBJECTS = Mission::OBJECTS + %w{\S+}
8
+ CONDITION = %q{(OBJECTS)\s*(METHODS)\s*(['":])?(.*)$}
9
+
10
+ #:stopdoc:
11
+ def current_methods
12
+ (OPERATORS & MethodMission.action_methods) + ['[']
13
+ end
14
+
15
+ def matched_method
16
+ {'['=>'[]'}[@matched[2]] || @matched[2]
17
+ end
18
+
19
+ def after_match(input)
20
+ set_action_and_search
21
+ @completion_prefix, typed = input.to_s.sub(/#{Regexp.quote(@matched[-1])}$/, ''), @matched[-1]
22
+ create_input typed, :object=>@evaled_object, :argument=>1
23
+ end
24
+ #:startdoc:
25
+ end
26
+ end
data/lib/bond/rawline.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  module Bond
2
- # A readline plugin for use with {Rawline}[http://github.com/h3rald/rawline/tree/master]. This plugin
2
+ # A readline plugin for use with {Rawline}[http://github.com/h3rald/rawline]. This plugin
3
3
  # should be used in conjunction with {a Rawline shell}[http://www.h3rald.com/articles/real-world-rawline-usage].
4
4
  module Rawline
5
- def setup
5
+ def setup(agent)
6
6
  require 'rawline'
7
7
  ::Rawline.completion_append_character = nil
8
8
  ::Rawline.basic_word_break_characters= " \t\n\"\\'`><;|&{("
9
- ::Rawline.completion_proc = self
9
+ ::Rawline.completion_proc = agent
10
10
  end
11
11
 
12
12
  def line_buffer
data/lib/bond/rc.rb ADDED
@@ -0,0 +1,48 @@
1
+ module Bond
2
+ # Namespace in which completion files, ~/.bondrc and ~/.bond/completions/*.rb, are evaluated. Methods in this module
3
+ # and Search are the DSL in completion files and can be used within completion actions.
4
+ #
5
+ # === Example ~/.bondrc
6
+ # # complete arguments for any object's :respond_to?
7
+ # complete(:method=>"Object#respond_to?") {|e| e.object.methods }
8
+ # # complete arguments for any module's :public
9
+ # complete(:method=>"Module#public") {|e| e.object.instance_methods }
10
+ #
11
+ # # Share generate_tags action across completions
12
+ # complete(:method=>"edit_tags", :action=>:generate_tags)
13
+ # complete(:method=>"delete_tags", :search=>false) {|e| generate_tags(e).grep(/#{e}/i) }
14
+ #
15
+ # def generate_tags(input)
16
+ # ...
17
+ # end
18
+ module Rc
19
+ extend self, Search
20
+
21
+ # See Bond.complete
22
+ def complete(*args, &block); M.complete(*args, &block); end
23
+ # See Bond.recomplete
24
+ def recomplete(*args, &block); M.recomplete(*args, &block); end
25
+
26
+ # Action method with search which returns array of files that match current input.
27
+ def files(input)
28
+ (::Readline::FILENAME_COMPLETION_PROC.call(input) || []).map {|f|
29
+ f =~ /^~/ ? File.expand_path(f) : f
30
+ }
31
+ end
32
+
33
+ # Helper method which returns objects of a given class.
34
+ def objects_of(klass)
35
+ object = []
36
+ ObjectSpace.each_object(klass) {|e| object.push(e) }
37
+ object
38
+ end
39
+
40
+ # Calls eval with Mission.current_eval, rescuing any exceptions to return nil.
41
+ # If Bond.config[:debug] is true, exceptions are raised again.
42
+ def eval(str)
43
+ Mission.current_eval(str)
44
+ rescue Exception
45
+ raise if Bond.config[:debug]
46
+ end
47
+ end
48
+ end
data/lib/bond/readline.rb CHANGED
@@ -1,12 +1,11 @@
1
-
2
1
  module Bond
3
- # This is the default readline plugin for Bond. A valid plugin must define methods setup() and line_buffer(). setup()
4
- # should load the readline-like library and set the completion_proc. line_buffer() should give access to the full line of what
5
- # the user has typed.
2
+ # This is the default readline plugin for Bond. A valid plugin must be a module that defines methods setup
3
+ # and line_buffer as described below.
6
4
  module Readline
7
5
  DefaultBreakCharacters = " \t\n\"\\'`><=;|&{("
8
6
 
9
- def setup
7
+ # Loads the readline-like library and sets the completion_proc to the given agent.
8
+ def setup(agent)
10
9
  require 'readline'
11
10
  begin
12
11
  require 'readline_line_buffer'
@@ -37,9 +36,13 @@ module Bond
37
36
  ::Readline.basic_word_break_characters = DefaultBreakCharacters
38
37
  end
39
38
 
40
- ::Readline.completion_proc = self
39
+ ::Readline.completion_proc = agent
40
+ if (::Readline::VERSION rescue nil).to_s[/editline/i]
41
+ puts "Bond has detected EditLine and may not work with it. See the README's Limitations section."
42
+ end
41
43
  end
42
44
 
45
+ # Returns full line of what the user has typed.
43
46
  def line_buffer
44
47
  ::Readline.line_buffer
45
48
  end
data/lib/bond/search.rb CHANGED
@@ -1,8 +1,24 @@
1
1
  module Bond
2
2
  # Contains search methods used to filter possible completions given what the user has typed for that completion.
3
+ # For a search method to be used by Bond.complete it must end in '_search' and take two arguments: the Input
4
+ # string and an array of possible completions.
5
+ #
6
+ # ==== Creating a search method
7
+ # Say you want to create a custom search which ignores completions containing '-'.
8
+ # In a completion file under Rc namespace, define this method:
9
+ # def ignore_hyphen_search(input, list)
10
+ # normal_search(input, list.select {|e| e !~ /-/ })
11
+ # end
12
+ #
13
+ # Now you can pass this custom search to any complete() as :search=>:ignore_hyphen
3
14
  module Search
15
+ class<<self
16
+ # Default search used across missions, set by Bond.config[:default_search]
17
+ attr_accessor :default_search
18
+ end
19
+
4
20
  # Searches completions from the beginning of the string.
5
- def default_search(input, list)
21
+ def normal_search(input, list)
6
22
  list.grep(/^#{Regexp.escape(input)}/)
7
23
  end
8
24
 
@@ -16,20 +32,43 @@ module Bond
16
32
  list.grep(/^#{Regexp.escape(input)}/i)
17
33
  end
18
34
 
19
- # Searches completions from the beginning but also provides aliasing of underscored words.
20
- # For example 'some_dang_long_word' can be specified as 's-d-l-w'. Aliases can be any unique string
21
- # at the beginning of an underscored word. For example, to choose the first completion between 'so_long' and 'so_larger',
22
- # type 's-lo'.
35
+ # A normal_search which also provides aliasing of underscored words.
36
+ # For example 'some_dang_long_word' can be specified as 's_d_l_w'. Aliases can be any unique string
37
+ # at the beginning of an underscored word. For example, to choose the first completion between 'so_long'
38
+ # and 'so_larger', type 's_lo'.
23
39
  def underscore_search(input, list)
24
- if input.include?("-")
25
- index = 0
26
- input.split('-').inject(list) {|new_list,e|
27
- new_list = new_list.select {|f| f.split(/_+/)[index] =~ /^#{Regexp.escape(e)}/ };
28
- index +=1; new_list
29
- }
40
+ if input[/_(.+)$/]
41
+ regex = input.split('_').map {|e| Regexp.escape(e) }.join("([^_]+)?_")
42
+ list.select {|e| e =~ /^#{regex}/ }
30
43
  else
31
- default_search(input, list)
44
+ normal_search(input, list)
32
45
  end
33
46
  end
47
+
48
+ # Default search across missions to be invoked by a search that wrap another search i.e. files_search.
49
+ def default_search(input, list)
50
+ send("#{Search.default_search}_search", input, list)
51
+ end
52
+
53
+ # Does default_search on the given paths but only returns ones that match the input's current
54
+ # directory depth, determined by '/'. For example if a user has typed 'irb/c', this search returns
55
+ # matching paths that are one directory deep i.e. 'irb/cmd/ irb/completion.rb irb/context.rb'.
56
+ def files_search(input, list)
57
+ incremental_filter(input, list, '/')
58
+ end
59
+
60
+ # Does the same as files_search but for modules. A module depth is delimited by '::'.
61
+ def modules_search(input, list)
62
+ incremental_filter(input, list, '::')
63
+ end
64
+
65
+ # Used by files_search and modules_search.
66
+ def incremental_filter(input, list, delim)
67
+ i = 0; input.gsub(delim) {|e| i+= 1 }
68
+ delim_chars = delim.split('').uniq.join('')
69
+ current_matches, future_matches = default_search(input, list).partition {|e|
70
+ e[/^[^#{delim_chars}]*(#{delim}[^#{delim_chars}]+){0,#{i}}$/] }
71
+ (current_matches + future_matches.map {|e| e[/^(([^#{delim_chars}]*#{delim}){0,#{i+1}})/, 1] }).uniq
72
+ end
34
73
  end
35
74
  end
@@ -0,0 +1,3 @@
1
+ module Bond
2
+ VERSION = '0.2.0'
3
+ end
data/test/agent_test.rb CHANGED
@@ -1,122 +1,225 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
- class Bond::AgentTest < Test::Unit::TestCase
4
- before(:all) {|e| Bond.debrief(:readline_plugin=>valid_readline_plugin) }
3
+ describe "Agent" do
4
+ describe "#call" do
5
+ before { Bond.agent.reset }
5
6
 
6
- context "Agent" do
7
- before(:each) {|e| Bond.agent.reset }
8
-
9
- test "chooses default mission if no missions match" do
7
+ it "chooses default mission if no missions match" do
10
8
  complete(:on=>/bling/) {|e| [] }
11
- Bond.agent.default_mission.expects(:execute)
12
- tabtab 'blah'
9
+ Bond.agent.default_mission.expects(:execute).with {|e| e.is_a?(Input) }
10
+ tab 'blah'
13
11
  end
14
12
 
15
- test "chooses default mission if internal processing fails" do
13
+ it "for internal Bond error completes error" do
16
14
  complete(:on=>/bling/) {|e| [] }
17
- Bond.agent.expects(:find_mission).raises
18
- Bond.agent.default_mission.expects(:execute)
19
- tabtab('bling')
15
+ Bond.agent.expects(:find_mission).raises('wtf')
16
+ errors = tab('bling')
17
+ errors[0].should =~ /Bond Error: Failed internally.*'wtf'/
18
+ errors[1].should =~ /Please/
20
19
  end
21
20
 
22
- test "completes in middle of line" do
23
- complete(:object=>"Object")
24
- tabtab(':man.f blah', ':man.f').include?(':man.freeze').should == true
21
+ def complete_error(msg)
22
+ lambda {|e|
23
+ e[0].should =~ msg
24
+ e[1].should =~ /Completion Info: Matches.*blah/
25
+ }
25
26
  end
26
27
 
27
- test "places missions last when declared last" do
28
- complete(:object=>"Symbol", :place=>:last)
29
- complete(:method=>"man", :place=>:last) { }
30
- complete(:on=>/man\s*(.*)/) {|e| e.matched[1] }
31
- Bond.agent.missions.map {|e| e.class}.should == [Bond::Mission, Bond::Missions::ObjectMission, Bond::Missions::MethodMission]
32
- tabtab('man ok').should == ['ok']
28
+ it "for completion action raising error completes error" do
29
+ Bond.config[:debug] = false
30
+ complete(:on=>/blah/) { raise 'blah' }
31
+ errors = tab('blah')
32
+ errors.size.should == 2
33
+ errors.should complete_error(/Bond Error: Failed.*action.*'blah'/)
34
+ Bond.config[:debug] = true
33
35
  end
34
36
 
35
- test "places mission correctly for a place number" do
36
- complete(:object=>"Symbol")
37
- complete(:method=>"man") {}
38
- complete(:on=>/man\s*(.*)/, :place=>1) {|e| e.matched[1] }
39
- tabtab('man ok')
40
- Bond.agent.missions.map {|e| e.class}.should == [Bond::Mission, Bond::Missions::ObjectMission, Bond::Missions::MethodMission]
41
- tabtab('man ok').should == ['ok']
37
+ it "for completion action raising error with debug completes error and stacktrace" do
38
+ complete(:on=>/blah/) { raise 'blah' }
39
+ errors = tab('blah')
40
+ errors.size.should == 3
41
+ errors.should complete_error(/Bond Error: Failed.*action.*'blah'/)
42
+ errors[2].should =~ /Stack Trace:/
43
+ end
44
+
45
+ it "for completion action raising NoMethodError completes error" do
46
+ complete(:on=>/blah/) { raise NoMethodError }
47
+ tab('blah').should complete_error(/Bond Error: Failed.*action.*'NoMethodError'/)
48
+ end
49
+
50
+ it 'for completion action failing with Rc.eval completes empty' do
51
+ Bond.config[:debug] = false
52
+ complete(:on=>/blah/) { Rc.eval '{[}'}
53
+ tab('blah').should == []
54
+ Bond.config[:debug] = true
55
+ end
56
+
57
+ it 'for completion action failing with Rc.eval and debug completes error' do
58
+ complete(:on=>/blah/) { Rc.eval('{[}') || [] }
59
+ tab('blah').should complete_error(/Bond Error: Failed.*action.*(eval)/)
60
+ end
61
+
62
+ it "for completion action raising SyntaxError in eval completes error" do
63
+ complete(:on=>/blah/) { eval '{[}'}
64
+ tab('blah').should complete_error(/Bond Error: Failed.*action.*(eval)/)
65
+ end
66
+
67
+ it "for completion action that doesn't exist completes error" do
68
+ complete(:on=>/blah/, :action=>:huh)
69
+ tab('blah').should complete_error(/Bond Error:.*action 'huh' doesn't exist/)
70
+ end
71
+
72
+ it "for completion search raising error completes error" do
73
+ Rc.module_eval "def blah_search(*args); raise 'blah'; end"
74
+ complete(:on=>/blah/, :search=>:blah) { [1] }
75
+ tab('blah').should complete_error(/Bond Error: Failed.*search.*'blah'/)
76
+ end
77
+
78
+ it "for completion search that doesn't exist completes error" do
79
+ complete(:on=>/blah/, :search=>:huh) { [] }
80
+ tab('blah').should complete_error(/Bond Error:.*search 'huh' doesn't exist/)
42
81
  end
43
82
  end
44
83
 
45
- context "complete" do
46
- test "prints error if no action given" do
47
- capture_stderr { complete :on=>/blah/ }.should =~ /Invalid mission/
84
+ describe "complete" do
85
+ before {|e| Bond.agent.reset }
86
+ def complete_prints_error(msg, *args, &block)
87
+ capture_stderr { complete(*args, &block) }.should =~ msg
88
+ end
89
+
90
+ it "with no :action prints error" do
91
+ complete_prints_error /Invalid :action/, :on=>/blah/
92
+ end
93
+
94
+ it "with no :on prints error" do
95
+ complete_prints_error(/Invalid :on/) { [] }
48
96
  end
49
97
 
50
- test "prints error if no condition given" do
51
- capture_stderr { complete {|e| []} }.should =~ /Invalid mission/
98
+ it "with invalid :on prints error" do
99
+ complete_prints_error(/Invalid :on/, :on=>'blah') { [] }
52
100
  end
53
101
 
54
- test "prints error if invalid condition given" do
55
- capture_stderr { complete(:on=>'blah') {|e| []} }.should =~ /Invalid mission/
102
+ it "with internal failure prints error" do
103
+ Mission.expects(:create).raises(RuntimeError, 'blah')
104
+ complete_prints_error(/Unexpected error.*blah/, :on=>/blah/) { [] }
56
105
  end
57
106
 
58
- test "prints error if invalid symbol action given" do
59
- capture_stderr { complete(:on=>/blah/, :action=>:bling) }.should =~ /Invalid mission action/
107
+ it "with invalid :anywhere and :prefix prints no error" do
108
+ complete_prints_error(/^$/, :prefix=>nil, :anywhere=>:blah) {}
60
109
  end
61
110
 
62
- test "prints error if setting mission fails unpredictably" do
63
- Bond::Mission.expects(:create).raises(RuntimeError)
64
- capture_stderr { complete(:on=>/blah/) {|e| [] } }.should =~ /Mission setup failed/
111
+ it "with invalid :object prints no error" do
112
+ complete_prints_error(/^$/, :object=>:Mod) {}
113
+ end
114
+
115
+ it "with invalid :method prints error" do
116
+ complete_prints_error(/Invalid :method\(s\)/, :method=>true) {}
117
+ end
118
+
119
+ it "with invalid :methods prints error" do
120
+ complete_prints_error(/Invalid :method\(s\)/, :methods=>[:blah]) {}
121
+ end
122
+
123
+ it "with invalid :action for method completion prints error" do
124
+ complete_prints_error(/Invalid string :action/, :method=>"blah", :action=>"Kernel#wtf") {}
125
+ end
126
+
127
+ it "with invalid :class prints no error" do
128
+ complete_prints_error(/^$/, :method=>'ok', :class=>/wtf/) {}
129
+ end
130
+
131
+ it "places missions last when declared last" do
132
+ complete(:object=>"Symbol", :place=>:last)
133
+ complete(:on=>/man/, :place=>:last) { }
134
+ complete(:on=>/man\s*(.*)/) {|e| [e.matched[1]] }
135
+ Bond.agent.missions.map {|e| e.class}.should == [Mission, ObjectMission, Mission]
136
+ tab('man ok').should == ['ok']
137
+ end
138
+
139
+ it "places mission correctly for a place number" do
140
+ complete(:object=>"Symbol")
141
+ complete(:on=>/man/) {}
142
+ complete(:on=>/man\s*(.*)/, :place=>1) {|e| [e.matched[1]] }
143
+ tab('man ok')
144
+ Bond.agent.missions.map {|e| e.class}.should == [Mission, ObjectMission, Mission]
145
+ tab('man ok').should == ['ok']
65
146
  end
66
147
  end
67
148
 
68
- context "recomplete" do
69
- before(:each) {|e| Bond.agent.reset }
149
+ describe "recomplete" do
150
+ before {|e| Bond.agent.reset }
70
151
 
71
- test "recompletes a mission" do
72
- Bond.complete(:on=>/man/) { %w{1 2 3}}
152
+ it "recompletes a mission" do
153
+ complete(:on=>/man/) { %w{1 2 3}}
73
154
  Bond.recomplete(:on=>/man/) { %w{4 5 6}}
74
- tabtab('man ').should == %w{4 5 6}
155
+ tab('man ').should == %w{4 5 6}
156
+ end
157
+
158
+ it "recompletes a mission with :name" do
159
+ complete(:on=>/man/, :name=>:count) { %w{1 2 3}}
160
+ Bond.recomplete(:on=>/man/, :name=>:count) { %w{4 5 6}}
161
+ tab('man ').should == %w{4 5 6}
75
162
  end
76
163
 
77
- test "recompletes a method mission" do
78
- Bond.complete(:method=>'blah') { %w{1 2 3}}
164
+ it "recompletes a method mission" do
165
+ complete(:all_methods=>true)
166
+ MethodMission.reset
167
+ complete(:method=>'blah') { %w{1 2 3}}
79
168
  Bond.recomplete(:method=>'blah') { %w{4 5 6}}
80
- tabtab('blah ').should == %w{4 5 6}
169
+ tab('blah ').should == %w{4 5 6}
81
170
  end
82
171
 
83
- test "recompletes an object mission" do
84
- Bond.complete(:object=>'String') { %w{1 2 3}}
172
+ it "completes a method mission if mission not found" do
173
+ complete(:all_methods=>true)
174
+ MethodMission.reset
175
+ Bond.recomplete(:method=>'blah') { %w{4 5 6}}
176
+ tab('blah ').should == %w{4 5 6}
177
+ end
178
+
179
+ it "recompletes an object mission" do
180
+ complete(:object=>'String') { %w{1 2 3}}
85
181
  Bond.recomplete(:object=>'String') { %w{4 5 6}}
86
- tabtab('"blah".').should == %w{.4 .5 .6}
182
+ tab('"blah".').should == %w{.4 .5 .6}
183
+ end
184
+
185
+ it "recompletes anywhere mission" do
186
+ complete(:anywhere=>'dude.*') { %w{duder dudest} }
187
+ Bond.recomplete(:anywhere=>'dude.*') { %w{duderific dudeacious} }
188
+ tab('dude').should == %w{duderific dudeacious}
87
189
  end
88
190
 
89
- test "prints error if no existing mission" do
90
- Bond.complete(:object=>'String') { %w{1 2 3}}
191
+ it "prints error if no existing mission" do
192
+ complete(:object=>'String') { %w{1 2 3}}
91
193
  capture_stderr { Bond.recomplete(:object=>'Array') { %w{4 5 6}}}.should =~ /No existing mission/
92
- tabtab('[].').should == []
194
+ tab('[].').should == []
93
195
  end
94
196
 
95
- test "prints error if invalid condition given" do
96
- capture_stderr { Bond.recomplete}.should =~ /Invalid mission/
197
+ it "prints error if invalid condition given" do
198
+ capture_stderr { Bond.recomplete}.should =~ /Invalid :action/
97
199
  end
98
200
  end
99
201
 
100
- context "spy" do
101
- before(:all) {
102
- Bond.reset; complete(:on=>/end$/) { [] }; complete(:method=>'the') { %w{spy who loved me} }
202
+ describe "spy" do
203
+ before_all {
204
+ M.reset; complete(:on=>/end$/) { [] };
205
+ complete(:all_methods=>true); complete(:method=>'the') { %w{spy who loved me} }
103
206
  complete(:object=>"Symbol")
104
207
  }
105
208
 
106
- test "detects basic mission" do
209
+ it "detects basic mission" do
107
210
  capture_stdout { Bond.spy('the end')}.should =~ /end/
108
211
  end
109
212
 
110
- test "detects object mission" do
213
+ it "detects object mission" do
111
214
  capture_stdout { Bond.spy(':dude.i')}.should =~ /object.*Symbol.*dude\.id/m
112
215
  end
113
216
 
114
- test "detects method mission" do
115
- capture_stdout { Bond.spy('the ')}.should =~ /method.*the.*loved/m
217
+ it "detects method mission" do
218
+ capture_stdout { Bond.spy('the ')}.should =~ /method.*the.*Kernel.*loved/m
116
219
  end
117
220
 
118
- test "detects no mission" do
221
+ it "detects no mission" do
119
222
  capture_stdout { Bond.spy('blah')}.should =~ /Doesn't match/
120
223
  end
121
224
  end
122
- end
225
+ end