grouped_scope 0.6.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/.travis.yml +5 -0
  2. data/CHANGELOG +13 -0
  3. data/Gemfile +4 -6
  4. data/README.md +173 -0
  5. data/lib/grouped_scope.rb +7 -7
  6. data/lib/grouped_scope/arish/associations/association_scope.rb +90 -0
  7. data/lib/grouped_scope/arish/associations/builder/grouped_association.rb +50 -0
  8. data/lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb +32 -0
  9. data/lib/grouped_scope/arish/associations/collection_association.rb +25 -0
  10. data/lib/grouped_scope/arish/base.rb +24 -0
  11. data/lib/grouped_scope/arish/reflection.rb +18 -0
  12. data/lib/grouped_scope/arish/relation/predicate_builer.rb +27 -0
  13. data/lib/grouped_scope/errors.rb +2 -3
  14. data/lib/grouped_scope/self_grouping.rb +59 -23
  15. data/lib/grouped_scope/version.rb +2 -4
  16. data/test/cases/has_many_test.rb +155 -0
  17. data/test/cases/has_many_through_test.rb +51 -0
  18. data/test/cases/reflection_test.rb +62 -0
  19. data/test/cases/self_grouping_test.rb +201 -0
  20. data/test/helper.rb +48 -35
  21. metadata +27 -30
  22. data/README.rdoc +0 -98
  23. data/lib/grouped_scope/association_reflection.rb +0 -54
  24. data/lib/grouped_scope/class_methods.rb +0 -32
  25. data/lib/grouped_scope/core_ext.rb +0 -29
  26. data/lib/grouped_scope/grouping.rb +0 -9
  27. data/lib/grouped_scope/has_many_association.rb +0 -28
  28. data/lib/grouped_scope/has_many_through_association.rb +0 -28
  29. data/lib/grouped_scope/instance_methods.rb +0 -10
  30. data/test/grouped_scope/association_reflection_test.rb +0 -73
  31. data/test/grouped_scope/class_methods_test.rb +0 -51
  32. data/test/grouped_scope/has_many_association_test.rb +0 -156
  33. data/test/grouped_scope/has_many_through_association_test.rb +0 -51
  34. data/test/grouped_scope/self_grouping_test.rb +0 -146
@@ -0,0 +1,201 @@
1
+ require 'helper'
2
+
3
+ class GroupedScope::SelfGrouppingTest < GroupedScope::TestCase
4
+
5
+ describe 'General behavior' do
6
+
7
+ before do
8
+ @employee = FactoryGirl.create(:employee)
9
+ end
10
+
11
+ it 'return #ids array' do
12
+ assert_equal [@employee.id], @employee.group.ids
13
+ e1 = FactoryGirl.create :employee, :group_id => 3
14
+ e2 = FactoryGirl.create :employee, :group_id => 3
15
+ assert_same_elements [e1.id, e2.id], e1.group.ids
16
+ end
17
+
18
+ it 'return #quoted_ids string for use in sql statments' do
19
+ assert_equal "#{@employee.id}", @employee.group.quoted_ids
20
+ end
21
+
22
+ it 'respond true to grouped associations' do
23
+ assert @employee.group.respond_to?(:reports)
24
+ end
25
+
26
+ it 'raise a GroupedScope::NoGroupIdError exception for objects with no group_id schema' do
27
+ FooBar.column_names.wont_include 'group_id'
28
+ lambda{ GroupedScope::SelfGroupping.new(FooBar.new) }.must_raise(GroupedScope::NoGroupIdError)
29
+ end
30
+
31
+ it 'return correct predicate for GroupedScope::SelfGroupping object' do
32
+ @employee.update_attribute :group_id, 82
33
+ expected_sql = /"group_id" IN \(SELECT "employees"\."id" FROM "employees" WHERE "employees"\."group_id" = 82/
34
+ assert_sql(expected_sql) { Employee.where(:group_id => @employee.group).all }
35
+ assert_sql(expected_sql) { Employee.all(:conditions => {:group_id => @employee.group}) }
36
+ assert_equal [@employee], Employee.where(:group_id => @employee.group).all
37
+ end
38
+
39
+ it 'allows you to ask if the group is present' do
40
+ @employee.update_attribute :group_id, 28
41
+ assert_no_queries do
42
+ assert @employee.group_id.present?
43
+ assert @employee.group.present?
44
+ end
45
+ end
46
+
47
+ it 'allows you to ask if the group is blank' do
48
+ assert_no_queries do
49
+ assert @employee.group_id.blank?
50
+ assert @employee.group.blank?
51
+ end
52
+ end
53
+
54
+ describe 'for #with_reflection' do
55
+
56
+ before { @reflection = Employee.reflections[:reports] }
57
+
58
+ it 'will set a reflection and always set it back to nil' do
59
+ assert_nil @employee.group.reflection
60
+ @employee.group.with_reflection(@reflection) do
61
+ assert_equal @reflection, @employee.group.reflection
62
+ end
63
+ assert_nil @employee.group.reflection
64
+ end
65
+
66
+ it 'will use the primary key of the reflection' do
67
+ pk = 'association_primary_key'
68
+ @reflection.stubs :association_primary_key => pk
69
+ @employee.group.with_reflection(@reflection) do
70
+ assert_equal pk, @employee.group.send(:primary_key)
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ describe 'for Array delegates' do
77
+
78
+ it 'respond to first/last' do
79
+ [:first,:last].each do |method|
80
+ assert @employee.group.respond_to?(method), "Should respond to #{method.inspect}"
81
+ end
82
+ end
83
+
84
+ it 'respond to each' do
85
+ assert @employee.group.respond_to?(:each)
86
+ @employee.group.each do |employee|
87
+ assert_instance_of Employee, employee
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ describe 'Calling #group' do
96
+
97
+ it 'returns a active record relation' do
98
+ assert_instance_of ActiveRecord::Relation, FactoryGirl.create(:employee).group
99
+ end
100
+
101
+ describe 'with a NIL group_id' do
102
+
103
+ before do
104
+ @employee = FactoryGirl.create(:employee)
105
+ end
106
+
107
+ it 'return a collection of one' do
108
+ assert_equal 1, @employee.group.size
109
+ end
110
+
111
+ it 'include self in group' do
112
+ assert @employee.group.include?(@employee)
113
+ end
114
+
115
+ it 'returns a sql literal for #ids_sql scoped to single record' do
116
+ @employee.group.ids_sql.must_be_instance_of Arel::Nodes::SqlLiteral
117
+ @employee.group.ids_sql.must_match %r{SELECT \"employees\".\"id\" FROM \"employees\" WHERE \"employees\".\"id\" = #{@employee.id}}
118
+ end
119
+
120
+ end
121
+
122
+ describe 'with a set group_id' do
123
+
124
+ before do
125
+ @employee = FactoryGirl.create(:employee, :group_id => 1)
126
+ end
127
+
128
+ it 'return a collection of one' do
129
+ assert_equal 1, @employee.group.size
130
+ end
131
+
132
+ it 'include self in group' do
133
+ assert @employee.group.include?(@employee)
134
+ end
135
+
136
+ it 'returns a sql literal for #ids_sql scoped to group' do
137
+ new_group_id = 420
138
+ e1 = FactoryGirl.create :employee, :group_id => new_group_id
139
+ e2 = FactoryGirl.create :employee, :group_id => new_group_id
140
+ e1.group.ids_sql.must_be_instance_of Arel::Nodes::SqlLiteral
141
+ e1.group.ids_sql.must_match %r{SELECT \"employees\".\"id\" FROM \"employees\" WHERE \"employees\".\"group_id\" = #{new_group_id}}
142
+ end
143
+
144
+ it 'allows the group to be further scoped' do
145
+ new_group_id = 420
146
+ e1 = FactoryGirl.create :employee, :group_id => new_group_id, :name => 'Ken', :email => 'ken@actionmoniker.com'
147
+ e2 = FactoryGirl.create :employee, :group_id => new_group_id, :name => 'Hostmaster', :email => 'hostmaster@actionmoniker.com'
148
+ e3 = FactoryGirl.create :employee, :group_id => new_group_id, :name => 'Ken', :email => 'ken@metaskills.net'
149
+ assert_same_elements [e1, e2], e1.group.email_for_actionmoniker
150
+ end
151
+
152
+ end
153
+
154
+ describe 'with different groups available' do
155
+
156
+ before do
157
+ @e1 = FactoryGirl.create(:employee_with_reports, :group_id => 1)
158
+ @e2 = FactoryGirl.create(:employee, :group_id => 1)
159
+ @e3 = FactoryGirl.create(:employee_with_reports, :group_id => 2)
160
+ @e4 = FactoryGirl.create(:employee, :group_id => 2)
161
+ end
162
+
163
+ it 'return a collection of group members' do
164
+ assert_equal 2, @e1.group.size
165
+ end
166
+
167
+ it 'include all group members' do
168
+ assert_same_elements [@e1,@e2], @e1.group
169
+ end
170
+
171
+ it 'allow member to find grouped associations of other member' do
172
+ assert_same_elements @e1.reports, @e2.group.reports
173
+ end
174
+
175
+ it 'allow proxy owner to define all grouped which ignores group_id schema' do
176
+ @e2.stubs :all_grouped? => true
177
+ assert_same_elements [@e1,@e2,@e3,@e4], @e2.group
178
+ assert_same_elements @e1.reports + @e3.reports, @e2.group.reports
179
+ end
180
+
181
+ end
182
+
183
+ describe 'with different groups in legacy schema' do
184
+
185
+ before do
186
+ @e1 = FactoryGirl.create(:legacy_employee_with_reports, :group_id => 1)
187
+ @e2 = FactoryGirl.create(:legacy_employee, :group_id => 1)
188
+ @e3 = FactoryGirl.create(:legacy_employee_with_reports, :group_id => 2)
189
+ @e4 = FactoryGirl.create(:legacy_employee, :group_id => 2)
190
+ end
191
+
192
+ it 'honor legacy reports association options like class_name and foreign_key' do
193
+ @e2.group.reports.all? { |r| r.is_a?(LegacyReport) }
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+
200
+
201
+ end
@@ -3,28 +3,40 @@ require 'bundler'
3
3
  require "bundler/setup"
4
4
  Bundler.require(:default, :development, :test)
5
5
  require 'grouped_scope'
6
- require 'mini_shoulda'
7
6
  require 'minitest/autorun'
8
7
  require 'factories'
8
+ require 'logger'
9
9
 
10
- WillPaginate.enable_activerecord
11
10
 
12
- ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__)+'/debug.log')
11
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__),'debug.log'))
13
12
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
14
- ActiveRecord::Base.connection.class.class_eval do
15
- IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/]
16
- def execute_with_query_record(sql, name = nil, &block)
17
- $queries_executed ||= []
18
- $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
19
- execute_without_query_record(sql, name, &block)
13
+ module ActiveRecord
14
+ class SQLCounter
15
+ cattr_accessor :ignored_sql
16
+ self.ignored_sql = [/^PRAGMA table_info\(.*\)/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
17
+ ignored_sql.concat [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im]
18
+ def initialize
19
+ $queries_executed = []
20
+ end
21
+ def call(name, start, finish, message_id, values)
22
+ sql = values[:sql]
23
+ unless 'CACHE' == values[:name]
24
+ $queries_executed << sql unless self.class.ignored_sql.any? { |r| sql =~ r }
25
+ end
26
+ end
20
27
  end
21
- alias_method_chain :execute, :query_record
28
+ ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
22
29
  end
23
30
 
24
31
 
25
32
  module GroupedScope
26
33
  class TestCase < MiniTest::Spec
27
34
 
35
+ include Mocha::API
36
+
37
+ before { setup_environment }
38
+ after { mocha_teardown }
39
+
28
40
  def setup_environment(options={})
29
41
  options.reverse_merge! :group_column => :group_id
30
42
  setup_database(options)
@@ -47,23 +59,24 @@ module GroupedScope
47
59
  def assert_sql(*patterns_to_match)
48
60
  $queries_executed = []
49
61
  yield
62
+ $queries_executed
50
63
  ensure
51
64
  failed_patterns = []
52
65
  patterns_to_match.each do |pattern|
53
66
  failed_patterns << pattern unless $queries_executed.any?{ |sql| pattern === sql }
54
67
  end
55
- assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found in:\n#{$queries_executed.inspect}"
68
+ assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{$queries_executed.size == 0 ? '' : "\nQueries:\n#{$queries_executed.join("\n")}"}"
56
69
  end
57
70
 
58
71
  def assert_queries(num = 1)
59
72
  $queries_executed = []
60
73
  yield
61
74
  ensure
62
- assert_equal num, $queries_executed.size, "#{$queries_executed.size} instead of #{num} queries were executed."
75
+ assert_equal num, $queries_executed.size, "#{$queries_executed.size} instead of #{num} queries were executed.#{$queries_executed.size == 0 ? '' : "\nQueries:\n#{$queries_executed.join("\n")}"}"
63
76
  end
64
77
 
65
- def assert_no_queries(&block)
66
- assert_queries(0, &block)
78
+ def assert_no_queries
79
+ assert_queries(0) { yield }
67
80
  end
68
81
 
69
82
  def setup_database(options)
@@ -108,44 +121,44 @@ module GroupedScope
108
121
  end
109
122
  end
110
123
 
111
- class Employee < ActiveRecord::Base
112
- has_many :reports do ; def urgent ; find(:all,:conditions => {:title => 'URGENT'}) ; end ; end
113
- has_many :taxonomies, :as => :classable
124
+ class Department < ActiveRecord::Base
125
+ scope :it, where(:name => 'IT')
126
+ scope :hr, where(:name => 'Human Resources')
127
+ scope :finance, where(:name => 'Finance')
114
128
  has_many :department_memberships
115
- has_many :departments, :through => :department_memberships
116
- grouped_scope :reports, :departments
129
+ has_many :employees, :through => :department_memberships
130
+ end
131
+
132
+ class DepartmentMembership < ActiveRecord::Base
133
+ belongs_to :employee
134
+ belongs_to :department
117
135
  end
118
136
 
119
137
  class Report < ActiveRecord::Base
120
- named_scope :with_urgent_title, :conditions => {:title => 'URGENT'}
121
- named_scope :with_urgent_body, :conditions => "body LIKE '%URGENT%'"
138
+ scope :with_urgent_title, where(:title => 'URGENT')
139
+ scope :with_urgent_body, where("body LIKE '%URGENT%'")
122
140
  belongs_to :employee
123
141
  def urgent_title? ; self[:title] == 'URGENT' ; end
124
142
  def urgent_body? ; self[:body] =~ /URGENT/ ; end
125
143
  end
126
144
 
127
- class Department < ActiveRecord::Base
128
- named_scope :it, :conditions => {:name => 'IT'}
129
- named_scope :hr, :conditions => {:name => 'Human Resources'}
130
- named_scope :finance, :conditions => {:name => 'Finance'}
131
- has_many :department_memberships
132
- has_many :employees, :through => :department_memberships
145
+ class LegacyReport < ActiveRecord::Base
146
+ belongs_to :employee, :class_name => 'LegacyEmployee', :foreign_key => 'email'
133
147
  end
134
148
 
135
- class DepartmentMembership < ActiveRecord::Base
136
- belongs_to :employee
137
- belongs_to :department
149
+ class Employee < ActiveRecord::Base
150
+ scope :email_for_actionmoniker, where("email LIKE '%@actionmoniker.com'")
151
+ has_many :reports do ; def urgent ; find(:all,:conditions => {:title => 'URGENT'}) ; end ; end
152
+ has_many :taxonomies, :as => :classable
153
+ has_many :department_memberships
154
+ has_many :departments, :through => :department_memberships
155
+ grouped_scope :reports, :departments
138
156
  end
139
157
 
140
158
  class LegacyEmployee < ActiveRecord::Base
141
159
  set_primary_key :email
142
160
  has_many :reports, :class_name => 'LegacyReport', :foreign_key => 'email'
143
161
  grouped_scope :reports
144
- alias_method :email=, :id=
145
- end
146
-
147
- class LegacyReport < ActiveRecord::Base
148
- belongs_to :employee, :class_name => 'LegacyEmployee', :foreign_key => 'email'
149
162
  end
150
163
 
151
164
  class FooBar < ActiveRecord::Base
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grouped_scope
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
- - 0
8
- - 6
7
+ - 3
9
8
  - 1
10
- version: 0.6.1
9
+ - 0
10
+ version: 3.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ken Collins
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-11 00:00:00 -04:00
19
- default_executable:
18
+ date: 2011-12-07 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: activerecord
@@ -26,12 +25,12 @@ dependencies:
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 31
28
+ hash: 5
30
29
  segments:
31
- - 2
32
30
  - 3
33
- - 14
34
- version: 2.3.14
31
+ - 1
32
+ - 3
33
+ version: 3.1.3
35
34
  type: :runtime
36
35
  version_requirements: *id001
37
36
  description: Extends has_many associations to group scope. For ActiveRecord 2.3.x!
@@ -45,30 +44,29 @@ extra_rdoc_files: []
45
44
 
46
45
  files:
47
46
  - .gitignore
47
+ - .travis.yml
48
48
  - CHANGELOG
49
49
  - Gemfile
50
50
  - MIT-LICENSE
51
- - README.rdoc
51
+ - README.md
52
52
  - Rakefile
53
53
  - lib/grouped_scope.rb
54
- - lib/grouped_scope/association_reflection.rb
55
- - lib/grouped_scope/class_methods.rb
56
- - lib/grouped_scope/core_ext.rb
54
+ - lib/grouped_scope/arish/associations/association_scope.rb
55
+ - lib/grouped_scope/arish/associations/builder/grouped_association.rb
56
+ - lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb
57
+ - lib/grouped_scope/arish/associations/collection_association.rb
58
+ - lib/grouped_scope/arish/base.rb
59
+ - lib/grouped_scope/arish/reflection.rb
60
+ - lib/grouped_scope/arish/relation/predicate_builer.rb
57
61
  - lib/grouped_scope/errors.rb
58
- - lib/grouped_scope/grouping.rb
59
- - lib/grouped_scope/has_many_association.rb
60
- - lib/grouped_scope/has_many_through_association.rb
61
- - lib/grouped_scope/instance_methods.rb
62
62
  - lib/grouped_scope/self_grouping.rb
63
63
  - lib/grouped_scope/version.rb
64
+ - test/cases/has_many_test.rb
65
+ - test/cases/has_many_through_test.rb
66
+ - test/cases/reflection_test.rb
67
+ - test/cases/self_grouping_test.rb
64
68
  - test/factories.rb
65
- - test/grouped_scope/association_reflection_test.rb
66
- - test/grouped_scope/class_methods_test.rb
67
- - test/grouped_scope/has_many_association_test.rb
68
- - test/grouped_scope/has_many_through_association_test.rb
69
- - test/grouped_scope/self_grouping_test.rb
70
69
  - test/helper.rb
71
- has_rdoc: true
72
70
  homepage: http://github.com/metaskills/grouped_scope/
73
71
  licenses: []
74
72
 
@@ -98,15 +96,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
96
  requirements: []
99
97
 
100
98
  rubyforge_project:
101
- rubygems_version: 1.6.2
99
+ rubygems_version: 1.8.11
102
100
  signing_key:
103
101
  specification_version: 3
104
102
  summary: Extends has_many associations to group scope.
105
103
  test_files:
104
+ - test/cases/has_many_test.rb
105
+ - test/cases/has_many_through_test.rb
106
+ - test/cases/reflection_test.rb
107
+ - test/cases/self_grouping_test.rb
106
108
  - test/factories.rb
107
- - test/grouped_scope/association_reflection_test.rb
108
- - test/grouped_scope/class_methods_test.rb
109
- - test/grouped_scope/has_many_association_test.rb
110
- - test/grouped_scope/has_many_through_association_test.rb
111
- - test/grouped_scope/self_grouping_test.rb
112
109
  - test/helper.rb