<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/fixtures/posts.yml</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -4,7 +4,7 @@ has_tokens
 Instalation
 -----------
 
-1) Install the plugin with `script/plugin install http://svn.simplesideias.com.br/general/rails/plugins/has_tokens`
+1) Install the plugin with `script/plugin install git://github.com/fnando/has_tokens.git`
 2) Generate a migration with `script/generate migration create_tokens` and add the following code:
 
 class CreateTokens &lt; ActiveRecord::Migration
@@ -29,7 +29,6 @@ class CreateTokens &lt; ActiveRecord::Migration
   end
 end
 
-
 3) Run the migrations with `rake db:migrate`
 
 Usage
@@ -57,6 +56,10 @@ user.add_token(:activate)
 # uses custom size (up to 32)
 user.add_token(:activate, :size =&gt; 20)
 
+# create token with arbitrary data
+data = {:action =&gt; 'do something'}
+user.add_token(:activate, :data =&gt; data.to_json)
+
 # find token by name
 user.find_token_by_name(:reset_account)
 
@@ -78,4 +81,16 @@ User.generate_token
 # remove a token by its name
 user.remove_token(:activate)
 
+# find user by token
+User.find_by_token(:activate, 'ea2f14aeac40')
+
+# find user by valid token (same name, same hash, not expired)
+User.find_by_valid_token(:activate, 'ea2f14aeac40')
+
+# find a token using class scope
+User.find_token(:activate, 'ea2f14aeac40')
+
+# Token hash
+token.to_s #=&gt; ea2f14aeac40
+
 Copyright (c) 2008 Nando Vieira, released under the MIT license</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -9,11 +9,11 @@ module SimplesIdeias
       
       module ClassMethods
         def has_tokens
-          write_inheritable_attribute(:tokenize_me_options, {
+          write_inheritable_attribute(:has_tokens_options, {
             :token_type =&gt; ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s
           })
           
-          class_inheritable_reader :tokenize_me_options
+          class_inheritable_reader :has_tokens_options
           
           has_many :tokens, :as =&gt; :tokenizable, :dependent =&gt; :destroy
           include SimplesIdeias::Acts::Tokens::InstanceMethods
@@ -30,33 +30,50 @@ module SimplesIdeias
           token
         end
         
-        def find_by_token(name, code)
-          token = Token.find(:first, :conditions =&gt; {
-            :tokenizable_type =&gt; tokenize_me_options[:token_type],
-            :name =&gt; name.to_s,
-            :token =&gt; code
-          })
+        # Find a token
+        # User.find_token(:activation, 'abcdefg')
+        # User.find_token(:name =&gt; activation, :token =&gt; 'abcdefg')
+        # User.find_token(:name =&gt; activation, :token =&gt; 'abcdefg', :tokenizable_id =&gt; 1)
+        def find_token(*args)
+          unless (options = args.first).is_a?(Hash)
+            options = {:name =&gt; args.first, :token =&gt; args.last.to_s}
+          end
           
-          return nil unless token
-          
-          find(:first, :conditions =&gt; {:id =&gt; token.tokenizable_id})
+          options[:name] = options[:name].to_s
+          options.merge!({:tokenizable_type =&gt; has_tokens_options[:token_type]})
+          Token.find(:first, :conditions =&gt; options)
+        end
+        
+        # Find object by token
+        # User.find_by_token(:activation, 'abcdefg')
+        def find_by_token(name, token)
+          t = find_token(:name =&gt; name.to_s, :token =&gt; token)
+          return nil unless t
+          t.tokenizable
+        end
+        
+        # Find object by valid token (same name, same hash, not expired)
+        # User.find_by_valid_token(:activation, 'abcdefg')
+        def find_by_valid_token(name, token)
+          t = find_token(:name =&gt; name.to_s, :token =&gt; token)
+          return nil unless t &amp;&amp; !t.expired? &amp;&amp; t.hash == token
+          t.tokenizable
         end
       end
       
       module InstanceMethods
+        # Object has a valid token (same name, same hash, not expired)
+        # @user.valid_token?(:activation, 'abcdefg')
         def valid_token?(name, token)
           t = find_token_by_name(name)
-          return false unless t
-          return false if t.expires_at &lt; Time.now
-          return false unless t.token == token
-          return true
+          !!(t &amp;&amp; !t.expired? &amp;&amp; t.hash == token)
         end
         
         def remove_token(name)
           Token.delete_all([
             &quot;tokenizable_id = ? AND tokenizable_type = ? AND name = ?&quot;, 
             self.id, 
-            self.class.tokenize_me_options[:token_type], 
+            self.class.has_tokens_options[:token_type], 
             name.to_s
           ])
         end
@@ -84,8 +101,10 @@ module SimplesIdeias
           self.tokens.find_by_name(name.to_s)
         end
         
-        def find_token(token)
-          self.tokens.find(:first, :conditions =&gt; {:token =&gt; token.to_s})
+        # Find a token
+        # @user.find_token(:activation, 'abcdefg')
+        def find_token(name, token)
+          self.class.find_token(:tokenizable_id =&gt; self.id, :name =&gt; name.to_s, :token =&gt; token)
         end
       end
     end</diff>
      <filename>lib/has_tokens.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,4 +4,4 @@ class String
   def to_sha1
     Digest::SHA1.hexdigest(self.dup)
   end
-end
+end
\ No newline at end of file</diff>
      <filename>lib/string_ext.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,9 +5,12 @@ class Token &lt; ActiveRecord::Base
     token
   end
   
+  def to_s
+    hash
+  end
+  
   def expired?
-    return true if expires_at &amp;&amp; expires_at &lt; Time.now
-    return false
+    expires_at &amp;&amp; expires_at &lt; Time.now
   end
   
   def self.delete_expired</diff>
      <filename>lib/token.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,18 +1,23 @@
 require &quot;spec_helper&quot;
 
 # unset models used for testing purposes
-Object.unset_class('User')
+Object.unset_class('User', 'Post')
 
 class User &lt; ActiveRecord::Base
   has_tokens
 end
 
+class Post &lt; ActiveRecord::Base
+  has_tokens
+end
+
 describe &quot;has_tokens&quot; do
-  fixtures :users
+  fixtures :users, :posts
   
   before(:each) do
     @user = users(:homer)
     @another_user = users(:bart)
+    @post = posts(:how_to_make_donuts)
     @expire = 3.days.from_now
   end
   
@@ -39,12 +44,12 @@ describe &quot;has_tokens&quot; do
     end
     
     it &quot;should find token by its name&quot; do
-      @user.add_token(:uid)
-      @user.find_token_by_name(:uid).should be_an_instance_of(Token)
+      token = @user.add_token(:uid)
+      @user.find_token_by_name(:uid).should == token
     end
     
     it &quot;should be nil when no token is found&quot; do
-      @user.find_token('abcdef').should be_nil
+      @user.find_token(:uid, 'abcdef').should be_nil
       @user.find_token_by_name(:uid).should be_nil
     end
     
@@ -57,9 +62,9 @@ describe &quot;has_tokens&quot; do
       @user.valid_token?(:uid, 'invalid').should be_false
     end
     
-    it &quot;should find token by its hash&quot; do
+    it &quot;should find token by its name and hash&quot; do
       token = @user.add_token(:uid)
-      @user.find_token(token.hash).should be_an_instance_of(Token)
+      @user.find_token(:uid, token.hash).should == token
     end
     
     it &quot;should not be expired when have no expiration date&quot; do
@@ -125,4 +130,37 @@ describe &quot;has_tokens&quot; do
     token = @user.add_token(:uid)
     token.hash.should == token.token
   end
+  
+  it &quot;should find user by token&quot; do
+    token = @user.add_token(:uid)
+    User.find_by_token(:uid, token.hash).should == @user
+  end
+  
+  it &quot;should return user by its valid token without expiration time&quot; do
+    token = @user.add_token(:uid)
+    User.find_by_valid_token(:uid, token.hash).should == @user
+  end
+  
+  it &quot;should return user by its valid token with expiration time&quot; do
+    token = @user.add_token(:uid, :expires_at =&gt; @expire)
+    User.find_by_valid_token(:uid, token.hash).should == @user
+  end
+  
+  it &quot;should find token using class method with one argument (hash only)&quot; do
+    token = @user.add_token(:uid)
+    User.find_token(:name =&gt; :uid, :token =&gt; token.hash).should == token
+  end
+  
+  it &quot;should not conflict with other models&quot; do
+    user_token = @user.add_token(:uid)
+    post_token = @post.add_token(:uid)
+    
+    User.find_token(post_token.to_s).should == nil
+    User.find_token(:name =&gt; :uid)
+  end
+  
+  it &quot;to_s should return hash&quot; do
+    token = @user.add_token(:uid)
+    token.to_s.should == token.hash
+  end
 end
\ No newline at end of file</diff>
      <filename>test/has_tokens_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,10 @@ ActiveRecord::Schema.define(:version =&gt; 0) do
     t.string :name
   end
   
+  create_table :posts do |t|
+    t.string :title
+  end
+  
   create_table :tokens do |t|
     t.integer :tokenizable_id, :null =&gt; false
     t.string :tokenizable_type, :name, :null =&gt; false</diff>
      <filename>test/schema.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c07e42f23c6f09ebcc67ca4cf2896d988a5e6ffb</id>
    </parent>
  </parents>
  <author>
    <name>Nando Vieira</name>
    <email>fnando.vieira@gmail.com</email>
  </author>
  <url>http://github.com/fnando/has_tokens/commit/a9f633b98d06acc55f5e771e67fb098909c1ae82</url>
  <id>a9f633b98d06acc55f5e771e67fb098909c1ae82</id>
  <committed-date>2008-08-08T15:45:34-07:00</committed-date>
  <authored-date>2008-08-08T15:45:34-07:00</authored-date>
  <message>Added more tests. Added find_by_valid_token and find_token class methods.</message>
  <tree>344768a19072488baddb9758848f10a3c3c5dc12</tree>
  <committer>
    <name>Nando Vieira</name>
    <email>fnando.vieira@gmail.com</email>
  </committer>
</commit>
