<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,16 +1,54 @@
-This is a silly plugin to let you take a shortcut.  Here's the blog post example:
+Find-Param
+==========
 
-class Post &lt; ActiveRecord::Base
-  define_find_param :slug
-end
+This is a simple plugin to let you easily define a parameter to use for
+#to_param, and also define a finder to access that same parameter.
 
-This will set the to_param to be post.slug and add the following method to the Post model:
+This plugin is most useful for situations where you want to override the usage
+of ID as the default parameter value. Using a slug creates URLs that can be
+friendlier for humans and bots alike.
 
-def self.find_by_param(*args)
-  find_by_slug(*args)
-end
 
-You can also pass :raise_on_not_found =&gt; true to have it raise ActiveRecord::RecordNotFound
-if the result set is empty.
+Getting Started
+---------------
 
-Like I said, it's silly, but I find myself using this pattern a lot.
+Here we define the find param to be a slug:
+
+  class Post &lt; ActiveRecord::Base
+    find_param :slug
+  end
+
+This will set the #to_param to be #slug and add a finder to the model called
+#find_by_param that can be used in your controllers to fetch records using
+params[:id].
+
+  class PostController
+    before_filter :find_post, :only =&gt; %(show edit update destroy)
+
+    def find_post
+      find_by_param(params[:id])
+    end
+  end
+
+
+Options
+-------
+
+To have your find param automatically populated on record creation, use the
+:initialize_with option.
+
+  class Post &lt; ActiveRecord::Base
+    find_param :slug, :initialize_with =&gt; :title
+  end
+
+This will use the title property to populate the slug. By default this value is
+lowercased and all whitespace and special characters are replaced by hyphens.
+To specify your own formatted for the find param, there a :using option that
+accepts a proc.
+
+  class Post &lt; ActiveRecord::Base
+    find_param :slug, :initialize_with =&gt; :title, :using =&gt; Proc.new { |value| value.upcase }
+  end
+
+You can also pass :raise_on_not_found =&gt; true to have it raise an
+ActiveRecord::RecordNotFound erorr when the result set is empty.</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -1,2 +1,3 @@
 require 'find_by_param'
-ActiveRecord::Base.send(:extend, FindByParam::ClassMethods)
\ No newline at end of file
+
+ActiveRecord::Base.send(:extend, FindByParam::ClassMethods)</diff>
      <filename>init.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,43 +1,52 @@
 module FindByParam
-  
-  ##
   # Catch-all error for any issue arrising within the FindByParam plugin.
-  #
   class Error &lt; RuntimeError; end
-  
-  ##
-  # Raised when the param requested is not in the model's table definition.
-  # For example:
-  #
-  #     class WillRaiseError &lt; ActiveRecord::Base
-  #       define_find_param :undefined_column
-  #     end
+
+  # Raised when the param requested is not in the model's table definition:
   #
+  #   class WillRaiseError &lt; ActiveRecord::Base
+  #     define_find_param :undefined_column
+  #   end
   class ColumnNotFoundError &lt; Error; end
-  
+
   module ClassMethods
-    def define_find_param(param, options={})
-      param = param.to_s
-      options[:raise_on_not_found] ||= false
-      if column_names.include?(param)
-        write_inheritable_attribute :find_parameter, param
-        write_inheritable_attribute :find_param_options, options
-        bl = lambda do |args|
-          results = send(&quot;find_by_#{read_inheritable_attribute(:find_parameter)}&quot;, *args)
-          raise ActiveRecord::RecordNotFound if options[:raise_on_not_found] &amp;&amp; (results.nil? or (results.is_a?(Array) &amp;&amp; results.size == 0))
-          return results
+    # Defines a finder (#find_by_param) using the specified parameter name.
+    # Also, defines #to_param to use the same parameter.
+    #
+    # Options:
+    # * &lt;tt&gt;:raise_on_not_found&lt;/tt&gt;: cases ActiveRecord::RecordNotFound to be raised when no record is found
+    # * &lt;tt&gt;:initialize_with&lt;/tt&gt;: the name of parameter to use to initialize the find parameter when a new record is created
+    # * &lt;tt&gt;:using&lt;/tt&gt;: a proc used to manipulated the initialization parameter before setting the find parameter
+    def find_param(param, options={})
+      raise_on_not_found = options.delete(:raise_on_not_found)
+      initialize_with = options.delete(:initialize_with)
+      raise ColumnNotFoundError unless column_names.include?(param.to_s)
+
+      self.class.send(:define_method, :find_by_param) do |args|
+        returning send(&quot;find_by_#{param}&quot;, *args) do |results|
+          raise ActiveRecord::RecordNotFound if raise_on_not_found &amp;&amp; (results.nil? || (results.is_a?(Array) &amp;&amp; results.size == 0))
         end
-        self.class.send(:define_method, 'find_by_param', &amp;bl)
-      else
-        raise ColumnNotFoundError
       end
-      self.send(:include, FindByParam::InstanceMethods)
+
+      self.send(:alias_method, :to_param, param)
+
+      initialize_parameter(param, initialize_with, options) if initialize_with
     end
-  end
-  
-  module InstanceMethods
-    def to_param
-      self.send(self.class.read_inheritable_attribute(:find_parameter))
+
+    def initialize_parameter(param, source, options={})
+      raise ColumnNotFoundError unless column_names.include?(source.to_s)
+      using = options.delete(:using)
+
+      self.send(:define_method, :set_param) do
+        value = self.send(source)
+        value = using.respond_to?(:call) ? using.call(value) : value.downcase.gsub(/[^\w]+/, '-')
+
+        self.send(&quot;#{param}=&quot;,  value)
+      end
+      self.send(:private, :set_param)
+
+      self.send(:before_create, :set_param)
     end
+    private :initialize_parameter
   end
-end
\ No newline at end of file
+end</diff>
      <filename>lib/find_by_param.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,48 +2,75 @@ require File.join(File.dirname(__FILE__), 'test_helper')
 
 class FindByParamTest &lt; Test::Unit::TestCase
   def setup
-    BlogPost.create(:slug =&gt; 'adam-west', :title =&gt; 'Adam West')
-    BlogPost.create(:slug =&gt; 'burt-ward', :title =&gt; 'Burt Ward')
-    BlogPost.send(:define_find_param, 'slug')
+    Post.create(:slug =&gt; 'adam-west', :title =&gt; 'Adam West')
+    Post.create(:slug =&gt; 'burt-ward', :title =&gt; 'Burt Ward')
+    Post.find_param(:slug)
   end
   
   def teardown
-    BlogPost.delete_all
+    Post.delete_all
   end
   
   def test_plugin_loaded_correctly
-    assert_kind_of FindByParam::ClassMethods, BlogPost
-    assert BlogPost.respond_to?(:find_by_param)
+    assert_kind_of FindByParam::ClassMethods, Post
+  end
+
+  def test_find_by_param_was_defined
+    assert Post.respond_to?(:find_by_param)
+  end
+
+  def test_find_by_param_is_defined_in_subclasses
+    assert Blog.respond_to?(:find_by_param)
   end
   
   def test_returns_valid_data
-    bp = BlogPost.find(:first, :conditions =&gt; 'slug = &quot;adam-west&quot;')
-    assert_equal BlogPost.find_by_param('adam-west'), bp
+    post = Post.find_by_param('adam-west')
+    assert_equal Post.find_by_slug('adam-west'), post
   end
   
-  def test_can_define_find_parameter
-    BlogPost.send('define_find_param', 'title')
-    bp = BlogPost.find(:first, :conditions =&gt; {:slug =&gt; 'adam-west'})
-    assert_equal BlogPost.find_by_param('Adam West'), bp
+  def test_can_define_find_parameter_with_symbol
+    Post.find_param(:title)
+    post = Post.find_by_param('Adam West')
+    assert_equal Post.find_by_title('Adam West'), post
   end
   
+  def test_can_define_find_parameter_with_string
+    Post.find_param('title')
+    post = Post.find_by_param('Adam West')
+    assert_equal Post.find_by_title('Adam West'), post
+  end
+
   def test_correctly_goes_to_param
-    bp = BlogPost.find(:first, :conditions =&gt; {:slug =&gt; 'adam-west'})
-    assert_equal bp.to_param, 'adam-west'
+    post = Post.find(:first, :conditions =&gt; { :slug =&gt; 'adam-west' })
+    assert_equal 'adam-west', post.to_param
   end
   
   def test_raises_on_not_found_if_specified
-    BlogPost.send(:define_find_param, 'slug', :raise_on_not_found =&gt; true)
+    Post.find_param('slug', :raise_on_not_found =&gt; true)
     assert_raises ActiveRecord::RecordNotFound do
-      BlogPost.find_by_param('in ur tests, failing')
+      Post.find_by_param('non-existent-slug')
     end
   end
   
   def test_raises_column_not_found_error_when_given_undefined_column
     assert_raise(FindByParam::ColumnNotFoundError) do
-      BlogPost.send(:define_find_param, 'bad_column_name')
+      Post.find_param(:bad_column_name)
     end
+  end
+
+  def test_column_not_found_error_is_a_find_by_param_error
     assert_kind_of FindByParam::Error, FindByParam::ColumnNotFoundError.new
   end
   
-end
\ No newline at end of file
+  def test_initializes_param_on_create
+    Post.find_param(:slug, :initialize_with =&gt; :title)
+    blog_post = Post.create(:title =&gt; 'A Test Post')
+    assert_equal 'a-test-post', blog_post.slug
+  end
+
+  def test_initializes_param_on_create_using_a_custom_initializer
+    Post.find_param(:slug, :initialize_with =&gt; :title, :using =&gt; Proc.new { |value| value.upcase.gsub(/\s+/, '_') })
+    blog_post = Post.create(:title =&gt; 'A Test Post')
+    assert_equal 'A_TEST_POST', blog_post.slug
+  end
+end</diff>
      <filename>test/find_by_param_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-$LOAD_PATH.unshift 'lib/'
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
 
 require 'rubygems'
 require 'multi_rails_init'
@@ -15,17 +15,16 @@ end
 RAILS_ROOT = '.'    unless defined? RAILS_ROOT
 RAILS_ENV  = 'test' unless defined? RAILS_ENV
 
-
 ActiveRecord::Base.send(:extend, FindByParam::ClassMethods)
-ActiveRecord::Base.establish_connection(:adapter =&gt; &quot;sqlite3&quot;, :dbfile =&gt; &quot;:memory:&quot;)
+ActiveRecord::Base.establish_connection(:adapter =&gt; 'sqlite3', :dbfile =&gt; ':memory:')
 ActiveRecord::Base.logger = Logger.new(STDOUT)
 
 ActiveRecord::Schema.define(:version =&gt; 1) do
-  create_table :blog_posts do |t|
-    t.column :slug, :string
+  create_table :posts do |t|
     t.column :title, :string
+    t.column :slug, :string
   end
 end
 
-class BlogPost &lt; ActiveRecord::Base
-end
\ No newline at end of file
+class Post &lt; ActiveRecord::Base ; end
+class Blog &lt; Post ; end</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5d01367e7c9cc5ae02ddd0a5507746d471a5bd6d</id>
    </parent>
  </parents>
  <author>
    <name>Tyler Hunt</name>
    <email>tyler@halogenguides.com</email>
  </author>
  <url>http://github.com/tylerhunt/find-param/commit/085b4bc66aea7723a7880b9d2fc33eaa8a19a28a</url>
  <id>085b4bc66aea7723a7880b9d2fc33eaa8a19a28a</id>
  <committed-date>2008-05-29T11:13:48-07:00</committed-date>
  <authored-date>2008-05-29T11:12:43-07:00</authored-date>
  <message>Added support for automatic initialization using :initialize_with.
Changed the public method name to simply be #find_param.
Refactored to remove dependence on class inheritable attributes.
Improved the documentation.</message>
  <tree>7b6e3cf23b3d470925793962a46b746bdb14a0e3</tree>
  <committer>
    <name>Tyler Hunt</name>
    <email>tyler@halogenguides.com</email>
  </committer>
</commit>
