<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,8 +1,15 @@
 module DataMapper
   module Is
     module Slug
+      class InvalidSlugSource &lt; Exception
+      end
+      
       DEFAULT_SLUG_SIZE = 50
       
+      DEFAULT_SLUG_OPTIONS = {
+        :permanent_slug =&gt; true
+      }
+      
       # @param [String] str A string to escape for use as a slug
       # @return [String] an URL-safe string
       def self.escape(str)
@@ -36,7 +43,9 @@ module DataMapper
       # +permanent_slug+::
       #   Permanent slugs are not changed even if the source property has
       # +source+::
-      #   The property on the model to use as the source of the generated slug
+      #   The property on the model to use as the source of the generated slug,
+      #   or an instance method defined in the model, the method must return
+      #   a string or nil.
       # +size+::
       #   The length of the +slug+ property
       #
@@ -45,31 +54,11 @@ module DataMapper
         extend  DataMapper::Is::Slug::ClassMethods
         include DataMapper::Is::Slug::InstanceMethods
         
-        # merge in default options
-        options = { :permanent_slug =&gt; true }.merge(options)
-        
-        # must at least specify a source property to generate the slug
-#        raise 'You must specify a :source to generate slug' unless options.include?(:source)
-        raise 'You must specify a :source to generate slug' unless options[:source]
-        
-        # make sure the source property exsists
-        source_property = properties.detect do |p|
-          p.name == options[:source].to_sym &amp;&amp; p.type == String
-        end
+        @slug_options = DEFAULT_SLUG_OPTIONS.merge(options)
+        raise InvalidSlugSource('You must specify a :source to generate slug.') unless slug_source
 
-        # Find the string length so that slug can adapt size dynamically 
-        # depending on the source property, or use the default slug size.
-        options[:size] ||= source_property &amp;&amp;
-                             source_property.size ||
-                             DataMapper::Is::Slug::DEFAULT_SLUG_SIZE
-        
-        # save as class variable for later...
-        @slug_options = options
-        
-        unless slug_property
-          property :slug, String, :size =&gt; options[:size], :unique =&gt; true
-        end
-         
+        slug_options[:size] ||= get_slug_size
+        property(:slug, String, :size =&gt; slug_options[:size], :unique =&gt; true) unless slug_property
         before :save, :generate_slug
       end
 
@@ -81,7 +70,7 @@ module DataMapper
         end
         
         def slug_source
-          slug_options[:source].to_sym
+          slug_options[:source] ? slug_options[:source].to_sym : nil
         end
         
         def slug_source_property
@@ -99,6 +88,10 @@ module DataMapper
             p.name == name &amp;&amp; p.type == String
           end
         end
+        
+        def get_slug_size
+          slug_source_property &amp;&amp; slug_source_property.size || DataMapper::Is::Slug::DEFAULT_SLUG_SIZE
+        end
       end # ClassMethods
 
       module InstanceMethods
@@ -122,22 +115,34 @@ module DataMapper
           self.class.slug_property
         end
         
-        def generate_slug
-          source = self.send(slug_source)
-          
-          raise ':source is invalid!' unless slug_source_property || self.respond_to?(slug_source)
-                              
-          return if permanent_slug? &amp;&amp; self.slug || source.nil?
-          
-          # we turn the source into a slug here
-          self.slug = DataMapper::Is::Slug.escape(source)
-          
-          self.slug = &quot;#{self.slug}-2&quot; if self.class.first(:slug =&gt; self.slug)
+        def slug_source_value
+          self.send(slug_source)
+        end
+        
+        # The slug is not stale if 
+        # 1. the slug is permanent, and slug column has something valid in it
+        # 2. the slug source value is nil or empty
+        def stale_slug?
+          !((permanent_slug? &amp;&amp; slug &amp;&amp; !slug.empty?) || (slug_source_value.nil? || slug_source_value.empty?))
+        end
+        
+        private
+                
+        def make_unique_slug!
+          unique_slug = DataMapper::Is::Slug.escape(slug_source_value)
+          unique_slug = &quot;#{unique_slug}-2&quot; if self.class.first(:slug =&gt; unique_slug)
 
-          while self.class.first(:slug =&gt; self.slug) != nil
-            i = self.slug[-1..-1].to_i + 1
-            self.slug = self.slug[0..-2] + i.to_s
+          while(self.class.first(:slug =&gt; unique_slug))
+            i = unique_slug[-1..-1].to_i + 1
+            unique_slug = unique_slug[0..-2] + i.to_s
           end
+          unique_slug
+        end
+        
+        def generate_slug
+          raise InvalidSlugSource('Invalid slug source.') unless slug_source_property || self.respond_to?(slug_source)
+          return unless stale_slug?
+          self.slug = make_unique_slug!
         end
       end # InstanceMethods
       </diff>
      <filename>lib/dm-is-slug/is/slug.rb</filename>
    </modified>
    <modified>
      <diff>@@ -113,6 +113,7 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
  
       user.email = &quot;changed@ekohe.com&quot;
       user.should be_dirty
+
       user.save.should be_true
       user.slug.should == &quot;changed&quot;
       user.destroy
@@ -155,12 +156,9 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
     end
  
     it &quot;should find model using get method using id&quot; do
-      u = User.get(@u1.id)
+      u = User.get(@u1.id)      
       u.should_not be_nil
       u.should == @u1
-
-      Post.get(&quot;my-first-shinny-blog-post&quot;).should == @p1
-      @u1.posts.get(&quot;my-first-shinny-blog-post&quot;).should == @p1
     end
  
     it &quot;should find model using get method using id with non-slug models&quot; do</diff>
      <filename>spec/integration/slug_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>3e5d855ea849cad2230b320d439e9086cd7b0505</id>
    </parent>
  </parents>
  <author>
    <name>Aaron</name>
    <email>aq1018@gmail.com</email>
  </author>
  <url>http://github.com/aq1018/dm-is-slug/commit/68312c75ed7efeca81d39e3fca68a69a6b57c286</url>
  <id>68312c75ed7efeca81d39e3fca68a69a6b57c286</id>
  <committed-date>2009-01-12T02:54:55-08:00</committed-date>
  <authored-date>2009-01-12T02:54:55-08:00</authored-date>
  <message>made it shorter</message>
  <tree>3f5121619cb3a2aa10362d481b83a344a4c261d8</tree>
  <committer>
    <name>Aaron</name>
    <email>aq1018@gmail.com</email>
  </committer>
</commit>
