<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/abstract_unit.rb</filename>
    </added>
    <added>
      <filename>test/database.yml</filename>
    </added>
    <added>
      <filename>test/debug.log</filename>
    </added>
    <added>
      <filename>test/dummy_classes.rb</filename>
    </added>
    <added>
      <filename>test/fixtures/cars.yml</filename>
    </added>
    <added>
      <filename>test/schema.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -58,7 +58,9 @@ class User &lt; ActiveRecord::Base
   caches_method :costy_method, :until =&gt; :midnight
 end
 
-:until also accepts Time and date objects
+:until also accepts Time and date objects but I'm considering removing until or have it 
+support things like :midnight because otherwise it would cause errors after the specified
+date or time have passed.
 
 To expire cached instance methods
 @user.expire_method :costy_method
@@ -80,4 +82,7 @@ caches_class_method also supports the :for and :until options
 To expire class methods
 User.expire_class_method :costy_class_method
 
+Test
+====
+rake test:plugins DB=sqlite3
 Copyright (c) 2008 humanzz (Ahmed Sobhi), released under the MIT license</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -1,12 +1,15 @@
 class MethodCacher
-  def self.read(key)
+  def self.read(key, raise_exceptions = false)
     value = Rails.cache.read(key)
     begin
       value = Marshal.load(value) unless value.nil?
     rescue ArgumentError =&gt; e
       #autorequiring types that have not been yet required
       match = /#&lt;ArgumentError: undefined class\/module (.*)&gt;/.match(e.inspect)
-      raise e if match.nil?
+      if match.nil?
+        raise if raise_exceptions
+        return nil
+      end  
       #match[1] can take the forms: Item, Product::Item, Item::, Product::Item::
       missing_constants = match[1].split('::')
       if missing_constants.length == 1
@@ -22,22 +25,24 @@ class MethodCacher
     value
   rescue MemCache::MemCacheError =&gt; err
     ActiveRecord::Base.logger.info &quot;MethodCacher.read MemCache Error: #{err.message}&quot;
+    raise if raise_exceptions
     nil
   end
   
-  def self.write(key, value, expiry = 0)
+  def self.write(key, value, expiry = 0, raise_exception = false)
     Rails.cache.write(key,Marshal.dump(value), :expires_in =&gt; expiry)
     value
   rescue MemCache::MemCacheError =&gt; err
     ActiveRecord::Base.logger.debug &quot;MethodCacher.write MemCache Error: #{err.message}&quot;
+    raise if raise_exceptions
     nil
   end
   
-  def self.delete(key)
+  def self.delete(key, raise_exceptions = false)
     Rails.cache.delete(key)
-    nil
   rescue MemCache::MemCacheError =&gt; err
     ActiveRecord::Base.logger.debug &quot;MethodCacher.delete MemCache Error: #{err.message}&quot;
+    raise if raise_exceptions
     nil
   end
 end
@@ -58,6 +63,8 @@ module ActiveRecord
         def caches_method(method, options = {})
           include InstanceMethods
           return unless ActionController::Base.perform_caching
+          options[:until] = options[:until].to_time.rfc2822 if options[:until] &amp;&amp; (options[:until].is_a?(Time) ||options[:until].is_a?(Date))
+          options[:for] = options[:for].to_i if options[:for]
           class_eval &lt;&lt;-&quot;end_eval&quot;
           alias_method  :cached_#{method.to_s}, :#{method.to_s}
           def #{method.to_s}
@@ -73,33 +80,45 @@ module ActiveRecord
           end
           
           def cached_#{method.to_s}_options
-            @cached_#{method}_options = eval &quot;#{options.inspect}&quot; if @cached_#{method}_options.nil?
+            if @cached_#{method}_options.nil?
+              @cached_#{method}_options = #{options.inspect}
+              if @cached_#{method}_options[:until] &amp;&amp; @cached_#{method}_options[:until].is_a?(String) 
+                @cached_#{method}_options[:until] = Time.rfc2822(@cached_#{method}_options[:until]) 
+              end
+            end
             @cached_#{method}_options
           end
           end_eval
         end
         
         def caches_class_method(method, options = {})
+          options[:until] = options[:until].rfc2822 if options[:until] &amp;&amp; (options[:until].is_a?(Time) ||options[:until].is_a?(Date))
+          options[:for] = options[:for].to_i if options[:for]
           return unless ActionController::Base.perform_caching
           class_eval &lt;&lt;-&quot;end_eval&quot;
           class &lt;&lt; self
-            @@cached_method_options = eval &quot;#{options.inspect}&quot;
+            @@cached_#{method}_options = #{options.inspect}
             cached_data = nil                      
             alias_method  :cached_#{method.to_s}, :#{method.to_s}
             
             def #{method.to_s}
-              #ActiveRecord::Base.logger.debug &quot;&gt;&gt;&gt;&gt;&gt;&gt;cached_method called&quot;
               #needs to get data from cache here
-              #ActiveRecord::Base.logger.debug &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;class variable nil. getting from memcache &quot; + &quot;cached_#{method}_for_\#{self.to_s}&quot;
               cached_data = MethodCacher.read(&quot;cached_#{method}_for_\#{self.to_s}&quot;)
               if cached_data.nil?
-                #ActiveRecord::Base.logger.debug &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;class variable nil. getting from original method&quot;
                 cached_data = cached_#{method.to_s}
-                MethodCacher.write(&quot;cached_#{method}_for_\#{self.to_s}&quot;,cached_data, seconds_to_expire(@@cached_method_options))
+                MethodCacher.write(&quot;cached_#{method}_for_\#{self.to_s}&quot;,cached_data, seconds_to_expire(cached_#{method}_options))
               end
-              #ActiveRecord::Base.logger.debug &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;returning class variable&quot;
               cached_data
             end
+            
+            def cached_#{method}_options
+              if @@cached_#{method}_options[:until] &amp;&amp; @@cached_#{method}_options[:until].is_a?(String) 
+                @@cached_#{method}_options[:until] = Time.rfc2822(@@cached_#{method}_options[:until]) 
+              end
+              @@cached_#{method}_options
+            end  
+            
+            
           end
           end_eval
         end        
@@ -110,9 +129,7 @@ module ActiveRecord
         end
         
         def expire_instance_method(method, id)
-          #puts &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;expire_instance_method #{method} 1&quot;
           return unless ActionController::Base.perform_caching
-          #puts &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;expire_instance_method #{method} 2&quot;
           MethodCacher.delete(&quot;cached_#{method}_for_#{self.to_s}_#{id}&quot;)
         end
         
@@ -120,14 +137,14 @@ module ActiveRecord
           if options.has_key?(:until)
             case options[:until]
               when 'midnight', :midnight
-              return ((Time.now + 1.day).midnight - Time.now).to_i
+              secs = ((Time.now + 1.day).midnight - Time.now).to_i
             else
-              if options[:until].is_a?(Time) || options[:until].is_a?(Date)
-                return (options[:until].to_time - Time.now).to_i
-              end  
+              secs = (options[:until] - Time.now).to_i
             end
+            raise &quot;:until(#{options[:until].inspect}) is less than Time.now by #{secs}&quot; if secs &lt;= 0
+            return secs
           elsif options.has_key?(:for)
-            return options[:for]
+            return options[:for].to_i
           else
             0
           end
@@ -136,9 +153,7 @@ module ActiveRecord
       
       module InstanceMethods
         def expire_method(method)
-          #puts &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;expire_method #{method} 1&quot;
           return unless ActionController::Base.perform_caching
-          #puts &quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;expire_method #{method} 2&quot;
           MethodCacher.delete(&quot;cached_#{method.to_s}_for_#{self.class.name}_#{@attributes['id']}&quot;)
           remove_instance_variable(&quot;@cached_#{method.to_s}&quot;.to_sym) if instance_variables.include? &quot;@cached_#{method.to_s}&quot;
         end
@@ -148,12 +163,12 @@ module ActiveRecord
           if options.has_key?(:until)
             case options[:until]
               when 'midnight', :midnight
-              return ((Time.now + 1.day).midnight - Time.now).to_i
+              secs = ((Time.now + 1.day).midnight - Time.now).to_i  
             else
-              if options[:until].is_a?(Time) || options[:until].is_a?(Date)
-                return (options[:until].to_time - Time.now).to_i
-              end  
+              secs = (options[:until] - Time.now).to_i
             end
+            raise &quot;:until(#{options[:until].inspect}) is less than Time.now by #{secs}&quot; if secs &lt;= 0
+            return secs
           elsif options.has_key?(:for)
             return options[:for]
           else</diff>
      <filename>lib/method_cache.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,113 @@
 require 'test/unit'
+require File.join(File.dirname(__FILE__), 'abstract_unit')
+require File.join(File.dirname(__FILE__), 'dummy_classes')
 
 class MethodCacheTest &lt; Test::Unit::TestCase
+  
+  fixtures :cars
+  
+  def setup
+    ActionController::Base.perform_caching = true
+    ActionController::Base.cache_store = :mem_cache_store, &quot;localhost&quot;
+  end
+  
+  def test_method_cacher
+    MethodCacher.write('koko','soso',0,true)
+    assert_equal 'soso', MethodCacher.read('koko')
+    MethodCacher.delete 'koko'
+    assert_nil MethodCacher.read('koko')
+  end
+  
+  def test_method_cacher_with_time
+    MethodCacher.write('koko','soso',3,true)
+    assert_equal 'soso', MethodCacher.read('koko')
+    sleep 3
+    assert_nil MethodCacher.read('koko')
+  end
+  
   # Replace this with your real tests.
-  def test_this_plugin
-    flunk
+  def test_caches_method
+    c = Car.find :first
+    assert !c.instance_variables.include?(&quot;@cached_costy_method&quot;)
+    assert_equal &quot;costy_method&quot;, c.costy_method
+    assert c.instance_variables.include?(&quot;@cached_costy_method&quot;)
+    assert_equal &quot;costy_method&quot;, MethodCacher.read(&quot;cached_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+  end
+  
+  def test_expire_method
+    c = Car.find :first
+    c.costy_method
+    assert c.instance_variables.include?(&quot;@cached_costy_method&quot;)
+    assert_equal &quot;costy_method&quot;, MethodCacher.read(&quot;cached_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+    assert c.instance_variables.include?(&quot;@cached_costy_method&quot;)
+    
+    c.expire_method :costy_method
+    assert !c.instance_variables.include?(&quot;@cached_costy_method&quot;)
+    assert_nil MethodCacher.read(&quot;cached_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+  end
+  
+  def test_expire_instance_method
+    c = Car.find :first
+    c.costy_method
+    assert_equal &quot;costy_method&quot;, MethodCacher.read(&quot;cached_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+    
+    Car.expire_instance_method :costy_method, c.id
+    assert_nil MethodCacher.read(&quot;cached_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+  end
+  
+  def test_caches_method_with_for
+    c = Car.find :first
+    MethodCacher.delete(&quot;cached_for_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+    assert_nil MethodCacher.read(&quot;cached_for_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+    assert_equal &quot;for_costy_method&quot;, c.for_costy_method
+    assert_equal &quot;for_costy_method&quot;, MethodCacher.read(&quot;cached_for_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+    sleep 5
+    assert_nil MethodCacher.read(&quot;cached_for_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+  end
+  
+#  def test_caches_method_with_until
+#    c = Car.find :first
+#    MethodCacher.delete(&quot;cached_until_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+#    assert_nil MethodCacher.read(&quot;cached_until_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+#    puts &quot;about to call c.until_costy_method #{Time.now.inspect}&quot;
+#    assert_equal &quot;until_costy_method&quot;, c.until_costy_method
+#    puts &quot;after calling c.until_costy_method #{Time.now.inspect}&quot;
+#    assert_equal &quot;until_costy_method&quot;, MethodCacher.read(&quot;cached_until_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+#    sleep 8
+#    assert_nil MethodCacher.read(&quot;cached_until_costy_method_for_#{Car.name}_#{c.id}&quot;, true)
+#  end
+  
+  def test_caches_class_method
+    assert_nil MethodCacher.read(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+    assert_equal &quot;costy_class_method&quot;, Car.costy_class_method
+    assert_equal &quot;costy_class_method&quot;, MethodCacher.read(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+    MethodCacher.delete(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+  end
+  
+  def test_expire_class_method
+    assert_nil MethodCacher.read(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+    assert_equal &quot;costy_class_method&quot;, Car.costy_class_method
+    assert_equal &quot;costy_class_method&quot;, MethodCacher.read(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+    
+    Car.expire_class_method :costy_class_method
+    assert_nil MethodCacher.read(&quot;cached_costy_class_method_for_#{Car.name}&quot;, true)
+  end
+  
+  def test_caches_class_method_with_for
+    MethodCacher.delete(&quot;cached_for_costy_class_method_for_#{Car.name}&quot;, true)
+    assert_nil MethodCacher.read(&quot;cached_for_costy_class_method_for_#{Car.name}&quot;, true)
+    assert_equal &quot;for_costy_class_method&quot;, Car.for_costy_class_method
+    assert_equal &quot;for_costy_class_method&quot;, MethodCacher.read(&quot;cached_for_costy_class_method_for_#{Car.name}&quot;, true)
+    sleep 5
+    assert_nil MethodCacher.read(&quot;cached_for_costy_class_method_for_#{Car.name}&quot;, true)
   end
+  
+#  def test_caches_class_method_with_until
+#    MethodCacher.delete(&quot;cached_until_costy_class_method_for_#{Car.name}&quot;, true)
+#    assert_nil MethodCacher.read(&quot;cached_until_costy_class_method_for_#{Car.name}&quot;, true)
+#    assert_equal &quot;until_costy_class_method&quot;, Car.until_costy_class_method
+#    assert_equal &quot;until_costy_class_method&quot;, MethodCacher.read(&quot;cached_until_costy_class_method_for_#{Car.name}&quot;, true)
+#    sleep 8
+#    assert_nil MethodCacher.read(&quot;cached_until_costy_class_method_for_#{Car.name}&quot;, true)
+#  end
 end</diff>
      <filename>test/method_cache_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>aca654a0f5ab3be85be8588af304bc034217edcd</id>
    </parent>
  </parents>
  <author>
    <name>Ahmed Sobhi</name>
    <email>humanzz@hotmail.com</email>
  </author>
  <url>http://github.com/humanzz/method_cache/commit/fb3ca3a6852962b9ae9107d545c31049eb3840ce</url>
  <id>fb3ca3a6852962b9ae9107d545c31049eb3840ce</id>
  <committed-date>2008-07-14T11:44:33-07:00</committed-date>
  <authored-date>2008-07-14T11:44:33-07:00</authored-date>
  <message>adding tests and fixing bugs</message>
  <tree>fcab1ad82ba6c7000c29af44dba08f4dbc957012</tree>
  <committer>
    <name>Ahmed Sobhi</name>
    <email>humanzz@hotmail.com</email>
  </committer>
</commit>
