groupify 0.3.1 → 0.4.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.
- data/.travis.yml +2 -18
- data/Gemfile +11 -1
- data/README.md +100 -20
- data/gemfiles/activesupport3.gemfile +18 -0
- data/gemfiles/activesupport4.gemfile +23 -0
- data/groupify.gemspec +7 -2
- data/lib/groupify/adapter/active_record.rb +318 -0
- data/lib/groupify/adapter/mongoid.rb +249 -0
- data/lib/groupify/railtie.rb +20 -0
- data/lib/groupify/version.rb +1 -1
- data/lib/groupify.rb +1 -195
- data/spec/groupify/active_record_spec.rb +231 -0
- data/spec/groupify/{mongoid3.yml → mongoid.yml} +0 -0
- data/spec/groupify/mongoid_spec.rb +93 -23
- data/spec/spec_helper.rb +2 -12
- metadata +60 -47
- data/gemfiles/mongoid2.gemfile +0 -10
- data/gemfiles/mongoid3.gemfile +0 -8
- data/spec/groupify/mongoid2.yml +0 -9
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
# Groups and members
|
5
|
+
module Groupify
|
6
|
+
module Mongoid
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
def none; where(:id => nil); end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def acts_as_group(opts = {})
|
15
|
+
include Groupify::Mongoid::Group
|
16
|
+
|
17
|
+
if (member_klass = opts.delete :default_members)
|
18
|
+
self.default_member_class = member_klass.to_s.classify.constantize
|
19
|
+
end
|
20
|
+
|
21
|
+
if (member_klasses = opts.delete :members)
|
22
|
+
member_klasses.each do |member_klass|
|
23
|
+
has_members(member_klass)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def acts_as_group_member(opts = {})
|
29
|
+
@group_class_name = opts[:class_name] || 'Group'
|
30
|
+
include Groupify::Mongoid::GroupMember
|
31
|
+
end
|
32
|
+
|
33
|
+
def acts_as_named_group_member(opts = {})
|
34
|
+
include Groupify::Mongoid::NamedGroupMember
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Usage:
|
39
|
+
# class Group
|
40
|
+
# include Mongoid::Document
|
41
|
+
#
|
42
|
+
# acts_as_group, :members => [:users]
|
43
|
+
# ...
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# group.add(member)
|
47
|
+
#
|
48
|
+
module Group
|
49
|
+
extend ActiveSupport::Concern
|
50
|
+
|
51
|
+
included do
|
52
|
+
@default_member_class = nil
|
53
|
+
@member_klasses ||= Set.new
|
54
|
+
end
|
55
|
+
|
56
|
+
def members
|
57
|
+
self.class.default_member_class.any_in(:group_ids => [self.id])
|
58
|
+
end
|
59
|
+
|
60
|
+
def member_classes
|
61
|
+
self.class.member_classes
|
62
|
+
end
|
63
|
+
|
64
|
+
def add(member)
|
65
|
+
member.groups << self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Merge a source group into this group.
|
69
|
+
def merge!(source)
|
70
|
+
self.class.merge!(source, self)
|
71
|
+
end
|
72
|
+
|
73
|
+
module ClassMethods
|
74
|
+
def with_member(member)
|
75
|
+
criteria.for_ids(member.group_ids)
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_member_class
|
79
|
+
@default_member_class ||= register(User)
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_member_class=(klass)
|
83
|
+
@default_member_class = klass
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns the member classes defined for this class, as well as for the super classes
|
87
|
+
def member_classes
|
88
|
+
(@member_klasses ||= Set.new).merge(superclass.method_defined?(:member_classes) ? superclass.member_classes : [])
|
89
|
+
end
|
90
|
+
|
91
|
+
# Define which classes are members of this group
|
92
|
+
def has_members(name)
|
93
|
+
klass = name.to_s.classify.constantize
|
94
|
+
register(klass)
|
95
|
+
|
96
|
+
# Define specific members accessor, i.e. group.users
|
97
|
+
define_method name.to_s.pluralize.underscore do
|
98
|
+
klass.any_in(:group_ids => [self.id])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Merge two groups. The members of the source become members of the destination, and the source is destroyed.
|
103
|
+
def merge!(source_group, destination_group)
|
104
|
+
# Ensure that all the members of the source can be members of the destination
|
105
|
+
invalid_member_classes = (source_group.member_classes - destination_group.member_classes)
|
106
|
+
invalid_member_classes.each do |klass|
|
107
|
+
if klass.any_in(:group_ids => [source_group.id]).count > 0
|
108
|
+
raise ArgumentError.new("#{source_group.class} has members that cannot belong to #{destination_group.class}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
source_group.member_classes.each do |klass|
|
113
|
+
klass.any_in(:group_ids => [source_group.id]).update(:$set => {:"group_ids.$" => destination_group.id})
|
114
|
+
end
|
115
|
+
source_group.destroy
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
def register(member_klass)
|
121
|
+
(@member_klasses ||= Set.new) << member_klass
|
122
|
+
member_klass
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Usage:
|
128
|
+
# class User
|
129
|
+
# include Mongoid::Document
|
130
|
+
#
|
131
|
+
# acts_as_group_member
|
132
|
+
# ...
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# user.groups << group
|
136
|
+
#
|
137
|
+
module GroupMember
|
138
|
+
extend ActiveSupport::Concern
|
139
|
+
|
140
|
+
included do
|
141
|
+
has_and_belongs_to_many :groups, :autosave => true, :inverse_of => nil, :class_name => @group_class_name
|
142
|
+
end
|
143
|
+
|
144
|
+
def in_group?(group)
|
145
|
+
self.groups.include?(group)
|
146
|
+
end
|
147
|
+
|
148
|
+
def in_any_group?(*groups)
|
149
|
+
groups.flatten.each do |group|
|
150
|
+
return true if in_group?(group)
|
151
|
+
end
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
|
155
|
+
def in_all_groups?(*groups)
|
156
|
+
Set.new(groups.flatten) == Set.new(self.named_groups)
|
157
|
+
end
|
158
|
+
|
159
|
+
def shares_any_group?(other)
|
160
|
+
in_any_group?(other.groups)
|
161
|
+
end
|
162
|
+
|
163
|
+
module ClassMethods
|
164
|
+
def group_class_name; @group_class_name ||= 'Group'; end
|
165
|
+
def group_class_name=(klass); @group_class_name = klass; end
|
166
|
+
|
167
|
+
def in_group(group)
|
168
|
+
group.present? ? where(:group_ids.in => [group.id]) : none
|
169
|
+
end
|
170
|
+
|
171
|
+
def in_any_group(*groups)
|
172
|
+
groups.present? ? where(:group_ids.in => groups.flatten.map(&:id)) : none
|
173
|
+
end
|
174
|
+
|
175
|
+
def in_all_groups(*groups)
|
176
|
+
groups.present? ? where(:group_ids => groups.flatten.map(&:id)) : none
|
177
|
+
end
|
178
|
+
|
179
|
+
def shares_any_group(other)
|
180
|
+
in_any_group(other.groups)
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Usage:
|
187
|
+
# class User
|
188
|
+
# include Mongoid::Document
|
189
|
+
#
|
190
|
+
# acts_as_named_group_member
|
191
|
+
# ...
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# user.named_groups << :admin
|
195
|
+
#
|
196
|
+
module NamedGroupMember
|
197
|
+
extend ActiveSupport::Concern
|
198
|
+
|
199
|
+
included do
|
200
|
+
field :named_groups, :type => Array, :default => []
|
201
|
+
|
202
|
+
before_save :uniq_named_groups
|
203
|
+
protected
|
204
|
+
def uniq_named_groups
|
205
|
+
named_groups.uniq!
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def in_named_group?(group)
|
210
|
+
named_groups.include?(group)
|
211
|
+
end
|
212
|
+
|
213
|
+
def in_any_named_group?(*groups)
|
214
|
+
groups.flatten.each do |group|
|
215
|
+
return true if in_named_group?(group)
|
216
|
+
end
|
217
|
+
return false
|
218
|
+
end
|
219
|
+
|
220
|
+
def in_all_named_groups?(*groups)
|
221
|
+
Set.new(groups.flatten) == Set.new(self.named_groups)
|
222
|
+
end
|
223
|
+
|
224
|
+
def shares_any_named_group?(other)
|
225
|
+
in_any_named_group?(other.named_groups)
|
226
|
+
end
|
227
|
+
|
228
|
+
module ClassMethods
|
229
|
+
def in_named_group(named_group)
|
230
|
+
named_group.present? ? where(:named_groups.in => [named_group]) : none
|
231
|
+
end
|
232
|
+
|
233
|
+
def in_any_named_group(*named_groups)
|
234
|
+
named_groups.present? ? where(:named_groups.in => named_groups.flatten) : none
|
235
|
+
end
|
236
|
+
|
237
|
+
def in_all_named_groups(*named_groups)
|
238
|
+
named_groups.present? ? where(:named_groups => named_groups.flatten) : none
|
239
|
+
end
|
240
|
+
|
241
|
+
def shares_any_named_group(other)
|
242
|
+
in_any_named_group(other.named_groups)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
Mongoid::Document.send :include, Groupify::Mongoid
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'groupify'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module Groupify
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer "groupify.active_record" do |app|
|
8
|
+
ActiveSupport.on_load :active_record do
|
9
|
+
require 'groupify/adapter/active_record'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
initializer "groupify.mongoid" do |app|
|
14
|
+
if defined?(Mongoid)
|
15
|
+
require 'groupify/adapter/mongoid'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/groupify/version.rb
CHANGED
data/lib/groupify.rb
CHANGED
@@ -1,197 +1,3 @@
|
|
1
1
|
require 'active_support'
|
2
|
-
require 'mongoid'
|
3
|
-
require 'set'
|
4
2
|
|
5
|
-
|
6
|
-
module Groupify
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
included do
|
10
|
-
def none; where(:id => nil); end
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
def acts_as_group(opts = {})
|
15
|
-
include Groupify::Group
|
16
|
-
|
17
|
-
if (member_klass = opts.delete :default_members)
|
18
|
-
self.default_member_class = member_klass.to_s.classify.constantize
|
19
|
-
end
|
20
|
-
|
21
|
-
if (member_klasses = opts.delete :members)
|
22
|
-
member_klasses.each do |member_klass|
|
23
|
-
has_members(member_klass)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def acts_as_group_member(opts = {})
|
29
|
-
class_eval { @group_class_name = opts[:class_name] || 'Group' }
|
30
|
-
include Groupify::GroupMember
|
31
|
-
end
|
32
|
-
|
33
|
-
def acts_as_named_group_member(opts = {})
|
34
|
-
include Groupify::NamedGroupMember
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Usage:
|
39
|
-
# class Group
|
40
|
-
# acts_as_group, :members => [:users]
|
41
|
-
# ...
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# group.add(member)
|
45
|
-
#
|
46
|
-
module Group
|
47
|
-
extend ActiveSupport::Concern
|
48
|
-
|
49
|
-
included do
|
50
|
-
@default_member_class = nil
|
51
|
-
end
|
52
|
-
|
53
|
-
def members
|
54
|
-
self.class.default_member_class.any_in(:group_ids => [self.id])
|
55
|
-
end
|
56
|
-
|
57
|
-
def add(member)
|
58
|
-
member.groups << self
|
59
|
-
end
|
60
|
-
|
61
|
-
module ClassMethods
|
62
|
-
def with_member(member)
|
63
|
-
criteria.for_ids(member.group_ids)
|
64
|
-
end
|
65
|
-
|
66
|
-
def default_member_class; @default_member_class || User; end
|
67
|
-
def default_member_class=(klass); @default_member_class = klass; end
|
68
|
-
|
69
|
-
# Define which classes are members of this group
|
70
|
-
def has_members(name)
|
71
|
-
klass = name.to_s.classify.constantize
|
72
|
-
define_method name.to_s.pluralize.underscore do
|
73
|
-
klass.any_in(:group_ids => [self.id])
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Usage:
|
80
|
-
# class User
|
81
|
-
# acts_as_group_member
|
82
|
-
# ...
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# user.groups << group
|
86
|
-
#
|
87
|
-
module GroupMember
|
88
|
-
extend ActiveSupport::Concern
|
89
|
-
|
90
|
-
included do
|
91
|
-
group_class_name='Group' unless defined?(@group_class_name)
|
92
|
-
has_and_belongs_to_many :groups, :autosave => true, :inverse_of => nil, :class_name => @group_class_name
|
93
|
-
end
|
94
|
-
|
95
|
-
def in_group?(group)
|
96
|
-
self.groups.include?(group)
|
97
|
-
end
|
98
|
-
|
99
|
-
def in_any_group?(*groups)
|
100
|
-
groups.flatten.each do |group|
|
101
|
-
return true if in_group?(group)
|
102
|
-
end
|
103
|
-
return false
|
104
|
-
end
|
105
|
-
|
106
|
-
def in_all_groups?(*groups)
|
107
|
-
Set.new(groups.flatten) == Set.new(self.named_groups)
|
108
|
-
end
|
109
|
-
|
110
|
-
def shares_any_group?(other)
|
111
|
-
in_any_group?(other.groups)
|
112
|
-
end
|
113
|
-
|
114
|
-
module ClassMethods
|
115
|
-
def group_class_name; @group_class_name || 'Group'; end
|
116
|
-
def group_class_name=(klass); @group_class_name = klass; end
|
117
|
-
|
118
|
-
def in_group(group)
|
119
|
-
group.present? ? where(:group_ids.in => [group.id]) : none
|
120
|
-
end
|
121
|
-
|
122
|
-
def in_any_group(*groups)
|
123
|
-
groups.present? ? where(:group_ids.in => groups.flatten.map{|g|g.id}) : none
|
124
|
-
end
|
125
|
-
|
126
|
-
def in_all_groups(*groups)
|
127
|
-
groups.present? ? where(:group_ids => groups.flatten.map{|g|g.id}) : none
|
128
|
-
end
|
129
|
-
|
130
|
-
def shares_any_group(other)
|
131
|
-
in_any_group(other.groups)
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Usage:
|
138
|
-
# class User
|
139
|
-
# acts_as_named_group_member
|
140
|
-
# ...
|
141
|
-
# end
|
142
|
-
#
|
143
|
-
# user.named_groups << :admin
|
144
|
-
#
|
145
|
-
module NamedGroupMember
|
146
|
-
extend ActiveSupport::Concern
|
147
|
-
|
148
|
-
included do
|
149
|
-
field :named_groups, :type => Array, :default => []
|
150
|
-
|
151
|
-
before_save :uniq_named_groups
|
152
|
-
protected
|
153
|
-
def uniq_named_groups
|
154
|
-
named_groups.uniq!
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def in_named_group?(group)
|
159
|
-
self.named_groups.include?(group)
|
160
|
-
end
|
161
|
-
|
162
|
-
def in_any_named_group?(*groups)
|
163
|
-
groups.flatten.each do |group|
|
164
|
-
return true if in_named_group?(group)
|
165
|
-
end
|
166
|
-
return false
|
167
|
-
end
|
168
|
-
|
169
|
-
def in_all_named_groups?(*groups)
|
170
|
-
Set.new(groups.flatten) == Set.new(self.named_groups)
|
171
|
-
end
|
172
|
-
|
173
|
-
def shares_any_named_group?(other)
|
174
|
-
in_any_named_group?(other.named_groups)
|
175
|
-
end
|
176
|
-
|
177
|
-
module ClassMethods
|
178
|
-
def in_named_group(named_group)
|
179
|
-
named_group.present? ? where(:named_groups.in => [named_group]) : none
|
180
|
-
end
|
181
|
-
|
182
|
-
def in_any_named_group(*named_groups)
|
183
|
-
named_groups.present? ? where(:named_groups.in => named_groups.flatten) : none
|
184
|
-
end
|
185
|
-
|
186
|
-
def in_all_named_groups(*named_groups)
|
187
|
-
named_groups.present? ? where(:named_groups => named_groups.flatten) : none
|
188
|
-
end
|
189
|
-
|
190
|
-
def shares_any_named_group(other)
|
191
|
-
in_any_named_group(other.named_groups)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
Mongoid::Document.send :include, Groupify
|
3
|
+
require 'groupify/railtie' if defined?(Rails)
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
# Load database config
|
5
|
+
if JRUBY
|
6
|
+
require 'jdbc/sqlite3'
|
7
|
+
require 'active_record'
|
8
|
+
require 'active_record/connection_adapters/jdbcsqlite3_adapter'
|
9
|
+
else
|
10
|
+
require 'sqlite3'
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.before(:suite) do
|
15
|
+
DatabaseCleaner[:active_record].strategy = :transaction
|
16
|
+
end
|
17
|
+
|
18
|
+
config.before(:each) do
|
19
|
+
DatabaseCleaner[:active_record].start
|
20
|
+
end
|
21
|
+
|
22
|
+
config.after(:each) do
|
23
|
+
DatabaseCleaner[:active_record].clean
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
|
28
|
+
|
29
|
+
ActiveRecord::Migration.verbose = false
|
30
|
+
ActiveRecord::Schema.define(:version => 1) do
|
31
|
+
|
32
|
+
create_table :groups do |t|
|
33
|
+
t.string :name
|
34
|
+
t.string :type
|
35
|
+
end
|
36
|
+
|
37
|
+
create_table :group_memberships do |t|
|
38
|
+
t.string :member_type
|
39
|
+
t.integer :member_id
|
40
|
+
t.integer :group_id
|
41
|
+
t.string :group_name
|
42
|
+
end
|
43
|
+
|
44
|
+
create_table :users do |t|
|
45
|
+
t.string :name
|
46
|
+
t.string :type
|
47
|
+
end
|
48
|
+
|
49
|
+
create_table :widgets do |t|
|
50
|
+
t.string :name
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :organizations do |t|
|
54
|
+
t.string :name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
require 'groupify'
|
59
|
+
require 'groupify/adapter/active_record'
|
60
|
+
|
61
|
+
class User < ActiveRecord::Base
|
62
|
+
acts_as_group_member
|
63
|
+
acts_as_named_group_member
|
64
|
+
end
|
65
|
+
|
66
|
+
class Widget < ActiveRecord::Base
|
67
|
+
acts_as_group_member
|
68
|
+
end
|
69
|
+
|
70
|
+
class Group < ActiveRecord::Base
|
71
|
+
acts_as_group :members => [:users, :widgets], :default_members => :users
|
72
|
+
end
|
73
|
+
|
74
|
+
class Manager < User
|
75
|
+
end
|
76
|
+
|
77
|
+
class Organization < Group
|
78
|
+
has_members :managers
|
79
|
+
end
|
80
|
+
|
81
|
+
class GroupMembership < ActiveRecord::Base
|
82
|
+
acts_as_group_membership
|
83
|
+
end
|
84
|
+
|
85
|
+
describe Group do
|
86
|
+
it { should respond_to :members}
|
87
|
+
it { should respond_to :add }
|
88
|
+
end
|
89
|
+
|
90
|
+
describe User do
|
91
|
+
it { should respond_to :groups}
|
92
|
+
it { should respond_to :in_group?}
|
93
|
+
it { should respond_to :in_any_group?}
|
94
|
+
it { should respond_to :in_all_groups?}
|
95
|
+
it { should respond_to :shares_any_group?}
|
96
|
+
end
|
97
|
+
|
98
|
+
describe Groupify::ActiveRecord do
|
99
|
+
let(:user) { User.create! }
|
100
|
+
let(:group) { Group.create! }
|
101
|
+
let(:widget) { Widget.create! }
|
102
|
+
|
103
|
+
it "adds a group to a member" do
|
104
|
+
user.groups << group
|
105
|
+
user.groups.should include(group)
|
106
|
+
group.members.should include(user)
|
107
|
+
group.users.should include(user)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "adds a member to a group" do
|
111
|
+
group.add user
|
112
|
+
user.groups.should include(group)
|
113
|
+
group.members.should include(user)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'lists which member classes can belong to this group' do
|
117
|
+
group.class.member_classes.should include(User, Widget)
|
118
|
+
group.member_classes.should include(User, Widget)
|
119
|
+
|
120
|
+
Organization.member_classes.should include(User, Widget, Manager)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "finds members by group" do
|
124
|
+
group.add user
|
125
|
+
|
126
|
+
User.in_group(group).first.should eql(user)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "finds the group a member belongs to" do
|
130
|
+
group.add user
|
131
|
+
|
132
|
+
Group.with_member(user).first.should == group
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'when merging' do
|
136
|
+
let(:task) { Task.create! }
|
137
|
+
let(:manager) { Manager.create! }
|
138
|
+
|
139
|
+
it "moves the members from source to destination and destroys the source" do
|
140
|
+
source = Group.create!
|
141
|
+
destination = Organization.create!
|
142
|
+
|
143
|
+
source.add(user)
|
144
|
+
destination.add(manager)
|
145
|
+
|
146
|
+
destination.merge!(source)
|
147
|
+
source.destroyed?.should be_true
|
148
|
+
|
149
|
+
destination.users.should include(user, manager)
|
150
|
+
destination.managers.should include(manager)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "fails to merge if the destination group cannot contain the source group's members" do
|
154
|
+
source = Organization.create!
|
155
|
+
destination = Group.create!
|
156
|
+
|
157
|
+
source.add(manager)
|
158
|
+
destination.add(user)
|
159
|
+
|
160
|
+
# Managers cannot be members of a Group
|
161
|
+
expect {destination.merge!(source)}.to raise_error(ArgumentError)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "merges incompatible groups as long as all the source members can be moved to the destination" do
|
165
|
+
source = Organization.create!
|
166
|
+
destination = Group.create!
|
167
|
+
|
168
|
+
source.add(user)
|
169
|
+
destination.add(widget)
|
170
|
+
|
171
|
+
expect {destination.merge!(source)}.to_not raise_error
|
172
|
+
|
173
|
+
source.destroyed?.should be_true
|
174
|
+
destination.users.to_a.should include(user)
|
175
|
+
destination.widgets.to_a.should include(widget)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "members can belong to many groups" do
|
180
|
+
user.groups << group
|
181
|
+
group2 = Group.create!
|
182
|
+
user.groups << group2
|
183
|
+
|
184
|
+
user.groups.should include(group)
|
185
|
+
user.groups.should include(group2)
|
186
|
+
|
187
|
+
User.in_group(group).first.should eql(user)
|
188
|
+
User.in_group(group2).first.should eql(user)
|
189
|
+
|
190
|
+
User.in_any_group(group).first.should eql(user)
|
191
|
+
User.in_all_groups(group, group2).first.should eql(user)
|
192
|
+
User.in_all_groups([group, group2]).first.should eql(user)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "members can have named groups" do
|
196
|
+
user.named_groups << :admin
|
197
|
+
user.named_groups << :user
|
198
|
+
user.save
|
199
|
+
user.named_groups.should include(:admin)
|
200
|
+
|
201
|
+
user.in_named_group?(:admin).should be_true
|
202
|
+
user.in_any_named_group?(:admin, :user, :test).should be_true
|
203
|
+
user.in_all_named_groups?(:admin, :user).should be_true
|
204
|
+
user.in_all_named_groups?(:admin, :user, :test).should be_false
|
205
|
+
|
206
|
+
User.in_named_group(:admin).first.should eql(user)
|
207
|
+
User.in_any_named_group(:admin, :test).first.should eql(user)
|
208
|
+
User.in_all_named_groups(:admin, :user).first.should eql(user)
|
209
|
+
|
210
|
+
# Uniqueness
|
211
|
+
user.named_groups << :admin
|
212
|
+
user.save
|
213
|
+
user.named_groups.count{|g| g == :admin}.should == 1
|
214
|
+
end
|
215
|
+
|
216
|
+
it "members can check if groups are shared" do
|
217
|
+
user.groups << group
|
218
|
+
user2 = User.create!(:groups => [group])
|
219
|
+
|
220
|
+
user.shares_any_group?(user2).should be_true
|
221
|
+
User.shares_any_group(user).to_a.should include(user2)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "members can check if named groups are shared" do
|
225
|
+
user.named_groups << :admin
|
226
|
+
user2 = User.create!(:named_groups => [:admin])
|
227
|
+
|
228
|
+
user.shares_any_named_group?(user2).should be_true
|
229
|
+
User.shares_any_named_group(user).to_a.should include(user2)
|
230
|
+
end
|
231
|
+
end
|
File without changes
|