permissive 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +179 -0
- data/VERSION +1 -0
- data/spec/acts_as_permissive_spec.rb +192 -0
- data/spec/permissions_spec.rb +44 -0
- data/spec/spec_helper.rb +59 -0
- metadata +63 -0
data/README.markdown
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
Permissive gives your ActiveRecord models granular permission support
|
2
|
+
=
|
3
|
+
Permissive combines a model-based permissions system with bitmasking to
|
4
|
+
create a flexible approach to maintaining permissions on your ActiveRecord
|
5
|
+
models. It supports an easy-to-use set of methods for accessing and
|
6
|
+
determining permissions, including some fun metaprogramming.
|
7
|
+
|
8
|
+
Installation
|
9
|
+
-
|
10
|
+
|
11
|
+
1. Get yourself some code. You can install as a gem:
|
12
|
+
|
13
|
+
`gem install permissive`
|
14
|
+
|
15
|
+
or as a plugin:
|
16
|
+
|
17
|
+
`script/plugin install git://github.com/flipsasser/permissive.git`
|
18
|
+
|
19
|
+
2. Generate a migration so you can get some sweet table action:
|
20
|
+
|
21
|
+
`script/generate permissive_migration`
|
22
|
+
|
23
|
+
`rake db:migrate`
|
24
|
+
|
25
|
+
Usage
|
26
|
+
-
|
27
|
+
|
28
|
+
First, define a few permissions constants. We'll define them in `Rails.root/config/initializers/permissive.rb`. The best practice is to name them in a verb format that follows this pattern: "Object can `DO_PERMISSION_NAME`".
|
29
|
+
|
30
|
+
Permission constants need to be int values counting up from zero. We use ints because Permissive uses bit masking to keep permissions data compact and performant.
|
31
|
+
|
32
|
+
module Permissive::Permissions
|
33
|
+
MANAGE_GAMES = 0
|
34
|
+
CONTROL_RIDES = 1
|
35
|
+
PUNCH = 2
|
36
|
+
end
|
37
|
+
|
38
|
+
And that's all it takes to configure permissions! Now that we have them, let's grant them to a model or two:
|
39
|
+
|
40
|
+
class Employee < ActiveRecord::Base
|
41
|
+
acts_as_permissive
|
42
|
+
validates_presence_of :first_name, :last_name
|
43
|
+
end
|
44
|
+
|
45
|
+
class Company < ActiveRecord::Base
|
46
|
+
validates_presence_of :name
|
47
|
+
end
|
48
|
+
|
49
|
+
Easy-peasy, right? Let's try granting a few permissions:
|
50
|
+
|
51
|
+
@james = Employee.create(:first_name => 'James', :last_name => 'Brennan')
|
52
|
+
@frigo = Employee.create(:first_name => 'Tommy', :last_name => 'Frigo')
|
53
|
+
@adventureland = Company.create(:name => 'Adventureland')
|
54
|
+
|
55
|
+
# Okay, let's do some granting. We'll start by scoping to a specific company.
|
56
|
+
@james.can!(:manage_games, :on => @adventureland)
|
57
|
+
|
58
|
+
# Now let's do some permission checking.
|
59
|
+
@james.can?(:manage_games, :on => @adventureland) #=> true
|
60
|
+
|
61
|
+
# We can also use the metaprogramming syntax:
|
62
|
+
@james.can_manage_games_on?(@adventureland) #=> true
|
63
|
+
@james.can_control_rides_on?(@adventureland) #=> false
|
64
|
+
|
65
|
+
# We can check for multiple permissions, too:
|
66
|
+
@james.can?(:manage_games, :control_rides) #=> false
|
67
|
+
# OR:
|
68
|
+
@james.can_manage_games_and_control_rides?
|
69
|
+
|
70
|
+
# Scoping can be done through any object
|
71
|
+
@frigo.can!(:punch, :on => @james)
|
72
|
+
@frigo.can_punch_on?(@james) #=> true
|
73
|
+
|
74
|
+
# And the permissions aren't reciprocal
|
75
|
+
@james.can_punch_on?(@frigo) #=> false
|
76
|
+
|
77
|
+
# Of course, we can grant global (non-scoped) permissions, too:
|
78
|
+
@frigo.can!(:control_rides)
|
79
|
+
@frigo.can_control_rides? #=> true
|
80
|
+
|
81
|
+
# BUT! Global permissions don't override scoped permissions.
|
82
|
+
@frigo.can_control_rides_on?(@adventureland) #=> false
|
83
|
+
|
84
|
+
# Likewise, scoped permissions don't bubble up globally:
|
85
|
+
@james.can_manage_games? #=> false
|
86
|
+
|
87
|
+
# And, last but not least, let's take all of those great permissions away:
|
88
|
+
@james.revoke(:manage_games, :on => @adventureland)
|
89
|
+
|
90
|
+
# We can revoke all permissions, in any scope, too:
|
91
|
+
@frigo.revoke(:all)
|
92
|
+
|
93
|
+
And that's it!
|
94
|
+
|
95
|
+
Scoping
|
96
|
+
-
|
97
|
+
|
98
|
+
Permissive supports scoping at the class-configuration level, which adds relationships to permitted objects:
|
99
|
+
|
100
|
+
class Employee < ActiveRecord::Base
|
101
|
+
acts_as_permissive :scope => :company
|
102
|
+
end
|
103
|
+
|
104
|
+
@frigo.permissive_companies #=> [Company 1, Company 2]
|
105
|
+
|
106
|
+
Replacing Permissions
|
107
|
+
-
|
108
|
+
|
109
|
+
Sometimes you want to overwrite all previous permissions in a can! method. That's pretty easy: just add :reset => true to the options.
|
110
|
+
|
111
|
+
@frigo.can!(:control_rides, :on => @adventureland, :reset => true)
|
112
|
+
|
113
|
+
Next Steps
|
114
|
+
-
|
115
|
+
|
116
|
+
There's a number of things I want to add to the permissive settings. At the moment, Permissive currently support scoping at the class level, BUT all it really does is add a `has_many` relationship. `@employee.can!(:do_anything)` will still work, as will `@employee.can!(:do_something, :on => @something_that_isnt_a_company)`. That's pretty confusing to me. Adding more granular permissions might be cooler:
|
117
|
+
|
118
|
+
class Employee < ActiveRecord::Base
|
119
|
+
has_permissions do
|
120
|
+
on :companies
|
121
|
+
on :employees
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
which might yield something like
|
126
|
+
|
127
|
+
@employee.permissive_companies
|
128
|
+
# and
|
129
|
+
@employee.can_control_rides_in_company @adventureland
|
130
|
+
|
131
|
+
I'd also like to support a more intelligent grammar:
|
132
|
+
|
133
|
+
@james.can_punch? @frigo
|
134
|
+
@frigo.can!(:control_rides, :in => @adventureland)
|
135
|
+
|
136
|
+
Meta-programmed methods for granting and revoking would be cool, too:
|
137
|
+
|
138
|
+
@james.can_punch! @frigo
|
139
|
+
@frigo.cannot_control_rides_in! @adventureland
|
140
|
+
|
141
|
+
And while we're on the subject of metaprogramming, let's add some OR-ing to the whole thing:
|
142
|
+
|
143
|
+
@james.can_control_rides_or_manage_games_in? @adventureland
|
144
|
+
|
145
|
+
I'd also like to enable Permissive::Templates (pre-set permission groups, like roles):
|
146
|
+
|
147
|
+
administrator = Permissive::Template.named('Administrator')
|
148
|
+
@james.acts_like administrator
|
149
|
+
|
150
|
+
Next up! I currently use a manual reset to grant permissions through a controller. It would by great to DRY this stuff up and provide some decent path for moving permissions into HTML forms. Right now, it looks something like this:
|
151
|
+
|
152
|
+
<%= check_box_tag("employee[permissions][]", Permissive::Permissions::CONTROL_RIDES, @employee.can_control_rides?) %> Control rides
|
153
|
+
|
154
|
+
.. and in the controller:
|
155
|
+
|
156
|
+
def update
|
157
|
+
@employee.can!(params[:employees].delete(:permissions), :revert => true)
|
158
|
+
respond_to do |format|
|
159
|
+
...
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
Finally, I'd like to use the `grant_mask` support that exists on the Permissive::Permission model to control what people can or cannot allow others to do. This would necessitate one of two things - first, a quick way of iterating over a person's granting permissions, e.g.:
|
164
|
+
|
165
|
+
<% current_user.grant_permissions.each do |permission| %>
|
166
|
+
<!-- Do something! -->
|
167
|
+
<% end %>
|
168
|
+
|
169
|
+
and second, write-time checking of grantor permissions. Something like this, maybe:
|
170
|
+
|
171
|
+
def update
|
172
|
+
current_user.grant(params[:employees][:permissions], :to => @employee)
|
173
|
+
end
|
174
|
+
|
175
|
+
which would allow the Permissive::Permission model to make sure whatever `current_user` is granting to @employee, they're **allowed** to grant to @employee.
|
176
|
+
|
177
|
+
And that's it! Like all of my projects, I extracted it from some live development - which means it, too, is still in development. So please feel free to contribute!
|
178
|
+
|
179
|
+
Copyright (c) 2009 Flip Sasser, released under the MIT license
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
# Setup some basic models to test with. We'll set permissions on both,
|
4
|
+
# and then test :scope'd permissions through both.
|
5
|
+
class Permissive::Organization < ActiveRecord::Base
|
6
|
+
set_table_name :permissive_organizations
|
7
|
+
end
|
8
|
+
|
9
|
+
class Permissive::User < ActiveRecord::Base
|
10
|
+
set_table_name :permissive_users
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Permissive::Permission do
|
14
|
+
before :each do
|
15
|
+
PermissiveSpecHelper.db_up
|
16
|
+
end
|
17
|
+
|
18
|
+
after :each do
|
19
|
+
PermissiveSpecHelper.db_down
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "`acts_as_permissive' default class method" do
|
23
|
+
[Permissive::User, Permissive::Organization].each do |model|
|
24
|
+
before :each do
|
25
|
+
model.acts_as_permissive
|
26
|
+
end
|
27
|
+
|
28
|
+
describe model do
|
29
|
+
it "should create a permissions reflection" do
|
30
|
+
model.new.should respond_to(:permissions)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should create a `can?' method" do
|
34
|
+
model.new.should respond_to(:can?)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create a `revoke' method" do
|
38
|
+
model.new.should respond_to(:revoke)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "permissions checking" do
|
45
|
+
before :each do
|
46
|
+
Permissive::User.acts_as_permissive
|
47
|
+
@user = Permissive::User.create
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should allow permissions checks through the `can?' method" do
|
51
|
+
@user.can?(:edit_organizations).should be_false
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should respond to the `can!' method" do
|
55
|
+
@user.should respond_to(:can!)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should allow permissions setting through the `can!' method" do
|
59
|
+
count = @user.permissions.count
|
60
|
+
@user.can!(:view_users)
|
61
|
+
@user.permissions.count.should == count.next
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return correct permissions through the `can?' method" do
|
65
|
+
@user.can!(:view_users)
|
66
|
+
@user.can?(:view_users).should be_true
|
67
|
+
['FINALIZE_LAB_SELECTION_LIST', 'SEARCH_APPLICANTS', 'CREATE_BASIC_USER', 'VIEW_BUDGET_REPORT'].each do |permission|
|
68
|
+
@user.can?(permission).should be_false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return correct permissions on multiple requests" do
|
73
|
+
@user.can!(:view_users)
|
74
|
+
@user.can!(:view_budget_report)
|
75
|
+
@user.can?(:view_users, :view_budget_report).should be_true
|
76
|
+
['FINALIZE_LAB_SELECTION_LIST', 'SEARCH_APPLICANTS', 'CREATE_BASIC_USER'].each do |permission|
|
77
|
+
@user.can?(:view_users, permission).should be_false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should revoke the correct permissions through the `revoke' method" do
|
82
|
+
@user.can!(:view_users, :view_budget_report)
|
83
|
+
@user.can?(:view_users).should be_true
|
84
|
+
@user.can?(:view_budget_report).should be_true
|
85
|
+
@user.revoke(:view_users)
|
86
|
+
@user.can?(:view_users).should be_false
|
87
|
+
@user.can?(:view_budget_report).should be_true
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should revoke the full permissions through the `revoke' method w/an :all argument" do
|
91
|
+
@user.can!(:view_users, :view_budget_report)
|
92
|
+
@user.can?(:view_users).should be_true
|
93
|
+
@user.can?(:view_budget_report).should be_true
|
94
|
+
@user.revoke(:all)
|
95
|
+
@user.can?(:view_users).should be_false
|
96
|
+
@user.can?(:view_budget_report).should be_false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "scoped permissions" do
|
101
|
+
before :each do
|
102
|
+
Permissive::User.acts_as_permissive(:scope => :organizations)
|
103
|
+
@user = Permissive::User.create
|
104
|
+
@organization = Permissive::Organization.create
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should allow scoped permissions checks through the `can?' method" do
|
108
|
+
@user.can?(:view_users, :on => @organization).should be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return correct permissions through a scoped `can?' method" do
|
112
|
+
@user.can!(:view_users, :on => @organization)
|
113
|
+
@user.can?(:view_users, :on => @organization).should be_true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should not respond to generic permissions on scoped permissions" do
|
117
|
+
@user.can!(:view_users, :on => @organization)
|
118
|
+
@user.can?(:view_users).should be_false
|
119
|
+
@user.can?(:view_users, :on => @organization).should be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should revoke the correct permissions through the `revoke' method" do
|
123
|
+
@user.can!(:view_users, :view_budget_report, :on => @organization)
|
124
|
+
@user.can?(:view_users, :on => @organization).should be_true
|
125
|
+
@user.can?(:view_budget_report, :on => @organization).should be_true
|
126
|
+
@user.revoke(:view_users, :on => @organization)
|
127
|
+
@user.can?(:view_users, :on => @organization).should be_false
|
128
|
+
@user.can?(:view_budget_report, :on => @organization).should be_true
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should revoke the full permissions through the `revoke' method w/an :all argument" do
|
132
|
+
@user.can!(:create_basic_user)
|
133
|
+
@user.can!(:view_users, :view_budget_report, :on => @organization)
|
134
|
+
@user.can?(:view_users, :on => @organization).should be_true
|
135
|
+
@user.can?(:view_budget_report, :on => @organization).should be_true
|
136
|
+
@user.can?(:create_basic_user).should be_true
|
137
|
+
@user.revoke(:all, :on => @organization)
|
138
|
+
!@user.can?(:view_users, :on => @organization).should be_false
|
139
|
+
!@user.can?(:view_budget_report, :on => @organization).should be_false
|
140
|
+
@user.can?(:create_basic_user).should be_true
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "automatic method creation" do
|
146
|
+
before :each do
|
147
|
+
Permissive::User.acts_as_permissive(:scope => :organizations)
|
148
|
+
@user = Permissive::User.create
|
149
|
+
@organization = Permissive::Organization.create
|
150
|
+
@user.can!(:finalize_lab_selection_list)
|
151
|
+
@user.can!(:create_basic_user)
|
152
|
+
@user.can!(:view_users, :on => @organization)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should not respond to invalid permission methods" do
|
156
|
+
lambda {
|
157
|
+
@user.can_finalize_lab_selection_list_fu?
|
158
|
+
}.should raise_error(NoMethodError)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should cache chained methods" do
|
162
|
+
@user.respond_to?(:can_finalize_lab_selection_list_and_view_users?).should be_false
|
163
|
+
@user.can_finalize_lab_selection_list_and_view_users?.should be_false
|
164
|
+
@user.should respond_to(:can_finalize_lab_selection_list_and_view_users?)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should respond to valid permission methods" do
|
168
|
+
@user.can_finalize_lab_selection_list?.should be_true
|
169
|
+
@user.can_create_basic_user?.should be_true
|
170
|
+
['SEARCH_APPLICANTS', 'VIEW_USERS', 'VIEW_BUDGET_REPORT'].each do |permission|
|
171
|
+
@user.send("can_#{permission.downcase}?").should be_false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should respond to chained permission methods" do
|
176
|
+
@user.can_finalize_lab_selection_list_and_create_basic_user?.should be_true
|
177
|
+
['SEARCH_APPLICANTS', 'VIEW_USERS', 'VIEW_BUDGET_REPORT'].each do |permission|
|
178
|
+
@user.send("can_finalize_lab_selection_list_and_#{permission.downcase}?").should be_false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should respond to scoped permission methods" do
|
183
|
+
@user.can_view_users_on?(@organization).should be_true
|
184
|
+
['FINALIZE_LAB_SELECTION_LIST', 'SEARCH_APPLICANTS', 'CREATE_BASIC_USER', 'VIEW_BUDGET_REPORT'].each do |permission|
|
185
|
+
@user.send("can_#{permission.downcase}_on?", @organization).should be_false
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
PermissiveSpecHelper.clear_log
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
describe Permissive::Permissions do
|
3
|
+
before :each do
|
4
|
+
PermissiveSpecHelper.db_up
|
5
|
+
end
|
6
|
+
|
7
|
+
after :each do
|
8
|
+
PermissiveSpecHelper.db_down
|
9
|
+
end
|
10
|
+
|
11
|
+
context "permission constants" do
|
12
|
+
it "should have a `hash' method" do
|
13
|
+
Permissive::Permissions.should respond_to(:hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return an ordered hash when `hash' is called" do
|
17
|
+
Permissive::Permissions.hash.should be_instance_of(ActiveSupport::OrderedHash)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have symbol keys for the permission constants" do
|
21
|
+
Permissive::Permissions.hash.has_key?(:finalize_lab_selection_list).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should convert all CONSTANT values to base-2 compatible integers" do
|
25
|
+
Permissive::Permissions.constants.each do |constant|
|
26
|
+
Permissive::Permissions.hash[constant.downcase.to_sym].should == 2 ** Permissive::Permissions.const_get(constant)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should explode when a constant isn't Numeric" do
|
31
|
+
Permissive::Permissions.const_set('FOOBAR', 'achoo')
|
32
|
+
lambda {
|
33
|
+
Permissive::Permissions.hash
|
34
|
+
}.should raise_error(Permissive::PermissionError)
|
35
|
+
|
36
|
+
Permissive::Permissions.const_set('FOOBAR', 5)
|
37
|
+
lambda {
|
38
|
+
Permissive::Permissions.hash
|
39
|
+
}.should_not raise_error(Permissive::PermissionError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
PermissiveSpecHelper.clear_log
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activerecord'
|
3
|
+
require 'permissive'
|
4
|
+
|
5
|
+
module PermissiveSpecHelper
|
6
|
+
def self.clear_log
|
7
|
+
File.open(PermissiveSpecHelper.log_path, 'w') do |file|
|
8
|
+
file.puts ''
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.db_down
|
13
|
+
File.unlink(db) if File.exists?(db)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.db_up
|
17
|
+
db_down
|
18
|
+
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => db, :pool => 5, :timeout => 5000})
|
19
|
+
silence_stream(STDOUT) do
|
20
|
+
ActiveRecord::Schema.define do
|
21
|
+
create_table :permissive_users, :force => true do |t|
|
22
|
+
t.timestamps
|
23
|
+
end
|
24
|
+
create_table :permissive_organizations, :force => true do |t|
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
create_table :permissive_permissions do |t|
|
28
|
+
t.integer :permitted_object_id
|
29
|
+
t.string :permitted_object_type, :limit => 32
|
30
|
+
t.integer :scoped_object_id
|
31
|
+
t.string :scoped_object_type, :limit => 32
|
32
|
+
t.integer :mask, :default => 0
|
33
|
+
t.integer :grant_mask, :default => 0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.log_path
|
40
|
+
File.join(File.dirname(__FILE__), 'spec.log')
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def self.db
|
45
|
+
@@db ||= File.expand_path(File.join(File.dirname(__FILE__), 'test.sqlite3'))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Setup some test permissions
|
50
|
+
module Permissive::Permissions
|
51
|
+
FINALIZE_LAB_SELECTION_LIST = 0
|
52
|
+
SEARCH_APPLICANTS = 1
|
53
|
+
CREATE_BASIC_USER = 2
|
54
|
+
VIEW_USERS = 3
|
55
|
+
VIEW_BUDGET_REPORT = 4
|
56
|
+
end
|
57
|
+
|
58
|
+
# Setup the logging
|
59
|
+
ActiveRecord::Base.logger = Logger.new(PermissiveSpecHelper.log_path)
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: permissive
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Flip Sasser
|
8
|
+
- Simon Parsons
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-11-01 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: |-
|
18
|
+
Permissive combines a model-based permissions system with bitmasking to
|
19
|
+
create a flexible approach to maintaining permissions on your ActiveRecord
|
20
|
+
models. It supports an easy-to-use set of methods for accessing and
|
21
|
+
determining permissions, including some fun metaprogramming.
|
22
|
+
email: flip@x451.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.markdown
|
29
|
+
files:
|
30
|
+
- VERSION
|
31
|
+
- README.markdown
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/flipsasser/permissive
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Permissive gives your ActiveRecord models granular permission support
|
60
|
+
test_files:
|
61
|
+
- spec/acts_as_permissive_spec.rb
|
62
|
+
- spec/permissions_spec.rb
|
63
|
+
- spec/spec_helper.rb
|