bandy-dci 0.0.4
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 +7 -0
- data/lib/dci.rb +4 -0
- data/lib/dci/castable.rb +49 -0
- data/lib/dci/context.rb +99 -0
- data/lib/dci/role_lookup.rb +13 -0
- data/spec/dci/castable_spec.rb +77 -0
- data/spec/dci/context_spec.rb +290 -0
- data/spec/dci/role_lookup_spec.rb +119 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30ad5219182fae98adeba5f1eb7880047078001f
|
4
|
+
data.tar.gz: 2284100d33e40d98f2ed53b5fa9b1647f9178ae8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d033acd944220f29b6c200200c84a49b44f0897f26c8e3d4dd48d663c334671b80cce044cac713bb8a6864b7acfb4ab8e2a40de1e8f920960ccc2157f9e6561
|
7
|
+
data.tar.gz: b6b61532643781f831dc46dffd1bff8482e629a2624435810a030de9423eac256ebf2483af4b1e8ed503a6dc48354f03e945fea5e3f584c631c1d5b94f109f2a
|
data/lib/dci.rb
ADDED
data/lib/dci/castable.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'dci/context'
|
2
|
+
|
3
|
+
module DCI
|
4
|
+
module Castable
|
5
|
+
def self.module_method_rebinding?
|
6
|
+
sample_method = Enumerable.instance_method(:to_a)
|
7
|
+
begin
|
8
|
+
!!sample_method.bind(Object.new)
|
9
|
+
rescue TypeError
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
if module_method_rebinding?
|
17
|
+
def delegated_method(role, method)
|
18
|
+
role.instance_method(method)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
def delegated_method(role, method)
|
22
|
+
clone.extend(role).method(method).unbind
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *arguments, &block)
|
27
|
+
role = participating_role_with_method(method)
|
28
|
+
role ? delegated_method(role, method).bind(self).call(*arguments, &block) : super
|
29
|
+
end
|
30
|
+
|
31
|
+
def participating_role_with_method(method)
|
32
|
+
context = DCI::Context.current
|
33
|
+
return unless context
|
34
|
+
|
35
|
+
roles = context[self]
|
36
|
+
return unless roles
|
37
|
+
|
38
|
+
roles.find do |role|
|
39
|
+
role.public_instance_methods.include?(method) ||
|
40
|
+
role.protected_instance_methods.include?(method) ||
|
41
|
+
role.private_instance_methods.include?(method)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def respond_to_missing?(method, include_private)
|
46
|
+
!!participating_role_with_method(method) || super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/dci/context.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'dci/castable'
|
2
|
+
|
3
|
+
module DCI
|
4
|
+
module Context
|
5
|
+
# The currently executing context
|
6
|
+
def self.current
|
7
|
+
Thread.current[:'DCI::Context.current']
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(calling_module)
|
11
|
+
calling_module.extend(DSL)
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast(actor, roles)
|
15
|
+
actor.extend(Castable) unless actor.is_a?(Castable)
|
16
|
+
|
17
|
+
@roles ||= {}
|
18
|
+
@roles[actor] ||= []
|
19
|
+
@roles[actor] |= roles.values
|
20
|
+
|
21
|
+
actor
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](actor)
|
25
|
+
@roles && @roles[actor]
|
26
|
+
end
|
27
|
+
|
28
|
+
module DSL
|
29
|
+
private
|
30
|
+
|
31
|
+
# Replace an existing method with a wrapper that advertises the current context
|
32
|
+
def define_entry_using_method(name)
|
33
|
+
method = instance_method(name)
|
34
|
+
define_method(name) do |*arguments, &block|
|
35
|
+
begin
|
36
|
+
# Swap out the currently executing context
|
37
|
+
Thread.current[:'DCI::Context.current'], old_context = self, Thread.current[:'DCI::Context.current']
|
38
|
+
method.bind(self).call(*arguments, &block)
|
39
|
+
ensure
|
40
|
+
# Reinstate the previously executing context
|
41
|
+
Thread.current[:'DCI::Context.current'] = old_context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create a method that executes the provided definition while advertising the current context
|
47
|
+
def define_entry_using_proc(name, definition)
|
48
|
+
define_method(name, &definition)
|
49
|
+
define_entry_using_method(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Define a context entry point
|
53
|
+
def entry(name, proc = nil, &block)
|
54
|
+
if block_given?
|
55
|
+
define_entry_using_proc(name, block)
|
56
|
+
elsif proc.respond_to?(:to_proc)
|
57
|
+
define_entry_using_proc(name, proc)
|
58
|
+
elsif method_defined?(name)
|
59
|
+
define_entry_using_method(name)
|
60
|
+
else
|
61
|
+
@entries ||= []
|
62
|
+
@entries |= [name]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Listen for new methods that are intended to be entry points
|
67
|
+
def method_added(name)
|
68
|
+
if @entries && @entries.delete(name)
|
69
|
+
define_entry_using_method(name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Define a context role
|
74
|
+
def role(name, *args, &block)
|
75
|
+
attr_reader name
|
76
|
+
public name
|
77
|
+
|
78
|
+
if block_given?
|
79
|
+
role_module = Module.new
|
80
|
+
role_module.module_eval(&block)
|
81
|
+
|
82
|
+
define_method("#{name}=") do |actor|
|
83
|
+
instance_variable_set("@#{name}", cast(actor, :as => role_module))
|
84
|
+
end
|
85
|
+
else
|
86
|
+
attr_writer name
|
87
|
+
end
|
88
|
+
|
89
|
+
protected "#{name}="
|
90
|
+
end
|
91
|
+
|
92
|
+
def trigger(name, delegate, method = name)
|
93
|
+
entry(name) do |*arguments, &block|
|
94
|
+
__send__(delegate).__send__(method, *arguments, &block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'dci/context'
|
2
|
+
|
3
|
+
module DCI
|
4
|
+
module RoleLookup
|
5
|
+
private
|
6
|
+
|
7
|
+
# Forward references to constants to the currently executing context
|
8
|
+
def const_missing(name)
|
9
|
+
context = DCI::Context.current
|
10
|
+
context.respond_to?(name) ? context.__send__(name) : super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'dci/castable'
|
2
|
+
|
3
|
+
describe DCI::Castable do
|
4
|
+
let(:something) { Class.new { include DCI::Castable; def greet; 'hello'; end } }
|
5
|
+
subject(:actor) { something.new }
|
6
|
+
|
7
|
+
context 'when the actor is not participating in the current context' do
|
8
|
+
specify 'calling a nonexistent method raises NoMethodError' do
|
9
|
+
expect { actor.smile }.to raise_error(NoMethodError)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify 'calling an implemented method works' do
|
13
|
+
expect(actor.greet).to eq 'hello'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when the actor is participating in the current context' do
|
18
|
+
let(:context_participants) { { actor => [role] } }
|
19
|
+
let(:role) { Module.new }
|
20
|
+
|
21
|
+
before do
|
22
|
+
allow(DCI::Context).to receive(:current).and_return(context_participants)
|
23
|
+
end
|
24
|
+
|
25
|
+
specify 'calling a method implemented by none of its roles raises NoMethodError' do
|
26
|
+
expect(actor).to_not respond_to(:smile)
|
27
|
+
expect { actor.smile }.to raise_error(NoMethodError)
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when one of its roles implements a public method' do
|
31
|
+
let(:role) { Module.new { def eat; :yum; end } }
|
32
|
+
|
33
|
+
specify 'calling that method works' do
|
34
|
+
expect(actor).to respond_to(:eat)
|
35
|
+
expect(actor.eat).to be :yum
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when one of its roles implements a protected method' do
|
40
|
+
let(:role) { Module.new { protected; def eat; :yum; end } }
|
41
|
+
|
42
|
+
specify 'calling that method works' do
|
43
|
+
expect(actor).to respond_to(:eat)
|
44
|
+
expect(actor.eat).to be :yum
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when one of its roles implements a private method' do
|
49
|
+
let(:role) { Module.new { private; def eat; :yum; end } }
|
50
|
+
|
51
|
+
specify 'calling that method works' do
|
52
|
+
expect(actor).to respond_to(:eat)
|
53
|
+
expect(actor.eat).to be :yum
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when one of its role methods takes arguments' do
|
58
|
+
let(:role) { Module.new { def sing(song); song; end } }
|
59
|
+
|
60
|
+
specify 'calling that method without arguments raises ArgumentError' do
|
61
|
+
expect { actor.sing }.to raise_error(ArgumentError)
|
62
|
+
end
|
63
|
+
|
64
|
+
specify 'calling that method with arguments works' do
|
65
|
+
expect(actor.sing(:song)).to be :song
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when one of its role methods takes a block' do
|
70
|
+
let(:role) { Module.new { def sing(&block); block.call; end } }
|
71
|
+
|
72
|
+
specify 'calling that method with a block works' do
|
73
|
+
expect(actor.sing { :song }).to be :song
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'dci/context'
|
2
|
+
|
3
|
+
describe DCI::Context do
|
4
|
+
describe 'role implementations' do
|
5
|
+
let(:context) { Class.new { include DCI::Context } }
|
6
|
+
let(:context_instance) { context.new }
|
7
|
+
let(:participating_roles) { context_instance[role_player] }
|
8
|
+
let(:role_implementation) { Module.new }
|
9
|
+
let(:role_player) { double }
|
10
|
+
|
11
|
+
specify 'are applied using #cast' do
|
12
|
+
context_instance.cast(role_player, :as => role_implementation)
|
13
|
+
|
14
|
+
expect(role_player).to be_a(DCI::Castable)
|
15
|
+
expect(participating_roles).to eq [role_implementation]
|
16
|
+
end
|
17
|
+
|
18
|
+
specify 'are nil when not applied' do
|
19
|
+
expect(participating_roles).to be nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'role identifiers are defined using ::role' do
|
24
|
+
let(:context) do
|
25
|
+
Class.new do
|
26
|
+
include DCI::Context
|
27
|
+
|
28
|
+
role :One
|
29
|
+
|
30
|
+
def initialize(one)
|
31
|
+
self.One = one
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'at runtime' do
|
37
|
+
subject(:context_instance) { context.new(one) }
|
38
|
+
let(:one) { double }
|
39
|
+
|
40
|
+
specify 'role players can be assigned' do
|
41
|
+
expect { context_instance }.to_not raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
specify 'role players can be accessed' do
|
45
|
+
expect(context_instance.One).to be one
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'when passed a block, that block becomes the implementation' do
|
50
|
+
let(:context) do
|
51
|
+
Class.new do
|
52
|
+
include DCI::Context
|
53
|
+
|
54
|
+
role :One do
|
55
|
+
def something
|
56
|
+
:expected
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
self.One = Object.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:context_instance) { context.new }
|
67
|
+
let(:participating_roles) { context_instance[role_player] }
|
68
|
+
let(:role_player) { context_instance.One }
|
69
|
+
|
70
|
+
specify 'it is applied when the role is assigned' do
|
71
|
+
expect(role_player).to be_a DCI::Castable
|
72
|
+
expect(participating_roles).to be_an Array
|
73
|
+
expect(participating_roles.first).to be_a Module
|
74
|
+
expect(participating_roles.first.public_instance_methods).to include :something
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'context entry points are identified using ::entry' do
|
80
|
+
subject(:context_instance) { context.new }
|
81
|
+
|
82
|
+
shared_examples 'correctly manages the currently executing context' do
|
83
|
+
specify 'it assigns the executing context' do
|
84
|
+
context_instance.something { expect(DCI::Context.current).to be context_instance }
|
85
|
+
end
|
86
|
+
|
87
|
+
specify 'it restores the previously executing context' do
|
88
|
+
expect { context_instance.something {} }.to_not change { DCI::Context.current }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when the method exists' do
|
93
|
+
let(:context) do
|
94
|
+
Class.new do
|
95
|
+
include DCI::Context
|
96
|
+
|
97
|
+
def something(&block)
|
98
|
+
block.call
|
99
|
+
end
|
100
|
+
|
101
|
+
entry :something
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
specify 'it can be called' do
|
106
|
+
expect(context_instance).to respond_to :something
|
107
|
+
expect(context_instance.something { :expected }).to be :expected
|
108
|
+
end
|
109
|
+
|
110
|
+
include_examples 'correctly manages the currently executing context'
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when the method does not exist' do
|
114
|
+
let(:context) do
|
115
|
+
Class.new do
|
116
|
+
include DCI::Context
|
117
|
+
|
118
|
+
entry :something
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
specify 'it cannot be called' do
|
123
|
+
expect(context_instance).to_not respond_to :something
|
124
|
+
expect { context_instance.something }.to raise_error(NoMethodError, /something/)
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'once the method is defined' do
|
128
|
+
before do
|
129
|
+
context.class_exec do
|
130
|
+
def something(&block)
|
131
|
+
block.call
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
specify 'it can be called' do
|
137
|
+
expect(context_instance).to respond_to :something
|
138
|
+
expect(context_instance.something { :expected }).to be :expected
|
139
|
+
end
|
140
|
+
|
141
|
+
include_examples 'correctly manages the currently executing context'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'when passed a block, that block becomes the definition' do
|
146
|
+
let(:context) do
|
147
|
+
Class.new do
|
148
|
+
include DCI::Context
|
149
|
+
|
150
|
+
entry :point do
|
151
|
+
:expected
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
specify 'that can be called' do
|
157
|
+
expect(context_instance).to respond_to :point
|
158
|
+
expect(context_instance.point).to be :expected
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when the block has parameters' do
|
162
|
+
let(:context) do
|
163
|
+
Class.new do
|
164
|
+
include DCI::Context
|
165
|
+
|
166
|
+
entry :parameters do |argument|
|
167
|
+
argument
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
specify 'those parameters are required' do
|
173
|
+
expect { context_instance.parameters }.to raise_error ArgumentError
|
174
|
+
end
|
175
|
+
|
176
|
+
specify 'and can be called with arguments' do
|
177
|
+
expect(context_instance.parameters(:expected)).to be :expected
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'when the block takes a block' do
|
182
|
+
let(:context) do
|
183
|
+
Class.new do
|
184
|
+
include DCI::Context
|
185
|
+
|
186
|
+
entry :block do |&block|
|
187
|
+
block.call
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
specify 'it works' do
|
193
|
+
expect(context_instance.block { :expected }).to be :expected
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe 'when passed a lambda, that lambda becomes the definition' do
|
199
|
+
let(:context) do
|
200
|
+
Class.new do
|
201
|
+
include DCI::Context
|
202
|
+
|
203
|
+
entry :parameters, ->(argument) do
|
204
|
+
argument
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
specify 'that can be called' do
|
210
|
+
expect(context_instance).to respond_to :parameters
|
211
|
+
expect { context_instance.parameters }.to raise_error ArgumentError
|
212
|
+
expect(context_instance.parameters(:expected)).to be :expected
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe 'use case triggers are identified using ::trigger' do
|
218
|
+
let(:context) do
|
219
|
+
Class.new do
|
220
|
+
include DCI::Context
|
221
|
+
trigger :trigger_name, :RoleName, :method_name
|
222
|
+
end
|
223
|
+
end
|
224
|
+
let(:context_instance) { context.new }
|
225
|
+
|
226
|
+
specify 'the trigger is callable' do
|
227
|
+
expect(context_instance).to respond_to :trigger_name
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'when the role does not exist' do
|
231
|
+
specify 'calling the trigger raises a NoMethodError' do
|
232
|
+
expect { context_instance.trigger_name }.to raise_error(NoMethodError, /RoleName/)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'when the role method does not exist' do
|
237
|
+
before { context.class_eval { role :RoleName } }
|
238
|
+
|
239
|
+
specify 'calling the trigger raises a NoMethodError' do
|
240
|
+
expect { context_instance.trigger_name }.to raise_error(NoMethodError, /method_name/)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'when the role and method exist' do
|
245
|
+
before do
|
246
|
+
context.class_eval do
|
247
|
+
role :RoleName do
|
248
|
+
def method_name(&block)
|
249
|
+
block.call
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def initialize
|
254
|
+
self.RoleName = Object.new
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
specify 'it can be called' do
|
260
|
+
expect(context_instance.trigger_name { :expected }).to be :expected
|
261
|
+
end
|
262
|
+
|
263
|
+
specify 'it assigns the executing context' do
|
264
|
+
context_instance.trigger_name { expect(DCI::Context.current).to be context_instance }
|
265
|
+
end
|
266
|
+
|
267
|
+
specify 'it restores the previously executing context' do
|
268
|
+
expect { context_instance.trigger_name {} }.to_not change { DCI::Context.current }
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
context 'with two arguments' do
|
273
|
+
let(:context) do
|
274
|
+
Class.new do
|
275
|
+
include DCI::Context
|
276
|
+
|
277
|
+
trigger :trigger_name, :RoleName
|
278
|
+
end
|
279
|
+
end
|
280
|
+
let(:role_player) { double }
|
281
|
+
|
282
|
+
before { allow(context_instance).to receive(:RoleName).and_return(role_player) }
|
283
|
+
|
284
|
+
specify 'the method defaults to trigger name' do
|
285
|
+
expect(role_player).to receive :trigger_name
|
286
|
+
context_instance.trigger_name
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'dci/role_lookup'
|
2
|
+
|
3
|
+
describe DCI::RoleLookup do
|
4
|
+
context 'when roles are lowercase' do
|
5
|
+
class LowercaseContext
|
6
|
+
include DCI::Context
|
7
|
+
extend DCI::RoleLookup
|
8
|
+
|
9
|
+
role :one
|
10
|
+
role :two do
|
11
|
+
def access_one
|
12
|
+
one
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
entry :access_one_from_two do
|
17
|
+
two.access_one
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
self.one = Object.new
|
22
|
+
self.two = Object.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:context_instance) { LowercaseContext.new }
|
27
|
+
|
28
|
+
specify 'role lookup does not work' do
|
29
|
+
expect { context_instance.access_one_from_two }.to raise_error(NameError, /undefined.*one/)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when roles are capitalized' do
|
34
|
+
context 'in an anonymous module' do
|
35
|
+
let(:context) do
|
36
|
+
Class.new do
|
37
|
+
include DCI::Context
|
38
|
+
extend DCI::RoleLookup
|
39
|
+
|
40
|
+
role :One
|
41
|
+
|
42
|
+
entry :access_one do
|
43
|
+
One
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:context_instance) { context.new }
|
49
|
+
|
50
|
+
specify 'role lookup does not work' do
|
51
|
+
expect { context_instance.access_one }.to raise_error(NameError, /One/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'in a named module' do
|
56
|
+
class NamedContext
|
57
|
+
include DCI::Context
|
58
|
+
extend DCI::RoleLookup
|
59
|
+
|
60
|
+
role :One
|
61
|
+
role :Two
|
62
|
+
role :Three do
|
63
|
+
def access_one
|
64
|
+
One
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module TwoMethods
|
69
|
+
extend DCI::RoleLookup
|
70
|
+
|
71
|
+
def access_one
|
72
|
+
One
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
entry :access_one_from_two do
|
77
|
+
Two.access_one
|
78
|
+
end
|
79
|
+
|
80
|
+
entry :access_one_from_three do
|
81
|
+
Three.access_one
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(one)
|
85
|
+
self.One = one
|
86
|
+
self.Two = cast(Object.new, :as => TwoMethods)
|
87
|
+
self.Three = Object.new
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:context_instance) { NamedContext.new(one) }
|
92
|
+
let(:one) { double }
|
93
|
+
|
94
|
+
specify 'role lookup works' do
|
95
|
+
expect(context_instance.access_one_from_two).to be == one
|
96
|
+
expect(context_instance.access_one_from_three).to be == one
|
97
|
+
end
|
98
|
+
|
99
|
+
specify 'those roles cannot be referenced by a later executing context' do
|
100
|
+
class FirstContext
|
101
|
+
include DCI::Context
|
102
|
+
role :One
|
103
|
+
entry :call do
|
104
|
+
SecondContext.new.call
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class SecondContext
|
109
|
+
include DCI::Context
|
110
|
+
entry :call do
|
111
|
+
One
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
expect { FirstContext.new.call }.to raise_error(NameError, /One/)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bandy-dci
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Bandy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.14'
|
27
|
+
description: Facilitate DCI in Ruby
|
28
|
+
email:
|
29
|
+
- bandy.chris@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/dci.rb
|
35
|
+
- lib/dci/castable.rb
|
36
|
+
- lib/dci/context.rb
|
37
|
+
- lib/dci/role_lookup.rb
|
38
|
+
- spec/dci/castable_spec.rb
|
39
|
+
- spec/dci/context_spec.rb
|
40
|
+
- spec/dci/role_lookup_spec.rb
|
41
|
+
homepage: https://github.com/cbandy/ruby-dci
|
42
|
+
licenses:
|
43
|
+
- Apache License Version 2.0
|
44
|
+
metadata: {}
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.9'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 2.0.14
|
62
|
+
signing_key:
|
63
|
+
specification_version: 4
|
64
|
+
summary: DCI
|
65
|
+
test_files:
|
66
|
+
- spec/dci/castable_spec.rb
|
67
|
+
- spec/dci/context_spec.rb
|
68
|
+
- spec/dci/role_lookup_spec.rb
|