mayi 1.0.2 → 2.0.0
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/Gemfile.lock +3 -3
- data/README.markdown +30 -69
- data/VERSION +1 -1
- data/lib/mayi.rb +6 -3
- data/lib/mayi/access_denied_error.rb +5 -6
- data/lib/mayi/methods.rb +42 -0
- data/mayi.gemspec +4 -4
- data/spec/lib/test_helper.rb +6 -0
- data/spec/mayi_spec.rb +73 -3
- data/spec/spec_helper.rb +2 -1
- metadata +5 -5
- data/lib/mayi/access.rb +0 -79
- data/lib/mayi/proxy.rb +0 -19
data/Gemfile.lock
CHANGED
data/README.markdown
CHANGED
@@ -2,41 +2,44 @@
|
|
2
2
|
|
3
3
|
A plugable access rights API. Meant to make integrations easier. Verry useful as an integration point for blog,forum and CMS components. Also its much nicer to read than the basic stuff i usually do.
|
4
4
|
|
5
|
-
|
5
|
+
An example basic way to do rights handeling
|
6
6
|
|
7
7
|
```ruby
|
8
8
|
if user_object.is_admin?
|
9
|
-
|
9
|
+
...
|
10
10
|
end
|
11
11
|
```
|
12
12
|
|
13
|
-
|
13
|
+
With mayi this changes to method with an explicit mening to it.
|
14
14
|
|
15
15
|
```ruby
|
16
16
|
access.may_add_user! do
|
17
|
-
|
17
|
+
...
|
18
18
|
end
|
19
19
|
```
|
20
20
|
|
21
21
|
|
22
22
|
|
23
23
|
|
24
|
-
##
|
24
|
+
## An example
|
25
25
|
|
26
|
-
|
26
|
+
Your rights implements with boolean questions.
|
27
27
|
|
28
28
|
```ruby
|
29
|
-
class
|
30
|
-
|
31
|
-
|
29
|
+
class MyAccessHandler
|
30
|
+
|
31
|
+
include MayI
|
32
|
+
|
33
|
+
def initialize(user)
|
34
|
+
@user = user
|
32
35
|
end
|
33
36
|
|
34
|
-
def
|
35
|
-
stuff.owner_id ==
|
37
|
+
def may_view_secret_project(project)
|
38
|
+
stuff.owner_id == @user.id
|
36
39
|
end
|
37
40
|
|
38
41
|
def may_create_new_record
|
39
|
-
|
42
|
+
@user.type == "admin"
|
40
43
|
end
|
41
44
|
end
|
42
45
|
```
|
@@ -45,7 +48,8 @@ This can then be used with the MayI::Access class.
|
|
45
48
|
|
46
49
|
|
47
50
|
```ruby
|
48
|
-
|
51
|
+
|
52
|
+
access = MyAccessHandler.new(user)
|
49
53
|
|
50
54
|
# Simple boolean
|
51
55
|
if access.may_create_new_record?
|
@@ -56,84 +60,41 @@ end
|
|
56
60
|
access.may_create_new_record? do
|
57
61
|
# You do stuff here
|
58
62
|
end
|
59
|
-
```
|
60
63
|
|
61
|
-
|
64
|
+
# Raise errors on false
|
65
|
+
access.may_view_secret_project!(project)
|
66
|
+
# or
|
67
|
+
access.error_message("A custom error message").may_view_secret_project!(project)
|
62
68
|
|
63
|
-
```ruby
|
64
|
-
access = MayI::Access.new(MyBasicAccess)
|
65
|
-
|
66
|
-
# Simple boolean
|
67
|
-
if access.may_create_new_record!
|
68
|
-
# You do stuff here
|
69
|
-
end
|
70
|
-
|
71
|
-
# With a block
|
72
|
-
access.may_create_new_record! do
|
73
|
-
# You do stuff here
|
74
|
-
end
|
75
|
-
```
|
76
|
-
|
77
|
-
With custom error message
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
access.error_message("Sorry but you are not allowed to do this!").may_create_new_record! do
|
81
|
-
# You do stuff here
|
82
|
-
end
|
83
69
|
```
|
84
70
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
71
|
## A Rails example
|
90
72
|
|
91
|
-
On each request we create a new instance of MyBasicAccess with the current session.
|
92
|
-
|
93
73
|
```ruby
|
94
74
|
class ApplicationController < ActionController::Base
|
95
|
-
|
96
|
-
|
97
|
-
def
|
98
|
-
|
99
|
-
ApplicationController.access.refresh({:session => session})
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.access
|
103
|
-
@@access_cache
|
75
|
+
|
76
|
+
helper_method :current_user
|
77
|
+
def current_user
|
78
|
+
...
|
104
79
|
end
|
105
80
|
|
81
|
+
helper_method :access
|
106
82
|
def access
|
107
|
-
@@access_cache
|
83
|
+
@@access_cache ||= MyAccessHandler.new(current_user)
|
108
84
|
end
|
109
85
|
|
110
|
-
@@access_cache = MayI::Access.new
|
111
|
-
@@access_cache.implementation = MyBasicAccess
|
112
86
|
end
|
113
87
|
```
|
114
88
|
|
115
|
-
|
89
|
+
Check if a user should be able to view some secret stuff.
|
116
90
|
|
117
91
|
```ruby
|
118
|
-
class
|
92
|
+
class StuffController < ApplicationController
|
119
93
|
|
120
94
|
def show
|
121
95
|
stuff = Stuff.find(params[:id])
|
122
|
-
access.may_view_secret_stuff?(stuff) do
|
123
96
|
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
```
|
129
|
-
|
130
|
-
We can also use it in a model.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
class ShortUrl < ActiveRecord::Base
|
134
|
-
|
135
|
-
def method_that_requires_special_access
|
136
|
-
ApplicationController.access.may_create_new_record! do
|
97
|
+
access.may_view_secret_stuff?(stuff) do
|
137
98
|
|
138
99
|
end
|
139
100
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0
|
data/lib/mayi.rb
CHANGED
@@ -2,8 +2,11 @@
|
|
2
2
|
# Add the directory containing this file to the start of the load path if it
|
3
3
|
# isn't there already.
|
4
4
|
$:.unshift(File.dirname(__FILE__)) unless
|
5
|
-
|
5
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
6
|
+
|
7
|
+
module MayI
|
8
|
+
|
9
|
+
end
|
6
10
|
|
7
|
-
require 'mayi/proxy'
|
8
11
|
require 'mayi/access_denied_error'
|
9
|
-
require 'mayi/
|
12
|
+
require 'mayi/methods'
|
data/lib/mayi/methods.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module MayI
|
3
|
+
|
4
|
+
def method_missing(meth, *args, &block)
|
5
|
+
if is_a_may_i_method?(meth)
|
6
|
+
if self.send(meth.to_s[0..-2].to_sym,*args)
|
7
|
+
yield if block_given?
|
8
|
+
true
|
9
|
+
else
|
10
|
+
meth.to_s.end_with?("!") ? raise_may_i_error(meth) : false
|
11
|
+
end
|
12
|
+
else
|
13
|
+
super(meth,*args,&block)
|
14
|
+
end
|
15
|
+
ensure
|
16
|
+
@may_i_error_message = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to?(meth)
|
20
|
+
if is_a_may_i_method?(meth)
|
21
|
+
super(meth.to_s[0..-2].to_sym)
|
22
|
+
else
|
23
|
+
super(meth)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def error_message(message)
|
28
|
+
@custom_may_i_error_message = message
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def is_a_may_i_method?(sym)
|
35
|
+
sym.to_s.match(/^(may)_.*(\?|!)$/)
|
36
|
+
end
|
37
|
+
|
38
|
+
def raise_may_i_error(meth)
|
39
|
+
raise MayI::AccessDeniedError.new(@custom_may_i_error_message || meth.to_s[0..-2].gsub("_", " ").gsub("may","may not"))
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/mayi.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "mayi"
|
8
|
-
s.version = "
|
8
|
+
s.version = "2.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Darwin"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2013-05-16"
|
13
13
|
s.description = " A plugable access rights API. Meant to make integrations easier. Werry useful as an integration point for blog,forum and CMS components. Also its much nicer to read than the basic stuff i usually do. "
|
14
14
|
s.email = "darwin@bits2life.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,10 +26,10 @@ Gem::Specification.new do |s|
|
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"lib/mayi.rb",
|
29
|
-
"lib/mayi/access.rb",
|
30
29
|
"lib/mayi/access_denied_error.rb",
|
31
|
-
"lib/mayi/
|
30
|
+
"lib/mayi/methods.rb",
|
32
31
|
"mayi.gemspec",
|
32
|
+
"spec/lib/test_helper.rb",
|
33
33
|
"spec/mayi_spec.rb",
|
34
34
|
"spec/spec_helper.rb"
|
35
35
|
]
|
data/spec/mayi_spec.rb
CHANGED
@@ -1,7 +1,77 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe "MayI" do
|
4
|
-
|
5
|
-
|
3
|
+
describe "MayI::Methods" do
|
4
|
+
|
5
|
+
subject { TestHelper.new }
|
6
|
+
|
7
|
+
context "call a may method with question mark" do
|
8
|
+
|
9
|
+
it 'should call the map_do_something method' do
|
10
|
+
subject.should_receive(:may_do_something).and_return(true)
|
11
|
+
subject.may_do_something?.should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should yield to the block when true' do
|
15
|
+
|
16
|
+
subject.should_receive(:may_do_something).and_return(true)
|
17
|
+
has_yielded = false
|
18
|
+
subject.may_do_something? do
|
19
|
+
has_yielded = true
|
20
|
+
end
|
21
|
+
|
22
|
+
has_yielded.should be_true
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should not yield to the block when false' do
|
27
|
+
|
28
|
+
subject.should_receive(:may_do_something).and_return(false)
|
29
|
+
has_yielded = false
|
30
|
+
subject.may_do_something? do
|
31
|
+
has_yielded = true
|
32
|
+
end
|
33
|
+
|
34
|
+
has_yielded.should be_false
|
35
|
+
|
36
|
+
end
|
37
|
+
|
6
38
|
end
|
39
|
+
|
40
|
+
context "call a may method with exclimation point " do
|
41
|
+
|
42
|
+
it 'should call the map_do_something method' do
|
43
|
+
subject.should_receive(:may_do_something).and_return(true)
|
44
|
+
subject.may_do_something!.should be_true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should raise an error on false' do
|
48
|
+
subject.should_receive(:may_do_something).and_return(false)
|
49
|
+
lambda{ subject.may_do_something! }.should raise_error(MayI::AccessDeniedError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should yield to the block' do
|
53
|
+
|
54
|
+
subject.should_receive(:may_do_something).and_return(true)
|
55
|
+
has_yielded = false
|
56
|
+
subject.may_do_something! do
|
57
|
+
has_yielded = true
|
58
|
+
end
|
59
|
+
|
60
|
+
has_yielded.should be_true
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "call a may method with an error message" do
|
67
|
+
|
68
|
+
it 'should set the error message for the exception' do
|
69
|
+
|
70
|
+
subject.should_receive(:may_do_something).and_return(false)
|
71
|
+
lambda{ subject.error_message("A error message").may_do_something! }.should raise_error(MayI::AccessDeniedError, "A error message")
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
7
77
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
3
|
require 'rspec'
|
4
|
-
require '
|
4
|
+
require 'mayi'
|
5
|
+
require_relative 'lib/test_helper'
|
5
6
|
|
6
7
|
# Requires supporting files with custom matchers and macros, etc,
|
7
8
|
# in ./support/ and its subdirectories.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mayi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-05-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -94,10 +94,10 @@ files:
|
|
94
94
|
- Rakefile
|
95
95
|
- VERSION
|
96
96
|
- lib/mayi.rb
|
97
|
-
- lib/mayi/access.rb
|
98
97
|
- lib/mayi/access_denied_error.rb
|
99
|
-
- lib/mayi/
|
98
|
+
- lib/mayi/methods.rb
|
100
99
|
- mayi.gemspec
|
100
|
+
- spec/lib/test_helper.rb
|
101
101
|
- spec/mayi_spec.rb
|
102
102
|
- spec/spec_helper.rb
|
103
103
|
homepage: http://github.com/bjornblomqvist/mayi
|
@@ -115,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
115
|
version: '0'
|
116
116
|
segments:
|
117
117
|
- 0
|
118
|
-
hash: -
|
118
|
+
hash: -3855034540096933122
|
119
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
120
|
none: false
|
121
121
|
requirements:
|
data/lib/mayi/access.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
module MayI
|
2
|
-
class Access
|
3
|
-
|
4
|
-
attr_accessor :implementation
|
5
|
-
|
6
|
-
def initialize(implementation = nil)
|
7
|
-
self.implementation = implementation
|
8
|
-
end
|
9
|
-
|
10
|
-
def refresh(data = {})
|
11
|
-
raise "You have not set any implementation yet" unless self.implementation
|
12
|
-
if self.implementation.is_a?(Class)
|
13
|
-
Thread.current["mayi_access_implementation_#{self.object_id}"] = self.implementation.new(data)
|
14
|
-
else
|
15
|
-
instance = self.implementation.to_s.split('::').reduce(Object){|cls, c| cls.const_get(c) }.new(data)
|
16
|
-
Thread.current["mayi_access_implementation_#{self.object_id}"] = instance
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def clear
|
22
|
-
Thread.current["mayi_access_implementation_#{self.object_id}"] = nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def current_instance
|
26
|
-
raise "You must call refresh to create a new instance of your Access implementation before being able to use the access object." unless Thread.current["mayi_access_implementation_#{self.object_id}"]
|
27
|
-
|
28
|
-
Thread.current["mayi_access_implementation_#{self.object_id}"]
|
29
|
-
end
|
30
|
-
|
31
|
-
def method_missing(meth, *args, &block)
|
32
|
-
if meth.to_s =~ /^(may)_.*(\?|!)$/
|
33
|
-
if meth.to_s.end_with?("!")
|
34
|
-
if current_instance.send(meth.to_s[0..-2].to_sym,*args)
|
35
|
-
yield if block_given?
|
36
|
-
true
|
37
|
-
else
|
38
|
-
raise_error(meth)
|
39
|
-
end
|
40
|
-
elsif meth.to_s.end_with?("?")
|
41
|
-
if current_instance.send(meth.to_s[0..-2].to_sym,*args)
|
42
|
-
yield if block_given?
|
43
|
-
true
|
44
|
-
else
|
45
|
-
false
|
46
|
-
end
|
47
|
-
end
|
48
|
-
else
|
49
|
-
super(meth,*args,&block)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def respond_to?(meth)
|
54
|
-
if meth.to_s =~ /^(may)_.*(\?|!)$/
|
55
|
-
super(meth.to_s[0..-2].to_sym)
|
56
|
-
else
|
57
|
-
super(meth)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def error_message(message)
|
62
|
-
Proxy.new(self) do |state|
|
63
|
-
if state == :before
|
64
|
-
@error_message = message
|
65
|
-
else
|
66
|
-
@error_message = nil
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def raise_error(meth)
|
74
|
-
error_message = meth.to_s[0..-2].gsub("_", " ").gsub("may","may not")
|
75
|
-
raise AccessDeniedError.new(@error_message || error_message)
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
data/lib/mayi/proxy.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module MayI
|
2
|
-
class Proxy
|
3
|
-
instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }
|
4
|
-
|
5
|
-
def initialize(target,&block)
|
6
|
-
@target = target
|
7
|
-
@block = block
|
8
|
-
end
|
9
|
-
|
10
|
-
protected
|
11
|
-
|
12
|
-
def method_missing(name, *args, &block)
|
13
|
-
@block.call(:before)
|
14
|
-
@target.send(name, *args, &block)
|
15
|
-
ensure
|
16
|
-
@block.call(:after)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|