roleful 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + '/roleful'
2
+
3
+ require 'rubygems'
4
+ require 'nakajima'
5
+ require 'set'
6
+ require 'role'
7
+ require 'inclusion'
8
+
9
+ module Roleful
10
+ VERSION = '0.0.2'
11
+ end
@@ -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
@@ -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
+