surrounded 1.0.0 → 1.1.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.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/Changelog.md +11 -11
  3. data/LICENSE.txt +1 -1
  4. data/README.md +39 -9
  5. data/Rakefile +12 -5
  6. data/lib/surrounded/access_control.rb +19 -26
  7. data/lib/surrounded/context/forwarding.rb +10 -10
  8. data/lib/surrounded/context/initializing.rb +10 -7
  9. data/lib/surrounded/context/name_collision_detector.rb +17 -17
  10. data/lib/surrounded/context/negotiator.rb +13 -13
  11. data/lib/surrounded/context/role_builders.rb +8 -7
  12. data/lib/surrounded/context/role_map.rb +20 -13
  13. data/lib/surrounded/context/seclusion.rb +20 -0
  14. data/lib/surrounded/context/trigger_controls.rb +14 -16
  15. data/lib/surrounded/context.rb +64 -72
  16. data/lib/surrounded/east_oriented.rb +4 -4
  17. data/lib/surrounded/exceptions.rb +1 -1
  18. data/lib/surrounded/shortcuts.rb +15 -5
  19. data/lib/surrounded/version.rb +2 -2
  20. data/lib/surrounded.rb +7 -7
  21. data/surrounded.gemspec +21 -16
  22. data/test/{casting_role_player_test.rb → casting_test_helper.rb} +4 -3
  23. data/test/collection_role_players_test.rb +16 -16
  24. data/test/context_access_test.rb +31 -30
  25. data/test/context_forwarding_test.rb +30 -30
  26. data/test/context_reuse_test.rb +14 -14
  27. data/test/context_shortcuts_test.rb +38 -11
  28. data/test/east_oriented_triggers_test.rb +14 -13
  29. data/test/example_delegate_class_test.rb +8 -8
  30. data/test/example_proxy_test.rb +25 -23
  31. data/test/example_threaded_test.rb +13 -13
  32. data/test/example_wrapper_test.rb +7 -7
  33. data/test/initialization_test.rb +25 -26
  34. data/test/name_collisions_test.rb +48 -42
  35. data/test/non_surrounded_role_player_test.rb +8 -8
  36. data/test/override_methods_test.rb +9 -9
  37. data/test/role_context_method_test.rb +144 -98
  38. data/test/surrounded_context_test.rb +71 -62
  39. data/test/surrounded_test.rb +13 -15
  40. data/test/test_helper.rb +8 -5
  41. data/test/threaded_context_test.rb +70 -0
  42. metadata +9 -52
  43. data/.codeclimate.yml +0 -4
  44. data/.gitignore +0 -19
  45. data/.pullreview.yml +0 -4
  46. data/.simplecov +0 -3
  47. data/.travis.yml +0 -19
  48. data/Gemfile +0 -10
  49. data/examples/bottles.rb +0 -145
  50. data/examples/rails.rb +0 -57
@@ -1,62 +1,63 @@
1
- require 'test_helper'
2
- require 'minitest/mock'
1
+ require "test_helper"
2
+ require "minitest/mock"
3
3
 
4
4
  class FilteredContext
5
5
  extend Surrounded::Context
6
+
6
7
  protect_triggers
7
-
8
+
8
9
  initialize :user, :other_user
9
-
10
+
10
11
  trigger :if_ready do
11
- 'ready'
12
+ "ready"
12
13
  end
13
-
14
+
14
15
  guard :if_ready do
15
- user.name != 'Amy'
16
+ user.name != "Amy"
16
17
  end
17
-
18
+
18
19
  trigger :check_disallow_behavior do
19
20
  # used for disallow check
20
21
  end
21
-
22
+
22
23
  disallow :check_disallow_behavior do
23
24
  user.special
24
25
  end
25
-
26
+
26
27
  trigger :unguarded do
27
28
  # used for disallow check
28
29
  end
29
30
 
30
31
  role :user do
31
32
  def special
32
- 'special user method'
33
+ "special user method"
33
34
  end
34
35
  end
35
36
  end
36
37
 
37
- describe Surrounded::Context, 'access control' do
38
- let(:user){ User.new("Jim") }
39
- let(:other_user){ User.new("Guille") }
40
- let(:context){ FilteredContext.new(user: user, other_user: other_user) }
41
-
42
- it 'includes triggers when allowed' do
38
+ describe Surrounded::Context, "access control" do
39
+ let(:user) { User.new("Jim") }
40
+ let(:other_user) { User.new("Guille") }
41
+ let(:context) { FilteredContext.new(user: user, other_user: other_user) }
42
+
43
+ it "includes triggers when allowed" do
43
44
  context.stub(:disallow_if_ready?, false) do
44
45
  assert context.triggers.include?(:if_ready)
45
46
  end
46
47
  end
47
48
 
48
- it 'excludes triggers when not allowed' do
49
+ it "excludes triggers when not allowed" do
49
50
  refute context.triggers.include?(:if_ready)
50
51
  end
51
-
52
- it 'raises error specific to the context class when trigger method not allowed' do
53
- error = assert_raises(::FilteredContext::AccessError){
52
+
53
+ it "raises error specific to the context class when trigger method not allowed" do
54
+ error = assert_raises(::FilteredContext::AccessError) {
54
55
  context.if_ready
55
56
  }
56
57
  assert_match(/access to FilteredContext#if_ready is not allowed/i, error.message)
57
58
  end
58
-
59
- it 'supports rescuing from Surrounded defined error when trigger method not allowed' do
59
+
60
+ it "supports rescuing from Surrounded defined error when trigger method not allowed" do
60
61
  begin
61
62
  context.if_ready
62
63
  rescue ::Surrounded::Context::AccessError => error
@@ -64,20 +65,20 @@ describe Surrounded::Context, 'access control' do
64
65
  end
65
66
  assert_match(/access to FilteredContext#if_ready is not allowed/i, error.message)
66
67
  end
67
-
68
- it 'applies roles in disallow blocks' do
69
- assert_equal 'special user method', context.disallow_check_disallow_behavior?
68
+
69
+ it "applies roles in disallow blocks" do
70
+ assert_equal "special user method", context.disallow_check_disallow_behavior?
70
71
  end
71
72
 
72
- it 'lets you ask if the object will allow a method' do
73
+ it "lets you ask if the object will allow a method" do
73
74
  assert context.allow?(:unguarded)
74
75
  refute context.allow?(:check_disallow_behavior)
75
76
  end
76
77
 
77
- it 'complains if you ask about an undefined method' do
78
- error = assert_raises(NoMethodError){
78
+ it "complains if you ask about an undefined method" do
79
+ error = assert_raises(NoMethodError) {
79
80
  context.allow?(:not_a_defined_method)
80
81
  }
81
82
  assert_match(/undefined method `not_a_defined_method' for #<#{context.class}/, error.message)
82
83
  end
83
- end
84
+ end
@@ -1,32 +1,32 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class Sending
4
4
  extend Surrounded::Context
5
-
5
+
6
6
  initialize :one, :two
7
-
7
+
8
8
  forwarding [:hello, :goodbye] => :one
9
9
  forward_trigger :two, :ping
10
10
  forward_trigger :two, :argumentative
11
11
  forwards :two, :blockhead
12
-
12
+
13
13
  role :one do
14
14
  def hello
15
- 'hello'
15
+ "hello"
16
16
  end
17
-
17
+
18
18
  def goodbye
19
- 'goodbye'
19
+ "goodbye"
20
20
  end
21
21
  end
22
-
22
+
23
23
  role :two do
24
24
  def ping
25
25
  one.hello
26
26
  end
27
27
 
28
28
  def argumentative(yes, no)
29
- [yes, no].join(' and ')
29
+ [yes, no].join(" and ")
30
30
  end
31
31
 
32
32
  def blockhead
@@ -35,31 +35,31 @@ class Sending
35
35
  end
36
36
  end
37
37
 
38
- describe Surrounded::Context, 'forwarding triggers' do
39
- let(:user){ User.new("Jim") }
40
- let(:other_user){ User.new("Guille") }
41
- let(:context){ Sending.new(one: user, two: other_user) }
42
-
43
- it 'forwards multiple configured instance methods as triggers' do
44
- assert_equal 'hello', context.hello
45
- assert_equal 'goodbye', context.goodbye
38
+ describe Surrounded::Context, "forwarding triggers" do
39
+ let(:user) { User.new("Jim") }
40
+ let(:other_user) { User.new("Guille") }
41
+ let(:context) { Sending.new(one: user, two: other_user) }
42
+
43
+ it "forwards multiple configured instance methods as triggers" do
44
+ assert_equal "hello", context.hello
45
+ assert_equal "goodbye", context.goodbye
46
46
  end
47
-
48
- it 'forwards individual configured instance methods as triggers' do
49
- assert_equal 'hello', context.ping
47
+
48
+ it "forwards individual configured instance methods as triggers" do
49
+ assert_equal "hello", context.ping
50
50
  end
51
-
52
- it 'does not forward __id__' do
53
- error = assert_raises(ArgumentError){
51
+
52
+ it "does not forward __id__" do
53
+ error = assert_raises(ArgumentError) {
54
54
  Sending.class_eval do
55
55
  forward_trigger :one, :__id__
56
56
  end
57
57
  }
58
58
  assert_match(/you may not forward '__id__`/i, error.message)
59
59
  end
60
-
61
- it 'does not forward __send__' do
62
- error = assert_raises(ArgumentError){
60
+
61
+ it "does not forward __send__" do
62
+ error = assert_raises(ArgumentError) {
63
63
  Sending.class_eval do
64
64
  forward_trigger :one, :__send__
65
65
  end
@@ -67,14 +67,14 @@ describe Surrounded::Context, 'forwarding triggers' do
67
67
  assert_match(/you may not forward '__send__/i, error.message)
68
68
  end
69
69
 
70
- it 'passes arguments' do
71
- assert_equal 'YES and NO', context.argumentative('YES','NO')
70
+ it "passes arguments" do
71
+ assert_equal "YES and NO", context.argumentative("YES", "NO")
72
72
  end
73
73
 
74
- it 'passes blocks' do
74
+ it "passes blocks" do
75
75
  result = context.blockhead do
76
76
  "Put them in the iron maiden. Excellent!"
77
77
  end
78
78
  assert_equal "Put them in the iron maiden. Excellent!", result
79
79
  end
80
- end
80
+ end
@@ -1,22 +1,22 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- describe Surrounded::Context, 'reusing context object' do
4
- let(:user){ User.new("Jim") }
5
- let(:other_user){ User.new("Guille") }
6
- let(:context){ TestContext.new(user: user, other_user: other_user) }
3
+ describe Surrounded::Context, "reusing context object" do
4
+ let(:user) { User.new("Jim") }
5
+ let(:other_user) { User.new("Guille") }
6
+ let(:context) { TestContext.new(user: user, other_user: other_user) }
7
7
 
8
- it 'allows rebinding new players' do
9
- expect(context.access_other_object).must_equal 'Guille'
10
- context.rebind(user: User.new('Amy'), other_user: User.new('Elizabeth'))
11
- expect(context.access_other_object).must_equal 'Elizabeth'
8
+ it "allows rebinding new players" do
9
+ expect(context.access_other_object).must_equal "Guille"
10
+ context.rebind(user: User.new("Amy"), other_user: User.new("Elizabeth"))
11
+ expect(context.access_other_object).must_equal "Elizabeth"
12
12
  end
13
13
 
14
- it 'clears internal storage when rebinding' do
15
- originals = context.instance_variables.map{|var| context.instance_variable_get(var) }
16
- context.rebind(user: User.new('Amy'), other_user: User.new('Elizabeth'))
17
- new_ivars = context.instance_variables.map{|var| context.instance_variable_get(var) }
14
+ it "clears internal storage when rebinding" do
15
+ originals = context.instance_variables.map { |var| context.instance_variable_get(var) }
16
+ context.rebind(user: User.new("Amy"), other_user: User.new("Elizabeth"))
17
+ new_ivars = context.instance_variables.map { |var| context.instance_variable_get(var) }
18
18
  originals.zip(new_ivars).each do |original_ivar, new_ivar|
19
19
  expect(original_ivar).wont_equal new_ivar
20
20
  end
21
21
  end
22
- end
22
+ end
@@ -1,26 +1,53 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ShortcutContext
4
4
  extend Surrounded::Context
5
+
5
6
  shortcut_triggers
6
-
7
+
7
8
  initialize :user, :other
8
-
9
+
9
10
  trigger :shorty do
10
11
  user.speak
11
12
  end
12
-
13
+
13
14
  role :user do
14
15
  def speak
15
- 'it works, shorty!'
16
+ "it works, shorty!"
16
17
  end
17
18
  end
18
19
  end
19
20
 
20
- describe Surrounded::Context, 'shortcuts' do
21
- let(:user){ User.new("Jim") }
22
- let(:other){ User.new("Guille") }
23
- it 'creates shortcut class methods for triggers' do
24
- assert_equal 'it works, shorty!', ShortcutContext.shorty(user: user, other: other)
21
+ class ShortcutContextNoKeywords
22
+ extend Surrounded::Context
23
+
24
+ shortcut_triggers
25
+
26
+ initialize_without_keywords :user, :other
27
+
28
+ trigger :shorty do
29
+ user.speak
25
30
  end
26
- end
31
+
32
+ role :user do
33
+ def speak
34
+ "it works, shorty!"
35
+ end
36
+ end
37
+ end
38
+
39
+ describe Surrounded::Context, "shortcuts" do
40
+ let(:user) { User.new("Jim") }
41
+ let(:other) { User.new("Guille") }
42
+ it "creates shortcut class methods for triggers" do
43
+ assert_equal "it works, shorty!", ShortcutContext.shorty(user: user, other: other)
44
+ end
45
+ end
46
+
47
+ describe Surrounded::Context, "shortcuts with initialize_without_keywords" do
48
+ let(:user) { User.new("Jim") }
49
+ let(:other) { User.new("Guille") }
50
+ it "creates shortcut class methods for triggers" do
51
+ assert_equal "it works, shorty!", ShortcutContextNoKeywords.shorty(user, other)
52
+ end
53
+ end
@@ -1,36 +1,37 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class EastTestContext
4
4
  extend Surrounded::Context
5
+
5
6
  east_oriented_triggers
6
-
7
+
7
8
  initialize :user, :other_user
8
-
9
+
9
10
  trigger :ask? do
10
11
  "asking a question..."
11
12
  end
12
13
  end
13
14
 
14
- describe Surrounded::Context, '.east_oriented_triggers' do
15
- let(:user){ User.new("Jim") }
16
- let(:other_user){ User.new("Guille") }
17
- let(:context){ EastTestContext.new(user: user, other_user: other_user) }
15
+ describe Surrounded::Context, ".east_oriented_triggers" do
16
+ let(:user) { User.new("Jim") }
17
+ let(:other_user) { User.new("Guille") }
18
+ let(:context) { EastTestContext.new(user: user, other_user: other_user) }
18
19
 
19
- it 'returns the context object from trigger methods' do
20
+ it "returns the context object from trigger methods" do
20
21
  assert_equal context, context.ask?
21
22
  end
22
23
  end
23
24
 
24
- describe Surrounded::Context, '.east_oriented_triggers with protect_triggers' do
25
- let(:user){ User.new("Jim") }
26
- let(:other_user){ User.new("Guille") }
27
- let(:context){
25
+ describe Surrounded::Context, ".east_oriented_triggers with protect_triggers" do
26
+ let(:user) { User.new("Jim") }
27
+ let(:other_user) { User.new("Guille") }
28
+ let(:context) {
28
29
  ctxt = EastTestContext.new(user: user, other_user: other_user)
29
30
  ctxt.singleton_class.send(:protect_triggers)
30
31
  ctxt
31
32
  }
32
33
 
33
- it 'returns the context object from trigger methods' do
34
+ it "returns the context object from trigger methods" do
34
35
  assert_equal context, context.ask?
35
36
  end
36
37
  end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  # If you want to use wrappers, here's how you could
4
4
  class DelegateClassContext
@@ -6,9 +6,9 @@ class DelegateClassContext
6
6
 
7
7
  initialize(:user, :task)
8
8
 
9
- delegate_class :user, 'User' do
9
+ delegate_class :user, "User" do
10
10
  def some_admin_method
11
- 'hello from the admin DelegateClass wrapper!'
11
+ "hello from the admin DelegateClass wrapper!"
12
12
  end
13
13
  end
14
14
  wrap :task do
@@ -20,10 +20,10 @@ class DelegateClassContext
20
20
  end
21
21
 
22
22
  describe DelegateClassContext do
23
- let(:context){
24
- DelegateClassContext.new(user: User.new('jim'), task: Object.new)
23
+ let(:context) {
24
+ DelegateClassContext.new(user: User.new("jim"), task: Object.new)
25
25
  }
26
- it 'wraps objects using DelegateClass' do
27
- assert_equal 'hello from the admin DelegateClass wrapper!', context.do_something
26
+ it "wraps objects using DelegateClass" do
27
+ assert_equal "hello from the admin DelegateClass wrapper!", context.do_something
28
28
  end
29
- end
29
+ end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ProxyContext
4
4
  extend Surrounded::Context
@@ -58,57 +58,59 @@ ProxyUser = Class.new do
58
58
  attr_reader :name
59
59
  end
60
60
 
61
+ ProxyTask = Data.define(:name)
62
+
61
63
  describe ProxyContext do
62
- let(:user){
63
- ProxyUser.new('Jim')
64
+ let(:user) {
65
+ ProxyUser.new("Jim")
64
66
  }
65
- let(:task){
66
- OpenStruct.new(name: 'GTD')
67
+ let(:task) {
68
+ ProxyTask.new(name: "GTD")
67
69
  }
68
- let(:context){
70
+ let(:context) {
69
71
  ProxyContext.new(admin: user, task: task)
70
72
  }
71
- it 'proxys methods between objects and its interface' do
72
- assert_equal 'hello from Jim, the admin interface!', context.do_something
73
+ it "proxys methods between objects and its interface" do
74
+ assert_equal "hello from Jim, the admin interface!", context.do_something
73
75
  end
74
76
 
75
- it 'forwards methods that the object responds to' do
76
- assert_equal 'Jim', context.admin_name
77
+ it "forwards methods that the object responds to" do
78
+ assert_equal "Jim", context.admin_name
77
79
  end
78
80
 
79
- it 'passes missing methods up the ancestry of the object' do
80
- err = ->{ context.admin_missing_method }.must_raise(NoMethodError)
81
+ it "passes missing methods up the ancestry of the object" do
82
+ err = _ { context.admin_missing_method }.must_raise(NoMethodError)
81
83
 
82
- assert_match(/ProxyUser.*name="Jim"/, err.message)
84
+ assert_match(/ProxyUser/, err.message)
83
85
  end
84
86
 
85
- it 'fails access to other objects in the context' do
86
- err = _{ context.talking }.must_raise NameError
87
- assert_match(%r{undefined local variable or method `task'}, err.message)
87
+ it "fails access to other objects in the context" do
88
+ err = _ { context.talking }.must_raise NameError
89
+ assert_match(/undefined local variable or method [`']task['`]/, err.message)
88
90
  end
89
91
 
90
- it 'sets roles to respond to role methods' do
92
+ it "sets roles to respond to role methods" do
91
93
  assert context.admin_responds?
92
94
  end
93
95
 
94
96
  # A Negotiator object merely applies methods to another object
95
97
  # so that once the method is called, the object has no knowledge
96
98
  # of the module from which the method was applied.
97
- it 'does not find other interface methods' do
98
- assert_raises(NameError){
99
+ it "does not find other interface methods" do
100
+ assert_raises(NameError) {
99
101
  context.combined_interface_methods
100
102
  }
101
103
  end
102
104
 
103
- it 'is able to grab methods from the object' do
105
+ it "is able to grab methods from the object" do
104
106
  assert_equal :talking_to_others, context.get_admin_method.name
105
107
  end
106
108
 
107
- it 'allows Surrounded objects to interact with others' do
108
- assert context.rebind(admin: User.new('Surrounded'), task: task).talking
109
+ it "allows Surrounded objects to interact with others" do
110
+ assert context.rebind(admin: User.new("Surrounded"), task: task).talking
109
111
  end
110
112
 
111
- it 'works with frozen and primitive objects' do
113
+ it "works with frozen and primitive objects" do
112
114
  context.rebind(admin: "brrr".freeze, task: task)
113
115
  assert context.get_admin_method
114
116
  context.rebind(admin: nil, task: task)
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ThreadedContext
4
4
  extend Surrounded::Context
@@ -16,7 +16,7 @@ class ThreadedContext
16
16
  result << members.concurrent_map do |member|
17
17
  result << member.greet
18
18
  end
19
- result.flatten.join(' ')
19
+ result.flatten.join(" ")
20
20
  end
21
21
 
22
22
  def greet
@@ -44,21 +44,21 @@ class ThreadedContext
44
44
  end
45
45
 
46
46
  describe ThreadedContext do
47
- let(:jim){ User.new('Jim') }
48
- let(:amy){ User.new('Amy') }
49
- let(:guille){ User.new('Guille') }
50
- let(:jason){ User.new('Jason') }
51
- let(:dave){ User.new('Dave') }
47
+ let(:jim) { User.new("Jim") }
48
+ let(:amy) { User.new("Amy") }
49
+ let(:guille) { User.new("Guille") }
50
+ let(:jason) { User.new("Jason") }
51
+ let(:dave) { User.new("Dave") }
52
52
 
53
- let(:greeter){ jim }
54
- let(:members){ [amy, guille, jason, dave] }
53
+ let(:greeter) { jim }
54
+ let(:members) { [amy, guille, jason, dave] }
55
55
 
56
- it 'works in multi-threaded environments' do
56
+ it "works in multi-threaded environments" do
57
57
  meeting = ThreadedContext.new(leader: jim, members: members)
58
58
 
59
59
  result = meeting.meet
60
60
 
61
- assert_includes result, 'Hello everyone. I am Jim'
62
- assert_includes result, 'Hello Jim, I am Amy'
61
+ assert_includes result, "Hello everyone. I am Jim"
62
+ assert_includes result, "Hello Jim, I am Amy"
63
63
  end
64
- end
64
+ end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  # If you want to use wrappers, here's how you could
4
4
  class WrapperContext
@@ -8,10 +8,10 @@ class WrapperContext
8
8
 
9
9
  wrap :admin do
10
10
  def some_admin_method
11
- 'hello from the admin wrapper!'
11
+ "hello from the admin wrapper!"
12
12
  end
13
13
  end
14
- wrap :task do; end
14
+ wrap :task, &proc {}
15
15
 
16
16
  trigger :do_something do
17
17
  admin.some_admin_method
@@ -19,10 +19,10 @@ class WrapperContext
19
19
  end
20
20
 
21
21
  describe WrapperContext do
22
- let(:context){
22
+ let(:context) {
23
23
  WrapperContext.new(admin: Object.new, task: Object.new)
24
24
  }
25
- it 'wraps objects and allows them to respond to new methods' do
26
- assert_equal 'hello from the admin wrapper!', context.do_something
25
+ it "wraps objects and allows them to respond to new methods" do
26
+ assert_equal "hello from the admin wrapper!", context.do_something
27
27
  end
28
- end
28
+ end