Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 0c7406a498b9ceb3ade260f67663f970fccd5be8 0 parents
@robertjwhitney authored
17 .gitignore
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
4 Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in programr.gemspec
+gemspec
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Robert Whitney
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62 README.md
@@ -0,0 +1,62 @@
+# Programr
+
+### Aside:
+
+This is just a simple port of http://aiml-programr.rubyforge.org/ authored in 2007, to something
+a tiny bit more usable. No new code really, I just sorta took the necessary parts to turn it into a gem for curiosities sake.
+
+AIML itself seems pretty simple, and weak as far as pattern matching goes, but the ALICE bot has won the Loebner prize, so there's that.
+
+### About:
+
+ProgramR is a Ruby implementation of an interpreter for the Artificial Intelligence Markup Language (AIML) based on the work of Dr. Wallace and defined by the Alicebot and AIML Architecture Committee of the A.L.I.C.E. AI Foundation http://alicebot.org
+
+### Authors
+
+Mauro Cicio, Nicholas H.Tollervey and Ben Minton
+
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'programr'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install programr
+
+## Usage
+
+ require 'bundler'
+ Bundler.setup :default
+
+ require 'programr'
+
+ if ARGV.empty?
+ puts 'Please pass a list of AIMLs and/or directories as parameters'
+ puts 'Usage: programR {aimlfile|dir}[{aimlfile|dir}]...'
+ exit
+ end
+
+ robot = ProgramR::Facade.new
+ robot.learn(ARGV)
+
+ while true
+ print '>> '
+ s = STDIN.gets.chomp
+ reaction = robot.get_reaction(s)
+ STDOUT.puts "<< #{reaction}"
+ end
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
2  Rakefile
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
37 conf/readOnlyTags.yaml
@@ -0,0 +1,37 @@
+---
+ 'bot_name': 'infobot'
+ 'bot_location': 'vancouver'
+ 'bot_gender': 'male'
+ 'bot_birthday': 'December 19, 2008'
+ 'bot_master': 'infil00p'
+ 'bot_birthplace': 'vancouver'
+ 'bot_boyfriend': 'no'
+ 'bot_favoritefood': 'mathematics'
+ 'bot_favoritemovie': 'Wargames'
+ 'bot_favoriteband': 'Flight of the Conchords'
+ 'bot_favoritebook': 'I, Robot'
+ 'bot_favoritecolor': 'red'
+ 'bot_favoritesong': 'The Humans are Dead'
+ 'bot_friends': 'alice'
+ 'bot_girlfriend': 'no'
+ 'bot_wear': 'casual'
+ 'bot_sign': 'none'
+ 'bot_looklike': 'handsome'
+ 'bot_music': 'rock'
+ 'bot_talkabout': 'science'
+ 'for_fun': 'read'
+ 'getversion': '01'
+ 'getsize': '0'
+ 'question':
+ - "are you never tired to do the same things every day?"
+ - "Say something nice to me"
+ 'name': "client"
+ 'topic': 'general'
+ 'ip': 'localhost'
+ 'it': 'it'
+ 'they': 'they'
+ 'we': 'we'
+ 'gender': 'male'
+ 'location': 'canada'
+ 'age': '40'
+ 'has': 'nothing'
5 lib/programr.rb
@@ -0,0 +1,5 @@
+require "programr/version"
+require 'programr/facade'
+
+module Programr
+end
352 lib/programr/aiml_elements.rb
@@ -0,0 +1,352 @@
+require 'programr/environment'
+
+module ProgramR
+
+class Category
+ attr_accessor :template, :that, :topic
+
+ @@cardinality = 0
+ def initialize
+ @@cardinality += 1
+ @pattern = []
+ @that = []
+ end
+
+ def Category.cardinality; @@cardinality end
+
+ def add_pattern(anObj)
+ @pattern.push(anObj)
+ end
+
+ def add_that(anObj)
+ @that.push(anObj)
+ end
+
+ def get_pattern
+ res = ''
+ @pattern.each{|tocken|
+ res += tocken.to_s
+ }
+ return res.split(/\s+/)
+ end
+
+ def get_that
+ res = ''
+ @that.each{|tocken|
+ res += tocken.to_s
+ }
+ return res.split(/\s+/)
+ end
+end
+
+class Template
+ attr_accessor :value
+
+ def initialize() @value = [] end
+ def add(anObj) @value << anObj end
+ def append(aString)
+ @value << aString.gsub(/\s+/, ' ')
+ end
+
+ def inspect
+ res = ''
+ @value.each{|tocken| res += tocken.inspect }
+ res
+ end
+end
+
+class Random
+ @@environment = Environment.new
+
+ def initialize; @conditions = [] end
+ def setListElement(someAttributes)
+ @conditions.push([])
+ end
+
+ def add(aBody)
+ @conditions[-1].push(aBody)
+ end
+
+ def execute
+ res = ''
+ @@environment.getRandom(@conditions).each{|tocken|
+ res += tocken.to_s
+ }
+ return res.strip
+ end
+ alias to_s execute
+ def inspect(); "random -> #{execute}" end
+end
+
+class Condition
+ #se c'e' * nel value?
+ @@environment = Environment.new
+
+ def initialize(someAttributes)
+ @conditions = {}
+ @property = someAttributes['name']
+ @currentCondition = someAttributes['value'].sub('*','.*')
+ end
+
+ def add(aBody)
+ unless @conditions[@currentCondition]
+ @conditions[@currentCondition] = []
+ end
+ @conditions[@currentCondition].push(aBody)
+ end
+
+ def setListElement(someAttributes)
+ @property = someAttributes['name'] if(someAttributes.key?('name'))
+ @currentCondition = '_default'
+ if(someAttributes.key?('value'))
+ @currentCondition = someAttributes['value'].sub('*','.*')
+ end
+ end
+
+ def execute
+ return '' unless(@@environment.get(@property) =~ /^#{@currentCondition}$/)
+ res = ''
+ @conditions[@currentCondition].each{|tocken|
+ res += tocken.to_s
+ }
+ return res.strip
+ end
+ alias to_s execute
+ def inspect()
+ "condition -> #{execute}"
+ end
+end
+
+class ListCondition < Condition
+ def initialize(someAttributes)
+ @conditions = {}
+ @property = someAttributes['name'] if(someAttributes.key?('name'))
+ end
+
+ def execute
+ @conditions.keys.each do |key|
+ if(@@environment.get(@property) == key)
+ res = ''
+ @conditions[key].each{|tocken|
+ res += tocken.to_s
+ }
+ return res.strip
+ end
+ end
+ return ''
+ end
+ alias to_s execute
+end
+
+class SetTag
+ @@environment = Environment.new
+
+ def initialize(aLocalname,attributes)
+ if(attributes.empty?)
+ @localname = aLocalname.sub(/^set_/,'')
+ else
+ @localname = attributes['name']
+ end
+ @value = []
+ end
+
+ def add(aBody)
+ @value.push(aBody)
+ end
+
+ def execute
+ res = ''
+ @value.each{|tocken|
+ res += tocken.to_s
+ }
+ @@environment.set(@localname,res.strip)
+ end
+ alias to_s execute
+ def inspect(); "set tag #{@localname} -> #{execute}" end
+end
+
+class Input
+ @@environment = Environment.new
+
+ def initialize(someAttributes)
+ @index = 1
+ @index = someAttributes['index'].to_i if(someAttributes.key?('index'))
+ end
+
+ def execute
+ @@environment.getStimula(@index)
+ end
+ alias to_s execute
+ def inspect(); "input -> #{@@environment.getStimula(@index)}" end
+end
+
+class Star
+ @@environment = Environment.new
+
+ def initialize(aStarName,someAttributes)
+ @star = aStarName
+ @index = 0
+ @index = someAttributes['index'].to_i-1 unless(someAttributes.empty?)
+ end
+
+ def execute
+ @@environment.send(@star,@index)
+ end
+ alias to_s execute
+ def inspect()
+ return "#{@star} #{@index} -> #{@@environment.send(@star,@index)}"
+ end
+end
+
+class ReadOnlyTag
+ @@environment = Environment.new
+
+ def initialize(aLocalname,someAttributes)
+ @localname = aLocalname.sub(/^get_/,'')
+ if(someAttributes.key?('index') && @localname == 'that')
+ @localname = 'justbeforethat' if someAttributes['index'] == '2,1'
+ someAttributes = {}
+ end
+ @attributed = someAttributes
+ end
+
+ def execute
+ return @@environment.get(@localname) if(@attributed.empty?)
+ @@environment.get(@attributed['name'])
+ end
+ alias to_s execute
+ def inspect()
+ return "roTag #{@localname} -> #{execute}"
+ end
+end
+
+class Think
+ def initialize(aStatus); @status = aStatus end
+
+ def execute; @status end
+ alias to_s execute
+ def inspect(); "think status -> #{@status}" end
+end
+
+class Size
+ def execute; Category.cardinality.to_s end
+ alias to_s execute
+ def inspect(); "size -> #{Category.cardinality.to_s}" end
+end
+
+class Sys_Date
+ def execute; Date.today.to_s end
+ alias to_s execute
+ def inspect(); "date -> #{Date.today.to_s}" end
+end
+
+class Srai
+def initialize(anObj=nil)
+ @pattern = []
+ @pattern.push(anObj) if(anObj)
+end
+def add(anObj); @pattern.push(anObj) end
+def pattern
+ res = ''
+ @pattern.each{|tocken|
+ res += tocken.to_s
+ }
+ return res.strip
+end
+ def inspect(); "srai -> #{pattern}" end
+end
+
+class Person2
+ @@environment = Environment.new
+ @@swap = {'me' => 'you', 'you' => 'me'}
+ def initialize; @sentence = [] end
+ def add(anObj); @sentence.push(anObj) end
+ def execute
+ res = ''
+ @sentence.each{|tocken|
+ res += tocken.to_s
+ }
+ gender = @@environment.get('gender')
+ res.gsub(/\b((with|to|of|for|give|gave|giving) (you|me)|you|i)\b/i){
+ if($3)
+ $2.downcase+' '+@@swap[$3.downcase]
+ elsif($1.downcase == 'you')
+ 'i'
+ elsif($1.downcase == 'i')
+ 'you'
+ end
+ }
+ end
+ alias to_s execute
+ def inspect(); "person2 -> #{execute}" end
+end
+
+class Person
+ @@environment = Environment.new
+ @@swap = {'male' => {'me' => 'him',
+ 'my' => 'his',
+ 'myself' => 'himself',
+ 'mine' => 'his',
+ 'i' => 'he',
+ 'he' => 'i',
+ 'she' => 'i'},
+ 'female' => {'me' => 'her',
+ 'my' => 'her',
+ 'myself' => 'herself',
+ 'mine' => 'hers',
+ 'i' => 'she',
+ 'he' => 'i',
+ 'she' => 'i'}}
+
+ def initialize; @sentence = [] end
+ def add(anObj); @sentence.push(anObj) end
+ def execute
+ res = ''
+ @sentence.each{|tocken|
+ res += tocken.to_s
+ }
+ gender = @@environment.get('gender')
+ res.gsub(/\b(she|he|i|me|my|myself|mine)\b/i){
+ @@swap[gender][$1.downcase]
+ }
+ end
+ alias to_s execute
+ def inspect(); "person-> #{execute}" end
+end
+
+class Gender
+ def initialize; @sentence = [] end
+ def add(anObj); @sentence.push(anObj) end
+ def execute
+ res = ''
+ @sentence.each{|tocken|
+ res += tocken.to_s
+ }
+ res.gsub(/\b(she|he|him|his|(for|with|on|in|to) her|her)\b/i){
+
+ pronoun = $1.downcase
+ if(pronoun == 'she')
+ 'he'
+ elsif(pronoun == 'he')
+ 'she'
+ elsif(pronoun == 'him' || pronoun == 'his')
+ 'her'
+ elsif(pronoun == 'her')
+ 'his'
+ else
+ $2.downcase + ' ' + 'him'
+ end
+ }
+ end
+ alias to_s execute
+ def inspect(); "gender -> #{execute}" end
+end
+
+class Command
+ def initialize(text) @command = text end
+ def execute; `#{@command}` end
+ alias to_s execute
+ def inspect() "cmd -> #{@command}" end
+end
+
+end #ProgramR
269 lib/programr/aiml_parser.rb
@@ -0,0 +1,269 @@
+require 'rexml/parsers/sax2parser'
+require 'programr/aiml_elements'
+
+# gli accenti nel file di input vengono trasformati in &apos; !!!
+#
+module ProgramR
+class AimlParser
+ def initialize(learner); @learner = learner end
+
+ def parse(aiml)
+ @parser = REXML::Parsers::SAX2Parser.new(aiml)
+ category = nil
+ openLabels = []
+ patternIsOpen = false
+ thatIsOpen = false
+ currentSetLabel = nil
+ currentCondition = nil
+ currentSrai = nil
+ currentGender = nil
+ currentPerson = nil
+ currentPerson2 = nil
+ currentTopic = nil
+
+ @parser.listen(%w{ category }){|uri,localname,qname,attributes|
+ category = Category.new
+ category.topic = currentTopic if(currentTopic)
+ }
+
+ @parser.listen(['topicstar','thatstar','star']){|u,localname,qn,attributes|
+ openLabels[-1].add(Star.new(localname,attributes))
+ }
+
+### condition -- random
+ @parser.listen(%w{ condition }){|uri,localname,qname,attributes|
+ if(attributes.key?('value'))
+ currentCondition = Condition.new(attributes)
+ else
+ currentCondition = ListCondition.new(attributes)
+ end
+ openLabels[-1].add(currentCondition)
+ openLabels.push(currentCondition)
+ }
+
+ @parser.listen(%w{ random }){|uri,localname,qname,attributes|
+ currentCondition = Random.new
+ openLabels[-1].add(currentCondition)
+ openLabels.push(currentCondition)
+ }
+
+ @parser.listen(:characters, %w{ condition }){|text|
+ next if(text =~ /^\s+$/)
+ currentCondition.add(text)
+ }
+
+ @parser.listen(%w{ li }){|uri,localname,qname,attributes|
+ next unless currentCondition
+ currentCondition.setListElement(attributes)
+ }
+
+ @parser.listen(:characters,%w{ li }){|text|
+ next unless currentCondition
+ currentCondition.add(text)
+ }
+
+ @parser.listen(:end_element, ['condition','random']){
+ currentCondition = nil
+ openLabels.pop
+ }
+### end condition -- random
+
+ @parser.listen([/^get.*/,/^bot_*/,'for_fun',/that$/, 'question']){
+ |uri,localname,qname,attributes|
+ unless(openLabels.empty?)
+ openLabels[-1].add(ReadOnlyTag.new(localname, attributes))
+ end
+ }
+
+ @parser.listen(['bot','name']){|uri,localname,qname,attributes|
+ if(localname == 'bot')
+ localname = 'bot_'+attributes['name']
+ else
+ localname = 'bot_name'
+ end
+ if(patternIsOpen)
+ category.add_pattern(ReadOnlyTag.new(localname, {}))
+ elsif(thatIsOpen)
+ category.add_that(ReadOnlyTag.new(localname, {}))
+ else
+ openLabels[-1].add(ReadOnlyTag.new(localname, {}))
+ end
+ }
+
+### set
+ @parser.listen([/^set_*/,'set']){|uri,localname,qname,attributes|
+ setObj = SetTag.new(localname,attributes)
+ openLabels[-1].add(setObj)
+ openLabels.push(setObj)
+ }
+
+ @parser.listen(:characters,[/^set_*/]){|text|
+ openLabels[-1].add(text)
+ }
+
+ @parser.listen(:end_element, [/^set_*/,'set']){
+ openLabels.pop
+ }
+### end set
+
+### pattern
+ @parser.listen(%w{ pattern }){patternIsOpen = true}
+ @parser.listen(:characters,%w{ pattern }){|text|
+ #TODO verify if case insensitive. Cross check with facade
+ category.add_pattern(text.upcase)
+ }
+ @parser.listen(:end_element, %w{ pattern }){patternIsOpen = false}
+#end pattern
+
+#### that
+ @parser.listen(%w{ that }){thatIsOpen = true}
+ @parser.listen(:characters,%w{ that }){|text| category.add_that(text)}
+ @parser.listen(:end_element, %w{ that }){thatIsOpen = false}
+### end that
+
+### template
+ @parser.listen(%w{ template }){
+ category.template = Template.new
+ openLabels.push(category.template)
+ }
+
+ @parser.listen(:characters, %w{ template }){|text|
+ category.template.append(text)
+ }
+
+ @parser.listen(:end_element, %w{ template }){
+ openLabels.pop
+ }
+### end template
+
+ @parser.listen(%w{ input }){|uri,localname,qname,attributes|
+ category.template.add(Input.new(attributes))
+ }
+
+### think
+ @parser.listen(:start_element, %w{ think }){
+ openLabels[-1].add(Think.new('start'))
+ }
+
+ @parser.listen(:end_element, %w{ think }){
+ openLabels[-1].add(Think.new('end'))
+ }
+###end think
+
+ @parser.listen(:characters, %w{ uppercase }){|text|
+ openLabels[-1].add(text.upcase.gsub(/\s+/, ' '))
+ }
+
+ @parser.listen(:characters, %w{ lowercase }){|text|
+ openLabels[-1].add(text.downcase.gsub(/\s+/, ' '))
+ }
+
+ @parser.listen(:characters, %w{ formal }){|text|
+ text.gsub!(/(\w+)/){$1.capitalize}
+ openLabels[-1].add(text.gsub(/\s+/, ' '))
+ }
+
+ @parser.listen(:characters, %w{ sentence }){|text|
+ openLabels[-1].add(text.capitalize.gsub(/\s+/, ' '))
+ }
+
+ @parser.listen(%w{ date }){
+ openLabels[-1].add(Sys_Date.new)
+ }
+
+ @parser.listen(:characters, %w{ system }){|text|
+ openLabels[-1].add(Command.new(text))
+ }
+
+ @parser.listen(%w{ size }){
+ openLabels[-1].add(Size.new)
+ }
+
+ @parser.listen(%w{ sr }){|uri,localname,qname,attributes|
+ openLabels[-1].add(Srai.new(Star.new('star',{})))
+ }
+### srai
+ @parser.listen(%w{ srai }){|uri,localname,qname,attributes|
+ currentSrai = Srai.new
+ openLabels[-1].add(currentSrai)
+ openLabels.push(currentSrai)
+ }
+
+ @parser.listen(:characters, %w{ srai }){|text|
+ currentSrai = Srai.new
+ currentSrai.add(text)
+ }
+
+ @parser.listen(:end_element, %w{ srai }){
+ currentSrai = nil
+ openLabels.pop
+ }
+### end srai
+
+### gender
+ @parser.listen(%w{ gender }){|uri,localname,qname,attributes|
+ currentGender = Gender.new
+ openLabels[-1].add(currentGender)
+ openLabels.push(currentGender)
+ }
+
+ @parser.listen(:characters, %w{ gender }){|text|
+ currentGender.add(text)
+ }
+
+ @parser.listen(:end_element, %w{ gender }){
+ currentGender = nil
+ openLabels.pop
+ }
+### end gender
+
+### person
+ @parser.listen(%w{ person }){|uri,localname,qname,attributes|
+ currentPerson = Person.new
+ openLabels[-1].add(currentPerson)
+ openLabels.push(currentPerson)
+ }
+
+ @parser.listen(:characters, %w{ person }){|text|
+ currentPerson.add(text)
+ }
+
+ @parser.listen(:end_element, %w{ person }){
+ currentPerson = nil
+ openLabels.pop
+ }
+### end person
+
+### person2
+ @parser.listen(%w{ person2 }){|uri,localname,qname,attributes|
+ currentPerson2 = Person2.new
+ openLabels[-1].add(currentPerson2)
+ openLabels.push(currentPerson2)
+ }
+
+ @parser.listen(:characters, %w{ person2 }){|text|
+ currentPerson2.add(text)
+ }
+
+ @parser.listen(:end_element, %w{ person2 }){
+ currentPerson2 = nil
+ openLabels.pop
+ }
+### end perso2
+
+ @parser.listen(:end_element, %w{ category }){ @learner.learn(category) }
+
+### topic
+ @parser.listen(%w{ topic }){|uri,localname,qname,attributes|
+ currentTopic = attributes['name']
+ }
+
+ @parser.listen(:end_element, %w{ topic }){
+ currentTopic = nil
+ }
+### end topic
+
+ @parser.parse
+ end
+end #Aiml@parser
+end
75 lib/programr/environment.rb
@@ -0,0 +1,75 @@
+require 'yaml'
+require 'programr/history'
+
+module ProgramR
+class Environment
+ @@readOnlyTags = nil
+ @@history = nil
+
+ def initialize
+ return self unless(@@readOnlyTags == nil)
+ @@readOnlyTags = YAML::load(
+ File.open(
+ File.dirname(__FILE__) +
+ "/../../conf/readOnlyTags.yaml"))
+ @@history = History.new
+ srand(1)
+ end
+
+ def get(aTag)
+ send(aTag)
+ end
+
+ def set(aTag,aValue)
+ @@history.updateTopic(aValue) if(aTag == 'topic')
+ @@readOnlyTags[aTag] = aValue
+ end
+
+ def method_missing(methId)
+ tag = methId.id2name
+ return @@history.send(tag) if(tag =~ /that$/)
+ return @@readOnlyTags[tag] if(@@readOnlyTags.key?(tag))
+ ''
+ end
+
+ def test
+ #should overwrite test ....
+ return @@readOnlyTags[tag] if(@@readOnlyTags.key?(tag))
+ ''
+ end
+
+ def star(anIndex)
+ @@history.getStar(anIndex)
+ end
+
+ def thatstar(anIndex)
+ @@history.getThatStar(anIndex)
+ end
+
+ def topicstar(anIndex)
+ @@history.getTopicStar(anIndex)
+ end
+
+ def male
+ @@readOnlyTags['gender'] = 'male'
+ return 'male'
+ end
+
+ def female
+ @@readOnlyTags['gender'] = 'female'
+ return 'female'
+ end
+
+ def question
+ @@readOnlyTags['question'][rand(@@readOnlyTags['question'].length-1)]
+ end
+
+ def getRandom(anArrayofChoices)
+ anArrayofChoices[rand(anArrayofChoices.length-1)]
+ end
+
+ def getStimula(anIndex)
+ @@history.getStimula(anIndex)
+ end
+end
+end
65 lib/programr/facade.rb
@@ -0,0 +1,65 @@
+require 'programr/graph_master'
+require 'programr/aiml_parser'
+require 'programr/history'
+require 'programr/utils'
+
+module ProgramR
+class Facade
+ def initialize(cache = nil)
+ @graph_master = GraphMaster.new
+ @parser = AimlParser.new(@graph_master)
+ @history = History.new
+ end
+
+ def learn(files)
+ AimlFinder::find(files).each{|f| File.open(f,'r'){|f| @parser.parse f} }
+ end
+
+ def loading(theCacheFilename='cache')
+ cache = Cache::loading(theCacheFilename)
+ @graph_master = cache if cache
+ end
+
+ def merging(theCacheFilename='cache')
+ cache = Cache::loading(theCacheFilename)
+ @graph_master.merge(cache) if cache
+ end
+
+ def dumping(theCacheFilename='cache')
+ Cache::dumping(theCacheFilename,@graph_master)
+ end
+
+ def get_reaction(stimula,firstStimula=true)
+ starGreedy = []
+#TODO verify if case insensitive. Cross check with parser
+ #@history.updateStimula(stimula.upcase) if(firstStimula)
+@history.updateStimula(stimula.upcase) if(firstStimula)
+ thinkIsActive = false
+reaction = @graph_master.get_reaction(stimula.upcase, @history.that,
+ @history.topic,starGreedy)
+ @history.updateStarMatches(starGreedy)
+ res = ''
+ reaction.each{|tocken|
+ if(tocken.class == Srai)
+ tocken = get_reaction(tocken.pattern,false)
+ @history.updateStarMatches(starGreedy)
+ end
+ if tocken.class == Think
+ thinkIsActive = ! thinkIsActive
+ next
+ end
+ value = tocken.to_s
+ res += value unless(thinkIsActive)
+ }
+ #TODO verify if case insensitive. Cross check with main program & parser
+ @history.updateResponse(res.strip.upcase) if(firstStimula)
+ return res.strip
+ end
+
+ def to_s
+ @graph_master.to_s
+ end
+
+ # def getBotName()end
+end
+end
110 lib/programr/graph_master.rb
@@ -0,0 +1,110 @@
+require 'programr/aiml_elements'
+
+module ProgramR
+THAT = '<that>'
+TOPIC = '<topic>'
+class GraphMaster
+ attr_reader :graph
+ def initialize
+ @graph = Node.new
+ end
+
+ def merge(aCache)
+ @graph.merge(aCache.graph)
+ end
+
+ def learn(category)
+ path = category.get_pattern
+ path += [THAT] + category.get_that unless (category.get_that).empty?
+ path += [TOPIC] + category.topic.split(/\s+/) if category.topic
+ @graph.learn(category, path)
+ end
+
+ def to_s
+ @graph.inspectNode()
+ end
+
+ def get_reaction(stimula, last_said,cur_topic,starGreedy)
+ path = "#{stimula} #{THAT} #{last_said} #{TOPIC} #{cur_topic}"
+ template = @graph.get_template(path.split(/\s+/),starGreedy)
+ return template.value unless(template == nil)
+ return []
+ end
+end
+
+class Node
+ attr_reader :children
+ def initialize
+ @template = nil
+ @children = {}
+ end
+
+ def merge(aCache)
+ aCache.children.keys.each do |key|
+ if(@children.key?(key))
+ @children[key].merge(aCache.children[key])
+ next
+ end
+ @children[key] = aCache.children[key]
+ end
+ end
+
+ def learn(category, path)
+ branch = path.shift
+ return @template = category.template unless branch
+ @children[branch] = Node.new unless @children[branch]
+ @children[branch].learn(category, path)
+ end
+
+ def get_template(pattern,starGreedy,isGreedy=false)
+ currentTemplate = nil
+ gotValue = nil
+ curGreedy = []
+ if(@template)
+ if(isGreedy)
+ starGreedy.push(pattern.shift) until(pattern.empty?||pattern[0]==THAT ||
+ pattern[0] == TOPIC)
+ end
+ return @template if(pattern.empty?)
+ currentTemplate = @template if(pattern[0] == THAT || pattern[0] == TOPIC)
+ end
+ branch = pattern.shift
+ isGreedy = false if(branch == THAT || branch == TOPIC)
+ unless(branch != THAT || @children.key?(THAT))
+ branch = pattern.shift until (branch == nil or branch == TOPIC)
+ end
+ return nil unless(branch)
+ if(@children[branch])
+ gotValue = @children[branch].get_template(pattern.clone,curGreedy)
+ elsif(isGreedy)
+ curGreedy.push(branch)
+ gotValue = get_template(pattern.clone,curGreedy,true)
+ end
+ if(gotValue)
+ starGreedy.push(branch) if(branch == THAT || branch == TOPIC)
+ starGreedy.concat(curGreedy)
+ return gotValue
+ end
+ return currentTemplate if currentTemplate
+ ["_","*"].each do |star|
+ next unless(@children.key?(star))
+ next unless(gotValue=@children[star].get_template(pattern.clone,
+ curGreedy,true))
+starGreedy.push(branch) if(branch == THAT || branch == TOPIC)
+ starGreedy.concat(['<newMatch>',branch].concat(curGreedy))
+ return gotValue
+ end
+ return nil
+ end
+
+ def inspectNode(nodeId = nil, ind = 0)
+ str = ''
+ str += '| '*(ind - 1) + "|_#{nodeId}" unless ind == 0
+ str += ": [#{@template.inspect}]" if @template
+ str += "\n" unless ind == 0
+ @children.each_key{|c| str += @children[c].inspectNode(c, ind+1)}
+ str
+ end
+end
+
+end #ProgramR
82 lib/programr/history.rb
@@ -0,0 +1,82 @@
+module ProgramR
+class History
+ @@topic = 'default'
+ @@inputs = []
+ @@responses = []
+ @@starGreedy = []
+ @@thatGreedy = []
+ @@topicGreedy = []
+
+ def topic; @@topic end
+
+ def that
+ return 'undef' unless @@responses[0]
+ @@responses[0]
+ end
+
+ def justbeforethat
+ return 'undef' unless @@responses[1]
+ @@responses[1]
+ end
+
+ def justthat
+ return 'undef' unless @@inputs[0]
+ @@inputs[0]
+ end
+
+ def beforethat
+ return 'undef' unless @@inputs[1]
+ @@inputs[1]
+ end
+
+ def getStar(anIndex)
+ return 'undef' unless @@starGreedy[anIndex]
+ @@starGreedy[anIndex].join(' ')
+ end
+
+ def getThatStar(anIndex)
+ return 'undef' unless @@thatGreedy[anIndex]
+ @@thatGreedy[anIndex].join(' ')
+ end
+
+ def getTopicStar(anIndex)
+ return 'undef' unless @@topicGreedy[anIndex]
+ @@topicGreedy[anIndex].join(' ')
+ end
+
+ def updateTopic(aTopic)
+ @@topic = aTopic
+ end
+
+ def updateResponse(aResponse)
+ @@responses.unshift(aResponse)
+ end
+
+ def updateStimula(aStimula)
+ @@inputs.unshift(aStimula)
+ end
+
+ def getStimula(anIndex)
+ @@inputs[anIndex]
+ end
+
+ def updateStarMatches(aStarGreedyArray)
+ @@starGreedy = []
+ @@thatGreedy = []
+ @@topicGreedy = []
+ currentGreedy = @@starGreedy
+ aStarGreedyArray.each do |greedy|
+ if(greedy == '<that>')
+ currentGreedy = @@thatGreedy
+ elsif(greedy == '<topic>')
+ currentGreedy = @@topicGreedy
+ elsif(greedy == '<newMatch>')
+ currentGreedy.push([])
+ else
+ currentGreedy[-1].push(greedy)
+ end
+ end
+ end
+end
+end
+
30 lib/programr/utils.rb
@@ -0,0 +1,30 @@
+module ProgramR
+ module Cache
+ def self.dumping(aFilename,theGraphMaster)
+ File.open(aFilename,'w') do |file|
+ file.write(Marshal.dump(theGraphMaster,-1))
+ end
+ end
+
+ def self.loading(aFilename)
+ File.open(aFilename,'r') do |file|
+ return Marshal.load(file.read)
+ end rescue nil
+ end
+ end # module Cache
+
+ module AimlFinder
+ # Returns an array of aiml files recursively found
+ def self.find(files_and_dirs)
+ files = []
+ files_and_dirs.each{|file|
+ if File.file?(file) && (file =~ /.*\.aiml$/)
+ files << file
+ next
+ end
+ files += find(Dir.glob("#{file}/*"))
+ }
+ files
+ end
+ end
+end #module ProgramR
3  lib/programr/version.rb
@@ -0,0 +1,3 @@
+module Programr
+ VERSION = "0.0.1"
+end
17 programr.gemspec
@@ -0,0 +1,17 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/programr/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Mauro Cicio, Nicholas H.Tollervey, Ben Minton and Robert J Whitney"]
+ gem.email = ["robertj.whitney@gmail.com"]
+ gem.description = %q{Ruby interpreter for the AIML}
+ gem.summary = %q{ProgramR is a Ruby implementation of an interpreter for the Artificial Intelligence Markup Language (AIML) based on the work of Dr. Wallace and defined by the Alicebot and AIML Architecture Committee of the A.L.I.C.E. AI Foundation (http://alicebot.org}
+ gem.homepage = "http://aiml-programr.rubyforge.org/"
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "programr"
+ gem.require_paths = ["lib"]
+ gem.version = Programr::VERSION
+end
125 test/data/1.aiml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+<!-- Free software (c) 2001 ALICE A.I. Foundation. -->
+<!-- This program is open source code released under -->
+<!-- the terms of the GNU General Public License -->
+<!-- as published by the Free Software Foundation. -->
+<!-- Complies with AIML 1.0 Tag Set Specification -->
+<!-- as adopted by the ALICE A.I. Foundation. -->
+<!-- A.L.I.C.E. Build Wed Sep 26 13:05:06 PDT 2001 -->
+<!-- 41124 total categories. -->
+<category>
+<pattern>1 *</pattern>
+<template>One what?
+</template></category>
+<category>
+<pattern>1 0</pattern>
+<template>One.
+</template></category>
+<category>
+<pattern>1</pattern>
+<template>Only one?
+</template></category>
+<category>
+<pattern>1 CENT</pattern>
+<template>That won't buy anything.
+</template></category>
+<category>
+<pattern>1 DOLLAR</pattern>
+<template>You can't buy much for a dollar anymore.
+</template></category>
+<category>
+<pattern>1 OR 2</pattern>
+<template>A couple.
+</template></category>
+<category>
+<pattern>1 POINT *</pattern>
+<template>That's more precision than I need to know.
+</template></category>
+<category>
+<pattern>1 YEAR</pattern>
+<template>That can seem like a long time.
+</template></category>
+<category>
+<pattern>10 *</pattern>
+<template><srai>WHAT IS 10<star/></srai>
+</template></category>
+<category>
+<pattern>10</pattern>
+<template><srai>I AM 10 YEARS OLD</srai>
+</template></category>
+<category>
+<pattern>100 *</pattern><that>HOW MUCH *</that>
+<template>Wow that is <random>
+<li>expensive.</li>
+<li>a lot of money.</li>
+<li>more than I have.</li>
+</random>
+</template></category>
+<category>
+<pattern>100 PERSON</pattern>
+<template><srai>WHO IS 100 PERSON</srai>
+</template></category>
+<category>
+<pattern>11</pattern>
+<template><srai>I am 11 years old</srai>
+</template></category>
+<category>
+<pattern>12</pattern>
+<template><srai>I am 12 years old</srai>
+</template></category>
+<category>
+<pattern>123456789</pattern>
+<template>Ten.
+</template></category>
+<category>
+<pattern>13 *</pattern>
+<template><srai>I am 13 years old</srai>
+</template></category>
+<category>
+<pattern>13</pattern>
+<template><srai>I am 13 years old</srai>
+</template></category>
+<category>
+<pattern>14 *</pattern>
+<template><srai>I am 14 years old</srai>
+</template></category>
+<category>
+<pattern>14</pattern>
+<template><srai>I am 14 years old</srai>
+</template></category>
+<category>
+<pattern>15</pattern>
+<template><srai>I am 15 years old</srai>
+</template></category>
+<category>
+<pattern>153</pattern>
+<template>One hundred fifty three.
+</template></category>
+<category>
+<pattern>16</pattern>
+<template><srai>I am 16 years old</srai>
+</template></category>
+<category>
+<pattern>17</pattern>
+<template><srai>I am 17 years old</srai>
+</template></category>
+<category>
+<pattern>18</pattern>
+<template><srai>I AM 18 YEARS OLD</srai>
+</template></category>
+<category>
+<pattern>184</pattern>
+<template><srai>WHO IS 184 PERSON</srai>
+</template></category>
+<category>
+<pattern>19</pattern>
+<template><srai>I AM 19 YEARS OLD</srai>
+</template></category>
+<category>
+<pattern>1999</pattern>
+<template>This year.
+</template></category>
+</aiml>
233 test/data/facade.aiml
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+Client: I admire robots like you.
+ Robot: That's good information: Joe said he admire robots like me.
+
+<topic name="WORK">
+ <category>
+ <pattern>atomic test</pattern>
+ <template>new test succeded</template>
+ </category>
+</topic>
+
+ <category>
+ <pattern>yes *</pattern>
+ <template><srai>yes</srai> <sr/></template>
+ </category>
+
+ <category>
+ <pattern>yes</pattern>
+ <template>ok yes</template>
+ </category>
+
+<topic name="* GAME">
+ <category>
+ <pattern>atomic test</pattern>
+ <template>topic star test succeded <topicstar/></template>
+ </category>
+</topic>
+
+ <category>
+ <pattern>test thatstar</pattern>
+ <template>WHAT IS YOUR FAVORITE FOOTBALL TEAM</template>
+ </category>
+
+ <category>
+ <pattern>MY FAVORITE FOOTBALL TEAM IS *</pattern>
+ <template>ALSO MINE IS <star index='1'/></template>
+ </category>
+
+ <category>
+ <pattern>*</pattern> <that>WHAT IS YOUR FAVORITE *</that>
+ <template><srai>MY FAVORITE <thatstar/> IS <star/></srai></template>
+ </category>
+
+ <category>
+ <pattern>gender test 2 *</pattern>
+ <template><gender><star/></gender></template>
+ </category>
+
+ <category>
+ <pattern>test gender</pattern>
+ <template><gender>he told to her to take a hike</gender> but
+ <gender>his ego was too much for her</gender></template>
+ </category>
+
+ <category>
+ <pattern>* answers no</pattern>
+ <template><person><star/></person> answers no</template>
+ </category>
+
+ <category>
+ <pattern>you say everything ok to me</pattern>
+ <template><person2>you say everything ok to me</person2></template>
+ </category>
+
+ <category>
+ <pattern>test input</pattern>
+ <template><input/>.<input index="2"/></template>
+ </category>
+
+ <category>
+ <pattern>random test</pattern>
+ <template>
+ <random>
+ <li>A</li>
+ </random>
+ </template>
+ </category>
+
+ <category>
+ <pattern>formal test</pattern>
+ <template><formal>the formal test</formal></template>
+ </category>
+
+ <category>
+ <pattern>sentence test</pattern>
+ <template><sentence>the sentence test</sentence></template>
+ </category>
+
+ <category>
+ <pattern>I AM BLOND</pattern>
+ <template>You sound very
+ <condition name="gender" value="*emale">attractive.</condition>
+ <condition name="gender" value="male">handsome.</condition>
+ </template>
+ </category>
+
+<category>
+ <pattern>I AM RED</pattern>
+ <template>You sound very
+ <condition>
+ <li name="gender" value="female">attractive.</li>
+ <li name="gender" value="male">handsome.</li>
+ </condition>
+ </template>
+ </category>
+
+<category>
+ <pattern>I AM BLACK</pattern>
+ <template>You sound very
+ <condition name="gender">
+ <li value="female">attractive.</li>
+ <li value="male">handsome.</li>
+ </condition>
+ </template>
+ </category>
+
+ <category>
+ <pattern>test set</pattern>
+ <template><get_gender/>.<set_gender>female</set_gender>.<get_gender/></template>
+ </category>
+
+ <category>
+ <pattern>think test. i am male</pattern>
+ <template>ok.<think><get_gender/></think></template>
+ </category>
+
+ <category>
+ <pattern>question test</pattern>
+ <template><question/></template>
+ </category>
+
+ <category>
+ <pattern>get test 1</pattern>
+ <template><bot_name/></template>
+ </category>
+
+ <category>
+ <pattern>get test 2</pattern>
+ <template><get name="ip"/></template>
+ </category>
+
+ <category>
+ <pattern>justbeforethat tag test</pattern>
+ <template><that index="2,1"/></template>
+ </category>
+
+ <category>
+ <pattern>that tag test</pattern>
+ <template><that/></template>
+ </category>
+
+ <category>
+ <pattern>atomic test</pattern>
+ <template>test succeded</template>
+ </category>
+
+ <category>
+ <pattern>srai test</pattern>
+ <template><srai>atomic test</srai><think><set_topic>WORK</set_topic></think></template>
+ </category>
+
+ <category>
+ <pattern>that test</pattern>
+ <that>NEW TEST SUCCEDED</that>
+ <template>that test 1</template>
+ </category>
+
+ <category>
+ <pattern>that test</pattern>
+ <that>THAT TEST 1</that>
+ <template>that test 2<think><set_topic>OK GAME</set_topic></think></template>
+ </category>
+
+ <category>
+ <pattern>uppercase test</pattern>
+ <template>the <uppercase>uppercase</uppercase> test</template>
+ </category>
+
+ <category>
+ <pattern>LOWERCASE TEST</pattern>
+ <template>the <lowercase>LOWERCASE</lowercase> test</template>
+ </category>
+
+ <category>
+ <pattern>DATE TEST</pattern>
+ <template><date/></template>
+ </category>
+
+ <category>
+ <pattern>SYSTEM TEST</pattern>
+ <template>time:<system>date</system></template>
+ </category>
+
+ <category>
+ <pattern>SIZE TEST</pattern>
+ <template><size/></template>
+ </category>
+
+ <category>
+ <pattern>SPACE TEST</pattern>
+ <template> TEST SPACE </template>
+ </category>
+
+ <!-- next three are test for * and _ -->
+ <category>
+ <pattern>This * her</pattern>
+ <template>star wins</template>
+ </category>
+
+ <category>
+ <pattern>This _ you</pattern>
+ <template>underscore wins</template>
+ </category>
+
+ <category>
+ <pattern>This * you</pattern>
+ <template>star does not win</template>
+ </category>
+
+ <category>
+ <pattern>This is clearly you</pattern>
+ <template>explicit pattern wins</template>
+ </category>
+
+ <category>
+ <pattern>These * clearly * them</pattern>
+ <template>first star is <star index="1"/> second star is <star index="2"/></template>
+ </category>
+ <!-- end test for * and _ -->
+</aiml>
1  test/data/mixed/dir/badfile
@@ -0,0 +1 @@
+badfile
9 test/data/mixed/dir/in_dir.aiml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+ <category>
+ <pattern>in dir</pattern>
+ <template>OK</template>
+ </category>
+</aiml>
17 test/data/mixed/dir/subdir/in_sub_dir.aiml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+ <category>
+ <pattern>in sub dir</pattern>
+ <template>OK</template>
+ </category>
+ <category>
+ <pattern>in sub dir marco</pattern>
+ <template>ciao</template>
+ </category>
+ <category>
+ <pattern>in sub dir pippo</pattern>
+ <template>ciao</template>
+ </category>
+</aiml>
9 test/data/mixed/single.aiml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+ <category>
+ <pattern>single file</pattern>
+ <template>OK</template>
+ </category>
+</aiml>
44 test/data/test.aiml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<aiml version="1.0.1" xmlns="http://alicebot.org/2001/AIML-1.0.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
+ <category>
+ <pattern>1 *</pattern>
+ <template>One what? </template>
+ </category>
+
+ <category>
+ <pattern>1 0</pattern>
+ <template>One. </template>
+ </category>
+
+ <category>
+ <pattern>very long pattern is this</pattern>
+ <template>very long</template>
+ </category>
+
+ <category>
+ <pattern>very long pattern is that over there</pattern>
+ <template>very very long</template>
+ </category>
+
+ <category>
+ <pattern>DATE TEST</pattern>
+ <template><date/></template>
+ </category>
+
+ <category>
+ <pattern>SIZE TEST</pattern>
+ <template><size/></template>
+ </category>
+
+ <category>
+ <pattern>SYSTEM TEST</pattern>
+ <template><system>whoami</system></template>
+ </category>
+
+ <category>
+ <pattern>SRAI TEST</pattern>
+ <template><srai>SIZE TEST</srai></template>
+ </category>
+</aiml>
67 test/test_facade.rb
@@ -0,0 +1,67 @@
+require 'test/unit'
+require 'programr/facade'
+require 'programr/aiml_elements'
+require 'date'
+
+class TestFacade < Test::Unit::TestCase
+ def setup
+ @robot = ProgramR::Facade.new
+ @robot.learn('test/data/facade.aiml')
+ end
+
+ def test_stimula_reaction
+ assert_equal('test succeded', @robot.get_reaction('atomic test'), 'ATOMIC')
+ assert_equal('test succeded', @robot.get_reaction('srai test'), "SRAI")
+ assert_equal('new test succeded',@robot.get_reaction('atomic test'),"TOPIC")
+ assert_equal('that test 1', @robot.get_reaction('that test'), 'THAT 1')
+ assert_equal('that test 2', @robot.get_reaction('that test'), "THAT 2")
+ assert_equal('topic star test succeded OK',
+ @robot.get_reaction('atomic test'), "STAR TOPIC")
+ assert_equal('the UPPERCASE test', @robot.get_reaction('uppercase test'))
+ assert_equal('the lowercase test', @robot.get_reaction('LOWERCASE TEST'))
+ assert_equal(Date.today.to_s, @robot.get_reaction('DATE TEST'))
+ assert_equal('time:' + `date`.chomp, @robot.get_reaction('SYSTEM TEST'))
+ assert_equal(ProgramR::Category.cardinality.to_s,
+ @robot.get_reaction('SIZE TEST'))
+ assert_equal("TEST SPACE", @robot.get_reaction("SPACE TEST"))
+ assert_equal('tiresia', @robot.get_reaction('get test 1'))
+ assert_equal('TEST SPACE', @robot.get_reaction('justbeforethat tag test'))
+ assert_equal('TEST SPACE', @robot.get_reaction('that tag test'))
+ assert_equal('are you never tired to do the same things every day?',
+ @robot.get_reaction('question test'))
+ assert_equal('localhost', @robot.get_reaction('get test 2'))
+ assert_equal('ok.', @robot.get_reaction('think test. i am male'))
+ assert_equal('male.female.female', @robot.get_reaction('test set'))
+ assert_equal('You sound very attractive.',@robot.get_reaction('I AM BLOND'))
+ assert_equal('You sound very attractive.', @robot.get_reaction('I AM RED'))
+ assert_equal('You sound very attractive.',@robot.get_reaction('I AM BLACK'))
+ assert_equal('The sentence test', @robot.get_reaction('sentence test'))
+ assert_equal('The Formal Test', @robot.get_reaction('formal test'))
+ assert_equal('A', @robot.get_reaction('random test'))
+ assert_equal('RANDOM TEST.FORMAL TEST', @robot.get_reaction('test input'))
+ assert_equal(
+ 'she told to him to take a hike but her ego was too much for him',
+ @robot.get_reaction('test gender'))
+ assert_equal('she TOLD to him',
+ @robot.get_reaction('gender test 2 he told to her'))
+ assert_equal(
+ 'she TOLD MAURO EVERYTHING OK WITH her PROBLEM BUT i answers no',
+ @robot.get_reaction(
+ 'i told mauro everything ok with my problem but he answers no'))
+ assert_equal('i say everything ok to you',
+ @robot.get_reaction('you say everything ok to me'))
+ assert_equal('star wins', @robot.get_reaction('This is her'))
+ assert_equal('underscore wins', @robot.get_reaction('This is you'))
+ assert_equal('explicit pattern wins',
+ @robot.get_reaction('This is clearly you'))
+ assert_equal('first star is ARE NEAT AND second star is GOOD AS',
+ @robot.get_reaction('These are neat and clearly good as them'))
+ assert_equal('WHAT IS YOUR FAVORITE FOOTBALL TEAM',
+ @robot.get_reaction('test thatstar'))
+ assert_equal('ALSO MINE IS AC MILAN', @robot.get_reaction('AC milan'))
+ assert_equal('WHAT IS YOUR FAVORITE FOOTBALL TEAM',
+ @robot.get_reaction('test thatstar'))
+ assert_equal('ok yes ALSO MINE IS AC MILAN',
+ @robot.get_reaction('yes AC milan'))
+ end
+end
18 test/test_utils.rb
@@ -0,0 +1,18 @@
+require 'test/unit'
+require 'programr/utils'
+
+class TestFacade < Test::Unit::TestCase
+ def setup
+ @robot = ProgramR::Facade.new
+ @robot.learn('test/data/facade.aiml')
+ end
+
+ def test_aiml_file_finder
+ actual = ProgramR::AimlFinder::find(['test/data/mixed/single.aiml',
+ 'test/data/mixed/dir']).sort
+ expected = ['test/data/mixed/single.aiml',
+ 'test/data/mixed/dir/in_dir.aiml',
+ 'test/data/mixed/dir/subdir/in_sub_dir.aiml'].sort
+ assert_equal(expected, actual)
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.