rangetastic 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-License +22 -0
- data/Manifest +11 -0
- data/README.markdown +40 -0
- data/Rakefile +14 -0
- data/lib/rangetastic.rb +62 -0
- data/rangetastic.gemspec +30 -0
- data/spec/fixtures/models.rb +7 -0
- data/spec/fixtures/structure.sql +20 -0
- data/spec/rangetastic_spec.rb +42 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/test_helper.rb +42 -0
- metadata +71 -0
data/MIT-License
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2009 Chris Herring
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
|
4
|
+
obtaining a copy of this software and associated documentation
|
|
5
|
+
files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use,
|
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the
|
|
9
|
+
Software is furnished to do so, subject to the following
|
|
10
|
+
conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be
|
|
13
|
+
included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
data/README.markdown
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Introduction
|
|
2
|
+
============
|
|
3
|
+
Rangetastic allows you to filter results of a named_scope call on any dates using any of a list of whitelisted fields you specify.
|
|
4
|
+
|
|
5
|
+
Configuration & Usage
|
|
6
|
+
=====================
|
|
7
|
+
|
|
8
|
+
To acheive this you need to install rangetastic
|
|
9
|
+
|
|
10
|
+
sudo gem install cherring-rangetastic
|
|
11
|
+
|
|
12
|
+
Then inside your environment.rb
|
|
13
|
+
|
|
14
|
+
config.gem "cherring-rangetastic", :lib => "rangetastic", :source => "http://gems.github.com"
|
|
15
|
+
|
|
16
|
+
Then in your model pass in the fields you wish to allow to be searchable using the between filter
|
|
17
|
+
|
|
18
|
+
class Order < ActiveRecord::Base
|
|
19
|
+
acts_as_rangetastic :fields => ["ordered_on", "fulfilled_on"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
You can then chain the between scope with any named_scope call you make:
|
|
23
|
+
|
|
24
|
+
Order.fulfilled.between(1.week.ago, 10.minutes.ago, "fulfilled_on")
|
|
25
|
+
|
|
26
|
+
But if you (or someone nasty!) try to use a field that is not whitelisted, it will raise ActiveRecord::StatementInvalid
|
|
27
|
+
|
|
28
|
+
Now you can also access this with the following syntax for any field ending with _on that is on the Model you are calling from like so.
|
|
29
|
+
|
|
30
|
+
Order.fulfilled.ordered_between(1.week.ago, 10.minutes.ago)
|
|
31
|
+
|
|
32
|
+
In this new version of rangetastic you can also query on _at fields. If you have an _at field such as created_at you can now
|
|
33
|
+
|
|
34
|
+
Order.fulfilled.created_between(1.week.ago, 10.minutes.ago)
|
|
35
|
+
|
|
36
|
+
However if you have an _on field and _at field the on field will take precedence over the at. If you want to access the _at field over _on field you will need to use the .between and whitelisted fields method specified first.
|
|
37
|
+
|
|
38
|
+
But if your field isn't on the Model or isn't an _on or an _at field then it will raise the standard NoMethodError.
|
|
39
|
+
|
|
40
|
+
Thanks to [spraints](http://github.com/spraints) for some inspiration.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'echoe'
|
|
4
|
+
|
|
5
|
+
Echoe.new('rangetastic', '0.3.2') do |p|
|
|
6
|
+
p.description = "Chain a date range to any named_scope on any date field with specified white listed fields"
|
|
7
|
+
p.url = "http://github.com/cherring/rangetastic"
|
|
8
|
+
p.author = "Chris Herring"
|
|
9
|
+
p.email = "chris.herring.iphone@gmail.com"
|
|
10
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
|
11
|
+
p.development_dependencies = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/lib/rangetastic.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Rangetastic
|
|
2
|
+
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def acts_as_rangetastic(options = {:fields => []})
|
|
9
|
+
@fields = options[:fields]
|
|
10
|
+
named_scope :between, lambda{ |start_date, end_date, fieldname|
|
|
11
|
+
field = @fields.include?(fieldname) ? fieldname : raise(ActiveRecord::StatementInvalid)
|
|
12
|
+
{ :conditions => ["#{field} >= ? AND #{field} <= ?", start_date, end_date] }
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def method_missing(symbol, *args, &block)
|
|
18
|
+
if (field(symbol) || @fields.include?(field_to_query))
|
|
19
|
+
make_scope(symbol, field_to_query, *args)
|
|
20
|
+
else
|
|
21
|
+
super(symbol, *args)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def field(symbol)
|
|
26
|
+
if columns_hash.has_key? on_field(symbol)
|
|
27
|
+
@field = on_field(symbol)
|
|
28
|
+
elsif columns_hash.has_key? at_field(symbol)
|
|
29
|
+
@field = at_field(symbol)
|
|
30
|
+
else
|
|
31
|
+
@field = nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def at_field(symbol)
|
|
36
|
+
"#{symbol.to_s.gsub("_between","")}_at"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def on_field(symbol)
|
|
40
|
+
"#{symbol.to_s.gsub("_between","")}_on"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def field_to_query
|
|
44
|
+
@field
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def make_scope(scope, field, *args)
|
|
48
|
+
named_scope scope, lambda{ |start_date, end_date|
|
|
49
|
+
{ :conditions => ["#{field} BETWEEN ? AND ?", start_date, end_date] }
|
|
50
|
+
}
|
|
51
|
+
call_scope(scope, *args)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def call_scope(scope, *args)
|
|
55
|
+
self.send(scope, args[0], args[1])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
ActiveRecord::Base.class_eval do
|
|
61
|
+
include Rangetastic
|
|
62
|
+
end
|
data/rangetastic.gemspec
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{rangetastic}
|
|
5
|
+
s.version = "0.3.2"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Chris Herring"]
|
|
9
|
+
s.date = %q{2009-09-20}
|
|
10
|
+
s.description = %q{Chain a date range to any named_scope on any date field with specified white listed fields}
|
|
11
|
+
s.email = %q{chris.herring.iphone@gmail.com}
|
|
12
|
+
s.extra_rdoc_files = ["README.markdown", "lib/rangetastic.rb"]
|
|
13
|
+
s.files = ["MIT-License", "Manifest", "README.markdown", "Rakefile", "lib/rangetastic.rb", "rangetastic.gemspec", "spec/fixtures/models.rb", "spec/fixtures/structure.sql", "spec/rangetastic_spec.rb", "spec/spec_helper.rb", "spec/test_helper.rb"]
|
|
14
|
+
s.homepage = %q{http://github.com/cherring/rangetastic}
|
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rangetastic", "--main", "README.markdown"]
|
|
16
|
+
s.require_paths = ["lib"]
|
|
17
|
+
s.rubyforge_project = %q{rangetastic}
|
|
18
|
+
s.rubygems_version = %q{1.3.4}
|
|
19
|
+
s.summary = %q{Chain a date range to any named_scope on any date field with specified white listed fields}
|
|
20
|
+
|
|
21
|
+
if s.respond_to? :specification_version then
|
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
23
|
+
s.specification_version = 3
|
|
24
|
+
|
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
26
|
+
else
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
DROP TABLE IF EXISTS orders;
|
|
2
|
+
|
|
3
|
+
DROP SEQUENCE IF EXISTS orders_id_seq;
|
|
4
|
+
|
|
5
|
+
CREATE SEQUENCE orders_id_seq
|
|
6
|
+
START WITH 1
|
|
7
|
+
INCREMENT BY 1
|
|
8
|
+
NO MAXVALUE
|
|
9
|
+
NO MINVALUE
|
|
10
|
+
CACHE 1;
|
|
11
|
+
|
|
12
|
+
CREATE TABLE orders (
|
|
13
|
+
id integer NOT NULL default nextval('orders_id_seq'),
|
|
14
|
+
ordered_on timestamp,
|
|
15
|
+
fulfilled_on timestamp,
|
|
16
|
+
shipped_at timestamp,
|
|
17
|
+
created_at timestamp without time zone,
|
|
18
|
+
updated_at timestamp without time zone
|
|
19
|
+
);
|
|
20
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'spec/spec_helper'
|
|
2
|
+
require 'rangetastic'
|
|
3
|
+
include Rangetastic
|
|
4
|
+
|
|
5
|
+
describe Order do
|
|
6
|
+
|
|
7
|
+
it "should have 25 orders" do
|
|
8
|
+
Order.count.should == 25
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should respond to between" do
|
|
12
|
+
Order.respond_to?(:between).should == true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should have 5 orders fulfilled that were ordered no more than 10 days ago" do
|
|
16
|
+
Order.fulfilled.between(10.days.ago, 1.day.ago,"ordered_on").size.should == 5
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should raise an error if the field is not in fields => []" do
|
|
20
|
+
lambda{ Order.fulfilled.between(1.week.ago, 1.day.ago, "not_a_field") }.should raise_error(ActiveRecord::StatementInvalid)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should be able to filter on any field that is in fields => []" do
|
|
24
|
+
%w(ordered_on fulfilled_on shipped_at).each do |field|
|
|
25
|
+
lambda{ Order.fulfilled.between(1.week.ago, 1.day.ago, field) }.should_not raise_error(ActiveRecord::StatementInvalid)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should have 5 orders fulfilled that were ordered no more than 10 days ago - 3" do
|
|
30
|
+
Order.fulfilled.ordered_between(10.days.ago, 1.day.ago).size.should == 5
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
%w(ordered shipped fulfilled created updated).each do |field|
|
|
34
|
+
it "should be able to access #{field}_between" do
|
|
35
|
+
lambda{ Order.send("#{field}_between", 1.day.ago, Date.today) }.should_not raise_error(NoMethodError)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should raise no method error when a field doesn't exist" do
|
|
40
|
+
lambda{ Order.eaten_between(1.day.ago, Date.today) }.should raise_error(NoMethodError)
|
|
41
|
+
end
|
|
42
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Inspiration gained from Thinking Sphinx's test suite via Ryan Bigg's by_star test suite.
|
|
2
|
+
|
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'activerecord'
|
|
7
|
+
require 'rangetastic'
|
|
8
|
+
require 'spec/fixtures/models'
|
|
9
|
+
require 'spec/test_helper'
|
|
10
|
+
|
|
11
|
+
FileUtils.mkdir_p "#{Dir.pwd}/tmp"
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Base.logger = Logger.new(StringIO.new)
|
|
14
|
+
|
|
15
|
+
Spec::Runner.configure do |config|
|
|
16
|
+
test = TestHelper.new
|
|
17
|
+
test.setup_postgresql
|
|
18
|
+
end
|
data/spec/test_helper.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class TestHelper
|
|
2
|
+
attr_accessor :host, :username, :password
|
|
3
|
+
attr_reader :path
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@host = "localhost"
|
|
7
|
+
@username = "chris" #Insert username for db here
|
|
8
|
+
@password = ""
|
|
9
|
+
|
|
10
|
+
@path = File.expand_path(File.dirname(__FILE__))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def setup_postgresql
|
|
14
|
+
ActiveRecord::Base.establish_connection(
|
|
15
|
+
:adapter => 'postgresql',
|
|
16
|
+
:database => 'rangetastic',
|
|
17
|
+
:username => @username,
|
|
18
|
+
:password => @password,
|
|
19
|
+
:host => @host
|
|
20
|
+
)
|
|
21
|
+
ActiveRecord::Base.logger = Logger.new(File.open("tmp/activerecord.log", "a"))
|
|
22
|
+
|
|
23
|
+
structure = File.open("spec/fixtures/structure.sql") { |f| f.read.chomp }
|
|
24
|
+
structure.split(';').each { |table|
|
|
25
|
+
ActiveRecord::Base.connection.execute table
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
10.times do
|
|
29
|
+
Order.create(:ordered_on => 2.weeks.ago, :fulfilled_on => 2.days.ago)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
10.times do
|
|
33
|
+
Order.create(:ordered_on => 3.weeks.ago, :fulfilled_on => 2.days.ago)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
5.times do
|
|
37
|
+
Order.create(:ordered_on => 1.weeks.ago, :fulfilled_on => 2.days.ago)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rangetastic
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Chris Herring
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-09-20 00:00:00 +10:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: Chain a date range to any named_scope on any date field with specified white listed fields
|
|
17
|
+
email: chris.herring.iphone@gmail.com
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- README.markdown
|
|
24
|
+
- lib/rangetastic.rb
|
|
25
|
+
files:
|
|
26
|
+
- MIT-License
|
|
27
|
+
- Manifest
|
|
28
|
+
- README.markdown
|
|
29
|
+
- Rakefile
|
|
30
|
+
- lib/rangetastic.rb
|
|
31
|
+
- rangetastic.gemspec
|
|
32
|
+
- spec/fixtures/models.rb
|
|
33
|
+
- spec/fixtures/structure.sql
|
|
34
|
+
- spec/rangetastic_spec.rb
|
|
35
|
+
- spec/spec_helper.rb
|
|
36
|
+
- spec/test_helper.rb
|
|
37
|
+
has_rdoc: true
|
|
38
|
+
homepage: http://github.com/cherring/rangetastic
|
|
39
|
+
licenses: []
|
|
40
|
+
|
|
41
|
+
post_install_message:
|
|
42
|
+
rdoc_options:
|
|
43
|
+
- --line-numbers
|
|
44
|
+
- --inline-source
|
|
45
|
+
- --title
|
|
46
|
+
- Rangetastic
|
|
47
|
+
- --main
|
|
48
|
+
- README.markdown
|
|
49
|
+
require_paths:
|
|
50
|
+
- lib
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: "0"
|
|
56
|
+
version:
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: "1.2"
|
|
62
|
+
version:
|
|
63
|
+
requirements: []
|
|
64
|
+
|
|
65
|
+
rubyforge_project: rangetastic
|
|
66
|
+
rubygems_version: 1.3.4
|
|
67
|
+
signing_key:
|
|
68
|
+
specification_version: 3
|
|
69
|
+
summary: Chain a date range to any named_scope on any date field with specified white listed fields
|
|
70
|
+
test_files: []
|
|
71
|
+
|