module Bond # Handles finding and executing the first mission that matches the input line. Once found, it calls the mission's action. class Agent # The array of missions that will be searched when a completion occurs. attr_reader :missions def initialize(options={}) #:nodoc: raise ArgumentError unless options[:readline_plugin].is_a?(Module) extend(options[:readline_plugin]) @default_mission_action = options[:default_mission] if options[:default_mission] @eval_binding = options[:eval_binding] if options[:eval_binding] Mission.default_search = options[:default_search] if options[:default_search] setup @missions = [] end def complete(options={}, &block) if (mission = create_mission(options, &block)).is_a?(Mission) mission.place.is_a?(Integer) ? @missions.insert(mission.place - 1, mission).compact! : @missions << mission sort_last_missions end mission end def create_mission(options, &block) #:nodoc: options[:action] ||= block Mission.create(options.merge(:eval_binding=>@eval_binding)) rescue InvalidMissionError "Invalid mission given. Mission needs an action and a condition." rescue InvalidMissionActionError "Invalid mission action given. Make sure action responds to :call or refers to a predefined action that does." rescue "Mission setup failed with:\n#{$!}" end def recomplete(options={}, &block) if (mission = create_mission(options, &block)).is_a?(Mission) if (existing_mission = @missions.find {|e| e.unique_id == mission.unique_id }) @missions[@missions.index(existing_mission)] = mission sort_last_missions else return "No existing mission found to recomplete." end end mission end def sort_last_missions #:nodoc: @missions.replace @missions.partition {|e| e.place != :last }.flatten end def reset #:nodoc: @missions = [] end # This is where the action starts when a completion is initiated. def call(input) mission_input = line_buffer mission_input = $1 if mission_input !~ /#{Regexp.escape(input)}$/ && mission_input =~ /^(.*#{Regexp.escape(input)})/ (mission = find_mission(mission_input)) ? mission.execute : default_mission.execute(input) rescue FailedExecutionError $stderr.puts "", $!.message rescue if Bond.config[:debug] p $! p $!.backtrace.slice(0,5) end default_mission.execute(input) end def spy(input) if (mission = find_mission(input)) if mission.is_a?(Missions::ObjectMission) puts "Matches completion mission for object with an ancestor matching #{mission.object_condition.inspect}." elsif mission.is_a?(Missions::MethodMission) puts "Matches completion mission for method matching #{mission.method_condition.inspect}." else puts "Matches completion mission with condition #{mission.condition.inspect}." end puts "Possible completions: #{mission.execute.inspect}" else puts "Doesn't match a completion mission." end end def find_mission(input) #:nodoc: @missions.find {|mission| mission.matches?(input) } end # Default mission used by agent. def default_mission @default_mission ||= Missions::DefaultMission.new(:action=>@default_mission_action) end end end