Introduction
Introduction Statistics Contact Development Disclaimer Help
update to v1.3 - reportable - Fork of reportable required by WarVox, from hdm/r…
Log
Files
Refs
README
---
commit 1b697477d79a5e17e869b4acc1f6be4330226037
parent 80083c77564a3a852216fa1891136540ada6963b
Author: Marco Otte-Witte <[email protected]>
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(-)
---
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 woul…
+* Entries in the report cache entry are no longer identified by the :limit the…
+* rewrote the data retrieval and processing code, it's now much more compact a…
+
=== v1.2
* FIXED: duplicate key error when using custom time zones (thanks to myronmars…
diff --git a/README.rdoc b/README.rdoc
@@ -43,6 +43,26 @@ When invoking the report, you can override some of the optio…
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,…
+<b>Beware that when you modify data in the cache, report results may be incorr…
+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 vi…
<%= 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…
add_index :[table], :[date_column], :functional => "date_trunc('year', [date…
+You might also want to use fragment caching in your views since processing the…
+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
diff --git a/doc/classes/Simplabs/ReportsAsSparkline/ClassMethods.html b/doc/cl…
@@ -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_colum…
@@ -186,20 +181,20 @@ the <tt>:limit</tt> reporting periods until this date.
onclick="toggleCode('M000002-source');return false;">[Source]</a><…
<div class="method-source-code" id="M000002-source">
<pre>
- <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline.rb…
-41: <span class="ruby-keyword kw">def</span> <span class="ruby-identifie…
-42: (<span class="ruby-keyword kw">class</span> <span class="ruby-oper…
-43: <span class="ruby-identifier">define_method</span> <span class="…
-44: <span class="ruby-keyword kw">if</span> <span class="ruby-iden…
-45: <span class="ruby-identifier">report</span> = <span class="r…
-46: <span class="ruby-keyword kw">else</span>
-47: <span class="ruby-identifier">report</span> = <span class="r…
-48: <span class="ruby-keyword kw">end</span>
-49: <span class="ruby-identifier">raise</span> <span class="ruby-c…
-50: <span class="ruby-identifier">report</span>.<span class="ruby-…
-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…
+36: <span class="ruby-keyword kw">def</span> <span class="ruby-identifie…
+37: (<span class="ruby-keyword kw">class</span> <span class="ruby-oper…
+38: <span class="ruby-identifier">define_method</span> <span class="…
+39: <span class="ruby-keyword kw">if</span> <span class="ruby-iden…
+40: <span class="ruby-identifier">report</span> = <span class="r…
+41: <span class="ruby-keyword kw">else</span>
+42: <span class="ruby-identifier">report</span> = <span class="r…
+43: <span class="ruby-keyword kw">end</span>
+44: <span class="ruby-identifier">raise</span> <span class="ruby-c…
+45: <span class="ruby-identifier">report</span>.<span class="ruby-…
+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>
diff --git a/doc/classes/Simplabs/ReportsAsSparkline/CumulatedReport.html b/doc…
@@ -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><…
diff --git a/doc/classes/Simplabs/ReportsAsSparkline/Report.html b/doc/classes/…
@@ -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…
</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><…
- <div class="method-source-code" id="M000006-source">
+ onclick="toggleCode('M000007-source');return false;">[Source]</a><…
+ <div class="method-source-code" id="M000007-source">
<pre>
<span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/re…
24: <span class="ruby-keyword kw">def</span> <span class="ruby-identifie…
@@ -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">(optio…
</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><…
- <div class="method-source-code" id="M000007-source">
+ onclick="toggleCode('M000008-source');return false;">[Source]</a><…
+ <div class="method-source-code" id="M000008-source">
<pre>
<span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/re…
50: <span class="ruby-keyword kw">def</span> <span class="ruby-identifie…
diff --git a/doc/classes/Simplabs/ReportsAsSparkline/ReportCache.html b/doc/cla…
@@ -85,8 +85,7 @@ The <a href="ReportCache.html">ReportCache</a> class is a reg…
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">…
+ </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><…
+ <div class="method-source-code" id="M000006-source">
+<pre>
+ <span class="ruby-comment cmt"># File lib/simplabs/reports_as_sparkline/re…
+26: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword k…
+27: <span class="ruby-keyword kw">self</span>.<span class="ruby-identi…
+28: <span class="ruby-identifier">:model_name</span> =<span class="…
+29: <span class="ruby-identifier">:report_name</span> =<span class="…
+30: })
+31: <span class="ruby-keyword kw">end</span>
+</pre>
+ </div>
+ </div>
+ </div>
+
+
+ </div>
</div>
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
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::Repor…
+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 indice…
add_index :[table], :[date_column], :functional =&gt; &quot;date_trunc('week…
add_index :[table], :[date_column], :functional =&gt; &quot;date_trunc('year…
</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
diff --git a/doc/files/lib/simplabs/reports_as_sparkline/grouping_rb.html b/doc…
@@ -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>
diff --git a/doc/files/lib/simplabs/reports_as_sparkline/report_cache_rb.html b…
@@ -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>
diff --git a/doc/files/lib/simplabs/reports_as_sparkline/report_rb.html b/doc/f…
@@ -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>
diff --git a/doc/files/lib/simplabs/reports_as_sparkline/reporting_period_rb.ht…
@@ -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>
diff --git a/doc/files/lib/simplabs/reports_as_sparkline_rb.html b/doc/files/li…
@@ -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>
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">cle…
<a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000004"…
<a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000005"…
- <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000006">new (Sim…
+ <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000007">new (Sim…
<a href="classes/Simplabs/ReportsAsSparkline/ClassMethods.html#M000002">re…
<a href="classes/Simplabs/ReportsAsSparkline/CumulatedReport.html#M000003"…
- <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000007">run (Sim…
+ <a href="classes/Simplabs/ReportsAsSparkline/Report.html#M000008">run (Sim…
<a href="classes/Simplabs/ReportsAsSparkline/SparklineTagHelper.html#M0000…
</div>
</div>
diff --git a/lib/simplabs/reports_as_sparkline.rb b/lib/simplabs/reports_as_spa…
@@ -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_…
diff --git a/lib/simplabs/reports_as_sparkline/grouping.rb b/lib/simplabs/repor…
@@ -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
diff --git a/lib/simplabs/reports_as_sparkline/report.rb b/lib/simplabs/reports…
@@ -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
diff --git a/lib/simplabs/reports_as_sparkline/report_cache.rb b/lib/simplabs/r…
@@ -3,32 +3,41 @@ module Simplabs #:nodoc:
module ReportsAsSparkline #:nodoc:
# The ReportCache class is a regular +ActiveRecord+ model and represents c…
- # ReportCache instances are identified by the combination of +model_name+,…
+ # ReportCache instances are identified by the combination of +model_name+,…
class ReportCache < ActiveRecord::Base
set_table_name :reports_as_sparkline_cache
- # When reporting_period has a time zone conversion performed, we get dup…
- # This occurs because find_cached_data will return a record set that is …
- # have an end date. The SQL criteria reporting_period BETWEEN before_da…
- # the last record that it should, because our end_date will not be time-…
- # the reported_period in the database will be time-zone converted (ex: 5…
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, :registrati…
+ 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(opt…
-
if cache
- cached_data = find_cached_data(report, options, first_reporting_pe…
- first_cached_reporting_period = cached_data.empty? ? nil : Reporti…
- last_cached_reporting_period = cached_data.empty? ? nil : Reportin…
+ cached_data = read_cached_data(report, options)
end
- new_data = read_new_data(first_reporting_period, last_reporting_peri…
-
+ 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 …
new_data = new_data.map { |data| [ReportingPeriod.from_db_string(opt…
- result = cached_data.map { |cached| [cached.reporting_period, cached…
- last_reporting_period = ReportingPeriod.new(options[:grouping])
- reporting_period = cached_data.empty? ? get_first_reporting_period(o…
- while reporting_period < (options[:end_date] ? ReportingPeriod.new(o…
- cached = build_cached_data(report, options[:grouping], options[:li…
- cached.save! if cache
- result << [reporting_period.date_time, cached.value]
+ cached_data.map! { |cached| [ReportingPeriod.new(options[:grouping],…
+ current_reporting_period = ReportingPeriod.current(options[:grouping…
+ reporting_period = get_first_reporting_period(options)
+ result = []
+ while reporting_period < (options[:end_date] ? ReportingPeriod.new(o…
+ if cached = cached_data.find { |cached| reporting_period == cached…
+ result << cached
+ else
+ new_cached = build_cached_data(report, options[:grouping], repor…
+ 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, l…
+ result << [current_reporting_period.date_time, find_value(new_data…
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, …
+ 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, las…
+ def self.read_cached_data(report, options)
conditions = [
- 'model_name = ? AND report_name = ? AND grouping = ? AND aggregati…
+ 'model_name = ? AND report_name = ? AND grouping = ? AND aggregati…
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, …
- if !options[:live_data] && last_cached_reporting_period == Reporting…
+ 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_…
- yield((last_cached_reporting_period.next rescue first_reporting_pe…
+ first_reporting_period_to_read = if cached_data.length < options[:…
+ get_first_reporting_period(options)
+ else
+ ReportingPeriod.new(options[:grouping], cached_data.last.reporti…
+ end
+ last_reporting_period_to_read = options[:end_date] ? ReportingPeri…
+ yield(first_reporting_period_to_read.date_time, last_reporting_per…
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]) i…
+ end
+
end
end
diff --git a/lib/simplabs/reports_as_sparkline/reporting_period.rb b/lib/simpla…
@@ -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.identifie…
+ 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.identifie…
- end
-
def ==(other)
- if other.class == Simplabs::ReportsAsSparkline::ReportingPeriod
- return @date_time.to_s == other.date_time.to_s && @grouping.identifi…
+ if other.is_a?(Simplabs::ReportsAsSparkline::ReportingPeriod)
+ @date_time.to_s == other.date_time.to_s && @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.…
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.…
end
- raise ArgumentError.new("Can only compare instances of #{Simplabs::Rep…
end
def last_date_time
diff --git a/spec/classes/report_cache_spec.rb b/spec/classes/report_cache_spec…
@@ -6,6 +6,19 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
@report = Simplabs::ReportsAsSparkline::Report.new(User, :registrations, :…
end
+ describe '.clear_for' do
+
+ it 'should delete all entries in the cache for the klass and report name' …
+ Simplabs::ReportsAsSparkline::ReportCache.should_receive(:delete_all).on…
+ :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…
+ it 'should yield the first reporting period if not all required data cou…
reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(
@report.options[:grouping],
Time.now - 3.send(@report.options[:grouping].identifier)
)
+ Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return([Simp…
+
+ Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options) d…
+ begin_at.should == Simplabs::ReportsAsSparkline::ReportingPeriod.fir…
+ end_at.should == nil
+ []
+ end
+ end
+
+ it 'should yield the reporting period after the last one in the cache if…
+ reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new(
+ @report.options[:grouping],
+ Time.now - @report.options[:limit].send(@report.options[:grouping].i…
+ )
cached = Simplabs::ReportsAsSparkline::ReportCache.new
cached.stub!(:reporting_period).and_return(reporting_period.date_time)
- Simplabs::ReportsAsSparkline::ReportCache.stub!(:find).and_return([cac…
+ Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return(Array…
Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options) d…
- 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 befor…
- cached = Simplabs::ReportsAsSparkline::ReportCache.new
- cached.stub!(:reporting_period).and_return(Simplabs::ReportsAsSparklin…
- Simplabs::ReportsAsSparkline::ReportCache.stub!(:find).and_return([cac…
+ it 'should not yield if all required data could be retrieved from the ca…
+ Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return(Array…
+
lambda {
Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.o…
}.should_not raise_error(YieldMatchException)
end
- it 'should yield to the block if no data for the reporting period before…
+ it 'should yield to the block if no data could be retrieved from the cac…
+ Simplabs::ReportsAsSparkline::ReportCache.stub!(:all).and_return([])
+
lambda {
Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.o…
}.should raise_error(YieldMatchException)
end
- it 'should yield the reporting period after the last one in the cache if…
- 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([cac…
+ describe 'with :end_date = <some date>' do
- Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.opt…
- 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 th…
+ reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new…
+
+ Simplabs::ReportsAsSparkline::ReportCache.process(@report, @options)…
+ 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.wit…
- :all,
+ Simplabs::ReportsAsSparkline::ReportCache.should_receive(:all).once.with(
:conditions => [
- 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
+ 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
@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[…
],
:limit => 10,
:order => 'reporting_period ASC'
- )
+ ).and_return([])
Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.optio…
end
it 'should utilize the end_date in the conditions' do
end_date = Time.now
- Simplabs::ReportsAsSparkline::ReportCache.should_receive(:find).once.wit…
- :all,
+ Simplabs::ReportsAsSparkline::ReportCache.should_receive(:all).once.with(
:conditions => [
- 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
+ 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
@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[…
Simplabs::ReportsAsSparkline::ReportingPeriod.new(@report.options[:g…
],
:limit => 10,
:order => 'reporting_period ASC'
- )
+ ).and_return([])
Simplabs::ReportsAsSparkline::ReportCache.process(@report, @report.optio…
end
@@ -135,17 +160,16 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
Simplabs::ReportsAsSparkline::ReportCache.should_receive(:find).once.wit…
:all,
:conditions => [
- 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
+ 'model_name = ? AND report_name = ? AND grouping = ? AND aggregation…
@report.klass.to_s,
@report.name.to_s,
grouping.identifier.to_s,
@report.aggregation.to_s,
- 10,
Simplabs::ReportsAsSparkline::ReportingPeriod.first(grouping, 10).da…
],
:limit => 10,
:order => 'reporting_period ASC'
- )
+ ).and_return([])
Simplabs::ReportsAsSparkline::ReportCache.process(@report, { :limit => 1…
end
@@ -193,7 +217,6 @@ describe Simplabs::ReportsAsSparkline::ReportCache do
Simplabs::ReportsAsSparkline::ReportCache.should_receive(:build_cached_d…
@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_d…
@report,
@report.options[:grouping],
- 10,
anything(),
0.0
).and_return(@cached)
Simplabs::ReportsAsSparkline::ReportCache.should_receive(:build_cached_d…
@report,
@report.options[:grouping],
- 10,
@current_reporting_period.previous,
1.0
).and_return(@cached)
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 a…
+ @report = Simplabs::ReportsAsSparkline::Report.new(User, :regi…
+ :aggregation => :count,
+ :grouping => grouping,
+ :limit => 10,
+ :live_data => live_data
+ )
+ result = @report.run(:end_date => Time.now - 1.send(grouping))…
+
+ 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))…
+
+ result[9][1].should == 2.0
+ result[8][1].should == 0.0
+ result[7][1].should == 0.0
+ end
+
end
end
diff --git a/spec/classes/reporting_period_spec.rb b/spec/classes/reporting_per…
@@ -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…
+
+ 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…
+
+ 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 …
+ date_time = DateTime.new(2009, 5, 4) #monday (first day of the week …
+ reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new…
+
+ reporting_period.should == DateTime.new(2009, 5, 7) #thursday of sam…
+ end
+
+ end
+
+ describe 'for grouping :month' do
+
+ it 'should return true when the date of the first day in that month is…
+ date_time = DateTime.new(2009, 5, 1)
+ reporting_period = Simplabs::ReportsAsSparkline::ReportingPeriod.new…
+
+ reporting_period.should == DateTime.new(2009, 5, 17)
+ end
+
+ end
+
+ end
+
end
describe '.first' do
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_lim…
end
You are viewing proxied material from jay.scot. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.