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