win32-autogui 0.2.0

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 (72) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +10 -0
  3. data/.yardopts +6 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +60 -0
  6. data/HISTORY.markdown +11 -0
  7. data/LICENSE +20 -0
  8. data/README.markdown +265 -0
  9. data/Rakefile +55 -0
  10. data/TODO.markdown +9 -0
  11. data/VERSION +1 -0
  12. data/config/cucumber.yml +7 -0
  13. data/examples/quicknote/.gitignore +8 -0
  14. data/examples/quicknote/FormAboutU.dfm +44 -0
  15. data/examples/quicknote/FormAboutU.pas +36 -0
  16. data/examples/quicknote/FormMainU.dfm +110 -0
  17. data/examples/quicknote/FormMainU.pas +268 -0
  18. data/examples/quicknote/FormSplashU.dfm +32 -0
  19. data/examples/quicknote/FormSplashU.pas +52 -0
  20. data/examples/quicknote/LICENSE +20 -0
  21. data/examples/quicknote/README.markdown +28 -0
  22. data/examples/quicknote/Rakefile +12 -0
  23. data/examples/quicknote/TODO.markdown +15 -0
  24. data/examples/quicknote/dcu/.gitignore +1 -0
  25. data/examples/quicknote/exe/.gitignore +0 -0
  26. data/examples/quicknote/exe/quicknote.exe +0 -0
  27. data/examples/quicknote/lib/quicknote.rb +140 -0
  28. data/examples/quicknote/quicknote.cfg +37 -0
  29. data/examples/quicknote/quicknote.dof +158 -0
  30. data/examples/quicknote/quicknote.dpr +16 -0
  31. data/examples/quicknote/quicknote.res +0 -0
  32. data/examples/quicknote/spec/quicknote/form_about_spec.rb +50 -0
  33. data/examples/quicknote/spec/quicknote/form_main_spec.rb +274 -0
  34. data/examples/quicknote/spec/quicknote/form_splash_spec.rb +44 -0
  35. data/examples/quicknote/spec/spec.opts +2 -0
  36. data/examples/quicknote/spec/spec_helper.rb +34 -0
  37. data/examples/quicknote/spec/watchr.rb +143 -0
  38. data/examples/skeleton/.gitignore +8 -0
  39. data/examples/skeleton/LICENSE +20 -0
  40. data/examples/skeleton/README.markdown +62 -0
  41. data/examples/skeleton/Rakefile +21 -0
  42. data/examples/skeleton/TODO.markdown +9 -0
  43. data/examples/skeleton/config/cucumber.yml +7 -0
  44. data/examples/skeleton/dcu/.gitignore +1 -0
  45. data/examples/skeleton/exe/.gitignore +1 -0
  46. data/examples/skeleton/features/basic.feature +6 -0
  47. data/examples/skeleton/features/step_definitions/.gitignore +0 -0
  48. data/examples/skeleton/features/step_definitions/application_steps.rb +43 -0
  49. data/examples/skeleton/features/support/env.rb +5 -0
  50. data/examples/skeleton/lib/myapp.rb +73 -0
  51. data/examples/skeleton/spec/myapp/form_about_spec.rb +50 -0
  52. data/examples/skeleton/spec/myapp/form_main_spec.rb +60 -0
  53. data/examples/skeleton/spec/spec.opts +2 -0
  54. data/examples/skeleton/spec/spec_helper.rb +29 -0
  55. data/examples/skeleton/spec/watchr.rb +143 -0
  56. data/features/automating_an_application.feature +11 -0
  57. data/features/step_definitions/.gitignore +0 -0
  58. data/features/step_definitions/calculator_steps.rb +37 -0
  59. data/features/support/env.rb +4 -0
  60. data/lib/win32/autogui.rb +27 -0
  61. data/lib/win32/autogui/application.rb +249 -0
  62. data/lib/win32/autogui/input.rb +238 -0
  63. data/lib/win32/autogui/window.rb +191 -0
  64. data/lib/win32/autogui/windows/window.rb +22 -0
  65. data/spec/applications/calculator.rb +34 -0
  66. data/spec/auto_gui/application_spec.rb +132 -0
  67. data/spec/basic_gem/basic_gem_spec.rb +13 -0
  68. data/spec/spec.opts +2 -0
  69. data/spec/spec_helper.rb +31 -0
  70. data/spec/watchr.rb +144 -0
  71. data/win32-autogui.gemspec +43 -0
  72. metadata +329 -0
@@ -0,0 +1,16 @@
1
+ program quicknote;
2
+
3
+ uses
4
+ Forms,
5
+ FormMainU in 'FormMainU.pas' {FormMain},
6
+ FormAboutU in 'FormAboutU.pas' {FormAbout},
7
+ FormSplashU in 'FormSplashU.pas' {FormSplash};
8
+
9
+ {$R *.res}
10
+
11
+ begin
12
+ Application.Initialize;
13
+ Application.Title := 'QuickNote';
14
+ Application.CreateForm(TFormMain, FormMain);
15
+ Application.Run;
16
+ end.
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Autogui::Input
4
+
5
+ describe "FormAbout" do
6
+
7
+ before(:all) do
8
+ @application = Quicknote.new
9
+ end
10
+
11
+ after(:all) do
12
+ @application.close(:wait_for_close => true) if @application.running?
13
+ @application.should_not be_running
14
+ end
15
+
16
+ before(:each) do
17
+ @application.dialog_about.should be_nil
18
+ @application.set_focus
19
+ keystroke(VK_MENU, VK_H, VK_A)
20
+ @dialog_about = @application.dialog_about
21
+ @dialog_about.should_not be_nil
22
+ @dialog_about.is_window?.should == true
23
+ end
24
+
25
+ after(:each) do
26
+ @dialog_about.close if @dialog_about.is_window?
27
+ @dialog_about.is_window?.should == false
28
+ end
29
+
30
+ it "should open with the hotkey combination VK_MENU, VK_H, VK_A" do
31
+ @dialog_about.is_window?.should == true
32
+ end
33
+
34
+ it "should close by hitting return" do
35
+ @dialog_about.set_focus
36
+ keystroke(VK_RETURN)
37
+ @application.dialog_about.should be_nil
38
+ end
39
+
40
+ it "should have the title 'About QuickNote'" do
41
+ @dialog_about.title.should == "About QuickNote"
42
+ end
43
+
44
+ it "should have an 'OK' button" do
45
+ button = @dialog_about.children.find {|w| w.window_class == 'TButton'}
46
+ button.should_not be_nil
47
+ button.text.should match(/^OK$/)
48
+ end
49
+
50
+ end
@@ -0,0 +1,274 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Autogui::Input
4
+
5
+ describe "FormMain" do
6
+ before(:all) do
7
+ @debug = false
8
+ @verbose = true
9
+ @application = Quicknote.new
10
+ FileUtils.rm_rf(current_dir)
11
+ puts "FormMain before(:all)" if @debug
12
+ puts "application:\n#{@application.inspect}\n" if @debug && @verbose
13
+ puts "application.combined_text:\n #{@application.combined_text}\n" if @debug && @verbose
14
+ end
15
+ before(:each) do
16
+ @application = Quicknote.new unless @application.running?
17
+ @application.should be_running
18
+ @application.set_focus
19
+ puts "FormMain before(:each)" if @debug
20
+ end
21
+ after(:all) do
22
+ if @application.running?
23
+ @application.file_exit
24
+ # still running? force it to close
25
+ @application.close(:wait_for_close => true)
26
+ @application.should_not be_running
27
+ end
28
+ puts "FormMain after(:all)" if @debug
29
+ end
30
+ after(:each) do
31
+ if @application.running?
32
+ keystroke(VK_N) if @application.message_dialog_confirm || @application.dialog_overwrite_confirm
33
+ keystroke(VK_ESCAPE) if @application.error_dialog
34
+ end
35
+ puts "FormMain after(:each)" if @debug
36
+ end
37
+
38
+ describe "after startup" do
39
+ it "should have the title 'QuickNote - untitled.txt'" do
40
+ @application.main_window.title.should == "QuickNote - untitled.txt"
41
+ end
42
+ it "should have no text" do
43
+ @application.edit_window.text.should == ''
44
+ end
45
+ end
46
+
47
+ describe "editing text" do
48
+ after(:each) do
49
+ @application.file_new(:save => false)
50
+ end
51
+
52
+ it "should add the '+' modified flag to the title" do
53
+ @application.main_window.title.should == "QuickNote - untitled.txt"
54
+ type_in("hello")
55
+ @application.main_window.title.should == "QuickNote - +untitled.txt"
56
+ end
57
+ it "should change the text" do
58
+ @application.edit_window.text.should == ''
59
+ type_in("hello")
60
+ @application.edit_window.text.should == 'hello'
61
+ end
62
+ end
63
+
64
+ describe "file open (VK_MENU, VK_F, VK_O)" do
65
+ before(:each) do
66
+ @filename = "input_file.txt"
67
+ @file_contents = create_file(@filename, "the quick brown fox")
68
+ @application.file_new(:save => false)
69
+ end
70
+ after(:each) do
71
+ keystroke(VK_N) if @application.message_dialog_confirm
72
+ keystroke(VK_ESCAPE) if @application.file_open_dialog
73
+ end
74
+
75
+ it "should prompt to save with modified text" do
76
+ type_in("foobar")
77
+ @application.main_window.title.should match(/\+/)
78
+ keystroke(VK_MENU, VK_F, VK_O)
79
+ @application.message_dialog_confirm.should_not be_nil
80
+ end
81
+ it "should not prompt to save with unmodified text" do
82
+ @application.main_window.title.should_not match(/\+/)
83
+ keystroke(VK_MENU, VK_F, VK_O)
84
+ @application.message_dialog_confirm.should be_nil
85
+ end
86
+
87
+ describe "succeeding" do
88
+ it "should add the filename to the title" do
89
+ @application.main_window.title.should == "QuickNote - untitled.txt"
90
+ @application.file_open(fullpath(@filename), :save => false)
91
+ @application.main_window.title.should == "QuickNote - #{fullpath(@filename)}"
92
+ end
93
+ it "should load the text" do
94
+ @application.file_open(fullpath(@filename), :save => false)
95
+ @application.edit_window.text.should == 'the quick brown fox'
96
+ end
97
+ end
98
+
99
+ describe "failing" do
100
+ it "should show an error dialog with message 'Cannot open file'" do
101
+ type_in("foobar")
102
+ @application.file_open(fullpath("a_bogus_filename.txt"), :save => false)
103
+ @application.error_dialog.should_not be_nil
104
+ @application.error_dialog.combined_text.should match(/Cannot open file/)
105
+ end
106
+ it "should keep existing text" do
107
+ type_in("foobar")
108
+ @application.file_open(fullpath("a_bogus_filename.txt"), :save => false)
109
+ @application.error_dialog.should_not be_nil
110
+ @application.edit_window.text.should == 'foobar'
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "file new (VK_MENU, VK_F, VK_N)" do
116
+ it "should prompt to save modified text" do
117
+ type_in("hello")
118
+ @application.main_window.title.should match(/\+/)
119
+ keystroke(VK_MENU, VK_F, VK_N)
120
+ @application.message_dialog_confirm.should_not be_nil
121
+ end
122
+ it "should not prompt to save with unmodified text" do
123
+ @application.file_new(:save => false)
124
+ @application.main_window.title.should_not match(/\+/)
125
+ keystroke(VK_MENU, VK_F, VK_N)
126
+ @application.message_dialog_confirm.should be_nil
127
+ end
128
+ it "should add the filename 'untitled.txt' to the title" do
129
+ filename = "input_file.txt"
130
+ file_contents = create_file(filename, "the quick brown fox")
131
+ @application.file_open(filename, :save => false)
132
+ @application.main_window.title.downcase.should == "QuickNote - #{fullpath(filename)}".downcase
133
+ @application.file_new(:save => false)
134
+ @application.main_window.title.should == "QuickNote - untitled.txt"
135
+ end
136
+ it "should remove the '+' modified flag from the title" do
137
+ type_in("hello")
138
+ @application.main_window.title.should match(/\+/)
139
+ @application.file_new(:save => false)
140
+ @application.main_window.title.should_not match(/\+/)
141
+ end
142
+ it "should clear the existing text" do
143
+ type_in("hello")
144
+ @application.edit_window.text.should match(/hello/)
145
+ @application.file_new(:save => false)
146
+ @application.edit_window.text.should == ''
147
+ end
148
+ end
149
+
150
+ describe "file save (VK_MENU, VK_F, VK_S)" do
151
+ before(:each) do
152
+ @filename = "input_file.txt"
153
+ @file_contents = create_file(@filename, "original content")
154
+ @application.file_open(fullpath(@filename), :save => false)
155
+ @application.main_window.title.downcase.should == "QuickNote - #{fullpath(@filename)}".downcase
156
+ @application.edit_window.text.should == "original content"
157
+ @application.set_focus
158
+ end
159
+
160
+ it "should do nothing unless modified text" do
161
+ append_to_file(@filename, "sneak in extra content that shouldn't be here")
162
+ contents = get_file_content(@filename)
163
+ contents.should match(/extra content/)
164
+ @application.file_save
165
+ contents.should match(/extra content/)
166
+ @application.edit_window.text.should_not match(/extra content/)
167
+ end
168
+
169
+ describe "succeeding" do
170
+ it "should remove the '+' modified flag from the title" do
171
+ type_in("anything")
172
+ @application.main_window.title.should == "QuickNote - +#{fullpath(@filename)}"
173
+ @application.file_save
174
+ @application.main_window.title.should == "QuickNote - #{fullpath(@filename)}"
175
+ end
176
+ it "should save the text" do
177
+ type_in("foobar")
178
+ @application.edit_window.text.should == "foobar" + "original content"
179
+ @application.file_save
180
+ get_file_content(@filename).should == "foobar" + "original content"
181
+ end
182
+ end
183
+
184
+ describe "failing" do
185
+ before(:each) do
186
+ # set read-only to cause save failure
187
+ in_current_dir do
188
+ `attrib +R #{@filename}`
189
+ end
190
+ end
191
+ after(:each) do
192
+ # cleanup read-only file
193
+ FileUtils.rm_rf(current_dir)
194
+ end
195
+
196
+ it "should show an error dialog with message 'Cannot create file'" do
197
+ type_in("anything")
198
+ @application.file_save
199
+ @application.error_dialog.should_not be_nil
200
+ @application.error_dialog.combined_text.should match(/Cannot create file/)
201
+ end
202
+ it "should keep the '+' modified flag on the title" do
203
+ type_in("anything")
204
+ @application.file_save
205
+ @application.main_window.title.should == "QuickNote - +#{fullpath(@filename)}"
206
+ end
207
+ it "should keep existing text" do
208
+ type_in("anything")
209
+ @application.file_save
210
+ @application.edit_window.text.should == "anything" + "original content"
211
+ end
212
+ end
213
+ end
214
+
215
+ describe "file save as (VK_MENU, VK_F, VK_A)" do
216
+ before(:each) do
217
+ @filename = "original.txt"
218
+ @file_contents = create_file(@filename, "original content")
219
+ @saveas_filename = "newfile.txt"
220
+ create_file(@saveas_filename, "")
221
+ @application.file_open(fullpath(@filename), :save => false)
222
+ end
223
+ after(:each) do
224
+ keystroke(VK_N) if @application.dialog_overwrite_confirm
225
+ keystroke(VK_ESCAPE) if @application.file_save_as_dialog
226
+ end
227
+
228
+ it "should prompt for filename" do
229
+ keystroke(VK_MENU, VK_F, VK_A)
230
+ @application.file_save_as_dialog.should_not be_nil
231
+ end
232
+ it "should confirm file overwrites" do
233
+ type_in("anything")
234
+ keystroke(VK_MENU, VK_F, VK_A)
235
+ @application.clipboard.text = fullpath(@saveas_filename)
236
+ keystroke(VK_CONTROL, VK_V)
237
+ keystroke(VK_RETURN)
238
+ File.exists?(fullpath(@saveas_filename)).should be_true
239
+ @application.dialog_overwrite_confirm.should_not be_nil
240
+ end
241
+ it "should remove the '+' modified flag from the title" do
242
+ type_in("anything")
243
+ @application.main_window.title.should match(/\+/)
244
+ @application.file_save_as(fullpath(@saveas_filename), :overwrite => true)
245
+ @application.main_window.title.should_not match(/\+/)
246
+ end
247
+ it "should add the filename to the title" do
248
+ @application.file_save_as(fullpath(@saveas_filename), :overwrite => true)
249
+ @application.main_window.title.downcase.should == "QuickNote - #{fullpath(@saveas_filename)}".downcase
250
+ end
251
+ it "should save the text" do
252
+ get_file_content(@saveas_filename).should == ''
253
+ @application.file_save_as(fullpath(@saveas_filename), :overwrite => true)
254
+ get_file_content(@saveas_filename).should match(/original content/)
255
+ end
256
+ end
257
+
258
+ describe "file exit (VK_MENU, VK_F, VK_X)" do
259
+ it "should prompt and save with modified text" do
260
+ type_in("anything")
261
+ keystroke(VK_MENU, VK_F, VK_X)
262
+ @application.message_dialog_confirm.should_not be_nil
263
+ @application.main_window.is_window?.should == true
264
+ @application.should be_running
265
+ end
266
+ it "should not prompt to save with unmodified text" do
267
+ keystroke(VK_MENU, VK_F, VK_X)
268
+ @application.message_dialog_confirm.should be_nil
269
+ @application.main_window.is_window?.should == false
270
+ @application.should_not be_running
271
+ end
272
+ end
273
+
274
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include Autogui::Input
4
+
5
+ describe "FormSplash" do
6
+ after(:all) do
7
+ if @application.running?
8
+ @application.splash.wait_for_close if @application.splash
9
+ @application.file_exit
10
+ # still running? force it to close
11
+ @application.close(:wait_for_close => true)
12
+ @application.should_not be_running
13
+ end
14
+ end
15
+
16
+ describe "startup with no command line parameters" do
17
+ before(:all) do
18
+ # --nosplash is the default, turn it back on
19
+ @application = Quicknote.new :parameters => ''
20
+ @application.should be_running
21
+ end
22
+
23
+ it "should show" do
24
+ @application.splash.should_not be_nil
25
+ end
26
+ it "should close within 5 seconds" do
27
+ @application.splash.should_not be_nil
28
+ seconds = 5
29
+ timeout(seconds) do
30
+ @application.splash.wait_for_close
31
+ end
32
+ @application.splash.should be_nil
33
+ end
34
+ end
35
+
36
+ describe "startup with '--nosplash' command line parameter" do
37
+ it "should not show" do
38
+ @application = Quicknote.new :parameters => '--nosplash'
39
+ @application.should be_running
40
+ @application.splash.should be_nil
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH.unshift File.expand_path('..', __FILE__) unless
2
+ $LOAD_PATH.include? File.expand_path('..', __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) unless
4
+ $LOAD_PATH.include? File.expand_path('../../lib', __FILE__)
5
+
6
+ # use development version of win32/autogui
7
+ # remove these lines in production code
8
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) unless
9
+ $LOAD_PATH.include? File.expand_path('../../../../lib', __FILE__)
10
+
11
+ require 'rubygems'
12
+ require 'win32/autogui'
13
+ require 'quicknote'
14
+ require 'spec'
15
+ require 'spec/autorun'
16
+ require 'aruba/api'
17
+
18
+ # aruba helper, returns full path to files in the aruba tmp folder
19
+ def fullpath(filename)
20
+ path = File.expand_path(File.join(current_dir, filename))
21
+ path = `cygpath -w #{path}`.chomp if path.match(/^\/cygdrive/) # cygwin?
22
+ path
23
+ end
24
+
25
+ # return the contents of "filename" in the aruba tmp folder
26
+ def get_file_content(filename)
27
+ in_current_dir do
28
+ IO.read(filename)
29
+ end
30
+ end
31
+
32
+ Spec::Runner.configure do |config|
33
+ config.include Aruba::Api
34
+ end
@@ -0,0 +1,143 @@
1
+ # Watchr: Autotest like functionality
2
+ #
3
+ # gem install watchr
4
+ #
5
+ # Run me with:
6
+ #
7
+ # $ watchr spec/watchr.rb
8
+
9
+ require 'term/ansicolor'
10
+
11
+ $c = Term::ANSIColor
12
+
13
+ def getch
14
+ state = `stty -g`
15
+ begin
16
+ `stty raw -echo cbreak`
17
+ $stdin.getc
18
+ ensure
19
+ `stty #{state}`
20
+ end
21
+ end
22
+
23
+ # --------------------------------------------------
24
+ # Convenience Methods
25
+ # --------------------------------------------------
26
+ def all_feature_files
27
+ Dir['features/*.feature']
28
+ end
29
+
30
+ def all_spec_files
31
+ files = Dir['spec/**/*_spec\.rb']
32
+ end
33
+
34
+ def run(cmd)
35
+
36
+ pid = fork do
37
+ puts "\n"
38
+ print $c.cyan, cmd, $c.clear, "\n"
39
+ exec(cmd)
40
+ end
41
+ Signal.trap('INT') do
42
+ puts "sending KILL to pid: #{pid}"
43
+ Process.kill("KILL", pid)
44
+ end
45
+ Process.waitpid(pid)
46
+
47
+ prompt
48
+ end
49
+
50
+ def run_all
51
+ run_all_specs
52
+ run_default_cucumber
53
+ end
54
+
55
+ # allow cucumber rerun.txt smarts
56
+ def run_default_cucumber
57
+ cmd = "cucumber"
58
+ run(cmd)
59
+ end
60
+
61
+ def run_all_features
62
+ cmd = "cucumber #{all_feature_files.join(' ')}"
63
+ run(cmd)
64
+ end
65
+
66
+ def run_feature(feature)
67
+ cmd = "cucumber #{feature}"
68
+ $last_feature = feature
69
+ run(cmd)
70
+ end
71
+
72
+ def run_last_feature
73
+ run_feature($last_feature) if $last_feature
74
+ end
75
+
76
+ def run_default_spec
77
+ cmd = "spec _1.3.1_ --color --format s ./spec"
78
+ run(cmd)
79
+ end
80
+
81
+ def run_all_specs
82
+ cmd = "spec _1.3.1_ --color --format s #{all_spec_files.join(' ')}"
83
+ p cmd
84
+ run(cmd)
85
+ end
86
+
87
+ def run_spec(spec)
88
+ cmd = "spec _1.3.1_ --color --format s #{spec}"
89
+ $last_spec = spec
90
+ run(cmd)
91
+ end
92
+
93
+ def run_last_spec
94
+ run_spec($last_spec) if $last_spec
95
+ end
96
+
97
+ def prompt
98
+ puts "Ctrl-\\ for menu, Ctrl-C to quit"
99
+ end
100
+
101
+ # init
102
+ $last_feature = nil
103
+ prompt
104
+
105
+ # --------------------------------------------------
106
+ # Watchr Rules
107
+ # --------------------------------------------------
108
+ watch( '^features/(.*)\.feature' ) { run_default_cucumber }
109
+
110
+ #watch( '^bin/(.*)' ) { run_default_cucumber }
111
+ watch( '^lib/(.*)' ) { run_default_cucumber }
112
+
113
+ watch( '^features/step_definitions/(.*)\.rb' ) { run_default_cucumber }
114
+ watch( '^features/support/(.*)\.rb' ) { run_default_cucumber }
115
+
116
+ watch( '^spec/(.*)_spec\.rb' ) { |m| run_spec(m[0]) }
117
+ # specify just the lib files that have specs
118
+ # TODO: This can be determined automatically from the spec file naming convention
119
+ watch( '^lib/(.*)' ) { run_default_spec }
120
+
121
+ # --------------------------------------------------
122
+ # Signal Handling
123
+ # --------------------------------------------------
124
+
125
+ # Ctrl-\
126
+ Signal.trap('QUIT') do
127
+
128
+ puts "\n\nMENU: a = all , f = features s = specs, l = last feature (#{$last_feature ? $last_feature : 'none'}), q = quit\n\n"
129
+ c = getch
130
+ puts c.chr
131
+ if c.chr == "a"
132
+ run_all
133
+ elsif c.chr == "f"
134
+ run_default_cucumber
135
+ elsif c.chr == "s"
136
+ run_all_specs
137
+ elsif c.chr == "q"
138
+ abort("exiting\n")
139
+ elsif c.chr == "l"
140
+ run_last_feature
141
+ end
142
+
143
+ end