surrounded 0.6.0 → 0.7.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.
- 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
|