rachinations 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +6 -0
- data/.travis.yml +8 -0
- data/.yardopts +1 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +93 -0
- data/LICENSE.txt +21 -0
- data/README.md +18 -0
- data/Rakefile +16 -0
- data/lib/rachinations.rb +49 -0
- data/lib/rachinations/domain/diagrams/diagram.rb +167 -0
- data/lib/rachinations/domain/diagrams/non_deterministic_diagram.rb +16 -0
- data/lib/rachinations/domain/diagrams/verbose_diagram.rb +9 -0
- data/lib/rachinations/domain/edge_collection.rb +12 -0
- data/lib/rachinations/domain/edges/edge.rb +159 -0
- data/lib/rachinations/domain/edges/random_edge.rb +4 -0
- data/lib/rachinations/domain/exceptions/bad_options.rb +3 -0
- data/lib/rachinations/domain/exceptions/no_elements_found.rb +2 -0
- data/lib/rachinations/domain/exceptions/no_elements_matching_condition_error.rb +2 -0
- data/lib/rachinations/domain/exceptions/no_elements_of_given_type.rb +3 -0
- data/lib/rachinations/domain/exceptions/unsupported_type_error.rb +2 -0
- data/lib/rachinations/domain/modules/common/hash_init.rb +88 -0
- data/lib/rachinations/domain/modules/common/invariant.rb +17 -0
- data/lib/rachinations/domain/modules/diagrams/verbose.rb +30 -0
- data/lib/rachinations/domain/node_collection.rb +30 -0
- data/lib/rachinations/domain/nodes/converter.rb +276 -0
- data/lib/rachinations/domain/nodes/gate.rb +6 -0
- data/lib/rachinations/domain/nodes/node.rb +166 -0
- data/lib/rachinations/domain/nodes/pool.rb +267 -0
- data/lib/rachinations/domain/nodes/resourceful_node.rb +96 -0
- data/lib/rachinations/domain/nodes/resourceless_node.rb +11 -0
- data/lib/rachinations/domain/nodes/sink.rb +17 -0
- data/lib/rachinations/domain/nodes/source.rb +161 -0
- data/lib/rachinations/domain/nodes/trader.rb +6 -0
- data/lib/rachinations/domain/resource_bag.rb +131 -0
- data/lib/rachinations/domain/resources/token.rb +51 -0
- data/lib/rachinations/domain/strategies/strategy.rb +5 -0
- data/lib/rachinations/domain/strategies/valid_types.rb +69 -0
- data/lib/rachinations/dsl/dsl.rb +63 -0
- data/lib/rachinations/extras/fifo.rb +27 -0
- data/lib/rachinations/version.rb +3 -0
- data/machinations_diagrams/apenas_bonito.xml +22 -0
- data/machinations_diagrams/behavior_converter.xml +53 -0
- data/machinations_diagrams/behavior_converter_fim.xml +10 -0
- data/machinations_diagrams/canon/README.md +8 -0
- data/machinations_diagrams/canon/converters_differences.xml +27 -0
- data/machinations_diagrams/canon/converters_differences2.xml +34 -0
- data/machinations_diagrams/canon/converters_similarities.xml +63 -0
- data/machinations_diagrams/canon/converters_similarities2.xml +21 -0
- data/machinations_diagrams/canon/nodes_and_edges_differences.xml +15 -0
- data/machinations_diagrams/canon/nodes_and_edges_similarities.xml +20 -0
- data/machinations_diagrams/deterministic_example.xml +46 -0
- data/machinations_diagrams/economies_of_scale.xml +32 -0
- data/machinations_diagrams/feature_ou_bug.xml +5 -0
- data/machinations_diagrams/loop_in_trigger.xml +21 -0
- data/machinations_diagrams/naficadevendo.xml +12 -0
- data/machinations_diagrams/noreporting_equivalent.xml +22 -0
- data/machinations_diagrams/pull_all_example.xml +7 -0
- data/machinations_diagrams/sketch_of_memory.xml +41 -0
- data/machinations_diagrams/software_engineering_process 2.xml +130 -0
- data/machinations_diagrams/software_engineering_process v3.xml +168 -0
- data/machinations_diagrams/software_engineering_process v4.xml +192 -0
- data/machinations_diagrams/software_engineering_process.xml +65 -0
- data/machinations_diagrams/software_engineering_process_with_rework_after_test.xml +195 -0
- data/machinations_diagrams/startup_marketing.xml +35 -0
- data/machinations_diagrams/triggers_allow_multiple_stages_at_same_round.xml +19 -0
- data/machinations_diagrams/um_de_cada_vez_vs_todos_de_uma_vez.xml +20 -0
- data/rachinations.gemspec +35 -0
- data/testing/features/step_definitions/step_definitions.rb +11 -0
- data/testing/simulations/modelo1.rb +20 -0
- data/testing/simulations/modelo2.rb +49 -0
- data/testing/simulations/noreporting.rb +51 -0
- data/testing/simulations/sequencial.rb +19 -0
- data/testing/simulations/sobonito.rb +28 -0
- data/testing/simulations/sobonitowhile.rb +28 -0
- data/testing/simulations/whatIwish1.rb +20 -0
- data/testing/spec/canon/converter_spec.rb +33 -0
- data/testing/spec/canon/pool_spec.rb +68 -0
- data/testing/spec/conditions_spec.rb +10 -0
- data/testing/spec/converter_spec.rb +223 -0
- data/testing/spec/diagram_spec.rb +671 -0
- data/testing/spec/edge_spec.rb +256 -0
- data/testing/spec/hash_init_spec.rb +59 -0
- data/testing/spec/node_spec.rb +31 -0
- data/testing/spec/non_deterministic_diagram_spec.rb +112 -0
- data/testing/spec/pool_spec.rb +233 -0
- data/testing/spec/source_spec.rb +132 -0
- data/testing/spec/spec_helper.rb +34 -0
- data/testing/spec/xexeo_spec.rb +193 -0
- metadata +283 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
require_relative '../../domain/modules/common/invariant'
|
2
|
+
require_relative '../../domain/modules/common/hash_init'
|
3
|
+
|
4
|
+
class Node
|
5
|
+
|
6
|
+
include Invariant
|
7
|
+
include HashInit
|
8
|
+
|
9
|
+
attr_reader :name,:types
|
10
|
+
|
11
|
+
|
12
|
+
def attach_condition(condition)
|
13
|
+
conditions.push(condition)
|
14
|
+
end
|
15
|
+
|
16
|
+
def conditions
|
17
|
+
@conditions ||= Array.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def edges
|
21
|
+
if @edges.is_a? Array
|
22
|
+
@edges
|
23
|
+
else
|
24
|
+
@edges = Array.new
|
25
|
+
@edges
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def incoming_edges
|
30
|
+
edges.select{|e| e.to == self}
|
31
|
+
end
|
32
|
+
|
33
|
+
def outgoing_edges
|
34
|
+
edges.select{|e| e.from == self}
|
35
|
+
end
|
36
|
+
|
37
|
+
def attach_edge(edge)
|
38
|
+
edges.push(edge)
|
39
|
+
end
|
40
|
+
|
41
|
+
def attach_edge!(edge)
|
42
|
+
attach_edge(edge)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def detach_edge(edge)
|
47
|
+
if edges.include?(edge)
|
48
|
+
edges.pop(edge)
|
49
|
+
else
|
50
|
+
raise RuntimeError "This #{self.class} does not include this #{edge.class}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def detach_edge!(edge)
|
55
|
+
detach_edge(edge)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def typed?
|
60
|
+
!untyped?
|
61
|
+
end
|
62
|
+
|
63
|
+
def untyped?
|
64
|
+
types.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
def attach_trigger(trig)
|
68
|
+
triggers.push(trig+[true])
|
69
|
+
end
|
70
|
+
|
71
|
+
def triggers
|
72
|
+
@triggers ||= Array.new
|
73
|
+
end
|
74
|
+
|
75
|
+
def clear_triggers
|
76
|
+
triggers.each do |t|
|
77
|
+
t[2]=true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def fire_triggers!
|
82
|
+
triggers.each do |n|
|
83
|
+
if (n[0].is_a? Proc) && n[2]
|
84
|
+
if n[0].call
|
85
|
+
n[2]=false
|
86
|
+
n[1].trigger!
|
87
|
+
end
|
88
|
+
elsif n[0] && n[2]
|
89
|
+
n[2]=false
|
90
|
+
n[1].trigger!
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def enabled?
|
96
|
+
res=true
|
97
|
+
conditions.each do |cond|
|
98
|
+
if cond.is_a? Proc
|
99
|
+
res=res && cond.call
|
100
|
+
elsif cond === false
|
101
|
+
return false
|
102
|
+
elsif cond === true
|
103
|
+
# do nothing
|
104
|
+
end
|
105
|
+
end
|
106
|
+
res
|
107
|
+
end
|
108
|
+
|
109
|
+
def disabled?
|
110
|
+
!enabled?
|
111
|
+
end
|
112
|
+
|
113
|
+
def commit!
|
114
|
+
clear_triggers
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def pull?
|
119
|
+
@mode === :pull || @mode === :pull_any || @mode === :pull_all
|
120
|
+
end
|
121
|
+
|
122
|
+
def push?
|
123
|
+
@mode === :push || @mode === :push_any || @mode === :push_all
|
124
|
+
end
|
125
|
+
|
126
|
+
def automatic?
|
127
|
+
@activation === :automatic
|
128
|
+
end
|
129
|
+
|
130
|
+
def passive?
|
131
|
+
@activation === :passive
|
132
|
+
end
|
133
|
+
|
134
|
+
def start?
|
135
|
+
@activation === :start
|
136
|
+
end
|
137
|
+
|
138
|
+
def any?
|
139
|
+
@mode === :push_any || @mode === :pull_any
|
140
|
+
end
|
141
|
+
|
142
|
+
def all?
|
143
|
+
@mode === :push_all || @mode === :pull_all
|
144
|
+
end
|
145
|
+
|
146
|
+
# Tries to take any resource that, when yielded to expression, returns true.
|
147
|
+
# In other words, tries to take any resource which matches the expression
|
148
|
+
# block given as parameter.
|
149
|
+
#
|
150
|
+
# @raise [RuntimeError] in case no resources in this node match given
|
151
|
+
# expression block.
|
152
|
+
# @param expression [Proc] the expression
|
153
|
+
def take_resource!(&expression)
|
154
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
155
|
+
end
|
156
|
+
|
157
|
+
# Places a single resource into this Node. Each subclass may then
|
158
|
+
# decide what to do with it; examples are to store the resource and/or to
|
159
|
+
# fire triggers.
|
160
|
+
#
|
161
|
+
# @raise [RuntimeError] in case this node won't take the resource
|
162
|
+
def put_resource!(res,edge=nil)
|
163
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
require_relative '../../domain/nodes/resourceful_node'
|
2
|
+
require_relative '../../domain/nodes/node'
|
3
|
+
require_relative '../../domain/resources/token'
|
4
|
+
require_relative '../resource_bag'
|
5
|
+
require_relative '../../domain/exceptions/no_elements_matching_condition_error'
|
6
|
+
|
7
|
+
|
8
|
+
class Pool < ResourcefulNode
|
9
|
+
|
10
|
+
def initialize(hsh={})
|
11
|
+
|
12
|
+
check_options!(hsh)
|
13
|
+
params = set_defaults(hsh)
|
14
|
+
|
15
|
+
@resources = get_initial_resources(params[:initial_value])
|
16
|
+
|
17
|
+
@types = get_types(params[:initial_value], params[:types])
|
18
|
+
|
19
|
+
#reference to the underlying diagram
|
20
|
+
@diagram = params[:diagram]
|
21
|
+
|
22
|
+
#this node's identifier
|
23
|
+
@name = params[:name]
|
24
|
+
|
25
|
+
#whether this node is passive or automatic (active)
|
26
|
+
@activation = params.fetch(:activation)
|
27
|
+
|
28
|
+
#pull or push
|
29
|
+
@mode = params.fetch(:mode)
|
30
|
+
|
31
|
+
#calling parent constructor to setup other variables.
|
32
|
+
super(hsh)
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def trigger!
|
37
|
+
|
38
|
+
if enabled?
|
39
|
+
if push? && any?
|
40
|
+
|
41
|
+
push_any!
|
42
|
+
|
43
|
+
elsif pull? && any?
|
44
|
+
|
45
|
+
pull_any!
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def resource_count(type=nil, &block)
|
53
|
+
|
54
|
+
raise ArgumentError.new('Please provide either a type or a block, but not both.') if block_given? && !type.nil?
|
55
|
+
|
56
|
+
if type.nil? && !block_given?
|
57
|
+
resources.count_where { |r| r.unlocked? }
|
58
|
+
elsif type.is_a?(Class) && type <= Token
|
59
|
+
|
60
|
+
if supports? type
|
61
|
+
resources.count_where { |r|
|
62
|
+
r.unlocked? && r.is_type?(type)
|
63
|
+
}
|
64
|
+
else
|
65
|
+
raise UnsupportedTypeError.new "Unsupported type: #{type.name}"
|
66
|
+
end
|
67
|
+
elsif block_given?
|
68
|
+
|
69
|
+
# client doesn't need to know about locked vs unlocked resources
|
70
|
+
unlock_condition = Proc.new { |r| r.unlocked? }
|
71
|
+
|
72
|
+
resources.count_where { |r| unlock_condition.match?(r) && block.match?(r) }
|
73
|
+
|
74
|
+
else
|
75
|
+
raise ArgumentError.new("Wrong parameter types passed to #{__callee__}")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def instant_resource_count(type=nil)
|
80
|
+
if type.nil?
|
81
|
+
@resources.count_where { true }
|
82
|
+
else
|
83
|
+
|
84
|
+
if supports? type
|
85
|
+
@resources.count_where { |r|
|
86
|
+
r.instance_of?(type)
|
87
|
+
}
|
88
|
+
else
|
89
|
+
raise UnsupportedTypeError.new "Unsupported type: #{type.name}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def commit!
|
96
|
+
|
97
|
+
unlock_resources!
|
98
|
+
|
99
|
+
super
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def put_resource!(obj, edge=nil)
|
105
|
+
|
106
|
+
inv { obj.unlocked? }
|
107
|
+
|
108
|
+
if supports? obj.class
|
109
|
+
@resources_added[obj.class] += 1
|
110
|
+
resources.add!(obj.lock!)
|
111
|
+
fire_triggers!
|
112
|
+
else
|
113
|
+
raise UnsupportedTypeError.new
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def take_resource!(&expression)
|
118
|
+
|
119
|
+
unless block_given?
|
120
|
+
# if no conditions given, then anything goes.
|
121
|
+
expression = Proc.new{ |res| true }
|
122
|
+
end
|
123
|
+
|
124
|
+
raise RuntimeError.new unless resources.count_where(&expression) > 0
|
125
|
+
|
126
|
+
res=remove_resource! &expression
|
127
|
+
|
128
|
+
fire_triggers!
|
129
|
+
|
130
|
+
res
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_s
|
135
|
+
"Pool '#{@name}': #{@resources.to_s}"
|
136
|
+
end
|
137
|
+
|
138
|
+
# TODO this smells. where is this used? can i do without it?
|
139
|
+
def get_initial_resources(initial_value)
|
140
|
+
inv { !self.instance_variable_defined?(:@resources) }
|
141
|
+
|
142
|
+
bag = ResourceBag.new
|
143
|
+
|
144
|
+
if initial_value.is_a?(Fixnum)
|
145
|
+
initial_value.times { bag.add!(Token.new) }
|
146
|
+
elsif initial_value.is_a?(Hash)
|
147
|
+
initial_value.each do |type, quantity|
|
148
|
+
quantity.times { bag.add!(type.new) }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
return bag
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
# TODO document this or else refactor it out
|
157
|
+
def get_types(initial_value, given_types)
|
158
|
+
inv { !self.instance_variable_defined?(:@types) }
|
159
|
+
|
160
|
+
if initial_value.is_a?(Fixnum) && given_types.empty?
|
161
|
+
# nothing to do
|
162
|
+
elsif initial_value == 0 && !given_types.empty?
|
163
|
+
# nothing to do
|
164
|
+
elsif initial_value.is_a?(Hash)
|
165
|
+
initial_value.each_key { |type| given_types.push(type) }
|
166
|
+
else
|
167
|
+
raise ArgumentError.new
|
168
|
+
end
|
169
|
+
|
170
|
+
given_types.uniq
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
def types
|
176
|
+
@types
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
attr_reader :resources
|
182
|
+
|
183
|
+
def remove_resource!(&expression)
|
184
|
+
|
185
|
+
# client doesn't need to know about locked vs unlocked resources
|
186
|
+
unlocked_expression = Proc.new { |r| r.unlocked? }
|
187
|
+
|
188
|
+
res=resources.get_where { |r| unlocked_expression.call(r) && expression.call(r) }
|
189
|
+
|
190
|
+
@resources_removed[res.class] += 1
|
191
|
+
|
192
|
+
res
|
193
|
+
end
|
194
|
+
|
195
|
+
def add_resource!(res)
|
196
|
+
|
197
|
+
resources.add!(res) and @resources_added[res.type]+=1
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
def options
|
202
|
+
[:conditions, :name, :activation, :mode, :types, :initial_value, :diagram]
|
203
|
+
end
|
204
|
+
|
205
|
+
def defaults
|
206
|
+
{
|
207
|
+
activation: :passive,
|
208
|
+
mode: :pull_any,
|
209
|
+
types: [],
|
210
|
+
initial_value: 0
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
def aliases
|
215
|
+
{:initial_values => :initial_value}
|
216
|
+
end
|
217
|
+
|
218
|
+
def push_any!
|
219
|
+
|
220
|
+
outgoing_edges.shuffle.each do |edge|
|
221
|
+
begin
|
222
|
+
blk = edge.push_expression
|
223
|
+
rescue => ex
|
224
|
+
# Could not get a block for one Edge, but this is push_any so I'll go ahead.
|
225
|
+
next #other edges might still be able to serve me.
|
226
|
+
end
|
227
|
+
|
228
|
+
edge.label.times do
|
229
|
+
begin
|
230
|
+
res = remove_resource!(&blk)
|
231
|
+
rescue => ex
|
232
|
+
# Failed to remove this resource. Let's try another Edge, perhaps?
|
233
|
+
break
|
234
|
+
end
|
235
|
+
|
236
|
+
edge.push!(res)
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def pull_any!
|
244
|
+
incoming_edges.shuffle.each do |edge|
|
245
|
+
begin
|
246
|
+
blk = edge.pull_expression
|
247
|
+
rescue RuntimeError => ex
|
248
|
+
# Could not get a block for one Edge, but this is pull_any so I'll go ahead.
|
249
|
+
next #other edges might still be able to serve me.
|
250
|
+
end
|
251
|
+
|
252
|
+
edge.label.times do
|
253
|
+
begin
|
254
|
+
res = edge.pull!(&blk)
|
255
|
+
rescue RuntimeError => ex
|
256
|
+
# Let's try another Edge, perhaps?
|
257
|
+
break
|
258
|
+
end
|
259
|
+
|
260
|
+
add_resource!(res.lock!)
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'set'
|
2
|
+
require_relative '../../domain/resources/token'
|
3
|
+
require_relative '../../domain/nodes/node'
|
4
|
+
|
5
|
+
class ResourcefulNode < Node
|
6
|
+
|
7
|
+
include Invariant
|
8
|
+
|
9
|
+
def initialize(hsh=nil)
|
10
|
+
@resources_added=Hash.new(0)
|
11
|
+
@resources_removed=Hash.new(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize_copy(orig)
|
15
|
+
super
|
16
|
+
|
17
|
+
#need to clone the resource bag as well...
|
18
|
+
@resources = @resources.clone()
|
19
|
+
|
20
|
+
#don't need this. takes too much space
|
21
|
+
@diagram = nil
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# pools are about resources
|
26
|
+
|
27
|
+
def supports?(klass)
|
28
|
+
if klass.eql?(Token)
|
29
|
+
untyped?
|
30
|
+
else
|
31
|
+
#untyped nodes support everything.
|
32
|
+
if untyped?
|
33
|
+
true
|
34
|
+
else
|
35
|
+
typed? && types.include?(klass)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :support?, :supports?
|
41
|
+
|
42
|
+
|
43
|
+
def resources_added(klass=nil)
|
44
|
+
if klass.nil?
|
45
|
+
@resources_added.values.reduce(0) { |acc, elem| acc += elem }
|
46
|
+
else
|
47
|
+
@resources_added[klass]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def resources_removed(klass=nil)
|
52
|
+
if klass.nil?
|
53
|
+
@resources_removed.values.reduce(0) { |acc, elem| acc += elem }
|
54
|
+
else
|
55
|
+
@resources_removed[klass]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def commit!
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def unlock_resources!
|
64
|
+
@resources.each_where { |r|
|
65
|
+
if r.locked?
|
66
|
+
r.unlock!
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def trigger!
|
72
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def resource_count(type=nil)
|
76
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def push_any
|
80
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def push_all
|
84
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def pull_any
|
88
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def pull_all
|
92
|
+
raise NotImplementedError, "Please update class #{self.class} to respond to: :#{__callee__}"
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|