convenient_scopes 0.4.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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/convenient_scopes.gemspec +65 -0
- data/lib/convenient_scopes.rb +182 -0
- data/test/helper.rb +48 -0
- data/test/test_all_and_any_conditions.rb +19 -0
- data/test/test_associations.rb +53 -0
- data/test/test_conditions.rb +70 -0
- data/test/test_ordering.rb +27 -0
- metadata +116 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ivan Schneider
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= convenient_scopes
|
2
|
+
|
3
|
+
Dynamic scopes by convention for ActiveRecord 3.
|
4
|
+
|
5
|
+
Pretty much the same API as searchlogic except it's compatible with ActiveRecord 3, unlike searchlogic as of now. The whole feature set of searchlogic isn't implemented yet in convenient_scopes though.
|
6
|
+
|
7
|
+
== Note on Patches/Pull Requests
|
8
|
+
|
9
|
+
* Fork the project.
|
10
|
+
* Make your feature addition or bug fix.
|
11
|
+
* Add tests for it. This is important so I don't break it in a
|
12
|
+
future version unintentionally.
|
13
|
+
* Commit, do not mess with rakefile, version, or history.
|
14
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
15
|
+
* Send me a pull request. Bonus points for topic branches.
|
16
|
+
|
17
|
+
== Copyright
|
18
|
+
|
19
|
+
Copyright (c) 2010 Ivan Schneider. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "convenient_scopes"
|
8
|
+
gem.summary = %Q{Dynamic scopes by convention for ActiveRecord 3}
|
9
|
+
gem.description = %Q{Dynamic scopes by convention for ActiveRecord 3}
|
10
|
+
gem.email = "isc@massivebraingames.com"
|
11
|
+
gem.homepage = "http://github.com/isc/convenient_scopes"
|
12
|
+
gem.authors = ["Ivan Schneider"]
|
13
|
+
gem.add_runtime_dependency "activerecord", ">= 3.0.0.beta4"
|
14
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
15
|
+
gem.add_development_dependency "sqlite3-ruby"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rake/testtask'
|
24
|
+
Rake::TestTask.new(:test) do |test|
|
25
|
+
test.libs << 'lib' << 'test'
|
26
|
+
test.pattern = 'test/**/test_*.rb'
|
27
|
+
test.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
require 'rcov/rcovtask'
|
32
|
+
Rcov::RcovTask.new do |test|
|
33
|
+
test.libs << 'test'
|
34
|
+
test.pattern = 'test/**/test_*.rb'
|
35
|
+
test.verbose = true
|
36
|
+
end
|
37
|
+
rescue LoadError
|
38
|
+
task :rcov do
|
39
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
task :test => :check_dependencies
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
require 'rake/rdoctask'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "convenient_scopes #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.0
|
@@ -0,0 +1,65 @@
|
|
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{convenient_scopes}
|
8
|
+
s.version = "0.4.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ivan Schneider"]
|
12
|
+
s.date = %q{2010-07-25}
|
13
|
+
s.description = %q{Dynamic scopes by convention for ActiveRecord 3}
|
14
|
+
s.email = %q{isc@massivebraingames.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"convenient_scopes.gemspec",
|
27
|
+
"lib/convenient_scopes.rb",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/test_associations.rb",
|
30
|
+
"test/test_conditions.rb",
|
31
|
+
"test/test_ordering.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/isc/convenient_scopes}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
37
|
+
s.summary = %q{Dynamic scopes by convention for ActiveRecord 3}
|
38
|
+
s.test_files = [
|
39
|
+
"test/helper.rb",
|
40
|
+
"test/test_all_and_any_conditions.rb",
|
41
|
+
"test/test_associations.rb",
|
42
|
+
"test/test_conditions.rb",
|
43
|
+
"test/test_ordering.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
52
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
56
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
57
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
61
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
62
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module ConvenientScopes
|
2
|
+
|
3
|
+
def method_missing(name, *args, &block)
|
4
|
+
if scope_data = (define_scope name)
|
5
|
+
scope name, convert_to_scope_arg(scope_data)
|
6
|
+
return send name, *args, &block
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Conditions
|
13
|
+
|
14
|
+
def equals_scope name
|
15
|
+
return unless (column = match_suffix_and_column_name name, %w(equals eq is))
|
16
|
+
lambda {|value| where(column => value)}
|
17
|
+
end
|
18
|
+
|
19
|
+
def does_not_equal_scope name
|
20
|
+
match_and_define_scope name, %w(does_not_equal doesnt_equal ne is_not), "%s != ?"
|
21
|
+
end
|
22
|
+
|
23
|
+
def less_than_scope name
|
24
|
+
match_and_define_scope name, %w(less_than lt before), "%s < ?"
|
25
|
+
end
|
26
|
+
|
27
|
+
def less_than_or_equal_scope name
|
28
|
+
match_and_define_scope name, %w(less_than_or_equal lte), "%s <= ?"
|
29
|
+
end
|
30
|
+
|
31
|
+
def greater_than_scope name
|
32
|
+
match_and_define_scope name, %w(greater_than gt after), "%s > ?"
|
33
|
+
end
|
34
|
+
|
35
|
+
def greater_than_or_equal_scope name
|
36
|
+
match_and_define_scope name, %w(greater_than_or_equal gte), "%s >= ?"
|
37
|
+
end
|
38
|
+
|
39
|
+
def like_scope name
|
40
|
+
match_and_define_scope name, %w(like matches contains includes), "%s like ?", "%%%s%%"
|
41
|
+
end
|
42
|
+
|
43
|
+
def not_like_scope name
|
44
|
+
suffixes = %w(not_like does_not_match doesnt_match does_not_contain doesnt_contain does_not_include doesnt_include)
|
45
|
+
match_and_define_scope name, suffixes, "%s not like ?", "%%%s%%"
|
46
|
+
end
|
47
|
+
|
48
|
+
def begins_with_scope name
|
49
|
+
match_and_define_scope name, %w(begins_with bw starts_with sw), "%s like ?", "%s%%"
|
50
|
+
end
|
51
|
+
|
52
|
+
def not_begin_with_scope name
|
53
|
+
suffixes = %w(not_begin_with does_not_begin_with doesnt_begin_with does_not_start_with doesnt_start_with)
|
54
|
+
match_and_define_scope name, suffixes, "%s not like ?", "%s%%"
|
55
|
+
end
|
56
|
+
|
57
|
+
def ends_with_scope name
|
58
|
+
match_and_define_scope name, %w(ends_with ew), "%s like ?", "%%%s"
|
59
|
+
end
|
60
|
+
|
61
|
+
def not_end_with_scope name
|
62
|
+
match_and_define_scope name, %w(not_end_with does_not_end_with doesnt_end_with), "%s not like ?", "%%%s"
|
63
|
+
end
|
64
|
+
|
65
|
+
def null_scope name
|
66
|
+
match_and_define_scope_without_value name, %w(null nil missing), "%s is null"
|
67
|
+
end
|
68
|
+
|
69
|
+
def not_null_scope name
|
70
|
+
match_and_define_scope_without_value name, %w(not_null not_nil not_missing), "%s is not null"
|
71
|
+
end
|
72
|
+
|
73
|
+
def boolean_column_scope name
|
74
|
+
return unless column_names.include? name.to_s
|
75
|
+
return unless boolean_column? name
|
76
|
+
where(name => true)
|
77
|
+
end
|
78
|
+
|
79
|
+
def negative_boolean_column_scope name
|
80
|
+
str_name = name.to_s
|
81
|
+
return unless str_name.gsub!(/^not_/, '')
|
82
|
+
return unless column_names.include? str_name
|
83
|
+
return unless boolean_column? str_name
|
84
|
+
where(str_name => false)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
include Conditions
|
90
|
+
|
91
|
+
module Ordering
|
92
|
+
|
93
|
+
def ascend_by_scope name
|
94
|
+
ordering_scope name, /^ascend_by_/, 'asc'
|
95
|
+
end
|
96
|
+
|
97
|
+
def descend_by_scope name
|
98
|
+
ordering_scope name, /^descend_by_/, 'desc'
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def ordering_scope name, prefix, direction
|
104
|
+
str_name = name.to_s
|
105
|
+
return unless str_name.gsub!(prefix, '')
|
106
|
+
determine_order_scope_data str_name, direction
|
107
|
+
end
|
108
|
+
|
109
|
+
def determine_order_scope_data name, direction
|
110
|
+
if column_names.include? name.to_s
|
111
|
+
order("#{quoted_table_name}.#{name} #{direction}")
|
112
|
+
elsif assoc = (possible_association_for_scope name)
|
113
|
+
next_scope = name.to_s.split("#{assoc.name}_").last.to_sym # age
|
114
|
+
scope_arg = assoc.klass.determine_order_scope_data next_scope, direction
|
115
|
+
scope_arg.is_a?(Array) ? [assoc.name] + scope_arg : [assoc.name, scope_arg] if scope_arg
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
include Ordering
|
120
|
+
|
121
|
+
def association_scope name
|
122
|
+
return unless assoc = (possible_association_for_scope name)
|
123
|
+
next_scope = name.to_s.split("#{assoc.name}_").last.to_sym
|
124
|
+
scope_arg = (assoc.klass.define_scope next_scope) || assoc.klass.scopes[next_scope]
|
125
|
+
scope_arg.is_a?(Array) ? [assoc.name] + scope_arg : [assoc.name, scope_arg] if scope_arg
|
126
|
+
end
|
127
|
+
|
128
|
+
def possible_association_for_scope name
|
129
|
+
reflect_on_all_associations.detect {|assoc| name.to_s.starts_with? assoc.name.to_s}
|
130
|
+
end
|
131
|
+
|
132
|
+
def define_scope name
|
133
|
+
[Conditions, Ordering].map(&:instance_methods).flatten.each do |scope_type|
|
134
|
+
if scope_arg = (send scope_type.to_sym, name)
|
135
|
+
return scope_arg unless scope_arg.nil?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
association_scope name
|
139
|
+
end
|
140
|
+
|
141
|
+
def match_and_define_scope name, suffixes, sql_format, value_format = nil
|
142
|
+
return unless (column = match_suffix_and_column_name name, suffixes)
|
143
|
+
sql = formatted_sql column, sql_format
|
144
|
+
lambda {|value| where([sql, value_format ? (value_format % value) : value])}
|
145
|
+
end
|
146
|
+
|
147
|
+
def match_and_define_scope_without_value name, suffixes, sql_format
|
148
|
+
return unless (column = match_suffix_and_column_name name, suffixes)
|
149
|
+
where(formatted_sql column, sql_format)
|
150
|
+
end
|
151
|
+
|
152
|
+
def formatted_sql column, sql_format
|
153
|
+
sql = sql_format % "#{quoted_table_name}.#{column}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def match_suffix_and_column_name name, suffixes
|
157
|
+
str_name = name.to_s
|
158
|
+
regexp_str = suffixes.map {|suffix| "(_#{suffix})"}.join('|') + '$'
|
159
|
+
return unless str_name.gsub!(Regexp.new(regexp_str), '')
|
160
|
+
return unless column_names.include? str_name
|
161
|
+
str_name
|
162
|
+
end
|
163
|
+
|
164
|
+
def boolean_column? name
|
165
|
+
columns.detect {|c|c.name == name.to_s}.type == :boolean
|
166
|
+
end
|
167
|
+
|
168
|
+
def convert_to_scope_arg scope_data
|
169
|
+
return scope_data unless scope_data.is_a? Array
|
170
|
+
relation_or_proc = scope_data.pop
|
171
|
+
joins_arg = (scope_data.size == 1) ? scope_data.first : {scope_data.first => scope_data.last}
|
172
|
+
if relation_or_proc.is_a? ActiveRecord::Relation
|
173
|
+
relation_or_proc.joins joins_arg
|
174
|
+
else
|
175
|
+
lambda {|*value| relation_or_proc.call(*value).joins joins_arg }
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
ActiveRecord::Base.extend ConvenientScopes
|
182
|
+
ActiveRecord::Relation.send :include, ConvenientScopes
|
data/test/helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'active_record'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
require 'convenient_scopes'
|
9
|
+
|
10
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
11
|
+
class User < ActiveRecord::Base
|
12
|
+
has_many :comments
|
13
|
+
belongs_to :group
|
14
|
+
end
|
15
|
+
class Group < ActiveRecord::Base
|
16
|
+
has_many :users
|
17
|
+
end
|
18
|
+
class Comment < ActiveRecord::Base
|
19
|
+
belongs_to :user
|
20
|
+
end
|
21
|
+
|
22
|
+
class Test::Unit::TestCase
|
23
|
+
def teardown
|
24
|
+
User.delete_all
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActiveRecord::Base.configurations = true
|
29
|
+
ActiveRecord::Schema.verbose = false
|
30
|
+
ActiveRecord::Schema.define(:version => 1) do
|
31
|
+
create_table :users do |t|
|
32
|
+
t.string :pseudo, :first_name, :last_name
|
33
|
+
t.integer :group_id, :age
|
34
|
+
t.datetime :activated_at
|
35
|
+
t.boolean :admin
|
36
|
+
t.timestamps
|
37
|
+
end
|
38
|
+
create_table :groups do |t|
|
39
|
+
t.string :name
|
40
|
+
t.timestamps
|
41
|
+
end
|
42
|
+
create_table :comments do |t|
|
43
|
+
t.string :body
|
44
|
+
t.integer :user_id
|
45
|
+
t.boolean :published
|
46
|
+
t.timestamps
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestAllAndAnyConditions < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "convenient_scopes" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@bob = User.create :pseudo => 'Bob Larchi'
|
9
|
+
@slim = User.create :pseudo => 'Slim Babine'
|
10
|
+
end
|
11
|
+
|
12
|
+
should "handle conditions scopes suffixed by any" do
|
13
|
+
flunk "not implemented yet"
|
14
|
+
assert_equal [@bob, @slim], User.pseudo_like_any('Bob', 'Slim')
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestAssociations < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "convenient_scopes" do
|
6
|
+
setup do
|
7
|
+
@manager_group = Group.create :name => 'Managers'
|
8
|
+
@bob = User.create :comments => [(Comment.new :body => 'Yo', :published => false, :created_at => 1.week.ago)], :group => @manager_group
|
9
|
+
@dev_group = Group.create :name => 'Developers'
|
10
|
+
@slim = User.create :comments => [(Comment.new :body => 'Bye', :published => false, :created_at => 10.minutes.ago),
|
11
|
+
(Comment.new :body => 'Hello', :published => true, :created_at => 2.days.ago)],
|
12
|
+
:group => @dev_group
|
13
|
+
end
|
14
|
+
|
15
|
+
should "not catch everything" do
|
16
|
+
assert_raise NoMethodError do
|
17
|
+
User.comment_body_is('Yo')
|
18
|
+
end
|
19
|
+
assert_raise NoMethodError do
|
20
|
+
User.comments_synopsis_eq('Yo')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
should "handle has_many association + attribute conditions" do
|
25
|
+
assert_equal [@bob], User.comments_body_equals('Yo')
|
26
|
+
assert_equal [@slim], User.comments_body_starts_with('He')
|
27
|
+
assert_equal [@bob], User.comments_id_is(@bob.comments.first.id)
|
28
|
+
assert_equal [@slim], User.comments_id_is(@slim.comments.last.id)
|
29
|
+
assert_equal [@bob], User.comments_created_at_before(3.days.ago)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "handle has many association + boolean column" do
|
33
|
+
assert_equal [@slim], User.comments_published
|
34
|
+
end
|
35
|
+
|
36
|
+
should "handle belongs_to association" do
|
37
|
+
assert_equal [@bob], User.group_name_is('Managers')
|
38
|
+
assert_equal [@slim], User.group_name_matches('velo')
|
39
|
+
end
|
40
|
+
|
41
|
+
should "handle two levels of association" do
|
42
|
+
assert_equal [@dev_group], Group.users_comments_published
|
43
|
+
end
|
44
|
+
|
45
|
+
should "be able to leverage a named scope on an association" do
|
46
|
+
Comment.scope :recent, Comment.created_at_after(1.hour.ago).created_at_not_nil
|
47
|
+
assert_equal [@slim], User.comments_recent
|
48
|
+
assert_equal [@dev_group], Group.users_comments_recent
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestConditions < Test::Unit::TestCase
|
4
|
+
context "Given two users" do
|
5
|
+
setup do
|
6
|
+
@bob = User.create :pseudo => 'Bob', :first_name => 'Robert', :age => 37,
|
7
|
+
:activated_at => 37.hours.ago, :admin => true
|
8
|
+
@slim = User.create :pseudo => 'Slim', :first_name => 'Angelo', :age => 12,
|
9
|
+
:activated_at => nil, :admin => false
|
10
|
+
end
|
11
|
+
|
12
|
+
should "equals scope" do
|
13
|
+
assert_raise NoMethodError do
|
14
|
+
User.blabla_eq('Bob')
|
15
|
+
end
|
16
|
+
assert_equal [@bob], User.pseudo_eq('Bob')
|
17
|
+
assert_equal [@slim], User.pseudo_is('Slim')
|
18
|
+
assert_equal [@bob], User.first_name_is('Robert')
|
19
|
+
end
|
20
|
+
|
21
|
+
should "equals scope on a relation" do
|
22
|
+
assert_equal [@bob], User.order('age').pseudo_eq('Bob')
|
23
|
+
end
|
24
|
+
|
25
|
+
should "not equals scope" do
|
26
|
+
assert_equal [@bob], User.pseudo_is_not('Slim')
|
27
|
+
assert_equal [@bob], User.first_name_does_not_equal('Angelo')
|
28
|
+
end
|
29
|
+
|
30
|
+
should "less than (or equal)? scope" do
|
31
|
+
assert_equal [@slim], User.age_lt(37)
|
32
|
+
assert_equal [@slim], User.age_less_than_or_equal(12)
|
33
|
+
end
|
34
|
+
|
35
|
+
should "greater than (or equal)? scope" do
|
36
|
+
assert_equal [@bob], User.age_greater_than(12)
|
37
|
+
assert_equal [@bob], User.age_gte(37)
|
38
|
+
assert_equal [@bob], User.activated_at_after(40.hours.ago)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "like scope" do
|
42
|
+
assert_equal [@slim], User.first_name_matches('nge')
|
43
|
+
end
|
44
|
+
|
45
|
+
should "not like scope" do
|
46
|
+
assert_equal [@slim], User.pseudo_not_like('o')
|
47
|
+
end
|
48
|
+
|
49
|
+
should "begins / ends with scope" do
|
50
|
+
assert_equal [@bob], User.first_name_starts_with('Rob')
|
51
|
+
assert_equal [@slim], User.first_name_ends_with('o')
|
52
|
+
end
|
53
|
+
|
54
|
+
should "not begins / ends with scope" do
|
55
|
+
assert_equal [@slim], User.first_name_does_not_start_with('Rob')
|
56
|
+
assert_equal [@bob], User.first_name_doesnt_end_with('o')
|
57
|
+
end
|
58
|
+
|
59
|
+
should "(not)? null scope" do
|
60
|
+
assert_equal [@slim], User.activated_at_null
|
61
|
+
assert_equal [@bob], User.activated_at_not_nil
|
62
|
+
end
|
63
|
+
|
64
|
+
should "boolean columns" do
|
65
|
+
assert_equal [@bob], User.admin
|
66
|
+
assert_equal [@slim], User.not_admin
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestOrdering < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "convenient_scopes" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@bob = User.create :age => 43
|
9
|
+
@slim = User.create :age => 27
|
10
|
+
@avon = User.create :age => 37
|
11
|
+
@managers = Group.create :users => [@bob, @avon]
|
12
|
+
@developers = Group.create :users => [@slim]
|
13
|
+
end
|
14
|
+
|
15
|
+
should "allow ordering by attributes" do
|
16
|
+
assert_equal [@slim, @avon, @bob], User.ascend_by_age
|
17
|
+
assert_equal [@bob, @avon, @slim], User.descend_by_age
|
18
|
+
end
|
19
|
+
|
20
|
+
should "allow ordering by attributes of an association" do
|
21
|
+
assert_equal [@developers, @managers], Group.ascend_by_users_age.uniq
|
22
|
+
assert_equal [@managers, @developers], Group.descend_by_users_age.uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: convenient_scopes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ivan Schneider
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-25 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activerecord
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 3
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
- beta4
|
32
|
+
version: 3.0.0.beta4
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: shoulda
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
version: "0"
|
45
|
+
type: :development
|
46
|
+
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3-ruby
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id003
|
59
|
+
description: Dynamic scopes by convention for ActiveRecord 3
|
60
|
+
email: isc@massivebraingames.com
|
61
|
+
executables: []
|
62
|
+
|
63
|
+
extensions: []
|
64
|
+
|
65
|
+
extra_rdoc_files:
|
66
|
+
- LICENSE
|
67
|
+
- README.rdoc
|
68
|
+
files:
|
69
|
+
- .document
|
70
|
+
- .gitignore
|
71
|
+
- LICENSE
|
72
|
+
- README.rdoc
|
73
|
+
- Rakefile
|
74
|
+
- VERSION
|
75
|
+
- convenient_scopes.gemspec
|
76
|
+
- lib/convenient_scopes.rb
|
77
|
+
- test/helper.rb
|
78
|
+
- test/test_associations.rb
|
79
|
+
- test/test_conditions.rb
|
80
|
+
- test/test_ordering.rb
|
81
|
+
has_rdoc: true
|
82
|
+
homepage: http://github.com/isc/convenient_scopes
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options:
|
87
|
+
- --charset=UTF-8
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.6
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Dynamic scopes by convention for ActiveRecord 3
|
111
|
+
test_files:
|
112
|
+
- test/helper.rb
|
113
|
+
- test/test_all_and_any_conditions.rb
|
114
|
+
- test/test_associations.rb
|
115
|
+
- test/test_conditions.rb
|
116
|
+
- test/test_ordering.rb
|