utility_scopes 0.3.0
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/.gitignore +2 -0
- data/CHANGELOG +29 -0
- data/LICENSE +18 -0
- data/README.textile +146 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/utility_scopes.rb +17 -0
- data/lib/utility_scopes/eager.rb +10 -0
- data/lib/utility_scopes/except.rb +41 -0
- data/lib/utility_scopes/limited.rb +26 -0
- data/lib/utility_scopes/ordered.rb +82 -0
- data/lib/utility_scopes/pks.rb +23 -0
- data/spec/abstract_spec.rb +10 -0
- data/spec/eager_spec.rb +20 -0
- data/spec/except_spec.rb +25 -0
- data/spec/fixtures/article.rb +2 -0
- data/spec/limit_spec.rb +36 -0
- data/spec/ordered_spec.rb +64 -0
- data/spec/spec_helper.rb +5 -0
- data/utility_scopes.gemspec +67 -0
- metadata +83 -0
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
0.3.0
|
2
|
+
|
3
|
+
Added only_pks named scope (and pks class method)
|
4
|
+
|
5
|
+
0.2.3
|
6
|
+
|
7
|
+
Renamed metaclass to eigenclass to avoid conflict w/ Rails' method of the same name
|
8
|
+
|
9
|
+
0.2.2
|
10
|
+
|
11
|
+
* More flexible @ordered@ syntax (by jney - http://github.com/jney)
|
12
|
+
|
13
|
+
0.2.1
|
14
|
+
|
15
|
+
* Fixed except named scope not correctly determining its base class
|
16
|
+
(as reported by Marcus Crafter: http://github.com/crafterm)
|
17
|
+
|
18
|
+
0.2.0
|
19
|
+
|
20
|
+
* Added except scope from danielmorrison (http://github.com/danielmorrison)
|
21
|
+
|
22
|
+
Article.except(1, 2, 3) # Get all articles whose id is NOT 1, 2 or 3
|
23
|
+
Article.except(@article) # Get all articles except the given one
|
24
|
+
Article.except(Article.published) # Get all UN-published articles (poor example
|
25
|
+
# since it executes full "published" query first)
|
26
|
+
|
27
|
+
0.1.0
|
28
|
+
|
29
|
+
* Initial release with limit, with (eager loading) and ordered scopes.
|
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2008 Ryan Daigle
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
h1. Utility Scopes
|
2
|
+
|
3
|
+
h2. Summary
|
4
|
+
|
5
|
+
Utility scopes provides a collection of utilitarian "named scopes":http://api.rubyonrails.com/classes/ActiveRecord/NamedScope/ClassMethods.html#M001246 for use with your
|
6
|
+
ActiveRecord models.
|
7
|
+
|
8
|
+
|
9
|
+
Utility scopes was originally announced "here":http://ryandaigle.com/articles/2008/8/20/named-scope-it-s-not-just-for-conditions-ya-know and has expanded in scope and functionality since then thanks to user contributions. See the
|
10
|
+
"CHANGELOG":http://github.com/yfactorial/utility_scopes/tree/master/CHANGELOG for contribution details.
|
11
|
+
|
12
|
+
Utility scopes has the following dependencies:
|
13
|
+
|
14
|
+
* activerecord >= 2.1.0
|
15
|
+
* rspec >= 1.1.4 (for specs only, not runtime)
|
16
|
+
|
17
|
+
h2. Installation
|
18
|
+
|
19
|
+
To install the utility_scopes gem run the following:
|
20
|
+
|
21
|
+
sudo gem install utility_scopes
|
22
|
+
|
23
|
+
And to enable the scopes in your project just require @utility_scopes@:
|
24
|
+
|
25
|
+
require 'utility_scopes'
|
26
|
+
|
27
|
+
h3. Rails
|
28
|
+
|
29
|
+
You can also specify the gem dependency if you're running Rails 2.1 in your @config/environment.rb@ file:
|
30
|
+
|
31
|
+
Rails::Initializer.run do |config|
|
32
|
+
# ...
|
33
|
+
config.gem "utility_scopes"
|
34
|
+
end
|
35
|
+
|
36
|
+
You don't need to @require 'utility_scopes'@ in this case as Rails will automatically require it.
|
37
|
+
|
38
|
+
h2. Scopes
|
39
|
+
|
40
|
+
Most examples assume the following @Article@ class:
|
41
|
+
|
42
|
+
class Article < ActiveRecord::Base
|
43
|
+
has_many :comments # (assume each comment also has a :user)
|
44
|
+
has_many :contributors
|
45
|
+
belongs_to :author, :class_name => 'User'
|
46
|
+
end
|
47
|
+
|
48
|
+
Named scopes are chainable by nature, meaning that the following is possible:
|
49
|
+
|
50
|
+
Article.with(:comments).except(1, 2, 3).ordered.limited(5)
|
51
|
+
|
52
|
+
Any exceptions to chainable scopes will be specified in their section below.
|
53
|
+
|
54
|
+
h3. With (eager-loading)
|
55
|
+
|
56
|
+
The @with@ scope let's you eager load your model associations. So instead of having to invoke @find(:all, :include => [:association1, :association2])@ just pass these association names into
|
57
|
+
the @with@ named scope:
|
58
|
+
|
59
|
+
<pre><code>
|
60
|
+
# Get all articles and eager-load their comments, each comments' user, article contributors
|
61
|
+
# and the article author.
|
62
|
+
Article.with({ :comments => :user }, :contributors, :author)
|
63
|
+
|
64
|
+
# Get all articles and eager-load their comments
|
65
|
+
Article.with(:comments)
|
66
|
+
</code></pre>
|
67
|
+
|
68
|
+
Again, just pass in the same arguments into @eager@ that you would pass in as the @:include@ value to "ActiveRecord::Base#find":http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001298
|
69
|
+
|
70
|
+
h3. Except
|
71
|
+
|
72
|
+
_contributed by danielmorrison_
|
73
|
+
|
74
|
+
@except@ excludes the given records from the result set:
|
75
|
+
|
76
|
+
Article.except(1, 2, 3) # Get all articles whose id is NOT 1, 2 or 3
|
77
|
+
Article.except(@article) # Get all articles except the given one
|
78
|
+
Article.except(@new_articles) # Get all non-new articles
|
79
|
+
|
80
|
+
h3. Limited
|
81
|
+
|
82
|
+
@limited@ lets you place a limit on the number of results returned. By default
|
83
|
+
the scope will limit the result set to 10 results if no argument is passed in:
|
84
|
+
|
85
|
+
Article.limited # Get the first 10 articles
|
86
|
+
Article.except(1).limited(5) # Get the first 5 articles where id != 1
|
87
|
+
|
88
|
+
If you're using "will_paginate":http://github.com/mislav/will_paginate/tree/master and don't
|
89
|
+
pass an argument to the scope then the @per_page@ value that is used by will_paginate
|
90
|
+
will be used:
|
91
|
+
|
92
|
+
Article.per_page #=> 20
|
93
|
+
Article.limited # Get the first 20 articles
|
94
|
+
|
95
|
+
If you would like to specify a different default value you can do so on a per class basis
|
96
|
+
using @default_limit@:
|
97
|
+
|
98
|
+
<pre><code>
|
99
|
+
# Set the default limit to be 15
|
100
|
+
class Article < ActiveRecord::Base
|
101
|
+
default_limit 15
|
102
|
+
end
|
103
|
+
|
104
|
+
Article.limited # Get the first 15 articles
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
h3. Ordered
|
108
|
+
|
109
|
+
_Note: the @ordered@ scope cannot be chained with any other @order@ clauses_
|
110
|
+
|
111
|
+
@ordered@ lets you dynamically specify the ordering of your result set. If no
|
112
|
+
arguments are given it will default to @created_at DESC@. (@ordered@ is also
|
113
|
+
available as @order_by@ and @sort_by@)
|
114
|
+
|
115
|
+
Article.ordered # Get all articles ordered by "created_at DESC"
|
116
|
+
Article.ordered(:id) # Get all articles ordered by "id"
|
117
|
+
Article.ordered("rank ASC") # Get all articles ordered by "rank ASC"
|
118
|
+
Article.order_by(:id) # order_by and sort_by are alias to ordered
|
119
|
+
Article.order_by([:id, :desc], :popularity) # can take a two-element array as parameter
|
120
|
+
Article.sort_by(:id => :desc, :popularity => :asc) # can take a hash as parameter
|
121
|
+
# only available for jruby/ruby 1.9
|
122
|
+
Article.order_by_id # can be set as a sentence
|
123
|
+
|
124
|
+
If you would like to specify a different default sort order you can do so on a per class basis
|
125
|
+
using @ordered_by@:
|
126
|
+
|
127
|
+
<pre><code>
|
128
|
+
# Set the default order to be "published_at DESC"
|
129
|
+
class Article < ActiveRecord::Base
|
130
|
+
ordered_by 'published_at DESC'
|
131
|
+
end
|
132
|
+
|
133
|
+
Article.ordered # Get all articles ordered by "published_at DESC"
|
134
|
+
Article.ordered("rank ASC") # Get all articles ordered by "rank ASC"
|
135
|
+
</code></pre>
|
136
|
+
|
137
|
+
The current default ordering for a class can always be accessed via @default_ordering@:
|
138
|
+
|
139
|
+
Article.default_ordering #=> "published_at DESC"
|
140
|
+
|
141
|
+
h3. PKs
|
142
|
+
|
143
|
+
@only_pks@ selects only the primary key column. This is useful when combined with the @pks@ class method to get the primary key values as an array:
|
144
|
+
|
145
|
+
Article.published.limited(10).only_pks # Get the first 10 published articles with only the 'id' value populated [<Article:XX>, <Article:XX>, ...]
|
146
|
+
Article.published.limited(10).pks # Get the first 10 published article ids: [1, 2, 3 ...]
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
desc 'Run the specs'
|
7
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
8
|
+
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
9
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Generate RDoc documentation.'
|
13
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'Rakefile').
|
15
|
+
include('lib/**/*.rb')
|
16
|
+
|
17
|
+
rdoc.main = "README.rdoc"
|
18
|
+
rdoc.title = "utility_scopes documentation"
|
19
|
+
|
20
|
+
rdoc.rdoc_dir = 'doc' # rdoc output folder
|
21
|
+
rdoc.options << '--inline-source' << '--charset=UTF-8'
|
22
|
+
rdoc.options << '--webcvs=http://github.com/yfactorial/utility_scopes/tree/master/'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Rakefile
|
26
|
+
begin
|
27
|
+
require 'jeweler'
|
28
|
+
Jeweler::Tasks.new do |gemspec|
|
29
|
+
gemspec.name = "utility_scopes"
|
30
|
+
gemspec.summary = "A collection of utilitarian named scopes providing common functionality for ActiveRecord models."
|
31
|
+
gemspec.description = "A collection of utilitarian named scopes providing common functionality for ActiveRecord models."
|
32
|
+
gemspec.email = "ryan@digitaltoniq.com"
|
33
|
+
gemspec.homepage = "http://github.com/yfactorial/utility_scopes"
|
34
|
+
gemspec.authors = ["Ryan Daigle", "Daniel Morrison"]
|
35
|
+
end
|
36
|
+
Jeweler::GemcutterTasks.new
|
37
|
+
rescue LoadError
|
38
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'utility_scopes'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'utility_scopes/limited'
|
2
|
+
require 'utility_scopes/ordered'
|
3
|
+
require 'utility_scopes/eager'
|
4
|
+
require 'utility_scopes/except'
|
5
|
+
require 'utility_scopes/pks'
|
6
|
+
|
7
|
+
if defined?(ActiveRecord)
|
8
|
+
|
9
|
+
ActiveRecord::Base.class_eval do
|
10
|
+
include UtilityScopes::Limited
|
11
|
+
include UtilityScopes::Ordered
|
12
|
+
include UtilityScopes::Eager
|
13
|
+
include UtilityScopes::Except
|
14
|
+
include UtilityScopes::Pks
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module UtilityScopes
|
2
|
+
module Except
|
3
|
+
|
4
|
+
def self.included(within)
|
5
|
+
within.class_eval do
|
6
|
+
|
7
|
+
# Give every class the ability to add to itself the except named
|
8
|
+
# scope
|
9
|
+
extend ClassMethods
|
10
|
+
|
11
|
+
# And automatically do so for all its subclasses
|
12
|
+
def self.inherited_with_except_scope_hook(child)
|
13
|
+
inherited_without_except_scope_hook(child)
|
14
|
+
child.attach_except_utility_scope
|
15
|
+
end
|
16
|
+
class << self
|
17
|
+
alias_method_chain :inherited, :except_scope_hook
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
|
24
|
+
# Must be a class method called directly on AR::Base subclasses
|
25
|
+
# so named_scope knows who its base class, and thus, table_name
|
26
|
+
# and primary_key are.
|
27
|
+
def attach_except_utility_scope
|
28
|
+
|
29
|
+
# Allow easy rejection of items.
|
30
|
+
# Can take an a single id or ActiveRecord object, or an array of them
|
31
|
+
# Example:
|
32
|
+
# before Article.all.reject{|a| a == @bad_article }
|
33
|
+
# after Article.except(@bad_article)
|
34
|
+
named_scope :except, lambda { |item_or_list|
|
35
|
+
# nil or empty array causes issues here with mysql
|
36
|
+
item_or_list.blank? ? {} : {:conditions => ["#{quoted_table_name}.#{primary_key} NOT IN (?)", item_or_list]}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module UtilityScopes
|
2
|
+
module Limited
|
3
|
+
|
4
|
+
def self.included(within)
|
5
|
+
|
6
|
+
within.class_eval do
|
7
|
+
|
8
|
+
# Provide default limit scope (can be overridden
|
9
|
+
# if default_limit is called)
|
10
|
+
named_scope :limited, lambda { |*num|
|
11
|
+
{ :limit => num.flatten.first || (defined?(per_page) ? per_page : 10) }
|
12
|
+
}
|
13
|
+
|
14
|
+
extend ClassMethods
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
# Set the default limit to use for the limit scope
|
21
|
+
def default_limit(default)
|
22
|
+
named_scope :limited, lambda { |*num| { :limit => num.flatten.first || default } }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#TODO: use base_class to get rid off duplication?
|
2
|
+
module UtilityScopes
|
3
|
+
module Ordered
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
|
8
|
+
base.class_eval do
|
9
|
+
# Provide an ordered scope
|
10
|
+
named_scope(:ordered, lambda { |*order|
|
11
|
+
{ :order => case
|
12
|
+
when order.empty?
|
13
|
+
self.default_ordering
|
14
|
+
# allow hash support for jruby or ruby 1.9
|
15
|
+
when order.size == 1 && order[0].is_a?(Hash) && (PLATFORM=~/java/ || RUBY_VERSION=~/1\.9.*/)
|
16
|
+
order.first.collect{|(k,v)| "#{k} #{v.to_s.upcase}"}.join(', ')
|
17
|
+
else
|
18
|
+
order.collect{|e| e.is_a?(Array) ? "#{e[0]} #{e[1].to_s.upcase}" : e}.join(', ')
|
19
|
+
end
|
20
|
+
}
|
21
|
+
})
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# Set alias order_by
|
25
|
+
alias_method :order_by, :ordered
|
26
|
+
# Set alias sort_by
|
27
|
+
alias_method :sort_by, :ordered
|
28
|
+
# Set the default order
|
29
|
+
define_method(:default_ordering) { 'created_at DESC' }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
|
36
|
+
# Decorate this class with the ability to order itself in queries
|
37
|
+
# either from a given parameter or from its default ordering:
|
38
|
+
#
|
39
|
+
# class Article < ActiveRecord::Base
|
40
|
+
# ordered_by "published_at DESC"
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# Article.ordered #=> all items ordered by "published_at DESC"
|
44
|
+
# Article.ordered('popularity ASC') #=> all items ordered by "popularity ASC"
|
45
|
+
# Article.default_ordering #=> "published_at DESC"
|
46
|
+
#
|
47
|
+
def ordered_by(clause)
|
48
|
+
# Override named scope on AR::Base so we can access default_ordering
|
49
|
+
# on subclass
|
50
|
+
named_scope(:ordered, lambda { |*order|
|
51
|
+
{ :order => case
|
52
|
+
when order.empty?
|
53
|
+
self.default_ordering
|
54
|
+
# allow hash support for jruby or ruby 1.9
|
55
|
+
when order.size == 1 && order[0].is_a?(Hash) && (PLATFORM=~/java/ || RUBY_VERSION=~/1\.9.*/)
|
56
|
+
order.first.collect{|(k,v)| "#{k} #{v.to_s.upcase}"}.join(', ')
|
57
|
+
else
|
58
|
+
order.collect{|e| e.is_a?(Array) ? "#{e[0]} #{e[1].to_s.upcase}" : e}.join(', ')
|
59
|
+
end
|
60
|
+
}
|
61
|
+
})
|
62
|
+
|
63
|
+
eigenclass.instance_eval do
|
64
|
+
define_method(:default_ordering) { clause }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_missing(method, *args, &block)
|
69
|
+
col = method.to_s.match(/^(order_by_|sort_by_)(.*)$/)[2] rescue false
|
70
|
+
if col && self.columns.collect{ |c| c.name }.include?(col)
|
71
|
+
return self.order_by(col, *args, &block)
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def eigenclass; class << self; self end; end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module UtilityScopes
|
2
|
+
module Pks
|
3
|
+
|
4
|
+
def self.included(within)
|
5
|
+
|
6
|
+
within.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Can't use named_scope b/c don't have access to table_name etc... yet
|
14
|
+
def only_pks
|
15
|
+
scoped(:select => "`#{table_name}`.#{primary_key}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def pks
|
19
|
+
only_pks.collect(&:"#{primary_key}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[spec_helper])
|
2
|
+
require 'activerecord'
|
3
|
+
|
4
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
5
|
+
require 'utility_scopes'
|
6
|
+
|
7
|
+
# Load a test class
|
8
|
+
def uses_fixture(fixture_name)
|
9
|
+
require File.join(File.dirname(__FILE__), 'fixtures', fixture_name.to_s)
|
10
|
+
end
|
data/spec/eager_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[abstract_spec])
|
2
|
+
|
3
|
+
describe "Eager scope" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
uses_fixture(:article)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should provide eager loading of a single association" do
|
10
|
+
Article.with(:comments).proxy_options.should == {:include => [:comments] }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should provide eager loading of a multiple associations" do
|
14
|
+
Article.with(:comments, :contributors).proxy_options.should == {:include => [:comments, :contributors] }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should provider eager loading of nested associations" do
|
18
|
+
Article.with(:comments => :author).proxy_options.should == {:include => [ {:comments => :author} ] }
|
19
|
+
end
|
20
|
+
end
|
data/spec/except_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[abstract_spec])
|
2
|
+
|
3
|
+
describe "except scope" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
uses_fixture(:article)
|
7
|
+
# Stub these so it doesn't try to hit the (non-existant) database
|
8
|
+
Article.stub!(:quoted_table_name).and_return("'articles'")
|
9
|
+
Article.stub!(:primary_key).and_return('id')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not change the scope with nil" do
|
13
|
+
Article.except(nil).proxy_options.should == {}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return all items except the one specified" do
|
17
|
+
item = 123
|
18
|
+
Article.except(item).proxy_options.should == {:conditions => ["'articles'.id NOT IN (?)", item]}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return all items except ones in the list specified" do
|
22
|
+
list = [123, 456, 7]
|
23
|
+
Article.except(list).proxy_options.should == {:conditions => ["'articles'.id NOT IN (?)", list]}
|
24
|
+
end
|
25
|
+
end
|
data/spec/limit_spec.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[abstract_spec])
|
2
|
+
|
3
|
+
describe "limited scope" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
uses_fixture(:article)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should default to a limited of 10" do
|
10
|
+
Article.limited.proxy_options.should == {:limit => 10}
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should allow the limited to be specified at runtime" do
|
14
|
+
Article.limited(20).proxy_options.should == {:limit => 20}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should find the per_page value from will_paginate" do
|
18
|
+
ActiveRecord::Base.instance_eval { def per_page; 50; end }
|
19
|
+
Article.limited.proxy_options.should == {:limit => 50}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should use the runtime limited value over the per_page value from will_paginate" do
|
23
|
+
ActiveRecord::Base.instance_eval { def per_page; 50; end }
|
24
|
+
Article.limited(5).proxy_options.should == {:limit => 5}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should allow override the default limited value with 'default_limited'" do
|
28
|
+
Article.default_limit 13
|
29
|
+
Article.limited.proxy_options.should == {:limit => 13}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should use the runtime value over the default limited value set with 'default_limited'" do
|
33
|
+
Article.default_limit 13
|
34
|
+
Article.limited(25).proxy_options.should == {:limit => 25}
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[abstract_spec])
|
2
|
+
|
3
|
+
describe "Ordered scope" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
uses_fixture(:article)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should default to created_at DESC" do
|
10
|
+
Article.ordered.proxy_options.should == {:order => 'created_at DESC'}
|
11
|
+
Article.default_ordering.should == 'created_at DESC'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should allow the order to be specified at runtime" do
|
15
|
+
Article.ordered('created_at ASC').proxy_options.should == {:order => 'created_at ASC'}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow the order to use arrays as arg" do
|
19
|
+
Article.ordered([:popularity, :asc], [:second_param, :desc]).proxy_options.should == {:order => 'popularity ASC, second_param DESC'}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow the order hash as arg" do
|
23
|
+
if (PLATFORM=~/java/ || RUBY_VERSION=~/1\.9.*/)
|
24
|
+
Article.ordered(:popularity => :asc, :second_param => :desc).proxy_options.should == {:order => 'popularity ASC, second_param DESC'}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should allow the order with several args" do
|
29
|
+
Article.ordered(:popularity, :updated_at).proxy_options.should == {:order => 'popularity, updated_at'}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should sort by column popularity when calling order_by_popularity" do
|
33
|
+
require 'ostruct'
|
34
|
+
columns = [OpenStruct.new({:name => 'popularity'})]
|
35
|
+
Article.stub!(:columns).and_return(columns)
|
36
|
+
Article.order_by_popularity.proxy_options.should == {:order => 'popularity'}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error when column does not exist" do
|
40
|
+
require 'ostruct'
|
41
|
+
columns = [OpenStruct.new({:name => 'popularity'})]
|
42
|
+
Article.stub!(:columns).and_return(columns)
|
43
|
+
lambda{ Article.order_by_unknown_columns }.should raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have an alias" do
|
47
|
+
Article.order_by([:popularity, :asc]).proxy_options.should == {:order => 'popularity ASC'}
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should allow the default to be overidden by using ordered_by" do
|
51
|
+
Article.ordered_by 'published_at DESC'
|
52
|
+
Article.default_ordering.should == 'published_at DESC'
|
53
|
+
Article.ordered.proxy_options.should == {:order => 'published_at DESC'}
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should use the runtime sort value over the ordered_by value" do
|
57
|
+
Article.ordered_by 'published_at DESC'
|
58
|
+
Article.ordered('popularity ASC').proxy_options.should == {:order => 'popularity ASC'}
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be able to handle symbol order criteria" do
|
62
|
+
Article.ordered(:id).proxy_options.should == { :order => 'id' }
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{utility_scopes}
|
8
|
+
s.version = "0.3.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ryan Daigle", "Daniel Morrison"]
|
12
|
+
s.date = %q{2009-12-11}
|
13
|
+
s.description = %q{A collection of utilitarian named scopes providing common functionality for ActiveRecord models.}
|
14
|
+
s.email = %q{ryan@digitaltoniq.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.textile"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"CHANGELOG",
|
22
|
+
"LICENSE",
|
23
|
+
"README.textile",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"init.rb",
|
27
|
+
"lib/utility_scopes.rb",
|
28
|
+
"lib/utility_scopes/eager.rb",
|
29
|
+
"lib/utility_scopes/except.rb",
|
30
|
+
"lib/utility_scopes/limited.rb",
|
31
|
+
"lib/utility_scopes/ordered.rb",
|
32
|
+
"lib/utility_scopes/pks.rb",
|
33
|
+
"spec/abstract_spec.rb",
|
34
|
+
"spec/eager_spec.rb",
|
35
|
+
"spec/except_spec.rb",
|
36
|
+
"spec/fixtures/article.rb",
|
37
|
+
"spec/limit_spec.rb",
|
38
|
+
"spec/ordered_spec.rb",
|
39
|
+
"spec/spec_helper.rb",
|
40
|
+
"utility_scopes.gemspec"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/yfactorial/utility_scopes}
|
43
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.5}
|
46
|
+
s.summary = %q{A collection of utilitarian named scopes providing common functionality for ActiveRecord models.}
|
47
|
+
s.test_files = [
|
48
|
+
"spec/abstract_spec.rb",
|
49
|
+
"spec/eager_spec.rb",
|
50
|
+
"spec/except_spec.rb",
|
51
|
+
"spec/fixtures/article.rb",
|
52
|
+
"spec/limit_spec.rb",
|
53
|
+
"spec/ordered_spec.rb",
|
54
|
+
"spec/spec_helper.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
62
|
+
else
|
63
|
+
end
|
64
|
+
else
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: utility_scopes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Daigle
|
8
|
+
- Daniel Morrison
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-12-11 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: A collection of utilitarian named scopes providing common functionality for ActiveRecord models.
|
18
|
+
email: ryan@digitaltoniq.com
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- LICENSE
|
25
|
+
- README.textile
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- CHANGELOG
|
29
|
+
- LICENSE
|
30
|
+
- README.textile
|
31
|
+
- Rakefile
|
32
|
+
- VERSION
|
33
|
+
- init.rb
|
34
|
+
- lib/utility_scopes.rb
|
35
|
+
- lib/utility_scopes/eager.rb
|
36
|
+
- lib/utility_scopes/except.rb
|
37
|
+
- lib/utility_scopes/limited.rb
|
38
|
+
- lib/utility_scopes/ordered.rb
|
39
|
+
- lib/utility_scopes/pks.rb
|
40
|
+
- spec/abstract_spec.rb
|
41
|
+
- spec/eager_spec.rb
|
42
|
+
- spec/except_spec.rb
|
43
|
+
- spec/fixtures/article.rb
|
44
|
+
- spec/limit_spec.rb
|
45
|
+
- spec/ordered_spec.rb
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- utility_scopes.gemspec
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/yfactorial/utility_scopes
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- --charset=UTF-8
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.3.5
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: A collection of utilitarian named scopes providing common functionality for ActiveRecord models.
|
76
|
+
test_files:
|
77
|
+
- spec/abstract_spec.rb
|
78
|
+
- spec/eager_spec.rb
|
79
|
+
- spec/except_spec.rb
|
80
|
+
- spec/fixtures/article.rb
|
81
|
+
- spec/limit_spec.rb
|
82
|
+
- spec/ordered_spec.rb
|
83
|
+
- spec/spec_helper.rb
|