troles 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Design.textile +68 -0
  2. data/Gemfile +9 -7
  3. data/Gemfile.lock +81 -76
  4. data/README.textile +63 -170
  5. data/VERSION +1 -1
  6. data/lib/trole.rb +2 -2
  7. data/lib/trole_groups/storage/base_many.rb +16 -5
  8. data/lib/troles/adapters/active_record/config.rb +19 -5
  9. data/lib/troles/api/config.rb +1 -1
  10. data/lib/troles/api/core.rb +4 -4
  11. data/lib/troles/common/api/core.rb +13 -14
  12. data/lib/troles/common/api/read.rb +6 -0
  13. data/lib/troles/common/api.rb +3 -2
  14. data/lib/troles/common/config/schema/helpers.rb +30 -11
  15. data/lib/troles/common/config/schema/role_helpers.rb +5 -5
  16. data/lib/troles/common/config/valid_roles.rb +4 -3
  17. data/lib/troles/common/dependencies.rb +1 -1
  18. data/lib/troles/common/storage.rb +16 -4
  19. data/lib/troles/common.rb +2 -2
  20. data/lib/troles/config.rb +4 -4
  21. data/lib/troles/storage/join_ref_many.rb +13 -0
  22. data/lib/troles/storage.rb +6 -5
  23. data/lib/troles.rb +3 -8
  24. data/spec/active_record/migrations/many/custom_join.rb +31 -0
  25. data/spec/active_record/migrations/many/join_ref_many.rb +31 -0
  26. data/spec/active_record/migrations/many/ref_many.rb +0 -8
  27. data/spec/active_record/models/custom_join.rb +13 -0
  28. data/spec/active_record/models/join_ref_many.rb +13 -0
  29. data/spec/active_record/models/ref_many.rb +0 -2
  30. data/spec/active_record/strategies/many/custom_join_spec.rb +46 -0
  31. data/spec/active_record/strategies/many/join_ref_many_spec.rb +46 -0
  32. data/spec/active_record/strategies/many/ref_many_spec.rb +2 -2
  33. data/spec/generic/models/base_user.rb +2 -1
  34. data/spec/trole/strategies/embed_one_spec.rb +1 -1
  35. data/spec/trole/strategies/ref_one_spec.rb +1 -1
  36. data/spec/trole/strategies/string_one_spec.rb +1 -1
  37. data/spec/troles/common/multi_roles_spec.rb +7 -13
  38. data/spec/troles/strategies/bit_many_spec.rb +1 -1
  39. data/spec/troles/strategies/embed_many_spec.rb +1 -1
  40. data/spec/troles/strategies/ref_many_spec.rb +1 -1
  41. data/spec/troles/strategies/string_many_spec.rb +1 -1
  42. data/spec/troles/strategy_helper.rb +1 -1
  43. data/troles.gemspec +38 -24
  44. metadata +72 -42
data/README.textile CHANGED
@@ -13,75 +13,6 @@ The roles list cache of a role subject (fx a user) is only updated (retrieved fr
13
13
 
14
14
  Note: Troles is a full redesign of _roles generic_ and company, using lessons learned. Troles uses a much cleaner design. It is aimed at being easy to extend and easy to create adapters for etc.
15
15
 
16
- h2. Status June 7, 2011
17
-
18
- I'm now in the process of implementing TroleGroups! Finally a fully integrated role groups solution for Ruby and Rails ;)
19
- Due to the flexible design ot troles and trole, I can reuse the same infrastructure/design/architecture to implement trole_groups!
20
- *Yiii...haaa!*
21
-
22
- "A RoleGroup is simply another role_subject and can thus be configured with a given role strategy!"
23
-
24
- Simple and Sweet :)
25
-
26
- h2. The Ruby Class Decorator (RCD) pattern is born!!!
27
-
28
- I realized a while ago that I had come upon a very cool kind of "class decorator" design pattern that can be generalized to any gem that "decorates" a class (or perhaps multiple classes) with certain behavior. Gems such as _act_as_xxx_ come to mind fx.
29
-
30
- I will soon try to generalize this pattern into a separate project and then have trole, troles and trole_groups all use this to leverage their functionality. Also, I will make use of an idea that I just had while taking a cold shower (try it sometime if you have a mind block!).
31
- The idea is to have an internal default API, and an exposed API that by default is a reflection of the internal API. However the user is free to block parts of the API from being loaded or define his own external API that utilizes the inner API.
32
-
33
- Since this is a general purpose decorator pattern, there should also be a kind of Index where you can see which decorators have been applied to an object and what API each such decorator exposes! Cool stuff!!!!
34
-
35
- Some example usage:
36
- <pre>
37
- return if !User.has_decorator?(:troles_group)
38
- # do some trole group stuff!!!
39
-
40
- # later ...
41
-
42
- # list all decorators currently applied to the User class
43
- puts User.decorators
44
-
45
- # print the methods of the public Write API for the :troles_group decorator :)
46
- puts User.decorator(:troles_group).public_api(:write).methods.sort
47
-
48
- # print the methods of the internal Write API for the :troles_group decorator :)
49
- puts User.decorator(:troles_group).internal_api(:write).methods.sort
50
- </pre>
51
-
52
- I will use the new Decorator API very soon... sth like this:
53
-
54
- <pre>
55
- User.decorator(:trole_groups).configure(:strategy) :ref_one do |strategy|
56
- strategy.orm = :mongoid
57
- strategy.auto_load = true
58
- end.configure!
59
- </pre>
60
-
61
- Awesome!
62
-
63
- h3. Yard documentation
64
-
65
- I'm using "Yard":http://rubydoc.info/docs/yard/file/docs/GettingStarted.md for documentation.
66
-
67
- <pre>$ yard server
68
-
69
- From browser, go to: http://0.0.0.0:8808/ # then you can enjoy! the nice documentation :)
70
- </pre>
71
-
72
- There is now support for Caching and invalidation of the _role_list_ when the roles change.
73
- The specs now validate that caching works as it should.
74
-
75
- Please help out to finalize this project! :)
76
-
77
- h2. Bug hunting by running specs
78
-
79
- Run specs for at most one strategy at the time for now...
80
-
81
- @$ rspec spec/troles/strategies/bit_many_spec.rb@
82
-
83
- Please see the document _spec/Guide to running specs.textile_ where I advise on how best to do "bug hunting" to help get this project off the ground!
84
-
85
16
  h2. Role strategies
86
17
 
87
18
  The following lists the role strategies to be supported
@@ -131,47 +62,47 @@ These strategies can be implemented for any data store using any schema format.
131
62
 
132
63
  h3. Using roles strategies with Users and User accounts
133
64
 
134
- Roles are assigned to role subject classes such as _User_ or _UserAccount_ (YES, Devise can have multiple user accounts!). The class that has a role strategy assigned is referred to as the _role subject class_.
135
- Different role subject classes can have different role strategies!
65
+ Roles are assigned to role subject classes such as _User_ or _UserAccount_ (YES, Devise can have multiple user accounts!). The class that has a role strategy assigned is referred to as the _role subject class_. Different role subject classes can have different role strategies!
136
66
 
137
67
  When using Devise this could translate fx into a UserAccount with a "many roles" strategy and an AdminAccount with a "single role" strategy (or vice versa).
138
68
 
139
69
  Example:
140
70
 
141
- <pre>
142
- require 'troles'
143
- require 'troles/macros'
144
-
145
- class UserAccount
146
- troles_strategy(:string_many).configure!
147
- end
71
+ <pre>require 'troles'
72
+ require 'troles/macros'
148
73
 
149
- class AdminAccount
150
- troles_strategy(:bit_one, :static => true).configure!
151
- end
74
+ class UserAccount
75
+ troles_strategy(:string_many).configure!
76
+ end
77
+
78
+ class AdminAccount
79
+ troles_strategy(:bit_one, :static => true).configure!
80
+ end
152
81
  </pre>
153
82
 
154
- The special troles macros must be enabled my requiring the _trole/macros_ file.
83
+ The special troles macros must currently be enabled my requiring the _troles/macros_ file.
84
+ If the troles macros are not included like this, the troles DSL can be made available for an individual class by including a specific Strategy.
85
+ Using the macros like in the above example is much easier and is recommended.
155
86
 
156
87
  h3. Macro options
157
88
 
158
89
  The @:static => true@ options is used to indicate, that the role can not be changed after being initially set.
159
- But we are getting ahead of ourselves... (more on this later).
160
- Troles can easily be extended to support other macro options if needed.
90
+ But we are getting ahead of ourselves... (more on this later). Troles can easily be extended to support other macro options if needed.
91
+ Note: This static roles functionality is currently in-progress... (used to work but under change).
161
92
 
162
93
  h2. Roles API
163
94
 
164
95
  The Roles API can be divided into:
165
96
 
166
97
  * Core
167
- * Event/Cache
98
+ * Event
99
+ * Cache
168
100
  * Read
169
101
  * Write
170
- * Store
171
102
  * Validation
172
103
  * Operations object
173
104
 
174
- There is an equivalen Trole API for single role strategies.
105
+ There is an equivalent Trole API for single role strategies.
175
106
 
176
107
  h3. Event/Cache API
177
108
 
@@ -181,46 +112,33 @@ can have subscribers to events.
181
112
 
182
113
  Also any write event to the datastore should be predicated on _#static_roles?_ not being true for the user (thus ensuring guest roles are never updated).
183
114
 
184
- Save triggers call to Event#update_roles
185
- <pre>
186
- User
187
- after_save: update_roles # event handler
188
- </pre>
189
-
190
- <pre>
191
- module Troles::Api::Event
192
- def update_roles
193
- def publish_change event
194
- </pre>
115
+ @User.after_save: update_roles # event handler@
195
116
 
196
117
  h3. Roles Read API
197
118
 
198
119
  This API operates directly on a user, fx _user#has_role?_
199
120
 
200
- <pre>
201
- user.has_role? :admin
202
- user.is_role? :editor
203
- user.has_any_roles? :editor, :admin
121
+ <pre>user.has_role? :admin
122
+ user.is_role? :editor
123
+ user.has_any_roles? :editor, :admin
204
124
  </pre>
205
125
 
206
126
  h3. Roles Write API
207
127
 
208
128
  This API operates directly on a user, fx _user#has_role?_
209
129
 
210
- <pre>
211
- user.add_role :admin
212
- user.remove_role :editor
130
+ <pre>user.add_role :admin
131
+ user.remove_role :editor
213
132
  </pre>
214
133
 
215
134
  h3. Roles Operations object
216
135
 
217
136
  The Roles Operations object is available on user#roles
218
137
 
219
- <pre>
220
- user.roles + :admin
221
- user.roles - :editor
222
- user.roles << [:editor, :admin]
223
- user.roles.clear!
138
+ <pre>user.roles + :admin
139
+ user.roles - :editor
140
+ user.roles << [:editor, :admin]
141
+ user.roles.clear!
224
142
  </pre>
225
143
 
226
144
  h3. Creating a custom Data Store Adapter (DSA)
@@ -231,11 +149,9 @@ Note that :single role strategies always have the namespace 'Trole' whereas for
231
149
 
232
150
  A custom Config class for _:single_ role strategies using _Mongoid_ could look sth. like this:
233
151
 
234
- <pre>
235
- module Trole::Mongoid
152
+ <pre>module Trole::Mongoid
236
153
  class Config < Troles::Common::Config
237
-
238
- def initialize subject_class, options = {}
154
+ def initialize subject, options = {}
239
155
  super
240
156
  end
241
157
 
@@ -265,8 +181,7 @@ See the _schema_helpers.rb_ file for more details!
265
181
 
266
182
  Example: Config class for :many roles strategies with _Mongoid_
267
183
 
268
- <pre>
269
- module Troles::Mongoid
184
+ <pre>module Troles::Mongoid
270
185
  class Config < Troles::Common::Config
271
186
 
272
187
  def initialize subject_class, options = {}
@@ -305,8 +220,7 @@ Note: #set_role is only required for :single role strategies. In this case #set_
305
220
 
306
221
  Example custom SSA (encrypted role string):
307
222
 
308
- <pre>
309
- module Trole::Storage
223
+ <pre>module Trole::Storage
310
224
  module EncryptedStringOne < BaseOne
311
225
  def initialize role_subject
312
226
  super
@@ -344,8 +258,7 @@ h3. Custom Storage for an ORM (or data store)
344
258
 
345
259
  In some cases it is useful to rewrite part of the base Storage functionality. One such method is #find_roles.
346
260
 
347
- <pre>
348
- module Troles::Storage
261
+ <pre>module Troles::Storage
349
262
  class BaseMany < Troles::Common::Storage
350
263
  def find_roles *roles
351
264
  role_model.where(:name => roles.flatten).all
@@ -357,8 +270,7 @@ end
357
270
  Active Record and Mongoid both implement the above API, so no need to customize this method in the Storage adapter.
358
271
  For most other ORMs/data stores you will likely have to write your own logic to achieve this.
359
272
 
360
- <pre>
361
- module Troles::MongoidStorage
273
+ <pre>module Troles::MongoidStorage
362
274
  class RefMany < Troles::Storage::BaseMany
363
275
 
364
276
  def find_roles *roles
@@ -371,10 +283,9 @@ h3. Custom data marshaller
371
283
 
372
284
  You can also use a custom "Marshaller":http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29 to store the roles in a non-standard format. This is used for the _BitMany_ strategy, which has a special _Marshaller::BitMask_ class which handles conversion between a list of symbols to an _Integer_ bitmap representing it (relative to a valid roles list!). You can create your own _Marshaller_, fx to encrypt the roles info or whatever you like!
373
285
 
374
- <pre>
375
- module Troles::Marshaller
286
+ <pre>module Troles::Marshaller
376
287
  class Encryption < Generic
377
- def initialize role_subject
288
+ def initialize subject
378
289
  super
379
290
  end
380
291
 
@@ -395,8 +306,7 @@ h3. Using a custom Marshaller in a Storage implementation
395
306
 
396
307
  The following example is taken from the BitOne Storage implementation that is part of troles:
397
308
 
398
- <pre>
399
- require 'troles/common/marshaller'
309
+ <pre>require 'troles/common/marshaller'
400
310
 
401
311
  module Trole::Storage
402
312
  class BitOne < BaseOne
@@ -432,10 +342,9 @@ Note that the same _BitMask_ marshaller is also reused in the _BitMany_ storage!
432
342
 
433
343
  The _#bitmask_ method returns an instance of the _Bitmask_ marshaller, instantiated with the _role_subject_ (the instance that has the #role_list method, typically the user or user account). To use the _Encryption_ marshaller in an Encryption storage we could create a _#marshaller_ method:
434
344
 
435
- <pre>
436
- def marshaller
437
- @marshaller ||= Troles::Marshaller::Encryption.new role_subject
438
- end
345
+ <pre>def marshaller
346
+ @marshaller ||= Troles::Marshaller::Encryption.new role_subject
347
+ end
439
348
  </pre>
440
349
 
441
350
  Then use @marshaller.write(*roles)@ in the _set_xxxx_ methods and @marshaller.read@ in _#display_roles_ method of the storage, as needed.
@@ -456,8 +365,7 @@ You rarely need to implement a custom Strategy module or custom API implementati
456
365
  Here is an example of a custom Strategy implementation for _EncryptedStringMany_ that simply wraps the _BaseMany_ strategy implementation.
457
366
  This example demonstrates how you can easily override functionality with custom implementations by including modules "on top".
458
367
 
459
- <pre>
460
- module Troles::Strategy
368
+ <pre>module Troles::Strategy
461
369
  module EncryptedStringMany
462
370
 
463
371
  # What to add to the role subject class when this role strategy is included
@@ -485,28 +393,25 @@ In some cases you need a custom Base strategy that contains common functionality
485
393
 
486
394
  Example: _BaseMany_, used as the base for all Many roles strategies
487
395
 
488
- <pre>
489
- module Troles::Mongoid
490
- module Strategy
491
- module BaseMany
492
- # @param [Class] the role subject class for which to include the Role strategy (fx User Account)
493
- #
494
- def self.included(base)
495
- base.send :include, Troles::Strategy::BaseMany
496
-
497
- # base.send :include, InstanceMethods
498
- # base.extend ClassMethods
499
- end
396
+ <pre>module Troles::Mongoid
397
+ module Strategy
398
+ module BaseMany
399
+ # @param [Class] the role subject class for which to include the Role strategy (fx User Account)
400
+ #
401
+ def self.included(base)
402
+ base.send :include, Troles::Strategy::BaseMany
403
+
404
+ # base.send :include, InstanceMethods
405
+ # base.extend ClassMethods
500
406
  end
501
407
  end
502
408
  end
409
+ end
503
410
  </pre>
504
411
 
505
412
  To use your adapter, simply pass an extra option to the _troles_strategy_ macro:
506
413
 
507
- <pre>
508
- User.troles_strategy(:bit_one, :orm => :mongoid).configure!
509
- </pre>
414
+ @User.troles_strategy(:bit_one, :orm => :mongoid).configure!@
510
415
 
511
416
  This even allows you to use different ORM role strategies/storages for different user accounts simultaneously!!!
512
417
 
@@ -514,22 +419,17 @@ Using the :auto_load option will 'auto load' (i.e require) the orm adapter from
514
419
  You can include a specific custom (or 3rd party) adapter manually. In the future it will be possible to configure troles with adapters
515
420
  and specify how/where to load them from as part of this configuration!
516
421
 
517
- <pre>
518
- User.troles_strategy(:bit_one, :orm => :mongoid, :auto_load => true).configure!
519
- </pre>
422
+ @User.troles_strategy(:bit_one, :orm => :mongoid, :auto_load => true).configure!@
520
423
 
521
424
  You can also specify some of the options relevant to model configuration on the call to #configure if you like ;)
522
425
 
523
- <pre>
524
- User.troles_strategy(:bit_one, :orm => :active_record, :auto_load => true).configure! :role_model => 'Troll'
525
- </pre>
426
+ @User.troles_strategy(:bit_one, :orm => :active_record, :auto_load => true).configure! :role_model => 'Troll'@
526
427
 
527
428
  The _troles_strategy_ macro will yield the Config object if you pass it a block.
528
429
  This allows you to configure your stategy with troles inside the block and then call _configure!_ on end of the block.
529
430
  Using all this in combination, you could configure it all doing sth. like this:
530
431
 
531
- <pre>
532
- require 'my/own/active_record/adapter'
432
+ <pre>require 'my/own/active_record/adapter'
533
433
 
534
434
  User.troles_strategy :bit_one, :orm => :active_record do |c|
535
435
  c.auto_load = false
@@ -591,14 +491,13 @@ _troles_ will be part of a larger project under development that will go under t
591
491
 
592
492
  h3. Guest users
593
493
 
594
- From the Devise wiki: https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
494
+ From the "Devise wiki":https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
595
495
 
596
496
  "In some applications, it's useful to have a guest User object to pass around even before the (human) user has registered or logged in. Normally, you want this guest user to persist as long as the browser session persists.
597
497
 
598
498
  Our approach is to create a guest user object in the database and store its id in session[:guest_user_id]. When (and if) the user registers or logs in, we delete the guest user and clear the session variable. A helper function, current_or_guest_user, returns guest_user if the user is not logged in and current_user if the user is logged in."
599
499
 
600
- <pre>
601
- module ApplicationHelper
500
+ <pre>module ApplicationHelper
602
501
  ...
603
502
  # if user is logged in, return current_user, else return guest_user
604
503
  def current_or_guest_user
@@ -631,9 +530,7 @@ end
631
530
 
632
531
  In the new system, I propose the following:
633
532
 
634
- <pre>
635
-
636
- # this will make the current user the guest user account for the given scope!
533
+ <pre># this will make the current user the guest user account for the given scope!
637
534
  def sign_in_guest scope, options = {}
638
535
  warden.set_user(guest_user.account, options.merge!(:scope => scope))
639
536
  end
@@ -665,8 +562,7 @@ def guest_user
665
562
  end
666
563
  </pre>
667
564
 
668
- <pre>
669
- class GuestUserAccount
565
+ <pre>class GuestUserAccount
670
566
  troles_strategy(:static_one, :role => :guest) do |c|
671
567
  # c.valid_roles = [:guest] not needed!
672
568
  end.configure!
@@ -685,8 +581,7 @@ end
685
581
 
686
582
  Here the special _:static_many_ strategy is used, which means that whatever the _role_list_ is first set to can never change for that user.
687
583
 
688
- <pre>
689
- module BaseAccount
584
+ <pre>module BaseAccount
690
585
  # transfer guest settings to logged_in user/account
691
586
  def transfer_guest(guest_user)
692
587
  end
@@ -711,8 +606,7 @@ end
711
606
 
712
607
  And here the User setup:
713
608
 
714
- <pre>
715
- module BaseUser
609
+ <pre>module BaseUser
716
610
  end
717
611
 
718
612
  class User
@@ -726,8 +620,7 @@ class User
726
620
  end
727
621
  </pre>
728
622
 
729
- <pre>
730
- class GuestUser
623
+ <pre>class GuestUser
731
624
  include BaseUser
732
625
 
733
626
  def account
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.1
1
+ 0.5.2
data/lib/trole.rb CHANGED
@@ -5,6 +5,6 @@ module Trole
5
5
  autoload :Config, 'trole/config'
6
6
  autoload :Api, 'trole/api'
7
7
  autoload :Operations, 'trole/operations'
8
- autoload :Strategy, 'trole/strategy'
8
+ autoload :Strategy, 'trole/strategy'
9
9
  autoload :Storage, 'trole/storage'
10
- end
10
+ end
@@ -28,7 +28,11 @@ module TroleGroups
28
28
  # sets the value of the role field (@trole or @troles) and persists the value (in the data store)
29
29
  # @param [Object] the value to set on the role field of the role subject
30
30
  def set_ds_field value
31
- return if ds_field_value == value
31
+ return if ds_field_value == value
32
+ if Troles::Common::Config.log_on?
33
+ puts "TroleGroups::Storage::BaseMany.set_ds_field:"
34
+ puts "#{rolegroup_subject}.#{ds_field_name} = #{value}"
35
+ end
32
36
  rolegroup_subject.send(:"#{ds_field_name}=", value)
33
37
  persist_role_changes!
34
38
  end
@@ -42,15 +46,22 @@ module TroleGroups
42
46
  # the current value of the role field
43
47
  # @return [Object] the value
44
48
  def ds_field_value
49
+ # puts "#{rolegroup_subject}.#{ds_field_name}" if Troles::Common::Config.log_on?
45
50
  rolegroup_subject.send(ds_field_name)
46
51
  end
47
52
 
48
53
  # Attempts to persist the role field changes
49
54
  # @return [true, false, error] true if saved, false if no save! method, Error on some error
50
- def persist_role_changes!
51
- return false if !rolegroup_subject.respond_to? :save!
52
- rolegroup_subject.save!
53
- rolegroup_subject.publish_change :role_groups
55
+ def persist_role_changes!
56
+ puts "TroleGroups::Storage::BaseMany.persist_role_changes!" if Troles::Common::Config.log_on?
57
+ if !rolegroup_subject.respond_to? :save
58
+ puts "could not save since no #save method on subject: #{rolegroup_subject}" if Troles::Common::Config.log_on?
59
+ return false
60
+ else
61
+ puts "#{rolegroup_subject}.save" if Troles::Common::Config.log_on?
62
+ rolegroup_subject.save
63
+ rolegroup_subject.publish_change :role_groups
64
+ end
54
65
  end
55
66
 
56
67
  protected
@@ -7,8 +7,10 @@ module Troles::ActiveRecord
7
7
 
8
8
  def configure_relation
9
9
  case strategy
10
+ when :join_ref_many
11
+ configure_join_model
10
12
  when :ref_many
11
- return configure_join_model if role_join_model
13
+ return configure_join_model if join_model
12
14
  has_and_belongs_many subject_class, object_model, :key => :accounts
13
15
  when :embed_many
14
16
  raise "Embed many configuration not yet implemented for ActiveRecord"
@@ -25,6 +27,11 @@ module Troles::ActiveRecord
25
27
  role_model
26
28
  end
27
29
 
30
+ def join_model
31
+ role_join_model
32
+ end
33
+
34
+
28
35
  def role_join_model
29
36
  @join_model_found ||= begin
30
37
  models = [@join_model, join_model_best_guess].select do |class_name|
@@ -50,10 +57,17 @@ module Troles::ActiveRecord
50
57
  make_key role_join_model
51
58
  end
52
59
 
53
- def configure_join_model
60
+ def configure_join_model
61
+ if Troles::Common::Config.log_on?
62
+ puts "configuring join model..."
63
+ puts "Subject class: #{subject_class}"
64
+ puts "Role class: #{object_model}"
65
+ puts "Join class: #{join_model}"
66
+ end
67
+
54
68
  # UserAccount
55
69
  # has_many :troles, :class_name => 'Role', :through => :users_roles
56
- has_many_for subject_class, role_model, :through => join_key
70
+ has_many_for subject_class, object_model, :opts => {:through => join_key.to_sym}
57
71
  # has_many :user_roles, :class_name => 'UserRole'
58
72
  has_many_for subject_class, role_join_model, :key => join_key
59
73
 
@@ -65,10 +79,10 @@ module Troles::ActiveRecord
65
79
 
66
80
  # Role
67
81
  # has_many :accounts, :class_name => 'User', :through => :user_roles
68
- has_many_for role, subject_class, :through => join_key, :key => :accounts
82
+ has_many_for object_model, subject_class, :key => :accounts, :opts => {:through => join_key.to_sym}
69
83
 
70
84
  # has_many :user_roles, :class_name => 'UserRole'
71
- has_many_for role, role_join_model, :key => join_key
85
+ has_many_for object_model, role_join_model, :key => join_key
72
86
  end
73
87
  end
74
88
  end
@@ -5,5 +5,5 @@
5
5
  #
6
6
  module Troles::Api
7
7
  module Config
8
- end
8
+ end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  module Troles::Api
2
- module Core
3
- module ClassMethods
2
+ module Core
3
+ module ClassMethods
4
4
  def role_field
5
5
  troles_config.role_field
6
- end
6
+ end
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -5,18 +5,18 @@
5
5
  #
6
6
  module Troles::Common::Api
7
7
  module Core
8
-
8
+
9
9
  # Access to the Troles operations API
10
10
  # @return [Troles::Operations] the operations API object
11
11
  def roles
12
12
  @roles ||= Troles::Operations.new(self)
13
- end
13
+ end
14
14
 
15
15
  # Sets the roles of the subject
16
16
  # (see #set_roles)
17
17
  def roles= *new_roles
18
18
  roles.set_roles new_roles
19
- end
19
+ end
20
20
 
21
21
  # If this role subject instance should have static (immutable) roles
22
22
  # @return [true, false] defaults to false so a role subject is allowed to change roles
@@ -25,28 +25,27 @@ module Troles::Common::Api
25
25
  end
26
26
 
27
27
  def troles_config
28
- self.class.troles_config
28
+ self.class.troles_config
29
29
  end
30
-
31
- module ClassMethods
32
-
30
+
31
+ module ClassMethods
32
+
33
33
  def valid_roles
34
34
  troles_config.valid_roles
35
35
  end
36
36
 
37
- # # TODO: make sure alphanumeric only
38
- # def valid_roles= *roles
39
- # troles_config.valid_roles = *roles
40
- # end
37
+ def valid_roles= *roles
38
+ troles_config.valid_roles = roles.flatten.map{|r| r.to_s.alpha_numeric}.map(&:to_sym).uniq
39
+ end
41
40
 
42
41
  # If all role subjects using this strategy should have static (immutable) roles
43
42
  #
44
- # @note Should also proxy Config object?
43
+ # @note Should also proxy Config object?
45
44
  #
46
45
  # @return [true, false] if role subjects have static roles or not (default: false)
47
46
  def static_roles?
48
47
  troles_config.static_roles?
49
- end
48
+ end
50
49
  end
51
50
  end
52
- end
51
+ end
@@ -39,6 +39,12 @@ module Troles::Common::Api
39
39
  # (see #has_roles?)
40
40
  def has_any_role? *roles
41
41
  !(role_list & roles.to_symbols).empty?
42
+ end
43
+
44
+ # Checks if the role subject has any of the listed roles
45
+ # (see #has_roles?)
46
+ def has_all_roles? *roles
47
+ (roles.to_symbols - role_list).empty?
42
48
  end
43
49
  end
44
50
  end
@@ -15,14 +15,15 @@ module Troles::Common
15
15
  end
16
16
 
17
17
  def included(base)
18
+ puts "Included #{base}"
18
19
  apis.each do |api|
19
20
  begin
20
21
  base.include_and_extend :"#{api.to_s.camelize}"
21
22
  rescue
22
23
  end
23
- end
24
+ end
24
25
  end
25
26
  end
26
27
  extend ClassMethods
27
28
  end
28
- end
29
+ end