rachinations 0.0.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 +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
|
+
|