roleful 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/roleful.rb +11 -0
- data/lib/roleful/inclusion.rb +75 -0
- data/lib/roleful/role.rb +72 -0
- metadata +75 -0
data/lib/roleful.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Roleful
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
extend(ClassMethods)
|
5
|
+
include(InstanceMethods)
|
6
|
+
const_set("ROLES", { })
|
7
|
+
const_set("PERMISSIONS", Set.new)
|
8
|
+
define_role(:null)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def with_role(*tmp_roles)
|
14
|
+
old = meta_def(:role) {tmp_roles }
|
15
|
+
result = yield
|
16
|
+
meta_eval { remove_method(:role) }
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :with_roles, :with_role
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def role_proxy
|
25
|
+
begin
|
26
|
+
name = (role || :null).is_a?(Array) ?
|
27
|
+
map_roles :
|
28
|
+
self.class::ROLES[role.to_sym]
|
29
|
+
rescue => e
|
30
|
+
warn "#{role.inspect}: #{e}"
|
31
|
+
self.class::ROLES[:null]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def map_roles
|
36
|
+
role.map { |name| self.class::ROLES[name.to_s.to_sym] }.compact
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module ClassMethods
|
41
|
+
def role(*args, &block)
|
42
|
+
options = args.extract_options!
|
43
|
+
roles = [:all].eql?(args) ? all_roles : args
|
44
|
+
roles.each { |name| define_role(name.to_sym, options, &block) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adapted from ActiveSupport, modified a bit to ease binding contexts
|
48
|
+
def delegate_permission(*methods)
|
49
|
+
options = methods.pop
|
50
|
+
raise ArgumentError, "Delegation needs a target." unless options.is_a?(Hash) && to = options[:to]
|
51
|
+
|
52
|
+
methods.each do |method|
|
53
|
+
module_eval(<<-EOS, "(__DELEGATION__)", 1)
|
54
|
+
def #{method}(*args, &block)
|
55
|
+
target = Array(send(#{to.inspect}))
|
56
|
+
target.any? do |to|
|
57
|
+
to.__send__(#{method.inspect}, self, *args, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
EOS
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def all_roles
|
67
|
+
self::ROLES.keys.reject { |name| name.eql?(:null) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def define_role(name, options={}, &block)
|
71
|
+
self::ROLES[name] ||= Role.new(self, name, options)
|
72
|
+
self::ROLES[name].instance_eval(&block) if block_given?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/roleful/role.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Roleful
|
2
|
+
class Role
|
3
|
+
attr_reader :name, :permissions, :handlers, :options
|
4
|
+
|
5
|
+
def initialize(klass, name, options={})
|
6
|
+
@klass, @name, @options = klass, name, options
|
7
|
+
@permissions = Set.new
|
8
|
+
@handlers = { }
|
9
|
+
define_predicates
|
10
|
+
end
|
11
|
+
|
12
|
+
def can(permission, &block)
|
13
|
+
permission_name = "can_#{permission}?"
|
14
|
+
|
15
|
+
handlers[permission] = block || proc { true }
|
16
|
+
meta_def(permission_name) { |target, *args| handle(target, permission, *args) }
|
17
|
+
|
18
|
+
meta_delegate(permission_name)
|
19
|
+
add_permission(permission)
|
20
|
+
end
|
21
|
+
|
22
|
+
def can?(target, permission, *args)
|
23
|
+
superuser? ?
|
24
|
+
@klass::PERMISSIONS.include?(permission) :
|
25
|
+
handle(target, permission, *args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(sym, *args)
|
29
|
+
method_id = sym.to_s
|
30
|
+
match_permission_or_predicate?(method_id) ? superuser? : super
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def handle(target, permission, *args)
|
36
|
+
return false if handlers[permission].nil?
|
37
|
+
target.instance_exec(*args, &handlers[permission])
|
38
|
+
end
|
39
|
+
|
40
|
+
def superuser?
|
41
|
+
options[:superuser] || false # returns false, not nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def permission?(method)
|
45
|
+
method.match(/can_(#{@klass::PERMISSIONS.to_a.join('|')})+\?/)
|
46
|
+
end
|
47
|
+
|
48
|
+
def predicate?(method)
|
49
|
+
method.match(/(#{@klass::ROLES.keys.join('|')})\?/)
|
50
|
+
end
|
51
|
+
|
52
|
+
def match_permission_or_predicate?(method_id)
|
53
|
+
permission?(method_id) or predicate?(method_id)
|
54
|
+
end
|
55
|
+
|
56
|
+
def define_predicates
|
57
|
+
meta_def("#{name}?") { true }
|
58
|
+
meta_delegate("#{name}?")
|
59
|
+
meta_delegate("can?")
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_permission(permission)
|
63
|
+
permission = permission.to_sym
|
64
|
+
@permissions.add(permission)
|
65
|
+
@klass::PERMISSIONS.merge(@permissions)
|
66
|
+
end
|
67
|
+
|
68
|
+
def meta_delegate(name)
|
69
|
+
@klass.delegate_permission name, :to => :role_proxy
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roleful
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pat Nakajima
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-27 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: metaid
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nakajima-nakajima
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: patnakajima@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/roleful
|
45
|
+
- lib/roleful/inclusion.rb
|
46
|
+
- lib/roleful/role.rb
|
47
|
+
- lib/roleful.rb
|
48
|
+
has_rdoc: false
|
49
|
+
homepage: http://github.com/nakajima/roleful
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.0
|
71
|
+
signing_key:
|
72
|
+
specification_version: 2
|
73
|
+
summary: Generic roles for you and your objects
|
74
|
+
test_files: []
|
75
|
+
|