jferris-sconnect 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +45 -0
- data/Rakefile +62 -0
- data/lib/sconnect.rb +15 -0
- data/lib/sconnect/not.rb +55 -0
- data/lib/sconnect/or.rb +67 -0
- data/spec/not_spec.rb +66 -0
- data/spec/or_spec.rb +109 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/active_record_extensions.rb +18 -0
- data/spec/support/model_builder.rb +67 -0
- data/spec/support/scope_matcher.rb +8 -0
- data/spec/support/scope_options_matcher.rb +38 -0
- metadata +68 -0
data/README.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= Sconnect
|
2
|
+
|
3
|
+
Sconnect is an extension to ActiveRecord's named_scopes that allows you to combine scopes in more interesting and useful ways.
|
4
|
+
|
5
|
+
== Download
|
6
|
+
|
7
|
+
Github: http://github.com/jferris/sconnect/tree/master
|
8
|
+
|
9
|
+
== Examples
|
10
|
+
|
11
|
+
Given the following model:
|
12
|
+
|
13
|
+
class Post < ActiveRecord::Base
|
14
|
+
named_scope :published, :conditions => { :published => true }
|
15
|
+
named_scope :titled, :conditions => "title IS NOT NULL"
|
16
|
+
named_scope :from_today, lambda {
|
17
|
+
{ :conditions => ['created_at >= ?', 1.day.ago] }
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveRecord provides scope chains:
|
22
|
+
|
23
|
+
# All published posts with titles
|
24
|
+
Post.published.titled
|
25
|
+
|
26
|
+
# All published posts from today
|
27
|
+
Post.published.from_today
|
28
|
+
|
29
|
+
Sconnect extends these scopes:
|
30
|
+
|
31
|
+
# All posts that are either published or titled
|
32
|
+
Post.published.or.titled
|
33
|
+
|
34
|
+
# All posts that are published but not created today
|
35
|
+
Post.published.not.from_today
|
36
|
+
|
37
|
+
# All posts that are either published or untitled
|
38
|
+
Post.published.or.not.titled
|
39
|
+
|
40
|
+
# All posts from today that are either published or titled
|
41
|
+
Post.published.or.titled.from_today
|
42
|
+
|
43
|
+
== Author
|
44
|
+
|
45
|
+
Sconnect was written by Joe Ferris.
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rcov'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
Spec::Rake::SpecTask.new do |t|
|
8
|
+
t.libs << 'spec'
|
9
|
+
t.spec_opts << '-O spec/spec.opts'
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Generate documentation'
|
13
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = 'Sconnect'
|
16
|
+
rdoc.options <<
|
17
|
+
'--line-numbers' <<
|
18
|
+
'--inline-source' <<
|
19
|
+
"--main" <<
|
20
|
+
"README.rdoc"
|
21
|
+
rdoc.rdoc_files.include('README.rdoc')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :spec
|
26
|
+
|
27
|
+
spec = Gem::Specification.new do |s|
|
28
|
+
s.name = %q{sconnect}
|
29
|
+
s.version = "0.1"
|
30
|
+
s.summary = %q{Sconnect extends ActiveRecord's named scoped_chains to be
|
31
|
+
more useful an interesting.}
|
32
|
+
s.description = %q{Sconnect extends ActiveRecord's named_scope chains to allow
|
33
|
+
scopes to be combined inclusively, inverted, and more.}
|
34
|
+
|
35
|
+
s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'spec/**/*.rb']
|
36
|
+
s.require_path = 'lib'
|
37
|
+
s.test_files = Dir[*['spec/**/*_spec.rb']]
|
38
|
+
|
39
|
+
s.has_rdoc = true
|
40
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
41
|
+
s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.rdoc"]
|
42
|
+
|
43
|
+
s.authors = ["Joe Ferris"]
|
44
|
+
s.email = %q{jferris@thoughtbot.com}
|
45
|
+
|
46
|
+
s.platform = Gem::Platform::RUBY
|
47
|
+
end
|
48
|
+
|
49
|
+
Rake::GemPackageTask.new spec do |pkg|
|
50
|
+
pkg.need_tar = true
|
51
|
+
pkg.need_zip = true
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Clean files generated by rake tasks"
|
55
|
+
task :clobber => [:clobber_rdoc, :clobber_package]
|
56
|
+
|
57
|
+
desc "Generate a gemspec file"
|
58
|
+
task :gemspec do
|
59
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
60
|
+
f.write spec.to_ruby
|
61
|
+
end
|
62
|
+
end
|
data/lib/sconnect.rb
ADDED
data/lib/sconnect/not.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Sconnect #:nodoc:
|
2
|
+
class NotScope < ActiveRecord::NamedScope::Scope #:nodoc:
|
3
|
+
|
4
|
+
delegate :current_scoped_methods, :sanitize_sql, :to => :proxy_scope
|
5
|
+
|
6
|
+
def initialize(proxy_scope)
|
7
|
+
@proxy_scope = proxy_scope
|
8
|
+
end
|
9
|
+
|
10
|
+
def proxy_options
|
11
|
+
@proxy_options ||= invert_scope_conditions(@right_scope)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def invert_scope_conditions(scope)
|
17
|
+
scope = scope.merge(:conditions => invert_conditions(scope[:conditions]))
|
18
|
+
end
|
19
|
+
|
20
|
+
def invert_conditions(conditions)
|
21
|
+
"NOT (#{sanitize_sql(conditions)})"
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method, *args, &block)
|
25
|
+
if scopes.include?(method)
|
26
|
+
right_scope = scopes[method].call(self, *args)
|
27
|
+
if @right_scope
|
28
|
+
right_scope
|
29
|
+
else
|
30
|
+
@right_scope = right_scope.proxy_options
|
31
|
+
self
|
32
|
+
end
|
33
|
+
else
|
34
|
+
super(method, *args, &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module ActiveRecordClassExtensions
|
40
|
+
# Inverts the conditions of the following scope.
|
41
|
+
#
|
42
|
+
# Examples:
|
43
|
+
# # Returns all unpublished posts
|
44
|
+
# Post.not.published
|
45
|
+
#
|
46
|
+
# # Returns all unpublished posts from today
|
47
|
+
# Post.not.published.from_today
|
48
|
+
#
|
49
|
+
# # Same as above
|
50
|
+
# Post.from_today.not.published
|
51
|
+
def not
|
52
|
+
NotScope.new(self)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/sconnect/or.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Sconnect #:nodoc:
|
2
|
+
class OrScope < ActiveRecord::NamedScope::Scope #:nodoc:
|
3
|
+
|
4
|
+
delegate :current_scoped_methods, :sanitize_sql, :to => :proxy_scope
|
5
|
+
|
6
|
+
def initialize(left_scope)
|
7
|
+
@left_scope = left_scope.proxy_options
|
8
|
+
@proxy_scope = left_scope.proxy_scope
|
9
|
+
end
|
10
|
+
|
11
|
+
def proxy_options
|
12
|
+
@proxy_options ||= inclusively_combine_scopes(@left_scope, @right_scope)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def inclusively_combine_scopes(left, right)
|
18
|
+
exclusively_combine_scopes(left, right).
|
19
|
+
merge(:conditions => combine_conditions(left, right))
|
20
|
+
end
|
21
|
+
|
22
|
+
def exclusively_combine_scopes(left, right)
|
23
|
+
with_scope(:find => left) do
|
24
|
+
with_scope(:find => right) do
|
25
|
+
current_scoped_methods[:find]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def combine_conditions(*scopes)
|
31
|
+
segments = scopes.collect do |scope|
|
32
|
+
sanitize_sql(scope[:conditions])
|
33
|
+
end
|
34
|
+
conditions = "(#{segments.join(') OR (')})"
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(method, *args, &block)
|
38
|
+
if scopes.include?(method)
|
39
|
+
right_scope = scopes[method].call(self, *args)
|
40
|
+
if @right_scope
|
41
|
+
right_scope
|
42
|
+
else
|
43
|
+
@right_scope = right_scope.proxy_options
|
44
|
+
self
|
45
|
+
end
|
46
|
+
else
|
47
|
+
super(method, *args, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module ScopeExtensions
|
53
|
+
# Joins the left and right-hand scopes into an inclusive conditional clause.
|
54
|
+
#
|
55
|
+
# Examples:
|
56
|
+
#
|
57
|
+
# # Posts published or owned by the user
|
58
|
+
# Post.published.or.owned_by(@user)
|
59
|
+
#
|
60
|
+
# # Posts from today that are either published or owned by the given user
|
61
|
+
# # (note that "or" binds tighter than the implicit "and")
|
62
|
+
# Post.from_today.published.or.owned_by(@user)
|
63
|
+
def or
|
64
|
+
OrScope.new(self)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/not_spec.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Post" do
|
4
|
+
|
5
|
+
include ModelBuilder
|
6
|
+
|
7
|
+
before do
|
8
|
+
define_model :user
|
9
|
+
define_model :category
|
10
|
+
define_model :post, :published => :boolean,
|
11
|
+
:title => :string,
|
12
|
+
:user_id => :integer,
|
13
|
+
:category_id => :integer do
|
14
|
+
belongs_to :user
|
15
|
+
belongs_to :category
|
16
|
+
named_scope :published, :conditions => { :published => true },
|
17
|
+
:include => :user
|
18
|
+
named_scope :titled, :conditions => "title IS NOT NULL",
|
19
|
+
:include => :category
|
20
|
+
named_scope :from_today, lambda {
|
21
|
+
{ :conditions => ['created_at >= ?', 1.day.ago] }
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "titled but not published", :shared => true do
|
27
|
+
it "should find an unpublished, titled post" do
|
28
|
+
should include(Post.create!(:published => false, :title => 'Title'))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not find an unpublished, titled post" do
|
32
|
+
should_not include(Post.create!(:published => true, :title => 'Title'))
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not find an published, untitled post" do
|
36
|
+
should_not include(Post.create!(:published => true, :title => nil))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ".not.published" do
|
41
|
+
subject { Post.not.published }
|
42
|
+
|
43
|
+
it "should find an unpublished post" do
|
44
|
+
should include(Post.create!(:published => false))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not find an unpublished post" do
|
48
|
+
should_not include(Post.create!(:published => true))
|
49
|
+
end
|
50
|
+
|
51
|
+
it { should be_chainable }
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".not.published.titled" do
|
55
|
+
subject { Post.not.published }
|
56
|
+
it_should_behave_like "titled but not published"
|
57
|
+
it { should be_chainable }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe ".titled.not.published" do
|
61
|
+
subject { Post.not.published }
|
62
|
+
it_should_behave_like "titled but not published"
|
63
|
+
it { should be_chainable }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/spec/or_spec.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Post" do
|
4
|
+
|
5
|
+
include ModelBuilder
|
6
|
+
|
7
|
+
before do
|
8
|
+
define_model :user
|
9
|
+
define_model :category
|
10
|
+
define_model :post, :published => :boolean,
|
11
|
+
:title => :string,
|
12
|
+
:user_id => :integer,
|
13
|
+
:category_id => :integer do
|
14
|
+
belongs_to :user
|
15
|
+
belongs_to :category
|
16
|
+
named_scope :published, :conditions => { :published => true },
|
17
|
+
:include => :user
|
18
|
+
named_scope :titled, :conditions => "title IS NOT NULL",
|
19
|
+
:include => :category
|
20
|
+
named_scope :from_today, lambda {
|
21
|
+
{ :conditions => ['created_at >= ?', 1.day.ago] }
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "published.or.titled", :shared => true do
|
27
|
+
it "should find a published, untitled post" do
|
28
|
+
should include(Post.create!(:published => true, :title => nil))
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should find an unpublished, titled post" do
|
32
|
+
should include(Post.create!(:published => false, :title => 'Title'))
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should find a published, titled post" do
|
36
|
+
should include(Post.create!(:published => true, :title => 'Title'))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "not should find an unpublished, untitled post" do
|
40
|
+
should_not include(Post.create!(:published => false, :title => nil))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should use non-conditional options from .published.titled" do
|
44
|
+
should include_scope_options_from(Post.published.titled)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "from_today", :shared => true do
|
49
|
+
it "not find a post published two days ago" do
|
50
|
+
should_not include(Post.create!(:published => true,
|
51
|
+
:title => 'Title',
|
52
|
+
:created_at => 2.days.ago))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".published.or.titled" do
|
57
|
+
subject { Post.published.or.titled }
|
58
|
+
it_should_behave_like "published.or.titled"
|
59
|
+
it { should be_chainable }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe ".from_today.published.or.titled" do
|
63
|
+
subject { Post.from_today.published.or.titled }
|
64
|
+
|
65
|
+
it_should_behave_like "published.or.titled"
|
66
|
+
it_should_behave_like "from_today"
|
67
|
+
it { should be_chainable }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe ".published.or.titled.from_today" do
|
71
|
+
subject { Post.published.or.titled.from_today }
|
72
|
+
|
73
|
+
it_should_behave_like "published.or.titled"
|
74
|
+
it_should_behave_like "from_today"
|
75
|
+
it { should be_chainable }
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ".published.or.titled.or.from_today" do
|
79
|
+
subject { Post.published.or.titled.or.from_today }
|
80
|
+
|
81
|
+
it "should find a published, untitled post from today" do
|
82
|
+
should include(Post.create!(:published => true, :title => nil))
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should find an unpublished, titled post from today" do
|
86
|
+
should include(Post.create!(:published => false, :title => 'Title'))
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should find a published, titled post from today" do
|
90
|
+
should include(Post.create!(:published => true, :title => 'Title'))
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should find an unpublished, untitled post from today" do
|
94
|
+
should include(Post.create!(:published => false, :title => nil))
|
95
|
+
end
|
96
|
+
|
97
|
+
it "not should find an unpublished, untitled post from two days ago" do
|
98
|
+
should_not include(Post.create!(:published => false,
|
99
|
+
:title => nil,
|
100
|
+
:created_at => 2.days.ago))
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should use non-conditional options from .published.titled" do
|
104
|
+
should include_scope_options_from(Post.published.titled)
|
105
|
+
end
|
106
|
+
|
107
|
+
it { should be_chainable }
|
108
|
+
end
|
109
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
SCONNECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
6
|
+
|
7
|
+
Dir["#{SCONNECT_ROOT}/spec/support/**/*.rb"].each {|file| require(file) }
|
8
|
+
$: << "#{SCONNECT_ROOT}/lib"
|
9
|
+
|
10
|
+
ActiveRecord::Base.establish_connection(
|
11
|
+
:adapter => 'sqlite3',
|
12
|
+
:database => "#{SCONNECT_ROOT}/spec/database.sqlite3"
|
13
|
+
)
|
14
|
+
|
15
|
+
ActiveRecord::Base.logger = Logger.new("#{SCONNECT_ROOT}/spec/spec.log")
|
16
|
+
|
17
|
+
Spec::Runner.configure do |config|
|
18
|
+
config.include Matchers
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'sconnect'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
# This allows us to look at the options at the end of a chain of scopes.
|
4
|
+
def self.scope_options
|
5
|
+
current_scoped_methods[:find]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module NamedScope
|
10
|
+
class Scope
|
11
|
+
# This allows Scope objects to be used as matchers. Without this hack, a
|
12
|
+
# Scope will be converted to an array when #should is called, so the
|
13
|
+
# matcher will always receive an array. This prevents #should from being
|
14
|
+
# delegated to the Scope's proxy.
|
15
|
+
remove_method :should
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ModelBuilder
|
2
|
+
def self.included(example_group)
|
3
|
+
example_group.class_eval do
|
4
|
+
before do
|
5
|
+
@defined_constants = []
|
6
|
+
@created_tables = []
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
@defined_constants.each do |class_name|
|
11
|
+
Object.send(:remove_const, class_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
@created_tables.each do |table_name|
|
15
|
+
ActiveRecord::Base.
|
16
|
+
connection.
|
17
|
+
execute("DROP TABLE IF EXISTS #{table_name}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_table(table_name, &block)
|
24
|
+
connection = ActiveRecord::Base.connection
|
25
|
+
|
26
|
+
begin
|
27
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
28
|
+
connection.create_table(table_name, &block)
|
29
|
+
@created_tables << table_name
|
30
|
+
connection
|
31
|
+
rescue Exception => exception
|
32
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
33
|
+
raise exception
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_constant(class_name, base, &block)
|
38
|
+
class_name = class_name.to_s.camelize
|
39
|
+
|
40
|
+
klass = Class.new(base)
|
41
|
+
Object.const_set(class_name, klass)
|
42
|
+
|
43
|
+
klass.class_eval(&block) if block_given?
|
44
|
+
|
45
|
+
@defined_constants << class_name
|
46
|
+
|
47
|
+
klass
|
48
|
+
end
|
49
|
+
|
50
|
+
def define_model_class(class_name, &block)
|
51
|
+
define_constant(class_name, ActiveRecord::Base, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def define_model(name, columns = {}, &block)
|
55
|
+
class_name = name.to_s.pluralize.classify
|
56
|
+
table_name = class_name.tableize
|
57
|
+
|
58
|
+
create_table(table_name) do |table|
|
59
|
+
columns.each do |name, type|
|
60
|
+
table.column name, type
|
61
|
+
end
|
62
|
+
table.timestamps
|
63
|
+
end
|
64
|
+
|
65
|
+
define_model_class(class_name, &block)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Matchers
|
2
|
+
|
3
|
+
class ScopeOptionsMatcher
|
4
|
+
def initialize(expected)
|
5
|
+
@expected_scope_options = scope_options(expected)
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches?(target)
|
9
|
+
target_scope_options = scope_options(target)
|
10
|
+
@expected_scope_options.detect do |@key, expected_values|
|
11
|
+
expected_values = [expected_values] unless expected_values.is_a?(Array)
|
12
|
+
@target_values = target_scope_options[@key]
|
13
|
+
@target_values = [@target_values] unless @target_values.is_a?(Array)
|
14
|
+
@missing =
|
15
|
+
expected_values.detect {|value| !@target_values.include?(value) }
|
16
|
+
end
|
17
|
+
|
18
|
+
@missing.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
def failure_message
|
22
|
+
"Missing value #{@missing.inspect} for #{@key.inspect}" <<
|
23
|
+
" (found values: #{@target_values.inspect})"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def scope_options(scope)
|
29
|
+
scope_options = scope.scope_options
|
30
|
+
scope_options.delete(:conditions)
|
31
|
+
scope_options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def include_scope_options_from(scope)
|
36
|
+
ScopeOptionsMatcher.new(scope)
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jferris-sconnect
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joe Ferris
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-21 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Sconnect extends ActiveRecord's named_scope chains to allow scopes to be combined inclusively, inverted, and more.
|
17
|
+
email: jferris@thoughtbot.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- README.rdoc
|
27
|
+
- lib/sconnect/not.rb
|
28
|
+
- lib/sconnect/or.rb
|
29
|
+
- lib/sconnect.rb
|
30
|
+
- spec/not_spec.rb
|
31
|
+
- spec/or_spec.rb
|
32
|
+
- spec/spec_helper.rb
|
33
|
+
- spec/support/active_record_extensions.rb
|
34
|
+
- spec/support/model_builder.rb
|
35
|
+
- spec/support/scope_matcher.rb
|
36
|
+
- spec/support/scope_options_matcher.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage:
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --line-numbers
|
42
|
+
- --inline-source
|
43
|
+
- --main
|
44
|
+
- README.rdoc
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Sconnect extends ActiveRecord's named scoped_chains to be more useful an interesting.
|
66
|
+
test_files:
|
67
|
+
- spec/not_spec.rb
|
68
|
+
- spec/or_spec.rb
|