Introduction
Introduction Statistics Contact Development Disclaimer Help
Merge branch 'master' of git://github.com/saulabs/reportable - reportable - For…
Log
Files
Refs
README
---
commit e2a282013a4ad968a58806bb0fc8e3efbab5bd8d
parent f8532eeb704c511bb75b5bd4fd9656243c9b118b
Author: HD Moore <[email protected]>
Date: Mon, 8 Sep 2014 01:08:56 -0500
Merge branch 'master' of git://github.com/saulabs/reportable
Conflicts:
lib/saulabs/reportable/report.rb
lib/saulabs/reportable/report_cache.rb
spec/classes/report_spec.rb
Diffstat:
M .travis.yml | 2 ++
M Gemfile | 14 +++++---------
M README.md | 1 +
M lib/saulabs/reportable.rb | 2 ++
M lib/saulabs/reportable/cumulated_r… | 2 +-
M lib/saulabs/reportable/report.rb | 23 +++++++++++++----------
M lib/saulabs/reportable/report_cach… | 65 +++++++++++++--------------…
M lib/saulabs/reportable/reporting_p… | 2 +-
M reportable.gemspec | 2 +-
M spec/classes/report_cache_spec.rb | 27 +++++++--------------------
M spec/classes/report_spec.rb | 9 +++++----
M spec/spec_helper.rb | 10 ++++++++--
12 files changed, 74 insertions(+), 85 deletions(-)
---
diff --git a/.travis.yml b/.travis.yml
@@ -1,4 +1,6 @@
language: ruby
rvm:
- 1.9.3
+ - 2.0.0
+ - 2.1.1
script: "rake spec"
diff --git a/Gemfile b/Gemfile
@@ -1,16 +1,12 @@
source "http://rubygems.org"
-gem 'rails', '~> 3.2.0'
-gem 'activerecord', '~> 3.2.0', :require => 'active_record'
-gem 'activesupport', '~> 3.2.0', :require => 'active_support'
-gem 'actionpack', '~> 3.2.0', :require => 'action_pack'
+gem 'rails', '~> 4.1.0'
+gem 'protected_attributes'
-gem 'sqlite3-ruby', '>= 1.2.0'
-gem 'mysql', '>= 2.8.0'
-gem 'pg', '>= 0.9.0'
-gem 'tzinfo', '>= 0.3.0'
+gem 'sqlite3'
+# gem 'mysql', '>= 2.8.0'
+gem 'pg'
-gem 'rake', '>= 0.8.7'
gem 'rspec', '~> 2.8.0'
gem 'simplecov'
gem 'excellent', '>= 1.5.4'
diff --git a/README.md b/README.md
@@ -1,5 +1,6 @@
Reportable
==========
+[![Build Status](https://travis-ci.org/saulabs/reportable.png?branch=master)](…
Reportable allows for the easy creation of reports based on `ActiveRecord` mod…
diff --git a/lib/saulabs/reportable.rb b/lib/saulabs/reportable.rb
@@ -38,6 +38,8 @@ module Saulabs
# the number of reporting periods to get (see +:grouping+)
# @option options [Hash] :conditions ({})
# conditions like in +ActiveRecord::Base#find+; only records that ma…
+ # @option options [Hash] :include ({})
+ # include like in +ActiveRecord::Base#find+; names associations that…
# @option options [Boolean] :live_data (false)
# specifies whether data for the current reporting period is to be r…
# @option options [DateTime, Boolean] :end_date (false)
diff --git a/lib/saulabs/reportable/cumulated_report.rb b/lib/saulabs/reportabl…
@@ -34,7 +34,7 @@ module Saulabs
def initial_cumulative_value(date, options)
conditions = setup_conditions(nil, date, options[:conditions])
- @klass.send(@aggregation, @value_column, :conditions => conditions)
+ @klass.where(conditions).calculate(@aggregation, @value_column)
end
end
diff --git a/lib/saulabs/reportable/report.rb b/lib/saulabs/reportable/report.rb
@@ -54,6 +54,8 @@ module Saulabs
# the number of reporting periods to get (see +:grouping+)
# @option options [Hash] :conditions ({})
# conditions like in +ActiveRecord::Base#find+; only records that matc…
+ # @option options [Hash] :include ({})
+ # include like in +ActiveRecord::Base#find+; names associations that s…
# @option options [Boolean] :live_data (false)
# specifies whether data for the current reporting period is to be rea…
# @option options [DateTime, Boolean] :end_date (false)
@@ -71,6 +73,7 @@ module Saulabs
@options = {
:limit => options[:limit] || 100,
:distinct => options[:distinct] || false,
+ :include => options[:include] || [],
:conditions => options[:conditions] || [],
:grouping => Grouping.new(options[:grouping] || :day),
:live_data => options[:live_data] || false,
@@ -122,14 +125,14 @@ module Saulabs
def read_data(begin_at, end_at, options)
conditions = setup_conditions(begin_at, end_at, options[:conditions])
- @klass.send(@aggregation,
- @value_column,
- :conditions => conditions,
- :distinct => options[:distinct],
- :group => options[:grouping].to_sql(@date_column),
- :order => "#{options[:grouping].to_sql(@date_column)} ASC",
- :limit => options[:limit]
- )
+ table_name = ActiveRecord::Base.connection.quote_table_name(@klass.t…
+ date_column = ActiveRecord::Base.connection.quote_column_name(@date_…
+ grouping = options[:grouping].to_sql("#{table_name}.#{date_column}")
+ order = "#{grouping} ASC"
+
+ @klass.where(conditions).includes(options[:include]).distinct(option…
+ group(grouping).order(order).limit(options[:limit]).
+ calculate(@aggregation, @value_column)
end
def setup_conditions(begin_at, end_at, custom_conditions = [])
@@ -153,13 +156,13 @@ module Saulabs
case context
when :initialize
options.each_key do |k|
- raise ArgumentError.new("Invalid option #{k}!") unless [:limit…
+ raise ArgumentError.new("Invalid option #{k}!") unless [:limit…
end
raise ArgumentError.new("Invalid aggregation #{options[:aggregat…
raise ArgumentError.new('The name of the column holding the valu…
when :run
options.each_key do |k|
- raise ArgumentError.new("Invalid option #{k}!") unless [:limit…
+ raise ArgumentError.new("Invalid option #{k}!") unless [:limit…
end
end
raise ArgumentError.new('Options :live_data and :end_date may not bo…
diff --git a/lib/saulabs/reportable/report_cache.rb b/lib/saulabs/reportable/re…
@@ -20,7 +20,7 @@ module Saulabs
validates_presence_of :value
validates_presence_of :reporting_period
- attr_accessible :model_name, :report_name, :grouping, :aggregation, :val…
+ # attr_accessible :model_name, :report_name, :grouping, :aggregation, :v…
self.skip_time_zone_conversion_for_attributes = [:reporting_period]
@@ -40,10 +40,7 @@ module Saulabs
# Saulabs::Reportable::ReportCache.clear_for(User, :registrations)
#
def self.clear_for(klass, report)
- self.delete_all(:conditions => {
- :model_name => klass.name,
- :report_name => report.to_s
- })
+ self.where(model_name: klass.name, report_name: report.to_s).delete_all
end
# Processes the report using the respective cache.
@@ -90,21 +87,20 @@ module Saulabs
private
def self.prepare_result(new_data, cached_data, report, options)
- new_data = new_data.map { |data| [ReportingPeriod.from_db_string(opt…
- cached_data.map! { |cached| [ReportingPeriod.new(options[:grouping],…
+ new_data = new_data.to_a.map { |data| [ReportingPeriod.from_db_strin…
+ cached_data.to_a.map! { |cached| [ReportingPeriod.new(options[:group…
current_reporting_period = ReportingPeriod.new(options[:grouping])
reporting_period = get_first_reporting_period(options)
result = []
while reporting_period < (options[:end_date] ? ReportingPeriod.new(o…
if options[:cacheable] and cached = cached_data.find { |cached| re…
result << [cached[0].date_time, cached[1]]
+ elsif reporting_period.last_date_time.past?
+ new_cached = build_cached_data(report, options[:grouping], optio…
+ new_cached.save!
+ result << [reporting_period.date_time, new_cached.value]
else
- value = find_value(new_data, reporting_period)
- if options[:cacheable]
- new_cached = build_cached_data(report, options[:grouping], opt…
- new_cached.save! if options[:cacheable]
- end
- result << [reporting_period.date_time, value]
+ result << [reporting_period.date_time, find_value(new_data, repo…
end
reporting_period = reporting_period.next
end
@@ -142,36 +138,31 @@ module Saulabs
end
def self.read_cached_data(report, options)
- return [] if not options[:cacheable]
- options[:conditions] ||= []
- conditions = [
- %w(model_name report_name grouping aggregation conditions).map do …
- "#{self.connection.quote_column_name(column_name)} = ?"
- end.join(' AND '),
- report.klass.to_s,
- report.name.to_s,
- options[:grouping].identifier.to_s,
- report.aggregation.to_s,
- serialize_conditions(options[:conditions])
- ]
- first_reporting_period = get_first_reporting_period(options)
+ conditions = build_conditions_for_reading_cached_data(report, option…
+ conditions.limit(options[:limit]).order('reporting_period ASC')
+ end
+
+ def self.build_conditions_for_reading_cached_data(report, options)
+ start_date = get_first_reporting_period(options).date_time
+
+ conditions = where('reporting_period >= ?', start_date).where(
+ model_name: report.klass.to_s,
+ report_name: report.name.to_s,
+ grouping: options[:grouping].identifier.to_s,
+ aggregation: report.aggregation.to_s,
+ conditions: serialize_conditions(options[:conditions] || [])
+ )
+
if options[:end_date]
- conditions.first << ' AND reporting_period BETWEEN ? AND ?'
- conditions << first_reporting_period.date_time
- conditions << ReportingPeriod.new(options[:grouping], options[:end…
+ end_date = ReportingPeriod.new(options[:grouping], options[:end_da…
+ conditions.where('reporting_period <= ?', end_date)
else
- conditions.first << ' AND reporting_period >= ?'
- conditions << first_reporting_period.date_time
+ conditions
end
- self.all(
- :conditions => conditions,
- :limit => options[:limit],
- :order => 'reporting_period ASC'
- )
end
def self.read_new_data(cached_data, options, &block)
- return [] if !options[:live_data] && cached_data.length == options[:…
+ return [] if !options[:live_data] && cached_data.size == options[:li…
first_reporting_period_to_read = get_first_reporting_period_to_read(…
last_reporting_period_to_read = options[:end_date] ? ReportingPeriod…
diff --git a/lib/saulabs/reportable/reporting_period.rb b/lib/saulabs/reportabl…
@@ -70,7 +70,7 @@ module Saulabs
# the reporting period for the {Saulabs::Reportable::Grouping} as pars…
#
def self.from_db_string(grouping, db_string)
- return self.new(grouping, db_string) if db_string.is_a?(Date)
+ return self.new(grouping, db_string) if db_string.is_a?(Date) || db_st…
parts = grouping.date_parts_from_db_string(db_string.to_s)
case grouping.identifier
when :hour
diff --git a/reportable.gemspec b/reportable.gemspec
@@ -14,7 +14,7 @@ pkg_files += Dir['spec/**/*.{rb,yml,opts}']
Gem::Specification.new do |s|
s.name = %q{reportable}
- s.version = '1.2.0'
+ s.version = '1.3.1'
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?(…
s.authors = ['Marco Otte-Witte', 'Martin Kavalar']
diff --git a/spec/classes/report_cache_spec.rb b/spec/classes/report_cache_spec…
@@ -91,19 +91,6 @@ describe Saulabs::Reportable::ReportCache do
end
- describe '.clear_for' do
-
- it 'should delete all entries in the cache for the klass and report name' …
- Saulabs::Reportable::ReportCache.should_receive(:delete_all).once.with(:…
- :model_name => User.name,
- :report_name => 'registrations'
- })
-
- Saulabs::Reportable::ReportCache.clear_for(User, :registrations)
- end
-
- end
-
describe '.process' do
before do
@@ -136,7 +123,7 @@ describe Saulabs::Reportable::ReportCache do
end
it 'should yield the first reporting period if not all required data cou…
- Saulabs::Reportable::ReportCache.stub!(:all).and_return([Saulabs::Repo…
+ Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return([…
Saulabs::Reportable::ReportCache.process(@report, @options) do |begin_…
begin_at.should == Saulabs::Reportable::ReportingPeriod.first(@repor…
@@ -152,7 +139,7 @@ describe Saulabs::Reportable::ReportCache do
)
cached = Saulabs::Reportable::ReportCache.new
cached.stub!(:reporting_period).and_return(reporting_period.date_time)
- Saulabs::Reportable::ReportCache.stub!(:all).and_return(Array.new(@rep…
+ Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return(A…
Saulabs::Reportable::ReportCache.process(@report, @options) do |begin_…
begin_at.should == reporting_period.date_time
@@ -166,7 +153,7 @@ describe Saulabs::Reportable::ReportCache do
describe 'with :live_data = false' do
it 'should not yield if all required data could be retrieved from the ca…
- Saulabs::Reportable::ReportCache.stub!(:all).and_return(Array.new(@rep…
+ Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return(A…
lambda {
Saulabs::Reportable::ReportCache.process(@report, @report.options) {…
@@ -174,7 +161,7 @@ describe Saulabs::Reportable::ReportCache do
end
it 'should yield to the block if no data could be retrieved from the cac…
- Saulabs::Reportable::ReportCache.stub!(:all).and_return([])
+ Saulabs::Reportable::ReportCache.stub!(:read_cached_data).and_return([…
lambda {
Saulabs::Reportable::ReportCache.process(@report, @report.options) {…
@@ -200,7 +187,7 @@ describe Saulabs::Reportable::ReportCache do
end
- it 'should read existing data from the cache' do
+ xit 'should read existing data from the cache' do
Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
:conditions => [
%w(model_name report_name grouping aggregation conditions).map do |c…
@@ -220,7 +207,7 @@ describe Saulabs::Reportable::ReportCache do
Saulabs::Reportable::ReportCache.process(@report, @report.options) { [] }
end
- it 'should utilize the end_date in the conditions' do
+ xit 'should utilize the end_date in the conditions' do
end_date = Time.now - 1.send(@report.options[:grouping].identifier)
Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
:conditions => [
@@ -242,7 +229,7 @@ describe Saulabs::Reportable::ReportCache do
Saulabs::Reportable::ReportCache.process(@report, @report.options.merge(…
end
- it "should read existing data from the cache for the correct grouping if o…
+ xit "should read existing data from the cache for the correct grouping if …
grouping = Saulabs::Reportable::Grouping.new(:month)
Saulabs::Reportable::ReportCache.should_receive(:all).once.with(
:conditions => [
diff --git a/spec/classes/report_spec.rb b/spec/classes/report_spec.rb
@@ -21,7 +21,8 @@ describe Saulabs::Reportable::Report do
it 'should process the data with the report cache' do
Saulabs::Reportable::ReportCache.should_receive(:process).once.with(
@report,
- { :limit => 100, :grouping => @report.options[:grouping], :conditions …
+
+ { :limit => 100, :grouping => @report.options[:grouping], :conditions …
)
@report.run
@@ -30,7 +31,7 @@ describe Saulabs::Reportable::Report do
it 'should process the data with the report cache when custom conditions a…
Saulabs::Reportable::ReportCache.should_receive(:process).once.with(
@report,
- { :limit => 100, :grouping => @report.options[:grouping], :conditions …
+ { :limit => 100, :grouping => @report.options[:grouping], :conditions …
)
@report.run(:conditions => { :some => :condition })
@@ -47,7 +48,7 @@ describe Saulabs::Reportable::Report do
Saulabs::Reportable::Grouping.should_receive(:new).once.with(:month).and…
Saulabs::Reportable::ReportCache.should_receive(:process).once.with(
@report,
- { :limit => 100, :grouping => grouping, :conditions => [], :live_data …
+ { :limit => 100, :grouping => grouping, :conditions => [], :live_data …
)
@report.run(:grouping => :month)
@@ -581,7 +582,7 @@ describe Saulabs::Reportable::Report do
describe '#read_data' do
- it 'should invoke the aggregation method on the model' do
+ xit 'should invoke the aggregation method on the model' do
@report = Saulabs::Reportable::Report.new(User, :registrations, :aggrega…
User.should_receive(:count).once.and_return([])
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
@@ -27,8 +27,14 @@ require File.join(ROOT, 'lib', 'saulabs', 'reportable.rb')
# config.time_zone = 'Pacific Time (US & Canada)'
# end
-FileUtils.mkdir_p File.join(File.dirname(__FILE__), 'log')
-ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__F…
+# FileUtils.mkdir_p File.join(File.dirname(__FILE__), 'log')
+# ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(_…
+
+RSpec.configure do |config|
+ config.filter_run :focus => true
+ config.run_all_when_everything_filtered = true
+end
+ActiveRecord::Base.default_timezone = :local
databases = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'db', 'databa…
ActiveRecord::Base.establish_connection(databases[ENV['DB'] || 'sqlite3'])
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.