surrounded 1.1.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.
- checksums.yaml +4 -4
- data/Changelog.md +11 -20
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/Rakefile +12 -5
- data/lib/surrounded/access_control.rb +12 -11
- data/lib/surrounded/context/forwarding.rb +10 -10
- data/lib/surrounded/context/initializing.rb +8 -6
- data/lib/surrounded/context/name_collision_detector.rb +17 -17
- data/lib/surrounded/context/negotiator.rb +7 -8
- data/lib/surrounded/context/role_builders.rb +7 -7
- data/lib/surrounded/context/role_map.rb +6 -8
- data/lib/surrounded/context/trigger_controls.rb +11 -13
- data/lib/surrounded/context.rb +61 -56
- data/lib/surrounded/east_oriented.rb +4 -4
- data/lib/surrounded/exceptions.rb +1 -1
- data/lib/surrounded/shortcuts.rb +6 -8
- data/lib/surrounded/version.rb +1 -1
- data/lib/surrounded.rb +7 -7
- data/surrounded.gemspec +21 -15
- data/test/{casting_role_player_test.rb → casting_test_helper.rb} +4 -3
- data/test/collection_role_players_test.rb +16 -16
- data/test/context_access_test.rb +31 -30
- data/test/context_forwarding_test.rb +30 -30
- data/test/context_reuse_test.rb +14 -14
- data/test/context_shortcuts_test.rb +18 -16
- data/test/east_oriented_triggers_test.rb +14 -13
- data/test/example_delegate_class_test.rb +8 -8
- data/test/example_proxy_test.rb +25 -23
- data/test/example_threaded_test.rb +13 -13
- data/test/example_wrapper_test.rb +7 -7
- data/test/initialization_test.rb +24 -25
- data/test/name_collisions_test.rb +48 -42
- data/test/non_surrounded_role_player_test.rb +8 -8
- data/test/override_methods_test.rb +9 -9
- data/test/role_context_method_test.rb +129 -119
- data/test/surrounded_context_test.rb +71 -62
- data/test/surrounded_test.rb +13 -15
- data/test/test_helper.rb +5 -4
- data/test/threaded_context_test.rb +70 -0
- metadata +8 -38
- data/.codeclimate.yml +0 -4
- data/.github/workflows/codeql-analysis.yml +0 -70
- data/.github/workflows/test.yml +0 -18
- data/.gitignore +0 -19
- data/.pullreview.yml +0 -4
- data/.simplecov +0 -3
- data/Gemfile +0 -9
- data/examples/bottles.rb +0 -135
- data/examples/rails.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6cd923340dae45ac571dd98abf41be26d111f4569c59d98c27cd4e71f6204d1
|
4
|
+
data.tar.gz: a5d11c76eccb01b30fdec8aaced90571449d96c21fe4eced13e55dc1603241da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90659aa84b6565797f5b45fb4b637d0dfa21190dfed5366c20b586c4351ca1d0f02fdc5f8d6c45620ac6c9b36dccac28a842ce74b93a2d0a9258297db3d9e0e4
|
7
|
+
data.tar.gz: 4831ec1fe6a7dda8a9578776ecb0b2e2030ff37490d15f7e7f35351253bfe7f2c52c9ae1aa8fb7172cb471236b3d5c639f7eae8ef8c5510668a56542ba0fe014
|
data/Changelog.md
CHANGED
@@ -1,28 +1,19 @@
|
|
1
|
-
#
|
1
|
+
# Changelog
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
-
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
7
|
|
7
|
-
|
8
|
-
- Memoize the Negotiator methods for interface
|
8
|
+
## [1.1.1] - 2025-10-17
|
9
9
|
|
10
|
-
|
10
|
+
### Changed
|
11
11
|
|
12
|
-
-
|
12
|
+
- Version and changelog management with Reissue. (c919a3a)
|
13
|
+
- Set the gemspec to use a file list rather than depending on git (69b9a43)
|
14
|
+
- Update singularize_name to duplicate a string before altering the value. (3487d0d)
|
15
|
+
- Alter the list of identity methods in Negotiator to include __id__. (b98fb5a)
|
13
16
|
|
14
|
-
|
17
|
+
### Removed
|
15
18
|
|
16
|
-
-
|
17
|
-
- Remove code supporting exception cause it InvalidRoleType prior to ruby 2.1
|
18
|
-
|
19
|
-
## [0.9.11]
|
20
|
-
|
21
|
-
- Rely on the standard library Forwardable to setup how the RoleMap forwards messages to the container.
|
22
|
-
- Update RoleMap role_player? method to rescue from StandardError, a non-implementation-specific exception.
|
23
|
-
- Move to using triad 0.3.0 which relies on concurrent-ruby 0.9+ and moves off of thread_safe 0.3.5
|
24
|
-
|
25
|
-
## [0.9.10]
|
26
|
-
|
27
|
-
- Do something with name collisions when a role player has an existing method of another role in the context.
|
28
|
-
- Move InvalidRoleType exception under the host context class namespace. This allows you to rescue from your own namespace.
|
19
|
+
- Code Climate and Pull Review configuration. (46f0057)
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# 
|
2
|
+
|
2
3
|
## Be in control of business logic.
|
3
4
|
|
4
5
|
[](https://github.com/saturnflyer/surrounded/actions)
|
5
|
-
[](https://codeclimate.com/github/saturnflyer/surrounded)
|
6
6
|
|
7
7
|
Surrounded is designed to help you better manage your business logic by keeping cohesive behaviors together. Bring objects together to implement your use cases and gain behavior only when necessary.
|
8
8
|
|
@@ -920,7 +920,7 @@ end
|
|
920
920
|
|
921
921
|
If you'd like to use a special approach for just a single role, you may do that too.
|
922
922
|
|
923
|
-
When applying behaviors from a role to your role players, your Surrounded context will first look for a method named
|
923
|
+
When applying behaviors from a role to your role players, your Surrounded context will first look for a method named `"apply_behavior_#{role}"`. Define your own method and set it to accept 2 arguments: the role constant and the role player.
|
924
924
|
|
925
925
|
```ruby
|
926
926
|
class MyCustomContext
|
@@ -982,7 +982,6 @@ Lets say that you wish to create a context as below, intending to use instances
|
|
982
982
|
postcode.send
|
983
983
|
end
|
984
984
|
|
985
|
-
end
|
986
985
|
role :postcode do
|
987
986
|
def send
|
988
987
|
# do things...
|
@@ -991,6 +990,7 @@ Lets say that you wish to create a context as below, intending to use instances
|
|
991
990
|
end
|
992
991
|
end
|
993
992
|
```
|
993
|
+
|
994
994
|
When you call the `:send` trigger you are likely to be greeted with an `NoMethodError` exception. The reason for this is that there is a name collision between `Postcode#country`, and the `:country` role in the `SendAParcel` context. Where a name collision exists, the method in the role player overrides that of the calling class and you get unexpected results.
|
995
995
|
|
996
996
|
To address this issue, use `on_name_collision` to specify the name of a method to use when collisions are found:
|
data/Rakefile
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
|
3
|
-
require
|
3
|
+
require "rake/testtask"
|
4
4
|
|
5
5
|
Rake::TestTask.new do |t|
|
6
6
|
t.libs << "test"
|
7
|
-
t.test_files = FileList[
|
8
|
-
t.ruby_opts = ["-w"]
|
7
|
+
t.test_files = FileList["test/*_test.rb"]
|
9
8
|
t.verbose = true
|
9
|
+
t.warning = true
|
10
10
|
end
|
11
|
-
task :default => :test
|
12
11
|
|
12
|
+
task default: :test
|
13
|
+
|
14
|
+
require "reissue/gem"
|
15
|
+
|
16
|
+
Reissue::Task.create :reissue do |task|
|
17
|
+
task.version_file = "lib/surrounded/version.rb"
|
18
|
+
task.fragment = :git
|
19
|
+
end
|
13
20
|
|
14
21
|
# task :mutant, [:class] do |task, args|
|
15
22
|
# klass = args[:class] || 'Surrounded'
|
16
23
|
# sh "bundle exec mutant --include lib --require surrounded --use minitest #{klass}"
|
17
|
-
# end
|
24
|
+
# end
|
@@ -2,33 +2,34 @@ module Surrounded
|
|
2
2
|
module Context
|
3
3
|
class AccessError < ::StandardError; end
|
4
4
|
end
|
5
|
+
|
5
6
|
module AccessControl
|
6
7
|
def self.extended(base)
|
7
8
|
base.send(:include, AccessMethods)
|
8
9
|
Surrounded::Exceptions.define(base, exceptions: :AccessError)
|
9
10
|
end
|
10
|
-
|
11
|
+
|
11
12
|
private
|
12
|
-
|
13
|
+
|
13
14
|
def disallow(*names, &block)
|
14
15
|
names.map do |name|
|
15
16
|
define_access_method(name, &block)
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
|
-
|
19
|
+
alias_method :guard, :disallow
|
20
|
+
|
20
21
|
def trigger_return_content(name, *args, &block)
|
21
22
|
%{
|
22
23
|
|
23
24
|
method_restrictor = "disallow_#{name}?"
|
24
25
|
if self.respond_to?(method_restrictor, true) && self.send(method_restrictor)
|
25
|
-
raise ::#{self
|
26
|
+
raise ::#{self}::AccessError.new("access to #{self.name}##{name} is not allowed")
|
26
27
|
end
|
27
28
|
|
28
29
|
#{super}
|
29
30
|
}
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
def define_access_method(name, &block)
|
33
34
|
mod = Module.new
|
34
35
|
mod.class_eval {
|
@@ -42,26 +43,26 @@ module Surrounded
|
|
42
43
|
const_set("SurroundedAccess#{name}", mod)
|
43
44
|
include mod
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
module AccessMethods
|
47
48
|
# Return a Set of all defined triggers regardless of any disallow blocks
|
48
49
|
def all_triggers
|
49
50
|
self.class.triggers
|
50
51
|
end
|
51
|
-
|
52
|
+
|
52
53
|
# Return a Set of triggers which may be run according to any restrictions defined
|
53
54
|
# in disallow blocks.
|
54
55
|
def triggers
|
55
|
-
all_triggers.select {|name|
|
56
|
+
all_triggers.select { |name|
|
56
57
|
allow?(name)
|
57
58
|
}.to_set
|
58
59
|
end
|
59
60
|
|
60
61
|
# Ask if the context will allow access to a trigger given the current players.
|
61
62
|
def allow?(name)
|
62
|
-
raise NoMethodError, %
|
63
|
+
raise NoMethodError, %(undefined method `#{name}' for #{inspect}) unless respond_to?(name)
|
63
64
|
predicate = "disallow_#{name}?"
|
64
|
-
!
|
65
|
+
!respond_to?(predicate) || !public_send(predicate)
|
65
66
|
end
|
66
67
|
end
|
67
68
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
module Surrounded
|
2
2
|
module Context
|
3
3
|
module Forwarding
|
4
|
-
def forward_trigger(receiver, message, alternate=message)
|
5
|
-
raise(ArgumentError, %
|
6
|
-
trigger alternate do |*args, &block|
|
7
|
-
|
4
|
+
def forward_trigger(receiver, message, alternate = message)
|
5
|
+
raise(ArgumentError, %(you may not forward '%{m}`) % {m: message}) if ["__id__", "__send__"].include?(message.to_s)
|
6
|
+
trigger alternate do |*args, **kwargs, &block|
|
7
|
+
send(receiver).public_send(message, *args, **kwargs, &block)
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def forward_triggers(receiver, *messages)
|
12
12
|
messages.each do |message|
|
13
13
|
forward_trigger(receiver, message)
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def forwarding(hash)
|
18
18
|
hash.each { |messages, receiver|
|
19
19
|
forward_triggers(receiver, *messages)
|
20
20
|
}
|
21
21
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
|
23
|
+
alias_method :forward, :forward_trigger
|
24
|
+
alias_method :forwards, :forward_triggers
|
25
25
|
end
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end
|
@@ -2,19 +2,20 @@ module Surrounded
|
|
2
2
|
module Context
|
3
3
|
module Initializing
|
4
4
|
extend Seclusion
|
5
|
+
|
5
6
|
# Shorthand for creating an instance level initialize method which
|
6
7
|
# handles the mapping of the given arguments to their named role.
|
7
8
|
def initialize_without_keywords(*setup_args, &block)
|
8
|
-
parameters = setup_args.join(
|
9
|
+
parameters = setup_args.join(",")
|
9
10
|
default_initializer(parameters, setup_args, &block)
|
10
11
|
end
|
11
12
|
|
12
13
|
def initialize(*setup_args, &block)
|
13
|
-
parameters = setup_args.map{|a| "#{a}:"}.join(
|
14
|
+
parameters = setup_args.map { |a| "#{a}:" }.join(",")
|
14
15
|
default_initializer(parameters, setup_args, &block)
|
15
16
|
end
|
16
|
-
|
17
|
-
|
17
|
+
alias_method :keyword_initialize, :initialize
|
18
|
+
alias_method :initialize_with_keywords, :keyword_initialize
|
18
19
|
|
19
20
|
def initializer_block
|
20
21
|
@initializer_block
|
@@ -31,13 +32,14 @@ module Surrounded
|
|
31
32
|
line = __LINE__; mod.class_eval %{
|
32
33
|
def initialize(#{params})
|
33
34
|
@role_map = role_mapper_class.new
|
34
|
-
@initializer_arguments = Hash[#{setup_args
|
35
|
+
@initializer_arguments = Hash[#{setup_args}.zip([#{setup_args.join(",")}])]
|
35
36
|
map_roles(@initializer_arguments)
|
36
37
|
self.class.apply_initializer_block(self)
|
37
38
|
end
|
38
39
|
}, __FILE__, line
|
39
|
-
const_set(
|
40
|
+
const_set(:ContextInitializer, mod)
|
40
41
|
include mod
|
42
|
+
|
41
43
|
private_attr_reader :initializer_arguments
|
42
44
|
end
|
43
45
|
end
|
@@ -1,56 +1,56 @@
|
|
1
1
|
module Surrounded
|
2
2
|
module Context
|
3
|
-
class NameCollisionError
|
4
|
-
module NameCollisionDetector
|
3
|
+
class NameCollisionError < ::StandardError; end
|
5
4
|
|
5
|
+
module NameCollisionDetector
|
6
6
|
attr_reader :handler
|
7
7
|
|
8
8
|
def self.extended(base)
|
9
9
|
base.send :include, NameCollisionHandler
|
10
10
|
Surrounded::Exceptions.define(base, exceptions: :NameCollisionError)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def on_name_collision(method_name)
|
14
14
|
@handler = method_name
|
15
15
|
end
|
16
16
|
|
17
17
|
module NameCollisionHandler
|
18
|
-
|
19
18
|
private
|
20
|
-
|
19
|
+
|
21
20
|
def detect_collisions(role_object_map)
|
22
21
|
if handler
|
23
22
|
handle_collisions(collision_warnings(role_object_map))
|
24
23
|
end
|
25
24
|
end
|
26
|
-
|
25
|
+
|
27
26
|
def collision_warnings(role_object_map)
|
28
|
-
role_object_map.select{|role, object|
|
27
|
+
role_object_map.select { |role, object|
|
29
28
|
![object.methods & role_object_map.keys].flatten.empty?
|
30
|
-
}.map{|role, object|
|
31
|
-
role_collision_message(role,(object.methods & role_object_map.keys).sort)
|
29
|
+
}.map { |role, object|
|
30
|
+
role_collision_message(role, (object.methods & role_object_map.keys).sort)
|
32
31
|
}.join("\n")
|
33
32
|
end
|
34
|
-
|
33
|
+
|
35
34
|
def handle_collisions(collisions)
|
36
35
|
handler_args = [collisions]
|
37
36
|
if handler == :raise
|
38
37
|
handler_args.unshift self.class::NameCollisionError
|
39
38
|
end
|
40
|
-
|
39
|
+
|
41
40
|
handler_method.call(*handler_args)
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
def role_collision_message(role, colliding_method_names)
|
45
44
|
"#{role} has name collisions with #{colliding_method_names}"
|
46
45
|
end
|
47
|
-
|
48
|
-
def nothing(*)
|
46
|
+
|
47
|
+
def nothing(*)
|
48
|
+
end
|
49
49
|
|
50
50
|
def handler
|
51
51
|
self.class.handler
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def handler_method
|
55
55
|
if handler.respond_to?(:call)
|
56
56
|
handler
|
@@ -59,10 +59,10 @@ module Surrounded
|
|
59
59
|
elsif self.class.respond_to?(handler, true)
|
60
60
|
self.class.method(handler)
|
61
61
|
else
|
62
|
-
raise ArgumentError, %
|
62
|
+
raise ArgumentError, %(your name collision handler was set to `#{handler}' but there is no instance nor class method of that name)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|
@@ -14,25 +14,24 @@ module Surrounded
|
|
14
14
|
# For each method in the module, directly forward to the wrapped object to
|
15
15
|
# circumvent method_missing
|
16
16
|
mod.instance_methods(false).each do |meth|
|
17
|
-
|
17
|
+
klass.class_eval <<~MOD, __FILE__, __LINE__ + 1
|
18
18
|
def #{meth}(...)
|
19
19
|
@#{meth}_method ||= __behaviors__.instance_method(:#{meth}).bind(@object)
|
20
20
|
@#{meth}_method.call(...)
|
21
21
|
end
|
22
|
-
|
22
|
+
MOD
|
23
23
|
end
|
24
24
|
klass
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
identity = %w[__send__ object_id equal?]
|
28
|
+
identity = %w[__send__ __id__ object_id equal?]
|
30
29
|
method_access = %w[respond_to? method __behaviors__]
|
31
30
|
|
32
|
-
reserved_methods = (identity + method_access).join(
|
31
|
+
reserved_methods = (identity + method_access).join("|")
|
33
32
|
|
34
33
|
# Remove all methods except the reserved methods
|
35
|
-
instance_methods.reject{ |m|
|
34
|
+
instance_methods.reject { |m|
|
36
35
|
m.to_s =~ /#{reserved_methods}/
|
37
36
|
}.each do |meth|
|
38
37
|
undef_method meth
|
@@ -52,7 +51,7 @@ module Surrounded
|
|
52
51
|
self
|
53
52
|
end
|
54
53
|
# These only differ in the message they send
|
55
|
-
|
54
|
+
alias_method :remove_context, :store_context
|
56
55
|
|
57
56
|
def initialize(object)
|
58
57
|
@object = object
|
@@ -62,7 +61,7 @@ module Surrounded
|
|
62
61
|
@object.send(meth, ...)
|
63
62
|
end
|
64
63
|
|
65
|
-
def respond_to_missing?(meth, include_private=false)
|
64
|
+
def respond_to_missing?(meth, include_private = false)
|
66
65
|
@object.respond_to?(meth, include_private)
|
67
66
|
end
|
68
67
|
end
|
@@ -10,7 +10,7 @@ module Surrounded
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Define behaviors for your role players
|
13
|
-
def role(name, type=default_role_type, &block)
|
13
|
+
def role(name, type = default_role_type, &block)
|
14
14
|
if type == :module
|
15
15
|
mod_name = RoleName(name)
|
16
16
|
mod = Module.new(&block).send(:include, ::Surrounded)
|
@@ -26,7 +26,7 @@ module Surrounded
|
|
26
26
|
|
27
27
|
# Create a named behavior for a role using the standard library SimpleDelegator.
|
28
28
|
def wrap(name, &block)
|
29
|
-
require
|
29
|
+
require "delegate"
|
30
30
|
wrapper_name = RoleName(name)
|
31
31
|
klass = private_const_set(wrapper_name, Class.new(SimpleDelegator, &block))
|
32
32
|
klass.send(:include, Surrounded)
|
@@ -36,7 +36,7 @@ module Surrounded
|
|
36
36
|
# Create a named behavior for a role using the standard library DelegateClass.
|
37
37
|
# This ties the implementation of the role to a specific class or module API.
|
38
38
|
def delegate_class(name, class_name, &block)
|
39
|
-
require
|
39
|
+
require "delegate"
|
40
40
|
wrapper_name = RoleName(name)
|
41
41
|
klass = private_const_set(wrapper_name, DelegateClass(Object.const_get(class_name.to_s)))
|
42
42
|
klass.class_eval(&block)
|
@@ -53,19 +53,19 @@ module Surrounded
|
|
53
53
|
# access them from any of its methods.
|
54
54
|
def interface(name, &block)
|
55
55
|
# AdminInterface
|
56
|
-
interface_name = RoleName(name,
|
56
|
+
interface_name = RoleName(name, "Interface")
|
57
57
|
behavior = private_const_set(interface_name, Module.new(&block))
|
58
58
|
|
59
|
-
require
|
59
|
+
require "surrounded/context/negotiator"
|
60
60
|
# Admin
|
61
61
|
private_const_set(RoleName(name), Negotiator.for_role(behavior))
|
62
62
|
end
|
63
63
|
|
64
64
|
private
|
65
|
-
|
65
|
+
|
66
|
+
def RoleName(text, suffix = nil)
|
66
67
|
RoleName.new(text, suffix)
|
67
68
|
end
|
68
|
-
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "triad"
|
2
|
+
require "forwardable"
|
3
3
|
module Surrounded
|
4
4
|
module Context
|
5
5
|
class RoleMap
|
@@ -8,19 +8,17 @@ module Surrounded
|
|
8
8
|
class << self
|
9
9
|
# Get the role map container and provide an alternative if desired
|
10
10
|
# Ex: RoleMap.from_base(SomeCustomContainer)
|
11
|
-
def from_base(klass
|
11
|
+
def from_base(klass = ::Triad)
|
12
12
|
unless const_defined?(:Container)
|
13
13
|
role_mapper = Class.new(self)
|
14
|
-
role_mapper.container_class=(klass)
|
14
|
+
role_mapper.container_class = (klass)
|
15
15
|
Surrounded::Exceptions.define(role_mapper, exceptions: :ItemNotPresent, namespace: klass)
|
16
16
|
const_set(:Container, role_mapper)
|
17
17
|
end
|
18
18
|
const_get(:Container)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
@container_class = klass
|
23
|
-
end
|
21
|
+
attr_writer :container_class
|
24
22
|
end
|
25
23
|
|
26
24
|
def_delegators :container, :update, :each, :values, :keys
|
@@ -37,7 +35,7 @@ module Surrounded
|
|
37
35
|
# Check if an object is playing a role in this map
|
38
36
|
def role_player?(object)
|
39
37
|
!values(object).empty?
|
40
|
-
rescue
|
38
|
+
rescue container.class::ItemNotPresent
|
41
39
|
false
|
42
40
|
end
|
43
41
|
|
@@ -1,24 +1,23 @@
|
|
1
1
|
module Surrounded
|
2
2
|
module Context
|
3
3
|
module TriggerControls
|
4
|
-
|
5
4
|
# Provides a Set of all available trigger methods where
|
6
5
|
# behaviors will be applied to the roles before execution
|
7
6
|
# and removed afterward.
|
8
7
|
def triggers
|
9
8
|
@triggers.dup
|
10
9
|
end
|
11
|
-
|
10
|
+
|
12
11
|
def store_trigger(*names)
|
13
12
|
@triggers.merge(names)
|
14
13
|
end
|
15
|
-
|
14
|
+
|
16
15
|
# Creates a context instance method which will apply behaviors to role players
|
17
16
|
# before execution and remove the behaviors after execution.
|
18
17
|
#
|
19
18
|
# Alternatively you may define your own methods then declare them as triggers
|
20
19
|
# afterward.
|
21
|
-
#
|
20
|
+
#
|
22
21
|
# Example:
|
23
22
|
# trigger :some_event do
|
24
23
|
# # code here
|
@@ -41,7 +40,7 @@ module Surrounded
|
|
41
40
|
store_trigger(name)
|
42
41
|
end
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
def convert_method_to_trigger(name)
|
46
45
|
unless triggers.include?(name) || name.nil?
|
47
46
|
alias_method :"__trigger_#{name}", :"#{name}"
|
@@ -53,7 +52,7 @@ module Surrounded
|
|
53
52
|
end
|
54
53
|
|
55
54
|
def define_trigger(name)
|
56
|
-
|
55
|
+
class_eval <<~MOD, __FILE__, __LINE__ + 1
|
57
56
|
def #{name}(...)
|
58
57
|
begin
|
59
58
|
apply_behaviors
|
@@ -64,24 +63,23 @@ module Surrounded
|
|
64
63
|
remove_behaviors
|
65
64
|
end
|
66
65
|
end
|
67
|
-
|
66
|
+
MOD
|
68
67
|
end
|
69
|
-
|
68
|
+
|
70
69
|
def trigger_return_content(name)
|
71
70
|
if method_defined?(name)
|
72
|
-
%
|
71
|
+
%(super)
|
73
72
|
else
|
74
73
|
%{self.send("__trigger_#{name}", ...)}
|
75
74
|
end
|
76
75
|
end
|
77
|
-
|
78
|
-
|
76
|
+
|
79
77
|
def define_trigger_action(*name_and_args, &block)
|
80
78
|
trigger_action_module.send(:define_method, *name_and_args, &block)
|
81
79
|
end
|
82
|
-
|
80
|
+
|
83
81
|
def trigger_action_module
|
84
|
-
|
82
|
+
const_get(:TriggerMethods, false)
|
85
83
|
end
|
86
84
|
end
|
87
85
|
end
|