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
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