<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/has_emails/extensions/action_mailer.rb</filename>
    </added>
    <added>
      <filename>test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb</filename>
    </added>
    <added>
      <filename>test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb</filename>
    </added>
    <added>
      <filename>test/factory.rb</filename>
    </added>
    <added>
      <filename>test/functional/has_emails_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,13 @@
 *SVN*
 
+*0.1.0* (May 5th, 2008)
+
+* Update to latest has_messages api
+
+* Simplify by removing support for models other than EmailAddresses in Emails
+
+* Updated documentation
+
 *0.0.1* (September 26th, 2007)
 
 * Refactor has_email_address/has_email_addresses so that new associations for unsent/sent emails isn't created for has_email_address</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -1,13 +1,10 @@
 = has_emails
 
-+has_emails+ adds support for emailing capabilities between ActiveRecord models.
++has_emails+ demonstrates a reference implementation for sending emails with
+logging and asynchronous support.
 
 == Resources
 
-Announcement
-
-* http://www.pluginaweek.org
-
 Wiki
 
 * http://wiki.pluginaweek.org/Has_emails
@@ -18,11 +15,11 @@ API
 
 Development
 
-* http://dev.pluginaweek.org/browser/trunk/plugins/active_record/has/has_emails
+* http://dev.pluginaweek.org/browser/trunk/has_emails
 
 Source
 
-* http://svn.pluginaweek.org/trunk/plugins/active_record/has/has_emails
+* http://svn.pluginaweek.org/trunk/has_emails
 
 == Description
 
@@ -33,43 +30,29 @@ web application to send notices and other notifications to users.
 
 Rails already provides ActionMailer as a way of sending emails.  However, the
 framework does not provide an easy way to persist emails, track their status, and
-process them asynchronously.  Designing and building this type of framework can
-become complex and cumbersome and takes away from the focus of the web application.
-This plugin helps ease that process by providing a complete implementation for
-sending and receiving emails to and between models in your application.
+process them asynchronously.  Designing and building a framework that supports this
+can be complex and takes away from the business focus.  This plugin can help ease
+that process by demonstrating a complete implementation of these features.
 
 == Usage
 
-=== Adding emailing support
-
-If you want to use the built-in support for email addresses (using the EmailAddress
-model), you can add emailing support for users like so:
-
-  class User &lt; ActiveRecord::Base
-    has_email_address
-    # has_email_addresses if you want to support multiple addresses
-  end
+=== Creating new emails
 
-On the other hand, if you already have the email address for users stored as a
-column in your users table, you can add emailing support like so:
+Emails should usually still be created using ActionMailer.  However, instead of
+delivering the emails, you can queue the emails like so:
 
-  class User &lt; ActiveRecord::Base
-    has_messages  :emails,
-                    :message_class =&gt; 'Email'
-  end
+  Notifier.deliver_signup_notification(david) # sends the email now
+  Notifier.queue_signup_notification(david) # sends the email later (has_emails kicks in)
 
-=== Creating new emails
+In addition to queueing emails, you can build them directly like so:
 
-  email = user.emails.build
-  email.to &lt;&lt; [user1, email_address1, 'someone@somewhere.com']
+  email_address = EmailAddress.find(123)
+  email = email_address.emails.build
+  email.to EmailAddress.find(456)
   email.subject = 'Hey!'
   email.body = 'Does anyone want to go out tonight?'
   email.deliver!
 
-As can be seen in the above example, you can use Users, EmailAddresses, or even
-Strings as recipients in emails.  Each will be automatically converted to the
-EmailRecipient class so that it can be stored in the database.
-
 === Replying to emails
 
   reply = email.reply_to_all
@@ -82,50 +65,27 @@ EmailRecipient class so that it can be stored in the database.
   forward.body = 'Interested?'
   forward.deliver!
 
-=== External process messaging
+=== Processing email asynchronously
 
 In addition to delivering emails immediately, you can also *queue* emails so
-that an external application processes and delivers them.  This is especially
-useful when you want to asynchronously send e-mails so that it doesn't block the
-user interface on your web application.
-
-To queue emails for external processing, you can simply use the &lt;tt&gt;queue!&lt;/tt&gt;
-event, rather than &lt;tt&gt;deliver!&lt;/tt&gt;.  This will indicate to any external processes
-that the email is ready to be sent.  The external process can then invoke &lt;tt&gt;deliver!&lt;/tt&gt;
-whenever it is ready to send the queued email.
-
-=== Running migrations
+that an external application processes and delivers them (as mentioned above).
+This is especially useful when you want to asynchronously send e-mails so that
+it doesn't block the user interface on your web application.
 
-To migrate the tables required for this plugin, you can either run the
-migration from the command line like so:
+To process queued emails, you need an external cron job that checks and sends
+them like so:
 
-  rake db:migrate:plugins PLUGIN=has_emails
-
-or (more ideally) generate a migration file that will integrate into your main
-application's migration path:
-
-  ruby script/generate plugin_migration has_emails
+  Email.with_state('queued').each do |email|
+    email.deliver!
+  end
 
 == Testing
 
-Before you can run any tests, the following gems must be installed:
+Before you can run any tests, the following gem must be installed:
 * plugin_test_helper[http://wiki.pluginaweek.org/Plugin_test_helper]
-* dry_validity_assertions[http://wiki.pluginaweek.org/Dry_validity_assertions]
 
 == Dependencies
 
-This plugin depends on the presence of the following plugins:
+* plugins_plus[http://wiki.pluginaweek.org/Plugins_plus]
 * has_messages[http://wiki.pluginaweek.org/Has_messages]
-* validates_as_email_address[http://wiki.pluginaweek.org/Validates_as_email_address]
-
-This plugin is also a plugin+.  That means that it contains a slice of an
-application, such as models and migrations.  To test or use a plugin+, you
-must have the following plugins/gems installed:
-* plugin_dependencies[http://wiki.pluginaweek.org/Plugin_dependencies]
-* loaded_plugins[http://wiki.pluginaweek.org/Loaded_plugins]
-* appable_plugins[http://wiki.pluginaweek.org/Appable_plugins]
-* plugin_migrations[http://wiki.pluginaweek.org/Plugin_migrations]
-
-Instead of installing each individual plugin+ feature, you can install them all
-at once using the plugins+[http://wiki.pluginaweek.org/Plugins_plus] meta package,
-which contains all additional features.
+* state_machine[http://wiki.pluginaweek.org/State_machine]</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@ require 'rake/gempackagetask'
 require 'rake/contrib/sshpublisher'
 
 PKG_NAME           = 'has_emails'
-PKG_VERSION        = '0.0.1'
+PKG_VERSION        = '0.1.0'
 PKG_FILE_NAME      = &quot;#{PKG_NAME}-#{PKG_VERSION}&quot;
 RUBY_FORGE_PROJECT = 'pluginaweek'
 
@@ -31,17 +31,17 @@ spec = Gem::Specification.new do |s|
   s.name            = PKG_NAME
   s.version         = PKG_VERSION
   s.platform        = Gem::Platform::RUBY
-  s.summary         = 'Adds support for emailing capabilities between ActiveRecord models.'
+  s.summary         = 'Demonstrates a reference implementation for sending emails with logging and asynchronous support.'
   
   s.files           = FileList['{app,db,lib,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
   s.require_path    = 'lib'
   s.autorequire     = 'has_emails'
   s.has_rdoc        = true
   s.test_files      = Dir['test/**/*_test.rb']
-  s.add_dependency  'has_messages', '&gt;= 0.0.1'
-  s.add_dependency  'validates_as_email_address', '&gt;= 0.0.1'
+  s.add_dependency  'has_messages', '&gt;= 0.1.0'
+  s.add_dependency  'validates_as_email_address', '&gt;= 0.0.2'
   
-  s.author          = 'Aaron Pfeifer, Neil Abraham'
+  s.author          = 'Aaron Pfeifer'
   s.email           = 'info@pluginaweek.org'
   s.homepage        = 'http://www.pluginaweek.org'
 end</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -1,84 +1,12 @@
 # Represents an email which has been sent to one or more recipients.  This is
-# essentially the same as the Message class, but overrides the +to+, +cc+, and +bcc+
-# associations to that proper instances of the MessageRecipient class are created.
+# essentially the same as the Message class, but overrides how the it is
+# delivered.
 class Email &lt; Message
-  validates_presence_of       :sender_spec
-  validates_as_email_address  :sender_spec,
-                                :allow_nil =&gt; true
-  
-  with_options(
-    :class_name =&gt; 'EmailRecipient',
-    :foreign_key =&gt; 'message_id',
-    :order =&gt; 'position ASC',
-    :dependent =&gt; true
-  ) do |e|
-    e.has_many  :to,
-                  :conditions =&gt; ['kind = ?', 'to'],
-                  :extend =&gt; [MessageRecipientToBuildExtension, EmailRecipientBuildExtension]
-    e.has_many  :cc,
-                  :conditions =&gt; ['kind = ?', 'cc'],
-                  :extend =&gt; [MessageRecipientCcBuildExtension, EmailRecipientBuildExtension]
-    e.has_many  :bcc,
-                  :conditions =&gt; ['kind = ?', 'bcc'],
-                  :extend =&gt; [MessageRecipientBccBuildExtension, EmailRecipientBuildExtension]
-  end
-  
-  # Returns the sender of the message.  This can be a string if being sent
-  # from an arbitrary e-mail address.
-  def sender_with_spec
-    sender_without_spec || sender_spec
-  end
-  alias_method_chain :sender, :spec
-  
-  # If sender is a string, then sets the spec, otherwise uses the original
-  # sender setter
-  def sender_with_spec=(value)
-    self.sender_spec = EmailAddress.convert_from(value).spec
-    self.sender_without_spec = value if !value.is_a?(String)
-  end
-  alias_method_chain :sender=, :spec
-  
-  # Converts the sender into an Email Address, whether it be a string,
-  # EmailAddress, or other model type
-  def sender_email_address
-    EmailAddress.convert_from(sender_spec)
-  end
-  
-  # The name of the person whose sending the email
-  def sender_name
-    sender_without_spec ? EmailAddress.convert_from(sender_without_spec).name : sender_email_address.name
-  end
-  
-  # Returns a string version of the email address plus any name like
-  # &quot;John Doe &lt;john.doe@gmail.com&gt;&quot;..
-  def sender_with_name
-    address = self.email_address
-    address.name = self.name
-    address.with_name
-  end
-  
-  # Actually delivers the email to the recipients
-  def deliver
-    ApplicationMailer.deliver_email(self)
-  end
-  
-  # Saves the +sender_spec+ in the forwarded message
-  def forward
-    message = super
-    message.sender_spec = sender_spec
-    message
-  end
-  
-  # Saves the +sender_spec+ in the replied message
-  def reply
-    message = super
-    message.sender_spec = sender_spec
-    message
-  end
+  after_deliver :deliver_email
   
   private
-  # Strings are allowed to participate in messaging
-  def model_participant?
-    sender_id &amp;&amp; sender_type || sender_spec.nil?
-  end
+    # Actually delivers the email to the recipients
+    def deliver_email
+      ActionMailer::Base.deliver_email(self)
+    end
 end</diff>
      <filename>app/models/email.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,123 +1,45 @@
 # Represents a valid RFC822 email address
 class EmailAddress &lt; ActiveRecord::Base
+  has_emails
+  
+  validates_presence_of       :spec
+  validates_as_email_address  :spec
+  validates_uniqueness_of     :spec,
+                                :scope =&gt; 'name'
+  
   class &lt;&lt; self
-    # Converts the specified record to an EmailAddress.  It will convert the
-    # following types:
-    # 1. String
-    # 2. A record with an +email_address+ String attribute
-    # 3. A record with an +email_address+ association
-    # 4. A record with an +email_addresses+ association (first record will be chosen)
-    # 
-    # If an EmailAddress is specified, the same model will be returned.  An
-    # ArgumentError is raised if it doesn't match any of the above criteria.
-    def convert_from(record)
-      if record
-        if EmailAddress === record
-          record
-        elsif String === record
-          EmailAddress.new(:spec =&gt; record)
-        elsif record.respond_to?(:email_address)
-          if record.email_address.is_a?(String)
-            address = EmailAddress.new(:spec =&gt; record.email_address)
-            address.name = record.name if record.respond_to?(:name)
-            address
-          else
-            record.email_address
-          end
-        elsif record.respond_to?(:email_addresses)
-          record.email_addresses.first
-        else
-          raise ArgumentError, &quot;Cannot convert #{record.class} to an EmailAddress&quot;
-        end
-      end
+    # Finds or create an email address based on the given value
+    def find_or_create_by_address(address)
+      name, spec = split_address(address)
+      find_or_create_by_name_and_spec(name, spec)
     end
     
-    # Determines if the given spec is a valid address using the RFC822 spec
-    def valid?(spec)
-      !RFC822::EmailAddress.match(spec).nil?
+    # Splits the given address into a name and spec
+    def split_address(address)
+      if match = /^(\S.*)\s+&lt;(.*)&gt;$/.match(address)
+        name = match[1]
+        spec = match[2]
+      else
+        spec = address
+      end
+      
+      return name, spec
     end
   end
   
-  acts_as_tokenized :token_field =&gt; 'verification_code', :token_length =&gt; 32
-  
-  # Support e-mail address verification
-  has_states    :initial =&gt; :unverified
-  
-  # Add messaging capabilities.  This will give us an email_box.
-  has_messages  :emails,
-                  :message_class =&gt; 'Email'
-  belongs_to    :emailable,
-                  :polymorphic =&gt; true
-  
-  validates_presence_of       :spec
-  
-  with_options(:allow_nil =&gt; true) do |klass|
-    klass.validates_uniqueness_of     :spec
-    klass.validates_as_email_address  :spec
-  end
-  
-  # The name of the person who owns this email address
-  attr_accessor :name
-  
-  # Ensure that the e-mail address has a verification code that can be sent
-  # to the user
-  before_create :set_code_expiry
-  
-  state :unverified, :verified
-  
-  # Verifies that the email address is valid
-  event :verify do
-    transition_to :verified, :from =&gt; :unverified
-  end
-  
-  # Sets the full address
-  def spec=(new_spec)
-    @local_name = @domain = nil
-    write_attribute(:spec, new_spec)
-  end
-  
-  # The part of the e-mail address before the @
-  def local_name
-    parse_spec if !@local_name
-    @local_name
-  end
-  
-  # The part of the e-mail address after the @
-  def domain
-    parse_spec if !@domain
-    @domain
-  end
-  
-  # Gets the name of the person whose email address this is.  Default is an
-  # empty string.  Override this if you want it to appear in with_name
-  def name
-    @name || ''
+  # Sets the value to be used for this email address.  This can come in two formats:
+  # * With name - John Doe &lt;john.doe@gmail.com&gt;
+  # * Without name - john.doe@gmail.com
+  def address=(address)
+    self.name, self.spec = self.class.split_address(address)
   end
   
-  # Returns a string version of the email address plus any name like
-  # &quot;John Doe &lt;john.doe@gmail.com&gt;&quot;.  In order to have a valid name within the
-  # string, you must override +name+.
+  # Generates the value for the email address, including the name associated with
+  # it (if provided).  For example,
+  # 
+  #   e = EmailAddress.new(:name =&gt; 'John Doe', :spec =&gt; 'john.doe@gmail.com')
+  #   e.with_name # =&gt; &quot;John Doe &lt;john.doe@gmail.com&gt;&quot;
   def with_name
-    name.blank? ? to_s : &quot;#{name} &lt;#{to_s}&gt;&quot;
-  end
-  
-  # Returns the full email address (without the name)
-  def to_s #:nodoc
-    spec
-  end
-  
-  private
-  # Sets the time at which the verification code will expire
-  def set_code_expiry
-    self.code_expiry = 48.hour.from_now
-  end
-  
-  # Parses the current spec and sets +@local_name+ and +@domain+ based on the
-  # matching groups within the regular expression
-  def parse_spec
-    if !@local_name &amp;&amp; !@domain &amp;&amp; match = RFC822::EmailAddress.match(spec)
-      @local_name = match.captures[0]
-      @domain = match.captures[1]
-    end
+    name.blank? ? spec : &quot;#{name} &lt;#{spec}&gt;&quot;
   end
 end</diff>
      <filename>app/models/email_address.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,23 +1,14 @@
 class CreateEmailAddresses &lt; ActiveRecord::Migration
   def self.up
     create_table :email_addresses do |t|
-      t.column :emailable_id, :integer, :null =&gt; false, :references =&gt; nil
-      t.column :emailable_type, :string, :null =&gt; false
-      t.column :spec, :string, :null =&gt; false, :limit =&gt; 382
-      t.column :verification_code, :string, :limit =&gt; 40
-      t.column :code_expiry, :datetime
-      t.column :created_at, :timestamp, :null =&gt; false
-      t.column :updated_at, :datetime, :null =&gt; false
+      t.string :spec, :null =&gt; false, :limit =&gt; 382
+      t.string :name
+      t.timestamps
     end
-    add_index :email_addresses, :spec, :unique =&gt; true
-    add_index :email_addresses, :verification_code, :unique =&gt; true
-    
-    PluginAWeek::Has::States.migrate_up(:email_addresses)
+    add_index :email_addresses, [:spec, :name], :unique =&gt; true
   end
   
   def self.down
-    PluginAWeek::Has::States.migrate_down(:email_addresses)
-    
     drop_table :email_addresses
   end
 end</diff>
      <filename>db/migrate/001_create_email_addresses.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,92 +1,65 @@
 require 'has_messages'
 require 'validates_as_email_address'
-require 'acts_as_tokenized'
-require 'nested_has_many_through'
+require 'has_emails/extensions/action_mailer'
 
 module PluginAWeek #:nodoc:
-  module Has #:nodoc:
-    # Adds support for sending emails to models
-    module Emails
-      def self.included(base) #:nodoc:
-        base.extend(MacroMethods)
+  # Adds a generic implementation for sending emails
+  module HasEmails
+    def self.included(base) #:nodoc:
+      base.class_eval do
+        extend PluginAWeek::HasEmails::MacroMethods
       end
-      
-      module MacroMethods
-        # Adds support for emailing instances of this model through multiple
-        # email addresses.
-        # 
-        # == Generated associations
-        # 
-        # The following +has_many+ associations are created for models that support
-        # emailing:
-        # * +email_addresses+ - The email addresses of this model
-        # * +emails+ - A collection of Emails of which this model was the sender
-        # * +email_recipients+ - A collection of EmailRecipients in which this record is a receiver
-        def has_email_addresses
-          has_many  :email_addresses,
-                      :class_name =&gt; 'EmailAddress',
-                      :as =&gt; :emailable,
-                      :dependent =&gt; :destroy
-          
-          # Add associations for all emails the model has sent and received
-          has_many  :emails,
-                      :through =&gt; :email_addresses
-          has_many  :email_recipients,
-                      :through =&gt; :email_addresses
-          
-          include PluginAWeek::Has::Emails::InstanceMethods
-        end
+    end
+    
+    module MacroMethods
+      # Creates the following email associations:
+      # * +emails+ - Emails that were composed and are visible to the owner.  Emails may have been sent or unsent.
+      # * +received_emails - Emails that have been received from others and are visible.  Emails may have been read or unread.
+      # 
+      # == Creating new emails
+      # 
+      # To create a new email, the +emails+ association should be used, for example:
+      # 
+      #   address = EmailAddress.find(123)
+      #   email = user.emails.build
+      #   email.subject = 'Hello'
+      #   email.body = 'How are you?'
+      #   email.to User.EmailAddress(456)
+      #   email.save!
+      #   email.deliver!
+      # 
+      # Alternatively, 
+      def has_emails
+        has_many  :emails,
+                    :as =&gt; :sender,
+                    :class_name =&gt; 'Email',
+                    :conditions =&gt; {:hidden_at =&gt; nil},
+                    :order =&gt; 'messages.created_at ASC'
+        has_many  :received_emails,
+                    :as =&gt; :receiver,
+                    :class_name =&gt; 'MessageRecipient',
+                    :include =&gt; :message,
+                    :conditions =&gt; ['message_recipients.hidden_at IS NULL AND messages.state = ?', 'sent'],
+                    :order =&gt; 'messages.created_at ASC'
         
-        # Adds support for emailing instances of this model through a single
-        # email address.
-        # 
-        # == Generated associations
-        # 
-        # The following associations are created for models that support emailing:
-        # * +email_address+ - The email address of this model
-        # * +emails+ - A collection of Emails of which this model was the sender
-        # * +email_recipients+ - A collection of EmailRecipients in which this record is a receiver
-        def has_email_address
-          has_one :email_address,
-                    :class_name =&gt; 'EmailAddress',
-                    :as =&gt; :emailable,
-                    :dependent =&gt; :destroy
-          
-          delegate  :emails,
-                    :email_recipients,
-                      :to =&gt; :email_address
-          
-          include PluginAWeek::Has::Emails::InstanceMethods
-        end
+        include PluginAWeek::HasEmails::InstanceMethods
+      end
+    end
+    
+    module InstanceMethods
+      # Composed emails that have not yet been sent
+      def unsent_emails
+        emails.with_state('unsent')
       end
       
-      module InstanceMethods
-        # All emails this model has received
-        def received_emails
-          email_recipients.active.find_in_states(:all, :unread, :read, :include =&gt; :message, :conditions =&gt; ['messages.state_id = ?', Message.states.find_by_name('sent').id]).collect do |recipient|
-            ReceivedMessage.new(recipient)
-          end
-        end
-        
-        # All emails that have not yet been sent by this model (excluding any that have been deleted)
-        def unsent_emails(*args)
-          emails.active.unsent(*args)
-        end
-        
-        # All emails that have been sent by this model (excluding any that have been deleted)
-        def sent_emails(*args)
-          emails.active.find_in_states(:all, :queued, :sent, *args)
-        end
-        
-        # Contains all of the emails that have been sent and received
-        def email_box
-          @email_box ||= MessageBox.new(received_emails, unsent_emails, sent_emails)
-        end
+      # Composed emails that have already been sent
+      def sent_emails
+        emails.with_states(%w(queued sent))
       end
     end
   end
 end
 
 ActiveRecord::Base.class_eval do
-  include PluginAWeek::Has::Emails
+  include PluginAWeek::HasEmails
 end</diff>
      <filename>lib/has_emails.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,33 +1,10 @@
 require 'config/boot'
-
-$:.unshift(&quot;#{RAILS_ROOT}/../../../../../rails/plugin_dependencies/lib&quot;)
-begin
-  require 'plugin_dependencies'
-rescue Exception =&gt; e
-end
+require &quot;#{File.dirname(__FILE__)}/../../../../plugins_plus/boot&quot;
 
 Rails::Initializer.run do |config|
-  config.plugin_paths.concat([
-    &quot;#{RAILS_ROOT}/../../..&quot;,
-    &quot;#{RAILS_ROOT}/../../../../migrations&quot;,
-    &quot;#{RAILS_ROOT}/../../../../../rails&quot;,
-    &quot;#{RAILS_ROOT}/../../../../../test&quot;,
-    &quot;#{RAILS_ROOT}/../../../../../third_party&quot;
-  ])
-  config.plugins = [
-    'loaded_plugins',
-    'appable_plugins',
-    'plugin_migrations',
-    'has_states',
-    'has_finder',
-    'has_messages',
-    'acts_as_tokenized',
-    'nested_has_many_through',
-    File.basename(File.expand_path(&quot;#{RAILS_ROOT}/../..&quot;)),
-    'dry_validity_assertions'
-  ]
+  config.plugin_paths &lt;&lt; '..'
+  config.plugins = %w(plugins_plus state_machine has_messages validates_as_email_address has_emails)
   config.cache_classes = false
   config.whiny_nils = true
+  config.action_mailer.delivery_method = :test
 end
-
-Plugin.mix_code_from(:mailers =&gt; /.+_mailer/)</diff>
      <filename>test/app_root/config/environment.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,76 +1,13 @@
-# Load local repository plugin paths
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../associations/class_associations/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../has/has_messages/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../has/has_states/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../miscellaneous/custom_callbacks/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../miscellaneous/dry_transaction_rollbacks/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../validations/validates_as_email_address/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../ruby/object/eval_call/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../third_party/acts_as_tokenized/lib&quot;)
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../third_party/nested_has_many_through/lib&quot;)
-
 # Load the plugin testing framework
-$:.unshift(&quot;#{File.dirname(__FILE__)}/../../../../test/plugin_test_helper/lib&quot;)
+$:.unshift(&quot;#{File.dirname(__FILE__)}/../../plugin_test_helper/lib&quot;)
 require 'rubygems'
 require 'plugin_test_helper'
 
-# Run the plugin migrations
-%w(has_states has_messages has_emails).each do |plugin|
-  Rails.plugins[plugin].migrate
-end
-
-# Run the test app migrations
+# Run the migrations
 ActiveRecord::Migrator.migrate(&quot;#{RAILS_ROOT}/db/migrate&quot;)
 
-# Bootstrap the database
-%w(has_messages has_emails).each do |plugin|
-  plugin = Rails.plugins[plugin]
-  bootstrap_path = &quot;#{plugin.migration_path}/../bootstrap&quot;
-  
-  Dir.glob(&quot;#{bootstrap_path}/*.{yml,csv}&quot;).each do |fixture_file|
-    table_name = File.basename(fixture_file, '.*')
-    Fixtures.new(ActiveRecord::Base.connection, table_name, nil, File.join(bootstrap_path, table_name)).insert_fixtures
-  end
-end
-
+# Mixin the factory helper
+require File.expand_path(&quot;#{File.dirname(__FILE__)}/factory&quot;)
 class Test::Unit::TestCase #:nodoc:
-  def self.require_fixture_classes(table_names=nil)
-    # Don't allow fixture classes to be required because classes like Message are
-    # going to throw an error since the states and events have not yet been
-    # loaded
-  end
-  
-  # Freezes time for running email tests
-  def freeze_time(frozen_time = 946702800)
-    Time.instance_eval do
-      frozen_now = (frozen_time)
-      alias :original_now :now
-      alias :now :frozen_now
-    end
-    
-    if block_given?
-      begin
-        yield
-      ensure
-        unfreeze_time
-      end
-    end
-  end
-  
-  # Restores the original method for time
-  def unfreeze_time
-    Time.instance_eval do
-      alias :now :original_now
-    end    
-  end
-end
-
-class Time
-  def self.frozen_now=(val)
-    @frozen_now = val
-  end
-  
-  def self.frozen_now
-    Time.at(@frozen_now || 946702800)
-  end
+  include Factory
 end</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,200 +1,148 @@
-require File.dirname(__FILE__) + '/../test_helper'
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
 
-class EmailAddressTest &lt; Test::Unit::TestCase
-  fixtures :departments, :users, :email_addresses, :messages, :message_recipients, :state_changes
-  
-  def test_should_convert_email_address_using_same_model
-    e = email_addresses(:bob)
-    assert_same e, EmailAddress.convert_from(e)
-  end
-  
-  def test_should_convert_string
-    e = EmailAddress.convert_from('test@email.com')
-    assert_instance_of EmailAddress, e
-    assert_equal 'test@email.com', e.spec
-  end
-  
-  def test_should_convert_record_with_email_address_column
-    department = departments(:marketing)
-    e = EmailAddress.convert_from(department)
-    assert_instance_of EmailAddress, e
-    assert_equal 'marketing@companyxyz.com', e.spec
+class EmailAddressByDefaultTest &lt; Test::Unit::TestCase
+  def setup
+    @email_address = EmailAddress.new
   end
   
-  def test_should_convert_record_with_email_address_association
-    user = users(:bob)
-    class &lt;&lt; user
-      def email_address
-        EmailAddress.new(:spec =&gt; 'test@email.com')
-      end
-    end
-    
-    e = EmailAddress.convert_from(user)
-    assert_instance_of EmailAddress, e
-    assert_equal 'test@email.com', e.spec
-  end
-  
-  def test_should_convert_record_with_email_addresses_association_using_first_email_address
-    e = EmailAddress.convert_from(users(:bob))
-    assert_instance_of EmailAddress, e
-    assert_equal 'bob@bob.com', e.spec
+  def test_should_not_have_a_name
+    assert @email_address.name.blank?
   end
   
-  def test_should_raise_exception_if_converting_unknown_class_to_email_address
-    assert_raise(ArgumentError) {EmailAddress.convert_from(1)}
+  def test_should_not_have_a_spec
+    assert @email_address.name.blank?
   end
-  
-  def test_invalid_spec_should_not_be_valid
-    assert !EmailAddress.valid?('invalid')
-  end
-  
-  def test_valid_spec_should_be_valid
-    assert EmailAddress.valid?('valid@valid.com')
-  end
-  
-  def test_should_be_valid
-    assert_valid email_addresses(:bob)
-  end
-  
-  def test_should_require_spec
-    assert_invalid email_addresses(:bob), :spec, nil
-  end
-  
-  def test_should_require_unique_spec
-    assert_invalid email_addresses(:bob).clone, :spec
-  end
-  
-  def test_should_require_minimum_length_for_spec
-    assert_invalid email_addresses(:bob), :spec, 'ab'
-    assert_valid email_addresses(:bob), :spec, 'a@a'
-  end
-  
-  def test_should_require_maximum_length_for_spec
-    assert_invalid email_addresses(:bob), :spec, 'a' * 300 + '@' + 'a' * 20
-    assert_valid email_addresses(:bob), :spec, 'a' * 300 + '@' + 'a' * 19
+end
+
+class EmailAddressTest &lt; Test::Unit::TestCase
+  def test_should_be_valid_with_a_set_of_valid_attributes
+    email_address = new_email_address
+    assert email_address.valid?
   end
   
-  def test_should_require_specific_format_for_spec
-    assert_invalid email_addresses(:bob), :spec, 'aaaaaaaaaa'
-    assert_valid email_addresses(:bob), :spec, 'aaa@aaa.com'
+  def test_should_require_a_spec
+    email_address = new_email_address(:spec =&gt; nil)
+    assert !email_address.valid?
+    assert_equal 3, Array(email_address.errors.on(:spec)).size
   end
   
-  def test_should_have_polymorphic_emailable_association
-    assert_equal users(:bob), email_addresses(:bob).emailable
+  def test_should_require_a_properly_formatted_email
+    email_address = new_email_address(:spec =&gt; '!@@!@@!')
+    assert !email_address.valid?
+    assert_equal 1, Array(email_address.errors.on(:spec)).size
   end
   
-  def test_should_have_unsent_emails_association
-    assert_equal [messages(:unsent_from_bob)], email_addresses(:bob).unsent_emails
+  def test_should_not_allow_emails_less_than_3_characters
+    email_address = new_email_address(:spec =&gt; 'aa')
+    assert !email_address.valid?
+    assert_equal 2, Array(email_address.errors.on(:spec)).size
+    
+    email_address.spec = 'a@a'
+    assert email_address.valid?
   end
   
-  def test_should_have_sent_emails_association
-    assert_equal [messages(:sent_from_bob), messages(:queued_from_bob)], email_addresses(:bob).sent_emails
+  def test_should_not_allow_emails_longer_than_320_characters
+    email_address = new_email_address(:spec =&gt; 'a' * 314 + '@a.com')
+    assert email_address.valid?
+    
+    email_address.spec += 'a'
+    assert !email_address.valid?
+    assert_equal 1, Array(email_address.errors.on(:spec)).size
   end
   
-  def test_should_have_received_emails_association
-    assert_equal [messages(:sent_from_bob), messages(:sent_from_mary)], email_addresses(:john).received_emails.map(&amp;:email)
+  def test_should_require_a_unique_spec_scoped_by_name
+    email_address = create_email_address(:spec =&gt; 'john.smith@gmail.com', :name =&gt; 'John Smith')
+    
+    second_email_address = new_email_address(:spec =&gt; 'john.smith@gmail.com', :name =&gt; 'John Smith II')
+    assert second_email_address.valid?
+    
+    second_email_address = new_email_address(:spec =&gt; 'john.smith@gmail.com', :name =&gt; 'John Smith')
+    assert !second_email_address.valid?
+    assert_equal 1, Array(second_email_address.errors.on(:spec)).size
   end
   
-  def test_initial_state_should_be_unverified
-    assert_equal :unverified, EmailAddress.new.state.to_sym
+  def test_should_not_require_a_name
+    email_address = new_email_address(:name =&gt; nil)
+    assert email_address.valid?
   end
-  
-  def test_should_verify_if_unverified
-    e = email_addresses(:bob)
-    assert e.unverified?
-    assert e.verify!
-    assert e.verified?
+end
+
+class EmailAddressFromAddressTest &lt; Test::Unit::TestCase
+  def setup
+    @email_address = EmailAddress.new(:address =&gt; 'John Smith &lt;john.smith@gmail.com&gt;')
   end
   
-  def test_should_not_verify_if_verified
-    e = email_addresses(:john)
-    assert e.verified?
-    assert !e.verify!
+  def test_should_be_valid
+    assert @email_address.valid?
   end
   
-  def test_should_create_verification_code_on_create
-    e = EmailAddress.new(:spec =&gt; 'test@me.com', :emailable =&gt; users(:bob))
-    assert_nil e.verification_code
-    assert e.save!
-    assert_not_nil e.verification_code
-    assert_equal 32, e.verification_code.length
+  def test_should_find_a_name
+    assert_equal 'John Smith', @email_address.name
   end
   
-  def test_should_not_modify_verification_code_on_update
-    e = email_addresses(:bob)
-    original_verification_code = e.verification_code
-    e.spec = 'test@me.com'
-    assert e.save!
-    assert_equal original_verification_code, e.verification_code
+  def test_should_find_a_spec
+    assert_equal 'john.smith@gmail.com', @email_address.spec
   end
-  
-  def test_should_create_code_expiry_on_create
-    e = EmailAddress.new(:spec =&gt; 'test@me.com', :emailable =&gt; users(:bob))
-    assert_nil e.code_expiry
-    assert e.save!
-    assert_not_nil e.code_expiry
+end
+
+class EmailAddressFromAddressWithoutNameTest &lt; Test::Unit::TestCase
+  def setup
+    @email_address = EmailAddress.new(:address =&gt; 'john.smith@gmail.com')
   end
   
-  def test_should_not_modify_code_expiry_on_update
-    e = email_addresses(:bob)
-    original_code_expiry = e.code_expiry
-    e.spec = 'test@me.com'
-    assert e.save!
-    assert_equal original_code_expiry, e.code_expiry
+  def test_should_be_valid
+    assert @email_address.valid?
   end
   
-  def test_should_not_automatically_parse_local_name_after_find
-    assert_nil email_addresses(:bob).send(:instance_variable_get, '@local_name')
+  def test_should_not_find_a_name
+    assert @email_address.name.blank?
   end
   
-  def test_should_not_automatically_parse_domain_after_find
-    assert_nil email_addresses(:bob).send(:instance_variable_get, '@domain')
+  def test_should_find_a_spec
+    assert_equal 'john.smith@gmail.com', @email_address.spec
   end
-  
-  def test_should_parse_local_name_when_accessed
-    assert_equal 'bob', email_addresses(:bob).local_name
+end
+
+class EmailAddressAfterBeingCreatedTest &lt; Test::Unit::TestCase
+  def setup
+    @email_address = create_email_address(:name =&gt; 'John Smith', :spec =&gt; 'john.smith@gmail.com')
   end
   
-  def test_should_parse_domain_when_accessed
-    assert_equal 'bob.com', email_addresses(:bob).domain
+  def test_should_record_when_it_was_created
+    assert_not_nil @email_address.created_at
   end
   
-  def test_should_reset_local_name_and_domain_when_new_spec_is_set
-    e = email_addresses(:bob)
-    assert_equal 'bob', e.local_name
-    assert_equal 'bob.com', e.domain
-    
-    e.spec = 'test@me.com'
-    assert_equal 'test', e.local_name
-    assert_equal 'me.com', e.domain
+  def test_should_record_when_it_was_updated
+    assert_not_nil @email_address.updated_at
   end
   
-  def test_name_should_be_blank_by_default
-    assert_equal '', EmailAddress.new.name
+  def test_should_generate_an_address_with_the_name
+    assert_equal 'John Smith &lt;john.smith@gmail.com&gt;', @email_address.with_name
   end
-  
-  def test_should_set_name_from_attributes
-    assert_equal 'bob', EmailAddress.new(:name =&gt; 'bob').name
+end
+
+class EmailAddressAsAClassTest &lt; Test::Unit::TestCase
+  def test_should_be_able_to_split_address_containing_name
+    name, spec = EmailAddress.split_address('John Smith &lt;john.smith@gmail.com&gt;')
+    assert_equal 'John Smith', name
+    assert_equal 'john.smith@gmail.com', spec
   end
   
-  def test_should_return_spec_for_with_name_when_name_is_blank
-    e = email_addresses(:bob)
-    assert_equal e.spec, e.with_name
+  def test_should_be_able_to_split_address_not_containing_name
+    name, spec = EmailAddress.split_address('john.smith@gmail.com')
+    assert_nil name
+    assert_equal 'john.smith@gmail.com', spec
   end
   
-  def test_should_return_name_and_spec_for_with_name_when_name_is_not_blank
-    e = email_addresses(:bob)
-    e.instance_eval do
-      def name
-        'Bob'
-      end
-    end
-    
-    assert_equal 'Bob &lt;bob@bob.com&gt;', e.with_name
+  def test_should_be_able_to_find_an_existing_email_by_address
+    email_address = create_email_address(:address =&gt; 'John Smith &lt;john.smith@gmail.com&gt;')
+    assert_equal email_address, EmailAddress.find_or_create_by_address('John Smith &lt;john.smith@gmail.com&gt;')
   end
   
-  def test_should_use_spec_for_stringification
-    e = email_addresses(:bob)
-    assert_equal e.spec, e.to_s
+  def test_should_be_able_to_create_from_a_new_address
+    email_address = EmailAddress.find_or_create_by_address('John Smith &lt;john.smith@gmail.com&gt;')
+    assert !email_address.new_record?
+    assert_equal 'John Smith', email_address.name
+    assert_equal 'john.smith@gmail.com', email_address.spec
   end
 end</diff>
      <filename>test/unit/email_address_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,89 +1,29 @@
-require File.dirname(__FILE__) + '/../test_helper'
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
 
-class EmailTest &lt; Test::Unit::TestCase
-  fixtures :users, :email_addresses, :messages, :message_recipients, :state_changes
-  
-  def test_should_be_valid
-    assert_valid messages(:sent_from_bob)
-  end
-  
-  def test_should_require_sender_spec
-    assert_invalid messages(:sent_from_bob), :sender_spec, nil
-  end
-  
-  def test_should_require_minimum_length_for_sender_spec
-    assert_invalid messages(:sent_from_bob), :sender_spec, 'ab'
-    assert_valid messages(:sent_from_bob), :sender_spec, 'a@a'
-  end
-  
-  def test_should_require_maximum_length_for_sender_spec
-    assert_invalid messages(:sent_from_bob), :sender_spec, 'a' * 300 + '@' + 'a' * 20
-    assert_valid messages(:sent_from_bob), :sender_spec, 'a' * 300 + '@' + 'a' * 19
-  end
-  
-  def test_should_require_specific_format_for_sender_spec
-    assert_invalid messages(:sent_from_bob), :sender_spec, 'aaaaaaaaaa'
-    assert_valid messages(:sent_from_bob), :sender_spec, 'aaa@aaa.com'
-  end
-  
-  def test_to_should_create_email_recipient
-    assert_instance_of EmailRecipient, messages(:sent_from_bob).to.build
-  end
-  
-  def test_cc_should_create_email_recipient
-    assert_instance_of EmailRecipient, messages(:sent_from_bob).cc.build
-  end
-  
-  def test_bcc_should_create_email_recipient
-    assert_instance_of EmailRecipient, messages(:sent_from_bob).bcc.build
-  end
-  
-  def test_sender_should_be_spec_if_arbitrary_email_address_used
-    assert_equal 'stranger@somewhere.com', messages(:unsent_from_stranger).sender
-  end
-  
-  def test_sender_should_be_model_if_known_email_address_used
-    assert_equal email_addresses(:bob), messages(:sent_from_bob).sender
-  end
-  
-  def test_should_set_sender_spec_if_sender_is_arbitrary_email_address
-    email = messages(:unsent_from_stranger)
-    email.sender = 'stranger@somewhereelse.com'
-    assert_equal 'stranger@somewhereelse.com', email.sender_spec
-    assert_nil email.sender_id
-    assert_nil email.sender_type
-  end
-  
-  def test_should_set_sender_and_sender_spec_if_sender_is_known_email_address
-    email = messages(:unsent_from_stranger)
-    email.sender_spec = nil
-    email.sender = email_addresses(:john)
-    assert_equal 2, email.sender_id
-    assert_equal 'EmailAddress', email.sender_type
-    assert_equal 'john@john.com', email.sender_spec
-  end
-  
-  def test_sender_email_address_should_convert_sender_spec_if_arbitrary_email_address_used
-    email_address = messages(:unsent_from_stranger).sender_email_address
-    assert_instance_of EmailAddress, email_address
-    assert_equal 'stranger@somewhere.com', email_address.spec
-  end
-  
-  def test_sender_email_address_should_use_sender_if_known_email_address_used
-    email_address = messages(:sent_from_bob).sender_email_address
-    assert_instance_of EmailAddress, email_address
-    assert_equal 'bob@bob.com', email_address.spec
-  end
-  
-  def test_reply_should_use_sender_spec_for_sender_if_arbitrary_email_address_used
-    message = messages(:unsent_from_stranger)
-    reply = message.reply
-    assert_equal 'stranger@somewhere.com', reply.sender
-  end
-  
-  def test_forward_should_use_sender_spec_for_sender_if_arbitrary_email_address_used
-    message = messages(:unsent_from_stranger)
-    forward = message.forward
-    assert_equal 'stranger@somewhere.com', forward.sender
+class EmailAfterBeingDeliveredTest &lt; Test::Unit::TestCase
+  def setup
+    ActionMailer::Base.deliveries = []
+    
+    @email = new_email(
+      :subject =&gt; 'Hello',
+      :body =&gt; 'How are you?',
+      :sender =&gt; create_email_address(:spec =&gt; 'webmaster@localhost'),
+      :to =&gt; create_email_address(:spec =&gt; 'partners@localhost'),
+      :cc =&gt; create_email_address(:spec =&gt; 'support@localhost'),
+      :bcc =&gt; create_email_address(:spec =&gt; 'feedback@localhost')
+    )
+    assert @email.deliver!
+  end
+  
+  def test_should_send_mail
+    assert ActionMailer::Base.deliveries.any?
+    
+    delivery = ActionMailer::Base.deliveries.first
+    assert_equal 'Hello', delivery.subject
+    assert_equal 'How are you?', delivery.body
+    assert_equal ['webmaster@localhost'], delivery.from
+    assert_equal ['partners@localhost'], delivery.to
+    assert_equal ['support@localhost'], delivery.cc
+    assert_equal ['feedback@localhost'], delivery.bcc
   end
 end</diff>
      <filename>test/unit/email_test.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>app/mailers/application_mailer.rb</filename>
    </removed>
    <removed>
      <filename>app/models/email_recipient.rb</filename>
    </removed>
    <removed>
      <filename>app/models/email_recipient_build_extension.rb</filename>
    </removed>
    <removed>
      <filename>db/bootstrap/events.yml</filename>
    </removed>
    <removed>
      <filename>db/bootstrap/states.yml</filename>
    </removed>
    <removed>
      <filename>db/migrate/002_add_email_specs.rb</filename>
    </removed>
    <removed>
      <filename>db/migrate/003_add_email_recipient_specs.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/app/models/department.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/app/models/user.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/db/migrate/001_create_users.rb</filename>
    </removed>
    <removed>
      <filename>test/app_root/db/migrate/002_create_departments.rb</filename>
    </removed>
    <removed>
      <filename>test/fixtures/departments.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/email_addresses.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/message_recipients.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/messages.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/state_changes.yml</filename>
    </removed>
    <removed>
      <filename>test/fixtures/users.yml</filename>
    </removed>
    <removed>
      <filename>test/unit/application_mailer_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/email_recipient_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/has_emails_test.rb</filename>
    </removed>
    <removed>
      <filename>test/unit/recipient_extension_test.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>64aaafc4cecefdcdf9d8584fe309bb5937af3820</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </author>
  <url>http://github.com/pluginaweek/has_emails/commit/c0d234251d5b43b71a65c90bc2871385f73c6fe9</url>
  <id>c0d234251d5b43b71a65c90bc2871385f73c6fe9</id>
  <committed-date>2008-05-04T16:14:45-07:00</committed-date>
  <authored-date>2008-05-04T16:14:45-07:00</authored-date>
  <message>Update to latest has_messages api
Simplify by removing support for models other than EmailAddresses in Emails
Updated documentation</message>
  <tree>02df64e50bd49b6709f3c642484be44aa7cab0f0</tree>
  <committer>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </committer>
</commit>
