cicloid-conversational 0.3.2.pre
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.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +21 -0
- data/README.markdown +240 -0
- data/Rakefile +2 -0
- data/conversational.gemspec +22 -0
- data/features/configure_blank_topic.feature +9 -0
- data/features/configure_exclusion_conversations.feature +20 -0
- data/features/configure_unknown_topic.feature +9 -0
- data/features/find_existing_conversation.feature +21 -0
- data/features/find_or_create_with.feature +33 -0
- data/features/retrieve_conversation_details.feature +13 -0
- data/features/step_definitions/conversation_steps.rb +60 -0
- data/features/step_definitions/pickle_steps.rb +87 -0
- data/features/support/conversation.rb +2 -0
- data/features/support/email_spec.rb +1 -0
- data/features/support/env.rb +58 -0
- data/features/support/mail.rb +6 -0
- data/features/support/paths.rb +33 -0
- data/features/support/pickle.rb +24 -0
- data/features/support/sample_conversation.rb +3 -0
- data/lib/conversational.rb +3 -0
- data/lib/conversational/active_record_additions.rb +122 -0
- data/lib/conversational/conversation.rb +285 -0
- data/lib/conversational/version.rb +4 -0
- data/lib/generators/conversational/migration/USAGE +5 -0
- data/lib/generators/conversational/migration/migration_generator.rb +23 -0
- data/lib/generators/conversational/migration/templates/migration.rb +14 -0
- data/lib/generators/conversational/skeleton/USAGE +6 -0
- data/lib/generators/conversational/skeleton/skeleton_generator.rb +17 -0
- data/lib/generators/conversational/skeleton/templates/conversation.rb +3 -0
- data/spec/active_record_additions_spec.rb +120 -0
- data/spec/conversation_definition_spec.rb +248 -0
- data/spec/conversation_spec.rb +34 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/conversation.rb +3 -0
- metadata +113 -0
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'rails/generators'
         | 
| 2 | 
            +
            require 'rails/generators/migration'
         | 
| 3 | 
            +
            module Conversational
         | 
| 4 | 
            +
              class MigrationGenerator < Rails::Generators::Base
         | 
| 5 | 
            +
                include Rails::Generators::Migration
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.source_root
         | 
| 8 | 
            +
                   @source_root ||= File.join(File.dirname(__FILE__), 'templates')
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.next_migration_number(dirname)
         | 
| 12 | 
            +
                  if ActiveRecord::Base.timestamped_migrations
         | 
| 13 | 
            +
                    Time.now.utc.strftime("%Y%m%d%H%M%S")
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    "%.3d" % (current_migration_number(dirname) + 1)
         | 
| 16 | 
            +
                   end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def create_migration_file
         | 
| 20 | 
            +
                  migration_template 'migration.rb', 'db/migrate/create_conversations.rb'
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            class CreateConversations < ActiveRecord::Migration
         | 
| 2 | 
            +
              def self.up
         | 
| 3 | 
            +
                create_table :conversations do |t|
         | 
| 4 | 
            +
                  t.string :with, :null => false
         | 
| 5 | 
            +
                  t.string :state
         | 
| 6 | 
            +
                  t.string :topic
         | 
| 7 | 
            +
                  t.timestamps
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              def self.down
         | 
| 12 | 
            +
                drop_table :conversations
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            require 'rails/generators'
         | 
| 2 | 
            +
            module Conversational
         | 
| 3 | 
            +
              class SkeletonGenerator < Rails::Generators::Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def self.source_root
         | 
| 6 | 
            +
                   @source_root ||= File.join(File.dirname(__FILE__), 'templates')
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def create_conversations_directory
         | 
| 10 | 
            +
                  empty_directory "app/conversations"
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def copy_conversation_file
         | 
| 14 | 
            +
                  copy_file "conversation.rb", "app/conversations/conversation.rb"
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,120 @@ | |
| 1 | 
            +
            # See support/conversation.rb
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Conversational::ActiveRecordAdditions do
         | 
| 6 | 
            +
              let(:valid_attributes) { {:with => "someone"} }
         | 
| 7 | 
            +
              describe "scopes" do
         | 
| 8 | 
            +
                let!(:conversation) { Conversation.create!(valid_attributes) }
         | 
| 9 | 
            +
                describe ".converser" do
         | 
| 10 | 
            +
                  it "should find the conversation with someone" do
         | 
| 11 | 
            +
                    Conversation.converser("someone").last.should == conversation
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                describe ".recent" do
         | 
| 15 | 
            +
                  context "the conversation was updated less than 24 hours ago" do
         | 
| 16 | 
            +
                    context "passing no arguments" do
         | 
| 17 | 
            +
                      it "should find the conversation" do
         | 
| 18 | 
            +
                        Conversation.recent.last.should == conversation
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                  context "the conversation was updated more than 24 hours ago" do
         | 
| 23 | 
            +
                    before {
         | 
| 24 | 
            +
                      Conversation.record_timestamps = false
         | 
| 25 | 
            +
                      conversation.updated_at = 24.hours.ago
         | 
| 26 | 
            +
                      conversation.save!
         | 
| 27 | 
            +
                      Conversation.record_timestamps = true
         | 
| 28 | 
            +
                    }
         | 
| 29 | 
            +
                    context "passing no arguments" do
         | 
| 30 | 
            +
                      it "should not find the conversation" do
         | 
| 31 | 
            +
                        Conversation.recent.last.should be_nil
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                    context "passing an argument" do
         | 
| 35 | 
            +
                      it "should find the conversation" do
         | 
| 36 | 
            +
                        Conversation.recent(25.hours.ago).last.should == conversation
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                describe ".in_progress" do
         | 
| 42 | 
            +
                  context "conversation is in progress" do
         | 
| 43 | 
            +
                    it "should find the conversation" do
         | 
| 44 | 
            +
                      Conversation.in_progress.last.should == conversation
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                  context "conversation is finished" do
         | 
| 48 | 
            +
                    before {
         | 
| 49 | 
            +
                      conversation.state = "finished"
         | 
| 50 | 
            +
                      conversation.save!
         | 
| 51 | 
            +
                    }
         | 
| 52 | 
            +
                    it "should not find the conversation" do
         | 
| 53 | 
            +
                      Conversation.in_progress.last.should be_nil
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                describe ".with" do
         | 
| 58 | 
            +
                  context "conversation is in progress and recent" do
         | 
| 59 | 
            +
                    it "should find the conversation" do
         | 
| 60 | 
            +
                      Conversation.with("someone").last.should == conversation
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
              
         | 
| 66 | 
            +
              describe ".find_or_create_with" do
         | 
| 67 | 
            +
                context "when no existing conversation exists with 'someone'" do
         | 
| 68 | 
            +
                  context "but a subclass for this topic exists and has not been excluded" do
         | 
| 69 | 
            +
                    let(:subclass) { mock("Subclass") }
         | 
| 70 | 
            +
                    before {
         | 
| 71 | 
            +
                      Conversational::ConversationDefinition.stub!(
         | 
| 72 | 
            +
                        :find_subclass_by_topic
         | 
| 73 | 
            +
                      ).with("something").and_return(subclass)
         | 
| 74 | 
            +
                    }
         | 
| 75 | 
            +
                    it "should create an instance of the subclass" do
         | 
| 76 | 
            +
                      subclass.should_receive(:create!).with(
         | 
| 77 | 
            +
                        :with => "someone", :topic => "something"
         | 
| 78 | 
            +
                      )
         | 
| 79 | 
            +
                      Conversation.find_or_create_with("someone", "something")
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                  context "and a subclass for this topic also does not exist" do
         | 
| 83 | 
            +
                    before {
         | 
| 84 | 
            +
                      Conversational::ConversationDefinition.stub!(
         | 
| 85 | 
            +
                        :find_subclass_by_topic
         | 
| 86 | 
            +
                      ).and_return(nil)
         | 
| 87 | 
            +
                    }
         | 
| 88 | 
            +
                    context "and the topic is blank" do
         | 
| 89 | 
            +
                      it "should raise an error" do
         | 
| 90 | 
            +
                        lambda {
         | 
| 91 | 
            +
                          Conversation.find_or_create_with("someone", nil)
         | 
| 92 | 
            +
                        }.should raise_error(/not defined a blank_topic_subclass/)
         | 
| 93 | 
            +
                      end
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
                    context "though the topic is not blank" do
         | 
| 96 | 
            +
                      it "should still raise an error" do
         | 
| 97 | 
            +
                        lambda {
         | 
| 98 | 
            +
                          Conversation.find_or_create_with(
         | 
| 99 | 
            +
                            "someone", "something"
         | 
| 100 | 
            +
                          )
         | 
| 101 | 
            +
                        }.should raise_error(/not defined SomethingConversation/)
         | 
| 102 | 
            +
                      end
         | 
| 103 | 
            +
                    end
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
                context "a conversation already exists" do
         | 
| 107 | 
            +
                  let(:conversation) { Conversation.new(valid_attributes) }
         | 
| 108 | 
            +
                  let(:defined_conversation) { mock("defined_conversation") }
         | 
| 109 | 
            +
                  before {
         | 
| 110 | 
            +
                    Conversation.stub_chain(:with, :last).and_return(conversation)
         | 
| 111 | 
            +
                  }
         | 
| 112 | 
            +
                  it "should return the conversation as an instance of the subclass" do
         | 
| 113 | 
            +
                    conversation.should_receive(:details).and_return(defined_conversation)
         | 
| 114 | 
            +
                    Conversation.find_or_create_with(
         | 
| 115 | 
            +
                      "someone", "something"
         | 
| 116 | 
            +
                    ).should == defined_conversation
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
            end
         | 
| @@ -0,0 +1,248 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Conversational::ConversationDefinition do
         | 
| 4 | 
            +
              def define_conversation(params=nil)
         | 
| 5 | 
            +
                defined_conversation = {}
         | 
| 6 | 
            +
                unless params && (params[:blank] || params[:unknown])
         | 
| 7 | 
            +
                  defined_conversation[:class] = mock("DefinedConversation")
         | 
| 8 | 
            +
                  defined_conversation[:instance] = mock("defined_conversation")
         | 
| 9 | 
            +
                  topic = "defined"
         | 
| 10 | 
            +
                  topic.stub!(:+).and_return(topic)
         | 
| 11 | 
            +
                  topic.stub!(:classify).and_return(topic)
         | 
| 12 | 
            +
                  topic.stub!(:constantize).and_return(defined_conversation[:class])
         | 
| 13 | 
            +
                  defined_conversation[:topic] = topic
         | 
| 14 | 
            +
                  defined_conversation[:class].stub!(:<=).and_return(true)
         | 
| 15 | 
            +
                else
         | 
| 16 | 
            +
                  if params[:unknown]
         | 
| 17 | 
            +
                    defined_conversation[:class] = mock("UnknownConversation")
         | 
| 18 | 
            +
                    defined_conversation[:instance] = mock("unknown_conversation")
         | 
| 19 | 
            +
                    Conversational::ConversationDefinition.unknown_topic_subclass = defined_conversation[:class]
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  if params[:blank]
         | 
| 22 | 
            +
                    defined_conversation[:class] = mock("BlankConversation")
         | 
| 23 | 
            +
                    defined_conversation[:instance] = mock("blank_conversation")
         | 
| 24 | 
            +
                    Conversational::ConversationDefinition.blank_topic_subclass = defined_conversation[:class]
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                defined_conversation
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              describe ".exclude" do
         | 
| 31 | 
            +
                it "should accept a string" do
         | 
| 32 | 
            +
                  lambda {
         | 
| 33 | 
            +
                    Conversational::ConversationDefinition.exclude "something"
         | 
| 34 | 
            +
                    }.should_not raise_error
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
                it "should accept a symbol" do
         | 
| 37 | 
            +
                  lambda {
         | 
| 38 | 
            +
                    Conversational::ConversationDefinition.exclude :defined_conversation
         | 
| 39 | 
            +
                    }.should_not raise_error
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                it "should accept a regex" do
         | 
| 42 | 
            +
                  lambda {
         | 
| 43 | 
            +
                    Conversational::ConversationDefinition.exclude /something/i
         | 
| 44 | 
            +
                    }.should_not raise_error
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                it "should accept a Class" do
         | 
| 47 | 
            +
                  some_class = mock("SomeClass", :superclass => Class)
         | 
| 48 | 
            +
                  some_class.stub!(:is_a?).with(Class).and_return(true)
         | 
| 49 | 
            +
                  lambda {
         | 
| 50 | 
            +
                    Conversational::ConversationDefinition.exclude some_class
         | 
| 51 | 
            +
                    }.should_not raise_error
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
                it "should accept an Array where the elements are a Class, String, Symbol or Regexp" do
         | 
| 54 | 
            +
                  some_class = mock("SomeClass", :superclass => Class)
         | 
| 55 | 
            +
                  some_class.stub!(:is_a?).with(Class).and_return(true)
         | 
| 56 | 
            +
                  lambda {
         | 
| 57 | 
            +
                    Conversational::ConversationDefinition.exclude ["Something", some_class, /something/i, :something]
         | 
| 58 | 
            +
                    }.should_not raise_error
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                it "should accept nil" do
         | 
| 61 | 
            +
                  lambda {
         | 
| 62 | 
            +
                    Conversational::ConversationDefinition.exclude nil
         | 
| 63 | 
            +
                    }.should_not raise_error
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
                it "should not accept anything else" do
         | 
| 66 | 
            +
                  some_class = mock("SomeClass")
         | 
| 67 | 
            +
                  lambda {
         | 
| 68 | 
            +
                    Conversational::ConversationDefinition.exclude some_class
         | 
| 69 | 
            +
                    }.should raise_error(/You specified a /)
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              describe ".find_subclass_by_topic" do
         | 
| 74 | 
            +
                context "a conversation definition with this topic has been defined" do
         | 
| 75 | 
            +
                  let(:defined_conversation) { define_conversation }
         | 
| 76 | 
            +
                  context "and it subclasses conversation" do
         | 
| 77 | 
            +
                    before {
         | 
| 78 | 
            +
                      defined_conversation[:class].stub!(:<=).and_return(true)
         | 
| 79 | 
            +
                    }
         | 
| 80 | 
            +
                    context "and it has not been excluded" do
         | 
| 81 | 
            +
                      before {
         | 
| 82 | 
            +
                        Conversational::ConversationDefinition.exclude nil
         | 
| 83 | 
            +
                      }
         | 
| 84 | 
            +
                      it "should return the conversation definition class" do
         | 
| 85 | 
            +
                        Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 86 | 
            +
                          defined_conversation[:topic]
         | 
| 87 | 
            +
                        ).should == defined_conversation[:class]
         | 
| 88 | 
            +
                      end
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
                    context "but it has been excluded" do
         | 
| 91 | 
            +
                      before {
         | 
| 92 | 
            +
                        Conversational::ConversationDefinition.stub!(:exclude?).and_return(true)
         | 
| 93 | 
            +
                      }
         | 
| 94 | 
            +
                      context "and it has not been explicitly included" do
         | 
| 95 | 
            +
                        context "and an unknown topic subclass has been defined" do
         | 
| 96 | 
            +
                          let!(:unknown_conversation) { define_conversation(:unknown => true) }
         | 
| 97 | 
            +
                          it "should return the unknown conversation subclass" do
         | 
| 98 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 99 | 
            +
                               defined_conversation[:topic]
         | 
| 100 | 
            +
                            ).should == unknown_conversation[:class]
         | 
| 101 | 
            +
                          end
         | 
| 102 | 
            +
                        end
         | 
| 103 | 
            +
                        context "and an unknown topic subclass has not been defined" do
         | 
| 104 | 
            +
                          before {
         | 
| 105 | 
            +
                            Conversational::ConversationDefinition.unknown_topic_subclass = nil
         | 
| 106 | 
            +
                          }
         | 
| 107 | 
            +
                          it "should return nil" do
         | 
| 108 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 109 | 
            +
                              defined_conversation[:topic]
         | 
| 110 | 
            +
                            ).should be_nil
         | 
| 111 | 
            +
                          end
         | 
| 112 | 
            +
                        end
         | 
| 113 | 
            +
                      end
         | 
| 114 | 
            +
                      context "but it was explicitly included for this query" do
         | 
| 115 | 
            +
                        it "should return the conversation definition class" do
         | 
| 116 | 
            +
                          Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 117 | 
            +
                            defined_conversation[:topic], :include_all => true
         | 
| 118 | 
            +
                          ).should == defined_conversation[:class]
         | 
| 119 | 
            +
                        end
         | 
| 120 | 
            +
                      end
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
                    context "and an unknown topic subclass has not been defined" do
         | 
| 123 | 
            +
                      before {
         | 
| 124 | 
            +
                        Conversational::ConversationDefinition.unknown_topic_subclass = nil
         | 
| 125 | 
            +
                      }
         | 
| 126 | 
            +
                      context "and the conversation has been excluded" do
         | 
| 127 | 
            +
                        context "by setting Conversation.exclude 'defined_conversation'" do
         | 
| 128 | 
            +
                          before {
         | 
| 129 | 
            +
                            excluded_class = "defined_conversation"
         | 
| 130 | 
            +
                            excluded_class.stub_chain(
         | 
| 131 | 
            +
                              :classify,
         | 
| 132 | 
            +
                              :constantize).and_return(
         | 
| 133 | 
            +
                              defined_conversation[:class]
         | 
| 134 | 
            +
                            )
         | 
| 135 | 
            +
                            Conversational::ConversationDefinition.exclude excluded_class
         | 
| 136 | 
            +
                          }
         | 
| 137 | 
            +
                          it "should return nil" do
         | 
| 138 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 139 | 
            +
                              defined_conversation[:topic]
         | 
| 140 | 
            +
                            ).should be_nil
         | 
| 141 | 
            +
                          end
         | 
| 142 | 
            +
                        end
         | 
| 143 | 
            +
                        context "by setting Conversation.exclude DefinedConversation" do
         | 
| 144 | 
            +
                          before {
         | 
| 145 | 
            +
                            excluded_class = defined_conversation[:class]
         | 
| 146 | 
            +
                            defined_conversation[:class].stub!(:superclass).and_return(Class)
         | 
| 147 | 
            +
                            defined_conversation[:class].stub!(:is_a?).with(
         | 
| 148 | 
            +
                              Class
         | 
| 149 | 
            +
                              ).and_return(true)
         | 
| 150 | 
            +
                            Conversational::ConversationDefinition.exclude(
         | 
| 151 | 
            +
                              defined_conversation[:class]
         | 
| 152 | 
            +
                            )
         | 
| 153 | 
            +
                          }
         | 
| 154 | 
            +
                          it "should return nil" do
         | 
| 155 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 156 | 
            +
                              defined_conversation[:topic]
         | 
| 157 | 
            +
                            ).should be_nil
         | 
| 158 | 
            +
                          end
         | 
| 159 | 
            +
                        end
         | 
| 160 | 
            +
                        context "by setting Conversation.exclude /defined/i" do
         | 
| 161 | 
            +
                          before {
         | 
| 162 | 
            +
                            Conversational::ConversationDefinition.exclude /defined/i
         | 
| 163 | 
            +
                          }
         | 
| 164 | 
            +
                          it "should return nil" do
         | 
| 165 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 166 | 
            +
                              defined_conversation[:topic]
         | 
| 167 | 
            +
                            ).should be_nil
         | 
| 168 | 
            +
                          end
         | 
| 169 | 
            +
                        end
         | 
| 170 | 
            +
                        context "by setting Conversation.exclude [/defined/i]" do
         | 
| 171 | 
            +
                          before {
         | 
| 172 | 
            +
                            Conversational::ConversationDefinition.exclude [/defined/i]
         | 
| 173 | 
            +
                          }
         | 
| 174 | 
            +
                          it "should return nil" do
         | 
| 175 | 
            +
                            Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 176 | 
            +
                              defined_conversation[:topic]
         | 
| 177 | 
            +
                            ).should be_nil
         | 
| 178 | 
            +
                          end
         | 
| 179 | 
            +
                        end
         | 
| 180 | 
            +
                      end
         | 
| 181 | 
            +
                    end
         | 
| 182 | 
            +
                  end
         | 
| 183 | 
            +
                  context "but it is not a type of conversation" do
         | 
| 184 | 
            +
                    before {
         | 
| 185 | 
            +
                      defined_conversation[:class].stub!(:<=).and_return(false)
         | 
| 186 | 
            +
                    }
         | 
| 187 | 
            +
                    context "but an unknown topic subclass has been defined" do
         | 
| 188 | 
            +
                      let!(:unknown_conversation) { define_conversation(:unknown => true) }
         | 
| 189 | 
            +
                      it "should return the unknown conversation subclass" do
         | 
| 190 | 
            +
                        Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 191 | 
            +
                          defined_conversation[:topic]
         | 
| 192 | 
            +
                        ).should == unknown_conversation[:class]
         | 
| 193 | 
            +
                      end
         | 
| 194 | 
            +
                    end
         | 
| 195 | 
            +
                    context "and an unknown topic subclass has not been defined" do
         | 
| 196 | 
            +
                      before {
         | 
| 197 | 
            +
                        Conversational::ConversationDefinition.unknown_topic_subclass = nil
         | 
| 198 | 
            +
                      }
         | 
| 199 | 
            +
                      it "should return nil" do
         | 
| 200 | 
            +
                        Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 201 | 
            +
                          defined_conversation[:topic]
         | 
| 202 | 
            +
                        ).should be_nil
         | 
| 203 | 
            +
                      end
         | 
| 204 | 
            +
                    end
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
                end
         | 
| 207 | 
            +
                context "and a conversation definition with this topic has not been defined" do
         | 
| 208 | 
            +
                  context "but an unknown conversation definition has been defined" do
         | 
| 209 | 
            +
                    let!(:unknown_conversation) { define_conversation(:unknown => true) }
         | 
| 210 | 
            +
                    it "should return the unknown conversation subclass" do
         | 
| 211 | 
            +
                      Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 212 | 
            +
                        "something"
         | 
| 213 | 
            +
                      ).should == unknown_conversation[:class]
         | 
| 214 | 
            +
                    end
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
                  context "and an unknown conversation definition has not been defined" do
         | 
| 217 | 
            +
                    before {
         | 
| 218 | 
            +
                      Conversational::ConversationDefinition.unknown_topic_subclass = nil
         | 
| 219 | 
            +
                    }
         | 
| 220 | 
            +
                    it "should return nil" do
         | 
| 221 | 
            +
                      Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 222 | 
            +
                        "someone"
         | 
| 223 | 
            +
                      ).should be_nil
         | 
| 224 | 
            +
                    end
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
                end
         | 
| 227 | 
            +
                context "and the topic for conversation is blank" do
         | 
| 228 | 
            +
                  context "but a blank conversation definition has been defined" do
         | 
| 229 | 
            +
                    let!(:blank_conversation) { define_conversation(:blank => true) }
         | 
| 230 | 
            +
                    it "should return the blank conversation subclass" do
         | 
| 231 | 
            +
                      Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 232 | 
            +
                        nil
         | 
| 233 | 
            +
                      ).should == blank_conversation[:class]
         | 
| 234 | 
            +
                    end
         | 
| 235 | 
            +
                  end
         | 
| 236 | 
            +
                  context "and a blank conversation definition has not been defined" do
         | 
| 237 | 
            +
                    before(:each) do
         | 
| 238 | 
            +
                      Conversational::ConversationDefinition.blank_topic_subclass = nil
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
                    it "should return nil" do
         | 
| 241 | 
            +
                      Conversational::ConversationDefinition.find_subclass_by_topic(
         | 
| 242 | 
            +
                        nil
         | 
| 243 | 
            +
                      ).should be_nil
         | 
| 244 | 
            +
                    end
         | 
| 245 | 
            +
                  end
         | 
| 246 | 
            +
                end
         | 
| 247 | 
            +
              end
         | 
| 248 | 
            +
            end
         |