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 +34 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +98 -0
- data/Rakefile +43 -0
- data/init.rb +2 -0
- data/lib/grouped_scope/association_reflection.rb +54 -0
- data/lib/grouped_scope/class_methods.rb +32 -0
- data/lib/grouped_scope/core_ext.rb +21 -0
- data/lib/grouped_scope/errors.rb +12 -0
- data/lib/grouped_scope/grouping.rb +9 -0
- data/lib/grouped_scope/has_many_association.rb +30 -0
- data/lib/grouped_scope/has_many_through_association.rb +28 -0
- data/lib/grouped_scope/instance_methods.rb +10 -0
- data/lib/grouped_scope/self_grouping.rb +78 -0
- data/lib/grouped_scope.rb +15 -0
- data/test/factories.rb +46 -0
- data/test/grouped_scope/association_reflection_test.rb +83 -0
- data/test/grouped_scope/class_methods_test.rb +51 -0
- data/test/grouped_scope/has_many_association_test.rb +157 -0
- data/test/grouped_scope/has_many_through_association_test.rb +53 -0
- data/test/grouped_scope/self_grouping_test.rb +147 -0
- data/test/helper.rb +108 -0
- data/test/lib/boot.rb +32 -0
- data/test/lib/core_ext.rb +20 -0
- data/test/lib/named_scope/core_ext.rb +82 -0
- data/test/lib/named_scope/named_scope.rb +168 -0
- data/test/lib/named_scope/named_scope_patch_1.2.rb +85 -0
- data/test/lib/named_scope/named_scope_patch_2.0.rb +55 -0
- data/test/lib/named_scope.rb +7 -0
- data/test/lib/test_case.rb +44 -0
- metadata +84 -0
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,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,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,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
|