groupify 0.6.0.rc1 → 0.6.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 688ba7945e95997b9bd71d248d9c8d0e17da2663
4
- data.tar.gz: 6e239d414dd7098a5d36e1517ac25827187ea55e
3
+ metadata.gz: 105996dc9352662d0363b74124dbb8f936b0d81b
4
+ data.tar.gz: 81479cdb755adba4da248918fcb891313279e772
5
5
  SHA512:
6
- metadata.gz: a9e8494ba575bf48cf3b1c439aba5fbfd512e08a51d998c48a84ea10738cd43d409c8588e053391a5f4a8da50b683dba8bf9ae57907c262d71a40fb930d0377f
7
- data.tar.gz: 2ee79e0d86e422250f1bc6859707ba439009eb5d8ef95e47998f87e492e983cce22bd7153703f8dc446f5688374e65e7a95bd364286ca3e0378febfe6829f14d
6
+ metadata.gz: 8fdd61ea3448ef18e8249c8680019ed21288c34c33738b695d660a1efaca29c3d55bb71ff9345f869d7d0d4086084092537fe0a183f2e963fb8aa62a92060315
7
+ data.tar.gz: 3c858406df76fe3cb960602e889bdd95cfde1d46c0addf5bbd70b03507e958a7d7448e0f79d42b7d65dbbc5b8665769af5ac284bfce18df35aad76d27fd244fe
data/.travis.yml CHANGED
@@ -5,6 +5,7 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - 2.1.1
8
+ - 2.1.2
8
9
  - jruby-19mode
9
10
  - rbx-2
10
11
  gemfile:
@@ -13,4 +14,4 @@ gemfile:
13
14
  - gemfiles/rails_4.1.gemfile
14
15
  matrix:
15
16
  allow_failures:
16
- - rvm: rbx-2
17
+ - rvm: rbx-2
data/Appraisals CHANGED
@@ -5,20 +5,11 @@ end
5
5
 
6
6
  appraise "rails-4.0" do
7
7
  gem 'activerecord', "~> 4.0.0"
8
-
9
- # TODO: Enable once Mongoid 4 is released
10
- #gem "mongoid", ">= 4.0"
11
-
12
- #gem "mongoid", github: "mongoid/mongoid", branch: "master"
13
- gem "mongoid", "4.0.0.rc2"
8
+ gem "mongoid", "~> 4.0"
14
9
  end
15
10
 
16
11
  appraise "rails-4.1" do
17
12
  gem 'activerecord', "~> 4.1.0"
18
13
 
19
- # TODO: Enable once Mongoid 4 is released
20
- #gem "mongoid", ">= 4.0"
21
-
22
- #gem "mongoid", :github => "mongoid/mongoid"
23
- gem "mongoid", "4.0.0.rc2"
14
+ gem "mongoid", "~> 4.0"
24
15
  end
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Groupify
2
- [![Build Status](https://secure.travis-ci.org/dwbutler/groupify.png)](http://travis-ci.org/dwbutler/groupify) [![Coverage Status](https://coveralls.io/repos/dwbutler/groupify/badge.png?branch=master)](https://coveralls.io/r/dwbutler/groupify?branch=master) [![Code Climate](https://codeclimate.com/github/dwbutler/groupify.png)](https://codeclimate.com/github/dwbutler/groupify) [![Dependency Status](https://gemnasium.com/dwbutler/groupify.png)](https://gemnasium.com/dwbutler/groupify)
2
+ [![Build Status](https://secure.travis-ci.org/dwbutler/groupify.png)](http://travis-ci.org/dwbutler/groupify) [![Coverage Status](https://coveralls.io/repos/dwbutler/groupify/badge.png?branch=master)](https://coveralls.io/r/dwbutler/groupify?branch=master) [![Code Climate](https://codeclimate.com/github/dwbutler/groupify.png)](https://codeclimate.com/github/dwbutler/groupify)
3
3
 
4
4
  Adds group and membership functionality to Rails models. Defines a polymorphic
5
5
  relationship between a Group model and any member model. Don't need a Group
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "jdbc-sqlite3", :platform => :jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
7
7
  gem "activerecord", "~> 4.0.0"
8
- gem "mongoid", "4.0.0.rc2"
8
+ gem "mongoid", "~> 4.0"
9
9
 
10
10
  group :development do
11
11
  gem "pry"
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gem "jdbc-sqlite3", :platform => :jruby
6
6
  gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
7
7
  gem "activerecord", "~> 4.1.0"
8
- gem "mongoid", "4.0.0.rc2"
8
+ gem "mongoid", "~> 4.0"
9
9
 
10
10
  group :development do
11
11
  gem "pry"
@@ -1,588 +1,14 @@
1
1
  require 'active_record'
2
2
  require 'set'
3
3
 
4
- # Groups and members
5
4
  module Groupify
6
5
  module ActiveRecord
7
- module Adapter
8
- extend ActiveSupport::Concern
9
-
10
- included do
11
- # Define a scope that returns nothing.
12
- # This is built into ActiveRecord 4, but not 3
13
- unless self.class.respond_to? :none
14
- def self.none
15
- where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
16
- end
17
- end
18
- end
19
-
20
- module ClassMethods
21
- def acts_as_group(opts = {})
22
- include Groupify::ActiveRecord::Group
6
+ require 'groupify/adapter/active_record/model'
23
7
 
24
- if (member_klass = opts.delete :default_members)
25
- self.default_member_class = member_klass.to_s.classify.constantize
26
- end
27
-
28
- if (member_klasses = opts.delete :members)
29
- member_klasses.each do |member_klass|
30
- has_members(member_klass)
31
- end
32
- end
33
- end
34
-
35
- def acts_as_group_member(opts = {})
36
- @group_class_name = opts[:class_name] || 'Group'
37
- include Groupify::ActiveRecord::GroupMember
38
- end
39
-
40
- def acts_as_named_group_member(opts = {})
41
- include Groupify::ActiveRecord::NamedGroupMember
42
- end
43
-
44
- def acts_as_group_membership(opts = {})
45
- include Groupify::ActiveRecord::GroupMembership
46
- end
47
- end
48
- end
49
-
50
- # Usage:
51
- # class Group < ActiveRecord::Base
52
- # acts_as_group, :members => [:users]
53
- # ...
54
- # end
55
- #
56
- # group.add(member)
57
- #
58
- module Group
59
- extend ActiveSupport::Concern
60
-
61
- included do
62
- @default_member_class = nil
63
- @member_klasses ||= Set.new
64
- has_many :group_memberships, :dependent => :destroy
65
- end
66
-
67
- def member_classes
68
- self.class.member_classes
69
- end
70
-
71
- def add(*args)
72
- opts = args.extract_options!
73
- membership_type = opts[:as]
74
- members = args.flatten
75
- return unless members.present?
76
-
77
- clear_association_cache
78
-
79
- members.each do |member|
80
- member.group_memberships.where(group_id: self.id).first_or_create!
81
- if membership_type
82
- member.group_memberships.where(group_id: self, membership_type: membership_type).first_or_create!
83
- end
84
- member.clear_association_cache
85
- end
86
- end
87
-
88
- # Merge a source group into this group.
89
- def merge!(source)
90
- self.class.merge!(source, self)
91
- end
92
-
93
- module ClassMethods
94
- def with_member(member)
95
- #joins(:group_memberships).where(:group_memberships => {:member_id => member.id, :member_type => member.class.to_s})
96
- member.groups
97
- end
98
-
99
- def default_member_class
100
- @default_member_class ||= (User rescue false)
101
- end
102
-
103
- def default_member_class=(klass)
104
- @default_member_class = klass
105
- end
106
-
107
- # Returns the member classes defined for this class, as well as for the super classes
108
- def member_classes
109
- (@member_klasses ||= Set.new).merge(superclass.method_defined?(:member_classes) ? superclass.member_classes : [])
110
- end
111
-
112
- # Define which classes are members of this group
113
- def has_members(name)
114
- klass = name.to_s.classify.constantize
115
- register(klass)
116
- end
117
-
118
- # Merge two groups. The members of the source become members of the destination, and the source is destroyed.
119
- def merge!(source_group, destination_group)
120
- # Ensure that all the members of the source can be members of the destination
121
- invalid_member_classes = (source_group.member_classes - destination_group.member_classes)
122
- invalid_member_classes.each do |klass|
123
- if klass.joins(:group_memberships).where(:group_memberships => {:group_id => source_group.id}).count > 0
124
- raise ArgumentError.new("#{source_group.class} has members that cannot belong to #{destination_group.class}")
125
- end
126
- end
127
-
128
- source_group.transaction do
129
- source_group.group_memberships.update_all(:group_id => destination_group.id)
130
- source_group.destroy
131
- end
132
- end
133
-
134
- protected
135
-
136
- def register(member_klass)
137
- (@member_klasses ||= Set.new) << member_klass
138
-
139
- associate_member_class(member_klass)
140
-
141
- member_klass
142
- end
143
-
144
- module MemberAssociationExtensions
145
- def as(membership_type)
146
- where(group_memberships: {membership_type: membership_type})
147
- end
148
-
149
- def delete(*args)
150
- opts = args.extract_options!
151
- members = args
152
-
153
- if opts[:as]
154
- proxy_association.owner.group_memberships.
155
- where(member_id: members.map(&:id), member_type: proxy_association.reflection.options[:source_type]).
156
- as(opts[:as]).
157
- delete_all
158
- else
159
- super(*members)
160
- end
161
- end
162
-
163
- def destroy(*args)
164
- opts = args.extract_options!
165
- members = args
166
-
167
- if opts[:as]
168
- proxy_association.owner.group_memberships.
169
- where(member_id: members.map(&:id), member_type: proxy_association.reflection.options[:source_type]).
170
- as(opts[:as]).
171
- destroy_all
172
- else
173
- super(*members)
174
- end
175
- end
176
- end
177
-
178
- def associate_member_class(member_klass)
179
- association_name = member_klass.name.to_s.pluralize.underscore.to_sym
180
- source_type = member_klass.base_class
181
-
182
- has_many association_name, through: :group_memberships, source: :member, source_type: source_type, extend: MemberAssociationExtensions
183
- override_member_accessor(association_name)
184
-
185
- if member_klass == default_member_class
186
- has_many :members, through: :group_memberships, source: :member, source_type: source_type, extend: MemberAssociationExtensions
187
- override_member_accessor(:members)
188
- end
189
- end
190
-
191
- def override_member_accessor(association_name)
192
- define_method(association_name) do |*args|
193
- opts = args.extract_options!
194
- membership_type = opts[:as]
195
- if membership_type.present?
196
- super().as(membership_type)
197
- else
198
- super()
199
- end
200
- end
201
- end
202
- end
203
- end
204
-
205
- # Join table that tracks which members belong to which groups
206
- #
207
- # Usage:
208
- # class GroupMembership < ActiveRecord::Base
209
- # acts_as_group_membership
210
- # ...
211
- # end
212
- #
213
- module GroupMembership
214
- extend ActiveSupport::Concern
215
-
216
- included do
217
- attr_accessible(:member, :group, :group_name, :membership_type, :as) if ActiveSupport::VERSION::MAJOR < 4
218
-
219
- belongs_to :member, :polymorphic => true
220
- belongs_to :group
221
- end
222
-
223
- def membership_type=(membership_type)
224
- self[:membership_type] = membership_type.to_s if membership_type.present?
225
- end
226
-
227
- def as=(membership_type)
228
- self.membership_type = membership_type
229
- end
230
-
231
- def as
232
- membership_type
233
- end
234
-
235
- module ClassMethods
236
- def named(group_name=nil)
237
- if group_name.present?
238
- where(group_name: group_name)
239
- else
240
- where("group_name IS NOT NULL")
241
- end
242
- end
243
-
244
- def as(membership_type)
245
- where(membership_type: membership_type)
246
- end
247
- end
248
- end
249
-
250
- # Usage:
251
- # class User < ActiveRecord::Base
252
- # acts_as_group_member
253
- # ...
254
- # end
255
- #
256
- # user.groups << group
257
- #
258
- module GroupMember
259
- extend ActiveSupport::Concern
260
-
261
- included do
262
- unless respond_to?(:group_memberships)
263
- has_many :group_memberships, :as => :member, :autosave => true, :dependent => :destroy
264
- end
265
-
266
- has_many :groups, :through => :group_memberships, :class_name => @group_class_name do
267
- def as(membership_type)
268
- return self unless membership_type
269
- where(group_memberships: {membership_type: membership_type})
270
- end
271
-
272
- def delete(*args)
273
- opts = args.extract_options!
274
- groups = args.flatten
275
-
276
- if opts[:as]
277
- proxy_association.owner.group_memberships.where(group_id: groups.map(&:id)).as(opts[:as]).delete_all
278
- else
279
- super(*groups)
280
- end
281
- end
282
-
283
- def destroy(*args)
284
- opts = args.extract_options!
285
- groups = args.flatten
286
-
287
- if opts[:as]
288
- proxy_association.owner.group_memberships.where(group_id: groups.map(&:id)).as(opts[:as]).destroy_all
289
- else
290
- super(*groups)
291
- end
292
- end
293
- end
294
- end
295
-
296
- def in_group?(group, opts={})
297
- criteria = {group_id: group.id}
298
-
299
- if opts[:as]
300
- criteria.merge!(membership_type: opts[:as])
301
- end
302
-
303
- group_memberships.exists?(criteria)
304
- end
305
-
306
- def in_any_group?(*args)
307
- opts = args.extract_options!
308
- groups = args
309
-
310
- groups.flatten.each do |group|
311
- return true if in_group?(group, opts)
312
- end
313
- return false
314
- end
315
-
316
- def in_all_groups?(*args)
317
- opts = args.extract_options!
318
- groups = args.flatten
319
-
320
- groups.to_set.subset? self.groups.as(opts[:as]).to_set
321
- end
322
-
323
- def in_only_groups?(*args)
324
- opts = args.extract_options!
325
- groups = args.flatten
326
-
327
- groups.to_set == self.groups.as(opts[:as]).to_set
328
- end
329
-
330
- def shares_any_group?(other, opts={})
331
- in_any_group?(other.groups, opts)
332
- end
333
-
334
- module ClassMethods
335
- def group_class_name; @group_class_name ||= 'Group'; end
336
- def group_class_name=(klass); @group_class_name = klass; end
337
-
338
- def as(membership_type)
339
- joins(:group_memberships).where(group_memberships: { membership_type: membership_type })
340
- end
341
-
342
- def in_group(group)
343
- return none unless group.present?
344
-
345
- joins(:group_memberships).where(group_memberships: { group_id: group.id }).uniq
346
- end
347
-
348
- def in_any_group(*groups)
349
- groups = groups.flatten
350
- return none unless groups.present?
351
-
352
- joins(:group_memberships).where(group_memberships: { group_id: groups.map(&:id) }).uniq
353
- end
354
-
355
- def in_all_groups(*groups)
356
- groups = groups.flatten
357
- return none unless groups.present?
358
-
359
- joins(:group_memberships).
360
- group(:"group_memberships.member_id").
361
- where(:group_memberships => {:group_id => groups.map(&:id)}).
362
- having("COUNT(group_memberships.group_id) = #{groups.count}").
363
- uniq
364
- end
365
-
366
- def in_only_groups(*groups)
367
- groups = groups.flatten
368
- return none unless groups.present?
369
-
370
- joins(:group_memberships).
371
- group(:"group_memberships.member_id").
372
- having("COUNT(DISTINCT group_memberships.group_id) = #{groups.count}").
373
- uniq
374
- end
375
-
376
- def shares_any_group(other)
377
- in_any_group(other.groups)
378
- end
379
-
380
- end
381
- end
382
-
383
- class NamedGroupCollection < Set
384
- def initialize(member)
385
- @member = member
386
- @named_group_memberships = member.group_memberships.named
387
- @group_names = @named_group_memberships.pluck(:group_name).map(&:to_sym)
388
- super(@group_names)
389
- end
390
-
391
- def add(named_group, opts={})
392
- named_group = named_group.to_sym
393
- membership_type = opts[:as]
394
-
395
- if @member.new_record?
396
- @member.group_memberships.build(group_name: named_group, membership_type: nil)
397
- else
398
- @member.transaction do
399
- @member.group_memberships.where(group_name: named_group, membership_type: nil).first_or_create!
400
- end
401
- end
402
-
403
- if membership_type
404
- if @member.new_record?
405
- @member.group_memberships.build(group_name: named_group, membership_type: membership_type)
406
- else
407
- @member.group_memberships.where(group_name: named_group, membership_type: membership_type).first_or_create!
408
- end
409
- end
410
-
411
- super(named_group)
412
- end
413
-
414
- alias_method :push, :add
415
- alias_method :<<, :add
416
-
417
- def merge(*args)
418
- opts = args.extract_options!
419
- named_groups = args.flatten
420
- named_groups.each do |named_group|
421
- add(named_group, opts)
422
- end
423
- end
424
-
425
- alias_method :concat, :merge
426
-
427
- def include?(named_group, opts={})
428
- named_group = named_group.to_sym
429
- if opts[:as]
430
- as(opts[:as]).include?(named_group)
431
- else
432
- super(named_group)
433
- end
434
- end
435
-
436
- def delete(*args)
437
- opts = args.extract_options!
438
- named_groups = args.flatten.compact
439
-
440
- remove(named_groups, :delete_all, opts)
441
- end
442
-
443
- def destroy(*args)
444
- opts = args.extract_options!
445
- named_groups = args.flatten.compact
446
-
447
- remove(named_groups, :destroy_all, opts)
448
- end
449
-
450
- def clear
451
- @named_group_memberships.delete_all
452
- super
453
- end
454
-
455
- alias_method :delete_all, :clear
456
- alias_method :destroy_all, :clear
457
-
458
- # Criteria to filter by membership type
459
- def as(membership_type)
460
- @named_group_memberships.as(membership_type).pluck(:group_name).map(&:to_sym)
461
- end
462
-
463
- protected
464
-
465
- def remove(named_groups, method, opts)
466
- if named_groups.present?
467
- scope = @named_group_memberships.where(group_name: named_groups)
468
-
469
- if opts[:as]
470
- scope = scope.where(membership_type: opts[:as])
471
- end
472
-
473
- scope.send(method)
474
-
475
- unless opts[:as]
476
- named_groups.each do |named_group|
477
- @hash.delete(named_group)
478
- end
479
- end
480
- end
481
- end
482
- end
483
-
484
-
485
- # Usage:
486
- # class User < ActiveRecord::Base
487
- # acts_as_named_group_member
488
- # ...
489
- # end
490
- #
491
- # user.named_groups << :admin
492
- #
493
- module NamedGroupMember
494
- extend ActiveSupport::Concern
495
-
496
- included do
497
- unless respond_to?(:group_memberships)
498
- has_many :group_memberships, :as => :member, :autosave => true, :dependent => :destroy
499
- end
500
- end
501
-
502
- def named_groups
503
- @named_groups ||= NamedGroupCollection.new(self)
504
- end
505
-
506
- def named_groups=(groups)
507
- groups.each do |group|
508
- self.named_groups << group
509
- end
510
- end
511
-
512
- def in_named_group?(named_group, opts={})
513
- named_groups.include?(named_group, opts)
514
- end
515
-
516
- def in_any_named_group?(*args)
517
- opts = args.extract_options!
518
- named_groups = args.flatten
519
- named_groups.each do |named_group|
520
- return true if in_named_group?(named_group, opts)
521
- end
522
- return false
523
- end
524
-
525
- def in_all_named_groups?(*args)
526
- opts = args.extract_options!
527
- named_groups = args.flatten.to_set
528
- named_groups.subset? self.named_groups.as(opts[:as]).to_set
529
- end
530
-
531
- def in_only_named_groups?(*args)
532
- opts = args.extract_options!
533
- named_groups = args.flatten.to_set
534
- named_groups == self.named_groups.as(opts[:as]).to_set
535
- end
536
-
537
- def shares_any_named_group?(other, opts={})
538
- in_any_named_group?(other.named_groups.to_a, opts)
539
- end
540
-
541
- module ClassMethods
542
- def as(membership_type)
543
- joins(:group_memberships).where(group_memberships: {membership_type: membership_type})
544
- end
545
-
546
- def in_named_group(named_group)
547
- return none unless named_group.present?
548
-
549
- joins(:group_memberships).where(group_memberships: {group_name: named_group}).uniq
550
- end
551
-
552
- def in_any_named_group(*named_groups)
553
- named_groups.flatten!
554
- return none unless named_groups.present?
555
-
556
- joins(:group_memberships).where(group_memberships: {group_name: named_groups.flatten}).uniq
557
- end
558
-
559
- def in_all_named_groups(*named_groups)
560
- named_groups.flatten!
561
- return none unless named_groups.present?
562
-
563
- joins(:group_memberships).
564
- group(:"group_memberships.member_id").
565
- where(:group_memberships => {:group_name => named_groups}).
566
- having("COUNT(DISTINCT group_memberships.group_name) = #{named_groups.count}").
567
- uniq
568
- end
569
-
570
- def in_only_named_groups(*named_groups)
571
- named_groups.flatten!
572
- return none unless named_groups.present?
573
-
574
- joins(:group_memberships).
575
- group("group_memberships.member_id").
576
- having("COUNT(DISTINCT group_memberships.group_name) = #{named_groups.count}").
577
- uniq
578
- end
579
-
580
- def shares_any_named_group(other)
581
- in_any_named_group(other.named_groups.to_a)
582
- end
583
- end
584
- end
8
+ autoload :Group, 'groupify/adapter/active_record/group'
9
+ autoload :GroupMember, 'groupify/adapter/active_record/group_member'
10
+ autoload :GroupMembership, 'groupify/adapter/active_record/group_membership'
11
+ autoload :NamedGroupCollection, 'groupify/adapter/active_record/named_group_collection'
12
+ autoload :NamedGroupMember, 'groupify/adapter/active_record/named_group_member'
585
13
  end
586
14
  end
587
-
588
- ActiveRecord::Base.send :include, Groupify::ActiveRecord::Adapter