groupify 0.6.0.rc1 → 0.6.0.rc2

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.
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