grouped_scope 0.6.1 → 3.1.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.
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