roleful 0.0.2
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/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
|
+
|