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
data/test/mission_test.rb CHANGED
@@ -1,65 +1,51 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
- class Bond::MissionTest < Test::Unit::TestCase
4
- before(:all) {|e| Bond.debrief(:readline_plugin=>valid_readline_plugin) }
5
-
6
- context "mission" do
7
- before(:each) {|e| Bond.agent.reset }
8
- test "completes" do
3
+ describe "Mission" do
4
+ describe "mission" do
5
+ before { Bond.agent.reset }
6
+ it "completes" do
9
7
  complete(:on=>/bling/) {|e| %w{ab cd fg hi}}
10
8
  complete(:method=>'cool') {|e| [] }
11
- tabtab('some bling f').should == %w{fg}
12
- end
13
-
14
- test "with method completes" do
15
- complete(:on=>/bling/) {|e| [] }
16
- complete(:method=>'cool') {|e| %w{ab cd ef gd} }
17
- tabtab('cool c').should == %w{cd}
18
- end
19
-
20
- test "with method and quoted argument completes" do
21
- complete(:on=>/bling/) {|e| [] }
22
- complete(:method=>'cool') {|e| %w{ab cd ef ad} }
23
- tabtab('cool "a').should == %w{ab ad}
9
+ tab('some bling f').should == %w{fg}
24
10
  end
25
11
 
26
- test "with string method completes exact matches" do
27
- complete(:method=>'cool?') {|e| [] }
28
- complete(:method=>'cool') {|e| %w{ab cd ef gd} }
29
- tabtab('cool c').should == %w{cd}
12
+ it "with regexp condition completes" do
13
+ complete(:on=>/\s*'([^']+)$/, :search=>false) {|e| %w{coco for puffs}.grep(/#{e.matched[1]}/) }
14
+ tab("require 'ff").should == ['puffs']
30
15
  end
31
16
 
32
- test "with regex method completes multiple methods" do
33
- complete(:method=>/cool|ls/) {|e| %w{ab cd ef ad}}
34
- tabtab("cool a").should == %w{ab ad}
35
- tabtab("ls c").should == %w{cd}
17
+ it "with non-string completions completes" do
18
+ complete(:on=>/.*/) { [:one,:two,:three] }
19
+ tab('ok ').should == %w{one two three}
36
20
  end
37
21
 
38
- test "with regexp condition completes" do
39
- complete(:on=>/\s*'([^']+)$/, :search=>false) {|e| %w{coco for puffs}.grep(/#{e.matched[1]}/) }
40
- tabtab("require 'ff").should == ['puffs']
22
+ it "with non-array completions completes" do
23
+ complete(:on=>/blah/) { 'blah' }
24
+ tab('blah ').should == ['blah']
41
25
  end
42
26
 
43
- test "with non-string completions completes" do
44
- complete(:on=>/.*/) { [:one,:two,:three] }
45
- tabtab('ok ').should == %w{one two three}
27
+ it "with symbol action completes" do
28
+ Rc.module_eval %[def blah(input); %w{one two three}; end]
29
+ complete(:on=>/blah/, :action=>:blah)
30
+ tab('blah ').should == %w{one two three}
46
31
  end
47
32
 
48
- test "with symbol action completes" do
49
- eval %[module ::Bond::Actions; def blah(input); %w{one two three}; end; end]
50
- complete(:method=>'blah', :action=>:blah)
51
- tabtab('blah ').should == %w{one two three}
33
+ it "with string action completes" do
34
+ Rc.module_eval %[def blah(input); %w{one two three}; end]
35
+ complete(:on=>/blah/, :action=>'blah')
36
+ tab('blah ').should == %w{one two three}
52
37
  end
53
38
 
54
- test "with invalid action prints error" do
55
- complete(:on=>/bling/) {|e| raise "whoops" }
56
- capture_stderr { tabtab('bling') }.should =~ /bling.*whoops/m
39
+ it "always passes Input to action block" do
40
+ complete(:on=>/man/) {|e| e.should.be.is_a(Input); [] }
41
+ tab('man ')
57
42
  end
58
43
  end
59
44
 
60
- test "default_mission set to a valid mission if irb doesn't exist" do
61
- Object.expects(:const_defined?).with(:IRB).returns(false)
62
- mission = Bond::Missions::DefaultMission.new
63
- mission.action.respond_to?(:call).should == true
45
+ it "sets binding to toplevel binding when not in irb" do
46
+ Mission.eval_binding = nil
47
+ mock_irb
48
+ ::IRB.CurrentContext.expects(:workspace).raises
49
+ Mission.eval_binding.should == ::TOPLEVEL_BINDING
64
50
  end
65
51
  end
@@ -1,63 +1,59 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
- class Bond::ObjectMissionTest < Test::Unit::TestCase
4
- before(:all) {|e| Bond.debrief(:readline_plugin=>valid_readline_plugin) }
5
- before(:each) {|e| Bond.agent.reset }
6
- context "object mission" do
7
- test "with default action completes" do
3
+ describe "ObjectMission" do
4
+ before { Bond.agent.reset }
5
+ describe "object mission" do
6
+ it "with default action completes" do
8
7
  complete(:object=>"String")
9
8
  complete(:on=>/man/) { %w{upper upster upful}}
10
- tabtab("'man'.u").should == [".upcase!", ".unpack", ".untaint", ".upcase", ".upto"]
9
+ tab("'man'.up").sort.should == [".upcase", ".upcase!", ".upto"]
11
10
  end
12
11
 
13
- test "with regex condition completes" do
14
- complete(:object=>/Str/) {|e| e.object.class.superclass.instance_methods(true) }
12
+ it "with regex condition completes" do
13
+ complete(:object=>'Str.*') {|e| e.object.class.superclass.instance_methods(true) }
15
14
  complete(:on=>/man/) { %w{upper upster upful}}
16
- tabtab("'man'.u").should == [".untaint"]
15
+ tab("'man'.unta").should == [".untaint"]
17
16
  end
18
17
 
19
- test "with explicit action completes" do
18
+ it "with explicit action completes" do
20
19
  complete(:object=>"String") {|e| e.object.class.superclass.instance_methods(true) }
21
20
  complete(:on=>/man/) { %w{upper upster upful}}
22
- tabtab("'man'.u").should == [".untaint"]
21
+ tab("'man'.unta").should == [".untaint"]
23
22
  end
24
23
 
25
- test "completes without including word break characters" do
24
+ it "completes without including word break characters" do
26
25
  complete(:object=>"Hash")
27
- matches = tabtab("{}.f")
28
- assert matches.size > 0
26
+ matches = tab("{}.f")
27
+ matches.size.should.be > 0
29
28
  matches.all? {|e| !e.include?('{')}.should == true
30
29
  end
31
30
 
32
- test "completes nil, false and range objects" do
31
+ it "completes with additional text after completion point" do
33
32
  complete(:object=>"Object")
34
- assert tabtab("nil.f").size > 0
35
- assert tabtab("false.f").size > 0
36
- assert tabtab("(1..10).f").size > 0
33
+ tab(':man.f blah', ':man.f').include?(':man.freeze').should == true
37
34
  end
38
35
 
39
- test "completes hashes and arrays with spaces" do
40
- complete(:object=>"Object")
41
- assert tabtab("[1, 2].f").size > 0
42
- assert tabtab("{:a =>1}.f").size > 0
36
+ it "doesn't evaluate anything before the completion object" do
37
+ complete(:object=>'Object')
38
+ tab('raise :man.i').size.should > 0
43
39
  end
44
40
 
45
- test "ignores invalid invalid ruby" do
41
+ it "ignores invalid ruby" do
46
42
  complete(:object=>"String")
47
- tabtab("blah.upt").should == []
43
+ tab("blah.upt").should == []
44
+ end
45
+
46
+ it "ignores object that doesn't have a valid class" do
47
+ complete :on=>/(.*)./, :object=>'Object'
48
+ capture_stdout {
49
+ tab("obj = Object.new; def obj.class; end; obj.").should == []
50
+ }.should == ''
48
51
  end
49
52
 
50
53
  # needed to ensure Bond works in irbrc
51
- test "doesn't evaluate irb binding on definition" do
54
+ it "doesn't evaluate irb binding on definition" do
52
55
  Object.expects(:const_defined?).never
53
56
  complete(:object=>"String")
54
57
  end
55
-
56
- test "sets binding to toplevel binding when not in irb" do
57
- Object.expects(:const_defined?).with(:IRB).returns(false)
58
- mission = Bond::Mission.create(:object=>'Symbol')
59
- mission.class.expects(:eval).with(anything, ::TOPLEVEL_BINDING)
60
- mission.matches?(':ok.')
61
- end
62
58
  end
63
59
  end
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "operator method mission" do
4
+ before_all { MethodMission.reset }
5
+ before { Bond.agent.reset; Bond.complete(:all_operator_methods=>true) }
6
+
7
+ describe "operator" do
8
+ before { complete(:method=>"Hash#[]") { %w{ab cd ae} } }
9
+
10
+ it "completes" do
11
+ tab('{}[a').should == ["}[ab", "}[ae"]
12
+ end
13
+
14
+ it "completes quoted argument" do
15
+ tab('{:a=>1}["a').should == %w{ab ae}
16
+ end
17
+
18
+ it "completes symbolic argument" do
19
+ tab('{}[:a').should == ["}[:ab", "}[:ae"]
20
+ end
21
+
22
+ it "completes with no space between method and argument" do
23
+ tab('{}[a').should == ["}[ab", "}[ae"]
24
+ end
25
+
26
+ it "completes with space between method and argument" do
27
+ tab('{}[ a').should == ["ab", "ae"]
28
+ end
29
+
30
+ it "completes with operator characters in object" do
31
+ tab('{:a=> 1}[').should == ["1}[ab", "1}[cd", "1}[ae"]
32
+ end
33
+
34
+ it "completes all arguments with only space as argument" do
35
+ tab('{}[ ').should == ["ab", "cd", "ae"]
36
+ end
37
+
38
+ it "completes with a chain of objects" do
39
+ tab('Hash.new[a').should == %w{Hash.new[ab Hash.new[ae}
40
+ end
41
+
42
+ it "completes in middle of line" do
43
+ tab('nil; {}[a').should == ["}[ab", "}[ae"]
44
+ end
45
+
46
+ it "doesn't complete for multiple arguments" do
47
+ tab('{}[a,').should == []
48
+ end
49
+ end
50
+
51
+ it "operator with space between object and method completes" do
52
+ complete(:method=>"Array#*") { %w{ab cd ae} }
53
+ tab('[1,2] * a').should == %w{ab ae}
54
+ tab('[1,2] *a').should == %w{*ab *ae}
55
+ end
56
+
57
+ it "class operator completes" do
58
+ complete(:method=>"Hash.*") { %w{ab cd ae} }
59
+ tab('Hash * a').should == %w{ab ae}
60
+ end
61
+
62
+ it "with :search completes" do
63
+ complete(:method=>"Array#*", :search=>:anywhere) { %w{abc bcd cde} }
64
+ tab('[1, 2] * b').should == ['abc', 'bcd']
65
+ end
66
+ end
data/test/search_test.rb CHANGED
@@ -1,55 +1,132 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
- class Bond::SearchTest < Test::Unit::TestCase
4
- before(:all) {|e| Bond.debrief(:readline_plugin=>valid_readline_plugin) }
5
- before(:each) {|e| Bond.agent.reset }
3
+ describe "Search" do
4
+ before { Bond.agent.reset }
6
5
 
7
- context "mission with search" do
8
- test "false completes" do
6
+ describe "mission with search" do
7
+ it "false completes" do
9
8
  complete(:on=>/cool '(.*)/, :search=>false) {|e| %w{coco for puffs}.grep(/#{e.matched[1]}/) }
10
- tabtab("cool 'ff").should == ['puffs']
9
+ tab("cool 'ff").should == ['puffs']
11
10
  end
12
11
 
13
- test "proc completes" do
14
- complete(:method=>'blah', :search=>proc {|input, list| list.grep(/#{input}/)}) {|e| %w{coco for puffs} }
15
- tabtab("blah 'ff").should == ['puffs']
12
+ it "defined in Rc completes" do
13
+ Rc.module_eval %q{def coco_search(input, list); list.grep(/#{input}/); end }
14
+ complete(:on=>/blah/, :search=>:coco) {|e| %w{coco for puffs} }
15
+ tab("blah ff").should == ['puffs']
16
16
  end
17
17
 
18
- test ":anywhere completes" do
19
- complete(:method=>'blah', :search=>:anywhere) {|e| %w{coco for puffs} }
20
- tabtab("blah 'ff").should == ['puffs']
18
+ it ":anywhere completes" do
19
+ complete(:on=>/blah/, :search=>:anywhere) {|e| %w{coco for puffs} }
20
+ tab("blah ff").should == ['puffs']
21
21
  end
22
22
 
23
- test ":ignore_case completes" do
24
- complete(:method=>'blah', :search=>:ignore_case) {|e| %w{Coco For PufFs} }
25
- tabtab("blah 'pu").should == ['PufFs']
23
+ it ":ignore_case completes" do
24
+ complete(:on=>/blah/, :search=>:ignore_case) {|e| %w{Coco For PufFs} }
25
+ tab("blah pu").should == ['PufFs']
26
26
  end
27
27
 
28
- test ":underscore completes" do
28
+ it ":underscore completes" do
29
29
  complete(:on=>/blah/, :search=>:underscore) {|e| %w{and_one big_two can_three} }
30
- tabtab("blah and").should == ['and_one']
31
- tabtab("blah b-t").should == ['big_two']
30
+ tab("blah and").should == ['and_one']
31
+ tab("blah b_t").should == ['big_two']
32
32
  end
33
33
  end
34
34
 
35
- test "underscore search doesn't pick up strings starting with __" do
35
+ it "underscore search doesn't pick up strings starting with __" do
36
36
  completions = ["include?", "instance_variable_defined?", "__id__", "include_and_exclude?"]
37
- complete(:method=>'blah', :search=>:underscore) { completions }
38
- tabtab("blah i").should == ["include?", "instance_variable_defined?", "include_and_exclude?"]
37
+ complete(:on=>/blah/, :search=>:underscore) { completions }
38
+ tab("blah i").should == ["include?", "instance_variable_defined?", "include_and_exclude?"]
39
39
  end
40
40
 
41
- test "underscore search can match first unique strings of each underscored word" do
41
+ it "underscore search can match first unique strings of each underscored word" do
42
42
  completions = %w{so_long so_larger so_louder}
43
- complete(:method=>'blah', :search=>:underscore) { completions }
44
- tabtab("blah s-lo").should == %w{so_long so_louder}
45
- tabtab("blah s-lou").should == %w{so_louder}
43
+ complete(:on=>/blah/, :search=>:underscore) { completions }
44
+ tab("blah s_lo").should == %w{so_long so_louder}
45
+ tab("blah s_lou").should == %w{so_louder}
46
46
  end
47
47
 
48
- test "search handles completions with regex characters" do
48
+ it "underscore search acts normal if ending in underscore" do
49
+ complete(:on=>/blah/, :search=>:underscore) {|e| %w{and_one big_two can_three ander_one} }
50
+ tab("blah and_").should == %w{and_one}
51
+ end
52
+
53
+ it "search handles completions with regex characters" do
49
54
  completions = ['[doh]', '.*a', '?ok']
50
55
  complete(:on=>/blah/) { completions }
51
- tabtab('blah .').should == ['.*a']
52
- tabtab('blah [').should == ['[doh]']
53
- tabtab('blah ?').should == ['?ok']
56
+ tab('blah .').should == ['.*a']
57
+ tab('blah [').should == ['[doh]']
58
+ tab('blah ?').should == ['?ok']
59
+ end
60
+
61
+ it "default search uses default search" do
62
+ Search.default_search.should == :underscore
63
+ Rc.expects(:underscore_search).with('a', %w{ab cd})
64
+ Rc.send(:default_search, 'a', %w{ab cd})
65
+ end
66
+
67
+ describe "modules search" do
68
+ before {
69
+ complete(:on=>/blah/, :search=>:modules) { %w{A1 M1::Z M1::Y::X M2::X} }
70
+ }
71
+ it "completes all modules" do
72
+ tab('blah ').should == ["A1", "M1::", "M2::"]
73
+ end
74
+
75
+ it "completes single first level module" do
76
+ tab('blah A').should == %w{A1}
77
+ end
78
+
79
+ it "completes single first level module parent" do
80
+ tab('blah M2').should == %w{M2::}
81
+ end
82
+
83
+ it "completes all second level modules" do
84
+ tab('blah M1::').should == %w{M1::Z M1::Y::}
85
+ end
86
+
87
+ it "completes second level module parent" do
88
+ tab('blah M1::Y').should == %w{M1::Y::}
89
+ end
90
+
91
+ it "completes third level module" do
92
+ tab('blah M1::Y::').should == %w{M1::Y::X}
93
+ end
94
+ end
95
+
96
+ describe "files search" do
97
+ before {
98
+ complete(:on=>/rm/, :search=>:files) { %w{a1 d1/f2 d1/d2/f1 d2/f1 d2/f1/ /f1} }
99
+ }
100
+ it "completes all paths" do
101
+ tab('rm ').should == %w{a1 d1/ d2/ /}
102
+ end
103
+
104
+ it "completes single first level file" do
105
+ tab('rm a').should == %w{a1}
106
+ end
107
+
108
+ it "completes single first level directory" do
109
+ tab('rm d2').should == %w{d2/}
110
+ end
111
+
112
+ it "completes all second level paths" do
113
+ tab('rm d1/').should == %w{d1/f2 d1/d2/}
114
+ end
115
+
116
+ it "completes single second level directory" do
117
+ tab('rm d1/d2').should == %w{d1/d2/}
118
+ end
119
+
120
+ it "completes single third level file" do
121
+ tab('rm d1/d2/').should == %w{d1/d2/f1}
122
+ end
123
+
124
+ it "completes file and directory with same name" do
125
+ tab('rm d2/f').should == %w{d2/f1 d2/f1/}
126
+ end
127
+
128
+ it "completes file with full path" do
129
+ tab('rm /f').should == %w{/f1}
130
+ end
54
131
  end
55
132
  end
data/test/test_helper.rb CHANGED
@@ -1,14 +1,12 @@
1
- require 'rubygems'
2
- require 'test/unit'
3
- require 'context' #gem install jeremymcanally-context -s http://gems.github.com
4
- require 'matchy' #gem install jeremymcanally-matchy -s http://gems.github.com
1
+ require 'bacon'
2
+ require File.dirname(__FILE__)+'/bacon_extensions'
5
3
  require 'mocha'
6
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'mocha-on-bacon'
7
5
  require 'bond'
8
6
 
9
- class Test::Unit::TestCase
10
- before(:all) {
11
- # Mock irb
7
+ module TestHelpers
8
+ extend self
9
+ def mock_irb
12
10
  unless Object.const_defined?(:IRB)
13
11
  eval %[
14
12
  module ::IRB
@@ -18,7 +16,7 @@ class Test::Unit::TestCase
18
16
  ]
19
17
  ::IRB.CurrentContext = stub(:workspace=>stub(:binding=>binding))
20
18
  end
21
- }
19
+ end
22
20
 
23
21
  def capture_stderr(&block)
24
22
  original_stderr = $stderr
@@ -42,8 +40,8 @@ class Test::Unit::TestCase
42
40
  fake.string
43
41
  end
44
42
 
45
- def tabtab(full_line, last_word=full_line)
46
- Bond.agent.stubs(:line_buffer).returns(full_line)
43
+ def tab(full_line, last_word=full_line)
44
+ Bond.agent.weapon.stubs(:line_buffer).returns(full_line)
47
45
  Bond.agent.call(last_word)
48
46
  end
49
47
 
@@ -52,6 +50,15 @@ class Test::Unit::TestCase
52
50
  end
53
51
 
54
52
  def valid_readline_plugin
55
- Module.new{ def setup; end; def line_buffer; end }
53
+ Module.new{ def setup(arg); end; def line_buffer; end }
56
54
  end
57
- end
55
+ end
56
+
57
+ class Bacon::Context
58
+ include TestHelpers
59
+ include BaconExtensions
60
+ end
61
+
62
+ # Default settings
63
+ Bond::M.debrief(:readline_plugin=>TestHelpers.valid_readline_plugin, :debug=>true)
64
+ include Bond