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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b50df20142b16850a46c0824115d7286d5c5db0
4
- data.tar.gz: bbf2f02bc6d2bf089f8a1a6c33627cac0efb8e43
3
+ metadata.gz: 31db490fd3a2fd39b290aa7c5f9368e1ce3fa963
4
+ data.tar.gz: eef7f29cd0632c9066686d00b873629ef80f7942
5
5
  SHA512:
6
- metadata.gz: 4d1badd06972d938d14bc50ea50d8d074c882a4ebf2728724de48131e875f55f75dcdd019fbcdd64322eb6591d414ec9fccbe12cc106518fa3d309a93ab31294
7
- data.tar.gz: b3aa0cfaaec0178fbe799fff2b64d16f4565be58eb6d95e29eb46542a7ef35a7bc50ddc80bae8b51ff5b614277ff3079846d4a872697e8d2c11364f3984781ea
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-19mode
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-19mode
16
+ - rvm: rbx
data/Gemfile CHANGED
@@ -7,4 +7,8 @@ group :test do
7
7
  gem 'casting'
8
8
  end
9
9
 
10
+ platforms :rbx do
11
+ gem 'rubysl', '~> 2.0'
12
+ end
13
+
10
14
  gemspec
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
- # role :activator, :module do
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
- # works as a trigger (assigning the current context) only if set_methods_as_triggers is set
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
@@ -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
@@ -3,5 +3,6 @@ module Surrounded
3
3
  module Context
4
4
  class InvalidRole < ::Triad::KeyNotPresent; end
5
5
  module InvalidRoleType; end
6
+ class AccessError < StandardError; end
6
7
  end
7
8
  end
@@ -1,3 +1,3 @@
1
1
  module Surrounded
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -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.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
- - "'Jim Gay'"
7
+ - '''Jim Gay'''
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-16 00:00:00.000000000 Z
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
- - ".gitignore"
63
- - ".simplecov"
64
- - ".travis.yml"
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.2.0
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