reuser 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/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
|