dstrelau-minty_scopes 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mkdn +60 -0
- data/Rakefile +39 -0
- data/lib/minty_scopes.rb +15 -0
- data/lib/minty_scopes/associations.rb +28 -0
- data/lib/minty_scopes/except.rb +17 -0
- data/lib/minty_scopes/order.rb +23 -0
- data/lib/minty_scopes/timestamps.rb +23 -0
- data/lib/minty_scopes/version.rb +3 -0
- data/test/test_helper.rb +19 -0
- data/test/units/associations_test.rb +39 -0
- data/test/units/except_test.rb +33 -0
- data/test/units/order_test.rb +49 -0
- data/test/units/timestamps_test.rb +32 -0
- metadata +88 -0
data/README.mkdn
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
What
|
2
|
+
====
|
3
|
+
|
4
|
+
A collection of handy `named_scope`s that you should be able to use in just about any model.
|
5
|
+
|
6
|
+
Why
|
7
|
+
===
|
8
|
+
|
9
|
+
Named scopes turn ugly finders into pretty ones.
|
10
|
+
|
11
|
+
Howto
|
12
|
+
=====
|
13
|
+
|
14
|
+
# environment.rb
|
15
|
+
config.gem 'dstrelau-minty_scopes', :source => "http://gems.github.com"
|
16
|
+
|
17
|
+
# any model
|
18
|
+
class Post < ActiveRecord::Base
|
19
|
+
extend MintyScopes
|
20
|
+
end
|
21
|
+
|
22
|
+
Scopes
|
23
|
+
======
|
24
|
+
|
25
|
+
Scopes are grouped into modules by functionality. If you only want some scopes, feel free to extend only the modules you want: `extend MintyScopes::Timestamps`
|
26
|
+
|
27
|
+
### Associations ###
|
28
|
+
|
29
|
+
with(:comments) #=> :joins => :comments, :group => 'posts.id' (only posts with comments)
|
30
|
+
without(:comments) #=> :joins => 'LEFT JOIN comments ON posts.id = comments.post_id',
|
31
|
+
# :conditions => {'comments.id' => nil}
|
32
|
+
including(:comments) #=> :include => [:comments]
|
33
|
+
|
34
|
+
### Except ###
|
35
|
+
|
36
|
+
except(post) #=> [ 'posts.id NOT IN (?)', post ]
|
37
|
+
except(post, post) #=> [ 'posts.id NOT IN (?)', [post, post] ]
|
38
|
+
except(post_collection) #=> [ 'posts.id NOT IN (?)', post_collection ]
|
39
|
+
|
40
|
+
### Order ###
|
41
|
+
|
42
|
+
newest #=> { :order => 'created_at DESC', :limit => per_page || limit }
|
43
|
+
newest(20) #=> { :order => 'created_at DESC', :limit => 20 }
|
44
|
+
oldest #=> { :order => 'created_at ASC', :limit => per_page || limit }
|
45
|
+
oldest(20) #=> { :order => 'created_at ASC', :limit => 20 }
|
46
|
+
|
47
|
+
### Timestamps ###
|
48
|
+
|
49
|
+
created_on(date) #=> :created_at => (date.beginning_of_day..date.end_of_day)
|
50
|
+
modified_on(date) #=> :modified_at => (date.beginning_of_day..date.end_of_day)
|
51
|
+
|
52
|
+
Thanks
|
53
|
+
======
|
54
|
+
|
55
|
+
Big thanks to Ryan Daigle for his [utility_scopes](http://github.com/yfactorial/utility_scope) plugin, the inspiration for this project.
|
56
|
+
|
57
|
+
License
|
58
|
+
=======
|
59
|
+
|
60
|
+
© 2008 Dean Strelau, Mint Digital. All Rights Reserved.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'lib/minty_scopes/version'
|
5
|
+
|
6
|
+
desc 'Default: Run Tests'
|
7
|
+
task :default => ['test']
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = "minty_scopes"
|
11
|
+
s.version = MintyScopes::VERSION
|
12
|
+
s.summary = "Useful, reusable named_scopes for ActiveRecord."
|
13
|
+
s.homepage = "https://github.com/dstrelau/minty_scopes"
|
14
|
+
|
15
|
+
s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
|
16
|
+
|
17
|
+
s.has_rdoc = false
|
18
|
+
s.extra_rdoc_files = ["README.mkdn", 'Rakefile']
|
19
|
+
s.rdoc_options = ["--line-numbers", "--inline-source",
|
20
|
+
"--main", "README.txt"]
|
21
|
+
|
22
|
+
s.authors = ["Dean Strelau"]
|
23
|
+
s.email = "dean@mintdigital.com"
|
24
|
+
|
25
|
+
s.add_dependency "activerecord", ">= 2.1.0"
|
26
|
+
s.add_dependency "activesupport", ">= 2.1.0"
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::GemPackageTask.new spec do |pkg|
|
30
|
+
pkg.need_tar = true
|
31
|
+
pkg.need_zip = true
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Generate a gemspec file for GitHub"
|
35
|
+
task :gemspec do
|
36
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
37
|
+
f.write spec.to_ruby
|
38
|
+
end
|
39
|
+
end
|
data/lib/minty_scopes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'minty_scopes/version'
|
2
|
+
|
3
|
+
require 'minty_scopes/associations'
|
4
|
+
require 'minty_scopes/except'
|
5
|
+
require 'minty_scopes/order'
|
6
|
+
require 'minty_scopes/timestamps'
|
7
|
+
|
8
|
+
module MintyScopes
|
9
|
+
def self.extended(within)
|
10
|
+
within.extend MintyScopes::Associations
|
11
|
+
within.extend MintyScopes::Except
|
12
|
+
within.extend MintyScopes::Order
|
13
|
+
within.extend MintyScopes::Timestamps
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module MintyScopes
|
2
|
+
module Associations
|
3
|
+
|
4
|
+
def self.extended(within)
|
5
|
+
within.class_eval do
|
6
|
+
# Only show items that have at least one of the associated items
|
7
|
+
# Meant for has_many associations
|
8
|
+
# Post.with(:comments)
|
9
|
+
named_scope :with, lambda { |assoc|
|
10
|
+
raise "The 'with' named_scope expects a non-nil argument." if assoc.nil?
|
11
|
+
{ :joins => assoc.to_sym, :group => "#{quoted_table_name}.id" }
|
12
|
+
}
|
13
|
+
|
14
|
+
named_scope :without, lambda {|assoc|
|
15
|
+
raise "The 'without' named_scope expects a non-nil argument." if assoc.nil?
|
16
|
+
{ :joins => "LEFT JOIN #{assoc.to_s} "+
|
17
|
+
"ON #{quoted_table_name}.id = #{assoc.to_s}.#{quoted_table_name.singularize}_id",
|
18
|
+
:conditions => {"#{assoc}.id" => nil} }
|
19
|
+
}
|
20
|
+
named_scope :including, lambda {|*assocs|
|
21
|
+
{ :include => assocs.flatten }
|
22
|
+
}
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MintyScopes
|
2
|
+
module Except
|
3
|
+
|
4
|
+
def self.extended(within)
|
5
|
+
within.class_eval do
|
6
|
+
# Allow easy rejection of items.
|
7
|
+
# Can take an a single id or ActiveRecord object, or an array of them
|
8
|
+
named_scope :except, lambda { |*args|
|
9
|
+
args.flatten!
|
10
|
+
raise "The 'except' named_scope expects no nil values." unless args.all?
|
11
|
+
{ :conditions => ["#{quoted_table_name}.#{primary_key} NOT IN (?)", args] }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MintyScopes
|
2
|
+
module Order
|
3
|
+
|
4
|
+
def self.extended(within)
|
5
|
+
within.class_eval do
|
6
|
+
# Get only the newest items. Limit by given parameter.
|
7
|
+
# Default to per_page if will_paginate is installed or 10
|
8
|
+
named_scope :newest, lambda { |*limit| {
|
9
|
+
:order => "#{quoted_table_name}.created_at DESC",
|
10
|
+
:limit => limit.empty? ? (per_page rescue 10) : limit.first
|
11
|
+
} }
|
12
|
+
|
13
|
+
# Get only the oldest items. Limit by given parameter.
|
14
|
+
# Default to per_page if will_paginate is installed or 10
|
15
|
+
named_scope :oldest, lambda { |*limit| {
|
16
|
+
:order => "#{quoted_table_name}.created_at ASC",
|
17
|
+
:limit => limit.empty? ? (per_page rescue 10) : limit.first
|
18
|
+
} }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MintyScopes
|
2
|
+
module Timestamps
|
3
|
+
|
4
|
+
def self.extended(within)
|
5
|
+
within.class_eval do
|
6
|
+
# Allow filtering by day of created_on
|
7
|
+
# Argument must be a Date, Time, or DateTime
|
8
|
+
named_scope :created_on, lambda { |date|
|
9
|
+
raise "The 'created_on' named_scope expects a Date, Time or DateTime object" unless date.respond_to? :end_of_day
|
10
|
+
{ :conditions => {:created_at => (date.beginning_of_day..date.end_of_day)} }
|
11
|
+
}
|
12
|
+
|
13
|
+
# Allow filtering by day of modified_on
|
14
|
+
# Argument must be a Date, Time, or DateTime
|
15
|
+
named_scope :modified_on, lambda { |date|
|
16
|
+
raise "The 'modified_on' named_scope expects a Date, Time or DateTime object" unless date.respond_to? :end_of_day
|
17
|
+
{ :conditions => {:modified_on => (date.beginning_of_day..date.end_of_day)} }
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
require 'minty_scopes'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'activerecord'
|
8
|
+
require 'activesupport'
|
9
|
+
|
10
|
+
class Post < ActiveRecord::Base
|
11
|
+
def self.quoted_table_name; 'posts'; end
|
12
|
+
def self.primary_key; 'id'; end
|
13
|
+
extend MintyScopes
|
14
|
+
end
|
15
|
+
|
16
|
+
class PaginatedPost < Post
|
17
|
+
def self.per_page; 30; end
|
18
|
+
extend MintyScopes
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class AssociationsTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "with" do
|
6
|
+
should "complain if passed nil" do
|
7
|
+
assert_raise(RuntimeError) { Post.with(nil).proxy_options }
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return all objects with associated items" do
|
11
|
+
assert_equal( { :joins => :comments, :group => 'posts.id' },
|
12
|
+
Post.with(:comments).proxy_options )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "without" do
|
17
|
+
should "complain if passed nil" do
|
18
|
+
assert_raise(RuntimeError) { Post.with(nil).proxy_options }
|
19
|
+
end
|
20
|
+
|
21
|
+
should "return all objects without associated items" do
|
22
|
+
assert_equal( { :joins => "LEFT JOIN comments ON posts.id = comments.post_id",
|
23
|
+
:conditions => {"comments.id" => nil} },
|
24
|
+
Post.without(:comments).proxy_options )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "including" do
|
29
|
+
should "return objects with given include" do
|
30
|
+
assert_equal( { :include => [:comments] },
|
31
|
+
Post.including(:comments).proxy_options )
|
32
|
+
end
|
33
|
+
|
34
|
+
should "return objects with all of given includes" do
|
35
|
+
assert_equal( { :include => [:comments, {:author => :avator}] },
|
36
|
+
Post.including(:comments, {:author => :avator}).proxy_options )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class ExceptTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "except" do
|
6
|
+
should "complain if passed nil" do
|
7
|
+
assert_raise(RuntimeError){ Post.except(nil).proxy_options }
|
8
|
+
end
|
9
|
+
|
10
|
+
should "complain if passed an array with nil" do
|
11
|
+
assert_raise(RuntimeError) { Post.except([99,nil,101]).proxy_options }
|
12
|
+
end
|
13
|
+
|
14
|
+
should "return all but the given object" do
|
15
|
+
item = 123
|
16
|
+
assert_equal( { :conditions => ["posts.id NOT IN (?)", [item]] },
|
17
|
+
Post.except(item).proxy_options )
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return all but the items in the given list" do
|
21
|
+
list = [123, 456, 7]
|
22
|
+
assert_equal( { :conditions => ["posts.id NOT IN (?)", list] },
|
23
|
+
Post.except(list).proxy_options )
|
24
|
+
end
|
25
|
+
|
26
|
+
should "return all but the given items" do
|
27
|
+
maple, oak = 42, 24
|
28
|
+
assert_equal( { :conditions => ["posts.id NOT IN (?)", [maple, oak]] },
|
29
|
+
Post.except(maple, oak).proxy_options )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class OrderTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "newest" do
|
6
|
+
should "return most recent items" do
|
7
|
+
assert Post.newest.proxy_options[:order] = 'posts.created_at DESC'
|
8
|
+
end
|
9
|
+
|
10
|
+
should "default to 10 items" do
|
11
|
+
assert_equal 10, Post.newest.proxy_options[:limit]
|
12
|
+
end
|
13
|
+
|
14
|
+
should "use the given limit" do
|
15
|
+
assert_equal 20, Post.newest(20).proxy_options[:limit]
|
16
|
+
end
|
17
|
+
|
18
|
+
should "default to per_page if it exists" do
|
19
|
+
assert_equal 30, PaginatedPost.newest.proxy_options[:limit]
|
20
|
+
end
|
21
|
+
|
22
|
+
should "use the given limit over per_page" do
|
23
|
+
assert_equal 15, PaginatedPost.newest(15).proxy_options[:limit]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "oldest" do
|
28
|
+
should "return oldest items" do
|
29
|
+
assert Post.oldest.proxy_options[:order] = 'posts.created_at ASC'
|
30
|
+
end
|
31
|
+
|
32
|
+
should "default to 10 items" do
|
33
|
+
assert_equal 10, Post.oldest.proxy_options[:limit]
|
34
|
+
end
|
35
|
+
|
36
|
+
should "use the given limit" do
|
37
|
+
assert_equal 20, Post.oldest(20).proxy_options[:limit]
|
38
|
+
end
|
39
|
+
|
40
|
+
should "default to per_page if it exists" do
|
41
|
+
assert_equal 30, PaginatedPost.oldest.proxy_options[:limit]
|
42
|
+
end
|
43
|
+
|
44
|
+
should "use the given limit over per_page" do
|
45
|
+
assert_equal 15, PaginatedPost.oldest(15).proxy_options[:limit]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class TimestampsTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
def setup
|
5
|
+
@today = Date.today
|
6
|
+
end
|
7
|
+
|
8
|
+
context "created_on" do
|
9
|
+
should "complain if passed a non date or time" do
|
10
|
+
assert_raise(RuntimeError){ Post.created_on(nil).proxy_options }
|
11
|
+
end
|
12
|
+
|
13
|
+
should "return all objects created on the given date" do
|
14
|
+
assert_equal({:conditions =>
|
15
|
+
{ :created_at => (@today.beginning_of_day..@today.end_of_day) }
|
16
|
+
}, Post.created_on(@today).proxy_options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "modified_on" do
|
21
|
+
should "complain if passed a non date or time" do
|
22
|
+
assert_raise(RuntimeError){ Post.modified_on(nil).proxy_options }
|
23
|
+
end
|
24
|
+
|
25
|
+
should "return all objects modified on the given date" do
|
26
|
+
assert_equal({:conditions =>
|
27
|
+
{ :modified_on => (@today.beginning_of_day..@today.end_of_day) }
|
28
|
+
}, Post.modified_on(@today).proxy_options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dstrelau-minty_scopes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dean Strelau
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-02 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.1.0
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: activesupport
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 2.1.0
|
32
|
+
version:
|
33
|
+
description:
|
34
|
+
email: dean@mintdigital.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README.mkdn
|
41
|
+
- Rakefile
|
42
|
+
files:
|
43
|
+
- Rakefile
|
44
|
+
- README.mkdn
|
45
|
+
- lib/minty_scopes
|
46
|
+
- lib/minty_scopes/associations.rb
|
47
|
+
- lib/minty_scopes/except.rb
|
48
|
+
- lib/minty_scopes/order.rb
|
49
|
+
- lib/minty_scopes/timestamps.rb
|
50
|
+
- lib/minty_scopes/version.rb
|
51
|
+
- lib/minty_scopes.rb
|
52
|
+
- test/test_helper.rb
|
53
|
+
- test/units
|
54
|
+
- test/units/associations_test.rb
|
55
|
+
- test/units/except_test.rb
|
56
|
+
- test/units/order_test.rb
|
57
|
+
- test/units/timestamps_test.rb
|
58
|
+
has_rdoc: false
|
59
|
+
homepage: https://github.com/dstrelau/minty_scopes
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --line-numbers
|
63
|
+
- --inline-source
|
64
|
+
- --main
|
65
|
+
- README.txt
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
version:
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
version:
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.2.0
|
84
|
+
signing_key:
|
85
|
+
specification_version: 2
|
86
|
+
summary: Useful, reusable named_scopes for ActiveRecord.
|
87
|
+
test_files: []
|
88
|
+
|