surrounded 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/Gemfile +4 -0
- data/README.md +61 -4
- data/lib/surrounded/access_control.rb +48 -0
- data/lib/surrounded/context.rb +5 -0
- data/lib/surrounded/context_errors.rb +1 -0
- data/lib/surrounded/version.rb +1 -1
- data/test/context_access_test.rb +40 -0
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31db490fd3a2fd39b290aa7c5f9368e1ce3fa963
|
4
|
+
data.tar.gz: eef7f29cd0632c9066686d00b873629ef80f7942
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6719cd08a3549f2b23a5193e86e656fb88480d3321193fad86709e09fdfe9ccf07b68659a5c51efe2b59e6c27904227246b23d17ece00882b411262123d9f881
|
7
|
+
data.tar.gz: 71ae69d703a4c4502ddc000f06294c6c87f047253c2c4a86b7acee3a6d3d0106abf4b9e4578bfe8320e109afbdd1f77caf99a16ecb237f1b1b604204f1087da3
|
data/.travis.yml
CHANGED
@@ -2,14 +2,15 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 1.9.3
|
4
4
|
- 2.0.0
|
5
|
+
- 2.1.0
|
5
6
|
- jruby-19mode # JRuby in 1.9 mode
|
6
7
|
- ruby-head
|
7
8
|
- jruby-head
|
8
|
-
- rbx
|
9
|
+
- rbx
|
9
10
|
env:
|
10
11
|
- COVERALLS=true
|
11
12
|
matrix:
|
12
13
|
allow_failures:
|
13
14
|
- rvm: ruby-head
|
14
15
|
- rvm: jruby-head
|
15
|
-
- rvm: rbx
|
16
|
+
- rvm: rbx
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -275,6 +275,40 @@ This will allow you to write methods like you normally would. They are aliased i
|
|
275
275
|
|
276
276
|
This works like Ruby's `public`,`protected`, and `private` keywords in that you can send symbols of method names to it. But `trigger` does not alter the parsing of the document like those core keywords do. In other words, you can't merely type `trigger` on one line, and have methods added afterward be treated as trigger methods.
|
277
277
|
|
278
|
+
## Access Control for Triggers
|
279
|
+
|
280
|
+
If you decide to build a user interface from the available triggers, you'll find you need to know what triggers are available.
|
281
|
+
|
282
|
+
Fortunately, you can make it easy.
|
283
|
+
|
284
|
+
By running `protect_triggers` you'll be able to define when triggers may or may not be run. You can still run them, but they'll raise an error. Here's an example.
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
class MyEnvironment
|
288
|
+
extend Surrounded::Context
|
289
|
+
protect_triggers
|
290
|
+
|
291
|
+
def shove_it
|
292
|
+
employee.quit
|
293
|
+
end
|
294
|
+
trigger :shove_it
|
295
|
+
|
296
|
+
disallow :shove_it do
|
297
|
+
employee.bank_balance < 100
|
298
|
+
end
|
299
|
+
end
|
300
|
+
```
|
301
|
+
|
302
|
+
Then, when the employee role's `bank_balance` is less than `100`, the available triggers won't include `:shove_it`.
|
303
|
+
|
304
|
+
You can compare the instance of the context by listing `all_triggers` and `triggers` to see what could be possible and what's currently possible.
|
305
|
+
|
306
|
+
Alternatively, if you just want to define your own methods without the DSL using `disallow`, you can just follow the pattern of `disallow_#{method_name}?` when creating your own protection.
|
307
|
+
|
308
|
+
In fact, that's exactly what happens with the `disallow` keyword. After using it here, we'd have a `disallow_shove_it?` method defined.
|
309
|
+
|
310
|
+
If you call the disallowed trigger directly, you'll raise a `Surrounded::Context::AccessError` exception and the code in your trigger will not be run.
|
311
|
+
|
278
312
|
## Where roles exist
|
279
313
|
|
280
314
|
By using `Surrounded::Context` you are declaring a relationship between the objects inside playing your defined roles.
|
@@ -438,12 +472,21 @@ class ActiviatingAccount
|
|
438
472
|
# pass an array of arrays with role name symbol and the object for that role
|
439
473
|
map_roles([[:activator, activator],[:account, account]])
|
440
474
|
end
|
475
|
+
|
476
|
+
# if you want to stick with the `initialize` shortcut you can define these methods
|
477
|
+
# for special initialization behavior.
|
478
|
+
def preinitialize
|
479
|
+
# to happen before any role mapping
|
480
|
+
end
|
481
|
+
def postinitialize
|
482
|
+
# to happen after any role mapping
|
483
|
+
end
|
441
484
|
|
442
485
|
role :activator do # module by default
|
443
486
|
def some_behavior; end
|
444
487
|
end
|
445
488
|
|
446
|
-
#
|
489
|
+
# role_methods :activator, :module do # alternatively use role_methods if you choose
|
447
490
|
# def some_behavior; end
|
448
491
|
# end
|
449
492
|
#
|
@@ -457,16 +500,19 @@ class ActiviatingAccount
|
|
457
500
|
#
|
458
501
|
# use your own classes if you don't want SimpleDelegator
|
459
502
|
# class SomeSpecialRole
|
460
|
-
# include Surrounded # you must remember this
|
503
|
+
# include Surrounded # <-- you must remember this in your own classes
|
461
504
|
# # Surrounded assumes SomeSpecialRole.new(some_special_role)
|
462
505
|
# def initialize(...);
|
463
506
|
# # ... your code here
|
464
507
|
# end
|
465
508
|
# end
|
466
509
|
|
467
|
-
#
|
510
|
+
# if you use a regular method and want to use context-specific behavior,
|
511
|
+
# you must handle storing the context yourself:
|
468
512
|
def regular_method
|
513
|
+
apply_roles # handles the adding of all the roles and behaviors
|
469
514
|
activator.some_behavior # behavior not available unless you apply roles on initialize
|
515
|
+
remove_roles # handles the removal of all roles and behaviors
|
470
516
|
end
|
471
517
|
|
472
518
|
trigger :some_trigger_method do
|
@@ -480,7 +526,18 @@ class ActiviatingAccount
|
|
480
526
|
def regular_non_trigger
|
481
527
|
activator.some_behavior # behavior always available with the following line
|
482
528
|
end
|
483
|
-
trigger :regular_non_trigger # turns the method into a trigger
|
529
|
+
trigger :regular_non_trigger # turns the method into a trigger
|
530
|
+
|
531
|
+
# create restrictions on what triggers may be used
|
532
|
+
protect_triggers # <-- this is required if you want to protect your triggers this way.
|
533
|
+
disallow :some_trigger_method do
|
534
|
+
# whatever conditional code for the instance of the context
|
535
|
+
end
|
536
|
+
|
537
|
+
# or define your own method without the `disallow` keyword
|
538
|
+
def disallow_some_trigger_method?
|
539
|
+
# whatever conditional code for the instance of the context
|
540
|
+
end
|
484
541
|
end
|
485
542
|
```
|
486
543
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Surrounded
|
2
|
+
module AccessControl
|
3
|
+
def self.extended(base)
|
4
|
+
base.send(:include, AccessMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def disallow(*names, &block)
|
10
|
+
names.map do |name|
|
11
|
+
define_method("disallow_#{name}?", &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def redo_method(name)
|
16
|
+
class_eval %{
|
17
|
+
def #{name}
|
18
|
+
begin
|
19
|
+
apply_roles if __apply_role_policy == :trigger
|
20
|
+
|
21
|
+
method_restrictor = "disallow_#{name}?"
|
22
|
+
if self.respond_to?(method_restrictor, true) && self.send(method_restrictor)
|
23
|
+
raise ::Surrounded::Context::AccessError.new("access to `#{name}' is not allowed")
|
24
|
+
end
|
25
|
+
|
26
|
+
self.send("__trigger_#{name}")
|
27
|
+
|
28
|
+
ensure
|
29
|
+
remove_roles if __apply_role_policy == :trigger
|
30
|
+
end
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
module AccessMethods
|
36
|
+
def all_triggers
|
37
|
+
self.class.triggers
|
38
|
+
end
|
39
|
+
|
40
|
+
def triggers
|
41
|
+
all_triggers.select {|name|
|
42
|
+
method_restrictor = "disallow_#{name}?"
|
43
|
+
!self.respond_to?(method_restrictor, true) || !self.send(method_restrictor)
|
44
|
+
}.to_set
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/surrounded/context.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'surrounded/context/role_map'
|
3
|
+
require 'surrounded/access_control'
|
3
4
|
|
4
5
|
# Some features are only available in versions of Ruby
|
5
6
|
# where this method is true
|
@@ -30,6 +31,10 @@ module Surrounded
|
|
30
31
|
class << self
|
31
32
|
attr_writer :default_role_type
|
32
33
|
end
|
34
|
+
|
35
|
+
def protect_triggers
|
36
|
+
self.extend(::Surrounded::AccessControl)
|
37
|
+
end
|
33
38
|
|
34
39
|
def new(*args, &block)
|
35
40
|
instance = allocate
|
data/lib/surrounded/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'minitest/mock'
|
3
|
+
|
4
|
+
class FilteredContext
|
5
|
+
extend Surrounded::Context
|
6
|
+
protect_triggers
|
7
|
+
|
8
|
+
initialize :user, :other_user
|
9
|
+
|
10
|
+
trigger :if_ready do
|
11
|
+
'ready'
|
12
|
+
end
|
13
|
+
|
14
|
+
disallow :if_ready do
|
15
|
+
user.name != 'Amy'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Surrounded::Context, 'access control' do
|
20
|
+
let(:user){ User.new("Jim") }
|
21
|
+
let(:other_user){ User.new("Guille") }
|
22
|
+
let(:context){ FilteredContext.new(user, other_user) }
|
23
|
+
|
24
|
+
it 'includes triggers when allowed' do
|
25
|
+
context.stub(:disallow_if_ready?, false) do
|
26
|
+
assert context.triggers.include?(:if_ready)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'excludes triggers when not allowed' do
|
31
|
+
refute context.triggers.include?(:if_ready)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'raises errors when trigger method not allowed' do
|
35
|
+
error = assert_raises(Surrounded::Context::AccessError){
|
36
|
+
context.if_ready
|
37
|
+
}
|
38
|
+
assert_match(/access to `if_ready' is not allowed/i, error.message)
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surrounded
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- '''Jim Gay'''
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: triad
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.1.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.1.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: Gives an object implicit access to other objects in it's environment.
|
@@ -59,21 +59,23 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
62
|
+
- .gitignore
|
63
|
+
- .simplecov
|
64
|
+
- .travis.yml
|
65
65
|
- Gemfile
|
66
66
|
- LICENSE.txt
|
67
67
|
- README.md
|
68
68
|
- Rakefile
|
69
69
|
- examples/rails.rb
|
70
70
|
- lib/surrounded.rb
|
71
|
+
- lib/surrounded/access_control.rb
|
71
72
|
- lib/surrounded/context.rb
|
72
73
|
- lib/surrounded/context/negotiator.rb
|
73
74
|
- lib/surrounded/context/role_map.rb
|
74
75
|
- lib/surrounded/context_errors.rb
|
75
76
|
- lib/surrounded/version.rb
|
76
77
|
- surrounded.gemspec
|
78
|
+
- test/context_access_test.rb
|
77
79
|
- test/example_proxy_test.rb
|
78
80
|
- test/example_threaded_test.rb
|
79
81
|
- test/example_wrapper_test.rb
|
@@ -91,21 +93,22 @@ require_paths:
|
|
91
93
|
- lib
|
92
94
|
required_ruby_version: !ruby/object:Gem::Requirement
|
93
95
|
requirements:
|
94
|
-
- -
|
96
|
+
- - '>='
|
95
97
|
- !ruby/object:Gem::Version
|
96
98
|
version: '0'
|
97
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
100
|
requirements:
|
99
|
-
- -
|
101
|
+
- - '>='
|
100
102
|
- !ruby/object:Gem::Version
|
101
103
|
version: '0'
|
102
104
|
requirements: []
|
103
105
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.0.14
|
105
107
|
signing_key:
|
106
108
|
specification_version: 4
|
107
109
|
summary: Create encapsulated environments for your objects.
|
108
110
|
test_files:
|
111
|
+
- test/context_access_test.rb
|
109
112
|
- test/example_proxy_test.rb
|
110
113
|
- test/example_threaded_test.rb
|
111
114
|
- test/example_wrapper_test.rb
|