active_restrictors 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,14 @@
1
+ == v0.2.0
2
+ * Removed any remaining Rails 2 support
3
+ * Added new parameter structure for defining restrictors
4
+ * Added parameter mapping to allow old restrictor definitions to continue to function
5
+ * Renamed :basic restrictor to :basic_user
6
+ * Added two new restrictor types: basic_model and :implicit
7
+ * Cleaned up restrictor functionality from both model directions
8
+ * Updated #full_restrictors to provide all restrictors
9
+ * Updated view helpers to provide all restrictors
10
+ * Updated form building to use proper *_ids naming scheme
11
+
1
12
  == v0.1.1
2
13
  * Fixed class eval blocks
3
14
  * Fixed hash variable naming
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gem 'activerecord', '~> 3.0'
4
+ gem 'rake'
5
+ gem 'minitest'
6
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
7
+ gem "jdbc-sqlite3", :platform => :jruby
8
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.1.3)
5
+ activesupport (= 3.1.3)
6
+ builder (~> 3.0.0)
7
+ i18n (~> 0.6)
8
+ activerecord (3.1.3)
9
+ activemodel (= 3.1.3)
10
+ activesupport (= 3.1.3)
11
+ arel (~> 2.2.1)
12
+ tzinfo (~> 0.3.29)
13
+ activerecord-jdbc-adapter (1.2.1)
14
+ activerecord-jdbcsqlite3-adapter (1.2.1)
15
+ activerecord-jdbc-adapter (~> 1.2.1)
16
+ jdbc-sqlite3 (~> 3.7.2)
17
+ activesupport (3.1.3)
18
+ multi_json (~> 1.0)
19
+ arel (2.2.1)
20
+ builder (3.0.0)
21
+ i18n (0.6.0)
22
+ jdbc-sqlite3 (3.7.2)
23
+ minitest (2.10.0)
24
+ multi_json (1.0.4)
25
+ rake (0.9.2.2)
26
+ sqlite3 (1.3.5)
27
+ tzinfo (0.3.31)
28
+
29
+ PLATFORMS
30
+ java
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ activerecord (~> 3.0)
35
+ activerecord-jdbcsqlite3-adapter
36
+ jdbc-sqlite3
37
+ minitest
38
+ rake
39
+ sqlite3
data/README.rdoc CHANGED
@@ -1,6 +1,8 @@
1
1
  == ActiveRestrictors
2
2
 
3
- Chainable ActiveRecord restriction chaining.
3
+ Chainable ActiveRecord restrictions.
4
+
5
+ {<img src="https://secure.travis-ci.org/chrisroberts/active_restrictors.png" />}[http://travis-ci.org/chrisroberts/active_restrictors]
4
6
 
5
7
  === Overview
6
8
 
@@ -47,10 +49,12 @@ Now, suppose a User should only be allowed to to see a Fubar instance if the Fub
47
49
 
48
50
  add_restrictor(:permissions,
49
51
  :enabled => lambda{ User.current_user.fubars_enabled? },
50
- :value => :name,
51
- :multiple => true,
52
- :default_view_all => true,
53
- :user_values_only => lambda{ User.current_user }
52
+ :views => {
53
+ :value => :name,
54
+ :multiple => true,
55
+ :default_view_all => true,
56
+ :user_values_only => lambda{ User.current_user }
57
+ }
54
58
  )
55
59
  end
56
60
 
@@ -95,7 +99,25 @@ The second is on Fubar instances:
95
99
  %td= "#{pair.first}:"
96
100
  %td= pair.last
97
101
 
98
- == Advanced Restrictor
102
+ == Restrictor Types
103
+
104
+ === Basic User
105
+
106
+ - TODO
107
+
108
+ === Basic Model
109
+
110
+ - TODO
111
+
112
+ === Implicit
113
+
114
+ - TODO
115
+
116
+ === Full
117
+
118
+ - TODO
119
+
120
+ == Custom Restrictors
99
121
 
100
122
  === User custom
101
123
 
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.pattern = 'spec/*_spec.rb'
5
+ end
@@ -9,7 +9,8 @@ Gem::Specification.new do |s|
9
9
  s.email = 'chrisroberts.code@gmail.com'
10
10
  s.homepage = 'http://bitbucket.org/chrisroberts/active_restrictors'
11
11
  s.description = 'Restrictors for Models'
12
+ s.add_dependency 'activerecord', '~> 3.0'
12
13
  s.require_path = 'lib'
13
14
  s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc']
14
- s.files = %w(README.rdoc CHANGELOG.rdoc active_restrictors.gemspec) + Dir.glob("{lib}/**/*")
15
+ s.files = Dir.glob('**/*')
15
16
  end
@@ -3,60 +3,86 @@ module ActiveRestrictor
3
3
 
4
4
  # name:: Name of restrictor. For non-basic types this must be the name of the association.
5
5
  # opts:: Options hash. Valid options:
6
- # :type:: Should be set to :basic when applying simple condition only
7
- # :condition:: Condition string applied to User
8
- # :class:: Class restriction is based on
9
- # :value:: Attribute name of value to display
10
- # :multiple:: Allow user to select multiple items for restriction
11
- # :include_blank:: Include blank option in restriction selection
12
- # :user_custom:: Block that returns User scope (passed: User scope, self instance)
13
- # :user_association:: Name of association on user
14
- # :model_custom:: Block that returns Model scope (passed: self instance, User instance)
6
+ # :type:: :full, :implicit, :basic_model, :basic_user
7
+ # :class:: Class restriction is based on if not guessable
15
8
  # :enabled:: If restrictor is enabled. Must be boolean value or a callable object that returns boolean value
16
- # :default_view_all:: If user has not been assigned a restrictor, they see all unless set to false
17
- # :user_values_only:: User instance. Set this if you only want values set against user to be selectable
9
+ # :scope:: Scope or callable block returning scope
10
+ # :views =>
11
+ # :value:: Attribute name of value to display
12
+ # :multiple:: Multiple assignments allowed
13
+ # :include_blank:: Allow assignments to be unset
14
+ # :user_values_only:: User instance. Set this if you only want values set against user to be selectable
15
+ # :id:: Value method for selection (defaults to :id)
16
+ # :user_association:: Name of association on user (if different from restrictor name)
17
+ # :user_custom:: Block that returns User scope (passed: User scope, self instance) - Used when generic scope building is lacking
18
+ # :model_custom:: Block that returns Model scope (passed: self instance, User instance) - Used when generic scope building is lacking
19
+ # :default_allowed_all:: If source instance has no restriction assigned, it is viewable
20
+ # :default_view_all:: Alias for :default_allowed_all
18
21
  # Adds restrictions to Model
19
- # NOTE: Basic type signifies that condition is forced without
20
- # user interaction. This means no select options will be used
21
- # as basic restrictors are never seen by the user. Basic restrictors
22
- # are applied directly against the user model.
22
+ # NOTE: Basic types are run directly against the model culminating in a count to see if it is valid (ex for :basic_user: User.where(:allowed_to_do_stuff => true))
23
+ # Implicit type is run directly against the source model. (ex: Fubar.includes(:feebar).where(:feebars => {:user_id => User.current_user.id}))
24
+ # Full is a full restrictor using join tables and provides view helpers for management
23
25
  def add_restrictor(name, opts={})
24
26
  self.restrictors ||= []
25
- new_opts = {:name => name, :id => :id, :enabled => true, :type => :full, :include => []}.merge(opts)
26
- new_opts[:include] = [new_opts[:include]] unless new_opts[:include].is_a?(Array)
27
- new_opts[:include].push(name) unless new_opts[:include].map(&:to_s).include?(name.to_s)
28
- self.restrictors.push(new_opts)
29
- if(new_opts[:type] == :full)
30
- self.class_eval do
31
- # This just creates a helper that will grab activerecord
32
- # instance from passed in IDs for applied restriction
33
- alias_method "original_#{name}=".to_sym, "#{name}=".to_sym
34
- define_method("#{name}=") do |args|
35
- args = (args.is_a?(Array) ? args : Array(args)).find_all{|arg|arg.present?}
36
- new_args = []
37
- ids = []
38
- args.each do |item|
39
- if(item.is_a?(ActiveRecord::Base) || (defined?(ActiveRecord::Relation) && item.is_a?(ActiveRecord::Relation)))
40
- new_args << item
41
- else
42
- ids << item.to_i
43
- end
44
- end
45
- new_args += new_opts[:class].find(ids) unless ids.empty?
46
- self.send("original_#{name}=".to_sym, new_args)
47
- end
27
+ new_opts = {:name => name, :enabled => true, :type => :full, :scope => self.scoped, :default_allowed_all => false}.merge(opts)
28
+ new_opts[:views] ||= {}
29
+ new_opts = map_deprecated_hash(new_opts)
30
+ new_opts[:views][:id] ||= :id
31
+ new_opts[:class] = restrictor_class(new_opts)
32
+ if(new_opts[:type] == :full && new_opts[:views][:value].blank?)
33
+ if(new_opts[:class].column_names.include?('name'))
34
+ new_opts[:views][:value] = :name
35
+ else
36
+ raise 'Value must be defined for association to generate views'
48
37
  end
49
38
  end
39
+ self.restrictors.push(new_opts)
40
+ end
41
+
42
+ # TODO: Add in proper mapping plus scope building
43
+ def map_deprecated_hash(hsh)
44
+ hsh[:type] = :basic_user if hsh[:type] == :basic
45
+ hsh[:scope] = self.class._restrictor_custom_user_class.where(hsh.delete(:condition)) if hsh[:condition].present?
46
+ [:value, :multiple, :include_blank, :user_values_only, :id].each do |v_opt|
47
+ hsh[:views][v_opt] = hsh.delete(v_opt) if hsh[v_opt].present?
48
+ end
49
+ hsh[:default_allowed_all] = hsh.delete(:default_view_all) if hsh.has_key?(:default_view_all)
50
+ hsh
50
51
  end
51
52
 
52
- # Returns restrictors not of type :basic
53
- def full_restrictors
54
- self.restrictors.find_all{|restrictor| restrictor[:type] != :basic && check_enabled(restrictor[:enabled]) == true}
53
+ # Returns restrictors of type: :full
54
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
55
+ def full_restrictors(*args)
56
+ self.restrictors.find_all do |restrictor|
57
+ restrictor[:type] == :full &&
58
+ (args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
59
+ end
55
60
  end
56
61
 
57
- # Returns restrictors of type :basic
58
- def basic_restrictors
59
- self.restrictors.find_all{|restrictor| restrictor[:type] == :basic && check_enabled(restrictor[:enabled]) == true}
62
+ # Returns restrictors of type :basic_model
63
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
64
+ def basic_model_restrictors(*args)
65
+ self.restrictors.find_all do |restrictor|
66
+ restrictor[:type] == :basic_model &&
67
+ (args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
68
+ end
69
+ end
70
+
71
+ # Returns restrictors of type :basic_user
72
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
73
+ def basic_user_restrictors(*args)
74
+ self.restrictors.find_all do |restrictor|
75
+ restrictor[:type] == :basic_user &&
76
+ (args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
77
+ end
78
+ end
79
+
80
+ # Returns restrictors of type :implicit
81
+ def implicit_restrictors(*args)
82
+ self.restrictors.find_all do |restrictor|
83
+ restrictor[:type] == :implicit &&
84
+ check_enabled(restrictor[:enabled]) == true
85
+ end
60
86
  end
61
87
 
62
88
  # Returns all restrictors that are currently in enabled state
@@ -70,8 +96,34 @@ module ActiveRestrictor
70
96
  if(hash[:class].present?)
71
97
  hash[:class]
72
98
  else
73
- self.relect_on_association(hash[:name]).klass
99
+ if(hash[:type] == :basic_user)
100
+ _restrictor_custom_user_class
101
+ elsif(hash[:type] == :basic_model)
102
+ self
103
+ else
104
+ n = self.reflect_on_association(hash[:name]).try(:klass)
105
+ if(n.blank?)
106
+ raise "Failed to location association for restrictor. Given: #{hash[:name]}. Please check assocation name."
107
+ end
108
+ n
109
+ end
110
+ end
111
+ end
112
+
113
+ def restrictor_user_scoping
114
+ user_scope = _restrictor_custom_user_class.scoped
115
+ basic_user_restrictors.each do |restrictor|
116
+ user_scope = user_scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
74
117
  end
118
+ user_scope
119
+ end
120
+
121
+ def restrictor_klass_scoping
122
+ klass_scope = self.scoped
123
+ (implicit_restrictors + basic_model_restrictors).each do |restrictor|
124
+ klass_scope = klass_scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
125
+ end
126
+ klass_scope
75
127
  end
76
128
 
77
129
  private
@@ -89,6 +141,7 @@ module ActiveRestrictor
89
141
  false
90
142
  end
91
143
  end
144
+
92
145
  end
93
146
 
94
147
  module InstanceMethods
@@ -100,13 +153,26 @@ module ActiveRestrictor
100
153
  end
101
154
 
102
155
  # Returns restrictors not of type :basic
103
- def full_restrictors
104
- self.class.full_restrictors
156
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
157
+ def full_restrictors(*args)
158
+ self.class.full_restrictors(*args)
159
+ end
160
+
161
+ # Returns restrictors of type :basic_user
162
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
163
+ def basic_user_restrictors(*args)
164
+ self.class.basic_user_restrictors(*args)
165
+ end
166
+
167
+ # Returns restrictors of type :basic_model
168
+ # NOTE: Returns enabled by default. Provide :include_disabled to get all
169
+ def basic_model_restrictors(*args)
170
+ self.class.basic_model_restrictors(*args)
105
171
  end
106
172
 
107
- # Returns restrictors of type :basic
108
- def basic_restrictors
109
- self.class.basic_restrictors
173
+ # Returns restrictors of type :implict
174
+ def implicit_restrictors
175
+ self.class.implicit_restrictors
110
176
  end
111
177
 
112
178
  # Returns all restrictors taht are currently in enabled status
@@ -114,31 +180,43 @@ module ActiveRestrictor
114
180
  self.class.enabled_restrictors
115
181
  end
116
182
 
183
+ # Grabs customizable user class
184
+ def _restrictor_custom_user_class
185
+ self.class._restrictor_custom_user_class
186
+ end
187
+
117
188
  # Returns User scope with all restrictors applied
118
189
  def allowed_users
119
- user_scope = User.scoped
120
- enabled_restrictors.each do |restrictor|
121
- next if restrictor[:user_custom]
122
- if(restrictor[:include].is_a?(ActiveRecord::Relation))
123
- user_scope = user_scope.merge(restrictor[:include])
124
- elsif(restrictor[:include].present?)
125
- user_scope = user_scope.joins(restrictor[:include])
126
- end
127
- if(restrictor[:condition].is_a?(ActiveRecord::Relation))
128
- user_scope = user_scope.merge(restrictor[:condition])
129
- elsif(restrictor[:condition].respond_to?(:call))
130
- user_scope = user_scope.merge(restrictor[:condition].call)
131
- elsif(restrictor[:condition].present?)
132
- user_scope = user_scope.where(restrictor[:condition])
190
+ klass_scope = self.class.restrictor_klass_scoping.where(:id => self.id)
191
+ user_scope = self.class.restrictor_user_scoping
192
+ if(klass_scope.count > 0)
193
+ full_restrictors.each do |restrictor|
194
+ user_scope = user_scope.includes(restrictor[:name])
195
+ unless(restrictor[:user_custom].present?)
196
+ rtable_name = restrictor[:table_name] || restrictor[:class].table_name
197
+ r_scope = self.send(restrictor[:name]).scoped.select("#{rtable_name}.id")
198
+ r_count = self.send(restrictor[:name]).scoped.select("count(*)")
199
+ # this next bit gets rid of the association_name.* rails insists upon and any extra cruft
200
+ r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{rtable_name}.id"}
201
+ r_count.arel.ast.cores.first.projections.delete_if{|item| item != "count(*)"}
202
+ user_scope = user_scope.where(
203
+ "#{rtable_name}.id IN (#{r_scope.to_sql})#{
204
+ " OR (#{r_count.to_sql}) = 0" if restrictor[:default_allowed_all]
205
+ }"
206
+ )
207
+ else
208
+ user_scope = restrictor[:user_custom].call(user_scope, self)
209
+ end
133
210
  end
134
- unless(restrictor[:type] == :basic)
135
- user_scope = user_scope.where("#{restrictor[:table_name] || restrictor_class(restrictor).table_name}.id IN (#{self.send(restrictor[:name]).scoped.select(:id).to_sql})")
211
+ if(Array(implicit_restrictors).size > 0)
212
+ if(r = _restrictor_custom_user_class.reflect_on_all_associations.detect{|r| r.klass == self.class})
213
+ user_scope = user_scope.includes(r.name).merge(klass_scope)
214
+ end
136
215
  end
216
+ user_scope
217
+ else
218
+ user_scope.where('null')
137
219
  end
138
- if((methods = enabled_restrictors.find_all{|res| res[:user_custom]}).size > 0)
139
- user_scope = methods.inject(user_scope){|result,func| func.call(result, self)}
140
- end
141
- user_scope
142
220
  end
143
221
  end
144
222
 
@@ -151,14 +229,28 @@ module ActiveRestrictor
151
229
  extend ClassMethods
152
230
  include InstanceMethods
153
231
 
232
+ unless(base.singleton_methods.map(&:to_sym).include?(:_restrictor_custom_user_class))
233
+ class << self
234
+ # This can be overridden for customization
235
+ def _restrictor_custom_user_class
236
+ User
237
+ end
238
+ end
239
+ end
154
240
  scope :allowed_for, lambda{|*args|
155
241
  user = args.detect{|item|item.is_a?(User)}
156
- where("#{table_name}.id IN (#{user.send("allowed_#{base.name.tableize}").select(:id).to_sql})")
242
+ if(user.present?)
243
+ r_scope = user.send("allowed_#{base.name.tableize}").select("#{base.table_name}.id")
244
+ r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{base.table_name}.id"}
245
+ where("#{table_name}.id IN (#{r_scope.to_sql})")
246
+ else
247
+ where('null')
248
+ end
157
249
  }
158
250
  end
159
251
  end
160
252
  # Patch up the user to provide restricted methods
161
- ([User] + User.descendants).compact.each do |user_klass|
253
+ ([klass._restrictor_custom_user_class] + klass._restrictor_custom_user_class.descendants).compact.each do |user_klass|
162
254
  user_klass.class_eval do
163
255
  # This patches a method onto the User instance to
164
256
  # provide access to the allowed instance of the model
@@ -168,45 +260,31 @@ module ActiveRestrictor
168
260
  define_method("allowed_#{klass.name.tableize}") do
169
261
  # First we perform a basic check against the User to see
170
262
  # if this user instance is even allowed by default
171
- user_scope = User.scoped
172
- klass.basic_restrictors.each do |restriction|
173
- if(restriction[:condition].is_a?(ActiveRecord::Relation))
174
- user_scope = user_scope.merge(restriction[:condition])
175
- elsif(restriction[:condition].respond_to?(:call))
176
- user_scope = user_scope.merge(restriction[:condition].call)
177
- elsif(restriction[:condition].present?)
178
- user_scope = user_scope.where(restriction[:condition])
179
- end
180
- if(restriction[:include].is_a?(ActiveRecord::Relation))
181
- user_scope = user_scope.merge(restriction[:include])
182
- elsif(restriction[:include].present?)
183
- user_scope = user_scope.join(restriction[:include])
184
- end
185
- end
263
+ user_scope = klass.restrictor_user_scoping.where(:id => self.id)
186
264
  if(user_scope.count > 0)
187
- scope = klass.scoped
265
+ scope = klass.restrictor_klass_scoping
188
266
  klass.full_restrictors.each do |restrictor|
189
- next if restrictor[:model_custom].present?
190
- rtable_name = restrictor[:table_name] || klass.restrictor_class(restrictor).table_name
191
- r_scope = self.send(restrictor[:name]).scoped.select("#{rtable_name}.id")
192
- r_scope.arel.ast.cores.first.projections.delete_at(0) # gets rid of the association_name.* rails insists upon
193
- if(restrictor[:default_view_all])
194
- scope = scope.includes(restrictor[:name]) if restrictor[:name].present?
267
+ scope = scope.includes(restrictor[:name])
268
+ if(restrictor[:scope].present?)
269
+ scope = scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
270
+ end
271
+ unless(restrictor[:model_custom].present?)
272
+ rtable_name = restrictor[:table_name] || restrictor[:class].table_name
273
+ r_scope = self.send(restrictor[:user_association] || restrictor[:name]).scoped.select("#{rtable_name}.id") # This gives us valid joiners!
274
+ # this next bit gets rid of the association_name.* rails insists upon and any extra cruft
275
+ r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{rtable_name}.id"}
276
+ scope = scope.where(
277
+ "#{rtable_name}.id IN (#{r_scope.to_sql})#{
278
+ " OR #{rtable_name}.id IS NULL" if restrictor[:default_allowed_all]
279
+ }"
280
+ )
195
281
  else
196
- scope = scope.joins(restrictor[:name]) if restrictor[:name].present?
282
+ scope = restrictor[:model_custom].call(scope, self)
197
283
  end
198
- scope = scope.where(
199
- "#{rtable_name}.id IN (#{r_scope.to_sql})#{
200
- " OR #{rtable_name}.id IS NULL" if restrictor[:default_view_all]
201
- }"
202
- )
203
- end
204
- if((methods = klass.restrictors.map{|res| res[:model_custom]}.compact).size > 0)
205
- scope = methods.inject(scope){|result,func| func.call(result, self)}
206
284
  end
207
285
  scope
208
286
  else
209
- klass.where('false')
287
+ klass.where('null')
210
288
  end
211
289
  end
212
290
  end
@@ -1,57 +1,65 @@
1
1
  module ActiveRestrictors
2
2
  module View
3
+
3
4
  # obj:: Instance with restrictors enabled
5
+ # args:: argument hash :
6
+ # :val_join:: string to join values with
7
+ # :include_disabled:: includes all restrictors
4
8
  # val_join:: String to join restictor values together
5
9
  # Provides array of enabled restrictors in the form of:
6
10
  # [[restrictor_name_label, string_of_restriction_values]]
7
- def display_full_restrictors(obj, val_join = '<br />')
11
+ def display_full_restrictors(obj, *args)
12
+ arg_h = args.last.is_a?(Hash) ? args.last : {}
13
+ res = []
14
+ if(args.size == 1 && args.first.is_a?(String))
15
+ val_join = args.first
16
+ else
17
+ val_join = arg_h[:val_join] || '<br />'
18
+ end
8
19
  if(obj.class.respond_to?(:full_restrictors))
9
- obj.class.full_restrictors.map do |restrictor|
10
- [
11
- label(obj.class.name.camelize, restrictor[:name]),
12
- obj.send(restrictor[:name]).map(&restrictor[:value].to_sym).join(val_join).html_safe
13
- ]
20
+ r_args = arg_h[:include_disabled] ? [:include_disabled] : []
21
+ res = obj.class.full_restrictors(*r_args).map do |restrictor|
22
+ [label(obj.class.name.camelize, restrictor[:name]),
23
+ obj.send(restrictor[:name]).map(&restrictor[:views][:value].to_sym).join(val_join).html_safe]
14
24
  end
15
- else
16
- []
17
25
  end
18
- end
19
-
20
- def display_custom_restrictors(klass)
21
- # Stub for now
22
- []
26
+ res
23
27
  end
24
28
 
25
29
  # obj:: Instance with restrictors enabled
26
30
  # form:: Form object to attach restrictor fields to
31
+ # args:: Argument hash ->
32
+ # :include_disabled:: includes all restrictors
27
33
  # Provides form items for restrictors in an array of format:
28
34
  # [[restrictor_name_label, form_selection_string]]
29
- def edit_full_restrictors(obj, form)
35
+ def edit_full_restrictors(obj, form, args={})
36
+ r_args = args[:include_disabled] ? [:include_disabled] : []
30
37
  if(obj.class.respond_to?(:full_restrictors))
31
- obj.class.full_restrictors.map do |restrictor|
32
- if(restrictor[:user_values_only])
33
- if(restrictor[:user_values_only].respond_to?(:call))
34
- user = restrictor[:user_values_only].call
38
+ obj.class.full_restrictors(*r_args).map do |restrictor|
39
+ if(restrictor[:views][:user_values_only])
40
+ if(restrictor[:views][:user_values_only].respond_to?(:call))
41
+ user = restrictor[:views][:user_values_only].call
35
42
  if(user)
36
43
  values = user.send(restrictor[:name].to_sym).find(:all, :order => restrictor[:value])
37
44
  else
38
- values = restrictor[:user_values_only].send(restrictor[:name].to_sym).find(:all, :order => restrictor[:value])
45
+ values = restrictor[:views][:user_values_only].send(restrictor[:name].to_sym).find(:all, :order => restrictor[:views][:value])
39
46
  end
40
47
  end
41
48
  end
42
- values = restrictor[:class].find(:all, :order => restrictor[:value]) unless values
49
+ @_restrictor_inflector_helper ||= Class.send(:include, ActiveSupport::Inflector).new
50
+ values = restrictor[:class].find(:all, :order => restrictor[:views][:value]) unless values
43
51
  [
44
52
  form.label(restrictor[:name]),
45
53
  form.collection_select(
46
- restrictor[:name],
54
+ "#{@_restrictor_inflector_helper.singularize(restrictor[:name])}_ids",
47
55
  values,
48
- restrictor[:id],
49
- restrictor[:value],
56
+ restrictor[:views][:id],
57
+ restrictor[:views][:value],
50
58
  {
51
- :include_blank => restrictor[:include_blank],
52
- :selected => Array(obj.send(restrictor[:name])).map(&restrictor[:id].to_sym)
59
+ :include_blank => restrictor[:views][:include_blank],
60
+ :selected => Array(obj.send(restrictor[:name])).map(&restrictor[:views][:id].to_sym)
53
61
  },
54
- :multiple => restrictor[:multiple]
62
+ :multiple => restrictor[:views][:multiple]
55
63
  )
56
64
  ]
57
65
  end
@@ -59,11 +67,6 @@ module ActiveRestrictors
59
67
  []
60
68
  end
61
69
  end
62
-
63
- def edit_custom_restrictors(klass)
64
- # Stub for now
65
- []
66
- end
67
70
  end
68
71
  end
69
72
 
@@ -13,5 +13,5 @@ module ActiveRestrictors
13
13
  end
14
14
  end
15
15
 
16
- VERSION = Version.new('0.1.1')
16
+ VERSION = Version.new('0.2.0')
17
17
  end
@@ -0,0 +1,116 @@
1
+ require 'active_record'
2
+ require 'active_record/migration'
3
+ require 'benchmark'
4
+ class ModelSetup < ActiveRecord::Migration
5
+ def self.up
6
+ create_table :users do |t|
7
+ t.string :username
8
+ t.boolean :active
9
+ end
10
+ create_table :fubars do |t|
11
+ t.string :name
12
+ t.boolean :enabled
13
+ t.integer :user_id
14
+ end
15
+ create_table :permissions do |t|
16
+ t.string :name
17
+ end
18
+ create_table :groups do |t|
19
+ t.string :name
20
+ end
21
+ create_table :user_permissions do |t|
22
+ t.integer :user_id
23
+ t.integer :permission_id
24
+ end
25
+ create_table :fubar_permissions do |t|
26
+ t.integer :fubar_id
27
+ t.integer :permission_id
28
+ end
29
+ create_table :user_groups do |t|
30
+ t.integer :group_id
31
+ t.integer :user_id
32
+ end
33
+ create_table :fubar_groups do |t|
34
+ t.integer :group_id
35
+ t.integer :fubar_id
36
+ end
37
+ end
38
+ end
39
+
40
+ ModelSetup.up
41
+
42
+ class User < ActiveRecord::Base
43
+ cattr_accessor :current_user
44
+ has_many :user_permissions, :dependent => :destroy
45
+ has_many :permissions, :through => :user_permissions
46
+ has_many :user_groups, :dependent => :destroy
47
+ has_many :groups, :through => :user_groups
48
+ has_many :fubars, :dependent => :destroy
49
+ end
50
+
51
+ class Permission < ActiveRecord::Base
52
+ has_many :user_permissions, :dependent => :destroy
53
+ has_many :users, :through => :user_permissions
54
+ has_many :fubar_permissions, :dependent => :destroy
55
+ has_many :fubars, :through => :fubar_permissions
56
+ end
57
+
58
+ class Group < ActiveRecord::Base
59
+ has_many :user_groups, :dependent => :destroy
60
+ has_many :users, :through => :user_groups
61
+ has_many :fubar_groups, :dependent => :destroy
62
+ has_many :fubars, :through => :fubar_groups
63
+ end
64
+
65
+ class Fubar < ActiveRecord::Base
66
+ include ActiveRestrictor
67
+ has_many :fubar_permissions, :dependent => :destroy
68
+ has_many :permissions, :through => :fubar_permissions
69
+ has_many :fubar_groups, :dependent => :destroy
70
+ has_many :groups, :through => :fubar_groups
71
+ belongs_to :user
72
+ end
73
+
74
+ class UserPermission < ActiveRecord::Base
75
+ belongs_to :user
76
+ belongs_to :permission
77
+ end
78
+
79
+ class FubarPermission < ActiveRecord::Base
80
+ belongs_to :fubar
81
+ belongs_to :permission
82
+ end
83
+
84
+ class FubarGroup < ActiveRecord::Base
85
+ belongs_to :fubar
86
+ belongs_to :group
87
+ end
88
+
89
+ class UserGroup < ActiveRecord::Base
90
+ belongs_to :user
91
+ belongs_to :group
92
+ end
93
+
94
+ def scrub_all
95
+ Fubar.restrictors.clear
96
+ UserGroup.delete_all
97
+ FubarGroup.delete_all
98
+ UserPermission.delete_all
99
+ FubarPermission.delete_all
100
+ User.current_user = nil
101
+ Fubar.update_all(:user_id => nil)
102
+ end
103
+
104
+ # Setup our test models
105
+ 10.times do |i|
106
+ User.create(:username => "user_#{i}", :active => i % 2 == 0)
107
+ Fubar.create(:name => "fubar_#{i}", :enabled => i % 2 == 0)
108
+ end
109
+
110
+ 5.times do |i|
111
+ Permission.create(:name => "permission_#{i}")
112
+ end
113
+
114
+ 5.times do |i|
115
+ Group.create(:name => "group_#{i}")
116
+ end
@@ -0,0 +1,386 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'setup')
2
+
3
+ describe ActiveRestrictor do
4
+ # Check for proper setup at the start
5
+ describe 'after suite setup' do
6
+ it 'should have properly setup models' do
7
+ assert_equal 10, User.count
8
+ assert_equal 10, Fubar.count
9
+ assert_equal 5, Group.count
10
+ assert_equal 5, Permission.count
11
+ refute_equal User.count, User.where(:active => true).count
12
+ end
13
+ end
14
+
15
+
16
+ #!!!! basic_user type restrictions
17
+ describe 'when basic user restrictor only allows active users' do
18
+ before do
19
+ Fubar.class_eval do
20
+ add_restrictor(:active,
21
+ :type => :basic_user,
22
+ :scope => User.where(:active => true)
23
+ )
24
+ end
25
+ end
26
+ after do
27
+ scrub_all
28
+ end
29
+ it 'should only allow active users access to fubars' do
30
+ u = User.where(:active => true).first
31
+ assert u.allowed_fubars.count > 0
32
+ u = User.where(:active => false).first
33
+ assert_equal 0, u.allowed_fubars.count
34
+ end
35
+ it 'should only show active users from fubars' do
36
+ Fubar.all.each do |fubar|
37
+ fubar.allowed_users.each do |user|
38
+ assert user.active
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe 'when basic user restrictor provide enabled block' do
45
+ before do
46
+ Fubar.class_eval do
47
+ add_restrictor(:active,
48
+ :type => :basic_user,
49
+ :scope => User.where(:active => true),
50
+ :enabled => lambda{ User.current_user.nil? || !User.current_user.username == 'user_1' }
51
+ )
52
+ end
53
+ u = User.find_by_username('user_1')
54
+ u.active = false
55
+ u.save!
56
+ end
57
+ after do
58
+ scrub_all
59
+ end
60
+ it 'should not allow fubars for user_1 when current_user is unset' do
61
+ assert_equal 0, User.find_by_username('user_1').allowed_fubars.count
62
+ end
63
+ it 'should allow fubars for user_1 when current_user is set' do
64
+ u = User.find_by_username('user_1')
65
+ User.current_user = u
66
+ assert u.allowed_fubars.count > 0
67
+ end
68
+ end
69
+
70
+ #!!! basic model type restrictions
71
+ describe 'when basic model restrictor only allows enabled fubars' do
72
+ before do
73
+ Fubar.class_eval do
74
+ add_restrictor(:enabled,
75
+ :type => :basic_model,
76
+ :scope => Fubar.where(:enabled => true)
77
+ )
78
+ end
79
+ end
80
+ after do
81
+ scrub_all
82
+ end
83
+ it 'should only allow users to access enabled fubars' do
84
+ User.all.each do |user|
85
+ user.allowed_fubars.each do |fubar|
86
+ assert fubar.enabled?
87
+ end
88
+ end
89
+ end
90
+ it 'should not provide users from disabled fubars' do
91
+ assert Fubar.where(:enabled => false).count > 0
92
+ Fubar.where(:enabled => false).all.each do |fubar|
93
+ assert_equal 0, fubar.allowed_users.count
94
+ end
95
+ end
96
+ end
97
+
98
+ #!!! implicit model type restrictions
99
+ describe 'when implict restrictor only allows fubars belonging to users' do
100
+ before do
101
+ Fubar.class_eval do
102
+ add_restrictor(:user,
103
+ :type => :implicit,
104
+ :scope => lambda{ where(:user_id => User.current_user.id) }
105
+ )
106
+ end
107
+ u = User.find_by_username("user_1")
108
+ 3.times do |i|
109
+ f = Fubar.find_by_name("fubar_#{i}")
110
+ f.user_id = u.id
111
+ f.save!
112
+ end
113
+ User.current_user = u
114
+ end
115
+ after do
116
+ scrub_all
117
+ end
118
+ it 'should show 3 fubars for user_1' do
119
+ assert_equal 3, User.find_by_username('user_1').fubars.count
120
+ end
121
+ it 'should show no fubars for users not user_1' do
122
+ User.where("username != 'user_1'").all.each do |user|
123
+ assert_equal 0, user.fubars.count
124
+ end
125
+ end
126
+ it 'should only show allowed users as assigned users' do
127
+ Fubar.all.each do |fubar|
128
+ if(fubar.user_id.nil?)
129
+ assert_equal 0, fubar.allowed_users.count
130
+ else
131
+ assert_equal 1, fubar.allowed_users.count
132
+ assert_equal 'user_1', fubar.allowed_users.first.username
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ #!!! full type restrictions
139
+ describe 'when full permission restrictor is applied' do
140
+ before do
141
+ Fubar.class_eval do
142
+ add_restrictor(:permissions,
143
+ :type => :full
144
+ )
145
+ end
146
+ 3.times do |i|
147
+ perm = Permission.find_by_name("permission_#{i}")
148
+ user = User.find_by_username("user_#{i}")
149
+ fubar = Fubar.find_by_name("fubar_#{i}")
150
+ user.permissions << perm
151
+ fubar.permissions << perm
152
+ end
153
+ end
154
+ after do
155
+ scrub_all
156
+ end
157
+ it 'should only allow users with matching permissions' do
158
+ 3.times do |i|
159
+ user = User.find_by_username("user_#{i}")
160
+ fubar = Fubar.find_by_name("fubar_#{i}")
161
+ assert_equal 1, user.allowed_fubars.count
162
+ assert_equal 1, fubar.allowed_users.count
163
+ assert_equal "fubar_#{i}", user.allowed_fubars.first.name
164
+ assert_equal "user_#{i}", fubar.allowed_users.first.username
165
+ end
166
+ end
167
+ it 'should not allow users without matching permissions' do
168
+ 7.times do |i|
169
+ i = i + 3
170
+ user = User.find_by_username("user_#{i}")
171
+ fubar = Fubar.find_by_name("fubar_#{i}")
172
+ assert_equal 0, user.allowed_fubars.count
173
+ assert_equal 0, fubar.allowed_users.count
174
+ end
175
+ end
176
+ end
177
+
178
+ #!!! Stacked full restrictions
179
+ describe 'when full permission and full group restrictors are applied' do
180
+ before do
181
+ Fubar.class_eval do
182
+ add_restrictor(:permissions,
183
+ :type => :full
184
+ )
185
+ add_restrictor(:groups,
186
+ :type => :full
187
+ )
188
+ end
189
+ 4.times do |i|
190
+ perm = Permission.find_by_name("permission_#{i}")
191
+ user = User.find_by_username("user_#{i}")
192
+ group = Group.find_by_name("group_#{i}")
193
+ fubar = Fubar.find_by_name("fubar_#{i}")
194
+ if(i % 2 == 0 || i == 3)
195
+ user.permissions << perm
196
+ fubar.permissions << perm
197
+ end
198
+ if(i % 2 == 1 || i == 3)
199
+ user.groups << group
200
+ fubar.groups << group
201
+ end
202
+ end
203
+ end
204
+ after do
205
+ scrub_all
206
+ end
207
+
208
+ it 'should be setup correctly' do
209
+ 3.times do |i|
210
+ u = User.find_by_username("user_#{i}")
211
+ if(u.groups.count > 0)
212
+ assert_equal(1, u.groups.count)
213
+ assert_equal(0, u.permissions.count)
214
+ elsif(u.permissions.count > 0)
215
+ assert_equal(1, u.permissions.count)
216
+ assert_equal(0, u.groups.count)
217
+ else
218
+ flunk "User should have one group or one permission assigned"
219
+ end
220
+ end
221
+ assert_equal 1, User.find_by_username('user_3').groups.count
222
+ assert_equal 1, User.find_by_username('user_3').permissions.count
223
+ assert_equal 0, User.find_by_username('user_4').groups.count
224
+ assert_equal 0, User.find_by_username('user_5').permissions.count
225
+ end
226
+ it 'should allow not allow users with single matching permission or group only' do
227
+ 3.times do |i|
228
+ user = User.find_by_username("user_#{i}")
229
+ assert_equal(0, user.allowed_fubars.count)
230
+ end
231
+ end
232
+ it 'should allow users with both matching permission and group' do
233
+ assert_equal(1, User.find_by_username('user_3').allowed_fubars.count)
234
+ end
235
+ it 'should not allow users with no matching permission or group' do
236
+ assert_equal(0, User.find_by_username('user_4').allowed_fubars.count)
237
+ end
238
+ end
239
+
240
+ describe 'when full permission and full group restrictors are applied using default_view_all' do
241
+ before do
242
+ Fubar.class_eval do
243
+ add_restrictor(:permissions,
244
+ :type => :full,
245
+ :default_view_all => true
246
+ )
247
+ add_restrictor(:groups,
248
+ :type => :full,
249
+ :default_view_all => true
250
+ )
251
+ end
252
+ 4.times do |i|
253
+ perm = Permission.find_by_name("permission_#{i}")
254
+ user = User.find_by_username("user_#{i}")
255
+ group = Group.find_by_name("group_#{i}")
256
+ fubar = Fubar.find_by_name("fubar_#{i}")
257
+ if(i % 2 == 0 || i == 3)
258
+ user.permissions << perm
259
+ fubar.permissions << perm
260
+ end
261
+ if(i % 2 == 1 || i == 3)
262
+ user.groups << group
263
+ fubar.groups << group
264
+ end
265
+ end
266
+ end
267
+ after do
268
+ scrub_all
269
+ end
270
+
271
+ it 'should only provide fubars without assigned groups and permissions to users without assigned groups and permissions' do
272
+ User.includes(:groups, :permissions).where(:groups => {:id => nil}, :permissions => {:id => nil}).each do |user|
273
+ assert_equal(6, user.allowed_fubars.count)
274
+ user.allowed_fubars.each do |fubar|
275
+ assert_equal(0, fubar.groups.count)
276
+ assert_equal(0, fubar.permissions.count)
277
+ end
278
+ assert_equal(0, user.groups.count)
279
+ assert_equal(0, user.permissions.count)
280
+ end
281
+ end
282
+ it 'should provide fubars with with matching group or permissions and fubars without assigned groups or permissions' do
283
+ 4.times do |i|
284
+ user = User.find_by_username("user_#{i}")
285
+ assert_equal(7, user.allowed_fubars.count)
286
+ user.allowed_fubars.each do |fubar|
287
+ if(fubar.groups.count > 0)
288
+ assert_equal fubar.groups.first, user.groups.first
289
+ end
290
+ if(fubar.permissions.count > 0)
291
+ assert_equal fubar.permissions.first, user.permissions.first
292
+ end
293
+ end
294
+ end
295
+ end
296
+ it 'should allow all users when no permission and groups are defined' do
297
+ 6.times do |i|
298
+ fubar = Fubar.find_by_name("fubar_#{i + 4}")
299
+ assert_equal(10, fubar.allowed_users.count)
300
+ end
301
+ end
302
+ it 'should only allow users with matching permission or group' do
303
+ 4.times do |i|
304
+ fubar = Fubar.find_by_name("fubar_#{i}")
305
+ assert_equal(1, fubar.allowed_users.count)
306
+ end
307
+ end
308
+ end
309
+
310
+ #!!! Stacked mixed restrictions
311
+ describe 'when basic and full restrictors are applied' do
312
+ before do
313
+ Fubar.class_eval do
314
+ add_restrictor(:enabled,
315
+ :type => :basic_user,
316
+ :scope => User.where(:active => true)
317
+ )
318
+ add_restrictor(:enabled,
319
+ :type => :basic_model,
320
+ :scope => where(:enabled => true)
321
+ )
322
+ add_restrictor(:permissions,
323
+ :type => :full
324
+ )
325
+ end
326
+ 4.times do |i|
327
+ user = User.find_by_username("user_#{i}")
328
+ perm = Permission.find_by_name("permission_#{i}")
329
+ fubar = Fubar.find_by_name("fubar_#{i}")
330
+ user.permissions << perm
331
+ fubar.permissions << perm
332
+ end
333
+ end
334
+ after do
335
+ scrub_all
336
+ end
337
+
338
+ it "should have disabled and enabled users and fubars setup" do
339
+ users = 4.times.map{|i| User.find_by_username("user_#{i}")}
340
+ fubars = 4.times.map{|i| Fubar.find_by_name("fubar_#{i}")}
341
+ assert users.detect(&:active?), 'Expecting active users'
342
+ assert users.detect{|u| !u.active?}, 'Expecting inactive users'
343
+ assert fubars.detect(&:enabled?), 'Expecting enabled fubars'
344
+ assert fubars.detect{|f| !f.enabled?}, 'Expecting disabled fubars'
345
+ end
346
+ it "should not show any allowed users when fubar is disabled" do
347
+ fubar = Fubar.where(:name => 4.times.map{|i|"fubar_#{i}"}, :enabled => false).first
348
+ assert fubar, "Expecting Fubar instance to be found"
349
+ assert_equal 0, fubar.allowed_users.count
350
+ end
351
+ it "should only show active users when fubar is enabled" do
352
+ fubar = Fubar.where(:name => 4.times.map{|i|"fubar_#{i}"}, :enabled => true).first
353
+ assert fubar, "Expecting Fubar instance to be found"
354
+ assert fubar.allowed_users.count > 0, 'Expecting allowed users to be found'
355
+ fubar.allowed_users.each do |user|
356
+ assert user.active?, 'Expecting user to be active'
357
+ end
358
+ end
359
+ it "should not show any allowed fubars when user is inactive" do
360
+ user = User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => false).first
361
+ assert user, "Expecting User instance to be found"
362
+ assert_equal(0, user.allowed_fubars.count)
363
+ end
364
+ it "should only show enabled fubars when user is active" do
365
+ user = User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => true).first
366
+ assert user, "Expecting User instance to be found"
367
+ assert user.allowed_fubars.count > 0, 'Expecting allowed fubars to be found'
368
+ user.allowed_fubars.each do |fubar|
369
+ assert fubar.enabled?, 'Expecting fubar to be enabled'
370
+ end
371
+ end
372
+ it "should only show enabled fubars with same permission as user" do
373
+ User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => true).all.each do |user|
374
+ assert user.active?, 'Expecting active user'
375
+ assert user.allowed_fubars.count > 0, 'Expecting user to have allowed fubars'
376
+ user.allowed_fubars.each do |fubar|
377
+ assert fubar.enabled?, 'Expecting Fubar to be enabled'
378
+ assert_equal fubar.permissions.first, user.permissions.first
379
+ end
380
+ end
381
+ end
382
+ end
383
+
384
+ # TODO: model_custom / user_custom
385
+ # TODO: more complex stacking
386
+ end
data/spec/setup.rb ADDED
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'active_record'
5
+ if(RUBY_PLATFORM == 'java')
6
+ require 'jdbc/sqlite3'
7
+ else
8
+ require 'sqlite3'
9
+ end
10
+ require 'active_restrictors'
11
+ require 'minitest/autorun'
12
+
13
+ ActiveRecord::Base.establish_connection(
14
+ :adapter => 'sqlite3',
15
+ :database => ':memory:'
16
+ )
17
+ load File.join(File.expand_path(File.dirname(__FILE__)), 'model_definitions.rb')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_restrictors
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chris Roberts
@@ -15,10 +15,24 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-09 00:00:00 -08:00
18
+ date: 2012-01-20 00:00:00 -08:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ version: "3.0"
34
+ type: :runtime
35
+ version_requirements: *id001
22
36
  description: Restrictors for Models
23
37
  email: chrisroberts.code@gmail.com
24
38
  executables: []
@@ -29,13 +43,19 @@ extra_rdoc_files:
29
43
  - README.rdoc
30
44
  - CHANGELOG.rdoc
31
45
  files:
46
+ - Gemfile.lock
47
+ - spec/restrictor_spec.rb
48
+ - spec/setup.rb
49
+ - spec/model_definitions.rb
32
50
  - README.rdoc
33
- - CHANGELOG.rdoc
34
- - active_restrictors.gemspec
51
+ - Gemfile
35
52
  - lib/active_restrictors/active_restrictor_views.rb
36
53
  - lib/active_restrictors/version.rb
37
54
  - lib/active_restrictors/active_restrictor.rb
38
55
  - lib/active_restrictors.rb
56
+ - active_restrictors.gemspec
57
+ - CHANGELOG.rdoc
58
+ - Rakefile
39
59
  has_rdoc: true
40
60
  homepage: http://bitbucket.org/chrisroberts/active_restrictors
41
61
  licenses: []