Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit (extraction from xtt)

  • Loading branch information...
commit 60aa6fcf2d1807875dac7cd08c012cc663efa59a 0 parents
@technoweenie authored
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Rick Olson
+
+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.
43 README
@@ -0,0 +1,43 @@
+CanSearch
+=========
+
+Allows you create common named_scopes and chain them together with #search and
+#search_for.
+
+ class Topic
+ belongs_to :forum
+
+ can_search do
+ scoped_by :forums
+ scoped_by :created, :scope => :date_range
+ end
+
+ # creates these two named scopes
+ # named_scope :by_forums, lambda { |f| {:conditions => {:forum_id => f}} }
+ # named_scope :created, lambda { |range| {:conditions => ...} }
+ end
+
+ Topic.search(:forum => 1) # Topic.by_forums(1)
+ Topic.search(:forums => [1,2]) # Topic.by_forums([1,2])
+ Topic.search(:created => (time1..time2)) # Topic.created(time1..time2)
+ Topic.search(:created => \
+ {:period => :daily, :start => Time.now}) # Topic.created(Time.now, Time.now + 1.day)
+
+You can automatically paginate:
+
+ Topic.search :forum => 1, :page => params[:page]
+
+You can also access the named_scope directly for custom #find or #calculate calls.
+
+ Topic.search_for(:forum => 1).sum(:hits)
+
+Oh, and you can combine scopes:
+
+ Topic.search :forum => 1, :forums => [2, 3], :created => (time1..time2)
+
+ def can_search(&block)
+ self.search_scopes = CanSearch::SearchScopes.new(self, &block)
+ end
+end
+
+Copyright (c) 2008-* Rick Olson, released under the MIT license
53 Rakefile
@@ -0,0 +1,53 @@
+require 'rake'
+require "rake/rdoctask"
+require 'rake/gempackagetask'
+require File.join(File.dirname(__FILE__), 'spec', 'spec_helper')
+require 'spec/rake/spectask'
+require 'spec/rake/verify_rcov'
+
+rdoc_files = FileList["{bin,lib,example_configs}/**/*"].to_a
+extra_rdoc_files = %w(README COPYRIGHT RELEASES CHANGELOG)
+
+Rake::RDocTask.new do |rd|
+ rd.main = "README"
+ rd.rdoc_files.include(rdoc_files, extra_rdoc_files)
+ rd.rdoc_dir = "doc/rdoc/"
+end
+
+desc "Run all examples with RCov"
+Spec::Rake::SpecTask.new(:rcov) do |t|
+ t.spec_files = FileList['spec/**/*.rb']
+ t.rcov = true
+ t.rcov_opts = ['--exclude', 'spec']
+ t.rcov_dir = "doc/rcov"
+end
+
+desc "Run all specs"
+Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_files = FileList['spec/**/*.rb']
+ t.rcov = false
+end
+
+desc "Generate RSpec Report"
+task :rspec_report => [:clobber_rspec_report] do
+ files = FileList["spec/**/*.rb"].to_s
+ %x(spec #{files} --format html:doc/rspec_report.html)
+end
+
+task :clobber_rspec_report do
+ %x(rm -rf doc/rspec_report.html)
+end
+
+desc "Generate all documentation"
+task :generate_documentation => [:clobber_documentation, :rdoc, :rcov, :rspec_report]
+
+desc "Remove all documentation"
+task :clobber_documentation => [:clobber_rdoc, :clobber_rcov, :clobber_rspec_report]
+
+desc "Build Release"
+task :build_release => [:pre_commit, :generate_documentation, :repackage] do
+ %x(mv pkg gem)
+end
+
+desc "Run this before commiting"
+task :pre_commit => [:verify_rcov]
39 init.rb
@@ -0,0 +1,39 @@
+class << ActiveRecord::Base
+ # Allows you create common named_scopes and chain them together with #search and
+ # #search_for.
+ #
+ # class Topic
+ # belongs_to :forum
+ #
+ # can_search do
+ # scoped_by :forums
+ # scoped_by :created, :scope => :date_range
+ # end
+ #
+ # # creates these two named scopes
+ # # named_scope :by_forums, lambda { |f| {:conditions => {:forum_id => f}} }
+ # # named_scope :created, lambda { |range| {:conditions => ...} }
+ # end
+ #
+ # Topic.search(:forum => 1) # Topic.by_forums(1)
+ # Topic.search(:forums => [1,2]) # Topic.by_forums([1,2])
+ # Topic.search(:created => (time1..time2)) # Topic.created(time1..time2)
+ # Topic.search(:created => \
+ # {:period => :daily, :start => Time.now}) # Topic.created(Time.now, Time.now + 1.day)
+ #
+ # You can automatically paginate:
+ #
+ # Topic.search :forum => 1, :page => params[:page]
+ #
+ # You can also access the named_scope directly for custom #find or #calculate calls.
+ #
+ # Topic.search_for(:forum => 1).sum(:hits)
+ #
+ # Oh, and you can combine scopes:
+ #
+ # Topic.search :forum => 1, :forums => [2, 3], :created => (time1..time2)
+ #
+ def can_search(&block)
+ self.search_scopes = CanSearch::SearchScopes.new(self, &block)
+ end
+end
19 lib/can_search.rb
@@ -0,0 +1,19 @@
+module CanSearch
+ def self.extended(base)
+ class << base
+ attr_accessor :search_scopes
+ end
+ end
+
+ # Calls either #paginate or #all on the returned scoped from #search_for.
+ def search(options = {})
+ options = options.dup
+ search_for(options).send(options.key?(:page) ? :paginate : :all, options)
+ end
+
+ # Strips search scope keys from options and builds a scoped finder object. This
+ # returns the model if no search scopes are in use.
+ def search_for(options = {})
+ search_scopes.search_for(options)
+ end
+end
93 lib/can_search/date_range_scope.rb
@@ -0,0 +1,93 @@
+module CanSearch
+ # Generates a named scope for searching by time ranges. You can either specify
+ # your own time range, or specify a single time and use one of the periods to determine
+ # the range.
+ #
+ # class Topic
+ # can_search do
+ # scoped_by :created, :scope => :date_range
+ # end
+ # end
+ #
+ # Topic.search(:created => (time1..time2)) # Topic.created(time1..time2)
+ # Topic.search(:created => \
+ # {:period => :daily, :start => Time.now}) # Topic.created(Time.now, Time.now + 1.day)
+ #
+ class DateRangeScope < BaseScope
+ # Default collection of all date range periods. A period is simply a proc
+ # that returns a time range calculated from the given time.
+ def self.periods() @periods ||= {} end
+ periods.update \
+ :daily => lambda { |now|
+ today = now.midnight
+ (today..today + 1.day - 1.second)
+ },
+ :weekly => lambda { |now|
+ mon = now.beginning_of_week
+ (mon..mon + 1.week - 1.second)
+ },
+ :'bi-weekly' => lambda { |now|
+ today = now.midnight
+ today.day >= 15 ? (today.change(:day => 15)..today.end_of_month) : (today.beginning_of_month..today.change(:day => 15) - 1.second)
+ },
+ :monthly => lambda { |now|
+ (now.beginning_of_month..now.end_of_month)
+ }
+
+ # The attribute adds a '_at' suffix to the scope name (:created => :created_at).
+ # The named_scope uses the scope name by default.
+ def initialize(model, name, options = {})
+ super
+ @attribute = options[:attribute] || begin
+ name_str = name.to_s
+ name_str =~ /_at$/ ? name : (name_str << "_at").to_sym
+ end
+ @named_scope = options[:named_scope] || @name
+ @model.named_scope @named_scope, lambda { |range|
+ if range.respond_to?(:[])
+ range = range[:period] && @model.date_range_for(range[:period], range[:start])
+ end
+ if range
+ {:conditions => "#{@model.table_name}.#{@attribute} #{range.to_s :db}"}
+ else
+ {}
+ end
+ }
+ end
+
+ def scope_for(finder, options = {})
+ if value = options.delete(@name)
+ finder.send(@named_scope, value)
+ else
+ finder
+ end
+ end
+ end
+
+ # Shortcut to CanSearch::DateRangeScope.periods
+ def date_periods() @date_periods ||= CanSearch::DateRangeScope.periods end
+
+ # Returns a range for the given time using the date period.
+ def date_range_for(period_name, time = nil)
+ if period = date_periods[period_name.to_sym]
+ period.call(parse_filtered_time(time))
+ else
+ raise "Invalid period: #{period_name.inspect}"
+ end
+ end
+
+protected
+ # Parses the given time. Strings are parsed with the current time zone, times are
+ # converted to the current time zone, and a nil value assumes you want Time.zone.now.
+ def parse_filtered_time(time = nil)
+ case time
+ when String then Time.zone.parse(time)
+ when nil then Time.zone.now
+ when Time, ActiveSupport::TimeWithZone then time.in_time_zone
+ else raise "Invalid time: #{time.inspect}"
+ end
+ end
+
+ # Add this scope type
+ SearchScopes.scope_types[:date_range] = DateRangeScope
+end
109 lib/can_search/search_scopes.rb
@@ -0,0 +1,109 @@
+module CanSearch
+ # Tracks the search scopes for a given model.
+ class SearchScopes
+ # Registered scope_types using their symbolized names as keys.
+ def self.scope_types() @scope_types ||= {} end
+
+ attr_reader :model, :scopes
+
+ def initialize(model, &block)
+ @scopes = {}
+ @model = model
+ @model.extend CanSearch
+ instance_eval(&block) if block
+ end
+
+ # Adds a new scope for the given model. It works by looking up the scope class
+ # in the scope_types hash and instantiating it with the given arguments.
+ def scoped_by(name, options = {})
+ options[:scope] ||= :reference
+ if scope_class = self.class.scope_types[options[:scope]]
+ @scopes[name] = scope_class.new(@model, name, options)
+ end
+ end
+
+ # Builds a combined scoped finder object, starting with the model itself.
+ def search_for(options = {})
+ @scopes.values.inject(@model) { |finder, scope| scope.scope_for(finder, options) }
+ end
+
+ def [](name)
+ @scopes[name]
+ end
+ end
+
+ # The base class for all scope classes. Scope classes know how to take the
+ # given arguments, generate a proper named_scope for the model, and perform
+ # searches on it.
+ class BaseScope
+ # This is the key the scope looks for to create the finder.
+ attr_reader :name
+
+ # This is the main attribute that is being used in the search.
+ attr_reader :attribute
+
+ # The name of the named_scope that is used.
+ attr_reader :named_scope
+
+ # a reference to the ActiveRecord model that this scope is attached to.
+ attr_reader :model
+
+ def initialize(model, name, options = {})
+ @model, @name = model, name
+ end
+
+ # strip out any scoped keys from options and return a chained finder.
+ def scope_for(finder, options = {})
+ finder
+ end
+
+ def ==(other)
+ self.class == other.class && other.name == @name && other.attribute == @attribute && other.named_scope == @named_scope
+ end
+ end
+
+ # Generates named_scope for belongs_to associations. ReferenceScopes actually look for both a singular
+ # and plural key. Singular keys should be the id value or the model instance.
+ #
+ # class Topic
+ # belongs_to :forum
+ #
+ # can_search do
+ # scoped_by :forums
+ # end
+ # end
+ #
+ # Topic.search(:forum => 1) # Topic.by_forums(1)
+ # Topic.search(:forums => [1,2]) # Topic.by_forums([1,2])
+ #
+ class ReferenceScope < BaseScope
+ attr_reader :singular_name
+
+ # By default, the singular_name is generated with the #singularize (:forums => :forum) inflection.
+ # The attribute is taken from the #foreign_key (:forum => :forum_id) inflection of the singular name.
+ # The named_scope adds a "by_" prefix to the scope name (:forums => :by_forums).
+ def initialize(model, name, options = {})
+ super
+ single = name.to_s.singularize
+ @singular_name = options[:singular] || single.to_sym
+ @attribute = options[:attribute] || single.foreign_key.to_sym
+ @named_scope = options[:named_scope] || "by_#{name}".to_sym
+ @model.named_scope @named_scope, lambda { |records| {:conditions => {@attribute => records}} }
+ end
+
+ def scope_for(finder, options = {})
+ value, values = options.delete(@singular_name), options.delete(@name) || []
+ values << value if value
+ return finder if values.empty?
+ finder.send(@named_scope, values.size == 1 ? values.first : values)
+ end
+
+ def ==(other)
+ super && other.singular_name == @singular_name
+ end
+ end
+
+ SearchScopes.scope_types[:reference] = ReferenceScope
+end
+
+send respond_to?(:require_dependency) ? :require_dependency : :require, 'can_search/date_range_scope'
146 spec/date_range_scope_spec.rb
@@ -0,0 +1,146 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+module CanSearch
+ DateRangeScope.periods[:spec] = lambda do |now|
+ (now..now + 300)
+ end
+
+ describe "all DateRange Scopes", :shared => true do
+ include CanSearchSpecHelper
+
+ it "instantiates date range scope" do
+ Record.search_scopes[@scope.name].should == @scope
+ end
+
+ it "creates named_scope" do
+ Record.scopes[@scope.named_scope].should_not be_nil
+ end
+
+ it "filters records by time range" do
+ compare_records Record.search(@scope.name => (@now-5.days..@now-7.minutes)), [:day, :week_1, :week_2]
+ end
+
+ it "filters today's records" do
+ compare_records Record.search(@scope.name => {:period => :daily}), [:default, :day]
+ end
+
+ it "filters daily records" do
+ compare_records Record.search(@scope.name => {:period => :daily, :start => @now - 3.days}), [:week_1]
+ end
+
+ it "filters this week's records" do
+ compare_records Record.search(@scope.name => {:period => :weekly}), [:default, :day, :week_1, :week_2]
+ end
+
+ it "filters this fortnight's records" do
+ compare_records Record.search(@scope.name => {:period => :'bi-weekly'}), [:default, :day, :week_1, :week_2, :biweek_1, :biweek_2]
+ end
+
+ it "filters earlier fortnight's records" do
+ compare_records Record.search(@scope.name => {:period => :'bi-weekly', :start => '2007-6-14 6:00:00'}), [:month_1, :month_2]
+ end
+
+ it "filters this month's records" do
+ compare_records Record.search(@scope.name => {:period => :monthly}), [:default, :day, :week_1, :week_2, :biweek_1, :biweek_2, :month_1, :month_2]
+ end
+
+ it "filters older month's records" do
+ compare_records Record.search(@scope.name => {:period => :monthly, :start => '2007-5-5'}), [:archive]
+ end
+ end
+
+ describe DateRangeScope do
+ describe "(DateRange Scope with no options)" do
+ before do
+ Record.can_search do
+ scoped_by :created, :scope => :date_range
+ end
+ @scope = DateRangeScope.new(Record, :created, :attribute => :created_at, :scope => :date_range, :named_scope => :created)
+ end
+
+ it_should_behave_like "all DateRange Scopes"
+ end
+
+ describe "(DateRange Scope with custom attribute)" do
+ before do
+ Record.can_search do
+ scoped_by :latest, :scope => :date_range, :attribute => :created_at
+ end
+ @scope = DateRangeScope.new(Record, :latest, :attribute => :created_at, :scope => :date_range, :named_scope => :latest )
+ end
+
+ it_should_behave_like "all DateRange Scopes"
+ end
+
+ describe "(DateRange Scope with custom attribute and finder)" do
+ before do
+ Record.can_search do
+ scoped_by :latest, :scope => :date_range, :attribute => :created_at, :named_scope => :woot
+ end
+ @scope = DateRangeScope.new(Record, :latest, :attribute => :created_at, :scope => :date_range, :named_scope => :woot)
+ end
+
+ it_should_behave_like "all DateRange Scopes"
+ end
+
+ describe "ActiveRecord::Base.date_range_for(period, time = nil) with ActiveSupport defaults" do
+ it "creates daily range" do
+ Record.date_range_for(:daily, Time.utc(2008, 1, 1, 12)).should == (Time.utc(2008, 1, 1)..Time.utc(2008, 1, 2)-1.second)
+ end
+
+ it "creates weekly range" do
+ Record.date_range_for(:weekly, Time.utc(2008, 1, 1)).should == (Time.utc(2007, 12, 31)..Time.utc(2008, 1, 7)-1.second)
+ end
+
+ it "creates bi-weekly range for first half of the month" do
+ Record.date_range_for(:'bi-weekly', Time.utc(2008, 1, 5)).should == (Time.utc(2008, 1, 1)..Time.utc(2008, 1, 15)-1.second)
+ end
+
+ it "creates bi-weekly range for second half of the month" do
+ Record.date_range_for(:'bi-weekly', Time.utc(2008, 1, 16)).should == (Time.utc(2008, 1, 15)..Time.utc(2008, 2, 1)-1.second)
+ end
+
+ it "creates monthly range" do
+ Record.date_range_for(:monthly, Time.utc(2008, 1, 5)).should == (Time.utc(2008, 1, 1)..Time.utc(2008, 2, 1)-1)
+ end
+
+ it "parses time and calls #with_date_range with valid filter" do
+ Record.date_range_for(:spec, '2008-1-1').should == (Time.utc(2008, 1, 1)..Time.utc(2008, 1, 1, 0, 5))
+ end
+
+ it "allows custom instance-level filter" do
+ Record.date_periods[:custom_spec] = lambda { |now| (now..now + 420) }
+ Record.date_range_for(:custom_spec, '2008-1-1').should == (Time.utc(2008, 1, 1)..Time.utc(2008, 1, 1, 0, 7))
+ Record.date_periods.delete(:custom_spec)
+ end
+
+ it "raises exception on bad filter" do
+ lambda { Record.date_range_for(:snozzberries, nil) }.should raise_error(RuntimeError)
+ end
+ end
+
+ describe "ActiveRecord::Base.parse_filtered_time(time_or_string)" do
+ before :all do
+ def Record.public_parse_filtered_time(*args)
+ parse_filtered_time(*args)
+ end
+ end
+
+ it "converts strings to times" do
+ Record.public_parse_filtered_time("2008-1-1").should == Time.utc(2008, 1, 1)
+ end
+
+ it "converts times to utc" do
+ time = Time.now
+ time.should_not be_utc
+ parsed = Record.public_parse_filtered_time(time)
+ parsed.should == time
+ parsed.should be_utc
+ end
+
+ it "raises error on bad filtered date value" do
+ lambda { Record.public_parse_filtered_time(:boom) }.should raise_error(RuntimeError)
+ end
+ end
+ end
+end
70 spec/search_scopes_spec.rb
@@ -0,0 +1,70 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+module CanSearch
+ describe "all Reference Scopes", :shared => true do
+ include CanSearchSpecHelper
+
+ it "instantiates reference scope" do
+ Record.search_scopes[@scope.name].should == @scope
+ end
+
+ it "creates named_scope" do
+ Record.scopes[@scope.named_scope].should_not be_nil
+ end
+
+ it "paginates records" do
+ compare_records Record.search(:page => nil, @scope.name => [2]), [:day, :week_2, :biweek_1]
+ end
+
+ it "filters records with plural value from named_scope" do
+ compare_records Record.search(@scope.name => [2]), [:day, :week_2, :biweek_1, :month_1]
+ end
+
+ it "filters records with singular value from named_scope" do
+ compare_records Record.search(@scope.singular_name => 2), [:day, :week_2, :biweek_1, :month_1]
+ end
+
+ it "filters records with plural record value from named_scope" do
+ compare_records Record.search(@scope.name => [records(:day)]), [:day, :week_2, :biweek_1, :month_1]
+ end
+
+ it "filters records with singular record value from named_scope" do
+ compare_records Record.search(@scope.singular_name => records(:day)), [:day, :week_2, :biweek_1, :month_1]
+ end
+ end
+
+ describe SearchScopes do
+ describe "(Reference Scope with no options)" do
+ before do
+ Record.can_search do
+ scoped_by :parents
+ end
+ @scope = ReferenceScope.new(Record, :parents, :attribute => :parent_id, :singular => :parent, :scope => :reference, :named_scope => :by_parents)
+ end
+
+ it_should_behave_like "all Reference Scopes"
+ end
+
+ describe "(Reference Scope with custom attribute)" do
+ before do
+ Record.can_search do
+ scoped_by :masters, :attribute => :parent_id
+ end
+ @scope = ReferenceScope.new(Record, :masters, :attribute => :parent_id, :singular => :master, :scope => :reference, :named_scope => :by_masters)
+ end
+
+ it_should_behave_like "all Reference Scopes"
+ end
+
+ describe "(Reference Scope with custom attribute and finder name)" do
+ before do
+ Record.can_search do
+ scoped_by :masters, :attribute => :parent_id, :named_scope => :great_scott
+ end
+ @scope = ReferenceScope.new(Record, :masters, :attribute => :parent_id, :singular => :master, :scope => :reference, :named_scope => :great_scott)
+ end
+
+ it_should_behave_like "all Reference Scopes"
+ end
+ end
+end
101 spec/spec_helper.rb
@@ -0,0 +1,101 @@
+require 'rubygems'
+
+dir = File.dirname(__FILE__)
+rails_app_spec = "#{dir}/../../../../config/environment.rb"
+vendor_rspec = "#{dir}/../../rspec/lib"
+
+if File.exist?(vendor_rspec)
+ $:.unshift vendor_rspec
+else
+ gem 'rspec'
+end
+
+if File.exist?(rails_app_spec)
+ require rails_app_spec
+ Time.zone = "UTC"
+else
+ raise "TODO: attempt to load activerecord and activesupport from gems"
+ # also, establish connection with sqlite3 or use DB env var as path to database.yml
+end
+
+$:.unshift "#{dir}/../lib"
+
+require 'ruby-debug'
+require 'spec'
+require 'can_search'
+require 'can_search/search_scopes'
+
+module CanSearch
+ class Record < ActiveRecord::Base
+ set_table_name 'can_search_records'
+
+ def self.per_page() 3 end
+
+ def self.create_table
+ connection.create_table table_name, :force => true do |t|
+ t.string :name
+ t.integer :parent_id
+ t.datetime :created_at
+ end
+ connection.add_index :can_search_records, :name
+ end
+
+ def self.drop_table
+ connection.drop_table table_name
+ end
+
+ def self.seed_data(now = Time.now.utc)
+ transaction do
+ create :name => 'default', :parent_id => 1, :created_at => now - 5.minutes
+ create :name => 'day', :parent_id => 2, :created_at => now - 8.minutes
+ create :name => 'week_1', :parent_id => 1, :created_at => now - 3.days
+ create :name => 'week_2', :parent_id => 2, :created_at => now - (4.days + 20.hours)
+ create :name => 'biweek_1', :parent_id => 2, :created_at => now - 8.days
+ create :name => 'biweek_2', :parent_id => 1, :created_at => now - (14.days + 20.hours)
+ create :name => 'month_1', :parent_id => 2, :created_at => now - 20.days
+ create :name => 'month_2', :parent_id => 1, :created_at => now - (28.days + 20.hours)
+ create :name => 'archive', :parent_id => 1, :created_at => now - 35.days
+ end
+ end
+ end
+
+ module CanSearchSpecHelper
+ def self.included(base)
+ base.before :all do
+ @now = Time.utc 2007, 6, 30, 6
+ Record.create_table
+ Record.seed_data @now
+ @expected_index = Record.find(:all).inject({}) { |h, r| h.update r.name.to_sym => r }
+ end
+
+ base.before do
+ Time.stub!(:now).and_return(@now)
+ end
+
+ base.after :all do
+ Record.connection.drop_table :can_search_records
+ end
+ end
+
+ def records(key)
+ @expected_index[key]
+ end
+
+ def compare_records(actual, expected)
+ actual = actual.sort { |x, y| y.created_at <=> x.created_at }
+ expected.each do |e|
+ a_index = actual.index(records(e))
+ e_index = expected.index(e)
+ if a_index.nil?
+ fail "Record record(#{e.inspect}) was not in the array, but should have been."
+ else
+ fail "Record record(#{e.inspect}) is in wrong position: #{a_index.inspect} instead of #{e_index.inspect}" unless a_index == e_index
+ end
+ end
+
+ actual.size.should == expected.size
+ end
+ end
+end
+
+Debugger.start
4 tasks/can_filter_by_dates_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :can_filter_by_dates do
+# # Task goes here
+# end
Please sign in to comment.
Something went wrong with that request. Please try again.