bond 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemspec +1 -1
- data/CHANGELOG.rdoc +6 -0
- data/README.rdoc +24 -14
- data/ext/readline_line_buffer/extconf.rb +7 -6
- data/lib/bond.rb +15 -12
- data/lib/bond/agent.rb +15 -14
- data/lib/bond/completions/bond.rb +1 -1
- data/lib/bond/m.rb +17 -7
- data/lib/bond/mission.rb +1 -1
- data/lib/bond/missions/anywhere_mission.rb +4 -3
- data/lib/bond/missions/method_mission.rb +8 -8
- data/lib/bond/missions/object_mission.rb +9 -9
- data/lib/bond/missions/operator_method_mission.rb +7 -5
- data/lib/bond/rc.rb +5 -5
- data/lib/bond/readline.rb +28 -38
- data/lib/bond/readlines/jruby.rb +13 -0
- data/lib/bond/readlines/rawline.rb +15 -0
- data/lib/bond/readlines/ruby.rb +9 -0
- data/lib/bond/search.rb +2 -2
- data/lib/bond/version.rb +1 -1
- data/test/agent_test.rb +2 -1
- data/test/bond_test.rb +24 -15
- data/test/completion_test.rb +2 -2
- data/test/completions_test.rb +1 -1
- data/test/test_helper.rb +9 -4
- metadata +11 -9
- data/lib/bond/rawline.rb +0 -16
data/.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = "gabriel.horner@gmail.com"
|
10
10
|
s.homepage = "http://tagaholic.me/bond/"
|
11
11
|
s.summary = "Mission: Easy custom autocompletion for arguments, methods and beyond. Accomplished for irb and any other readline-like console environments."
|
12
|
-
s.description = "Bond is on a mission to improve autocompletion in ruby, especially for ripl
|
12
|
+
s.description = "Bond is on a mission to improve autocompletion in ruby, especially for irb/ripl. Aside from doing everything irb's can do and fixing its quirks, Bond can autocomplete argument(s) to methods, uniquely completing per module, per method and per argument. Bond brings ruby autocompletion closer to bash/zsh as it provides a configuration system and a DSL for creating custom completions and completion rules. With this configuration system, users can customize their autocompletions and share it with others. Bond can also load completions that ship with gems. Bond is able to offer more than irb's completion since it uses the full line of input when completing as opposed to irb's last-word approach."
|
13
13
|
s.required_rubygems_version = ">= 1.3.6"
|
14
14
|
s.rubyforge_project = 'tagaholic'
|
15
15
|
s.has_rdoc = 'yard'
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 0.4.0
|
2
|
+
* Improve extconf.rb: support --without-readline, fail hard, detect windows
|
3
|
+
* Add rb-readline support for windows and non-readline users
|
4
|
+
* Rename :readline_plugin option to :readline
|
5
|
+
* Allow :readline option to take a symbol
|
6
|
+
|
1
7
|
== 0.3.5
|
2
8
|
* Move yard-related functionality to bond-yard gem
|
3
9
|
|
data/README.rdoc
CHANGED
@@ -1,32 +1,42 @@
|
|
1
|
-
Note: To read a linked version of this README, {click here}[http://tagaholic.me/bond/doc/]
|
2
|
-
|
3
1
|
== Description
|
4
2
|
|
5
|
-
Bond is on a mission to improve autocompletion in ruby, especially for ripl
|
3
|
+
Bond is on a mission to improve autocompletion in ruby, especially for irb/ripl. Aside from doing
|
6
4
|
everything irb's can do and fixing its quirks, Bond can autocomplete argument(s) to methods,
|
7
|
-
uniquely completing per module, per method and per argument. Bond brings
|
8
|
-
bash/zsh as it provides a configuration system and a DSL for creating custom completions and
|
9
|
-
completion rules. With this configuration system, users can customize their
|
5
|
+
uniquely completing per module, per method and per argument. Bond brings ruby autocompletion closer
|
6
|
+
to bash/zsh as it provides a configuration system and a DSL for creating custom completions and
|
7
|
+
completion rules. With this configuration system, users can customize their autocompletions and
|
10
8
|
share it with others. Bond can also load completions that ship with gems. Bond is able to offer
|
11
|
-
more than irb's completion since it uses
|
12
|
-
|
9
|
+
more than irb's completion since it uses the full line of input when completing as opposed to irb's
|
10
|
+
last-word approach.
|
13
11
|
|
14
12
|
== Install
|
15
13
|
|
16
|
-
|
14
|
+
To use bond with {Readline}[http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html] (version >=
|
15
|
+
5.6 recommended) or JLine for JRuby users, install the gem with:
|
16
|
+
|
17
|
+
gem install bond
|
18
|
+
|
19
|
+
To use bond with {a pure ruby readline}[https://github.com/luislavena/rb-readline] i.e. Windows
|
20
|
+
users or users without Readline:
|
21
|
+
|
22
|
+
gem install bond rb-readline -- --without-readline
|
17
23
|
|
18
|
-
|
24
|
+
To use bond without readline support (and presumably use your own readline plugin):
|
25
|
+
|
26
|
+
gem install bond -- --without-readline
|
19
27
|
|
20
28
|
== Setup
|
21
29
|
|
22
|
-
|
30
|
+
If you're using {ripl}[http://github.com/cldwalker/ripl] instead of irb, bond is already setup.
|
31
|
+
|
32
|
+
To start off, replace irb's completion (require 'irb/completion') with Bond's enhanced version in your irbrc:
|
23
33
|
|
24
34
|
require 'bond'
|
25
35
|
Bond.start
|
36
|
+
# For users using a pure ruby readline
|
37
|
+
Bond.start :readline => :ruby
|
26
38
|
|
27
|
-
|
28
|
-
|
29
|
-
This gives you more consistent method completion on any object, customizable completions
|
39
|
+
This setup gives you more consistent method completion on any object, customizable completions
|
30
40
|
and argument completion of some 80+ methods including Hash#[], Kernel#system, Kernel#require and some Rails methods.
|
31
41
|
|
32
42
|
== Method Argument Completion
|
@@ -7,16 +7,17 @@ def dummy_makefile
|
|
7
7
|
}
|
8
8
|
end
|
9
9
|
|
10
|
-
if RUBY_VERSION
|
10
|
+
if RUBY_VERSION >= '1.9.2' || RUBY_PLATFORM[/java|mswin|mingw|bccwin|wince/i] ||
|
11
|
+
ARGV.include?('--without-readline')
|
12
|
+
dummy_makefile
|
13
|
+
else
|
11
14
|
dir_config("readline")
|
12
15
|
have_library('readline')
|
13
16
|
if !have_header('readline/readline.h')
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
abort "\n** Bond Install Error: Unable to find readline.h. Please try again. **\n"+
|
18
|
+
"To install with your readline: gem install bond -- --with-readline-dir=/path/to/readline\n"+
|
19
|
+
"To install without readline: gem install bond -- --without-readline"
|
17
20
|
else
|
18
21
|
create_makefile 'readline_line_buffer'
|
19
22
|
end
|
20
|
-
else
|
21
|
-
dummy_makefile
|
22
23
|
end
|
data/lib/bond.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'bond/m'
|
2
2
|
require 'bond/version'
|
3
3
|
require 'bond/readline'
|
4
|
-
require 'bond/rawline'
|
4
|
+
require 'bond/readlines/rawline'
|
5
|
+
require 'bond/readlines/ruby'
|
6
|
+
require 'bond/readlines/jruby'
|
5
7
|
require 'bond/agent'
|
6
8
|
require 'bond/search'
|
7
9
|
require 'bond/input'
|
@@ -24,11 +26,11 @@ module Bond
|
|
24
26
|
# or turned off per mission with :search. If turned off, the action must also handle searching.
|
25
27
|
#
|
26
28
|
# ==== Examples:
|
27
|
-
# Bond.complete(:method=>'shoot') {|input| %w{to kill} }
|
28
|
-
# Bond.complete(:on
|
29
|
-
# Bond.complete(:object=>ActiveRecord::Base, :search
|
30
|
-
# Bond.complete(:method=>'you', :search=>proc {|input, list| list.grep(/#{input}/i)} ) {|input| %w{Only Live Twice} }
|
31
|
-
# Bond.complete(:method=>'system', :action
|
29
|
+
# Bond.complete(:method => 'shoot') {|input| %w{to kill} }
|
30
|
+
# Bond.complete(:on => /^((([a-z][^:.\(]*)+):)+/, :search => false) {|input| Object.constants.grep(/#{input.matched[1]}/) }
|
31
|
+
# Bond.complete(:object => ActiveRecord::Base, :search => :underscore, :place => :last)
|
32
|
+
# Bond.complete(:method => 'you', :search => proc {|input, list| list.grep(/#{input}/i)} ) {|input| %w{Only Live Twice} }
|
33
|
+
# Bond.complete(:method => 'system', :action => :shell_commands)
|
32
34
|
#
|
33
35
|
# @param [Hash] options When using :method(s) or :object, some hash keys may have different behavior. See
|
34
36
|
# Bond.complete sections of {MethodMission} and {ObjectMission} respectively.
|
@@ -61,7 +63,7 @@ module Bond
|
|
61
63
|
# Redefines an existing completion mission to have a different action. The condition can only be varied if :name is
|
62
64
|
# used to identify and replace a mission. Takes same options as {#complete}.
|
63
65
|
# ==== Example:
|
64
|
-
# Bond.recomplete(:on
|
66
|
+
# Bond.recomplete(:on => /man/, :name => :count) { %w{4 5 6}}
|
65
67
|
def recomplete(options={}, &block); M.recomplete(options, &block); end
|
66
68
|
|
67
69
|
# Reports what completion mission matches for a given input. Helpful for debugging missions.
|
@@ -80,17 +82,18 @@ module Bond
|
|
80
82
|
# {Rc} for the DSL to use in completion files and in the block.
|
81
83
|
#
|
82
84
|
# ==== Examples:
|
83
|
-
# Bond.start :gems
|
84
|
-
# Bond.start(:default_search
|
85
|
-
# complete(:method=>"Object#respond_to?") {|e| e.object.methods }
|
85
|
+
# Bond.start :gems => %w{hirb}
|
86
|
+
# Bond.start(:default_search => :ignore_case) do
|
87
|
+
# complete(:method => "Object#respond_to?") {|e| e.object.methods }
|
86
88
|
# end
|
87
89
|
#
|
88
90
|
# @param [Hash] options Sets global keys in {#config}, some which specify what completions to load.
|
89
91
|
# @option options [Array<String>] :gems Gems which have their completions loaded from
|
90
92
|
# @gem_source/lib/bond/completions/*.rb. If gem is a plugin gem i.e. ripl-plugin, completion will be loaded
|
91
93
|
# from @gem_source/lib/ripl/completions/plugin.rb.
|
92
|
-
# @option options [Module] :
|
93
|
-
#
|
94
|
+
# @option options [Module, Symbol] :readline (Bond::Readline) Specifies a Bond readline plugin.
|
95
|
+
# A symbol points to a capitalized Bond constant i.e. :ruby -> Bond::Ruby.
|
96
|
+
# Available plugins are Bond::Readline, Bond::Ruby, Bond::Jruby and Bond::Rawline.
|
94
97
|
# @option options [Proc] :default_mission (DefaultMission) Sets default completion to use when no missions match.
|
95
98
|
# See {Agent#default_mission}.
|
96
99
|
# @option options [Symbol] :default_search (:underscore) Name of a *_search method in Rc to use as the default
|
data/lib/bond/agent.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Bond
|
2
|
-
# Every time a completion is attempted, the Agent searches its missions for
|
3
|
-
#
|
2
|
+
# Every time a completion is attempted, the Agent searches its missions for
|
3
|
+
# the first one that matches the user input. Using either the found mission
|
4
|
+
# or Agent.default_mission, the Agent executes the mission's action.
|
4
5
|
class Agent
|
5
6
|
# The array of missions that will be searched when a completion occurs.
|
6
7
|
attr_reader :missions
|
@@ -8,7 +9,7 @@ module Bond
|
|
8
9
|
attr_reader :weapon
|
9
10
|
|
10
11
|
def initialize(options={}) #@private
|
11
|
-
|
12
|
+
setup_readline(options[:readline])
|
12
13
|
@default_mission_action = options[:default_mission] if options[:default_mission]
|
13
14
|
Mission.eval_binding = options[:eval_binding] if options[:eval_binding]
|
14
15
|
Search.default_search = options[:default_search] || :normal
|
@@ -37,20 +38,21 @@ module Bond
|
|
37
38
|
mission
|
38
39
|
end
|
39
40
|
|
40
|
-
# This is where the action starts when a completion is initiated. Optional
|
41
|
-
# overrides line buffer from readline plugin.
|
41
|
+
# This is where the action starts when a completion is initiated. Optional
|
42
|
+
# line_buffer overrides line buffer from readline plugin.
|
42
43
|
def call(input, line_buffer=nil)
|
43
44
|
mission_input = line_buffer || @weapon.line_buffer
|
44
45
|
mission_input = $1 if mission_input !~ /#{Regexp.escape(input)}$/ && mission_input =~ /^(.*#{Regexp.escape(input)})/
|
45
46
|
(mission = find_mission(mission_input)) ? mission.execute : default_mission.execute(Input.new(input))
|
46
|
-
rescue FailedMissionError=>e
|
47
|
+
rescue FailedMissionError => e
|
47
48
|
completion_error(e.message, "Completion Info: #{e.mission.match_message}")
|
48
49
|
rescue
|
49
50
|
completion_error "Failed internally with '#{$!.message}'.",
|
50
51
|
"Please report this issue with debug on: Bond.config[:debug] = true."
|
51
52
|
end
|
52
53
|
|
53
|
-
# Given a hypothetical user input, reports back what mission it would have
|
54
|
+
# Given a hypothetical user input, reports back what mission it would have
|
55
|
+
# found and executed.
|
54
56
|
def spy(input)
|
55
57
|
if (mission = find_mission(input))
|
56
58
|
puts mission.match_message, "Possible completions: #{mission.execute.inspect}",
|
@@ -58,7 +60,7 @@ module Bond
|
|
58
60
|
else
|
59
61
|
puts "Doesn't match a completion."
|
60
62
|
end
|
61
|
-
rescue FailedMissionError=>e
|
63
|
+
rescue FailedMissionError => e
|
62
64
|
puts e.mission.match_message, e.message,
|
63
65
|
"Matches for #{e.mission.condition.inspect} are #{e.mission.matched.to_a.inspect}"
|
64
66
|
end
|
@@ -69,7 +71,7 @@ module Bond
|
|
69
71
|
|
70
72
|
# Default mission used by agent. An instance of DefaultMission.
|
71
73
|
def default_mission
|
72
|
-
@default_mission ||= DefaultMission.new(:action
|
74
|
+
@default_mission ||= DefaultMission.new(:action => @default_mission_action)
|
73
75
|
end
|
74
76
|
|
75
77
|
# Resets an agent's missions
|
@@ -78,16 +80,15 @@ module Bond
|
|
78
80
|
end
|
79
81
|
|
80
82
|
protected
|
81
|
-
def
|
82
|
-
|
83
|
-
@weapon = plugin.extend(plugin)
|
83
|
+
def setup_readline(plugin)
|
84
|
+
@weapon = plugin
|
84
85
|
@weapon.setup(self)
|
85
86
|
rescue
|
86
87
|
$stderr.puts "Bond Error: Failed #{plugin.to_s[/[^:]+$/]} setup with '#{$!.message}'"
|
87
88
|
end
|
88
89
|
|
89
90
|
def create_mission(options, &block)
|
90
|
-
Mission.create options.merge!(:action=>options[:action] || block)
|
91
|
+
Mission.create options.merge!(:action => options[:action] || block)
|
91
92
|
rescue InvalidMissionError
|
92
93
|
"Invalid #{$!.message} for completion with options: #{options.inspect}"
|
93
94
|
rescue
|
@@ -104,4 +105,4 @@ module Bond
|
|
104
105
|
arr
|
105
106
|
end
|
106
107
|
end
|
107
|
-
end
|
108
|
+
end
|
@@ -2,5 +2,5 @@ complete(:methods=>%w{Bond.complete Bond.recomplete}) {
|
|
2
2
|
["on", "method", "methods", "class", "object", "anywhere", "prefix", "search", "action", "place", "name"]
|
3
3
|
}
|
4
4
|
complete(:methods=>['Bond.start', 'Bond.restart']) {
|
5
|
-
%w{gems
|
5
|
+
%w{gems readline default_mission default_search eval_binding debug eval_debug bare}
|
6
6
|
}
|
data/lib/bond/m.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Bond
|
2
|
-
# Takes international quagmires (a user's completion setup) and passes them on
|
2
|
+
# Takes international quagmires (a user's completion setup) and passes them on
|
3
|
+
# as missions to an Agent.
|
3
4
|
module M
|
4
5
|
extend self
|
5
6
|
|
@@ -30,7 +31,7 @@ module Bond
|
|
30
31
|
|
31
32
|
# See {Bond#config}
|
32
33
|
def config
|
33
|
-
@config ||= {:
|
34
|
+
@config ||= {:debug => false, :default_search => :underscore}
|
34
35
|
end
|
35
36
|
|
36
37
|
# Resets M's missions and config
|
@@ -47,10 +48,13 @@ module Bond
|
|
47
48
|
# Validates and sets values in M.config.
|
48
49
|
def debrief(options={})
|
49
50
|
config.merge! options
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
config[:readline] ||= default_readline
|
52
|
+
if !config[:readline].is_a?(Module) &&
|
53
|
+
Bond.const_defined?(config[:readline].to_s.capitalize)
|
54
|
+
config[:readline] = Bond.const_get(config[:readline].to_s.capitalize)
|
55
|
+
end
|
56
|
+
unless %w{setup line_buffer}.all? {|e| config[:readline].respond_to?(e) }
|
57
|
+
$stderr.puts "Bond Error: Invalid readline plugin '#{config[:readline]}'."
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
@@ -74,7 +78,8 @@ module Bond
|
|
74
78
|
!!@started
|
75
79
|
end
|
76
80
|
|
77
|
-
# Finds the full path to a gem's file relative it's load path directory.
|
81
|
+
# Finds the full path to a gem's file relative it's load path directory.
|
82
|
+
# Returns nil if not found.
|
78
83
|
def find_gem_file(rubygem, file)
|
79
84
|
begin gem(rubygem); rescue Exception; end
|
80
85
|
(dir = $:.find {|e| File.exists?(File.join(e, file)) }) && File.join(dir, file)
|
@@ -110,6 +115,11 @@ module Bond
|
|
110
115
|
end
|
111
116
|
|
112
117
|
protected
|
118
|
+
def default_readline
|
119
|
+
RUBY_PLATFORM[/mswin|mingw|bccwin|wince/i] ? Ruby :
|
120
|
+
RUBY_PLATFORM[/java/i] ? Jruby : Bond::Readline
|
121
|
+
end
|
122
|
+
|
113
123
|
def load_gem_completion(rubygem)
|
114
124
|
(dir = find_gem_file(rubygem, File.join(rubygem, '..', 'bond'))) ? load_dir(dir) :
|
115
125
|
rubygem[/\/|-/] ? load_plugin_file(rubygem) :
|
data/lib/bond/mission.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
# A mission which completes anywhere i.e. even after non word break characters
|
2
|
-
# With options :prefix and :anywhere, this mission matches
|
3
|
-
# /:prefix?(:anywhere)$/ and passes the first
|
1
|
+
# A mission which completes anywhere i.e. even after non word break characters
|
2
|
+
# such as '[' or '}'. With options :prefix and :anywhere, this mission matches
|
3
|
+
# on the following regexp condition /:prefix?(:anywhere)$/ and passes the first
|
4
|
+
# capture group to the mission action.
|
4
5
|
class Bond::AnywhereMission < Bond::Mission
|
5
6
|
def initialize(options={}) #@private
|
6
7
|
options[:on] = Regexp.new("#{options[:prefix]}(#{options[:anywhere]})$")
|
@@ -13,13 +13,13 @@ module Bond
|
|
13
13
|
# Otherwise defaults to normal :search behavior.
|
14
14
|
# [:name, :place] These options aren't supported by a MethodMission/OperatorMethodMission completion.
|
15
15
|
# ==== Examples:
|
16
|
-
# Bond.complete(:methods
|
17
|
-
# Bond.complete(:method=>"Hash#index") {|e| e.object.values }
|
16
|
+
# Bond.complete(:methods => %w{delete index rindex}, :class => "Array#") {|e| e.object }
|
17
|
+
# Bond.complete(:method => "Hash#index") {|e| e.object.values }
|
18
18
|
#
|
19
19
|
# ==== Argument Format
|
20
20
|
# All method arguments can autocomplete as symbols or strings and the first argument can be prefixed
|
21
21
|
# with '(':
|
22
|
-
# >> Bond.complete(:method=>'example') { %w{some example eh} }
|
22
|
+
# >> Bond.complete(:method => 'example') { %w{some example eh} }
|
23
23
|
# => true
|
24
24
|
# >> example '[TAB]
|
25
25
|
# eh example some
|
@@ -33,7 +33,7 @@ module Bond
|
|
33
33
|
# Every time a comma appears after a method, Bond starts a new completion. This allows a method to
|
34
34
|
# complete multiple arguments as well as complete keys for a hash. *Each* argument can be have a unique
|
35
35
|
# set of completions since a completion action is aware of what argument it is currently completing:
|
36
|
-
# >> Bond.complete(:method=>'FileUtils.chown') {|e|
|
36
|
+
# >> Bond.complete(:method => 'FileUtils.chown') {|e|
|
37
37
|
# e.argument > 3 ? %w{noop verbose} : %w{root admin me} }
|
38
38
|
# => true
|
39
39
|
# >> FileUtils.chown 'r[TAB]
|
@@ -42,7 +42,7 @@ module Bond
|
|
42
42
|
# >> FileUtils.chown 'root', 'admin'
|
43
43
|
# >> FileUtils.chown 'root', 'admin', 'some_file', :v[TAB]
|
44
44
|
# >> FileUtils.chown 'root', 'admin', 'some_file', :verbose
|
45
|
-
# >> FileUtils.chown 'root', 'admin', 'some_file', :verbose=>true
|
45
|
+
# >> FileUtils.chown 'root', 'admin', 'some_file', :verbose => true
|
46
46
|
#
|
47
47
|
# ==== Developer Notes
|
48
48
|
# Unlike other missions, creating these missions with Bond.complete doesn't add more completion rules
|
@@ -183,8 +183,8 @@ module Bond
|
|
183
183
|
def after_match(input)
|
184
184
|
set_action_and_search
|
185
185
|
@completion_prefix, typed = @matched[3], @matched[-1]
|
186
|
-
input_options = {:object
|
187
|
-
:arguments=>(@completion_prefix.to_s+typed).split(/\s*,\s*/) }
|
186
|
+
input_options = {:object => @evaled_object, :argument => 1+typed.count(','),
|
187
|
+
:arguments => (@completion_prefix.to_s+typed).split(/\s*,\s*/) }
|
188
188
|
if typed.to_s.include?(',') && (match = typed.match(/(.*?\s*)([^,]*)$/))
|
189
189
|
typed = match[2]
|
190
190
|
typed.sub!(/^(['":])/,'')
|
@@ -194,4 +194,4 @@ module Bond
|
|
194
194
|
end
|
195
195
|
|
196
196
|
end
|
197
|
-
end
|
197
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
# A mission which completes an object's methods. For this mission to match,
|
2
|
-
#
|
3
|
-
# Note: To access to the current object being completed on within an
|
4
|
-
# object attribute.
|
1
|
+
# A mission which completes an object's methods. For this mission to match, the
|
2
|
+
# condition must match and the current object must have an ancestor that matches
|
3
|
+
# :object. Note: To access to the current object being completed on within an
|
4
|
+
# action, use the input's object attribute.
|
5
5
|
#
|
6
6
|
# ==== Bond.complete Options:
|
7
|
-
# [:action] If an action is not specified, the default action is to complete an
|
8
|
-
#
|
7
|
+
# [:action] If an action is not specified, the default action is to complete an
|
8
|
+
# object's non-operator methods.
|
9
9
|
#
|
10
10
|
# ===== Example:
|
11
|
-
# Bond.complete(:object=>'ActiveRecord::Base') {|input| input.object.class.instance_methods(false) }
|
11
|
+
# Bond.complete(:object => 'ActiveRecord::Base') {|input| input.object.class.instance_methods(false) }
|
12
12
|
class Bond::ObjectMission < Bond::Mission
|
13
13
|
OBJECTS = %w<\S+> + Bond::Mission::OBJECTS
|
14
14
|
CONDITION = '(OBJECTS)\.(\w*(?:\?|!)?)$'
|
@@ -35,10 +35,10 @@ class Bond::ObjectMission < Bond::Mission
|
|
35
35
|
def after_match(input)
|
36
36
|
@completion_prefix = @matched[1] + "."
|
37
37
|
@action ||= lambda {|e| default_action(e.object) }
|
38
|
-
create_input @matched[2], :object
|
38
|
+
create_input @matched[2], :object => @evaled_object
|
39
39
|
end
|
40
40
|
|
41
41
|
def default_action(obj)
|
42
42
|
obj.methods.map {|e| e.to_s} - OPERATORS
|
43
43
|
end
|
44
|
-
end
|
44
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module Bond
|
2
|
-
# A mission which completes arguments for any module/class method that is an
|
3
|
-
# Takes same Bond.complete options as
|
4
|
-
#
|
2
|
+
# A mission which completes arguments for any module/class method that is an
|
3
|
+
# operator i.e. '>' or '*'. Takes same Bond.complete options as
|
4
|
+
# MethodMission. The only operator method this mission doesn't complete is
|
5
|
+
# '[]='. The operator '[]' should cover the first argument completion of '[]='
|
6
|
+
# anyways.
|
5
7
|
class OperatorMethodMission < MethodMission
|
6
8
|
OPERATORS = Mission::OPERATORS - ["[]", "[]="]
|
7
9
|
OBJECTS = Mission::OBJECTS + %w{\S+}
|
@@ -19,7 +21,7 @@ module Bond
|
|
19
21
|
def after_match(input)
|
20
22
|
set_action_and_search
|
21
23
|
@completion_prefix, typed = input.to_s.sub(/#{Regexp.quote(@matched[-1])}$/, ''), @matched[-1]
|
22
|
-
create_input typed, :object
|
24
|
+
create_input typed, :object => @evaled_object, :argument => 1
|
23
25
|
end
|
24
26
|
end
|
25
|
-
end
|
27
|
+
end
|
data/lib/bond/rc.rb
CHANGED
@@ -4,13 +4,13 @@ module Bond
|
|
4
4
|
#
|
5
5
|
# === Example ~/.bondrc
|
6
6
|
# # complete arguments for any object's :respond_to?
|
7
|
-
# complete(:method=>"Object#respond_to?") {|e| e.object.methods }
|
7
|
+
# complete(:method => "Object#respond_to?") {|e| e.object.methods }
|
8
8
|
# # complete arguments for any module's :public
|
9
|
-
# complete(:method=>"Module#public") {|e| e.object.instance_methods }
|
9
|
+
# complete(:method => "Module#public") {|e| e.object.instance_methods }
|
10
10
|
#
|
11
11
|
# # Share generate_tags action across completions
|
12
|
-
# complete(:method=>"edit_tags", :action
|
13
|
-
# complete(:method=>"delete_tags", :search=>false) {|e| generate_tags(e).grep(/#{e}/i) }
|
12
|
+
# complete(:method => "edit_tags", :action => :generate_tags)
|
13
|
+
# complete(:method => "delete_tags", :search => false) {|e| generate_tags(e).grep(/#{e}/i) }
|
14
14
|
#
|
15
15
|
# def generate_tags(input)
|
16
16
|
# ...
|
@@ -45,4 +45,4 @@ module Bond
|
|
45
45
|
raise if Bond.config[:debug]
|
46
46
|
end
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|
data/lib/bond/readline.rb
CHANGED
@@ -1,48 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
DefaultBreakCharacters = " \t\n\"\\'`><=;|&{("
|
1
|
+
# This is the default readline plugin for Bond. A valid plugin must be an object
|
2
|
+
# that responds to methods setup and line_buffer as described below.
|
3
|
+
class Bond::Readline
|
4
|
+
DefaultBreakCharacters = " \t\n\"\\'`><=;|&{("
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
unless ::Readline.respond_to?(:line_buffer)
|
11
|
-
RUBY_PLATFORM =~ /java/ ? load_jruby_extension : load_extension
|
12
|
-
end
|
6
|
+
# Loads the readline-like library and sets the completion_proc to the given agent.
|
7
|
+
def self.setup(agent)
|
8
|
+
readline_setup
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
::Readline.completion_proc = agent
|
21
|
-
if (::Readline::VERSION rescue nil).to_s[/editline/i]
|
22
|
-
puts "Bond has detected EditLine and may not work with it. See the README's Limitations section."
|
23
|
-
end
|
10
|
+
# Reinforcing irb defaults
|
11
|
+
Readline.completion_append_character = nil
|
12
|
+
if Readline.respond_to?("basic_word_break_characters=")
|
13
|
+
Readline.basic_word_break_characters = DefaultBreakCharacters
|
24
14
|
end
|
25
15
|
|
26
|
-
|
27
|
-
|
16
|
+
Readline.completion_proc = agent
|
17
|
+
end
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
19
|
+
def self.readline_setup
|
20
|
+
require 'readline'
|
21
|
+
load_extension unless Readline.respond_to?(:line_buffer)
|
22
|
+
if (Readline::VERSION rescue nil).to_s[/editline/i]
|
23
|
+
puts "Bond has detected EditLine and may not work with it." +
|
24
|
+
" See the README's Limitations section."
|
35
25
|
end
|
26
|
+
end
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
28
|
+
def self.load_extension
|
29
|
+
require 'readline_line_buffer'
|
30
|
+
rescue LoadError
|
31
|
+
$stderr.puts "Bond Error: Failed to load readline_line_buffer. Ensure that it exists and was built correctly."
|
32
|
+
end
|
42
33
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
34
|
+
# Returns full line of what the user has typed.
|
35
|
+
def self.line_buffer
|
36
|
+
Readline.line_buffer
|
47
37
|
end
|
48
38
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Readline for Jruby
|
2
|
+
class Bond::Jruby < Bond::Readline
|
3
|
+
def self.readline_setup
|
4
|
+
require 'readline'
|
5
|
+
require 'jruby'
|
6
|
+
class << Readline
|
7
|
+
ReadlineExt = org.jruby.ext.Readline
|
8
|
+
def line_buffer
|
9
|
+
ReadlineExt.s_get_line_buffer(JRuby.runtime.current_context, JRuby.reference(self))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# A pure ruby readline which requires {rawline}[http://github.com/h3rald/rawline].
|
2
|
+
class Bond::Rawline < Bond::Readline
|
3
|
+
def self.setup(agent)
|
4
|
+
require 'rawline'
|
5
|
+
Rawline.completion_append_character = nil
|
6
|
+
Rawline.basic_word_break_characters= " \t\n\"\\'`><;|&{("
|
7
|
+
Rawline.completion_proc = agent
|
8
|
+
rescue LoadError
|
9
|
+
abort "Bond Error: rawline gem is required for this readline plugin -> gem install rawline"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.line_buffer
|
13
|
+
Rawline.editor.line.text
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# A pure ruby readline which requires {rb-readline}[https://github.com/luislavena/rb-readline].
|
2
|
+
class Bond::Ruby < Bond::Readline
|
3
|
+
def self.readline_setup
|
4
|
+
require 'rb-readline'
|
5
|
+
rescue LoadError
|
6
|
+
abort "Bond Error: rb-readline gem is required for this readline plugin" +
|
7
|
+
" -> gem install rb-readline"
|
8
|
+
end
|
9
|
+
end
|
data/lib/bond/search.rb
CHANGED
@@ -10,7 +10,7 @@ module Bond
|
|
10
10
|
# normal_search(input, list.select {|e| e !~ /-/ })
|
11
11
|
# end
|
12
12
|
#
|
13
|
-
# Now you can pass this custom search to any complete() as :search
|
13
|
+
# Now you can pass this custom search to any complete() as :search => :ignore_hyphen
|
14
14
|
module Search
|
15
15
|
class<<self
|
16
16
|
# Default search used across missions, set by Bond.config[:default_search]
|
@@ -71,4 +71,4 @@ module Bond
|
|
71
71
|
(current_matches + future_matches.map {|e| e[/^(([^#{delim_chars}]*#{delim}){0,#{i+1}})/, 1] }).uniq
|
72
72
|
end
|
73
73
|
end
|
74
|
-
end
|
74
|
+
end
|
data/lib/bond/version.rb
CHANGED
data/test/agent_test.rb
CHANGED
@@ -210,7 +210,8 @@ describe "Agent" do
|
|
210
210
|
|
211
211
|
describe "spy" do
|
212
212
|
before_all {
|
213
|
-
|
213
|
+
reset
|
214
|
+
complete(:on=>/end$/) { [] };
|
214
215
|
complete(:all_methods=>true); complete(:method=>'the') { %w{spy who loved me} }
|
215
216
|
complete(:object=>"Symbol")
|
216
217
|
}
|
data/test/bond_test.rb
CHANGED
@@ -3,22 +3,31 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
3
3
|
describe "Bond" do
|
4
4
|
describe "start" do
|
5
5
|
def start(options={}, &block)
|
6
|
-
Bond.start({:
|
6
|
+
Bond.start({:readline=>valid_readline}.merge(options), &block)
|
7
7
|
end
|
8
8
|
|
9
9
|
before { M.instance_eval("@started = @agent = @config = nil"); M.expects(:load_completions) }
|
10
|
-
it "prints error if
|
11
|
-
capture_stderr {
|
10
|
+
it "prints error if readline doesn't have all required methods" do
|
11
|
+
capture_stderr {
|
12
|
+
start :readline=>Module.new{ def self.setup(arg); end }
|
13
|
+
}.should =~ /Invalid/
|
12
14
|
end
|
13
|
-
|
14
|
-
it "prints error if
|
15
|
-
capture_stderr {
|
15
|
+
|
16
|
+
it "prints error if readline symbol is invalid" do
|
17
|
+
capture_stderr {
|
18
|
+
start :readline => :blah
|
19
|
+
}.should =~ /Invalid.*'blah'/
|
16
20
|
end
|
17
21
|
|
18
|
-
it "prints no error if valid
|
22
|
+
it "prints no error if valid readline" do
|
19
23
|
capture_stderr { start }.should == ''
|
20
24
|
end
|
21
25
|
|
26
|
+
it 'prints no error if valid readline symbol' do
|
27
|
+
capture_stderr { start :readline => :ruby }.should == ''
|
28
|
+
Bond.config[:readline].should == Bond::Ruby
|
29
|
+
end
|
30
|
+
|
22
31
|
it "sets default mission" do
|
23
32
|
start :default_mission=>lambda {|e| %w{1 2 3}}
|
24
33
|
tab('1').should == ['1']
|
@@ -48,7 +57,7 @@ describe "Bond" do
|
|
48
57
|
Bond.started?.should == true
|
49
58
|
end
|
50
59
|
|
51
|
-
after_all {
|
60
|
+
after_all { reset }
|
52
61
|
end
|
53
62
|
|
54
63
|
describe "start with :gems" do
|
@@ -88,13 +97,13 @@ describe "Bond" do
|
|
88
97
|
M.expects(:gem)
|
89
98
|
start(:gems=>%w{awesome})
|
90
99
|
end
|
91
|
-
after_all {
|
100
|
+
after_all { reset }
|
92
101
|
end
|
93
102
|
|
94
103
|
it "prints error if Readline setup fails" do
|
95
104
|
Bond::Readline.expects(:setup).raises('WTF')
|
96
|
-
capture_stderr { Bond.start(:
|
97
|
-
M.debrief :
|
105
|
+
capture_stderr { Bond.start(:readline=>Bond::Readline) }.should =~ /Error.*Failed Readline.*'WTF'/
|
106
|
+
M.debrief :readline=>valid_readline
|
98
107
|
end
|
99
108
|
|
100
109
|
it "start prints error for failed completion file" do
|
@@ -105,19 +114,19 @@ describe "Bond" do
|
|
105
114
|
it "reset clears existing missions" do
|
106
115
|
complete(:on=>/blah/) {[]}
|
107
116
|
Bond.agent.missions.size.should.not == 0
|
108
|
-
|
117
|
+
reset
|
109
118
|
Bond.agent.missions.size.should == 0
|
110
119
|
end
|
111
120
|
|
112
121
|
describe "restart" do
|
113
122
|
def start(options={}, &block)
|
114
|
-
Bond.start({:
|
123
|
+
Bond.start({:readline=>valid_readline}.merge(options), &block)
|
115
124
|
end
|
116
125
|
|
117
126
|
it "deletes previous config" do
|
118
127
|
start :blah=>''
|
119
128
|
Bond.config[:blah].should.not == nil
|
120
|
-
Bond.restart({:
|
129
|
+
Bond.restart({:readline=>valid_readline})
|
121
130
|
Bond.config[:blah].should == nil
|
122
131
|
end
|
123
132
|
|
@@ -125,7 +134,7 @@ describe "Bond" do
|
|
125
134
|
start
|
126
135
|
complete(:method=>'blah') { [] }
|
127
136
|
MethodMission.actions['blah'].should.not == nil
|
128
|
-
Bond.restart({:
|
137
|
+
Bond.restart({:readline=>valid_readline})
|
129
138
|
MethodMission.actions['blah'].should == nil
|
130
139
|
end
|
131
140
|
end
|
data/test/completion_test.rb
CHANGED
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
2
2
|
|
3
3
|
describe "Completion" do
|
4
4
|
before_all {
|
5
|
-
|
5
|
+
reset
|
6
6
|
M.load_file File.dirname(__FILE__) + '/../lib/bond/completion.rb'
|
7
7
|
M.load_dir File.dirname(__FILE__) + '/../lib/bond'
|
8
8
|
}
|
@@ -48,7 +48,7 @@ describe "Completion" do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "completes hash coming from a method" do
|
51
|
-
tab('Bond.config[:r').should == ["Bond.config[:
|
51
|
+
tab('Bond.config[:r').should == ["Bond.config[:readline"]
|
52
52
|
end
|
53
53
|
|
54
54
|
it "methods don't swallow up default completion" do
|
data/test/completions_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -15,7 +15,7 @@ module TestHelpers
|
|
15
15
|
module InputCompletor; CompletionProc = lambda {|e| [] }; end
|
16
16
|
end
|
17
17
|
]
|
18
|
-
::IRB.CurrentContext = stub(:workspace=>stub(:binding=>binding))
|
18
|
+
::IRB.CurrentContext = stub(:workspace => stub(:binding => binding))
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -50,8 +50,13 @@ module TestHelpers
|
|
50
50
|
Bond.complete(*args, &block)
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
|
53
|
+
def valid_readline
|
54
|
+
Class.new { def self.setup(arg); end; def self.line_buffer; end }
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset
|
58
|
+
M.reset
|
59
|
+
M.debrief :readline => TestHelpers.valid_readline
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
@@ -60,5 +65,5 @@ class Bacon::Context
|
|
60
65
|
end
|
61
66
|
|
62
67
|
# Default settings
|
63
|
-
Bond::M.debrief(:
|
68
|
+
Bond::M.debrief(:readline => TestHelpers.valid_readline, :debug => true)
|
64
69
|
include Bond
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bond
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Gabriel Horner
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-11 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -78,7 +78,7 @@ dependencies:
|
|
78
78
|
version: "0"
|
79
79
|
type: :development
|
80
80
|
version_requirements: *id004
|
81
|
-
description: Bond is on a mission to improve autocompletion in ruby, especially for ripl
|
81
|
+
description: Bond is on a mission to improve autocompletion in ruby, especially for irb/ripl. Aside from doing everything irb's can do and fixing its quirks, Bond can autocomplete argument(s) to methods, uniquely completing per module, per method and per argument. Bond brings ruby autocompletion closer to bash/zsh as it provides a configuration system and a DSL for creating custom completions and completion rules. With this configuration system, users can customize their autocompletions and share it with others. Bond can also load completions that ship with gems. Bond is able to offer more than irb's completion since it uses the full line of input when completing as opposed to irb's last-word approach.
|
82
82
|
email: gabriel.horner@gmail.com
|
83
83
|
executables: []
|
84
84
|
|
@@ -106,9 +106,11 @@ files:
|
|
106
106
|
- lib/bond/missions/method_mission.rb
|
107
107
|
- lib/bond/missions/object_mission.rb
|
108
108
|
- lib/bond/missions/operator_method_mission.rb
|
109
|
-
- lib/bond/rawline.rb
|
110
109
|
- lib/bond/rc.rb
|
111
110
|
- lib/bond/readline.rb
|
111
|
+
- lib/bond/readlines/jruby.rb
|
112
|
+
- lib/bond/readlines/rawline.rb
|
113
|
+
- lib/bond/readlines/ruby.rb
|
112
114
|
- lib/bond/search.rb
|
113
115
|
- lib/bond/version.rb
|
114
116
|
- lib/bond.rb
|
@@ -132,14 +134,14 @@ files:
|
|
132
134
|
- test/deps.rip
|
133
135
|
- Rakefile
|
134
136
|
- .gemspec
|
135
|
-
has_rdoc:
|
137
|
+
has_rdoc: true
|
136
138
|
homepage: http://tagaholic.me/bond/
|
137
139
|
licenses:
|
138
140
|
- MIT
|
139
141
|
post_install_message:
|
140
142
|
rdoc_options:
|
141
143
|
- --title
|
142
|
-
- Bond 0.
|
144
|
+
- Bond 0.4.0 Documentation
|
143
145
|
require_paths:
|
144
146
|
- lib
|
145
147
|
required_ruby_version: !ruby/object:Gem::Requirement
|
data/lib/bond/rawline.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module Bond
|
2
|
-
# A readline plugin for use with {Rawline}[http://github.com/h3rald/rawline]. This plugin
|
3
|
-
# should be used in conjunction with {a Rawline shell}[http://www.h3rald.com/articles/real-world-rawline-usage].
|
4
|
-
module Rawline
|
5
|
-
def setup(agent)
|
6
|
-
require 'rawline'
|
7
|
-
::Rawline.completion_append_character = nil
|
8
|
-
::Rawline.basic_word_break_characters= " \t\n\"\\'`><;|&{("
|
9
|
-
::Rawline.completion_proc = agent
|
10
|
-
end
|
11
|
-
|
12
|
-
def line_buffer
|
13
|
-
::Rawline.editor.line.text
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|