surrounded 1.1.1 → 1.1.2
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/Changelog.md +6 -0
- data/lib/surrounded/context/role_builders.rb +2 -5
- data/lib/surrounded/context/role_map.rb +29 -5
- data/lib/surrounded/context/seclusion.rb +9 -3
- data/lib/surrounded/context.rb +7 -6
- data/lib/surrounded/version.rb +1 -1
- data/test/role_identity_test.rb +39 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa24dd1e23a33e7949fe503496f6ef64d86cccc0ac3abd70e149acc9cc24ac44
|
|
4
|
+
data.tar.gz: d282d6bdf295c8a0d9a08a0e43b679902a355f9a556dd9a2504261fbbecfa430
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea3dcc682bc3c6b3e5bc0c1be6e68fc4c2e920a0a25d5e8d12ee91ecd726ac2c812a3539576e2db1838d59fb65a9fdb18c9b65f5dd7dffeeeac1bf2f1c646a18
|
|
7
|
+
data.tar.gz: 3251756a4d7bd37979a8b8af55867b47d1cffdfabb1503ab641f1c756f22b8867c9e08f997e4a3a0582ff96d0b288a1dee1cb91e479f467d212925893ca838ac
|
data/Changelog.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [1.1.2] - 2026-06-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Roles applied through a wrapper, such as an interface, can reach the other roles in their context. (c1d41a6)
|
|
13
|
+
|
|
8
14
|
## [1.1.1] - 2025-10-17
|
|
9
15
|
|
|
10
16
|
### Changed
|
|
@@ -46,11 +46,8 @@ module Surrounded
|
|
|
46
46
|
# Create an object which will bind methods to the role player.
|
|
47
47
|
#
|
|
48
48
|
# This object will behave differently that a wrapper or delegate_class.
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# Because the interface methods are applied individually to an object,
|
|
52
|
-
# that object is unaware of the other objects in the context and cannot
|
|
53
|
-
# access them from any of its methods.
|
|
49
|
+
# Interface methods run as the wrapped object itself, so they can access
|
|
50
|
+
# the other objects in the context only if that object includes Surrounded.
|
|
54
51
|
def interface(name, &block)
|
|
55
52
|
# AdminInterface
|
|
56
53
|
interface_name = RoleName(name, "Interface")
|
|
@@ -32,17 +32,41 @@ module Surrounded
|
|
|
32
32
|
keys.include?(role)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
#
|
|
35
|
+
# Record the behaviored player applied to a role for the duration of a
|
|
36
|
+
# trigger. The assigned domain object stays in the container; the player
|
|
37
|
+
# (a wrapper, or the same object for cast roles) is tracked here.
|
|
38
|
+
def apply(role, player)
|
|
39
|
+
applied[role] = player
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The player a role currently presents: the applied player while a trigger
|
|
43
|
+
# is running, otherwise the assigned domain object.
|
|
44
|
+
def current_player(role)
|
|
45
|
+
applied.fetch(role) { assigned_player(role) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Forget all applied players, e.g. after a trigger removes behaviors.
|
|
49
|
+
def reset_applied
|
|
50
|
+
applied.clear
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Check if an object is playing a role in this map, by identity — whether
|
|
54
|
+
# it is the assigned domain object or the applied player wrapping it.
|
|
36
55
|
def role_player?(object)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
false
|
|
56
|
+
values.any? { |player| player.equal?(object) } ||
|
|
57
|
+
applied.values.any? { |player| player.equal?(object) }
|
|
40
58
|
end
|
|
41
59
|
|
|
42
|
-
# Get the object
|
|
60
|
+
# Get the domain object assigned to the given role
|
|
43
61
|
def assigned_player(role)
|
|
44
62
|
values(role).first
|
|
45
63
|
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def applied
|
|
68
|
+
@applied ||= {}
|
|
69
|
+
end
|
|
46
70
|
end
|
|
47
71
|
end
|
|
48
72
|
end
|
|
@@ -10,10 +10,16 @@ module Surrounded
|
|
|
10
10
|
const
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
# Create
|
|
13
|
+
# Create readers for the named methods and make them private. Role names
|
|
14
|
+
# resolve to the current player (original object, or its applied wrapper
|
|
15
|
+
# during a trigger); any other name reads its instance variable.
|
|
14
16
|
def private_attr_reader(*method_names)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
method_names.each do |name|
|
|
18
|
+
define_method(name) do
|
|
19
|
+
role_map.role?(name) ? role_map.current_player(name) : instance_variable_get(:"@#{name}")
|
|
20
|
+
end
|
|
21
|
+
private(name)
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
end
|
|
19
25
|
end
|
data/lib/surrounded/context.rb
CHANGED
|
@@ -96,7 +96,7 @@ module Surrounded
|
|
|
96
96
|
def role?(name, &block)
|
|
97
97
|
return false unless role_map.role?(name)
|
|
98
98
|
accessor = block.binding.eval("self")
|
|
99
|
-
role_map.role_player?(accessor) && role_map.
|
|
99
|
+
role_map.role_player?(accessor) && role_map.current_player(name)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
# Check if a given object is a role player in the context.
|
|
@@ -153,7 +153,6 @@ module Surrounded
|
|
|
153
153
|
end
|
|
154
154
|
|
|
155
155
|
def map_role(role, mod_name, object)
|
|
156
|
-
instance_variable_set("@#{role}", object)
|
|
157
156
|
role_map.update(role, role_module_basename(mod_name), object)
|
|
158
157
|
end
|
|
159
158
|
|
|
@@ -168,7 +167,6 @@ module Surrounded
|
|
|
168
167
|
end
|
|
169
168
|
|
|
170
169
|
role_player = applicator.call(role_const(behavior), object)
|
|
171
|
-
map_role(role, behavior, role_player)
|
|
172
170
|
end
|
|
173
171
|
role_player || object
|
|
174
172
|
end
|
|
@@ -206,6 +204,7 @@ module Surrounded
|
|
|
206
204
|
def apply_behaviors
|
|
207
205
|
role_map.each do |role, mod_name, object|
|
|
208
206
|
player = apply_behavior(role, mod_name, object)
|
|
207
|
+
role_map.apply(role, player)
|
|
209
208
|
if player.respond_to?(:store_context, true)
|
|
210
209
|
player.__send__(:store_context) {}
|
|
211
210
|
end
|
|
@@ -213,12 +212,14 @@ module Surrounded
|
|
|
213
212
|
end
|
|
214
213
|
|
|
215
214
|
def remove_behaviors
|
|
216
|
-
role_map.each do |role, mod_name,
|
|
215
|
+
role_map.each do |role, mod_name, object|
|
|
216
|
+
player = role_map.current_player(role)
|
|
217
217
|
if player.respond_to?(:remove_context, true)
|
|
218
218
|
player.__send__(:remove_context) {}
|
|
219
219
|
end
|
|
220
220
|
remove_behavior(role, mod_name, player)
|
|
221
221
|
end
|
|
222
|
+
role_map.reset_applied
|
|
222
223
|
end
|
|
223
224
|
|
|
224
225
|
# List of possible methods to use to add behavior to an object from a module.
|
|
@@ -284,8 +285,8 @@ module Surrounded
|
|
|
284
285
|
.to_s
|
|
285
286
|
.split("_")
|
|
286
287
|
.map { |part|
|
|
287
|
-
|
|
288
|
-
|
|
288
|
+
part.capitalize
|
|
289
|
+
}
|
|
289
290
|
.join
|
|
290
291
|
.sub(/_\d+/, "") + suffix.to_s
|
|
291
292
|
end
|
data/lib/surrounded/version.rb
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
# Refuses value-equality so resolution must use object identity.
|
|
4
|
+
class IdentityResistant
|
|
5
|
+
include Surrounded
|
|
6
|
+
|
|
7
|
+
def initialize(name)
|
|
8
|
+
@name = name
|
|
9
|
+
end
|
|
10
|
+
attr_reader :name
|
|
11
|
+
|
|
12
|
+
def ==(other) = false
|
|
13
|
+
def eql?(other) = false
|
|
14
|
+
def hash = object_id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class SpeakerContext
|
|
18
|
+
extend Surrounded::Context
|
|
19
|
+
|
|
20
|
+
initialize :speaker, :listener
|
|
21
|
+
|
|
22
|
+
interface :speaker do
|
|
23
|
+
def greet
|
|
24
|
+
listener.name
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
trigger :speak do
|
|
29
|
+
speaker.greet
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "role identity independent of equality" do
|
|
34
|
+
it "resolves a sibling role by object identity, not ==" do
|
|
35
|
+
a = IdentityResistant.new("A")
|
|
36
|
+
b = IdentityResistant.new("B")
|
|
37
|
+
expect(SpeakerContext.new(speaker: a, listener: b).speak).must_equal "B"
|
|
38
|
+
end
|
|
39
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: surrounded
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- "'Jim Gay'"
|
|
@@ -80,6 +80,7 @@ files:
|
|
|
80
80
|
- test/non_surrounded_role_player_test.rb
|
|
81
81
|
- test/override_methods_test.rb
|
|
82
82
|
- test/role_context_method_test.rb
|
|
83
|
+
- test/role_identity_test.rb
|
|
83
84
|
- test/surrounded_context_test.rb
|
|
84
85
|
- test/surrounded_test.rb
|
|
85
86
|
- test/test_helper.rb
|
|
@@ -102,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
102
103
|
- !ruby/object:Gem::Version
|
|
103
104
|
version: '0'
|
|
104
105
|
requirements: []
|
|
105
|
-
rubygems_version:
|
|
106
|
+
rubygems_version: 4.0.10
|
|
106
107
|
specification_version: 4
|
|
107
108
|
summary: Create encapsulated environments for your objects.
|
|
108
109
|
test_files: []
|