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.
- data/.autotest +27 -0
- data/README.txt +1 -0
- data/Rakefile +40 -0
- data/VERSION +1 -0
- data/bin/vmdeploy +23 -0
- data/bin/vmsim +37 -0
- data/doc/actuators_and_sensors.txt +32 -0
- data/doc/handout.odt +0 -0
- data/doc/machine.jpg +0 -0
- data/doc/todo.txt +25 -0
- data/lib/adapter/actuator_collection.rb +61 -0
- data/lib/adapter/sensor_collection.rb +57 -0
- data/lib/archive_builder.rb +64 -0
- data/lib/control/main.rb +21 -0
- data/lib/control.rb +3 -0
- data/lib/deploy/deployer.rb +96 -0
- data/lib/deploy.rb +1 -0
- data/lib/devices/devices.rb +73 -0
- data/lib/devices.rb +1 -0
- data/lib/gui/SimulatorGui.gtk +289 -0
- data/lib/gui/simulator_gtk.rb +57 -0
- data/lib/gui/simulator_gui.rb +64 -0
- data/lib/gui.rb +2 -0
- data/lib/hardware/bin.rb +28 -0
- data/lib/hardware/button.rb +18 -0
- data/lib/hardware/can.rb +9 -0
- data/lib/hardware/cash_register.rb +79 -0
- data/lib/hardware/component.rb +56 -0
- data/lib/hardware/display.rb +29 -0
- data/lib/hardware/drawer.rb +45 -0
- data/lib/hardware/enum.rb +20 -0
- data/lib/hardware/simulator.rb +98 -0
- data/lib/hardware.rb +10 -0
- data/lib/hardware_adapter.rb +11 -0
- data/lib/vmlog.rb +5 -0
- data/test/adapter/actuator_collection_test.rb +106 -0
- data/test/adapter/sensor_collection_test.rb +51 -0
- data/test/deploy/deployer_test.rb +114 -0
- data/test/deploy/was_run.sh +5 -0
- data/test/devices/devices_test.rb +78 -0
- data/test/hardware/bin_test.rb +57 -0
- data/test/hardware/button_test.rb +23 -0
- data/test/hardware/can_test.rb +11 -0
- data/test/hardware/cash_register_test.rb +157 -0
- data/test/hardware/component_test.rb +37 -0
- data/test/hardware/display_test.rb +94 -0
- data/test/hardware/drawer_test.rb +100 -0
- data/test/hardware/enum_test.rb +33 -0
- data/test/hardware/simulator_test.rb +189 -0
- data/test/test_helper.rb +5 -0
- data/vmsim.gemspec +89 -0
- 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">●</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">●</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
data/lib/hardware/bin.rb
ADDED
@@ -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
|
data/lib/hardware/can.rb
ADDED
@@ -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
|