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,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,8 +52,8 @@ module Surrounded
53
52
  end
54
53
 
55
54
  def define_trigger(name)
56
- line = __LINE__; self.class_eval %{
57
- def #{name}(*args, &block)
55
+ class_eval <<~MOD, __FILE__, __LINE__ + 1
56
+ def #{name}(...)
58
57
  begin
59
58
  apply_behaviors
60
59
 
@@ -64,25 +63,24 @@ module Surrounded
64
63
  remove_behaviors
65
64
  end
66
65
  end
67
- }, __FILE__, line
66
+ MOD
68
67
  end
69
-
68
+
70
69
  def trigger_return_content(name)
71
70
  if method_defined?(name)
72
- %{super}
71
+ %(super)
73
72
  else
74
- %{self.send("__trigger_#{name}", *args, &block)}
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
- self.const_get('TriggerMethods', false)
82
+ const_get(:TriggerMethods, false)
85
83
  end
86
84
  end
87
85
  end
88
- end
86
+ end
@@ -1,14 +1,14 @@
1
- require 'set'
2
- require 'surrounded/exceptions'
3
- require 'surrounded/context/role_map'
4
- require 'surrounded/context/role_builders'
5
- require 'surrounded/context/initializing'
6
- require 'surrounded/context/forwarding'
7
- require 'surrounded/context/trigger_controls'
8
- require 'surrounded/access_control'
9
- require 'surrounded/shortcuts'
10
- require 'surrounded/east_oriented'
11
- require 'surrounded/context/name_collision_detector'
1
+ require "surrounded/exceptions"
2
+ require "surrounded/context/role_map"
3
+ require "surrounded/context/seclusion"
4
+ require "surrounded/context/role_builders"
5
+ require "surrounded/context/initializing"
6
+ require "surrounded/context/forwarding"
7
+ require "surrounded/context/trigger_controls"
8
+ require "surrounded/access_control"
9
+ require "surrounded/shortcuts"
10
+ require "surrounded/east_oriented"
11
+ require "surrounded/context/name_collision_detector"
12
12
 
13
13
  # Extend your classes with Surrounded::Context to handle their
14
14
  # initialization and application of behaviors to the role players
@@ -20,22 +20,19 @@ module Surrounded
20
20
  module Context
21
21
  def self.extended(base)
22
22
  base.class_eval {
23
- extend RoleBuilders, Initializing, Forwarding, NameCollisionDetector
23
+ extend Seclusion, RoleBuilders, Initializing, Forwarding, NameCollisionDetector
24
24
 
25
25
  @triggers = Set.new
26
26
  include InstanceMethods
27
27
 
28
28
  trigger_mod = Module.new
29
- const_set('TriggerMethods', trigger_mod)
29
+ const_set(:TriggerMethods, trigger_mod)
30
30
  include trigger_mod
31
31
 
32
32
  extend TriggerControls
33
-
34
33
  }
35
34
  end
36
35
 
37
- private
38
-
39
36
  # Set the default type of implementation for role methods for all contexts.
40
37
  def self.default_role_type
41
38
  @default_role_type ||= :module
@@ -45,6 +42,8 @@ module Surrounded
45
42
  attr_writer :default_role_type
46
43
  end
47
44
 
45
+ private
46
+
48
47
  def default_role_type
49
48
  @default_role_type ||= Surrounded::Context.default_role_type
50
49
  end
@@ -55,13 +54,19 @@ module Surrounded
55
54
  end
56
55
 
57
56
  # Provide the ability to create access control methods for your triggers.
58
- def protect_triggers; self.extend(::Surrounded::AccessControl); end
57
+ def protect_triggers
58
+ extend(::Surrounded::AccessControl)
59
+ end
59
60
 
60
61
  # Automatically create class methods for each trigger method.
61
- def shortcut_triggers; self.extend(::Surrounded::Shortcuts); end
62
+ def shortcut_triggers
63
+ extend(::Surrounded::Shortcuts)
64
+ end
62
65
 
63
66
  # Automatically return the context object from trigger methods.
64
- def east_oriented_triggers; self.extend(::Surrounded::EastOriented); end
67
+ def east_oriented_triggers
68
+ extend(::Surrounded::EastOriented)
69
+ end
65
70
 
66
71
  # === Utility shortcuts
67
72
 
@@ -69,21 +74,6 @@ module Surrounded
69
74
  const_defined?(name, false)
70
75
  end
71
76
 
72
- # Set a named constant and make it private
73
- def private_const_set(name, const)
74
- unless role_const_defined?(name)
75
- const = const_set(name, const)
76
- private_constant name.to_sym
77
- end
78
- const
79
- end
80
-
81
- # Create attr_reader for the named methods and make them private
82
- def private_attr_reader(*method_names)
83
- attr_reader(*method_names)
84
- private(*method_names)
85
- end
86
-
87
77
  # Conditional const_get for a named role behavior
88
78
  def role_const(name)
89
79
  if role_const_defined?(name)
@@ -105,7 +95,7 @@ module Surrounded
105
95
  # is allowed to inquire about the roles.
106
96
  def role?(name, &block)
107
97
  return false unless role_map.role?(name)
108
- accessor = block.binding.eval('self')
98
+ accessor = block.binding.eval("self")
109
99
  role_map.role_player?(accessor) && role_map.assigned_player(name)
110
100
  end
111
101
 
@@ -119,10 +109,11 @@ module Surrounded
119
109
  self.class.triggers
120
110
  end
121
111
 
112
+ # Reuse the same context object but pass new values
122
113
  def rebind(**options_hash)
123
114
  clear_instance_variables
124
115
  begin
125
- initialize(options_hash)
116
+ initialize(**options_hash)
126
117
  rescue ArgumentError
127
118
  initialize(*options_hash.values)
128
119
  end
@@ -132,7 +123,7 @@ module Surrounded
132
123
  private
133
124
 
134
125
  def clear_instance_variables
135
- instance_variables.each{|ivar| remove_instance_variable(ivar) }
126
+ instance_variables.each { |ivar| remove_instance_variable(ivar) }
136
127
  end
137
128
 
138
129
  def role_map
@@ -142,8 +133,8 @@ module Surrounded
142
133
  def map_roles(role_object_array)
143
134
  detect_collisions role_object_array
144
135
  role_object_array.to_a.each do |role, object|
145
- if self.respond_to?("map_role_#{role}")
146
- self.send("map_role_#{role}", object)
136
+ if respond_to?("map_role_#{role}")
137
+ send("map_role_#{role}", object)
147
138
  else
148
139
  map_role(role, role_behavior_name(role), object)
149
140
  map_role_collection(role, role_behavior_name(role), object)
@@ -168,13 +159,13 @@ module Surrounded
168
159
 
169
160
  def apply_behavior(role, behavior, object)
170
161
  if behavior && role_const_defined?(behavior)
171
- applicator = if self.respond_to?("apply_behavior_#{role}")
172
- method("apply_behavior_#{role}")
173
- elsif role_const(behavior).is_a?(Class)
174
- method(:apply_class_behavior)
175
- else
176
- method(:apply_module_behavior)
177
- end
162
+ applicator = if respond_to?("apply_behavior_#{role}")
163
+ method("apply_behavior_#{role}")
164
+ elsif role_const(behavior).is_a?(Class)
165
+ method(:apply_class_behavior)
166
+ else
167
+ method(:apply_module_behavior)
168
+ end
178
169
 
179
170
  role_player = applicator.call(role_const(behavior), object)
180
171
  map_role(role, behavior, role_player)
@@ -183,7 +174,7 @@ module Surrounded
183
174
  end
184
175
 
185
176
  def apply_module_behavior(mod, obj)
186
- adder_name = module_extension_methods.find{|meth| obj.respond_to?(meth) }
177
+ adder_name = module_extension_methods.find { |meth| obj.respond_to?(meth) }
187
178
  return obj unless adder_name
188
179
 
189
180
  obj.method(adder_name).call(mod)
@@ -191,7 +182,7 @@ module Surrounded
191
182
  end
192
183
 
193
184
  def apply_class_behavior(klass, obj)
194
- wrapper_name = wrap_methods.find{|meth| klass.respond_to?(meth) }
185
+ wrapper_name = wrap_methods.find { |meth| klass.respond_to?(meth) }
195
186
  return obj if !wrapper_name
196
187
  klass.method(wrapper_name).call(obj)
197
188
  end
@@ -203,11 +194,11 @@ module Surrounded
203
194
  end
204
195
  end
205
196
 
206
- role_player = if self.respond_to?("remove_behavior_#{role}")
207
- self.send("remove_behavior_#{role}", role_const(behavior), object)
208
- elsif remover_name
209
- object.send(remover_name)
210
- end
197
+ role_player = if respond_to?("remove_behavior_#{role}")
198
+ send("remove_behavior_#{role}", role_const(behavior), object)
199
+ elsif remover_name
200
+ object.send(remover_name)
201
+ end
211
202
 
212
203
  role_player || object
213
204
  end
@@ -216,7 +207,7 @@ module Surrounded
216
207
  role_map.each do |role, mod_name, object|
217
208
  player = apply_behavior(role, mod_name, object)
218
209
  if player.respond_to?(:store_context, true)
219
- player.__send__(:store_context) do; end
210
+ player.__send__(:store_context) {}
220
211
  end
221
212
  end
222
213
  end
@@ -224,7 +215,7 @@ module Surrounded
224
215
  def remove_behaviors
225
216
  role_map.each do |role, mod_name, player|
226
217
  if player.respond_to?(:remove_context, true)
227
- player.__send__(:remove_context) do; end
218
+ player.__send__(:remove_context) {}
228
219
  end
229
220
  remove_behavior(role, mod_name, player)
230
221
  end
@@ -255,7 +246,7 @@ module Surrounded
255
246
  end
256
247
 
257
248
  def role_module_basename(mod)
258
- mod.to_s.split('::').last
249
+ mod.to_s.split("::").last
259
250
  end
260
251
 
261
252
  def role_const(name)
@@ -275,33 +266,34 @@ module Surrounded
275
266
  name.singularize
276
267
  else
277
268
  # good enough for now but should be updated with better rules
278
- name.to_s.tap do |string|
279
- if string =~ /ies\z/
280
- string.sub!(/ies\z/,'y')
281
- elsif string =~ /s\z/
282
- string.sub!(/s\z/,'')
283
- end
269
+ string = name.to_s.dup
270
+ if string.end_with?("ies")
271
+ string.sub(/ies\z/, "y")
272
+ elsif string.end_with?("s")
273
+ string.sub(/s\z/, "")
274
+ else
275
+ string
284
276
  end
285
277
  end
286
278
  end
287
279
  end
288
280
 
289
281
  class RoleName
290
- def initialize(string, suffix=nil)
291
- @string = string.
292
- to_s.
293
- split(/_/).
294
- map{|part|
295
- part.capitalize
296
- }.
297
- join.
298
- sub(/_\d+/,'') + suffix.to_s
282
+ def initialize(string, suffix = nil)
283
+ @string = string
284
+ .to_s
285
+ .split("_")
286
+ .map { |part|
287
+ part.capitalize
288
+ }
289
+ .join
290
+ .sub(/_\d+/, "") + suffix.to_s
299
291
  end
300
292
 
301
293
  def to_str
302
294
  @string
303
295
  end
304
- alias to_s to_str
296
+ alias_method :to_s, :to_str
305
297
 
306
298
  def to_sym
307
299
  @string.to_sym
@@ -3,11 +3,11 @@ module Surrounded
3
3
  # Always return the context object to ensure that a context may
4
4
  # not be asked for information.
5
5
  def trigger_return_content(name, *args, &block)
6
- %{
6
+ %(
7
7
  #{super}
8
-
8
+
9
9
  self
10
- }
10
+ )
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -1,7 +1,7 @@
1
1
  module Surrounded
2
2
  module Exceptions
3
3
  def self.define(klass, exceptions:, namespace: Surrounded::Context)
4
- Array(exceptions).each{ |exception|
4
+ Array(exceptions).each { |exception|
5
5
  unless klass.const_defined?(exception)
6
6
  klass.const_set(exception, Class.new(namespace.const_get(exception)))
7
7
  end
@@ -1,11 +1,21 @@
1
1
  module Surrounded
2
2
  module Shortcuts
3
3
  private
4
-
4
+
5
5
  def define_shortcut(name)
6
- singleton_class.send(:define_method, name) do |*args|
7
- instance = self.new(*args)
8
- instance.public_send(name)
6
+ # if keyword initialize
7
+ if instance_method(:initialize).parameters.dig(0, 0) == :keyreq
8
+ singleton_class.send(:define_method, name) do |**args|
9
+ instance = new(**args)
10
+
11
+ instance.public_send(name)
12
+ end
13
+ else # non-keyword initialize
14
+ singleton_class.send(:define_method, name) do |*args|
15
+ instance = new(*args)
16
+
17
+ instance.public_send(name)
18
+ end
9
19
  end
10
20
  end
11
21
 
@@ -16,4 +26,4 @@ module Surrounded
16
26
  super
17
27
  end
18
28
  end
19
- end
29
+ end
@@ -1,6 +1,6 @@
1
1
  module Surrounded
2
- VERSION = "1.0.0"
3
-
2
+ VERSION = "1.1.1"
3
+
4
4
  def self.version
5
5
  VERSION
6
6
  end
data/lib/surrounded.rb CHANGED
@@ -3,23 +3,22 @@ require "surrounded/context"
3
3
  require "singleton"
4
4
 
5
5
  # This module should be added to objects which will enter
6
- # into context objects.
6
+ # into context objects.
7
7
  #
8
8
  # Its main purpose is to keep a reference to the context
9
9
  # and to implement method_missing to handle the relationship
10
10
  # to other objects in the context.
11
11
  module Surrounded
12
-
13
12
  private
14
13
 
15
14
  def store_context(&block)
16
- accessor = block.binding.eval('self')
15
+ accessor = block.binding.eval("self")
17
16
  surroundings.unshift(accessor)
18
17
  self
19
18
  end
20
19
 
21
20
  def remove_context(&block)
22
- accessor = block.binding.eval('self')
21
+ accessor = block.binding.eval("self")
23
22
  surroundings.shift if surroundings.include?(accessor)
24
23
  self
25
24
  end
@@ -33,15 +32,16 @@ module Surrounded
33
32
  end
34
33
 
35
34
  def method_missing(meth, *args, &block)
36
- context.role?(meth){} || super
35
+ context.role?(meth) {} || super
37
36
  end
38
37
 
39
- def respond_to_missing?(meth, include_private=false)
40
- !!context.role?(meth){} || super
38
+ def respond_to_missing?(meth, include_private = false)
39
+ !!context.role?(meth) {} || super
41
40
  end
42
41
 
43
42
  class NullContext
44
43
  include Singleton
44
+
45
45
  def role?(*args)
46
46
  nil
47
47
  end
data/surrounded.gemspec CHANGED
@@ -1,25 +1,30 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'surrounded/version'
3
+ require "surrounded/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "surrounded"
8
- spec.version = Surrounded.version
9
- spec.authors = ["'Jim Gay'"]
10
- spec.email = ["jim@saturnflyer.com"]
11
- spec.description = %q{Gives an object implicit access to other objects in it's environment.}
12
- spec.summary = %q{Create encapsulated environments for your objects.}
13
- spec.homepage = "http://github.com/saturnflyer/surrounded"
14
- spec.license = "MIT"
6
+ spec.name = "surrounded"
7
+ spec.version = Surrounded.version
8
+ spec.authors = ["'Jim Gay'"]
9
+ spec.email = ["jim@saturnflyer.com"]
10
+ spec.description = "Gives an object implicit access to other objects in it's environment."
11
+ spec.summary = "Create encapsulated environments for your objects."
12
+ spec.homepage = "http://github.com/saturnflyer/surrounded"
13
+ spec.license = "MIT"
15
14
 
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.files = Dir[
16
+ "lib/**/*",
17
+ "Rakefile",
18
+ "README.md",
19
+ "Changelog.md",
20
+ "LICENSE.txt",
21
+ "test/**/*",
22
+ "surrounded.gemspec"
23
+ ]
24
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
25
  spec.require_paths = ["lib"]
20
26
 
21
- spec.add_dependency "triad", "~> 0.3.0"
27
+ spec.add_dependency "triad", ">= 0.3.0"
22
28
 
23
- spec.add_development_dependency "bundler", "~> 1.12"
24
29
  spec.add_development_dependency "rake"
25
30
  end
@@ -1,7 +1,8 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- require 'casting'
3
+ require "casting"
4
4
  class CastingUser < User
5
5
  include Casting::Client
6
+
6
7
  delegate_missing_methods
7
- end
8
+ end
@@ -1,4 +1,5 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
+ require "casting_test_helper"
2
3
 
3
4
  class CollectionContext
4
5
  extend Surrounded::Context
@@ -10,7 +11,7 @@ class CollectionContext
10
11
  end
11
12
 
12
13
  trigger :get_member_show do
13
- members.map(&:show).join(', ')
14
+ members.map(&:show).join(", ")
14
15
  end
15
16
 
16
17
  role :members do
@@ -25,27 +26,26 @@ class CollectionContext
25
26
  end
26
27
  end
27
28
 
28
- role :others do; end
29
- role :other do; end
30
-
29
+ role :others, &proc {}
30
+ role :other, &proc {}
31
31
  end
32
32
 
33
- describe Surrounded::Context, 'auto-assigning roles for collections' do
34
- let(:member_one){ User.new('Jim') }
35
- let(:member_two){ User.new('Amy') }
36
- let(:members){ [member_one, member_two] }
33
+ describe Surrounded::Context, "auto-assigning roles for collections" do
34
+ let(:member_one) { User.new("Jim") }
35
+ let(:member_two) { User.new("Amy") }
36
+ let(:members) { [member_one, member_two] }
37
37
 
38
- let(:other_one){ User.new('Guille') }
39
- let(:other_two){ User.new('Jason') }
40
- let(:others){ [other_one, other_two] }
38
+ let(:other_one) { User.new("Guille") }
39
+ let(:other_two) { User.new("Jason") }
40
+ let(:others) { [other_one, other_two] }
41
41
 
42
- let(:context){ CollectionContext.new(members: members, others: others) }
42
+ let(:context) { CollectionContext.new(members: members, others: others) }
43
43
 
44
- it 'assigns the collection role to collections' do
44
+ it "assigns the collection role to collections" do
45
45
  assert_equal members.size, context.get_members_count
46
46
  end
47
47
 
48
- it 'assigns a defined role to each item in a role player collection' do
48
+ it "assigns a defined role to each item in a role player collection" do
49
49
  assert_equal "member show, member show", context.get_member_show
50
50
  end
51
- end
51
+ end