decisiv-grouped_scope 0.5.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/CHANGELOG ADDED
@@ -0,0 +1,34 @@
1
+
2
+ *master*
3
+
4
+ *
5
+
6
+
7
+ *0.5.1* (January 7th 2009)
8
+
9
+ * Add rails 2.2.2 to test task and remove quite backtrace usage so 1.2.6 testing can run. [Ken Collins]
10
+
11
+
12
+ *0.4* (October 3rd 2008)
13
+
14
+ * Use the #737f2bdabb of NamedScope plugin from http://github.com/metaskills/named_scope/tree/master
15
+
16
+
17
+ *0.3* (October 2nd 2008)
18
+
19
+ * Add additional NamedScope patches for attribute_condition.
20
+ Also added GroupedScope::CoreExt to follow suite for GroupedScope::SelfGrouping attribute_conditions.
21
+
22
+
23
+ *0.2* (September 29th 2008)
24
+
25
+ * Add WillPaginate test and confirm grouped scope, named scope, and will paginate all play together. [Ken Collins]
26
+
27
+ * Stronger back port for named_scope in 1.2.6 and 2.0.4. Fixed bug where association proxy owner scope was after named_scope calls. [Ken Collins]
28
+
29
+
30
+ *0.1* (September 26th, 2008)
31
+
32
+ * Initial public release. [Ken Collins]
33
+
34
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2008 Ken Collins, Decisiv Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.rdoc ADDED
@@ -0,0 +1,98 @@
1
+
2
+ == GroupedScope: Has Many Associations IN (GROUPS)
3
+
4
+ GroupedScope aims to make two things easier in your ActiveRecord models. First, provide a
5
+ easy way to group objects, second, to allow the group to share associated object via existing
6
+ has_many relationships. See installation and usage for more details.
7
+
8
+ By the way, this plugin has been tested with rails 1.2.6, 2.0.4, and 2.1.1.
9
+
10
+
11
+ === Installation & Usage
12
+
13
+ From your project's RAILS_ROOT, run:
14
+
15
+ ./script/plugin install git://github.com/metaskills/grouped_scope.git
16
+
17
+ To use GroupedScope on a model it must have a :group_id column.
18
+
19
+ class AddGroupId < ActiveRecord::Migration
20
+ def self.up
21
+ add_column :employees, :group_id, :integer
22
+ end
23
+ def self.down
24
+ remove_column :employees, :group_id
25
+ end
26
+ end
27
+
28
+ Assume the following model.
29
+
30
+ class Employee < ActiveRecord::Base
31
+ has_many :reports
32
+ grouped_scope :reports
33
+ end
34
+
35
+ By calling grouped_scope on any association you create a new group accessor for each
36
+ instance. The object returned will act just like an array and at least include the
37
+ current object that called it.
38
+
39
+ @employee_one.group # => [#<Employee id: 1, group_id: nil>]
40
+
41
+ To group resources, just assign the same :group_id in the schema. Note that in future
42
+ versions I will be extending the GroupedScope::Grouping that each object belongs to.
43
+ If you do not just want to assign some random integers, then take a look at that model
44
+ and the belongs_to :grouping code, schema needed ofcourse
45
+
46
+ @employee_one.update_attribute :group_id, 1
47
+ @employee_two.update_attribute :group_id, 1
48
+ @employee_one.group # => [#<Employee id: 1, group_id: 1>, #<Employee id: 2, group_id: 1>]
49
+
50
+ Calling grouped_scope on the :reports association leaves the existing association intact.
51
+
52
+ @employee_one.reports # => [#<Report id: 2, employee_id: 1>]
53
+ @employee_two.reports # => [#<Report id: 18, employee_id: 2>, #<Report id: 36, employee_id: 2>]
54
+
55
+ Now the good part, all associations passed to the grouped_scope method can be called
56
+ on the group proxy. The collection will return resources shared by the group.
57
+
58
+ @employee_one.group.reports # => [#<Report id: 2, employee_id: 1>,
59
+ #<Report id: 18, employee_id: 2>,
60
+ #<Report id: 36, employee_id: 2>]
61
+
62
+ You can even call named scopes defined on the objects in the collection and association
63
+ extensions defined on the original has_many. For instance:
64
+
65
+ @employee.group.reports.urgent.assigned_to(user)
66
+
67
+
68
+
69
+ === Todo List
70
+
71
+ * Go back and start adding some rdocs.
72
+ * Add more GroupedScope::Grouping code.
73
+ * Add polymorphic support.
74
+ * Add/test has_and_belongs_to_many
75
+ * Raise errors and/or support :finder_sql/:counter_sql.
76
+ * Add a user definable group_id schema.
77
+
78
+
79
+ === Helping Our & Running Tests
80
+
81
+ Running the test suite is easy to do. Just make sure you have the following gems installed.
82
+
83
+ * shoulda
84
+ * quitebacktrace
85
+ * mocha
86
+ * factory_girl
87
+
88
+ If you want to run the tests for a specific version of rails in gems (other than the latest),
89
+ then you can set the RAILS_VERSION environment variable. For example `env RAILS_VERSION=1.2.6 autotest`.
90
+ When doing this you also need to make sure that you download version 4.1 of shoulda (not the gem)
91
+ and place its lib contents into `test/lib/shoulda` and `test/lib/shoulda.rb`. The reason is that
92
+ the latest should gem require ActiveSupport greater than 2.0.
93
+
94
+
95
+
96
+ Copyright (c) 2008 Ken Collins, Decisiv Inc.
97
+ Released under the MIT license.
98
+
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ def reset_invoked
6
+ ['test_rails','test'].each do |name|
7
+ Rake::Task[name].instance_variable_set '@already_invoked', false
8
+ end
9
+ end
10
+
11
+
12
+ desc 'Default: run unit tests.'
13
+ task :default => :test_rails
14
+
15
+ desc 'Test the GroupedScope plugin.'
16
+ Rake::TestTask.new(:test) do |t|
17
+ t.libs << 'lib'
18
+ t.libs << 'test'
19
+ t.pattern = 'test/**/*_test.rb'
20
+ t.verbose = true
21
+ end
22
+
23
+ desc 'Test the GroupedScope plugin with Rails 2.1.1, 2.0.4 & 1.2.6 gems'
24
+ task :test_rails do
25
+ test = Rake::Task['test']
26
+ versions = ['2.2.2','2.1.1','2.0.4','1.2.6']
27
+ versions.each do |version|
28
+ ENV['RAILS_VERSION'] = "#{version}"
29
+ test.invoke
30
+ reset_invoked unless version == versions.last
31
+ end
32
+ end
33
+
34
+ desc 'Generate documentation for the GroupedScope plugin.'
35
+ Rake::RDocTask.new(:rdoc) do |rdoc|
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = 'GroupedScope'
38
+ rdoc.options << '--line-numbers' << '--inline-source'
39
+ rdoc.rdoc_files.include('README')
40
+ rdoc.rdoc_files.include('lib/**/*.rb')
41
+ end
42
+
43
+
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'grouped_scope'
2
+
@@ -0,0 +1,54 @@
1
+ module GroupedScope
2
+ class AssociationReflection < ActiveRecord::Reflection::AssociationReflection
3
+
4
+ ((ActiveRecord::Reflection::AssociationReflection.instance_methods-Class.instance_methods) +
5
+ (ActiveRecord::Reflection::AssociationReflection.private_instance_methods-Class.private_instance_methods)).each do |m|
6
+ undef_method(m)
7
+ end
8
+
9
+ attr_accessor :name, :options
10
+
11
+ def initialize(active_record,ungrouped_name)
12
+ @active_record = active_record
13
+ @ungrouped_name = ungrouped_name
14
+ @name = :"grouped_scope_#{@ungrouped_name}"
15
+ verify_ungrouped_reflection
16
+ super(ungrouped_reflection.macro, @name, ungrouped_reflection.options.dup, @active_record)
17
+ create_grouped_association
18
+ end
19
+
20
+ def ungrouped_reflection
21
+ @active_record.reflections[@ungrouped_name]
22
+ end
23
+
24
+ def respond_to?(method, include_private=false)
25
+ super || ungrouped_reflection.respond_to?(method,include_private)
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def method_missing(method, *args, &block)
32
+ ungrouped_reflection.send(method, *args, &block)
33
+ end
34
+
35
+ def verify_ungrouped_reflection
36
+ if ungrouped_reflection.blank? || ungrouped_reflection.macro.to_s !~ /has_many|has_and_belongs_to_many/
37
+ raise ArgumentError, "Cannot create a group scope for :#{@ungrouped_name} because it is not a has_many " +
38
+ "or a has_and_belongs_to_many association. Make sure to call grouped_scope after " +
39
+ "the has_many associations."
40
+ end
41
+ end
42
+
43
+ def create_grouped_association
44
+ active_record.send(macro, name, options)
45
+ association_proxy_class = options[:through] ? ActiveRecord::Associations::HasManyThroughAssociation : ActiveRecord::Associations::HasManyAssociation
46
+ active_record.send(:collection_reader_method, self, association_proxy_class)
47
+
48
+ active_record.reflections[name] = self
49
+ active_record.grouped_scopes[@ungrouped_name] = true
50
+ options[:grouped_scope] = true
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ module GroupedScope
2
+ module ClassMethods
3
+
4
+ def grouped_scopes
5
+ read_inheritable_attribute(:grouped_scopes) || write_inheritable_attribute(:grouped_scopes, {})
6
+ end
7
+
8
+ def grouped_scope(*associations)
9
+ create_belongs_to_for_grouped_scope
10
+ associations.each { |association| AssociationReflection.new(self,association) }
11
+ create_grouped_scope_accessor
12
+ end
13
+
14
+ private
15
+
16
+ def create_grouped_scope_accessor
17
+ define_method(:group) do
18
+ @group ||= SelfGroupping.new(self)
19
+ end
20
+ end
21
+
22
+ def create_belongs_to_for_grouped_scope
23
+ grouping_class_name = 'GroupedScope::Grouping'
24
+ existing_grouping = reflections[:grouping]
25
+ return false if existing_grouping && existing_grouping.macro == :belongs_to && existing_grouping.options[:class_name] == grouping_class_name
26
+ belongs_to :grouping, :foreign_key => 'group_id', :class_name => grouping_class_name
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ ActiveRecord::Base.send :extend, GroupedScope::ClassMethods
@@ -0,0 +1,21 @@
1
+
2
+ class ActiveRecord::Base
3
+
4
+ class << self
5
+
6
+ private
7
+
8
+ def attribute_condition_with_grouped_scope(argument)
9
+ case argument
10
+ when GroupedScope::SelfGroupping then "IN (?)"
11
+ else attribute_condition_without_grouped_scope(argument)
12
+ end
13
+ end
14
+
15
+ alias_method_chain :attribute_condition, :grouped_scope
16
+
17
+ end
18
+
19
+ end
20
+
21
+
@@ -0,0 +1,12 @@
1
+ module GroupedScope
2
+
3
+ class GroupedScopeError < StandardError #:nodoc:
4
+ end
5
+
6
+ class NoGroupIdError < GroupedScopeError #:nodoc:
7
+ def initialize(owner) ; @owner = owner ; end
8
+ def message ; %|The #{@owner.class} class does not have a "group_id" attribute.| ; end
9
+ end
10
+
11
+
12
+ end
@@ -0,0 +1,9 @@
1
+ module GroupedScope
2
+ class Grouping < ActiveRecord::Base
3
+
4
+
5
+
6
+
7
+ end
8
+ end
9
+
@@ -0,0 +1,30 @@
1
+ module GroupedScope
2
+ module HasManyAssociation
3
+
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ alias_method_chain :construct_sql, :group_scope
7
+ end
8
+ end
9
+
10
+ def construct_sql_with_group_scope
11
+ if @reflection.options[:grouped_scope]
12
+ # CHANGED [Rails 1.2.6] Account for quoted_table_name.
13
+ table_name = @reflection.respond_to?(:quoted_table_name) ? @reflection.quoted_table_name : @reflection.klass.table_name
14
+ if @reflection.options[:as]
15
+ # TODO: Need to add case for polymorphic :as option.
16
+ else
17
+ @finder_sql = "#{table_name}.#{@reflection.primary_key_name} IN (#{@owner.group.quoted_ids})"
18
+ @finder_sql << " AND (#{conditions})" if conditions
19
+ end
20
+ @counter_sql = @finder_sql
21
+ else
22
+ construct_sql_without_group_scope
23
+ end
24
+ end
25
+
26
+
27
+ end
28
+ end
29
+
30
+ ActiveRecord::Associations::HasManyAssociation.send :include, GroupedScope::HasManyAssociation
@@ -0,0 +1,28 @@
1
+ module GroupedScope
2
+ module HasManyThroughAssociation
3
+
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ alias_method_chain :construct_conditions, :group_scope
7
+ end
8
+ end
9
+
10
+ def construct_conditions_with_group_scope
11
+ conditions = construct_conditions_without_group_scope
12
+ if @reflection.options[:grouped_scope]
13
+ if as = @reflection.options[:as]
14
+ # TODO: Need to add case for polymorphic :as option.
15
+ else
16
+ pattern = "#{@reflection.primary_key_name} = #{@owner.quoted_id}"
17
+ replacement = "#{@reflection.primary_key_name} IN (#{@owner.group.quoted_ids})"
18
+ conditions.sub!(pattern,replacement)
19
+ end
20
+ end
21
+ conditions
22
+ end
23
+
24
+
25
+ end
26
+ end
27
+
28
+ ActiveRecord::Associations::HasManyThroughAssociation.send :include, GroupedScope::HasManyThroughAssociation
@@ -0,0 +1,10 @@
1
+ module GroupedScope
2
+ module InstanceMethods
3
+
4
+ def group
5
+ @group ||= SelfGroupping.new(self)
6
+ end
7
+
8
+
9
+ end
10
+ end
@@ -0,0 +1,78 @@
1
+ module GroupedScope
2
+ class SelfGroupping
3
+
4
+ attr_reader :proxy_owner
5
+
6
+ delegate :primary_key, :quote_value, :columns_hash, :to => :proxy_class
7
+
8
+ [].methods.each do |m|
9
+ unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|respond_to\?)/
10
+ delegate m, :to => :group_proxy
11
+ end
12
+ end
13
+
14
+
15
+ def initialize(proxy_owner)
16
+ raise NoGroupIdError.new(proxy_owner) unless proxy_owner.class.column_names.include?('group_id')
17
+ @proxy_owner = proxy_owner
18
+ end
19
+
20
+ def ids
21
+ @ids ||= find_selves(group_id_scope_options).map(&:id)
22
+ end
23
+
24
+ def quoted_ids
25
+ ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',')
26
+ end
27
+
28
+ def respond_to?(method, include_private=false)
29
+ super || !proxy_class.grouped_scopes[method].blank?
30
+ end
31
+
32
+
33
+ protected
34
+
35
+ def group_proxy
36
+ @group_proxy ||= find_selves(group_scope_options)
37
+ end
38
+
39
+ def all_grouped?
40
+ proxy_owner.all_grouped? rescue false
41
+ end
42
+
43
+ def no_group?
44
+ proxy_owner.group_id.blank?
45
+ end
46
+
47
+ def find_selves(options={})
48
+ proxy_owner.class.find :all, options
49
+ end
50
+
51
+ def group_scope_options
52
+ return {} if all_grouped?
53
+ conditions = no_group? ? { primary_key => proxy_owner.id } : { :group_id => proxy_owner.group_id }
54
+ { :conditions => conditions }
55
+ end
56
+
57
+ def group_id_scope_options
58
+ { :select => primary_key }.merge(group_scope_options)
59
+ end
60
+
61
+ def proxy_class
62
+ proxy_owner.class
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def method_missing(method, *args, &block)
69
+ if proxy_class.grouped_scopes[method]
70
+ proxy_owner.send("grouped_scope_#{method}", *args, &block)
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+
@@ -0,0 +1,15 @@
1
+ require 'grouped_scope/errors'
2
+ require 'grouped_scope/grouping'
3
+ require 'grouped_scope/self_grouping'
4
+ require 'grouped_scope/association_reflection'
5
+ require 'grouped_scope/class_methods'
6
+ require 'grouped_scope/has_many_association'
7
+ require 'grouped_scope/has_many_through_association'
8
+ require 'grouped_scope/core_ext'
9
+
10
+ module GroupedScope
11
+
12
+ VERSION = '0.5.1'
13
+
14
+ end
15
+
data/test/factories.rb ADDED
@@ -0,0 +1,46 @@
1
+
2
+ Factory.sequence(:id) { |n| n }
3
+ Factory.sequence(:email) { |n| "test_#{n}@domain.com" }
4
+ Factory.sequence(:title) { |n| "Report Title ##{n}" }
5
+
6
+ Factory.define :employee do |e|
7
+ e.name { "Factory Employee ##{Factory.next(:id)}" }
8
+ e.email { Factory.next(:email) }
9
+ end
10
+
11
+ Factory.define :report do |r|
12
+ r.title { Factory.next(:title) }
13
+ r.body 'Bla bla bla. Bla. Bla bla.'
14
+ end
15
+
16
+ Factory.define :employee_with_reports, :class => 'Employee' do |e|
17
+ e.name { "Factory Employee ##{Factory.next(:id)}" }
18
+ e.email { Factory.next(:email) }
19
+ e.reports { |employee| [employee.association(:report),employee.association(:report)] }
20
+ end
21
+
22
+ Factory.define :employee_with_urgent_reports, :class => 'Employee' do |e|
23
+ e.name { "Factory Employee ##{Factory.next(:id)}" }
24
+ e.email { Factory.next(:email) }
25
+ e.reports { |employee| [employee.association(:report), employee.association(:report,:title=>'URGENT'),
26
+ employee.association(:report), employee.association(:report,:body=>'This is URGENT.')] }
27
+ end
28
+
29
+
30
+ Factory.define :legacy_employee do |e|
31
+ e.name { "Legacy Factory Employee ##{Factory.next(:id)}" }
32
+ e.email { Factory.next(:email) }
33
+ end
34
+
35
+ Factory.define :legacy_report do |r|
36
+ r.title { Factory.next(:title) }
37
+ r.body 'Legacy bla bla. Legacy. Legacy bla.'
38
+ end
39
+
40
+ Factory.define :legacy_employee_with_reports, :class => 'LegacyEmployee' do |e|
41
+ e.name { "Legacy Factory Employee ##{Factory.next(:id)}" }
42
+ e.email { Factory.next(:email) }
43
+ e.reports { |employee| [employee.association(:legacy_report),employee.association(:legacy_report)] }
44
+ end
45
+
46
+
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ class GroupedScope::AssociationReflectionTest < GroupedScope::TestCase
4
+
5
+ def setup
6
+ setup_environment
7
+ end
8
+
9
+ context 'For initialization' do
10
+
11
+ context 'Raise and exception' do
12
+
13
+ setup { @reflection_klass = GroupedScope::AssociationReflection }
14
+
15
+ should 'when a association does not exist' do
16
+ assert_raise(ArgumentError) { @reflection_klass.new(Employee,:foobars) }
17
+ end
18
+
19
+ should 'when the association is not a has_many or a has_and_belongs_to_many' do
20
+ Employee.class_eval { belongs_to(:foo) }
21
+ assert_raise(ArgumentError) { @reflection_klass.new(Employee,:foo) }
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+
29
+ context 'For #ungrouped_reflection' do
30
+
31
+ setup do
32
+ @ungrouped_reflection = Employee.reflections[:reports]
33
+ @grouped_reflection = Employee.reflections[:grouped_scope_reports]
34
+ end
35
+
36
+ should 'access ungrouped reflection' do
37
+ assert_equal @ungrouped_reflection, @grouped_reflection.ungrouped_reflection
38
+ end
39
+
40
+ should 'delegate instance methods to #ungrouped_reflection' do
41
+ methods = [:class_name,:klass,:table_name,:primary_key_name,:active_record,
42
+ :association_foreign_key,:counter_cache_column,:source_reflection]
43
+ # CHANGED [Rails 1.2.6] Account for quoted_table_name.
44
+ methods << :quoted_table_name if @ungrouped_reflection.respond_to?(:quoted_table_name)
45
+ methods.each do |m|
46
+ assert_equal @ungrouped_reflection.send(m), @grouped_reflection.send(m),
47
+ "The method #{m.inspect} does not appear to be proxied to the ungrouped reflection."
48
+ end
49
+ end
50
+
51
+ should 'not delegate to #ungrouped_reflection for #options and #name' do
52
+ assert_not_equal @ungrouped_reflection.name, @grouped_reflection.name
53
+ assert_not_equal @ungrouped_reflection.options, @grouped_reflection.options
54
+ end
55
+
56
+ should 'derive class name to same as ungrouped reflection' do
57
+ # CHANGED [Rails 1.2.6] Account for quoted_table_name.
58
+ if @ungrouped_reflection.respond_to?(:derive_class_name)
59
+ assert_equal @ungrouped_reflection.send(:derive_class_name), @grouped_reflection.send(:derive_class_name)
60
+ end
61
+ end
62
+
63
+ should 'derive primary key name to same as ungrouped reflection' do
64
+ # CHANGED [Rails 1.2.6] Account for quoted_table_name.
65
+ if @ungrouped_reflection.respond_to?(:derive_primary_key_name)
66
+ assert_equal @ungrouped_reflection.send(:derive_primary_key_name), @grouped_reflection.send(:derive_primary_key_name)
67
+ end
68
+ end
69
+
70
+ should 'honor explicit legacy reports association options like class_name and foreign_key' do
71
+ @ungrouped_reflection = LegacyEmployee.reflections[:reports]
72
+ @grouped_reflection = LegacyEmployee.reflections[:grouped_scope_reports]
73
+ [:class_name,:primary_key_name].each do |m|
74
+ assert_equal @ungrouped_reflection.send(m), @grouped_reflection.send(m),
75
+ "The method #{m.inspect} does not appear to be proxied to the ungrouped reflection."
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+
82
+
83
+ end
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ class GroupedScope::ClassMethodsTest < GroupedScope::TestCase
4
+
5
+ def setup
6
+ setup_environment
7
+ end
8
+
9
+ context 'For .grouped_scopes' do
10
+
11
+ should 'have a inheritable attribute hash' do
12
+ assert_instance_of Hash, Employee.grouped_scopes
13
+ end
14
+
15
+ should 'add to inheritable attributes with new grouped_scope' do
16
+ Employee.grouped_scopes[:foobars] = nil
17
+ Employee.class_eval { has_many(:foobars) ; grouped_scope(:foobars) }
18
+ assert Employee.grouped_scopes[:foobars]
19
+ end
20
+
21
+ end
22
+
23
+ context 'For .grouped_scope' do
24
+
25
+ should 'create a belongs_to :grouping association' do
26
+ assert Employee.reflections[:grouping]
27
+ end
28
+
29
+ should 'not recreate belongs_to :grouping on additional calls' do
30
+ Employee.stubs(:belongs_to).never
31
+ Employee.class_eval { has_many(:foobars) ; grouped_scope(:foobars) }
32
+ end
33
+
34
+ should 'create a has_many assoc named :grouped_scope_* using existing association as a suffix' do
35
+ grouped_reports_assoc = Employee.reflections[:grouped_scope_reports]
36
+ assert_instance_of GroupedScope::AssociationReflection, grouped_reports_assoc
37
+ assert Factory(:employee).respond_to?(:grouped_scope_reports)
38
+ end
39
+
40
+ should 'not add the :grouped_scope option to existing reflection' do
41
+ assert_nil Employee.reflections[:reports].options[:grouped_scope]
42
+ end
43
+
44
+ should 'have added the :grouped_scope option to new grouped reflection' do
45
+ assert Employee.reflections[:grouped_scope_reports].options[:grouped_scope]
46
+ end
47
+
48
+ end
49
+
50
+
51
+ end