reuser 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +75 -0
- data/Rakefile +24 -0
- data/lib/reuser/reuser.rb +70 -0
- data/lib/reuser/role.rb +43 -0
- data/lib/reuser.rb +2 -0
- data/spec/reuser/reuser.rb +97 -0
- data/spec/reuser.rb +1 -0
- metadata +53 -0
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#ReUser
|
2
|
+
##Purpose
|
3
|
+
Whenever you start a web app where a user has specific permissions, do you
|
4
|
+
end up writing your own solution or using something that has brain-bending
|
5
|
+
abstractions? If so, ReUser is the solution for you.
|
6
|
+
##Description
|
7
|
+
ReUser is an Internal DSL for Ruby to create roles and manage actions.
|
8
|
+
##Usage
|
9
|
+
Installing ReUser is easy:
|
10
|
+
|
11
|
+
gem install reuser
|
12
|
+
|
13
|
+
Now to incorporate it into a model:
|
14
|
+
|
15
|
+
require 'reuser'
|
16
|
+
|
17
|
+
class User
|
18
|
+
include ReUser
|
19
|
+
|
20
|
+
roles do
|
21
|
+
role(:admin).can :read, :write, :execute
|
22
|
+
role :user do |usr|
|
23
|
+
usr.can :read
|
24
|
+
usr.could :write {|obj| usr.owns?(obj)}
|
25
|
+
usr.cant :execute
|
26
|
+
end
|
27
|
+
role :writer, [:read, :write]
|
28
|
+
default :user
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
You can restrict the instances from doing things based on role:
|
33
|
+
|
34
|
+
def administrate
|
35
|
+
if @user.role? :admin
|
36
|
+
administer
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Or based on their actions:
|
41
|
+
|
42
|
+
def do_something_risky
|
43
|
+
if @user.can?(:do_this)
|
44
|
+
do_it
|
45
|
+
else
|
46
|
+
tell_them_to_get_out!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def do_something_with_obj
|
51
|
+
if @user.could?(:write, file)
|
52
|
+
write file
|
53
|
+
else
|
54
|
+
raise 'Not your file!'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##Issues?
|
59
|
+
Please don't hesitate to open up an issue. You can even contribute! Which
|
60
|
+
brings me to...
|
61
|
+
##Contributing!
|
62
|
+
This is open source, so I want others to help too. For now I have no plans
|
63
|
+
on adding too much more to this project, as far as functionality is
|
64
|
+
concerned, but don't let that get in your way of opening a request or forking
|
65
|
+
the project and adding something. I just ask that:
|
66
|
+
|
67
|
+
- You are polite about it.
|
68
|
+
- You test it.
|
69
|
+
- You explain it, or it is easy to read.
|
70
|
+
|
71
|
+
Following these will let us get along and make better software, quicker, and
|
72
|
+
with less bugs.(hypothetically)
|
73
|
+
|
74
|
+
I am still working on the final syntax, but we are getting closer. If you
|
75
|
+
have any suggestions on syntax, open a feature require
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
desc 'build the .gem file from gemspec'
|
2
|
+
task :build do
|
3
|
+
sh 'gem build reuser.gemspec'
|
4
|
+
end
|
5
|
+
|
6
|
+
desc 'install the gem from .gem file'
|
7
|
+
task :install do
|
8
|
+
sh 'gem install reuser-*.gem'
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'push the gem to rubygems.org'
|
12
|
+
task :push do
|
13
|
+
sh 'gem push reuser-*.gem'
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'make (build and install the gem from gemspec)'
|
17
|
+
task :make => [:build, :install]
|
18
|
+
|
19
|
+
desc 'run all the specs in the `spec/` directory.'
|
20
|
+
task :spec do
|
21
|
+
Dir.glob('./spec/reuser/**/*.rb').each do |file|
|
22
|
+
sh "rspec #{file}"
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative('../reuser')
|
2
|
+
|
3
|
+
module ReUser
|
4
|
+
class NoRoleError < StandardError; end;
|
5
|
+
class NoDefaultRoleError < StandardError; end;
|
6
|
+
instance_eval do
|
7
|
+
def included(subclass)
|
8
|
+
subclass.instance_eval do
|
9
|
+
@@roles = {}
|
10
|
+
def roles(&block)
|
11
|
+
@@roles ||= {}
|
12
|
+
yield if block
|
13
|
+
@@roles.freeze
|
14
|
+
@@roles.keys
|
15
|
+
end
|
16
|
+
|
17
|
+
def role(name, actions_list = nil, &block)
|
18
|
+
@@roles[name] ||= ReUser::Role.new(name)
|
19
|
+
role_name = @@roles[name]
|
20
|
+
yield(role_name) if block
|
21
|
+
if actions_list
|
22
|
+
role_name.can(*actions_list)
|
23
|
+
end
|
24
|
+
role_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def default(name = nil)
|
28
|
+
if name
|
29
|
+
@@roles[:default] = @@roles[name]
|
30
|
+
else
|
31
|
+
@@roles[:default]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
subclass.class_eval do
|
36
|
+
|
37
|
+
def role(name = nil)
|
38
|
+
if name
|
39
|
+
if @@roles[name]
|
40
|
+
@role = @@roles[name]
|
41
|
+
else
|
42
|
+
raise NoRoleError, "No role #{name} defined for #{self}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
@role
|
46
|
+
end
|
47
|
+
|
48
|
+
def role?(name)
|
49
|
+
role == self.class.role(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def can?(name)
|
53
|
+
!!role.can?(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
def cant?(name)
|
57
|
+
!role.can?(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def could?(name, obj)
|
61
|
+
role.could?(name, obj)
|
62
|
+
end
|
63
|
+
|
64
|
+
def couldnt?(name, obj)
|
65
|
+
!role.could?(name, obj)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/reuser/role.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative('../reuser')
|
2
|
+
|
3
|
+
module ReUser
|
4
|
+
class Role
|
5
|
+
attr_reader :actions
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@actions = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def can(*names)
|
12
|
+
names.each do |name|
|
13
|
+
action(name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def can?(name)
|
18
|
+
actions[name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def could(*names, &test)
|
22
|
+
names.each do |name|
|
23
|
+
action(name, test)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def could?(name, data)
|
28
|
+
@actions[name].call(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def actions(*names)
|
33
|
+
names.each do |name|
|
34
|
+
action(name)
|
35
|
+
end
|
36
|
+
@actions
|
37
|
+
end
|
38
|
+
|
39
|
+
def action(name, test = true)
|
40
|
+
@actions[name] = test
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/reuser.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'pry'
|
3
|
+
require_relative '../reuser'
|
4
|
+
|
5
|
+
class TestReUser
|
6
|
+
include ReUser
|
7
|
+
|
8
|
+
roles do
|
9
|
+
role(:admin).can(:read, :write, :execute)
|
10
|
+
role(:user) do |usr|
|
11
|
+
usr.can :read
|
12
|
+
|
13
|
+
usr.could :execute, :read do |obj|
|
14
|
+
obj == 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
role :writer, :write
|
18
|
+
role :sysadmin, [:write, :execute]
|
19
|
+
default(:user)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(name = :default)
|
23
|
+
@role = role(name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
REUSER_METHODS = [:roles,
|
27
|
+
:role,
|
28
|
+
:role?,
|
29
|
+
:default,
|
30
|
+
:can?,
|
31
|
+
:cant?,
|
32
|
+
:could?,
|
33
|
+
:couldnt?].sort
|
34
|
+
|
35
|
+
describe TestReUser do
|
36
|
+
context "has included the ReUser module" do
|
37
|
+
it "should be able to define roles with blocks" do
|
38
|
+
test_ru = TestReUser.new(:admin)
|
39
|
+
test_ru.can?(:read).should == true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be able to define roles with arrays" do
|
43
|
+
test_ru = TestReUser.new(:admin)
|
44
|
+
test_ru.can?(:read).should == true
|
45
|
+
end
|
46
|
+
|
47
|
+
context "has defined the :admin and :user roles," do
|
48
|
+
context "is instantiated as test_ru" do
|
49
|
+
context "set :user to the default" do
|
50
|
+
before do
|
51
|
+
@test_ru = TestReUser.new
|
52
|
+
end
|
53
|
+
context " using the default role" do
|
54
|
+
it "should not be able to write" do
|
55
|
+
@test_ru.cant?(:write).should == true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be able to read" do
|
59
|
+
@test_ru.can?(:read).should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not be able to call methods restricted to `:admin` roles" do
|
63
|
+
class InsufficientPermissionsError < StandardError;end
|
64
|
+
TestReUser.class_eval do
|
65
|
+
def foo
|
66
|
+
if @role == :admin
|
67
|
+
:something
|
68
|
+
else
|
69
|
+
raise InsufficientPermissionsError, "You can't do that!"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
lambda {@test_ru.foo}.should raise_error(InsufficientPermissionsError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should be able to execute on a 1 object." do
|
79
|
+
@test_ru.could?(:execute, 1).should == true
|
80
|
+
@test_ru.couldnt?(:execute, 3).should == true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "set role to :admin" do
|
85
|
+
before do
|
86
|
+
@test_ru = TestReUser.new :admin
|
87
|
+
end
|
88
|
+
it "should be able to read, write, and execute" do
|
89
|
+
@test_ru.can?(:read).should == true
|
90
|
+
@test_ru.can?(:write).should == true
|
91
|
+
@test_ru.can?(:execute).should == true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/reuser.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../lib/reuser'
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reuser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Isaac Sanders
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-12 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: ReUse is an Internal DSL for Ruby to create roles and manage actions.
|
15
|
+
email: isaacsanders@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/reuser.rb
|
21
|
+
- lib/reuser/role.rb
|
22
|
+
- lib/reuser/reuser.rb
|
23
|
+
- Rakefile
|
24
|
+
- README.md
|
25
|
+
- spec/reuser.rb
|
26
|
+
- spec/reuser/reuser.rb
|
27
|
+
homepage: http://isaacsanders.github.com/reuser
|
28
|
+
licenses: []
|
29
|
+
post_install_message:
|
30
|
+
rdoc_options: []
|
31
|
+
require_paths:
|
32
|
+
- lib
|
33
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 1.8.10
|
48
|
+
signing_key:
|
49
|
+
specification_version: 3
|
50
|
+
summary: An internal DSL for Ruby to make user role management simple.
|
51
|
+
test_files:
|
52
|
+
- spec/reuser.rb
|
53
|
+
- spec/reuser/reuser.rb
|