scopes_for_associations 0.1.0 → 0.1.1

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/.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