################################################################################ # Tries to negate a statement. # # > what is the opposite of "John eats an aple." # John does not eat an apple. # ################################################################################ require 'yaml' require 'drb' $Quitwords = [':q', 'quit', 'exit', 'bye'] class MyAgent def initialize(args=Array.new) @workingDir = File.expand_path(File.dirname(__FILE__)) @filename = @workingDir + "/oppagent-api.yaml" unless load_message = load_synonyms @patterns = [ [/^(.*?) is a synonym for (.*)/, :add_synonym], [/^save syn/, :save_synonyms], [/^load syn/, :load_synonyms], [/^add pattern (.*), (.*)/, :add_pattern], [/^>(.*)/, :defining_method], [/^restart/, :restart] ] save_synonyms # creates patterns.yaml on first use. else puts load_message end @method_def = '' @monty_started = false @monty = nil start_monty @opposite_rules = Array.new @opposite_rules.push("if np =~ /^every/i; grp1.sub!(/^every/i, 'every'); return 'Not ' << grp1 << '.'; end") @opposite_rules.push("if vp =~ /^are$/i; grp1.sub!(/ are /i, ' are not '); return grp1; end") @opposite_rules.push("if vp =~ /^is$/i; grp1.sub!(/ is /i, ' is not '); return grp1; end") @opposite_rules.push("if vp =~ /^am$/i; grp1.sub!(/ am /i, ' am not '); return grp1; end") @plurals = Array.new; @singulars = Array.new @plurals.push("I") end def isPlural?(phrase) @singulars.each { |sing| if phrase =~ /^#{sing}$/i then return false end } @plurals.each { |plural| if phrase =~ /^#{plural}$/i then return true end } if phrase[-1].chr == 's' then return true end return false end def start_monty if @monty_started then return end #puts "start_monty!" DRb.start_service() @monty = DRbObject.new(nil, 'druby://localhost:9070') #puts "startmonty!!" begin help, s = @monty.send("help") #puts "help == #{help}" @monty_started = true if help =~ /montylingua/i then return end rescue => err puts "error: #{err}" begin Dir.chdir("..\\..") IO.popen("montyd.bat") # Windows-specific! Dir.chdir("controller\\oppagent") puts "monty started!" rescue => error puts "error 2: #{error}" end end end def def_method method_def file = IO.read(__FILE__) return "Doesn't have 'end # class'" unless file =~ /(.*)end # class(.*)if \$0 == __FILE__(.*)/m grp1 = $1.to_s; grp2 = $2.to_s; grp3 = $3.to_s new_filename = get_new_filename # TODO: check for valid symbol. Otherwise program will crash File.open(new_filename, "w+") { |f| f.puts grp1 + method_def + "\n\nend # class\n\nif $0 == __FILE__" + grp3 } @patterns.push( [@new_regexp, @new_symbol] ) save_synonyms puts "#{method_def}" MyAgent.class_eval(method_def) end # If this file has a '.' + a number before the '.rb' extension # (i.e. foo.0.rb), increment the number (i.e. return foo.1.rb). # Otherwise return the name of this file unchanged. def get_new_filename old_filename = __FILE__ if old_filename =~ /(.*)\.(\d+)\.rb$/ incr = $2.to_i + 1 return new_filename = $1.to_s + "." + incr.to_s + ".rb" end return old_filename # Dangerous! end # Match input against each regexp pattern in @patterns; # if there's a match, call the method associated with the pattern. def getResponse input r = "Default response." #puts "input==#{input}" @patterns.each { |pattern| if input =~ pattern[0] return [self.send(pattern[1], pattern[0], input), 2] rescue return r end } return r end def load_synonyms(pattern=nil, input=nil) if File.exist?(@filename) @patterns = YAML.load_file(@filename) return "I have loaded #{@filename}." end return false end def save_synonyms(pattern=nil, input=nil) r = "Eep! error saving synonyms! " begin File.open(@filename, 'w') do |out| YAML.dump(@patterns, out) end return "Okay I have saved the synonyms to disk." rescue => error return r << error end end def add_synonym(pattern, input) return "Problem matching pattern." unless input =~ pattern grp1 = %r{(?i-mx:^#{$1})} grp2 = %r{(?i-mx:^#{$2})} method ='' @patterns.each { |p| #puts "p[0]==#{p[0]}; p[0].class==#{p[0].class}; grp2==#{grp2}; grp2.class==#{grp2.class}" if p[0].to_s == grp2.to_s method = p[1] break end } return unless method.to_s != nil @patterns.push( [grp1, method] ) save_synonyms return "Okay, #{grp1} has been added, and will now call #{method}." end def add_pattern(pattern=nil, input=nil) if input =~ pattern @new_regexp = $1 @new_symbol = $2 @new_regexp.gsub!(/\//, '') new_re = %r{#{@new_regexp}} # Make the regexp case insensitive. new_re_s = new_re.to_s if new_re_s =~ /(-mix)/ new_re_s = $~.pre_match << "i-mx" << $~.post_match end @new_regexp = %r{#{new_re_s}} #puts "@new_regexp==#{@new_regexp}" method_def = " def #{@new_symbol}(pattern=nil, input=nil)\n return \"#\{input} doesn't match #\{pattern}\" unless input =~ pattern\n return 'Default response from " + @new_symbol + "'\n end # method_def" begin return def_method(method_def) rescue => error return "Can't define method: #{error}." end else return "#{input} doesn't match #{pattern}." end end def defining_method(pattern=nil, input=nil) if input =~ pattern @method_def << "\n " << $1.to_s if @method_def =~ /end # method_def/ return def_method(@method_def) end return '' else return "#{input} doesn't match #{pattern}." end end def method_missing input, *rest return getResponse(input.to_s) end # Strips delimiters. def process str str.strip! str.sub!(/\?$/, '') str.sub!(/^\[/, '') str.sub!(/\]$/, '') str.sub!(/^(?:"|')/, '') str.sub!(/(?:"|')$/, '') str.sub!(/\.$/, '') str.sub!(/;$/, '') str.sub!(/,$/, '') str.sub!(/!$/, '') str.sub!(/\?$/, '') return str end def restart(pattern=nil,input=nil) exec "ruby #{__FILE__}" end # method_def def make_opposite(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 if grp1 =~ / not / then return grp1.sub(/ not /, ' ') end if grp1 =~ / = / then return grp1.sub(/ = /, ' != ') end start_monty np = ''; vp = '' begin np = @monty.send("subject: #{grp1}") vp = @monty.send("verb: #{grp1}") rescue => error puts "error: #{error}" @monty_started = false #return "Can't contact Monty, try again..." puts "Can't contact Monty, try again..." end rest = '' if vp =~ /I don't know/ vp = '' if grp1 =~ /#{np}(.*)/ then rest = $1 end else if grp1 =~ /#{vp}(.*)/ then rest = $1 end end # if np =~ /I don't know/ ??? @opposite_rules.each { |rule| # TODO: security checks, catch errors eval rule } # puts "1. np==#{np}; vp==#{vp}; rest==#{rest}" # when vp is more than one verb vparray = vp.split if vparray.size > 1 return "#{np} #{vparray[0]} not #{vparray[1..-1].join(' ')}#{rest}" end if isPlural?(np) return np << " do not " << vp << rest end if vp[-1].chr == 's' then vp.chop! end if vp == "doe" then vp = "do" end if vp == "ha" then vp = "have" end # puts "2. np==#{np}; vp==#{vp}; rest==#{rest}" return np << " does not " << vp << rest end # method_def def add_opposite_rule(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 if grp1 !~ /if.*(?:np|vp)/ then return "Can't add rule." end @opposite_rules.push(grp1) return "Okay" end # method_def def delete_opposite_rule(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern return 'Default response from delete_opposite_rule' end # method_def def show_opposite_rules(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern if @opposite_rules.size == 0 then return "There are no rules." end return @opposite_rules.join("\n") end # method_def def delete_all_opposite_rules(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern size = @opposite_rules.size if size == 0 then return "No rules to delete." end @opposite_rules.clear s = "s"; if size == 1 then s = ''; end return "Okay I have deleted #{size} opposite rule#{s}." end # method_def def add_to_plurals(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 @plurals.push(grp1) return "Okay, I have added #{grp1} as a plural form." end # method_def def add_to_singulars(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern grp1 = process $1 @singulars.push(grp1) return "Okay, I have added #{grp1} as a singular form." end # method_def def show_singulars(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern return @singulars.join(' | ') end # method_def def show_plurals(pattern=nil, input=nil) return "#{input} doesn't match #{pattern}" unless input =~ pattern return @plurals.join(' | ') end # method_def end # class if $0 == __FILE__ bot = MyAgent.new print "\n> "; $stdout.flush while (line = gets) !~ /^#{$Quitwords.join('|')}$/i and line !~ /^$/ response = bot.send(line.to_s).to_s if response.class == "Array" then response = response[0] end response = response.chop # remove the score puts response + "\n\n" print "> "; $stdout.flush end puts "Bye" end # of file