nakajima-roleful 0.0.1

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,5 @@
1
+ class Array
2
+ def extract_options!
3
+ last.is_a?(Hash) ? pop : { }
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class Object
2
+ def try(sym, *args, &block)
3
+ respond_to?(sym) ? send(sym, *args, &block) : nil
4
+ end
5
+
6
+ def blank?
7
+ to_s == nil.to_s
8
+ end
9
+
10
+ unless respond_to?(:instance_exec)
11
+ def instance_exec(*arguments, &block)
12
+ block.bind(self)[*arguments]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # from activesupport
2
+ class Proc
3
+ def bind(object)
4
+ block, time = self, Time.now
5
+ (class << object; self end).class_eval do
6
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
7
+ define_method(method_name, &block)
8
+ method = instance_method(method_name)
9
+ remove_method(method_name)
10
+ method
11
+ end.bind(object)
12
+ end
13
+ end
data/lib/roleful.rb ADDED
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + '/roleful'
2
+ $LOAD_PATH << File.dirname(__FILE__) + '/core_ext'
3
+
4
+ require 'rubygems'
5
+ require 'metaid'
6
+ require 'set'
7
+
8
+ require 'array'
9
+ require 'proc'
10
+ require 'object'
11
+
12
+ require 'role'
13
+ require 'inclusion'
14
+
15
+ module Roleful
16
+ VERSION = '0.0.1'
17
+ 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,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nakajima-roleful
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
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 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: metaid
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description:
25
+ email: patnakajima@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - lib/core_ext
34
+ - lib/core_ext/array.rb
35
+ - lib/core_ext/object.rb
36
+ - lib/core_ext/proc.rb
37
+ - lib/roleful
38
+ - lib/roleful/inclusion.rb
39
+ - lib/roleful/role.rb
40
+ - lib/roleful.rb
41
+ has_rdoc: false
42
+ homepage: http://github.com/nakajima/roleful
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.2.0
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: Generic roles for you and your objects
67
+ test_files: []
68
+