scopes_for_associations 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.rdoc CHANGED
@@ -16,6 +16,47 @@ Define very basic, commonly used scopes for ActiveRecord associations.
16
16
  Movie.for(Director.first)
17
17
  #=> [#<Movie ..., director_id: 1>]
18
18
 
19
- == Limitations
19
+ == Supported association types
20
20
 
21
- As of now, the gem only defines scopes for non-polymorphic belongs_to associations.
21
+ * belongs_to (non-polymorpic and polymorphic)
22
+
23
+ If you're like me and prefer learning through looking at code,
24
+ read through the specs.
25
+ The examples here are basically reproductions of the tests.
26
+
27
+ === belongs_to (non-polymorphic)
28
+
29
+ class Movie < ActiveRecord::Base
30
+ belongs_to :director
31
+ scopes_for_associations
32
+ end
33
+
34
+ Movie.for_director(Director.first)
35
+ #=> [#<Movie ..., director_id: 1>]
36
+ Movie.for(Director.first)
37
+ #=> [#<Movie ..., director_id: 1>]
38
+
39
+ === belongs_to (polymorphic)
40
+
41
+ class Movie < ActiveRecord::base
42
+ # It is important to define this association.
43
+ has_many :comments, :as => :commentable
44
+ end
45
+ class Comment < ActiveRecord::Base
46
+ belongs_to :commentable, :polymorphic => true
47
+ end
48
+
49
+ Commentable.for_movie(Movie.first)
50
+ #=> [#<Comment ..., commentable_type: "Movie", commentable_id: 1>]
51
+ Commentable.for(Movie.first)
52
+ #=> [#<Comment ..., commentable_type: "Movie", commentable_id: 1>]
53
+
54
+ == Installation
55
+
56
+ gem install scopes_for_associations
57
+
58
+ == Compatibility
59
+
60
+ works with ActiveRecord >=3.0.0
61
+
62
+ gem-testers: http://gem-testers.org/gems/scopes_for_associations
@@ -1,3 +1,3 @@
1
1
  module ScopesForAssociations
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,22 +1,57 @@
1
1
  module ScopesForAssociations
2
2
 
3
3
  def scopes_for_associations()
4
- # scopes for belongs_to associations.
5
- belongs_to_reflections = reflect_on_all_associations(:belongs_to)
6
- non_polymorphic_belongs_to_reflections = belongs_to_reflections.reject { |reflection| reflection.options[:polymorphic] }
4
+ define_scopes_for_non_polymorpic_belongs_to_associations
5
+ define_scopes_for_polymorpic_belongs_to_associations
6
+ define_named_scope_for
7
+ end
8
+
9
+ private
10
+
11
+ def non_polymorphic_belongs_to_reflections
12
+ reflect_on_all_associations(:belongs_to).reject { |reflection| reflection.options[:polymorphic] }
13
+ end
14
+
15
+ def polymorphic_belongs_to_reflections
16
+ reflect_on_all_associations(:belongs_to).select { |reflection| reflection.options[:polymorphic] }
17
+ end
18
+
19
+ def define_scopes_for_non_polymorpic_belongs_to_associations
7
20
  non_polymorphic_belongs_to_reflections.each do |reflection|
8
21
  name = reflection.name
9
- scope :"for_#{name}", proc { |obj| where(:"#{name}_id" => obj) }
22
+ scope :"for_#{name}", proc { |obj| where(:"#{name}_id" => obj.id) }
10
23
  end
11
- # scopes for has_many associations.
12
- #has_many_reflections = reflect_on_all_associations(:has_many)
13
- #non_through_has_many_reflections = has_many_reflections.reject { |reflection| reflection.options[:through] }
14
- #non_through_has_many_reflections.each do |reflection|
15
- #name = reflection.name
16
- #scope :"for_#{name}", proc { |obj| joins(name).where(name => {:"#{self.class.table_name.singularize}_id" => obj.id}) }
17
- #end
18
- # for scope.
19
- scope :for, proc { |obj| send("for_#{obj.class.name.underscore}", obj) }
24
+ end
25
+
26
+ def define_scopes_for_polymorpic_belongs_to_associations
27
+ polymorphic_belongs_to_reflections.each do |reflection|
28
+ name = reflection.name
29
+ scope :"for_#{name}", proc { |obj| where(:"#{name}_type" => obj.class.name, :"#{name}_id" => obj.id) }
30
+ end
31
+ end
32
+
33
+ # return [name, reflection] from matching reflection.klass and obj.class
34
+ def reflection_for_object(obj)
35
+ reflections.detect { |name, reflection| reflection.class_name == obj.class.name }
36
+ end
37
+
38
+ def define_named_scope_for
39
+ scope :for, proc { |object|
40
+ name, reflection = reflection_for_object(object)
41
+ if name
42
+ send(:"for_#{name}", object)
43
+ else
44
+ # see if it's polymorphic from object's associations.
45
+ reflection = object.class.reflect_on_all_associations(:has_many).detect { |reflection|
46
+ reflection.options[:as] && reflection.klass == self
47
+ }
48
+ if reflection
49
+ send(:"for_#{reflection.options[:as]}", object)
50
+ else
51
+ raise "no scope for #{object.class}"
52
+ end
53
+ end
54
+ }
20
55
  end
21
56
 
22
57
  end
@@ -19,7 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split($/).map{ |f| File.basename(f) }
20
20
  s.require_paths = ['lib']
21
21
 
22
+ s.add_dependency 'activerecord', '>= 3.0.0'
23
+
24
+ s.add_development_dependency 'awesome_print'
22
25
  s.add_development_dependency 'rspec', '2.5.0'
23
- s.add_development_dependency 'activerecord', '>= 3.0.0'
24
26
  s.add_development_dependency 'sqlite3-ruby', '1.2.5'
25
27
  end
@@ -4,24 +4,55 @@ describe ScopesForAssociations do
4
4
 
5
5
  let(:director) { Director.create! }
6
6
  let(:production_company) { ProductionCompany.create! }
7
+ let(:movie) { Movie.create!(:director => director, :production_company => production_company) }
8
+ let(:comment) { Comment.create! :commentable_type => 'Movie', :commentable_id => movie.id }
7
9
 
8
10
  it 'should be included in ActiveRecord::Base' do
9
11
  ActiveRecord::Base.should respond_to('scopes_for_associations')
10
12
  end
11
13
 
12
- it 'should define for_x scopes' do
13
- Movie.should respond_to('for_director')
14
- Movie.should respond_to('for_production_company')
15
- end
14
+ context 'for non-polymorphic belongs_to associations' do
15
+
16
+ it 'should define for_x scopes' do
17
+ Movie.should respond_to('for_director')
18
+ Movie.should respond_to('for_production_company')
19
+ end
20
+
21
+ it 'should scope for association as object' do
22
+ Movie.for_director(director).to_sql.should eq(Movie.where(:director_id => director.id).to_sql)
23
+ Movie.for_director(director).should eq([movie])
24
+ Movie.for_production_company(production_company).to_sql.should eq(Movie.where(:production_company_id => production_company.id).to_sql)
25
+ Movie.for_production_company(director).should eq([movie])
26
+ end
27
+
28
+ it 'should have a "polymorphic" scope :for' do
29
+ Movie.for(director).to_sql.should eq(Movie.for_director(director).to_sql)
30
+ Movie.for(director).should eq([movie])
31
+ Movie.for(production_company).to_sql.should eq(Movie.for_production_company(production_company).to_sql)
32
+ Movie.for(production_company).should eq([movie])
33
+ end
16
34
 
17
- it 'should scope for association as object' do
18
- Movie.for_director(director).to_sql.should eq(Movie.where(:director_id => director.id).to_sql)
19
- Movie.for_production_company(production_company).to_sql.should eq(Movie.where(:production_company_id => production_company.id).to_sql)
20
35
  end
21
36
 
22
- it 'should have a "polymorphic" scope :for' do
23
- Movie.for(director).to_sql.should eq(Movie.for_director(director).to_sql)
24
- Movie.for(production_company).to_sql.should eq(Movie.for_production_company(production_company).to_sql)
37
+ context 'for polymorphic belongs_to associations' do
38
+
39
+ it 'should define for_x scopes' do
40
+ Comment.should respond_to('for_commentable')
41
+ end
42
+
43
+ it 'should scope for association as object' do
44
+ Comment.for_commentable(movie)
45
+ end
46
+
47
+ it 'should scope for association as object' do
48
+ Comment.for_commentable(movie).to_sql.should eq(Comment.where(:commentable_type => 'Movie', :commentable_id => movie.id).to_sql)
49
+ Comment.for_commentable(movie).should eq([comment])
50
+ end
51
+
52
+ it 'should have a "polymorphic" scope :for' do
53
+ Comment.for(movie).to_sql.should eq(Comment.for_commentable(movie).to_sql)
54
+ end
55
+
25
56
  end
26
57
 
27
58
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  require 'pathname'
2
2
  require 'active_record'
3
+ require 'awesome_print'
3
4
 
4
5
  require File.join(Pathname(__FILE__).dirname.expand_path, '../lib/scopes_for_associations')
5
6
 
6
7
  # require support .rb files.
7
8
  Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
8
-
9
- #RSpec.configure do |config|
10
- #config.include(Macros)
11
- #end
@@ -1,11 +1,9 @@
1
1
  class Movie < ActiveRecord::Base
2
-
3
2
  belongs_to :director
4
3
  belongs_to :production_company
5
4
  has_one :trailer
6
-
5
+ has_many :comments, :as => 'commentable'
7
6
  scopes_for_associations
8
-
9
7
  end
10
8
 
11
9
  class Director < ActiveRecord::Base
@@ -20,3 +18,8 @@ class Trailer < ActiveRecord::Base
20
18
  belongs_to :production_company
21
19
  scopes_for_associations
22
20
  end
21
+
22
+ class Comment < ActiveRecord::Base
23
+ belongs_to :commentable, :polymorphic => true
24
+ scopes_for_associations
25
+ end
@@ -13,4 +13,7 @@ ActiveRecord::Schema.define do
13
13
  t.belongs_to :director
14
14
  t.belongs_to :production_company
15
15
  end
16
+ create_table :comments, :force => true do |t|
17
+ t.belongs_to :commentable, :polymorphic => true
18
+ end
16
19
  end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scopes_for_associations
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 0
10
- version: 0.1.0
5
+ version: 0.1.1
11
6
  platform: ruby
12
7
  authors:
13
8
  - Jared Ning
@@ -19,53 +14,49 @@ date: 2011-02-08 00:00:00 -06:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
22
- name: rspec
17
+ name: activerecord
23
18
  prerelease: false
24
19
  requirement: &id001 !ruby/object:Gem::Requirement
25
20
  none: false
26
21
  requirements:
27
- - - "="
22
+ - - ">="
28
23
  - !ruby/object:Gem::Version
29
- hash: 27
30
- segments:
31
- - 2
32
- - 5
33
- - 0
34
- version: 2.5.0
35
- type: :development
24
+ version: 3.0.0
25
+ type: :runtime
36
26
  version_requirements: *id001
37
27
  - !ruby/object:Gem::Dependency
38
- name: activerecord
28
+ name: awesome_print
39
29
  prerelease: false
40
30
  requirement: &id002 !ruby/object:Gem::Requirement
41
31
  none: false
42
32
  requirements:
43
33
  - - ">="
44
34
  - !ruby/object:Gem::Version
45
- hash: 7
46
- segments:
47
- - 3
48
- - 0
49
- - 0
50
- version: 3.0.0
35
+ version: "0"
51
36
  type: :development
52
37
  version_requirements: *id002
53
38
  - !ruby/object:Gem::Dependency
54
- name: sqlite3-ruby
39
+ name: rspec
55
40
  prerelease: false
56
41
  requirement: &id003 !ruby/object:Gem::Requirement
57
42
  none: false
58
43
  requirements:
59
44
  - - "="
60
45
  - !ruby/object:Gem::Version
61
- hash: 21
62
- segments:
63
- - 1
64
- - 2
65
- - 5
66
- version: 1.2.5
46
+ version: 2.5.0
67
47
  type: :development
68
48
  version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: sqlite3-ruby
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - "="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.2.5
58
+ type: :development
59
+ version_requirements: *id004
69
60
  description: Define very basic, commonly used scopes for ActiveRecord associations. E.g. if a Post model has an author and a category association, scopes will be defined like Post.for(author) or Post.for(category).
70
61
  email:
71
62
  - jared@redningja.com
@@ -78,6 +69,7 @@ extra_rdoc_files: []
78
69
  files:
79
70
  - .gemtest
80
71
  - .gitignore
72
+ - .rspec
81
73
  - .rvmrc
82
74
  - Gemfile
83
75
  - README.rdoc
@@ -103,18 +95,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
95
  requirements:
104
96
  - - ">="
105
97
  - !ruby/object:Gem::Version
106
- hash: 3
107
- segments:
108
- - 0
109
98
  version: "0"
110
99
  required_rubygems_version: !ruby/object:Gem::Requirement
111
100
  none: false
112
101
  requirements:
113
102
  - - ">="
114
103
  - !ruby/object:Gem::Version
115
- hash: 3
116
- segments:
117
- - 0
118
104
  version: "0"
119
105
  requirements: []
120
106