permissive 0.0.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/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
|