update to v1.3 - reportable - Fork of reportable required by WarVox, from hdm/reportable.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 1b697477d79a5e17e869b4acc1f6be4330226037
 (DIR) parent 80083c77564a3a852216fa1891136540ada6963b
 (HTM) Author: Marco Otte-Witte <marco.otte-witte@simplabs.com>
       Date:   Tue,  5 May 2009 19:17:04 +0200
       
       update to v1.3
       
       Diffstat:
         M HISTORY.rdoc                        |       6 ++++++
         M README.rdoc                         |      29 +++++++++++++++++++++++++++++
         M doc/classes/Simplabs/ReportsAsSpar… |      35 +++++++++++++------------------
         M doc/classes/Simplabs/ReportsAsSpar… |       2 +-
         M doc/classes/Simplabs/ReportsAsSpar… |      24 ++++++++++++------------
         M doc/classes/Simplabs/ReportsAsSpar… |      68 ++++++++++++++++++++++++++++++-
         M doc/created.rid                     |       2 +-
         M doc/files/README_rdoc.html          |      44 ++++++++++++++++++++++++++++++-
         M doc/files/lib/simplabs/reports_as_… |       2 +-
         M doc/files/lib/simplabs/reports_as_… |       2 +-
         M doc/files/lib/simplabs/reports_as_… |       2 +-
         M doc/files/lib/simplabs/reports_as_… |       2 +-
         M doc/files/lib/simplabs/reports_as_… |       2 +-
         M doc/fr_method_index.html            |       5 +++--
         M lib/simplabs/reports_as_sparkline.… |       5 -----
         M lib/simplabs/reports_as_sparkline/… |      10 +++++-----
         M lib/simplabs/reports_as_sparkline/… |       5 +++--
         M lib/simplabs/reports_as_sparkline/… |      93 +++++++++++++++++++------------
         M lib/simplabs/reports_as_sparkline/… |      28 +++++++++++++++++++---------
         M spec/classes/report_cache_spec.rb   |      93 +++++++++++++++++++------------
         M spec/classes/report_spec.rb         |      20 ++++++++++++++++++++
         M spec/classes/reporting_period_spec… |      48 +++++++++++++++++++++++++++++++
         M spec/db/schema.rb                   |       7 ++-----
       
       23 files changed, 393 insertions(+), 141 deletions(-)
       ---
 (DIR) diff --git a/HISTORY.rdoc b/HISTORY.rdoc
       @@ -1,3 +1,9 @@
       +=== v1.3
       +
       +* Fixed another bug where two report runs with different :end_date values would lead to invalid data
       +* Entries in the report cache entry are no longer identified by the :limit the report was run with (YOU WILL HAVE TO RECREATE YOUR CACHE TABLE!)
       +* rewrote the data retrieval and processing code, it's now much more compact and less complicated with fewer cache misses
       +
        === v1.2
        
        * FIXED: duplicate key error when using custom time zones (thanks to myronmarston  (http://github.com/myronmarston))
 (DIR) diff --git a/README.rdoc b/README.rdoc
       @@ -43,6 +43,26 @@ When invoking the report, you can override some of the options you specified for
          User.registrations_report(:conditions => ['last_name LIKE 'A%'])
          User.activations_report(:grouping => :week, :limit => 5)
        
       +=== The Report cache
       +
       +Unless you specify parameters that make it impossible to cache report results, all results will be cached. You can access the cache via the <tt>Simplabs::ReportsAsSparkline::ReportCache</tt> class.
       +<b>Beware that when you modify data in the cache, report results may be incorrect or execurting reports may even fail completely!</b> To clear the cache for a specific report, use the <tt>Simplabs::ReportsAsSparkline::ReportCache.clear_for</tt>
       +method.
       +
       +<b>Example</b>
       +
       +For a report defined as
       +
       +  class User < ActiveRecord::Base
       +    reports_as_sparkline :registrations
       +  end
       +
       +you can clear the cache with
       +
       +  Simplabs::ReportsAsSparkline::ReportCache.clear_for(User, :registrations)
       +
       +=== In your views
       +
        You can than render sparklines for these reports with sparkline_tag in your view:
        
          <%= sparkline_tag(User.registrations_report) %>
       @@ -91,6 +111,15 @@ If you are on PostgreSQL, you should add functional indices:
          add_index :[table], :[date_column], :functional => "date_trunc('week', [date_column])"
          add_index :[table], :[date_column], :functional => "date_trunc('year', [date_column])"
        
       +You might also want to use fragment caching in your views since processing the data read from the db (either from the model's table or from the cache)
       +aso takes some time.
       +
       +<b>Example</b>
       +
       +  <%- cache do -%>
       +    <%= sparkline_tag(User.registrations_report) %>
       +  <%- end -%>
       +
        == TODOs/ future plans
        
        * support for Oracle and DB2 (and others?) missing
 (DIR) diff --git a/doc/classes/Simplabs/ReportsAsSparkline/ClassMethods.html b/doc/classes/Simplabs/ReportsAsSparkline/ClassMethods.html
       @@ -115,7 +115,7 @@
                  <p>
        Generates a report on a model. That report can then be executed via the new
        method <tt>&lt;name&gt;_report</tt> (see documentation of <a
       -href="Report.html#M000007">Simplabs::ReportsAsSparkline::Report#run</a>).
       +href="Report.html#M000008">Simplabs::ReportsAsSparkline::Report#run</a>).
        </p>
        <h4>Parameters</h4>
        <ul>
       @@ -170,11 +170,6 @@ the <tt>:limit</tt> reporting periods until this date.
        </ul>
        <h4>Examples</h4>
        <pre>
       - class Game &lt; ActiveRecord::Base
       -   reports_as_sparkline :games_per_day
       -   reports_as_sparkline :games_played_total, :cumulate =&gt; true
       - end
       -
         class User &lt; ActiveRecord::Base
           reports_as_sparkline :registrations, :aggregation =&gt; :count
           reports_as_sparkline :activations,   :aggregation =&gt; :count, :date_column =&gt; :activated_at
       @@ -186,20 +181,20 @@ the <tt>:limit</tt> reporting periods until this date.
                    onclick="toggleCode('M000002-source');return false;">[Source]</a></p>
                  <div class="method-source-code" id="M000002-source">
        <pre>
       -    <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline.rb, line 41</span>
       -41:       <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">reports_as_sparkline</span>(<span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span> = {})
       -42:         (<span class="ruby-keyword kw">class</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-keyword kw">self</span>; <span class="ruby-keyword kw">self</span>; <span class="ruby-keyword kw">end</span>).<span class="ruby-identifier">instance_eval</span> <span class="ruby-keyword kw">do</span>
       -43:           <span class="ruby-identifier">define_method</span> <span class="ruby-node">&quot;#{name.to_s}_report&quot;</span>.<span class="ruby-identifier">to_sym</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-operator">*</span><span class="ruby-identifier">args</span><span class="ruby-operator">|</span>
       -44:             <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">options</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">:cumulate</span>)
       -45:               <span class="ruby-identifier">report</span> = <span class="ruby-constant">Simplabs</span><span class="ruby-operator">::</span><span class="ruby-constant">ReportsAsSparkline</span><span class="ruby-operator">::</span><span class="ruby-constant">CumulatedReport</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span>)
       -46:             <span class="ruby-keyword kw">else</span>
       -47:               <span class="ruby-identifier">report</span> = <span class="ruby-constant">Simplabs</span><span class="ruby-operator">::</span><span class="ruby-constant">ReportsAsSparkline</span><span class="ruby-operator">::</span><span class="ruby-constant">Report</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span>)
       -48:             <span class="ruby-keyword kw">end</span>
       -49:             <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>.<span class="ruby-identifier">new</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">0</span> <span class="ruby-operator">||</span> (<span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">args</span>[<span class="ruby-value">0</span>].<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>))
       -50:             <span class="ruby-identifier">report</span>.<span class="ruby-identifier">run</span>(<span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">0</span> <span class="ruby-operator">?</span> {} <span class="ruby-operator">:</span> <span class="ruby-identifier">args</span>[<span class="ruby-value">0</span>])
       -51:           <span class="ruby-keyword kw">end</span>
       -52:         <span class="ruby-keyword kw">end</span>
       -53:       <span class="ruby-keyword kw">end</span>
       +    <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline.rb, line 36</span>
       +36:       <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">reports_as_sparkline</span>(<span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span> = {})
       +37:         (<span class="ruby-keyword kw">class</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-keyword kw">self</span>; <span class="ruby-keyword kw">self</span>; <span class="ruby-keyword kw">end</span>).<span class="ruby-identifier">instance_eval</span> <span class="ruby-keyword kw">do</span>
       +38:           <span class="ruby-identifier">define_method</span> <span class="ruby-node">&quot;#{name.to_s}_report&quot;</span>.<span class="ruby-identifier">to_sym</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-operator">*</span><span class="ruby-identifier">args</span><span class="ruby-operator">|</span>
       +39:             <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">options</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">:cumulate</span>)
       +40:               <span class="ruby-identifier">report</span> = <span class="ruby-constant">Simplabs</span><span class="ruby-operator">::</span><span class="ruby-constant">ReportsAsSparkline</span><span class="ruby-operator">::</span><span class="ruby-constant">CumulatedReport</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span>)
       +41:             <span class="ruby-keyword kw">else</span>
       +42:               <span class="ruby-identifier">report</span> = <span class="ruby-constant">Simplabs</span><span class="ruby-operator">::</span><span class="ruby-constant">ReportsAsSparkline</span><span class="ruby-operator">::</span><span class="ruby-constant">Report</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span>)
       +43:             <span class="ruby-keyword kw">end</span>
       +44:             <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>.<span class="ruby-identifier">new</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">0</span> <span class="ruby-operator">||</span> (<span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">1</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">args</span>[<span class="ruby-value">0</span>].<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>))
       +45:             <span class="ruby-identifier">report</span>.<span class="ruby-identifier">run</span>(<span class="ruby-identifier">args</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">==</span> <span class="ruby-value">0</span> <span class="ruby-operator">?</span> {} <span class="ruby-operator">:</span> <span class="ruby-identifier">args</span>[<span class="ruby-value">0</span>])
       +46:           <span class="ruby-keyword kw">end</span>
       +47:         <span class="ruby-keyword kw">end</span>
       +48:       <span class="ruby-keyword kw">end</span>
        </pre>
                  </div>
                </div>
 (DIR) diff --git a/doc/classes/Simplabs/ReportsAsSparkline/CumulatedReport.html b/doc/classes/Simplabs/ReportsAsSparkline/CumulatedReport.html
       @@ -146,7 +146,7 @@ returns
                <div class="method-description">
                  <p>
        Runs the report (see <a
       -href="Report.html#M000007">Simplabs::ReportsAsSparkline::Report#run</a>)
       +href="Report.html#M000008">Simplabs::ReportsAsSparkline::Report#run</a>)
        </p>
                  <p><a class="source-toggle" href="#"
                    onclick="toggleCode('M000003-source');return false;">[Source]</a></p>
 (DIR) diff --git a/doc/classes/Simplabs/ReportsAsSparkline/Report.html b/doc/classes/Simplabs/ReportsAsSparkline/Report.html
       @@ -93,8 +93,8 @@ and calculations
              <h3 class="section-bar">Methods</h3>
        
              <div class="name-list">
       -      <a href="#M000006">new</a>&nbsp;&nbsp;
       -      <a href="#M000007">run</a>&nbsp;&nbsp;
       +      <a href="#M000007">new</a>&nbsp;&nbsp;
       +      <a href="#M000008">run</a>&nbsp;&nbsp;
              </div>
            </div>
        
       @@ -154,11 +154,11 @@ and calculations
            <div id="methods">
              <h3 class="section-bar">Public Class methods</h3>
        
       -      <div id="method-M000006" class="method-detail">
       -        <a name="M000006"></a>
       +      <div id="method-M000007" class="method-detail">
       +        <a name="M000007"></a>
        
                <div class="method-heading">
       -          <a href="#M000006" class="method-signature">
       +          <a href="#M000007" class="method-signature">
                  <span class="method-name">new</span><span class="method-args">(klass, name, options = {})</span>
                  </a>
                </div>
       @@ -221,8 +221,8 @@ the <tt>:limit</tt> reporting periods until this date.
        </li>
        </ul>
                  <p><a class="source-toggle" href="#"
       -            onclick="toggleCode('M000006-source');return false;">[Source]</a></p>
       -          <div class="method-source-code" id="M000006-source">
       +            onclick="toggleCode('M000007-source');return false;">[Source]</a></p>
       +          <div class="method-source-code" id="M000007-source">
        <pre>
            <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/report.rb, line 24</span>
        24:       <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">klass</span>, <span class="ruby-identifier">name</span>, <span class="ruby-identifier">options</span> = {})
       @@ -249,11 +249,11 @@ the <tt>:limit</tt> reporting periods until this date.
        
              <h3 class="section-bar">Public Instance methods</h3>
        
       -      <div id="method-M000007" class="method-detail">
       -        <a name="M000007"></a>
       +      <div id="method-M000008" class="method-detail">
       +        <a name="M000008"></a>
        
                <div class="method-heading">
       -          <a href="#M000007" class="method-signature">
       +          <a href="#M000008" class="method-signature">
                  <span class="method-name">run</span><span class="method-args">(options = {})</span>
                  </a>
                </div>
       @@ -290,8 +290,8 @@ the <tt>:limit</tt> reporting periods until this date.
        </li>
        </ul>
                  <p><a class="source-toggle" href="#"
       -            onclick="toggleCode('M000007-source');return false;">[Source]</a></p>
       -          <div class="method-source-code" id="M000007-source">
       +            onclick="toggleCode('M000008-source');return false;">[Source]</a></p>
       +          <div class="method-source-code" id="M000008-source">
        <pre>
            <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/report.rb, line 50</span>
        50:       <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">run</span>(<span class="ruby-identifier">options</span> = {})
 (DIR) diff --git a/doc/classes/Simplabs/ReportsAsSparkline/ReportCache.html b/doc/classes/Simplabs/ReportsAsSparkline/ReportCache.html
       @@ -85,8 +85,7 @@ The <a href="ReportCache.html">ReportCache</a> class is a regular
        reporting periods (table name is <tt>reports_as_sparkline_cache</tt>) <a
        href="ReportCache.html">ReportCache</a> instances are identified by the
        combination of <tt>model_name</tt>, <tt>report_name</tt>,
       -<tt>grouping</tt>, <tt>aggregation</tt>, <tt>reporting_period</tt>,
       -<tt>run_limit</tt>
       +<tt>grouping</tt>, <tt>aggregation</tt> and <tt>reporting_period</tt>
        </p>
        
            </div>
       @@ -94,6 +93,13 @@ combination of <tt>model_name</tt>, <tt>report_name</tt>,
        
           </div>
        
       +    <div id="method-list">
       +      <h3 class="section-bar">Methods</h3>
       +
       +      <div class="name-list">
       +      <a href="#M000006">clear_for</a>&nbsp;&nbsp;
       +      </div>
       +    </div>
        
          </div>
        
       @@ -110,6 +116,64 @@ combination of <tt>model_name</tt>, <tt>report_name</tt>,
        
        
            <!-- if method_list -->
       +    <div id="methods">
       +      <h3 class="section-bar">Public Class methods</h3>
       +
       +      <div id="method-M000006" class="method-detail">
       +        <a name="M000006"></a>
       +
       +        <div class="method-heading">
       +          <a href="#M000006" class="method-signature">
       +          <span class="method-name">clear_for</span><span class="method-args">(klass, report)</span>
       +          </a>
       +        </div>
       +      
       +        <div class="method-description">
       +          <p>
       +Clears the cache for the specified <tt>klass</tt> and <tt>report</tt>
       +</p>
       +<h3>Parameters</h3>
       +<ul>
       +<li><tt>klass</tt> - The model the report to clear the cache for works on
       +
       +</li>
       +<li><tt>report</tt> - The name of the report to clear the cache for
       +
       +</li>
       +</ul>
       +<h3>Example</h3>
       +<p>
       +To clear the cache for a report defined as
       +</p>
       +<pre>
       + class User &lt; ActiveRecord::Base
       +   reports_as_sparkline :registrations
       + end
       +</pre>
       +<p>
       +just do
       +</p>
       +<pre>
       + Simplabs::ReportsAsSparkline::ReportCache.clear_for(User, :registrations)
       +</pre>
       +          <p><a class="source-toggle" href="#"
       +            onclick="toggleCode('M000006-source');return false;">[Source]</a></p>
       +          <div class="method-source-code" id="M000006-source">
       +<pre>
       +    <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/report_cache.rb, line 26</span>
       +26:       <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">clear_for</span>(<span class="ruby-identifier">klass</span>, <span class="ruby-identifier">report</span>)
       +27:         <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">delete_all</span>(<span class="ruby-identifier">:conditions</span> =<span class="ruby-operator">&gt;</span> {
       +28:           <span class="ruby-identifier">:model_name</span>  =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">klass</span>.<span class="ruby-identifier">name</span>,
       +29:           <span class="ruby-identifier">:report_name</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">report</span>.<span class="ruby-identifier">to_s</span>
       +30:         })
       +31:       <span class="ruby-keyword kw">end</span>
       +</pre>
       +          </div>
       +        </div>
       +      </div>
       +
       +
       +    </div>
        
        
          </div>
 (DIR) diff --git a/doc/created.rid b/doc/created.rid
       @@ -1 +1 @@
       -Wed, 29 Apr 2009 19:32:38 +0200
       +Tue, 05 May 2009 19:07:12 +0200
 (DIR) diff --git a/doc/files/README_rdoc.html b/doc/files/README_rdoc.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:32:28 +0200 2009</td>
       +      <td>Tue May 05 19:07:10 +0200 2009</td>
            </tr>
            </table>
          </div>
       @@ -177,6 +177,35 @@ the <tt>:limit</tt> reporting periods until this date.
          User.registrations_report(:conditions =&gt; ['last_name LIKE 'A%'])
          User.activations_report(:grouping =&gt; :week, :limit =&gt; 5)
        </pre>
       +<h3>The Report cache</h3>
       +<p>
       +Unless you specify parameters that make it impossible to cache report
       +results, all results will be cached. You can access the cache via the
       +<tt><a
       +href="../classes/Simplabs/ReportsAsSparkline/ReportCache.html">Simplabs::ReportsAsSparkline::ReportCache</a></tt>
       +class. <b>Beware that when you modify data in the cache, report results may
       +be incorrect or execurting reports may even fail completely!</b> To clear
       +the cache for a specific report, use the
       +<tt>Simplabs::ReportsAsSparkline::ReportCache.clear_for</tt> method.
       +</p>
       +<p>
       +<b>Example</b>
       +</p>
       +<p>
       +For a report defined as
       +</p>
       +<pre>
       +  class User &lt; ActiveRecord::Base
       +    reports_as_sparkline :registrations
       +  end
       +</pre>
       +<p>
       +you can clear the cache with
       +</p>
       +<pre>
       +  Simplabs::ReportsAsSparkline::ReportCache.clear_for(User, :registrations)
       +</pre>
       +<h3>In your views</h3>
        <p>
        You can than render sparklines for these reports with sparkline_tag in your
        view:
       @@ -255,6 +284,19 @@ If you are on PostgreSQL, you should add functional indices:
          add_index :[table], :[date_column], :functional =&gt; &quot;date_trunc('week', [date_column])&quot;
          add_index :[table], :[date_column], :functional =&gt; &quot;date_trunc('year', [date_column])&quot;
        </pre>
       +<p>
       +You might also want to use fragment caching in your views since processing
       +the data read from the db (either from the model&#8216;s table or from the
       +cache) aso takes some time.
       +</p>
       +<p>
       +<b>Example</b>
       +</p>
       +<pre>
       +  &lt;%- cache(:key =&gt; 'UserRegistrationsReport') do -%&gt;
       +    &lt;%= sparkline_tag(User.registrations_report) %&gt;
       +  &lt;%- end -%&gt;
       +</pre>
        <h2>TODOs/ future plans</h2>
        <ul>
        <li>support for Oracle and DB2 (and others?) missing
 (DIR) diff --git a/doc/files/lib/simplabs/reports_as_sparkline/grouping_rb.html b/doc/files/lib/simplabs/reports_as_sparkline/grouping_rb.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:18:36 +0200 2009</td>
       +      <td>Tue May 05 18:20:50 +0200 2009</td>
            </tr>
            </table>
          </div>
 (DIR) diff --git a/doc/files/lib/simplabs/reports_as_sparkline/report_cache_rb.html b/doc/files/lib/simplabs/reports_as_sparkline/report_cache_rb.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:20:49 +0200 2009</td>
       +      <td>Tue May 05 19:02:15 +0200 2009</td>
            </tr>
            </table>
          </div>
 (DIR) diff --git a/doc/files/lib/simplabs/reports_as_sparkline/report_rb.html b/doc/files/lib/simplabs/reports_as_sparkline/report_rb.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:26:39 +0200 2009</td>
       +      <td>Tue May 05 15:51:11 +0200 2009</td>
            </tr>
            </table>
          </div>
 (DIR) diff --git a/doc/files/lib/simplabs/reports_as_sparkline/reporting_period_rb.html b/doc/files/lib/simplabs/reports_as_sparkline/reporting_period_rb.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:18:27 +0200 2009</td>
       +      <td>Tue May 05 18:41:47 +0200 2009</td>
            </tr>
            </table>
          </div>
 (DIR) diff --git a/doc/files/lib/simplabs/reports_as_sparkline_rb.html b/doc/files/lib/simplabs/reports_as_sparkline_rb.html
       @@ -56,7 +56,7 @@
            </tr>
            <tr class="top-aligned-row">
              <td><strong>Last Update:</strong></td>
       -      <td>Wed Apr 29 19:29:22 +0200 2009</td>
       +      <td>Tue May 05 19:02:42 +0200 2009</td>
            </tr>
            </table>
          </div>
 (DIR) diff --git a/doc/fr_method_index.html b/doc/fr_method_index.html
       @@ -20,12 +20,13 @@
        <div id="index">
          <h1 class="section-bar">Methods</h1>
          <div id="index-entries">
       +    <a href="classes/Simplabs/ReportsAsSparkline/ReportCache.html#M000006">clear_for (Simplabs::ReportsAsSparkline::ReportCache)</a><br />
            <a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000004">cumulate (Simplabs::ReportsAsSparkline::CumulatedReport)</a><br />
            <a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000005">initial_cumulative_value (Simplabs::ReportsAsSparkline::CumulatedReport)</a><br />
       -    <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000006">new (Simplabs::ReportsAsSparkline::Report)</a><br />
       +    <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000007">new (Simplabs::ReportsAsSparkline::Report)</a><br />
            <a href="classes/Simplabs/ReportsAsSparkline/ClassMethods.html#M000002">reports_as_sparkline (Simplabs::ReportsAsSparkline::ClassMethods)</a><br />
            <a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000003">run (Simplabs::ReportsAsSparkline::CumulatedReport)</a><br />
       -    <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000007">run (Simplabs::ReportsAsSparkline::Report)</a><br />
       +    <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000008">run (Simplabs::ReportsAsSparkline::Report)</a><br />
            <a href="classes/Simplabs/ReportsAsSparkline/SparklineTagHelper.html#M000001">sparkline_tag (Simplabs::ReportsAsSparkline::SparklineTagHelper)</a><br />
          </div>
        </div>
 (DIR) diff --git a/lib/simplabs/reports_as_sparkline.rb b/lib/simplabs/reports_as_sparkline.rb
       @@ -27,11 +27,6 @@ module Simplabs #:nodoc:
              #
              # ==== Examples
              #
       -      #  class Game < ActiveRecord::Base
       -      #    reports_as_sparkline :games_per_day
       -      #    reports_as_sparkline :games_played_total, :cumulate => true
       -      #  end
       -      #
              #  class User < ActiveRecord::Base
              #    reports_as_sparkline :registrations, :aggregation => :count
              #    reports_as_sparkline :activations,   :aggregation => :count, :date_column => :activated_at
 (DIR) diff --git a/lib/simplabs/reports_as_sparkline/grouping.rb b/lib/simplabs/reports_as_sparkline/grouping.rb
       @@ -14,7 +14,7 @@ module Simplabs #:nodoc:
              end
        
              def date_parts_from_db_string(db_string)
       -        return case ActiveRecord::Base.connection.adapter_name
       +        case ActiveRecord::Base.connection.adapter_name
                  when /mysql/i
                    from_mysql_db_string(db_string)
                  when /sqlite/i
       @@ -25,7 +25,7 @@ module Simplabs #:nodoc:
              end
        
              def to_sql(date_column) #:nodoc:
       -        return case ActiveRecord::Base.connection.adapter_name
       +        case ActiveRecord::Base.connection.adapter_name
                  when /mysql/i
                    mysql_format(date_column)
                  when /sqlite/i
       @@ -70,7 +70,7 @@ module Simplabs #:nodoc:
                end
        
                def mysql_format(date_column)
       -          return case @identifier
       +          case @identifier
                    when :hour
                      "DATE_FORMAT(#{date_column}, '%Y/%m/%d/%H')"
                    when :day
       @@ -83,7 +83,7 @@ module Simplabs #:nodoc:
                end
        
                def sqlite_format(date_column)
       -          return case @identifier
       +          case @identifier
                    when :hour
                      "strftime('%Y/%m/%d/%H', #{date_column})"
                    when :day
       @@ -96,7 +96,7 @@ module Simplabs #:nodoc:
                end
        
                def postgresql_format(date_column)
       -          return case @identifier
       +          case @identifier
                    when :hour
                      "date_trunc('hour', #{date_column})"
                    when :day
 (DIR) diff --git a/lib/simplabs/reports_as_sparkline/report.rb b/lib/simplabs/reports_as_sparkline/report.rb
       @@ -70,8 +70,9 @@ module Simplabs #:nodoc:
                  @klass.send(@aggregation,
                    @value_column,
                    :conditions => conditions,
       -            :group => options[:grouping].to_sql(@date_column),
       -            :order => "#{options[:grouping].to_sql(@date_column)} ASC"
       +            :group      => options[:grouping].to_sql(@date_column),
       +            :order      => "#{options[:grouping].to_sql(@date_column)} ASC",
       +            :limit      => options[:limit]
                  )
                end
        
 (DIR) diff --git a/lib/simplabs/reports_as_sparkline/report_cache.rb b/lib/simplabs/reports_as_sparkline/report_cache.rb
       @@ -3,32 +3,41 @@ module Simplabs #:nodoc:
          module ReportsAsSparkline #:nodoc:
        
            # The ReportCache class is a regular +ActiveRecord+ model and represents cached results for single reporting periods (table name is +reports_as_sparkline_cache+)
       -    # ReportCache instances are identified by the combination of +model_name+, +report_name+, +grouping+, +aggregation+, +reporting_period+, +run_limit+
       +    # ReportCache instances are identified by the combination of +model_name+, +report_name+, +grouping+, +aggregation+ and +reporting_period+
            class ReportCache < ActiveRecord::Base
        
              set_table_name :reports_as_sparkline_cache
        
       -      # When reporting_period has a time zone conversion performed, we get duplicate key sql errors.
       -      # This occurs because find_cached_data will return a record set that is missing a record when we
       -      # have an end date.  The SQL criteria reporting_period BETWEEN before_date AND end_date will not include
       -      # the last record that it should, because our end_date will not be time-zone converted (ex: 5/1/09 00:00:00) but
       -      # the reported_period in the database will be time-zone converted (ex: 5/1/00 07:00:00).
              self.skip_time_zone_conversion_for_attributes = [:reporting_period]
        
       +      # Clears the cache for the specified +klass+ and +report+
       +      #
       +      # === Parameters
       +      # * <tt>klass</tt> - The model the report to clear the cache for works on
       +      # * <tt>report</tt> - The name of the report to clear the cache for
       +      #
       +      # === Example
       +      # To clear the cache for a report defined as
       +      #  class User < ActiveRecord::Base
       +      #    reports_as_sparkline :registrations
       +      #  end
       +      # just do
       +      #  Simplabs::ReportsAsSparkline::ReportCache.clear_for(User, :registrations)
       +      def self.clear_for(klass, report)
       +        self.delete_all(:conditions => {
       +          :model_name  => klass.name,
       +          :report_name => report.to_s
       +        })
       +      end
       +
              def self.process(report, options, cache = true, &block) #:nodoc:
                raise ArgumentError.new('A block must be given') unless block_given?
                self.transaction do
                  cached_data = []
       -          first_reporting_period = get_first_reporting_period(options)
       -          last_reporting_period = options[:end_date] ? ReportingPeriod.new(options[:grouping], options[:end_date]) : nil
       -
                  if cache
       -            cached_data = find_cached_data(report, options, first_reporting_period, last_reporting_period)
       -            first_cached_reporting_period = cached_data.empty? ? nil : ReportingPeriod.new(options[:grouping], cached_data.first.reporting_period)
       -            last_cached_reporting_period = cached_data.empty? ? nil : ReportingPeriod.new(options[:grouping], cached_data.last.reporting_period)
       +            cached_data = read_cached_data(report, options)
                  end
       -          new_data = read_new_data(first_reporting_period, last_reporting_period, last_cached_reporting_period, options, &block)
       -
       +          new_data = read_new_data(cached_data, options, &block)
                  prepare_result(new_data, cached_data, report, options, cache)
                end
              end
       @@ -37,17 +46,22 @@ module Simplabs #:nodoc:
        
                def self.prepare_result(new_data, cached_data, report, options, cache = true)
                  new_data = new_data.map { |data| [ReportingPeriod.from_db_string(options[:grouping], data[0]), data[1]] }
       -          result = cached_data.map { |cached| [cached.reporting_period, cached.value] }
       -          last_reporting_period = ReportingPeriod.new(options[:grouping])
       -          reporting_period = cached_data.empty? ? get_first_reporting_period(options) : ReportingPeriod.new(options[:grouping], cached_data.last.reporting_period).next
       -          while reporting_period < (options[:end_date] ? ReportingPeriod.new(options[:grouping], options[:end_date]).next : last_reporting_period)
       -            cached = build_cached_data(report, options[:grouping], options[:limit], reporting_period, find_value(new_data, reporting_period))
       -            cached.save! if cache
       -            result << [reporting_period.date_time, cached.value]
       +          cached_data.map! { |cached| [ReportingPeriod.new(options[:grouping], cached.reporting_period), cached.value] }
       +          current_reporting_period = ReportingPeriod.current(options[:grouping])
       +          reporting_period = get_first_reporting_period(options)
       +          result = []
       +          while reporting_period < (options[:end_date] ? ReportingPeriod.new(options[:grouping], options[:end_date]).next : current_reporting_period)
       +            if cached = cached_data.find { |cached| reporting_period == cached[0] }
       +              result << cached
       +            else
       +              new_cached = build_cached_data(report, options[:grouping], reporting_period, find_value(new_data, reporting_period))
       +              new_cached.save! if cache
       +              result << [reporting_period.date_time, new_cached.value]
       +            end
                    reporting_period = reporting_period.next
                  end
                  if options[:live_data]
       -            result << [last_reporting_period.date_time, find_value(new_data, last_reporting_period)]
       +            result << [current_reporting_period.date_time, find_value(new_data, current_reporting_period)]
                  end
                  result
                end
       @@ -57,27 +71,27 @@ module Simplabs #:nodoc:
                  data ? data[1] : 0.0
                end
        
       -        def self.build_cached_data(report, grouping, limit, reporting_period, value)
       +        def self.build_cached_data(report, grouping, reporting_period, value)
                  self.new(
                    :model_name       => report.klass.to_s,
                    :report_name      => report.name.to_s,
                    :grouping         => grouping.identifier.to_s,
                    :aggregation      => report.aggregation.to_s,
                    :reporting_period => reporting_period.date_time,
       -            :value            => value,
       -            :run_limit        => limit
       +            :value            => value
                  )
                end
        
       -        def self.find_cached_data(report, options, first_reporting_period, last_reporting_period)
       +        def self.read_cached_data(report, options)
                  conditions = [
       -            'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND run_limit = ?',
       +            'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ?',
                    report.klass.to_s,
                    report.name.to_s,
                    options[:grouping].identifier.to_s,
       -            report.aggregation.to_s,
       -            options[:limit]
       +            report.aggregation.to_s
                  ]
       +          first_reporting_period = get_first_reporting_period(options)
       +          last_reporting_period = get_last_reporting_period(options)
                  if last_reporting_period
                    conditions.first << ' AND reporting_period BETWEEN ? AND ?'
                    conditions << first_reporting_period.date_time
       @@ -88,17 +102,22 @@ module Simplabs #:nodoc:
                  end
                  self.all(
                    :conditions => conditions,
       -            :limit => options[:limit],
       -            :order => 'reporting_period ASC'
       +            :limit      => options[:limit],
       +            :order      => 'reporting_period ASC'
                  )
                end
        
       -        def self.read_new_data(first_reporting_period, last_reporting_period, last_cached_reporting_period, options, &block)
       -          if !options[:live_data] && last_cached_reporting_period == ReportingPeriod.new(options[:grouping]).previous
       +        def self.read_new_data(cached_data, options, &block)
       +          if !options[:live_data] && cached_data.length == options[:limit]
                    []
                  else
       -            end_date = options[:live_data] ? nil : (options[:end_date] ? last_reporting_period.last_date_time : nil)
       -            yield((last_cached_reporting_period.next rescue first_reporting_period).date_time, end_date)
       +            first_reporting_period_to_read = if cached_data.length < options[:limit]
       +              get_first_reporting_period(options)
       +            else
       +              ReportingPeriod.new(options[:grouping], cached_data.last.reporting_period).next
       +            end
       +            last_reporting_period_to_read = options[:end_date] ? ReportingPeriod.new(options[:grouping], options[:end_date]).last_date_time : nil
       +            yield(first_reporting_period_to_read.date_time, last_reporting_period_to_read)
                  end
                end
        
       @@ -110,6 +129,10 @@ module Simplabs #:nodoc:
                  end
                end
        
       +        def self.get_last_reporting_period(options)
       +          return ReportingPeriod.new(options[:grouping], options[:end_date]) if options[:end_date]
       +        end
       +
            end
        
          end
 (DIR) diff --git a/lib/simplabs/reports_as_sparkline/reporting_period.rb b/lib/simplabs/reports_as_sparkline/reporting_period.rb
       @@ -11,10 +11,18 @@ module Simplabs #:nodoc:
                @date_time = parse_date_time(date_time || DateTime.now)
              end
        
       +      def offset(offset)
       +        self.class.new(@grouping, @date_time + offset.send(@grouping.identifier))
       +      end
       +
              def self.first(grouping, limit, end_date = nil)
                self.new(grouping, end_date).offset(-limit)
              end
        
       +      def self.current(grouping)
       +        self.new(grouping, Time.now)
       +      end
       +
              def self.from_db_string(grouping, db_string)
                parts = grouping.date_parts_from_db_string(db_string)
                result = case grouping.identifier
       @@ -38,22 +46,24 @@ module Simplabs #:nodoc:
                self.offset(-1)
              end
        
       -      def offset(offset)
       -        self.class.new(@grouping, @date_time + offset.send(@grouping.identifier))
       -      end
       -
              def ==(other)
       -        if other.class == Simplabs::ReportsAsSparkline::ReportingPeriod
       -          return @date_time.to_s == other.date_time.to_s && @grouping.identifier.to_s == other.grouping.identifier.to_s
       +        if other.is_a?(Simplabs::ReportsAsSparkline::ReportingPeriod)
       +          @date_time.to_s == other.date_time.to_s && @grouping.identifier.to_s == other.grouping.identifier.to_s
       +        elsif other.is_a?(Time) || other.is_a?(DateTime)
       +          @date_time == parse_date_time(other)
       +        else
       +          raise ArgumentError.new("Can only compare instances of #{self.class.name}")
                end
       -        false
              end
        
              def <(other)
       -        if other.class == Simplabs::ReportsAsSparkline::ReportingPeriod
       +        if other.is_a?(Simplabs::ReportsAsSparkline::ReportingPeriod)
                  return @date_time < other.date_time
       +        elsif other.is_a?(Time) || other.is_a?(DateTime)
       +          @date_time < parse_date_time(other)
       +        else
       +          raise ArgumentError.new("Can only compare instances of #{self.class.name}")
                end
       -        raise ArgumentError.new("Can only compare instances of #{Simplabs::ReportsAsSparkline::ReportingPeriod.klass}")
              end
        
              def last_date_time
 (DIR) diff --git a/spec/classes/report_cache_spec.rb b/spec/classes/report_cache_spec.rb
       @@ -6,6 +6,19 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
            @report = Simplabs::ReportsAsSparkline::Report.new(User, :registrations, :limit => 10)
          end
        
       +  describe '.clear_for' do
       +
       +    it 'should delete all entries in the cache for the klass and report name' do
       +      Simplabs::ReportsAsSparkline::ReportCache.should_receive(:delete_all).once.with(:conditions => {
       +        :model_name  => User.name,
       +        :report_name => 'registrations'
       +      })
       +
       +      Simplabs::ReportsAsSparkline::ReportCache.clear_for(User, :registrations)
       +    end
       +
       +  end
       +
          describe '.process' do
        
            before do
       @@ -37,17 +50,31 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
                }.should raise_error(YieldMatchException)
              end
        
       -      it 'should yield the reporting period after the last one in the cache if data was read from cache' do
       +      it 'should yield the first reporting period if not all required data could be retrieved from the cache' do
                reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(
                  @report.options[:grouping],
                  Time.now - 3.send(@report.options[:grouping].identifier)
                )
       +        Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return([Simplabs::ReportsAsSparkline::ReportCache.new])
       +
       +        Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options) do |begin_at, end_at|
       +          begin_at.should == Simplabs::ReportsAsSparkline::ReportingPeriod.first(@report.options[:grouping], @report.options[:limit]).date_time
       +          end_at.should   == nil
       +          []
       +        end
       +      end
       +
       +      it 'should yield the reporting period after the last one in the cache if all required data could be retrieved from the cache' do
       +        reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(
       +          @report.options[:grouping],
       +          Time.now - @report.options[:limit].send(@report.options[:grouping].identifier)
       +        )
                cached = Simplabs::ReportsAsSparkline::ReportCache.new
                cached.stub!(:reporting_period).and_return(reporting_period.date_time)
       -        Simplabs::ReportsAsSparkline::ReportCache.stub!(:find).and_return([cached])
       +        Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return(Array.new(@report.options[:limit] - 1, Simplabs::ReportsAsSparkline::ReportCache.new), cached)
        
                Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options) do |begin_at, end_at|
       -          begin_at.should == reporting_period.next.date_time
       +          begin_at.should == reporting_period.date_time
                  end_at.should   == nil
                  []
                end
       @@ -57,75 +84,73 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
        
            describe 'with :live_data = false' do
        
       -      it 'should not yield to the block if data for the reporting period before the current one has been found in the cache' do
       -        cached = Simplabs::ReportsAsSparkline::ReportCache.new
       -        cached.stub!(:reporting_period).and_return(Simplabs::ReportsAsSparkline::ReportingPeriod.new(@report.options[:grouping]).previous)
       -        Simplabs::ReportsAsSparkline::ReportCache.stub!(:find).and_return([cached])
       +      it 'should not yield if all required data could be retrieved from the cache' do
       +        Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return(Array.new(@report.options[:limit], Simplabs::ReportsAsSparkline::ReportCache.new))
       +
                lambda {
                  Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.options) { raise YieldMatchException.new }
                }.should_not raise_error(YieldMatchException)
              end
        
       -      it 'should yield to the block if no data for the reporting period before the current one has been found in the cache' do
       +      it 'should yield to the block if no data could be retrieved from the cache' do
       +        Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return([])
       +
                lambda {
                  Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.options) { raise YieldMatchException.new }
                }.should raise_error(YieldMatchException)
              end
        
       -      it 'should yield the reporting period after the last one in the cache if data was read from cache' do
       -        reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(
       -          @report.options[:grouping],
       -          Time.now - 3.send(@report.options[:grouping].identifier)
       -        )
       -        cached = Simplabs::ReportsAsSparkline::ReportCache.new
       -        cached.stub!(:reporting_period).and_return(reporting_period.date_time)
       -        Simplabs::ReportsAsSparkline::ReportCache.stub!(:find).and_return([cached])
       +      describe 'with :end_date = <some date>' do
        
       -        Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.options) do |begin_at, end_at|
       -          begin_at.should == reporting_period.next.date_time
       -          end_at.should == nil
       -          []
       +        before do
       +          @options = @report.options.merge(:end_date => Time.now)
                end
       +
       +        it 'should yield the last date and time of the reporting period for the specified end date' do
       +          reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(@report.options[:grouping], @options[:end_date])
       +
       +          Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options) do |begin_at, end_at|
       +            end_at.should   == reporting_period.last_date_time
       +            []
       +          end
       +        end
       +
              end
        
            end
        
            it 'should read existing data from the cache' do
       -      Simplabs::ReportsAsSparkline::ReportCache.should_receive(:find).once.with(
       -        :all,
       +      Simplabs::ReportsAsSparkline::ReportCache.should_receive(:all).once.with(
                :conditions => [
       -          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND run_limit = ? AND reporting_period >= ?',
       +          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND reporting_period >= ?',
                  @report.klass.to_s,
                  @report.name.to_s,
                  @report.options[:grouping].identifier.to_s,
                  @report.aggregation.to_s,
       -          10,
                  Simplabs::ReportsAsSparkline::ReportingPeriod.first(@report.options[:grouping], 10).date_time
                ],
                :limit => 10,
                :order => 'reporting_period ASC'
       -      )
       +      ).and_return([])
        
              Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.options) { [] }
            end
        
            it 'should utilize the end_date in the conditions' do
              end_date = Time.now
       -      Simplabs::ReportsAsSparkline::ReportCache.should_receive(:find).once.with(
       -        :all,
       +      Simplabs::ReportsAsSparkline::ReportCache.should_receive(:all).once.with(
                :conditions => [
       -          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND run_limit = ? AND reporting_period BETWEEN ? AND ?',
       +          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND reporting_period BETWEEN ? AND ?',
                  @report.klass.to_s,
                  @report.name.to_s,
                  @report.options[:grouping].identifier.to_s,
                  @report.aggregation.to_s,
       -          10,
                  Simplabs::ReportsAsSparkline::ReportingPeriod.first(@report.options[:grouping], 9).date_time,
                  Simplabs::ReportsAsSparkline::ReportingPeriod.new(@report.options[:grouping], end_date).date_time
                ],
                :limit => 10,
                :order => 'reporting_period ASC'
       -      )
       +      ).and_return([])
        
              Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.options.merge(:end_date => end_date)) { [] }
            end
       @@ -135,17 +160,16 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
              Simplabs::ReportsAsSparkline::ReportCache.should_receive(:find).once.with(
                :all,
                :conditions => [
       -          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND run_limit = ? AND reporting_period >= ?',
       +          'model_name = ? AND report_name = ? AND grouping = ? AND aggregation = ? AND reporting_period >= ?',
                  @report.klass.to_s,
                  @report.name.to_s,
                  grouping.identifier.to_s,
                  @report.aggregation.to_s,
       -          10,
                  Simplabs::ReportsAsSparkline::ReportingPeriod.first(grouping, 10).date_time
                ],
                :limit => 10,
                :order => 'reporting_period ASC'
       -      )
       +      ).and_return([])
        
              Simplabs::ReportsAsSparkline::ReportCache.process(@report, { :limit => 10, :grouping => grouping }) { [] }
            end
       @@ -193,7 +217,6 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
              Simplabs::ReportsAsSparkline::ReportCache.should_receive(:build_cached_data).exactly(10).times.with(
                @report,
                @report.options[:grouping],
       -        10,
                anything(),
                0.0
              ).and_return(@cached)
       @@ -205,14 +228,12 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
              Simplabs::ReportsAsSparkline::ReportCache.should_receive(:build_cached_data).exactly(9).times.with(
                @report,
                @report.options[:grouping],
       -        10,
                anything(),
                0.0
              ).and_return(@cached)
              Simplabs::ReportsAsSparkline::ReportCache.should_receive(:build_cached_data).once.with(
                @report,
                @report.options[:grouping],
       -        10,
                @current_reporting_period.previous,
                1.0
              ).and_return(@cached)
 (DIR) diff --git a/spec/classes/report_spec.rb b/spec/classes/report_spec.rb
       @@ -321,6 +321,26 @@ describe Simplabs::ReportsAsSparkline::Report do
                        result[6][1].should  == 0.0
                      end
        
       +              it 'should return correct results when run twice in a row with an end date further in the past on the second run' do
       +                @report = Simplabs::ReportsAsSparkline::Report.new(User, :registrations,
       +                  :aggregation => :count,
       +                  :grouping    => grouping,
       +                  :limit       => 10,
       +                  :live_data   => live_data
       +                )
       +                result = @report.run(:end_date => Time.now - 1.send(grouping)).to_a
       +
       +                result[9][1].should  == 1.0
       +                result[8][1].should  == 0.0
       +                result[7][1].should  == 2.0
       +
       +                result = @report.run(:end_date => Time.now - 3.send(grouping)).to_a
       +
       +                result[9][1].should  == 2.0
       +                result[8][1].should  == 0.0
       +                result[7][1].should  == 0.0
       +              end
       +
                    end
        
                  end
 (DIR) diff --git a/spec/classes/reporting_period_spec.rb b/spec/classes/reporting_period_spec.rb
       @@ -245,6 +245,54 @@ describe Simplabs::ReportsAsSparkline::ReportingPeriod do
              (reporting_period1 == reporting_period2).should == false
            end
        
       +    describe 'when invoked with DateTimes or Times' do
       +
       +      describe 'for grouping :hour' do
       +
       +        it 'should return true when the date and hour are equal' do
       +          date_time = DateTime.new(2008, 10, 30, 12)
       +          reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(Simplabs::ReportsAsSparkline::Grouping.new(:hour), date_time)
       +
       +          reporting_period.should == date_time
       +        end
       +
       +      end
       +
       +      describe 'for grouping :day' do
       +
       +        it 'should return true when the date is equal' do
       +          date_time = DateTime.new(2008, 10, 30)
       +          reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(Simplabs::ReportsAsSparkline::Grouping.new(:day), date_time)
       +
       +          reporting_period.should == date_time
       +        end
       +
       +      end
       +
       +      describe 'for grouping :week' do
       +
       +        it 'should return true when the date of the first day in that week is equal' do
       +          date_time = DateTime.new(2009, 5, 4) #monday (first day of the week for reports_asp_sparkline)
       +          reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(Simplabs::ReportsAsSparkline::Grouping.new(:week), date_time)
       +
       +          reporting_period.should == DateTime.new(2009, 5, 7) #thursday of same week, should be equal
       +        end
       +
       +      end
       +
       +      describe 'for grouping :month' do
       +
       +        it 'should return true when the date of the first day in that month is equal' do
       +          date_time = DateTime.new(2009, 5, 1)
       +          reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(Simplabs::ReportsAsSparkline::Grouping.new(:month), date_time)
       +
       +          reporting_period.should == DateTime.new(2009, 5, 17)
       +        end
       +
       +      end
       +
       +    end
       +
          end
        
          describe '.first' do
 (DIR) diff --git a/spec/db/schema.rb b/spec/db/schema.rb
       @@ -15,7 +15,6 @@ ActiveRecord::Schema.define(:version => 1) do
            t.string   :aggregation,      :null => false
            t.float    :value,            :null => false, :default => 0
            t.datetime :reporting_period, :null => false
       -    t.integer  :run_limit,        :null => false
        
            t.timestamps
          end
       @@ -23,16 +22,14 @@ ActiveRecord::Schema.define(:version => 1) do
            :model_name,
            :report_name,
            :grouping,
       -    :aggregation,
       -    :run_limit
       +    :aggregation
          ], :name => :name_model_grouping_agregation_run_limit
          add_index :reports_as_sparkline_cache, [
            :model_name,
            :report_name,
            :grouping,
            :aggregation,
       -    :reporting_period,
       -    :run_limit
       +    :reporting_period
          ], :unique => true, :name => :name_model_grouping_aggregation_period_run_limit
        
        end