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.
- data/CHANGELOG.rdoc +12 -0
- data/LICENSE.txt +1 -1
- data/README.rdoc +195 -173
- data/Rakefile +9 -45
- data/lib/bond.rb +62 -93
- data/lib/bond/agent.rb +39 -33
- data/lib/bond/completion.rb +15 -27
- data/lib/bond/completions/activerecord.rb +12 -0
- data/lib/bond/completions/array.rb +1 -0
- data/lib/bond/completions/bond.rb +2 -0
- data/lib/bond/completions/hash.rb +3 -0
- data/lib/bond/completions/kernel.rb +13 -0
- data/lib/bond/completions/module.rb +7 -0
- data/lib/bond/completions/object.rb +21 -0
- data/lib/bond/completions/struct.rb +1 -0
- data/lib/bond/input.rb +28 -0
- data/lib/bond/m.rb +95 -0
- data/lib/bond/mission.rb +109 -69
- data/lib/bond/missions/anywhere_mission.rb +18 -0
- data/lib/bond/missions/default_mission.rb +16 -6
- data/lib/bond/missions/method_mission.rb +194 -13
- data/lib/bond/missions/object_mission.rb +29 -32
- data/lib/bond/missions/operator_method_mission.rb +26 -0
- data/lib/bond/rawline.rb +3 -3
- data/lib/bond/rc.rb +48 -0
- data/lib/bond/readline.rb +9 -6
- data/lib/bond/search.rb +51 -12
- data/lib/bond/version.rb +3 -0
- data/test/agent_test.rb +168 -65
- data/test/anywhere_mission_test.rb +34 -0
- data/test/bacon_extensions.rb +26 -0
- data/test/bond_test.rb +38 -23
- data/test/completion_test.rb +123 -21
- data/test/completions_test.rb +96 -0
- data/test/method_mission_test.rb +246 -0
- data/test/mission_test.rb +30 -44
- data/test/object_mission_test.rb +28 -32
- data/test/operator_method_mission_test.rb +66 -0
- data/test/search_test.rb +106 -29
- data/test/test_helper.rb +20 -13
- metadata +37 -8
- data/VERSION.yml +0 -4
- data/lib/bond/actions.rb +0 -69
@@ -1,49 +1,46 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
# an
|
4
|
-
|
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
|
-
|
7
|
-
|
15
|
+
OBJECTS = %w<\S+> + Bond::Mission::OBJECTS
|
16
|
+
CONDITION = '(OBJECTS)\.(\w*(?:\?|!)?)$'
|
8
17
|
def initialize(options={})
|
9
|
-
@object_condition = options
|
10
|
-
|
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}+#{@
|
24
|
+
"#{@object_condition.inspect}+#{@on.inspect}"
|
18
25
|
end
|
19
26
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
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
|
41
|
-
@
|
42
|
-
@
|
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
|
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 =
|
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
|
4
|
-
#
|
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
|
-
|
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 =
|
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
|
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
|
-
#
|
20
|
-
# For example 'some_dang_long_word' can be specified as '
|
21
|
-
# at the beginning of an underscored word. For example, to choose the first completion between 'so_long'
|
22
|
-
# type '
|
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
|
25
|
-
|
26
|
-
|
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
|
-
|
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
|
data/lib/bond/version.rb
ADDED
data/test/agent_test.rb
CHANGED
@@ -1,122 +1,225 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
describe "Agent" do
|
4
|
+
describe "#call" do
|
5
|
+
before { Bond.agent.reset }
|
5
6
|
|
6
|
-
|
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
|
-
|
9
|
+
Bond.agent.default_mission.expects(:execute).with {|e| e.is_a?(Input) }
|
10
|
+
tab 'blah'
|
13
11
|
end
|
14
12
|
|
15
|
-
|
13
|
+
it "for internal Bond error completes error" do
|
16
14
|
complete(:on=>/bling/) {|e| [] }
|
17
|
-
Bond.agent.expects(:find_mission).raises
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
28
|
-
|
29
|
-
complete(:
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
36
|
-
complete(:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
51
|
-
|
98
|
+
it "with invalid :on prints error" do
|
99
|
+
complete_prints_error(/Invalid :on/, :on=>'blah') { [] }
|
52
100
|
end
|
53
101
|
|
54
|
-
|
55
|
-
|
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
|
-
|
59
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
69
|
-
before
|
149
|
+
describe "recomplete" do
|
150
|
+
before {|e| Bond.agent.reset }
|
70
151
|
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
-
|
78
|
-
|
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
|
-
|
169
|
+
tab('blah ').should == %w{4 5 6}
|
81
170
|
end
|
82
171
|
|
83
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
90
|
-
|
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
|
-
|
194
|
+
tab('[].').should == []
|
93
195
|
end
|
94
196
|
|
95
|
-
|
96
|
-
capture_stderr { Bond.recomplete}.should =~ /Invalid
|
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
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
209
|
+
it "detects basic mission" do
|
107
210
|
capture_stdout { Bond.spy('the end')}.should =~ /end/
|
108
211
|
end
|
109
212
|
|
110
|
-
|
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
|
-
|
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
|
-
|
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
|