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/lib/bond.rb CHANGED
@@ -1,121 +1,90 @@
1
- current_dir = File.dirname(__FILE__)
2
- $:.unshift(current_dir) unless $:.include?(current_dir) || $:.include?(File.expand_path(current_dir))
1
+ require 'bond/m'
2
+ require 'bond/version'
3
3
  require 'bond/readline'
4
4
  require 'bond/rawline'
5
5
  require 'bond/agent'
6
6
  require 'bond/search'
7
- require 'bond/actions'
7
+ require 'bond/input'
8
+ require 'bond/rc'
8
9
  require 'bond/mission'
9
10
  require 'bond/missions/default_mission'
10
11
  require 'bond/missions/method_mission'
11
12
  require 'bond/missions/object_mission'
13
+ require 'bond/missions/anywhere_mission'
14
+ require 'bond/missions/operator_method_mission'
12
15
 
13
- # Bond allows easy handling and creation of completion missions/rules with Bond.complete. When Bond is asked to autocomplete, Bond looks
14
- # up the completion missions in the order they were defined and picks the first one that matches what the user has typed.
15
- # Bond::Agent handles finding and executing the correct completion mission.
16
- # Some pointers on using/understanding Bond:
17
- # * Bond can work outside of irb and readline when debriefed with Bond.debrief. This should be called before any Bond.complete calls.
18
- # * Bond doesn't take over completion until an explicit Bond.complete is called.
19
- # * Order of completion missions matters. The order they're defined in is the order Bond searches
20
- # when looking for a matching completion. This means that more specific completions like method and object completions should come
21
- # before more general ones. You can tweak completion placement by passing :place to Bond.complete.
22
- # * If no completion missions match, then Bond falls back on a default mission. If using irb and irb/completion
23
- # this falls back on irb's completion. Otherwise an empty completion list is returned.
24
16
  module Bond
25
17
  extend self
26
18
 
27
- # Defines a completion mission aka a Bond::Mission. A valid mission consists of a condition and an action block.
28
- # A condition is specified with one of the following options: :on, :object or :method. Depending on the condition option, a
29
- # different type of Bond::Mission is created. Action blocks are given what the user has typed and should a return a list of possible
30
- # completions. By default Bond searches possible completions to only return the ones that match what has been typed. This searching
31
- # behavior can be customized with the :search option.
19
+ # Defines a completion rule (Mission). A valid Mission consists of a condition and an action. A
20
+ # condition is specified with one of the following options: :on, :object, :anywhere or :method(s). Each
21
+ # of these options creates a different Mission class. An action is either this method's block or :action.
22
+ # An action takes what the user has typed (Input) and returns an array of possible completions. Bond
23
+ # searches these completions and returns matching completions. This searching behavior can be configured
24
+ # or turned off per mission with :search. If turned off, the action must also handle searching.
32
25
  # ====Options:
33
- # [:on] Matches the given regular expression with the full line of input. Creates a Bond::Mission object.
34
- # Access to the matches in the regular expression are passed to the completion proc as the input's attribute :matched.
35
- # [:method] Matches the given string or regular expression with any methods (or any non-whitespace string) that start the beginning
36
- # of a line. Creates a Bond::Missions:MethodMission object. If given a string, the match has to be exact.
37
- # Since this is used mainly for argument completion, completions can have an optional quote in front of them.
38
- # [:object] Matches the given a string or regular expression to the ancestor of the current object being completed. Creates a
39
- # Bond::Missions::ObjectMission object. Access to the current object is passed to the completion proc as the input's
40
- # attribute :object. If no action is given, this completion type defaults to all methods the object responds to.
41
- # [:search] Given a symbol, proc or false, determines how completions are searched to match what the user has typed. Defaults to
42
- # traditional searching i.e. looking at the beginning of a string for possible matches. If false, search is turned off and
43
- # assumed to be done in the action block. Possible symbols are :anywhere, :ignore_case and :underscore. See Bond::Search for
44
- # more info about them. A proc is given two arguments: the input string and an array of possible completions.
45
- # [:place] Given a symbol or number, controls where this completion is placed in relation to existing ones. If a number, the
46
- # completion is placed at that number. If the symbol :last, the completion is placed at the end regardless of completions
47
- # defined after it. Use this symbol as a way of anchoring completions you want to remain at the end. Multiple declarations
48
- # of :last are kept last in the order they are defined.
49
- #
26
+ # [*:on*] Regular expression which matches the full line of input to create a Mission object.
27
+ # [*:method*, *:methods*, *:class*] See MethodMission.
28
+ # [*:anywhere*, *:prefix*] See AnywhereMission.
29
+ # [*:object*] See ObjectMission.
30
+ # [*:search*] A symbol or false which determines how completions are searched. Defaults to
31
+ # Search.default_search. If false, search is turned off and assumed to be done in the action.
32
+ # Possible symbols are :anywhere, :ignore_case, :underscore, :normal, :files and :modules.
33
+ # See Search for more info.
34
+ # [*:action*] Rc method name that takes an Input and returns possible completions. See MethodMission for
35
+ # specific behavior with :method(s).
36
+ # [*:place*] A number or :last which indicates where a mission is inserted amongst existing missions.
37
+ # If the symbol :last, places the mission at the end regardless of missions defined after
38
+ # it. Multiple declarations of :last are kept last in the order they are defined.
39
+ # [*:name*] A symbol or string that serves a unique id for a mission. This unique id can be passed by
40
+ # Bond.recomplete to identify and replace the mission.
50
41
  # ==== Examples:
51
42
  # Bond.complete(:method=>'shoot') {|input| %w{to kill} }
52
43
  # Bond.complete(:on=>/^((([a-z][^:.\(]*)+):)+/, :search=>false) {|input| Object.constants.grep(/#{input.matched[1]}/) }
53
44
  # Bond.complete(:object=>ActiveRecord::Base, :search=>:underscore, :place=>:last)
54
- # Bond.complete(:object=>ActiveRecord::Base) {|input| input.object.class.instance_methods(false) }
55
45
  # Bond.complete(:method=>'you', :search=>proc {|input, list| list.grep(/#{input}/i)} ) {|input| %w{Only Live Twice} }
56
- def complete(options={}, &block)
57
- if (result = agent.complete(options, &block)).is_a?(String)
58
- $stderr.puts result
59
- false
60
- else
61
- true
62
- end
63
- end
46
+ # Bond.complete(:method=>'system', :action=>:shell_commands)
47
+ def complete(options={}, &block); M.complete(options, &block); end
64
48
 
65
- # Redefines an existing completion mission. Takes same options as Bond.complete. This is useful when wanting to override existing
66
- # completions or when wanting to toggle between multiple definitions or modes of a completion.
67
- def recomplete(options={}, &block)
68
- if (result = agent.recomplete(options, &block)).is_a?(String)
69
- $stderr.puts result
70
- false
71
- else
72
- true
73
- end
74
- end
75
-
76
- # Resets Bond so that next time Bond.complete is called, a new set of completion missions are created. This does not
77
- # change current completion behavior.
78
- def reset
79
- @agent = nil
80
- end
81
-
82
- # Debriefs Bond to set global defaults. Call before defining completions.
83
- # ==== Options:
84
- # [:readline_plugin] Specifies a Bond plugin to interface with a Readline-like library. Available plugins are Bond::Readline and Bond::Rawline.
85
- # Defaults to Bond::Readline. Note that a plugin doesn't imply use with irb. Irb is joined to the hip with Readline.
86
- # [:default_mission] A proc to be used as the default completion proc when no completions match or one fails. When in irb with completion
87
- # enabled, uses irb completion. Otherwise defaults to a proc with an empty completion list.
88
- # [:default_search] A symbol or proc to be used as the default search in completions. See Bond.complete's :search option for valid symbols.
89
- # [:eval_binding] Specifies a binding to be used with Bond::Missions::ObjectMission. When in irb, defaults to irb's main binding. Otherwise
90
- # defaults to TOPLEVEL_BINDING.
91
- # [:debug] Boolean to print unexpected errors when autocompletion fails. Default is false.
92
- #
49
+ # Redefines an existing completion mission to have a different action. The condition can only be varied if :name is
50
+ # used to identify and replace a mission. Takes same options as Bond.complete.
93
51
  # ==== Example:
94
- # Bond.debrief :default_search=>:underscore, :default_mission=>:default
95
- def debrief(options={})
96
- config.merge! options
97
- plugin_methods = %w{setup line_buffer}
98
- unless config[:readline_plugin].is_a?(Module) &&
99
- plugin_methods.all? {|e| config[:readline_plugin].instance_methods.map {|f| f.to_s}.include?(e)}
100
- $stderr.puts "Invalid readline plugin set. Try again."
101
- end
102
- end
52
+ # Bond.recomplete(:on=>/man/, :name=>:count) { %w{4 5 6}}
53
+ def recomplete(options={}, &block); M.recomplete(options, &block); end
103
54
 
104
- # Reports what completion mission and possible completions would happen for a given input. Helpful for debugging
105
- # your completion missions.
55
+ # Reports what completion mission matches for a given input. Helpful for debugging missions.
106
56
  # ==== Example:
107
57
  # >> Bond.spy "shoot oct"
108
58
  # Matches completion mission for method matching "shoot".
109
59
  # Possible completions: ["octopussy"]
110
- def spy(input)
111
- agent.spy(input)
112
- end
60
+ def spy(*args); M.spy(*args); end
61
+
62
+ # Global config with the following keys:
63
+ # [*:readline_plugin*] Specifies a Bond plugin to interface with a Readline-like library. Available
64
+ # plugins are Readline and Rawline. Defaults to Readline.
65
+ # [*:default_mission*] A proc or name of an Rc method to use as the default completion when no
66
+ # missions match.
67
+ # [*:default_search*] Name of a *_search method in Rc to use as the default search in completions.
68
+ # Default is :underscore. See Bond.complete's :search option for valid values.
69
+ # [*:eval_binding*] Specifies a binding to use when evaluating objects in ObjectMission and MethodMission.
70
+ # When in irb, defaults to irb's current binding. Otherwise defaults to TOPLEVEL_BINDING.
71
+ # [*:debug*] Boolean to show the stacktrace when autocompletion fails and raise exceptions in Rc.eval.
72
+ # Default is false.
73
+ def config; M.config; end
74
+
75
+ # Starts Bond with a default set of completions that replace and improve irb's completion. Loads completion
76
+ # files in the following order: lib/bond/completion.rb, optional ~/.bondrc, lib/bond/completions/*.rb,
77
+ # optional ~/.bond/completions/*.rb and optional block. See Rc for the DSL to use in completion files and
78
+ # in the block. See Bond.config for valid options.
79
+ # ==== Example:
80
+ # Bond.start(:default_search=>:ignore_case) do
81
+ # complete(:method=>"Object#respond_to?") {|e| e.object.methods }
82
+ # end
83
+ def start(options={}, &block); M.start(options, &block); end
113
84
 
114
- def agent #:nodoc:
115
- @agent ||= Agent.new(config)
116
- end
85
+ # An Agent who saves all Bond.complete missions and executes the correct one when a completion is called.
86
+ def agent; M.agent; end
117
87
 
118
- def config #:nodoc:
119
- @config ||= {:readline_plugin=>Bond::Readline, :debug=>false}
120
- end
88
+ # Lists all methods that have argument completion.
89
+ def list_methods; MethodMission.all_methods; end
121
90
  end
data/lib/bond/agent.rb CHANGED
@@ -1,19 +1,29 @@
1
1
  module Bond
2
- # Handles finding and executing the first mission that matches the input line. Once found, it calls the mission's action.
2
+ # Every time a completion is attempted, the Agent searches its missions for the first one that matches the user input.
3
+ # Using either the found mission or Agent.default_mission, the Agent executes the mission's action.
3
4
  class Agent
4
5
  # The array of missions that will be searched when a completion occurs.
5
6
  attr_reader :missions
7
+ # An agent's best friend a.k.a. the readline plugin.
8
+ attr_reader :weapon
6
9
 
7
10
  def initialize(options={}) #:nodoc:
8
- raise ArgumentError unless options[:readline_plugin].is_a?(Module)
9
- extend(options[:readline_plugin])
11
+ setup_readline_plugin(options[:readline_plugin])
10
12
  @default_mission_action = options[:default_mission] if options[:default_mission]
11
- @eval_binding = options[:eval_binding] if options[:eval_binding]
12
- Mission.default_search = options[:default_search] if options[:default_search]
13
- setup
13
+ Mission.eval_binding = options[:eval_binding] if options[:eval_binding]
14
+ Search.default_search = options[:default_search] || :normal
14
15
  @missions = []
15
16
  end
16
17
 
18
+ def setup_readline_plugin(plugin) #:nodoc:
19
+ raise ArgumentError unless plugin.is_a?(Module)
20
+ @weapon = plugin.extend(plugin)
21
+ @weapon.setup(self)
22
+ rescue
23
+ $stderr.puts "Bond Error: Failed #{plugin.to_s[/[^:]+$/]} setup with '#{$!.message}'"
24
+ end
25
+
26
+ # Creates a mission.
17
27
  def complete(options={}, &block)
18
28
  if (mission = create_mission(options, &block)).is_a?(Mission)
19
29
  mission.place.is_a?(Integer) ? @missions.insert(mission.place - 1, mission).compact! : @missions << mission
@@ -23,19 +33,17 @@ module Bond
23
33
  end
24
34
 
25
35
  def create_mission(options, &block) #:nodoc:
26
- options[:action] ||= block
27
- Mission.create(options.merge(:eval_binding=>@eval_binding))
36
+ Mission.create options.merge!(:action=>options[:action] || block)
28
37
  rescue InvalidMissionError
29
- "Invalid mission given. Mission needs an action and a condition."
30
- rescue InvalidMissionActionError
31
- "Invalid mission action given. Make sure action responds to :call or refers to a predefined action that does."
38
+ "Invalid #{$!.message} for completion with options: #{options.inspect}"
32
39
  rescue
33
- "Mission setup failed with:\n#{$!}"
40
+ "Unexpected error while creating completion with options #{options.inspect}:\n#{$!}"
34
41
  end
35
42
 
43
+ # Creates a mission and replaces the mission it matches if possible.
36
44
  def recomplete(options={}, &block)
37
45
  if (mission = create_mission(options, &block)).is_a?(Mission)
38
- if (existing_mission = @missions.find {|e| e.unique_id == mission.unique_id })
46
+ if (existing_mission = @missions.find {|e| e.name == mission.name })
39
47
  @missions[@missions.index(existing_mission)] = mission
40
48
  sort_last_missions
41
49
  else
@@ -55,31 +63,29 @@ module Bond
55
63
 
56
64
  # This is where the action starts when a completion is initiated.
57
65
  def call(input)
58
- mission_input = line_buffer
66
+ mission_input = @weapon.line_buffer
59
67
  mission_input = $1 if mission_input !~ /#{Regexp.escape(input)}$/ && mission_input =~ /^(.*#{Regexp.escape(input)})/
60
- (mission = find_mission(mission_input)) ? mission.execute : default_mission.execute(input)
61
- rescue FailedExecutionError
62
- $stderr.puts "", $!.message
68
+ (mission = find_mission(mission_input)) ? mission.execute : default_mission.execute(Input.new(input))
69
+ rescue FailedMissionError
70
+ completion_error($!.message[0], "Completion Info: #{$!.message[1]}")
63
71
  rescue
64
- if Bond.config[:debug]
65
- p $!
66
- p $!.backtrace.slice(0,5)
67
- end
68
- default_mission.execute(input)
72
+ completion_error "Failed internally with '#{$!.message}'.",
73
+ "Please report this issue with debug on: Bond.config[:debug] = true."
69
74
  end
70
75
 
76
+ def completion_error(desc, message) #:nodoc:
77
+ arr = ["Bond Error: #{desc}", message]
78
+ arr << "Stack Trace: #{$!.backtrace.inspect}" if Bond.config[:debug]
79
+ arr
80
+ end
81
+
82
+ # Given a hypothetical user input, reports back what mission it would have found and executed.
71
83
  def spy(input)
72
84
  if (mission = find_mission(input))
73
- if mission.is_a?(Missions::ObjectMission)
74
- puts "Matches completion mission for object with an ancestor matching #{mission.object_condition.inspect}."
75
- elsif mission.is_a?(Missions::MethodMission)
76
- puts "Matches completion mission for method matching #{mission.method_condition.inspect}."
77
- else
78
- puts "Matches completion mission with condition #{mission.condition.inspect}."
79
- end
80
- puts "Possible completions: #{mission.execute.inspect}"
85
+ puts mission.match_message, "Possible completions: #{mission.execute.inspect}",
86
+ "Matches for #{mission.condition.inspect} are #{mission.matched.to_a.inspect}"
81
87
  else
82
- puts "Doesn't match a completion mission."
88
+ puts "Doesn't match a completion."
83
89
  end
84
90
  end
85
91
 
@@ -87,9 +93,9 @@ module Bond
87
93
  @missions.find {|mission| mission.matches?(input) }
88
94
  end
89
95
 
90
- # Default mission used by agent.
96
+ # Default mission used by agent. An instance of DefaultMission.
91
97
  def default_mission
92
- @default_mission ||= Missions::DefaultMission.new(:action=>@default_mission_action)
98
+ @default_mission ||= DefaultMission.new(:action=>@default_mission_action)
93
99
  end
94
100
  end
95
101
  end
@@ -1,28 +1,16 @@
1
- # You shouldn't place Bond.complete statements before requiring this file
2
- # unless you're also reproducing this Bond.debrief
3
- Bond.debrief(:default_search=>:underscore) unless Bond.config[:default_search]
4
- Bond.debrief(:default_mission=>:default) unless Bond.config[:default_mission]
5
- Bond.complete(:method=>/system|`/, :action=>:shell_commands)
6
- Bond.complete(:method=>'require', :action=>:method_require, :search=>false)
7
-
8
- # irb/completion reproduced without the completion quirks
9
- # Completes classes and constants
10
- Bond.complete(:on=>/(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/, :action=>:constants, :search=>false)
11
- # Completes absolute constants
12
- Bond.complete(:on=>/::([A-Z][^:\.\(]*)$/, :search=>false) {|e|
13
- Object.constants.grep(/^#{Regexp.escape(e.matched[1])}/).collect{|f| "::" + f}
1
+ # any object's methods
2
+ complete :object=>"Object"
3
+ # method arguments
4
+ complete :all_methods=>true
5
+ complete :all_operator_methods=>true
6
+ # classes and constants
7
+ complete(:name=>:constants, :anywhere=>'(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)') {|e|
8
+ receiver = e.matched[2]
9
+ candidates = eval("#{receiver}.constants | #{receiver}.methods") || []
10
+ normal_search(e.matched[5], candidates).map {|e| receiver + "::" + e}
14
11
  }
15
- # Completes symbols
16
- Bond.complete(:on=>/(:[^:\s.]*)$/) {|e|
17
- Symbol.respond_to?(:all_symbols) ? Symbol.all_symbols.map {|f| ":#{f}" } : []
18
- }
19
- # Completes global variables
20
- Bond.complete(:on=>/(\$[^\s.]*)$/, :search=>false) {|e|
21
- global_variables.grep(/^#{Regexp.escape(e.matched[1])}/)
22
- }
23
- # Completes files
24
- Bond.complete(:on=>/[\s(]["']([^'"]*)$/, :search=>false, :action=>:quoted_files, :place=>:last)
25
- # Completes any object's methods
26
- Bond.complete(:object=>"Object", :place=>:last)
27
- # Completes method completion anywhere in the line
28
- Bond.complete(:on=>/([^.\s]+)\.([^.\s]*)$/, :object=>"Object", :place=>:last)
12
+ # absolute constants
13
+ complete(:prefix=>'::', :anywhere=>'[A-Z][^:\.\(]*') {|e| Object.constants }
14
+ complete(:anywhere=>':[^:\s.]*') {|e| Symbol.all_symbols.map {|f| ":#{f}" } rescue [] }
15
+ complete(:anywhere=>'\$[^\s.]*') {|e| global_variables }
16
+ complete(:name=>:quoted_files, :on=>/[\s(]["']([^'"]*)$/, :search=>false, :place=>:last) {|e| files(e.matched[1]) }
@@ -0,0 +1,12 @@
1
+ attribute_imethods = %w{attribute_for_inspect column_for_attribute decrement} +
2
+ %w{increment update_attribute toggle update_attributes []}
3
+ complete(:methods=>attribute_imethods, :class=>"ActiveRecord::Base#") {|e| e.object.attribute_names }
4
+
5
+ attribute_cmethods = %w{attr_accessible attr_protected attr_readonly create create! decrement_counter} +
6
+ %w{destroy_all exists? increment_counter new serialize update update_all update_counters where}
7
+ complete(:methods=>attribute_cmethods, :class=>'ActiveRecord::Base.') {|e| e.object.column_names }
8
+
9
+ complete(:method=>"ActiveRecord::Base.establish_connection") { %w{adapter host username password database} }
10
+ complete(:methods=>%w{find all first last}, :class=>'ActiveRecord::Base.') {
11
+ %w{conditions order group having limit offset joins include select from readonly lock}
12
+ }
@@ -0,0 +1 @@
1
+ complete(:methods=>%w{delete index rindex include?}, :class=>"Array#") {|e| e.object }
@@ -0,0 +1,2 @@
1
+ complete(:methods=>%w{Bond.complete Bond.recomplete}) {
2
+ %w{on action method methods class object prefix search place name} }
@@ -0,0 +1,3 @@
1
+ complete(:methods=>%w{delete fetch store, [] has_key? key? include? member? values_at},
2
+ :class=>"Hash#") {|e| e.object.keys }
3
+ complete(:methods=>%w{index value? has_value?}, :class=>"Hash#") {|e| e.object.values }
@@ -0,0 +1,13 @@
1
+ complete(:methods=>%w{Kernel#raise Kernel#fail}) { objects_of(Class).select {|e| e < StandardError } }
2
+ complete(:method=>%w{Kernel#system Kernel#exec}) {|e|
3
+ ENV['PATH'].split(File::PATH_SEPARATOR).uniq.map {|e| Dir.entries(e) }.flatten.uniq - ['.', '..']
4
+ }
5
+ complete(:method=>"Kernel#require", :search=>:files) {
6
+ paths = $:.map {|e| Dir["#{e}/**/*.{rb,bundle,dll,so}"].map {|f| f.sub(e+'/', '') } }.flatten
7
+ if Object.const_defined?(:Gem)
8
+ paths += Gem.path.map {|e| Dir["#{e}/gems/*/lib/*.{rb,bundle,dll,so}"].
9
+ map {|f| f.sub(/^.*\//,'') } }.flatten
10
+ end
11
+ paths.uniq
12
+ }
13
+ complete(:methods=>%w{Kernel#trace_var Kernel#untrace_var}) { global_variables.map {|e| ":#{e}"} }
@@ -0,0 +1,7 @@
1
+ complete(:methods=>%w{const_get const_set const_defined? remove_const}, :class=>"Module#") {|e| e.object.constants }
2
+ complete(:methods=>%w{class_variable_defined? class_variable_get class_variable_set remove_class_variable},
3
+ :class=>"Module#") {|e| e.object.class_variables }
4
+ complete(:methods=>%w{instance_method method_defined? module_function public private protected remove_method undef_method},
5
+ :class=>"Module#") {|e| e.object.instance_methods }
6
+ complete(:methods=>%w{< <= <=> > >= include? include}, :class=>"Module#", :search=>:modules) { objects_of(Module) }
7
+ complete(:method=>'Module#alias_method') {|e| e.argument > 1 ? e.object.instance_methods : [] }
@@ -0,0 +1,21 @@
1
+ instance_meths = %w{instance_variable_get instance_variable_set remove_instance_variable instance_variable_defined?}
2
+ complete(:methods=>instance_meths, :class=>"Object#") {|e| e.object.instance_variables }
3
+ complete(:method=>"Object#instance_of?", :search=>:modules) { objects_of(Class) }
4
+ complete(:methods=>%w{is_a? kind_a? extend}, :class=>"Object#", :search=>:modules) { objects_of(Module) }
5
+ complete(:methods=>%w{Object#method Object#respond_to?}) {|e| e.object.methods }
6
+ complete(:method=>"Object#[]") {|e| e.object.keys rescue [] }
7
+ complete(:method=>"Object#send") {|e|
8
+ if e.argument > 1
9
+ if (meth = eval(e.arguments[0])) && meth.to_s != 'send' &&
10
+ (action = MethodMission.find(e.object, meth.to_s))
11
+ e.argument -= 1
12
+ e.arguments.shift
13
+ action[0].call(e)
14
+ end
15
+ else
16
+ send_methods(e.object)
17
+ end
18
+ }
19
+ def send_methods(obj)
20
+ (obj.methods + obj.private_methods(false)).map {|e| e.to_s } - Mission::OPERATORS
21
+ end
@@ -0,0 +1 @@
1
+ complete(:method=>"Struct#[]") {|e| e.object.members }
data/lib/bond/input.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Bond
2
+ # A string representing the last word the user has typed. This string is passed to a mission
3
+ # action to generate possible completions. This string contains a number of attributes from the
4
+ # matching mission, useful in generating completions.
5
+ class Input < String
6
+ # Actual object a user has just typed. Used by MethodMission and ObjectMission.
7
+ attr_accessor :object
8
+ # MatchData object from the matching mission (Mission#matched).
9
+ attr_reader :matched
10
+ # Current argument number and array of argument strings. Used by MethodMission.
11
+ attr_accessor :argument, :arguments
12
+ # The full line the user has typed.
13
+ attr_reader :line
14
+ def initialize(str, options={}) #:nodoc:
15
+ super(str || '')
16
+ @matched = options[:matched]
17
+ @line = options[:line]
18
+ @object = options[:object] if options[:object]
19
+ @argument = options[:argument] if options[:argument]
20
+ @arguments = options[:arguments] if options[:arguments]
21
+ end
22
+
23
+ def inspect #:nodoc:
24
+ "#<Bond::Input #{self.to_s.inspect} @matched=#{@matched.to_a.inspect} @line=#{@line.inspect} "+
25
+ "@argument=#{@argument.inspect} @arguments=#{@arguments.inspect} @object=#{@object.inspect}>"
26
+ end
27
+ end
28
+ end