trust 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -141,8 +141,32 @@ can? :edit, @account, @client # is current user allowed to edit the accoun
141
141
  #### On ActiveRecord objects you will use permits?
142
142
 
143
143
  ``` Ruby
144
- @customer.permits? :edit # does the current user have permission to edit the given customer?
145
- Customer.permits? :create, @client # does the current user have permission to create customers?
144
+ @customer.permits? :edit # does the current user have permission to edit the given customer?
145
+ Customer.permits? :create, @client # does the current user have permission to create customers for client?
146
+ Customer.permits? :create, @client, :by => @auditor # does the auditor have permission to create customers?
147
+ Customer.permits? :create, :for => @client, :by => @auditor # same as above
148
+ ```
149
+
150
+ #### You can also designate actors in your model so you can test if other people has access to do operations on a subject
151
+
152
+ Include the Actor role in the class
153
+ ``` Ruby
154
+ class Auditor
155
+ include Trust::Actor
156
+ ...
157
+ end
158
+ ```
159
+
160
+ Now you can test if the auditor has permission to modify customer for client. Three ways of writing it
161
+ ``` Ruby
162
+ @auditor.can? :update, @customer, @client
163
+ @auditor.can? :update, @customer, :for => @client
164
+ @auditor.can? :update, @customer, :parent => @client
165
+ ```
166
+
167
+ The above is the same as
168
+ ``` Ruby
169
+ @customer.permits? :update, @client, :by => @auditor
146
170
  ```
147
171
 
148
172
  ## Instance variables
@@ -0,0 +1,76 @@
1
+ # Copyright (c) 2012 Bingo Entreprenøren AS
2
+ # Copyright (c) 2012 Teknobingo Scandinavia AS
3
+ # Copyright (c) 2012 Knut I. Stenmark
4
+ # Copyright (c) 2012 Patrick Hanevold
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ module Trust
26
+ # = Trust::ActiveModel extension
27
+ #
28
+ # Extends ActiveRecord with the +permits?+ and +ensure_permitted!+ method on class and instances
29
+ # If using Mongoid same features are included there
30
+ #
31
+ # Options:
32
+ #
33
+ # * +:parent+ - Specifies that the persmision should be tested in the context of a parent
34
+ # * +:by+ - Specifies an actor to be used instead of the currently logged in user
35
+ #
36
+ # ==== Examples
37
+ #
38
+ # # If current user is permitted to create customers, create it
39
+ # if Customer.permits? :create
40
+ # Customer.create attributes
41
+ # end
42
+ #
43
+ # # If current user is permitted to create accounts for the given customer, create it
44
+ # if Account.permits? :create, @customer
45
+ # Account.create attributes
46
+ # end
47
+ #
48
+ # # If the specified actor is permitted to create accounts for the given customer, create it
49
+ # if Account.permits? :create, @customer, :by => @actor
50
+ # Account.create attributes
51
+ # end
52
+ #
53
+ # # Raise an exception if user is not permitted to update the given customer, else save it
54
+ # @customer.ensure_permitted! :update
55
+ # @customer.save
56
+ #
57
+ # # Raise an exception if the specified user is not permitted to update the given customer, else save it
58
+ # @customer.ensure_permitted! :update, :by => @actor
59
+ # @customer.save
60
+ module ActiveModel
61
+ extend ActiveSupport::Concern
62
+
63
+ included do
64
+ include ClassMethods
65
+ end
66
+
67
+ module ClassMethods
68
+ def permits?(action, *args)
69
+ Trust::Authorization.authorized?(action, self, *args)
70
+ end
71
+ def ensure_permitted!(action, *args)
72
+ Trust::Authorization.authorize!(action, self, *args)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -23,43 +23,33 @@
23
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
25
  module Trust
26
- module ActiveRecord
26
+ # = Trust::Actor extension
27
+ #
28
+ # Include this module if you want to check if an actor can act upon a specific subject
29
+ #
30
+ # ==== Examples
31
+ #
32
+ # # If the @actor can create customers, create it
33
+ # if @actor.can? :create, Customer
34
+ # Customer.create attributes
35
+ # end
36
+ #
37
+ # # If @actor can create accounts for the given customer, create it
38
+ # if @actor.can? :create, Account, @customer
39
+ # Account.create attributes
40
+ # end
41
+ # # It is also possible to make code more descripting for the same as above
42
+ # if @actor.can? :create, Account, :parent => @customer # or, ...
43
+ # if @actor.can? :create, Account, :for => @customer
44
+ #
45
+ module Actor
27
46
  extend ActiveSupport::Concern
28
- # = Trust::ActiveRecord extension
29
- # Extends ActiveRecord with the +permits?+ and +ensure_permitted!+ method on class and instances
30
- #
31
- # ==== Examples
32
- #
33
- # # If current user is permitted to create customers, create it
34
- # if Customer.permits? :create
35
- # Customer.create attributes
36
- # end
37
- #
38
- # # If current user is permitted to create accounts for the given customer, create it
39
- # if Account.permits? :create, @customer
40
- # Account.create attributes
41
- # end
42
- #
43
- # # If current user is permitted to update the given customer, update it
44
- # if @customer.permits? :update
45
- # @customer.save
46
- # end
47
- #
48
- # # Raise an exception if user is not permitted to update the given customer, else save it
49
- # @customer.ensure_permitted! :update
50
- # @customer.save
51
47
 
52
- included do
53
- include ClassMethods
54
- end
55
-
56
- module ClassMethods
57
- def permits?(action, parent = nil)
58
- Trust::Authorization.authorized?(action, self, parent)
59
- end
60
- def ensure_permitted!(action, parent = nil)
61
- Trust::Authorization.authorize!(action, self, parent)
62
- end
48
+ def can?(action, subject, *args)
49
+ options = args.extract_options!
50
+ options[:parent] ||= args.first || options.delete(:for)
51
+ options[:by] = self
52
+ Trust::Authorization.authorized?(action, subject, options)
63
53
  end
64
54
  end
65
55
  end
@@ -23,13 +23,26 @@
23
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
25
  module Trust
26
+ # = Trust Authorization
26
27
  class Authorization
27
28
  class << self
28
- # Returns true if user is authorized to perform +action+ on +object+ or +class+
29
- # If +parent+ is given, +parent+ may be tested in the implemented Permissions class
29
+
30
+ # Returns true if user is authorized to perform +action+ on +object+ or +class+.
31
+ #
32
+ # Options:
33
+ #
34
+ # * +:parent+ - the parent class to associate the subject with, can also be specified after the object
35
+ # or class. If +parent+ is given, +parent+ may be tested in the implemented Permissions class.
36
+ # +:parent+ is also aliased to +:for+.
37
+ #
38
+ # * +:by+ - Spoecify an actor instead of the user currently logged in
39
+ #
30
40
  # This method is called by the +can?+ method in Trust::Controller, and is normally
31
41
  # not necessary to call directly.
32
- def authorized?(action, object_or_class, parent)
42
+ def authorized?(action, object_or_class, *args)
43
+ options = args.extract_options!
44
+ parent = options[:parent] || options[:for] || args.first
45
+ actor = options[:by] || user
33
46
  if object_or_class.is_a? Class
34
47
  klass = object_or_class
35
48
  object = nil
@@ -40,35 +53,47 @@ module Trust
40
53
  # Identify which class to instanciate and then check authorization
41
54
  auth = authorizing_class(klass)
42
55
  # Rails.logger.debug "Trust: Authorizing class for #{klass.name} is #{auth.name}"
43
- auth.new(user, action.to_sym, klass, object, parent).authorized?
56
+ auth.new(actor, action.to_sym, klass, object, parent).authorized?
44
57
  end
45
58
 
46
59
  # Tests if user is authorized to perform +action+ on +object+ or +class+, with the
47
60
  # optional parent and raises Trust::AccessDenied exception if not permitted.
48
- # If using this method directly, an optional +message+ can be passed in to
49
- # replace the default message used.
61
+ #
62
+ # Options:
63
+ #
64
+ # * +:parent+ - the parent class to associate the subject with, can also be specified after the object
65
+ # or class. If +parent+ is given, +parent+ may be tested in the implemented Permissions class.
66
+ # +:parent+ is also aliased to +:for+.
67
+ #
68
+ # * +:by+ - Spoecify an actor instead of the user currently logged in
69
+ #
70
+ # * +:message+ - The message to be passed onto the AccessDenied exception class
71
+ #
50
72
  # This method is used by the +access_control+ method in Trust::Controller
51
- def authorize!(action, object_or_class, parent, message = nil)
52
- access_denied!(message, action, object_or_class, parent) unless authorized?(action, object_or_class, parent)
73
+ def authorize!(action, object_or_class, *args)
74
+ options = args.extract_options!
75
+ parent = options[:parent] || options[:for] || args.first
76
+ message = options[:message]
77
+ access_denied!(message, action, object_or_class, parent) unless authorized?(action, object_or_class, parent, options)
53
78
  end
54
79
 
55
- def access_denied!(message = nil, action = nil, subject = nil, parent = nil) # nodoc
80
+ def access_denied!(message = nil, action = nil, subject = nil, parent = nil) #:nodoc:
56
81
  raise AccessDenied.new(message, action, subject)
57
82
  end
58
83
 
59
- # returns the current +user+ being used in the authorization process
84
+ # Returns the current +user+ being used in the authorization process
60
85
  def user
61
86
  Thread.current["current_user"]
62
87
  end
63
88
 
64
- # sets the current +user+ to be used in the authorization process.
65
- # the +user+ is thread safe.
89
+ # Sets the current +user+ to be used in the authorization process.
90
+ # The +user+ is thread safe.
66
91
  def user=(user)
67
92
  Thread.current["current_user"] = user
68
93
  end
69
94
 
70
95
  private
71
- def authorizing_class(klass) # nodoc
96
+ def authorizing_class(klass) #:nodoc:
72
97
  auth = nil
73
98
  klass.ancestors.each do |k|
74
99
  break if k == ::ActiveRecord::Base
@@ -24,6 +24,7 @@
24
24
 
25
25
  module Trust
26
26
  module Controller
27
+ # = Trust Coontroller Properties
27
28
  class Properties
28
29
  delegate :logger, :to => Rails
29
30
  attr_reader :controller
@@ -33,7 +34,7 @@ module Trust
33
34
  attr_accessor :member_actions
34
35
  attr_accessor :collection_actions
35
36
 
36
- def initialize(controller, properties) # nodoc
37
+ def initialize(controller, properties) #:nodoc:
37
38
  @controller = controller
38
39
  @model = controller.controller_path
39
40
  if properties
@@ -50,16 +51,18 @@ module Trust
50
51
  end
51
52
 
52
53
  class << self
53
- # returns a controller properties object
54
- # ensures controller properties are instantiated in a correct manner and that inheritance is supported
54
+ # Returns a controller properties object.
55
+ #
56
+ # Ensures controller properties are instantiated in a correct manner and that inheritance is supported
55
57
  def instantiate(controller)
56
58
  new(controller, controller.superclass.instance_variable_get(:@properties))
57
59
  end
58
60
  end
59
61
 
60
- # returns or sets the model to be used in a controller
61
- # If not set, the controller_path is used
62
- # You can override the model to be accessed in a controller by setting the model
62
+ # Returns or sets the model to be used in a controller
63
+ #
64
+ # If not set, the controller_path is used.
65
+ # You can override the model to be accessed in a controller by setting the model.
63
66
  # Note that you should specify the model in plural form.
64
67
  #
65
68
  # ==== Example
@@ -81,10 +84,12 @@ module Trust
81
84
  end
82
85
 
83
86
  # Specify associated resources (nested resources)
84
- # Example:
85
- # belongs_to :lottery
86
- # belongs_to :table, :card_game
87
- # belongs_to :card_game, :as => :bridge
87
+ #
88
+ # === Example
89
+ #
90
+ # +belongs_to+ :lottery
91
+ # +belongs_to+ :table, :card_game
92
+ # +belongs_to+ :card_game, :as => :bridge
88
93
  #
89
94
  def belongs_to(*resources)
90
95
  raise ArgumentError, "You must specify at least one resource after belongs_to" unless resources
@@ -99,8 +104,10 @@ module Trust
99
104
  @associations.size > 0
100
105
  end
101
106
 
102
- # actions(options)
103
- # Options
107
+ # Specify actions to handle
108
+ #
109
+ # === Options
110
+ #
104
111
  # :new => actions # specify new actions - default id :new, :create
105
112
  # :member => actions # specify member actions - default is :show, :edit, :update, :destroy
106
113
  # :collection => actions # specify collection actions - default is :index
@@ -61,7 +61,8 @@ module Trust
61
61
  end
62
62
 
63
63
  # Sets the instance variable
64
- # Normally set by +load+
64
+ #
65
+ # Normally set by +load+.
65
66
  # You can access this method from the resource object.
66
67
  #
67
68
  # ==== Example
@@ -97,12 +98,14 @@ module Trust
97
98
  end
98
99
 
99
100
  # Sets the instance variable for collection
101
+ #
100
102
  # You may want to set this variable in your index action, we do not yet support loading of collections
101
103
  def instances=(instances)
102
104
  @controller.instance_variable_set(:"@#{plural_instance_name}", instances)
103
105
  end
104
106
 
105
107
  # Returns either the instances or the instance.
108
+ #
106
109
  # We have found that this can be useful in some implementation patterns
107
110
  def instantiated
108
111
  instances || instance
@@ -113,8 +116,10 @@ module Trust
113
116
  info.klass
114
117
  end
115
118
 
116
- # Loads the resource
119
+ # Loads the resource
120
+ #
117
121
  # See Trust::Controller::Properties which controls the behavior of this method.
122
+ #
118
123
  # It will normally find the instance variable for existing object or initialize them as new.
119
124
  # If using nested resources and +belongs_to+ has been declared in the controller it will use the
120
125
  # parent relation if found.
@@ -134,6 +139,7 @@ module Trust
134
139
  end
135
140
 
136
141
  # Returns the name of the instance for the resource
142
+ #
137
143
  # ==== Example
138
144
  #
139
145
  # # in AccountsController
@@ -143,6 +149,7 @@ module Trust
143
149
  end
144
150
 
145
151
  # Returns the plural name of the instance for the resource
152
+ #
146
153
  # ==== Example
147
154
  #
148
155
  # # in AccountsController
@@ -152,6 +159,7 @@ module Trust
152
159
  end
153
160
 
154
161
  # Returns the name of the parent resource
162
+ #
155
163
  # ==== Example
156
164
  #
157
165
  # # in AccountsController where belongs_to :customer has been declared
@@ -171,31 +179,35 @@ module Trust
171
179
  end
172
180
  end
173
181
 
174
- # ResorceInfo resolves information about the resource accessed in action controller
182
+ # = ResorceInfo
183
+ #
184
+ # resolves information about the resource accessed in action controller
175
185
  #
176
- # Examples in PeopleController (simple case)
177
- # ===
186
+ # === Examples in PeopleController (simple case)
187
+ #
178
188
  # resource.info.klass => Person
179
189
  # resource.info.params => {:person => {...}} # fetches the parameters for the resource
180
190
  # resource.info.name => :person
181
191
  # resource.info.plural_name => :people
182
192
  # resource.info.path => 'people' # this is the controller_path
183
193
  #
184
- # Examples in Lottery::AssignmentsController (with name space)
185
- # ===
194
+ # === Examples in Lottery::AssignmentsController (with name space)
195
+ #
186
196
  # resource.info.klass => Lottery::Assignment
187
197
  # resource.info.params => {:lottery_assignment => {...}}
188
198
  # resource.info.name => :lottery_assignment
189
199
  # resource.info.plural_name => :lottery_assignments
190
200
  # resource.info.path => 'lottery/assignments' # this is the controller_path
191
201
  #
192
- # Examples in ArchiveController (with inheritance)
202
+ # === Examples in ArchiveController (with inheritance)
193
203
  # Assumptions on routes:
204
+ #
194
205
  # resources :archives
195
206
  # resources :secret_acrvives, :controller => :archives
196
207
  # resources :public_acrvives, :controller => :archives
197
- # examples below assumes that the route secret_arcives is being accessed at the moment
198
- # ===
208
+ #
209
+ # === Examples below assumes that the route secret_arcives is being accessed at the moment
210
+ #
199
211
  # resource.info.klass => Archive
200
212
  # resource.info.params => {:secret_archive => {...}}
201
213
  # resource.info.name => :archive
@@ -203,27 +215,29 @@ module Trust
203
215
  # resource.info.path => 'archive' # this is the controller_path
204
216
  # resource.info.real_class => SecretArchive # Returns the real class which is accessed at the moment
205
217
  #
206
-
207
218
  class Resource::Info
208
219
  attr_reader :klass, :params, :name, :path, :real_class
209
220
 
210
- def params
221
+ def params #:nodoc:
211
222
  @data
212
223
  end
213
224
 
214
225
  protected
215
- def self.var_name(klass)
226
+ def self.var_name(klass) #:nodoc:
216
227
  klass.to_s.underscore.tr('/','_').to_sym
217
228
  end
218
- def var_name(klass)
229
+ def var_name(klass) #:nodoc:
219
230
  self.class.var_name(klass)
220
231
  end
221
232
  end
222
233
 
223
-
234
+ # = Resource::ResorceInfo
235
+ #
236
+ # Resolves the resource in subject
237
+ # (see #ResourceInfo)
224
238
  class Resource::ResourceInfo < Resource::Info
225
239
 
226
- def initialize(model, params)
240
+ def initialize(model, params) #:nodoc:
227
241
  @path, params = model, params
228
242
  @klass = model.to_s.classify.constantize
229
243
  @name = model.to_s.singularize.underscore.gsub('/','_').to_sym
@@ -234,13 +248,15 @@ module Trust
234
248
  @data = params[var_name(ptr)]
235
249
  end
236
250
 
251
+ # Returns the plural name of the resource
237
252
  def plural_name
238
253
  @plural_name ||= path.underscore.tr('/','_').to_sym
239
254
  end
240
255
 
241
- # returns an accessor for association. Tries with full name association first, and if that does not match, tries the demodularized association.
256
+ # Returns an accessor for association. Tries with full name association first, and if that does not match, tries the demodularized association.
257
+ #
258
+ # === Explanation
242
259
  #
243
- # Explanation:
244
260
  # Assuming
245
261
  # resource is instance of Lottery::Package #1 (@lottery_package)
246
262
  # association is Lottery::Prizes
@@ -258,6 +274,10 @@ module Trust
258
274
  end
259
275
  end
260
276
 
277
+ # = Resource::ParentInfo
278
+ #
279
+ # Resolves the parent resource in subject
280
+ # (see #ResourceInfo)
261
281
  class Resource::ParentInfo < Resource::Info
262
282
  attr_reader :object,:as
263
283
  def initialize(resources, params, request)
@@ -23,6 +23,7 @@
23
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
25
  module Trust
26
+ # = Trust Controller
26
27
  module Controller
27
28
  autoload :Resource, 'trust/controller/resource'
28
29
  autoload :Properties, 'trust/controller/properties'
@@ -49,6 +50,7 @@ module Trust
49
50
  delegate :belongs_to, :actions, :model, :to => :properties
50
51
 
51
52
  # Enables authorization in controller
53
+ #
52
54
  # +trustee+ accepts +:off+ or a hash of +callback+ options such as +:except+ and +:only+
53
55
  #
54
56
  # +trustee+ automatically calls the class methods: +set_user+, +load_resource+ and +access_control+
@@ -82,8 +84,6 @@ module Trust
82
84
  # redirect_to root_url, :alert => exception.message
83
85
  # end
84
86
  # end
85
-
86
-
87
87
  def trustee(*args)
88
88
  module_eval do
89
89
  include TrustInstanceMethods
@@ -95,15 +95,20 @@ module Trust
95
95
  end
96
96
 
97
97
  # Enable or disable +before_filter+ callback for setting the current user
98
- # Arguments:
98
+ #
99
+ # === Arguments:
100
+ #
99
101
  # :off - switch callback off
100
102
  # :only - only include these actions
101
103
  # :except - except these actions
102
104
  def set_user(*args)
103
105
  _filter_setting(:set_user, *args)
104
106
  end
107
+
105
108
  # Enable or disable +before_filter+ callback for setting the loading resource
106
- # Arguments:
109
+ #
110
+ # === Arguments:
111
+ #
107
112
  # :off - switch callback off
108
113
  # :only - only include these actions
109
114
  # :except - except these actions
@@ -112,7 +117,9 @@ module Trust
112
117
  end
113
118
  # Enable or disable +before_filter+ callback for setting the access control, i.e. verifying permissions
114
119
  # for the logged in user
115
- # Arguments:
120
+ #
121
+ # === Arguments:
122
+ #
116
123
  # :off - switch callback off
117
124
  # :only - only include these actions
118
125
  # :except - except these actions
@@ -132,7 +139,7 @@ module Trust
132
139
 
133
140
  module TrustInstanceMethods
134
141
  # Returns the controller Trust::Controller::Properties.
135
- # If no properties are instantiated, it will be instantiated
142
+ # If no properties are instantiated, it will be instantiated.
136
143
  #
137
144
  # == Delegated methods
138
145
  #
@@ -146,8 +153,9 @@ module Trust
146
153
  self.class.properties
147
154
  end
148
155
 
149
- # Sets the current user. It assumes +current_user+ is defined
150
- # This method is triggered as a callback on +before_filter+
156
+ # Sets the current user. It assumes +current_user+ is defined.
157
+ #
158
+ # This method is triggered as a callback on +before_filter+.
151
159
  # You may override this method.
152
160
  #
153
161
  # ==== Example
@@ -160,28 +168,32 @@ module Trust
160
168
  end
161
169
 
162
170
  # Returns the Trust::Controller::Resource resource for the controller.
163
- # Available as a helper in views
164
- # See Trust::Controller::Resource for relevant methods
171
+ #
172
+ # Available as a helper in views.
173
+ # See {Trust::Controller::Resource} for relevant methods.
165
174
  def resource
166
175
  @resource ||= Trust::Controller::Resource.new(self, self.class.properties, action_name, params, request)
167
176
  end
168
177
 
169
178
  # Loads the resource which basically means loading the instance and eventual parent defined through +belongs_to+
179
+ #
170
180
  # This method is triggered as a callback on +before_filter+
171
- # See Trust::Controller::Resource for more information
181
+ # See {Trust::Controller::Resource} for more information
172
182
  def load_resource
173
183
  resource.load
174
184
  end
175
185
 
176
- # Performs the actual access_control
186
+ # Performs the actual access_control.
187
+ #
177
188
  # This method is triggered as a callback on +before_filter+
178
189
  def access_control
179
190
  Trust::Authorization.authorize!(action_name, resource.instance || resource.klass, resource.parent)
180
191
  end
181
192
 
182
- # Tests for current users permissions
193
+ # Tests for current users permissions.
194
+ #
183
195
  # If access control is not sufficient in controller, you may use this method.
184
- # Also available as a helper in views
196
+ # Also available as a helper in views.
185
197
  #
186
198
  # ==== Examples
187
199
  # can? :edit # does the current user have permission to edit the current resource?
@@ -23,9 +23,10 @@
23
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
25
  module Trust
26
+ # = Trust InheritableAttribute
26
27
  module InheritableAttribute
27
28
 
28
- def self.deep_copy value
29
+ def self.deep_copy( value) #:nodoc:
29
30
  if value.is_a? Hash
30
31
  Hash[*value.map{ |k,v| [self.deep_copy(k),self.deep_copy(v)] }.flatten(1)]
31
32
  elsif value.is_a? Array
@@ -40,11 +41,12 @@ module Trust
40
41
  extend ActiveSupport::Concern
41
42
 
42
43
  module ClassMethods
43
- # Creates an inheritable attribute with accessors in the singleton class. Derived classes inherit the
44
- # attributes. This is especially helpful with arrays or hashes that are extended in the inheritance
45
- # chain. Note that you have to initialize the inheritable attribute.
44
+ # Creates an inheritable attribute with accessors in the singleton class.
45
+ #
46
+ # Derived classes inherit the attributes. This is especially helpful with arrays or hashes that
47
+ # are extended in the inheritance chain. Note that you have to initialize the inheritable attribute.
46
48
  #
47
- # Example:
49
+ # === Example
48
50
  #
49
51
  # class Cat
50
52
  # inheritable_attr :drinks