vmsim 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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