vmsim 0.2.3

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 (52) hide show
  1. data/.autotest +27 -0
  2. data/README.txt +1 -0
  3. data/Rakefile +40 -0
  4. data/VERSION +1 -0
  5. data/bin/vmdeploy +23 -0
  6. data/bin/vmsim +37 -0
  7. data/doc/actuators_and_sensors.txt +32 -0
  8. data/doc/handout.odt +0 -0
  9. data/doc/machine.jpg +0 -0
  10. data/doc/todo.txt +25 -0
  11. data/lib/adapter/actuator_collection.rb +61 -0
  12. data/lib/adapter/sensor_collection.rb +57 -0
  13. data/lib/archive_builder.rb +64 -0
  14. data/lib/control/main.rb +21 -0
  15. data/lib/control.rb +3 -0
  16. data/lib/deploy/deployer.rb +96 -0
  17. data/lib/deploy.rb +1 -0
  18. data/lib/devices/devices.rb +73 -0
  19. data/lib/devices.rb +1 -0
  20. data/lib/gui/SimulatorGui.gtk +289 -0
  21. data/lib/gui/simulator_gtk.rb +57 -0
  22. data/lib/gui/simulator_gui.rb +64 -0
  23. data/lib/gui.rb +2 -0
  24. data/lib/hardware/bin.rb +28 -0
  25. data/lib/hardware/button.rb +18 -0
  26. data/lib/hardware/can.rb +9 -0
  27. data/lib/hardware/cash_register.rb +79 -0
  28. data/lib/hardware/component.rb +56 -0
  29. data/lib/hardware/display.rb +29 -0
  30. data/lib/hardware/drawer.rb +45 -0
  31. data/lib/hardware/enum.rb +20 -0
  32. data/lib/hardware/simulator.rb +98 -0
  33. data/lib/hardware.rb +10 -0
  34. data/lib/hardware_adapter.rb +11 -0
  35. data/lib/vmlog.rb +5 -0
  36. data/test/adapter/actuator_collection_test.rb +106 -0
  37. data/test/adapter/sensor_collection_test.rb +51 -0
  38. data/test/deploy/deployer_test.rb +114 -0
  39. data/test/deploy/was_run.sh +5 -0
  40. data/test/devices/devices_test.rb +78 -0
  41. data/test/hardware/bin_test.rb +57 -0
  42. data/test/hardware/button_test.rb +23 -0
  43. data/test/hardware/can_test.rb +11 -0
  44. data/test/hardware/cash_register_test.rb +157 -0
  45. data/test/hardware/component_test.rb +37 -0
  46. data/test/hardware/display_test.rb +94 -0
  47. data/test/hardware/drawer_test.rb +100 -0
  48. data/test/hardware/enum_test.rb +33 -0
  49. data/test/hardware/simulator_test.rb +189 -0
  50. data/test/test_helper.rb +5 -0
  51. data/vmsim.gemspec +89 -0
  52. metadata +131 -0
@@ -0,0 +1,289 @@
1
+ <?xml version="1.0"?>
2
+ <interface>
3
+ <!-- interface-requires gtk+ 2.14 -->
4
+ <!-- interface-naming-policy project-wide -->
5
+ <object class="GtkWindow" id="window1">
6
+ <property name="title" translatable="yes">Vending Machine</property>
7
+ <property name="resizable">False</property>
8
+ <child>
9
+ <object class="GtkVBox" id="vbox1">
10
+ <property name="visible">True</property>
11
+ <property name="spacing">13</property>
12
+ <child>
13
+ <object class="GtkLabel" id="label1">
14
+ <property name="visible">True</property>
15
+ <property name="label" translatable="yes">Vending Machine</property>
16
+ <property name="use_markup">True</property>
17
+ </object>
18
+ <packing>
19
+ <property name="position">0</property>
20
+ </packing>
21
+ </child>
22
+ <child>
23
+ <object class="GtkVBox" id="vbox2">
24
+ <property name="visible">True</property>
25
+ <child>
26
+ <object class="GtkEntry" id="display_line_1">
27
+ <property name="visible">True</property>
28
+ <property name="can_focus">True</property>
29
+ <property name="editable">False</property>
30
+ <property name="invisible_char">&#x25CF;</property>
31
+ </object>
32
+ <packing>
33
+ <property name="expand">False</property>
34
+ <property name="position">0</property>
35
+ </packing>
36
+ </child>
37
+ <child>
38
+ <object class="GtkEntry" id="display_line_2">
39
+ <property name="visible">True</property>
40
+ <property name="can_focus">True</property>
41
+ <property name="editable">False</property>
42
+ <property name="invisible_char">&#x25CF;</property>
43
+ </object>
44
+ <packing>
45
+ <property name="expand">False</property>
46
+ <property name="position">1</property>
47
+ </packing>
48
+ </child>
49
+ </object>
50
+ <packing>
51
+ <property name="expand">False</property>
52
+ <property name="position">1</property>
53
+ </packing>
54
+ </child>
55
+ <child>
56
+ <object class="GtkHBox" id="hbox2">
57
+ <property name="visible">True</property>
58
+ <child>
59
+ <object class="GtkVButtonBox" id="vbuttonbox1">
60
+ <property name="visible">True</property>
61
+ <child>
62
+ <object class="GtkButton" id="cola_button">
63
+ <property name="label" translatable="yes">
64
+ Cola
65
+ </property>
66
+ <property name="visible">True</property>
67
+ <property name="can_focus">True</property>
68
+ <property name="receives_default">True</property>
69
+ <property name="focus_on_click">False</property>
70
+ <signal handler="on_cola_button_clicked" name="clicked"/>
71
+ </object>
72
+ <packing>
73
+ <property name="expand">False</property>
74
+ <property name="fill">False</property>
75
+ <property name="position">0</property>
76
+ </packing>
77
+ </child>
78
+ <child>
79
+ <object class="GtkButton" id="fanta_button">
80
+ <property name="label" translatable="yes">Fanta</property>
81
+ <property name="visible">True</property>
82
+ <property name="can_focus">True</property>
83
+ <property name="receives_default">True</property>
84
+ <property name="focus_on_click">False</property>
85
+ <signal handler="on_fanta_button_clicked" name="clicked"/>
86
+ </object>
87
+ <packing>
88
+ <property name="expand">False</property>
89
+ <property name="fill">False</property>
90
+ <property name="position">1</property>
91
+ </packing>
92
+ </child>
93
+ <child>
94
+ <object class="GtkButton" id="sprite_button">
95
+ <property name="label" translatable="yes">Sprite</property>
96
+ <property name="visible">True</property>
97
+ <property name="can_focus">True</property>
98
+ <property name="receives_default">True</property>
99
+ <property name="focus_on_click">False</property>
100
+ <signal handler="on_sprite_button_clicked" name="clicked"/>
101
+ </object>
102
+ <packing>
103
+ <property name="expand">False</property>
104
+ <property name="fill">False</property>
105
+ <property name="position">2</property>
106
+ </packing>
107
+ </child>
108
+ <child>
109
+ <object class="GtkButton" id="sisi_button">
110
+ <property name="label" translatable="yes">Sisi</property>
111
+ <property name="visible">True</property>
112
+ <property name="can_focus">True</property>
113
+ <property name="receives_default">True</property>
114
+ <property name="focus_on_click">False</property>
115
+ <signal handler="on_sisi_button_clicked" name="clicked"/>
116
+ </object>
117
+ <packing>
118
+ <property name="expand">False</property>
119
+ <property name="fill">False</property>
120
+ <property name="position">3</property>
121
+ </packing>
122
+ </child>
123
+ </object>
124
+ <packing>
125
+ <property name="expand">False</property>
126
+ <property name="padding">17</property>
127
+ <property name="position">0</property>
128
+ </packing>
129
+ </child>
130
+ <child>
131
+ <placeholder/>
132
+ </child>
133
+ <child>
134
+ <object class="GtkVButtonBox" id="vbuttonbox2">
135
+ <property name="visible">True</property>
136
+ <property name="layout_style">start</property>
137
+ <child>
138
+ <object class="GtkButton" id="two_euro_button">
139
+ <property name="label" translatable="yes">2 eur</property>
140
+ <property name="visible">True</property>
141
+ <property name="can_focus">True</property>
142
+ <property name="receives_default">True</property>
143
+ <signal handler="on_two_euro_button_clicked" name="clicked"/>
144
+ </object>
145
+ <packing>
146
+ <property name="expand">False</property>
147
+ <property name="fill">False</property>
148
+ <property name="position">0</property>
149
+ </packing>
150
+ </child>
151
+ <child>
152
+ <object class="GtkButton" id="one_euro_button">
153
+ <property name="label" translatable="yes">1 eur</property>
154
+ <property name="visible">True</property>
155
+ <property name="can_focus">True</property>
156
+ <property name="receives_default">True</property>
157
+ <signal handler="on_one_euro_button_clicked" name="clicked"/>
158
+ </object>
159
+ <packing>
160
+ <property name="expand">False</property>
161
+ <property name="fill">False</property>
162
+ <property name="position">1</property>
163
+ </packing>
164
+ </child>
165
+ <child>
166
+ <object class="GtkButton" id="fifty_cents_button">
167
+ <property name="label" translatable="yes">50 ct</property>
168
+ <property name="visible">True</property>
169
+ <property name="can_focus">True</property>
170
+ <property name="receives_default">True</property>
171
+ <signal handler="on_fifty_cents_button_clicked" name="clicked"/>
172
+ </object>
173
+ <packing>
174
+ <property name="expand">False</property>
175
+ <property name="fill">False</property>
176
+ <property name="position">2</property>
177
+ </packing>
178
+ </child>
179
+ </object>
180
+ <packing>
181
+ <property name="expand">False</property>
182
+ <property name="padding">14</property>
183
+ <property name="position">2</property>
184
+ </packing>
185
+ </child>
186
+ </object>
187
+ <packing>
188
+ <property name="expand">False</property>
189
+ <property name="position">2</property>
190
+ </packing>
191
+ </child>
192
+ <child>
193
+ <object class="GtkHBox" id="hbox4">
194
+ <property name="visible">True</property>
195
+ <child>
196
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
197
+ <property name="visible">True</property>
198
+ <property name="can_focus">True</property>
199
+ <property name="hscrollbar_policy">automatic</property>
200
+ <property name="vscrollbar_policy">automatic</property>
201
+ <child>
202
+ <object class="GtkTextView" id="bin_box">
203
+ <property name="visible">True</property>
204
+ <property name="can_focus">True</property>
205
+ <property name="editable">False</property>
206
+ <property name="cursor_visible">False</property>
207
+ </object>
208
+ </child>
209
+ </object>
210
+ <packing>
211
+ <property name="position">0</property>
212
+ </packing>
213
+ </child>
214
+ <child>
215
+ <object class="GtkVButtonBox" id="vbuttonbox3">
216
+ <property name="visible">True</property>
217
+ <property name="layout_style">end</property>
218
+ <child>
219
+ <object class="GtkButton" id="fetch_button">
220
+ <property name="label" translatable="yes">fetch</property>
221
+ <property name="visible">True</property>
222
+ <property name="can_focus">True</property>
223
+ <property name="receives_default">True</property>
224
+ <signal handler="on_fetch_button_clicked" name="clicked"/>
225
+ </object>
226
+ <packing>
227
+ <property name="expand">False</property>
228
+ <property name="fill">False</property>
229
+ <property name="position">0</property>
230
+ </packing>
231
+ </child>
232
+ </object>
233
+ <packing>
234
+ <property name="expand">False</property>
235
+ <property name="pack_type">end</property>
236
+ <property name="position">3</property>
237
+ </packing>
238
+ </child>
239
+ </object>
240
+ <packing>
241
+ <property name="position">3</property>
242
+ </packing>
243
+ </child>
244
+ <child>
245
+ <object class="GtkHBox" id="hbox3">
246
+ <property name="visible">True</property>
247
+ <child>
248
+ <placeholder/>
249
+ </child>
250
+ <child>
251
+ <object class="GtkHButtonBox" id="hbuttonbox2">
252
+ <property name="visible">True</property>
253
+ <child>
254
+ <placeholder/>
255
+ </child>
256
+ <child>
257
+ <placeholder/>
258
+ </child>
259
+ <child>
260
+ <object class="GtkButton" id="exit_button">
261
+ <property name="label" translatable="yes">exit</property>
262
+ <property name="visible">True</property>
263
+ <property name="can_focus">True</property>
264
+ <property name="receives_default">True</property>
265
+ <signal handler="on_exit_button_clicked" name="clicked"/>
266
+ </object>
267
+ <packing>
268
+ <property name="expand">False</property>
269
+ <property name="fill">False</property>
270
+ <property name="position">2</property>
271
+ </packing>
272
+ </child>
273
+ </object>
274
+ <packing>
275
+ <property name="expand">False</property>
276
+ <property name="fill">False</property>
277
+ <property name="position">1</property>
278
+ </packing>
279
+ </child>
280
+ </object>
281
+ <packing>
282
+ <property name="expand">False</property>
283
+ <property name="position">4</property>
284
+ </packing>
285
+ </child>
286
+ </object>
287
+ </child>
288
+ </object>
289
+ </interface>
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file is gererated by ruby-glade-create-template 1.1.4.
4
+ #
5
+ require 'rubygems'
6
+ require 'gtk2'
7
+
8
+ class SimulatorguiGtk
9
+ include GetText
10
+
11
+ attr :glade
12
+
13
+ def initialize(path_or_data, domain)
14
+ bindtextdomain(domain, nil, nil, "UTF-8")
15
+ @glade = Gtk::Builder.new()
16
+ @glade.add_from_file(path_or_data)
17
+ @glade.connect_signals {|handler| method(handler)}
18
+
19
+ end
20
+
21
+ def on_fetch_button_clicked(widget)
22
+ puts "on_fetch_button_clicked() is not implemented yet."
23
+ end
24
+ def on_two_euro_button_clicked(widget)
25
+ puts "on_two_euro_button_clicked() is not implemented yet."
26
+ end
27
+ def on_fanta_button_clicked(widget)
28
+ puts "on_fanta_button_clicked() is not implemented yet."
29
+ end
30
+ def on_sisi_button_clicked(widget)
31
+ puts "on_sisi_button_clicked() is not implemented yet."
32
+ end
33
+ def on_cola_button_clicked(widget)
34
+ puts "on_cola_button_clicked() is not implemented yet."
35
+ end
36
+ def on_sprite_button_clicked(widget)
37
+ puts "on_sprite_button_clicked() is not implemented yet."
38
+ end
39
+ def on_fifty_cents_button_clicked(widget)
40
+ puts "on_fifty_cents_button_clicked() is not implemented yet."
41
+ end
42
+ def on_exit_button_clicked(widget)
43
+ puts "on_exit_button_clicked() is not implemented yet."
44
+ end
45
+ def on_one_euro_button_clicked(widget)
46
+ puts "on_one_euro_button_clicked() is not implemented yet."
47
+ end
48
+ end
49
+
50
+ # Main program
51
+ if __FILE__ == $0
52
+ # Set values as your own application.
53
+ PROG_PATH = "SimulatorGui.glade"
54
+ PROG_NAME = "YOUR_APPLICATION_NAME"
55
+ SimulatorguiGlade.new(PROG_PATH, nil, PROG_NAME)
56
+ Gtk.main
57
+ end
@@ -0,0 +1,64 @@
1
+
2
+ PROG_PATH = File.join(File.dirname(__FILE__), "SimulatorGui.gtk")
3
+
4
+ PROG_NAME = "Vending Machine"
5
+ module Gui
6
+ class SimulatorGui < SimulatorguiGtk
7
+ def initialize(simulator)
8
+ super(PROG_PATH, PROG_NAME)
9
+ @simulator = simulator
10
+
11
+ simulator.monitor_changes(:bin) do
12
+ glade['bin_box'].buffer.text = @simulator.component(:bin).contents.join("\n")
13
+ end
14
+ simulator.monitor_changes(:display) do
15
+ glade['display_line_1'].buffer.text = @simulator.component(:display).line_one
16
+ glade['display_line_2'].buffer.text = @simulator.component(:display).line_two
17
+ end
18
+ end
19
+
20
+ def on_fetch_button_clicked(widget)
21
+ @simulator.component(:bin).fetch_all
22
+ end
23
+
24
+ def on_cola_button_clicked(widget)
25
+ @simulator.component(:button_0).press
26
+ end
27
+
28
+ def on_fanta_button_clicked(widget)
29
+ @simulator.component(:button_1).press
30
+ end
31
+
32
+ def on_sprite_button_clicked(widget)
33
+ @simulator.component(:button_2).press
34
+ end
35
+
36
+ def on_sisi_button_clicked(widget)
37
+ @simulator.component(:button_3).press
38
+ end
39
+
40
+ def on_two_euro_button_clicked(widget)
41
+ @simulator.component(:cash_register).insert_coin(Hardware::Coin.two_euro)
42
+ end
43
+
44
+ def on_one_euro_button_clicked(widget)
45
+ @simulator.component(:cash_register).insert_coin(Hardware::Coin.one_euro)
46
+ end
47
+
48
+ def on_fifty_cents_button_clicked(widget)
49
+ @simulator.component(:cash_register).insert_coin(Hardware::Coin.fifty_cents)
50
+ end
51
+
52
+ def on_exit_button_clicked(widget)
53
+ @stopped = true
54
+ end
55
+
56
+ def stopped?
57
+ @stopped
58
+ end
59
+
60
+ def show
61
+ glade['window1'].show_all
62
+ end
63
+ end
64
+ end
data/lib/gui.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'gui/simulator_gtk'
2
+ require 'gui/simulator_gui'
@@ -0,0 +1,28 @@
1
+ module Hardware
2
+
3
+ class Bin < Component
4
+ attr_reader :contents
5
+ def initialize(sensor_collection)
6
+ super(sensor_collection, nil)
7
+ @contents = []
8
+ end
9
+
10
+ def receive(object)
11
+ contents << object
12
+ changed
13
+ fire(:bin_entry)
14
+ end
15
+
16
+ def fetch_all
17
+ contents.clear
18
+ changed
19
+ fire(:bin_fetch_all)
20
+ end
21
+
22
+ def configure
23
+ create_sensor_for(:bin_entry)
24
+ create_sensor_for(:bin_fetch_all)
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Hardware
2
+
3
+ class Button < SequencedComponent
4
+
5
+ def initialize(sensor_collection, sequence_number)
6
+ super(sensor_collection, nil, sequence_number)
7
+ end
8
+
9
+ def press
10
+ fire(:button_press)
11
+ end
12
+
13
+ def configure
14
+ create_sensor_for(:button_press)
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module Hardware
2
+ class Can < Enum
3
+ values :cola, :fanta, :sprite, :sisi
4
+ def to_s
5
+ "can of #{@type}"
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,79 @@
1
+ module Hardware
2
+ class Coin < Enum
3
+ values :two_euro, :one_euro, :fifty_cents
4
+ def to_s
5
+ "#{@type} coin"
6
+ end
7
+ end
8
+
9
+ class CashRegister < Component
10
+ def initialize(bin, sensor_collection, actuator_collection)
11
+ super(sensor_collection, actuator_collection)
12
+ @bin = bin
13
+ @stocks = {}
14
+ @stocks.default = 0
15
+ end
16
+
17
+ def drop_coin(coin, delay = 1)
18
+ if @stocks[coin] > 0
19
+ sleep(delay)
20
+ @bin.receive(coin)
21
+ @stocks[coin] -= 1
22
+ end
23
+ end
24
+
25
+ def insert_coin(coin_type)
26
+ @stocks[coin_type] += 1
27
+ @sensor_collection.fire(insert_event_for(coin_type))
28
+ end
29
+
30
+ def insert_event_for(coin_type)
31
+ {Coin.two_euro => :cash_insert_200,
32
+ Coin.one_euro => :cash_insert_100,
33
+ Coin.fifty_cents => :cash_insert_50 }[coin_type]
34
+ end
35
+ private :insert_event_for
36
+
37
+ def fill(coin_type, amount, delay = 1)
38
+ amount.times do
39
+ sleep(delay)
40
+ @stocks[coin_type] += 1
41
+ @sensor_collection.fire(fill_event_for(coin_type))
42
+ end
43
+ end
44
+
45
+ def fill_event_for(coin_type)
46
+ {Coin.two_euro => :cash_fill_200,
47
+ Coin.one_euro => :cash_fill_100,
48
+ Coin.fifty_cents => :cash_fill_50 }[coin_type]
49
+ end
50
+ private :insert_event_for
51
+
52
+
53
+ def configure
54
+ create_sensor_for(:cash_insert_200)
55
+ create_sensor_for(:cash_insert_100)
56
+ create_sensor_for(:cash_insert_50)
57
+ create_sensor_for(:cash_fill_200)
58
+ create_sensor_for(:cash_fill_100)
59
+ create_sensor_for(:cash_fill_50)
60
+ create_actuator_for(:cash_drop_200) do
61
+ drop_coin(Coin.two_euro)
62
+ end
63
+ create_actuator_for(:cash_drop_100) do
64
+ drop_coin(Coin.one_euro)
65
+ end
66
+ create_actuator_for(:cash_drop_50) do
67
+ drop_coin(Coin.fifty_cents)
68
+ end
69
+ end
70
+
71
+ def empty?
72
+ @stocks.empty?
73
+ end
74
+
75
+ def reset
76
+ @stocks.clear
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,56 @@
1
+ module Hardware
2
+ class Component
3
+ def initialize(sensor_collection, actuator_collection)
4
+ @sensor_collection = sensor_collection
5
+ @actuator_collection = actuator_collection
6
+ end
7
+
8
+
9
+ def monitor_changes(&block)
10
+ @changed_block = block
11
+ end
12
+
13
+ def reset
14
+ # do noting on reset by default
15
+ end
16
+
17
+ protected
18
+
19
+ def changed
20
+ @changed_block.call if @changed_block
21
+ end
22
+
23
+ def fire(event)
24
+ @sensor_collection.fire(event)
25
+ end
26
+
27
+ def create_sensor_for(event)
28
+ @sensor_collection.create_sensor_for(event)
29
+ end
30
+
31
+ def create_actuator_for(event, &block)
32
+ @actuator_collection.create_actuator_for(event, &block)
33
+ end
34
+
35
+ end
36
+
37
+ class SequencedComponent < Component
38
+ def initialize(sensor_collection, actuator_collection, sequence_number)
39
+ super(sensor_collection, actuator_collection)
40
+ @sequence_number = sequence_number
41
+ end
42
+
43
+ protected
44
+ def fire(event)
45
+ super("#{event}_#{@sequence_number}".to_sym)
46
+ end
47
+
48
+ def create_sensor_for(event)
49
+ super("#{event}_#{@sequence_number}".to_sym)
50
+ end
51
+
52
+ def create_actuator_for(event, &block)
53
+ super("#{event}_#{@sequence_number}".to_sym, &block)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,29 @@
1
+ module Hardware
2
+ class Display < Component
3
+
4
+ def initialize(actuator_collection)
5
+ super(nil, actuator_collection)
6
+ @lines = ['','']
7
+ end
8
+
9
+ def line_one
10
+ @lines[0]
11
+ end
12
+
13
+ def line_two
14
+ @lines[1]
15
+ end
16
+
17
+ def show(line, message)
18
+ return unless line.is_a?(Fixnum) && line >= 0
19
+ @lines[line] = message[0,16]
20
+ changed
21
+ end
22
+
23
+ def configure
24
+ create_actuator_for(:display_show) do |line, message|
25
+ show(line, message)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ module Hardware
2
+ class Drawer < SequencedComponent
3
+ attr_reader :stock
4
+
5
+ def initialize(bin,
6
+ sensor_collection = Adapter::SensorCollection.null,
7
+ actuator_collection = Adapter::ActuatorCollection.null,
8
+ sequence_number = 0)
9
+ super(sensor_collection, actuator_collection, sequence_number)
10
+ @bin = bin
11
+ @stock = []
12
+ end
13
+
14
+ def fill(can_type, stock, time_it_takes_per_can = 1)
15
+ stock.times do
16
+ @stock << can_type
17
+ fire(:drawer_fill_can)
18
+ end
19
+ self
20
+ end
21
+
22
+ def drop(time_it_takes = 3)
23
+ return if @stock.empty?
24
+ fire(:drawer_drop_can)
25
+ sleep(time_it_takes)
26
+ @bin.receive(@stock.shift)
27
+ end
28
+
29
+ def configure
30
+ create_sensor_for(:drawer_drop_can)
31
+ create_sensor_for(:drawer_fill_can)
32
+ create_actuator_for(:drawer_drop_can) do
33
+ self.drop
34
+ end
35
+ end
36
+
37
+ def empty?
38
+ @stock.empty?
39
+ end
40
+
41
+ def reset
42
+ @stock.clear
43
+ end
44
+ end
45
+ end