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.
@@ -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
+