bond 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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