Setting up specs to run on mysql - reportable - Fork of reportable required by WarVox, from hdm/reportable.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 400b8c6b4167aa2e93683aa7ff34d0758c5292b5
 (DIR) parent 5d9e03aa1f738e273aeca4d0ba7dca3107ec3657
 (HTM) Author: Martin Kavalar <kavalar@gmail.com>
       Date:   Mon, 12 May 2008 14:46:47 +0200
       
       Setting up specs to run on mysql
       
       Diffstat:
         A History.txt                         |       0 
         A Manifest.txt                        |       0 
         A README.txt                          |      47 +++++++++++++++++++++++++++++++
         M lib/reports_as_sparkline/report.rb  |     281 ++++++++++++++++---------------
         A lib/reports_as_sparkline/report_ca… |       0 
         A spec/boot.rb                        |      23 +++++++++++++++++++++++
         M spec/db/database.yml                |       4 ++--
         M spec/db/schema.rb                   |      11 +++++++++++
         M spec/reports_as_sparkline_spec.rb   |       4 ++--
         M spec/spec_helper.rb                 |      48 +++++++++++++++++++++++++++++--
       
       10 files changed, 271 insertions(+), 147 deletions(-)
       ---
 (DIR) diff --git a/History.txt b/History.txt
 (DIR) diff --git a/Manifest.txt b/Manifest.txt
 (DIR) diff --git a/README.txt b/README.txt
       @@ -0,0 +1,46 @@
       += reports_as_sparkline
       +
       +* http://github.com/mk/reports_as_sparkline
       +
       +== DESCRIPTION:
       +
       +FIX (describe your package)
       +
       +== FEATURES/PROBLEMS:
       +
       +* FIX (list of features or problems)
       +
       +== SYNOPSIS:
       +
       +  FIX (code sample of usage)
       +
       +== REQUIREMENTS:
       +
       +* edge rails
       +
       +== INSTALL:
       +
       +* sudo gem install reports_as_sparkline
       +
       +== LICENSE:
       +
       +Copyright (c) 2008 Martin Kavalar
       +
       +Permission is hereby granted, free of charge, to any person obtaining
       +a copy of this software and associated documentation files (the
       +'Software'), to deal in the Software without restriction, including
       +without limitation the rights to use, copy, modify, merge, publish,
       +distribute, sublicense, and/or sell copies of the Software, and to
       +permit persons to whom the Software is furnished to do so, subject to
       +the following conditions:
       +
       +The above copyright notice and this permission notice shall be
       +included in all copies or substantial portions of the Software.
       +
       +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
       +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
       +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
       +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       +\ No newline at end of file
 (DIR) diff --git a/lib/reports_as_sparkline/report.rb b/lib/reports_as_sparkline/report.rb
       @@ -1,155 +1,156 @@
        module ReportsAsSparkline   #:nodoc:
       -    def self.included(base) 
       -      base.extend ClassMethods
       -    end
       -    
       -    class InvalidGroupExpception < Exception
       -    end
       -    
       -    class InvalidOperationExpception < Exception
       -    end
       -    
       -    class ReportingGroup
       -      @@ranges = [:month, :week, :day, :hour]
       -      
       -      attr_reader :group
       -      
       -      def initialize(range)
       -        raise Kvlr::ReportsAsSparkline::InvalidGroupExpception unless @@ranges.include?(range.to_sym)
       -        @group = range.to_sym
       -      end
       -      
       -      def group_sql(attribute)
       -        attribute = attribute.to_s
       -        raise "No date_column given" if attribute.blank?
       -        case @group
       -        when :day
       -          group_by = "DATE(#{attribute})"
       -        when :week
       -          group_by = "YEARWEEK(#{attribute})"
       -        when :month
       -          group_by = "YEAR(#{attribute}) * 100 +  MONTH(#{attribute})"
       -        when :hour
       -          group_by = "DATE(#{attribute}) + HOUR(#{attribute})"
       -        end
       -        group_by
       -      end
       -      
       -      def latest_datetime
       -        case @group
       -        
       -        when :day, :week, :month
       -          return 1.send(@group).ago.to_date.to_datetime
       -        when :hour
       -          return 1.day.ago.to_date.to_datetime
       -        end
       -      end
       -      
       -      def self.default
       -        :day
       -      end
       +  def self.included(base) 
       +    base.extend ClassMethods
       +  end
       +  
       +  class ReportCache < ActiveRecord::Base
       +  end
       +
       +  class InvalidGroupExpception < Exception
       +  end
       +
       +  class InvalidOperationExpception < Exception
       +  end
       +
       +  class ReportingGroup
       +    @@ranges = [:month, :week, :day, :hour]
       +
       +    attr_reader :group
       +
       +    def initialize(range)
       +      raise ReportsAsSparkline::InvalidGroupExpception unless @@ranges.include?(range.to_sym)
       +      @group = range.to_sym
            end
       -    
       -    class ReportingOperation
       -      @@operations = [:count, :sum]
       -      
       -      attr_reader :operation
       -      
       -      def initialize(op)
       -        raise Kvlr::ReportsAsSparkline::InvalidOperationExpception unless @@operations.include?(op.to_sym)
       -        @operation = op.to_sym
       -      end
       -      
       -      def self.default
       -        :count
       +
       +    def group_sql(attribute)
       +      attribute = attribute.to_s
       +      raise "No date_column given" if attribute.blank?
       +      case @group
       +      when :day
       +        group_by = "DATE(#{attribute})"
       +      when :week
       +        group_by = "YEARWEEK(#{attribute})"
       +      when :month
       +        group_by = "YEAR(#{attribute}) * 100 +  MONTH(#{attribute})"
       +      when :hour
       +        group_by = "DATE(#{attribute}) + HOUR(#{attribute})"
              end
       +      group_by
            end
       -    
        
       -    class Report
       -      
       -      @@default_statement_options = {:limit => 100, :operation => ReportingOperation.default, :group => ReportingGroup.default, :date_column => 'created_at'}
       -      attr_reader :name, :operation, :date_column, :value_column, :graph_options, :statement_options, :reporting_group
       -
       -      def initialize(name, options)
       -        @name  = name.to_sym
       -        @value_column = (options[:value_column] || @name).to_sym
       -        @statement_options = @@default_statement_options.merge options
       -        
       -        @reporting_group = ReportingGroup.new(@statement_options[:group])
       -        @reporting_operation = ReportingOperation.new(@statement_options[:operation])
       -      end
       +    def latest_datetime
       +      case @group
          
       -      def report(klass, options)
       -        statement_options = options.merge(@statement_options)
       -        reporting_group = statement_options[:group] != @reporting_group.group ? ReportingGroup.new(statement_options[:group]) : @reporting_group
       -        reporting_operation = statement_options[:operation] != @reporting_operation.operation ? ReportingOperation.new(statement_options[:operation]) : @reporting_operation
       -        
       -        conditions = ["model_name = ? AND report_name = ? AND report_range = ?", klass.to_s, name.to_s, reporting_group.group.to_s]
       -        newest_report = ReportCache.find(:first, :select => "start, value", :conditions => conditions, :order => "start DESC")
       -        newest_value = reporting_group.latest_datetime
       -        if newest_report.nil? or newest_report.start < newest_value
       -          value_statement = nil
       -          case reporting_operation.operation
       -          when :sum
       -            value_statement = "SUM(#{@value_column})"
       -          when :count
       -            value_statement = "COUNT(1)"
       -          end
       -          raise if value_statement.nil?
       -          
       -          where = ["#{reporting_group.group_sql(statement_options[:date_column])} <= \"#{newest_value.to_formatted_s(:db)}\""]
       -          where << "#{reporting_group.group_sql(statement_options[:date_column])} > \"#{(newest_report.start).to_formatted_s(:db)}\"" unless newest_report.nil?
       -          where = where.join(" AND ")
       -          
       -          query = "INSERT INTO #{ReportCache.table_name}  (model_name, report_name, report_range, start, value) 
       -            (
       -              SELECT \"#{klass.to_s}\", \"#{name}\", \"#{reporting_group.group.to_s}\", 
       -                #{reporting_group.group_sql(statement_options[:date_column])} AS start, 
       -                #{value_statement} AS value 
       -              FROM #{klass.table_name}
       -              WHERE #{where}
       -              GROUP BY start
       -            );"
       -          ActiveRecord::Base.connection.execute query
       -        end
       -        data = ReportCache.find(:all, :select => "start, value", :conditions => conditions, :order => "start DESC", :limit => statement_options[:limit])
       -        data.collect! {|report| [report.start, report.value] }
       -        data.reverse
       +      when :day, :week, :month
       +        return 1.send(@group).ago.to_date.to_datetime
       +      when :hour
       +        return 1.day.ago.to_date.to_datetime
              end
       -      
       -      # def generate_report(klass, options)
       -      #   
       -      #   
       -      #   case reporting_operation.operation
       -      #   when :sum
       -      #     return klass.sum @value_column, :group => @reporting_group.group_sql(@statement_options[:date_column])
       -      #   when :count
       -      #     return klass.count :group => @reporting_group.group_sql(@statement_options[:date_column])
       -      #   end
       -      # end
            end
       +
       +    def self.default
       +      :day
       +    end
       +  end
       +
       +  class ReportingOperation
       +    @@operations = [:count, :sum]
       +
       +    attr_reader :operation
       +
       +    def initialize(op)
       +      raise ReportsAsSparkline::InvalidOperationExpception unless @@operations.include?(op.to_sym)
       +      @operation = op.to_sym
       +    end
       +
       +    def self.default
       +      :count
       +    end
       +  end
       +
       +
       +  class Report
       +
       +    @@default_statement_options = {:limit => 100, :operation => ReportingOperation.default, :group => ReportingGroup.default, :date_column => 'created_at'}
       +    attr_reader :name, :operation, :date_column, :value_column, :graph_options, :statement_options, :reporting_group
       +
       +    def initialize(name, options)
       +      @name  = name.to_sym
       +      @value_column = (options[:value_column] || @name).to_sym
       +      @statement_options = @@default_statement_options.merge options
          
       +      @reporting_group = ReportingGroup.new(@statement_options[:group])
       +      @reporting_operation = ReportingOperation.new(@statement_options[:operation])
       +    end
       +
       +    def report(klass, options)
       +      statement_options = options.merge(@statement_options)
       +      reporting_group = statement_options[:group] != @reporting_group.group ? ReportingGroup.new(statement_options[:group]) : @reporting_group
       +      reporting_operation = statement_options[:operation] != @reporting_operation.operation ? ReportingOperation.new(statement_options[:operation]) : @reporting_operation
          
       -    class CumulateReport < Kvlr::ReportsAsSparkline::Report
       -  
       -      def report(klass, options)
       -        CumulateReport.cumulate!(super(klass, options))
       -      end
       -  
       -      protected
       -      def self.cumulate!(data)
       -        last_item = 0
       -        data.collect{ |element|
       -          last_item += element[1].to_i
       -          [element[0], last_item]
       -        }
       -      end
       +      conditions = ["model_name = ? AND report_name = ? AND report_range = ?", klass.to_s, name.to_s, reporting_group.group.to_s]
       +      newest_report = ReportCache.find(:first, :select => "start, value", :conditions => conditions, :order => "start DESC")
       +      newest_value = reporting_group.latest_datetime
       +      if newest_report.nil? or newest_report.start < newest_value
       +        value_statement = nil
       +        case reporting_operation.operation
       +        when :sum
       +          value_statement = "SUM(#{@value_column})"
       +        when :count
       +          value_statement = "COUNT(1)"
       +        end
       +        raise if value_statement.nil?
            
       +        where = ["#{reporting_group.group_sql(statement_options[:date_column])} <= \"#{newest_value.to_formatted_s(:db)}\""]
       +        where << "#{reporting_group.group_sql(statement_options[:date_column])} > \"#{(newest_report.start).to_formatted_s(:db)}\"" unless newest_report.nil?
       +        where = where.join(" AND ")
       +    
       +        query = "INSERT INTO #{ReportCache.table_name}  (model_name, report_name, report_range, start, value) 
       +          (
       +            SELECT \"#{klass.to_s}\", \"#{name}\", \"#{reporting_group.group.to_s}\", 
       +              #{reporting_group.group_sql(statement_options[:date_column])} AS start, 
       +              #{value_statement} AS value 
       +            FROM #{klass.table_name}
       +            WHERE #{where}
       +            GROUP BY start
       +          );"
       +        ActiveRecord::Base.connection.execute query
       +      end
       +      data = ReportCache.find(:all, :select => "start, value", :conditions => conditions, :order => "start DESC", :limit => statement_options[:limit])
       +      data.collect! {|report| [report.start, report.value] }
       +      data.reverse
            end
       -  
       +
       +    # def generate_report(klass, options)
       +    #   
       +    #   
       +    #   case reporting_operation.operation
       +    #   when :sum
       +    #     return klass.sum @value_column, :group => @reporting_group.group_sql(@statement_options[:date_column])
       +    #   when :count
       +    #     return klass.count :group => @reporting_group.group_sql(@statement_options[:date_column])
       +    #   end
       +    # end
          end
       -    
       +
       +
       +  class CumulateReport < ReportsAsSparkline::Report
       +
       +    def report(klass, options)
       +      CumulateReport.cumulate!(super(klass, options))
       +    end
       +
       +    protected
       +    def self.cumulate!(data)
       +      last_item = 0
       +      data.collect{ |element|
       +        last_item += element[1].to_i
       +        [element[0], last_item]
       +      }
       +    end
       +
       +  end
       +
          module ClassMethods
            #
            # Examples:
       @@ -167,7 +168,7 @@ module ReportsAsSparkline   #:nodoc:
            #   report_as_sparkline :rake, :operation => :sum
            # end
            def report_as_sparkline(name, options = {})
       -      report = options[:cumulate] ? Kvlr::ReportsAsSparkline::CumulateReport.new(options[:cumulate], options) : Kvlr::ReportsAsSparkline::Report.new(name, options)
       +      report = options[:cumulate] ? ReportsAsSparkline::CumulateReport.new(options[:cumulate], options) : ReportsAsSparkline::Report.new(name, options)
              (class << self; self; end).instance_eval { 
                define_method "#{name.to_s}_report".to_sym do |*args|
                  raise ArgumentError if args.size > 1
 (DIR) diff --git a/lib/reports_as_sparkline/report_cache.rb b/lib/reports_as_sparkline/report_cache.rb
 (DIR) diff --git a/spec/boot.rb b/spec/boot.rb
       @@ -0,0 +1,23 @@
       +plugin_root = File.join(File.dirname(__FILE__), '..')
       +version = ENV['RAILS_VERSION']
       +version = nil if version and version == ""
       +
       +# first look for a symlink to a copy of the framework
       +if !version and framework_root = ["#{plugin_root}/rails", "#{plugin_root}/../../rails"].find { |p| File.directory? p }
       +  puts "found framework root: #{framework_root}"
       +  # this allows for a plugin to be tested outside of an app and without Rails gems
       +  $:.unshift "#{framework_root}/activesupport/lib", "#{framework_root}/activerecord/lib", "#{framework_root}/actionpack/lib"
       +else
       +  # simply use installed gems if available
       +  puts "using Rails#{version ? ' ' + version : nil} gems"
       +  require 'rubygems'
       +  
       +  if version
       +    gem 'rails', version
       +  else
       +    gem 'actionpack'
       +    gem 'activerecord'
       +  end
       +  require 'active_record'
       +  require 'action_pack'
       +end
 (DIR) diff --git a/spec/db/database.yml b/spec/db/database.yml
       @@ -5,7 +5,7 @@ sqlite3:
        
        mysql:
          adapter: mysql
       -  username: rails
       -  password: mislav
       +  username: root
       +  password: 
          encoding: utf8
          database: reports_as_sparkline_test
 (DIR) diff --git a/spec/db/schema.rb b/spec/db/schema.rb
       @@ -3,4 +3,15 @@ ActiveRecord::Schema.define(:version => 1) do
            t.string :login, :string
            t.timestamps
          end
       +  
       +  create_table :report_caches, :force => true do |t|
       +    t.string :model_name
       +    t.string :report_name
       +    t.string :report_range
       +    t.float :value
       +    t.datetime :start
       +      
       +    t.timestamps
       +  end
       +  add_index :report_caches, [:model_name, :report_name, :report_range, :start], :unique => true, :name => "report_caches_uk"
        end
 (DIR) diff --git a/spec/reports_as_sparkline_spec.rb b/spec/reports_as_sparkline_spec.rb
       @@ -69,7 +69,7 @@ end
        describe "Model#name_report should default to count operation on created at" do
          
          it "should call models count function" do
       -    User.registrations_report.class.should == ActiveSupport::OrderedHash
       +    User.registrations_report.class.should == Array
          end
          
        end
       @@ -77,7 +77,7 @@ end
        describe "Model#name_report should default to count operation on created at" do
          
          it "should call models count function" do
       -    User.registrations_report.class.should == ActiveSupport::OrderedHash
       +    User.registrations_report.class.should == Array
          end
          
        end
 (DIR) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
       @@ -6,6 +6,48 @@ rescue LoadError
          gem 'rspec'
          require 'spec'
        end
       -
       +require File.dirname(__FILE__) + '/boot' unless defined?(ActiveRecord)
        $:.unshift(File.dirname(__FILE__) + '/../lib')
       -require 'reports_as_sparkline'
       -\ No newline at end of file
       +
       +plugin_spec_dir = File.dirname(__FILE__)
       +ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
       +
       +databases = YAML::load(IO.read(plugin_spec_dir + "/db/database.yml"))
       +ActiveRecord::Base.establish_connection(databases[ENV["DB"] || "mysql"])
       +load(File.join(plugin_spec_dir, "db", "schema.rb"))
       +
       +
       +require 'reports_as_sparkline'
       +
       +Spec::Runner.configure do |config|
       +  # If you're not using ActiveRecord you should remove these
       +  # lines, delete config/database.yml and disable :active_record
       +  # in your config/boot.rb
       +  #config.use_transactional_fixtures = true
       +  #config.use_instantiated_fixtures  = false
       +  #config.fixture_path = File.dirname(__FILE__) + '/spec/fixtures/'
       +
       +  # == Fixtures
       +  #
       +  # You can declare fixtures for each example_group like this:
       +  #   describe "...." do
       +  #     fixtures :table_a, :table_b
       +  #
       +  # Alternatively, if you prefer to declare them only once, you can
       +  # do so right here. Just uncomment the next line and replace the fixture
       +  # names with your fixtures.
       +  #
       +  # config.global_fixtures = :table_a, :table_b
       +  #
       +  # If you declare global fixtures, be aware that they will be declared
       +  # for all of your examples, even those that don't use them.
       +  #
       +  # == Mock Framework
       +  #
       +  # RSpec uses it's own mocking framework by default. If you prefer to
       +  # use mocha, flexmock or RR, uncomment the appropriate line:
       +  #
       +  # config.mock_with :mocha
       +  # config.mock_with :flexmock
       +  # config.mock_with :rr
       +end
       +\ No newline at end of file