MontealegreLuis/chat-bot

View on GitHub
lib/bot.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'yaml'
require_relative 'string'
require_relative 'word_play'

class Bot
    attr_reader :name

    def initialize(options)
        @name = options[:name] || 'Unnamed bot'
        begin
            @data = YAML.load(File.read(options[:data_file]))
        rescue
            raise "Cannot load bot data #{options[:data_file]}"
        end
    end

    def greeting
        random_response :greeting
    end

    def farewell
        random_response :farewell
    end

    def response_to(input)
        prepared_input = preprocess(input).downcase
        sentence = best_sentence(prepared_input)
        responses = possible_responses(sentence)
        responses[rand(responses.length)]
    end

    private

    def preprocess(input)
        perform_substitutions input
    end

    def perform_substitutions(input)
        @data[:presubs].each { |s| input.gsub!(s[0], s[1]) }
        input
    end

    def best_sentence(input)
        hot_words = @data[:responses].keys.select do |k|
            k.class == String && k =~ /^\w+$/
        end
        WordPlay.best_sentence(input.sentences, hot_words)
    end

    def possible_responses(sentence)
        responses = []
        # Find all patterns to try to match against
        @data[:responses].keys.each do |pattern|
            next unless pattern.is_a?(String)

            # For each pattern, see if the supplied sentence contains
            # a match. Remove substitution symbols (*) before checking.
            # Push all responses to the responses array.
            if sentence.match('\b' + pattern.gsub(/\*/, '') + '\b')
                # If the pattern contains substitution placeholders,
                # perform the substitutions
                if pattern.include?('*')
                    responses << @data[:responses][pattern].collect do |phrase|
                        # First, erase everything before the placeholder
                        # leaving everything after it
                        matching_section = sentence.sub(/^.*#{pattern}\s+/, '')

                        # Then substitute the text after the placeholder, with
                        # the pronouns switched
                        phrase.sub('*', WordPlay.switch_pronouns(matching_section))
                    end
                else
                    # No placeholders? Just add the phrases to the array
                    responses << @data[:responses][pattern]
                end
            end
        end

        # If there were no matches, add the default ones
        responses << @data[:responses][:default] if responses.empty?

        # Flatten the blocks of responses to a flat array
        responses.flatten
    end

    def random_response(key)
        random_index = rand(@data[:responses][key].length)
        @data[:responses][key][random_index].gsub(/\[name\]/, @name)
    end
end