greenletters 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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # Bones {
8
+ # ignore_file '.gitignore'
9
+ # }
10
+ #
11
+ # For a project with a C extension, the following would be a good set of
12
+ # exclude patterns (uncomment them if you want to use them):
13
+ # *.[oa]
14
+ # *~
15
+ announcement.txt
16
+ coverage
17
+ doc
18
+ pkg
19
+ /examples/cucumber/greenletters.log
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 / 2010-07-19
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.org ADDED
@@ -0,0 +1,107 @@
1
+ #+Title: Greenletters README
2
+ #+AUTHOR: Avdi Grimm
3
+ #+EMAIL: avdi@avdi.org
4
+
5
+ # Configuration:
6
+ #+STARTUP: odd
7
+ #+STARTUP: hi
8
+ #+STARTUP: hidestars
9
+
10
+
11
+ * Synopsis
12
+
13
+ #+begin_src ruby
14
+ require 'greenletters'
15
+ adv = Greenletters::Process.new("adventure", :transcript => $stdout)
16
+ adv.on(:output, /welcome to adventure/i) do |process, match_data|
17
+ adv << "no\n"
18
+ end
19
+
20
+ puts "Starting adventure..."
21
+ adv.start!
22
+ adv.wait_for(:output, /you are standing at the end of a road/i)
23
+ adv << "east\n"
24
+ adv.wait_for(:output, /inside a building/i)
25
+ adv << "quit\n"
26
+ adv.wait_for(:output, /really want to quit/i)
27
+ adv << "yes\n"
28
+ adv.wait_for(:exit)
29
+ puts "Adventure has exited."
30
+ #+end_src
31
+
32
+ Or, in Cucumber format:
33
+
34
+ #+BEGIN_SRC
35
+ Given process activity is logged to "greenletters.log"
36
+ Given a process "adventure" from command "adventure"
37
+ Given I reply "no" to output "Would you like instructions?" from process "adventure"
38
+ Given I reply "yes" to output "Do you really want to quit" from process "adventure"
39
+ When I execute the process "adventure"
40
+ Then I should see the following output from process "adventure":
41
+ """
42
+ You are standing at the end of a road before a small brick building.
43
+ Around you is a forest. A small stream flows out of the building and
44
+ down a gully.
45
+ """
46
+ When I enter "east" into process "adventure"
47
+ Then I should see the following output from process "adventure":
48
+ """
49
+ You are inside a building, a well house for a large spring.
50
+ """
51
+ #+END_SRC
52
+
53
+ * What
54
+
55
+ Greenletters is a console interaction automation library similar to [[http://directory.fsf.org/project/expect/][GNU
56
+ Expect]]. You can use it to script interactions with command-line programs.
57
+
58
+ * Why
59
+ Because Ruby's built-in expect.rb is pretty underpowered and I wanted to drive
60
+ command-line applications from Ruby, not TCL.
61
+
62
+ * Who
63
+ Greenletters is by [[mailto:avdi@avdi.org][Avdi Grimm]].
64
+
65
+ * Where
66
+ http://github.com/avdi/greenletters
67
+
68
+ * How
69
+ Greenletters uses the pty.rb library under the covers to create a UNIX
70
+ pseudoterminal under Ruby's control. Of course, this means that it is
71
+ *NIX-only; Windows users need not apply.
72
+
73
+ The advantage of using a PTY is that *any* output - inclding output written to
74
+ the console instead of STDOUT/STDERR - will be captured by Greenletters.
75
+
76
+ * Cucumber
77
+ To use the Cucumber steps in your own feature files, put the following in your env.rb:
78
+
79
+ #+BEGIN_SRC ruby
80
+ require 'greenletters'
81
+ require 'greenletters/cucumber_steps'
82
+ #+END_SRC
83
+
84
+ * LICENSE
85
+
86
+ (The MIT License)
87
+
88
+ Copyright (c) 2010 Avdi Grimm
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ 'Software'), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ task :default => 'test:run'
9
+ task 'gem:release' => 'test:run'
10
+
11
+ Bones {
12
+ name 'greenletters'
13
+ authors 'Avdi Grimm'
14
+ email 'avdi@avdi.org'
15
+ url 'http://github.com/avdi/greenletters'
16
+ ignore_file '.gitignore'
17
+ readme_file 'README.org'
18
+
19
+ summary 'A Ruby console automation framework a la Expect'
20
+
21
+ description <<-END
22
+ Greenletterrs is a console automation framework, similar to the classic
23
+ utility Expect. You give it a command to execute, and tell it which outputs
24
+ or events to expect and how to respond to them.
25
+
26
+ Greenletters also includes a set of Cucumber steps which simplify the task
27
+ of spcifying interactive command-line applications.
28
+ END
29
+ }
30
+
data/bin/greenletters ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib greenletters]))
5
+
6
+ # Put your code here
7
+
@@ -0,0 +1,30 @@
1
+ # This demo interacts with the classic Collossal Cave Adventure game. To install
2
+ # the game on Debian-based systems (Ubuntu, etc), execute:
3
+ #
4
+ # sudo apt-get install bsdgames
5
+ #
6
+ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
7
+ require 'greenletters'
8
+ require 'logger'
9
+
10
+ logger = ::Logger.new($stdout)
11
+ logger.level = ::Logger::INFO
12
+ # logger.level = ::Logger::DEBUG
13
+ adv = Greenletters::Process.new("adventure",
14
+ :logger => logger,
15
+ :transcript => $stdout)
16
+ adv.on(:output, /welcome to adventure/i) do |process, match_data|
17
+ adv << "no\n"
18
+ end
19
+
20
+ puts "Starting aadventure..."
21
+ adv.start!
22
+ adv.wait_for(:output, /you are standing at the end of a road/i)
23
+ adv << "east\n"
24
+ adv.wait_for(:output, /inside a building/i)
25
+ adv << "quit\n"
26
+ adv.wait_for(:output, /really want to quit/i)
27
+ adv << "yes\n"
28
+ adv.wait_for(:exit)
29
+ puts "Adventure has exited."
30
+
@@ -0,0 +1,67 @@
1
+ Feature: play adventure
2
+ As a nerd
3
+ I want to play a text adventure game
4
+ Because I'm old-skool
5
+
6
+ Scenario: play first few rooms (named process)
7
+ Given process activity is logged to "greenletters.log"
8
+ Given a process "adventure" from command "adventure"
9
+ Given I reply "no" to output "Would you like instructions?" from process "adventure"
10
+ Given I reply "yes" to output "Do you really want to quit" from process "adventure"
11
+ When I execute the process "adventure"
12
+ Then I should see the following output from process "adventure":
13
+ """
14
+ You are standing at the end of a road before a small brick building.
15
+ Around you is a forest. A small stream flows out of the building and
16
+ down a gully.
17
+ """
18
+ When I enter "east" into process "adventure"
19
+ Then I should see the following output from process "adventure":
20
+ """
21
+ You are inside a building, a well house for a large spring.
22
+ """
23
+ When I enter "west" into process "adventure"
24
+ Then I should see the following output from process "adventure":
25
+ """
26
+ You're at end of road again.
27
+ """
28
+ When I enter "south" into process "adventure"
29
+ Then I should see the following output from process "adventure":
30
+ """
31
+ You are in a valley in the forest beside a stream tumbling along a
32
+ rocky bed.
33
+ """
34
+ When I enter "quit" into process "adventure"
35
+ Then the process "adventure" should exit succesfully
36
+
37
+ Scenario: play first few rooms (default process)
38
+ Given process activity is logged to "greenletters.log"
39
+ Given a process from command "adventure"
40
+ Given I reply "no" to output "Would you like instructions?"
41
+ Given I reply "yes" to output "Do you really want to quit"
42
+ When I execute the process
43
+ Then I should see the following output:
44
+ """
45
+ You are standing at the end of a road before a small brick building.
46
+ Around you is a forest. A small stream flows out of the building and
47
+ down a gully.
48
+ """
49
+ When I enter "east"
50
+ Then I should see the following output:
51
+ """
52
+ You are inside a building, a well house for a large spring.
53
+ """
54
+ When I enter "west"
55
+ Then I should see the following output:
56
+ """
57
+ You're at end of road again.
58
+ """
59
+ When I enter "south"
60
+ Then I should see the following output:
61
+ """
62
+ You are in a valley in the forest beside a stream tumbling along a
63
+ rocky bed.
64
+ """
65
+ When I enter "quit"
66
+ Then the process should exit succesfully
67
+
@@ -0,0 +1,251 @@
1
+ D, [2010-07-18T09:07:00.322981 #4796] DEBUG -- : added trigger on output matching /Would\s+you\s+like\s+instructions\?/
2
+ D, [2010-07-18T09:07:00.324028 #4796] DEBUG -- : added trigger on output matching /Do\s+you\s+really\s+want\s+to\s+quit/
3
+ D, [2010-07-18T09:07:00.324701 #4796] DEBUG -- : installing end marker handler for __GREENLETTERS_PROCESS_ENDED__
4
+ D, [2010-07-18T09:07:00.324808 #4796] DEBUG -- : prepended trigger on output matching /__GREENLETTERS_PROCESS_ENDED__/
5
+ D, [2010-07-18T09:07:00.324875 #4796] DEBUG -- : executing /usr/bin/ruby1.8 -C /home/avdi/dev/greenletters/examples/cucumber -e system(*["adventure"]) -e puts("__GREENLETTERS_PROCESS_ENDED__") -e gets -e exit $?.exitstatus
6
+ D, [2010-07-18T09:07:00.325021 #4796] DEBUG -- : command environment:
7
+ {"LIBGL_DRIVERS_PATH"=>"/usr/lib/fglrx/dri:/usr/lib32/fglrx/dri", "GDM_LANG"=>"en_US.utf8", "LANGUAGE"=>"", "KONSOLE_DBUS_SERVICE"=>":1.10", "LOGNAME"=>"avdi", "GTK_MODULES"=>"canberra-gtk-module", "DBUS_SESSION_BUS_ADDRESS"=>"unix:abstract=/tmp/dbus-ysd8AY9I4g,guid=d9670f4428aeffbcad7a4cf94c40af03", "SPEECHD_PORT"=>"7560", "PATH"=>"/home/avdi/bin:/home/avdi/share/bin:/home/avdi/.gem/ruby/1.8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games", "USER"=>"avdi", "GNOME_KEYRING_PID"=>"2330", "LANG"=>"en_US.utf8", "DEFAULTS_PATH"=>"/usr/share/gconf/gnome.default.path", "WINDOWID"=>"23068726", "XDG_CONFIG_DIRS"=>"/etc/xdg/xdg-gnome:/etc/xdg", "ORBIT_SOCKETDIR"=>"/tmp/orbit-avdi", "XDG_DATA_DIRS"=>"/usr/share/gnome:/usr/local/share/:/usr/share/", "GNOME_DESKTOP_SESSION_ID"=>"this-is-deprecated", "DISPLAY"=>":0.0", "PWD"=>"/home/avdi/dev/greenletters/examples/cucumber", "GDMSESSION"=>"gnome", "GDM_KEYBOARD_LAYOUT"=>"us", "COLORFGBG"=>"15;0", "XAUTHORITY"=>"/var/run/gdm/auth-for-avdi-GRGq1x/database", "SSH_AGENT_PID"=>"2389", "XDG_SESSION_COOKIE"=>"95da948d870c084a39cf95e74bcf1d12-1279307523.573384-2005890633", "TERM"=>"xterm", "PROFILEHOME"=>"", "SESSION_MANAGER"=>"local/petronius:@/tmp/.ICE-unix/2348,unix/petronius:/tmp/.ICE-unix/2348", "DESKTOP_AUTOSTART_ID"=>"10957e6313bf75a5e0127930752431450800000023480004", "SSH_AUTH_SOCK"=>"/tmp/keyring-5DVyII/ssh", "KONSOLE_DBUS_SESSION"=>"/Sessions/4", "GNOME_KEYRING_CONTROL"=>"/tmp/keyring-5DVyII", "DESKTOP_SESSION"=>"gnome", "USERNAME"=>"avdi", "MANDATORY_PATH"=>"/usr/share/gconf/gnome.mandatory.path", "HOME"=>"/home/avdi", "GPG_AGENT_INFO"=>"/tmp/gpg-5xymDi/S.gpg-agent:2390:1", "SHELL"=>"/bin/zsh", "SHLVL"=>"1", "OLDPWD"=>"/home/avdi/dev/greenletters/examples", "EDITOR"=>"/home/avdi/share/bin/emacs-newwindow", "GEM_EDITOR"=>"/home/avdi/share/bin/emacs-newwindow", "ZSH"=>"/home/avdi/.oh-my-zsh", "ZSH_THEME"=>"robbyrussell", "LSCOLORS"=>"Gxfxcxdxbxegedabagacad", "GREP_OPTIONS"=>"--color=auto", "GREP_COLOR"=>"1;32", "PAGER"=>"less", "LC_CTYPE"=>"en_US.UTF-8", "rvm_path"=>"/home/avdi/.rvm", "rvm_rubies_path"=>"/home/avdi/.rvm/rubies", "rvm_scripts_path"=>"/home/avdi/.rvm/scripts", "rvm_archives_path"=>"/home/avdi/.rvm/archives", "rvm_src_path"=>"/home/avdi/.rvm/src", "rvm_log_path"=>"/home/avdi/.rvm/log", "rvm_bin_path"=>"/home/avdi/.rvm/bin", "rvm_gems_path"=>"/home/avdi/.rvm/gems", "rvm_config_path"=>"/home/avdi/.rvm/config", "rvm_tmp_path"=>"/home/avdi/.rvm/tmp", "rvm_hooks_path"=>"/home/avdi/.rvm/hooks", "rvm_gems_cache_path"=>"/home/avdi/.rvm/gems/cache", "rvm_gemset_separator"=>"@", "rvm_version"=>"0.1.28", "_"=>"/home/avdi/.gem/ruby/1.8/bin/cucumber"}
8
+ D, [2010-07-18T09:07:00.337560 #4796] DEBUG -- : spawned pid 4801
9
+ D, [2010-07-18T09:07:00.338511 #4796] DEBUG -- : added trigger on output matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
10
+ D, [2010-07-18T09:07:00.338569 #4796] DEBUG -- : waiting for output matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
11
+ D, [2010-07-18T09:07:00.338608 #4796] DEBUG -- : select()
12
+ D, [2010-07-18T09:07:00.338693 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
13
+ D, [2010-07-18T09:07:00.338747 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
14
+ D, [2010-07-18T09:07:00.338825 #4796] DEBUG -- :
15
+ <<
16
+ << Welcome to Adventure!! Would you like instructions?
17
+ D, [2010-07-18T09:07:00.338863 #4796] DEBUG -- : read 56 bytes
18
+ D, [2010-07-18T09:07:00.338910 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
19
+ D, [2010-07-18T09:07:00.338966 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\nWelcome to Adventure!! Would you like instructions?\r\n"
20
+ D, [2010-07-18T09:07:00.339007 #4796] DEBUG -- : no match
21
+ D, [2010-07-18T09:07:00.339043 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
22
+ D, [2010-07-18T09:07:00.339077 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\nWelcome to Adventure!! Would you like instructions?\r\n"
23
+ D, [2010-07-18T09:07:00.339117 #4796] DEBUG -- : matched /Would\s+you\s+like\s+instructions\?/
24
+ D, [2010-07-18T09:07:00.339168 #4796] DEBUG -- : match trigger output matching /Would\s+you\s+like\s+instructions\?/
25
+ D, [2010-07-18T09:07:00.339209 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
26
+ D, [2010-07-18T09:07:00.339247 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\n"
27
+ D, [2010-07-18T09:07:00.339281 #4796] DEBUG -- : no match
28
+ D, [2010-07-18T09:07:00.339316 #4796] DEBUG -- : checking output against output matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
29
+ D, [2010-07-18T09:07:00.339350 #4796] DEBUG -- : matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./ against "\r\n"
30
+ D, [2010-07-18T09:07:00.339380 #4796] DEBUG -- : no match
31
+ D, [2010-07-18T09:07:00.339414 #4796] DEBUG -- : select()
32
+ D, [2010-07-18T09:07:00.339455 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
33
+ D, [2010-07-18T09:07:00.339504 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
34
+ D, [2010-07-18T09:07:00.339563 #4796] DEBUG -- :
35
+ >> no
36
+ D, [2010-07-18T09:07:00.339599 #4796] DEBUG -- : wrote 3 bytes
37
+ D, [2010-07-18T09:07:00.339631 #4796] DEBUG -- : select()
38
+ D, [2010-07-18T09:07:00.339673 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
39
+ D, [2010-07-18T09:07:00.359024 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
40
+ D, [2010-07-18T09:07:00.359161 #4796] DEBUG -- :
41
+ << no
42
+ <<
43
+ << You are standing at the end of a road before a small brick building.
44
+ << Around you is a forest. A small stream flows out of the building and
45
+ << down a gully.
46
+ D, [2010-07-18T09:07:00.359200 #4796] DEBUG -- : read 162 bytes
47
+ D, [2010-07-18T09:07:00.359251 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
48
+ D, [2010-07-18T09:07:00.359299 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\nno\r\n\r\nYou are standing at the end of a road before a small brick building.\r\nAround you is a forest. A small stream flows out of the building and\r\ndown a gully.\r\n"
49
+ D, [2010-07-18T09:07:00.359334 #4796] DEBUG -- : no match
50
+ D, [2010-07-18T09:07:00.359368 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
51
+ D, [2010-07-18T09:07:00.359406 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\nno\r\n\r\nYou are standing at the end of a road before a small brick building.\r\nAround you is a forest. A small stream flows out of the building and\r\ndown a gully.\r\n"
52
+ D, [2010-07-18T09:07:00.359437 #4796] DEBUG -- : no match
53
+ D, [2010-07-18T09:07:00.359507 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
54
+ D, [2010-07-18T09:07:00.359548 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\nno\r\n\r\nYou are standing at the end of a road before a small brick building.\r\nAround you is a forest. A small stream flows out of the building and\r\ndown a gully.\r\n"
55
+ D, [2010-07-18T09:07:00.359585 #4796] DEBUG -- : no match
56
+ D, [2010-07-18T09:07:00.359621 #4796] DEBUG -- : checking output against output matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
57
+ D, [2010-07-18T09:07:00.359664 #4796] DEBUG -- : matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./ against "\r\nno\r\n\r\nYou are standing at the end of a road before a small brick building.\r\nAround you is a forest. A small stream flows out of the building and\r\ndown a gully.\r\n"
58
+ D, [2010-07-18T09:07:00.359714 #4796] DEBUG -- : matched /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
59
+ D, [2010-07-18T09:07:00.359754 #4796] DEBUG -- : match trigger output matching /You\s+are\s+standing\s+at\s+the\s+end\s+of\s+a\s+road\s+before\s+a\s+small\s+brick\s+building\.\s+Around\s+you\s+is\s+a\s+forest\.\s+A\s+small\s+stream\s+flows\s+out\s+of\s+the\s+building\s+and\s+down\s+a\s+gully\./
60
+ D, [2010-07-18T09:07:00.359790 #4796] DEBUG -- : unblocked
61
+ D, [2010-07-18T09:07:00.359829 #4796] DEBUG -- : trigger removed
62
+ D, [2010-07-18T09:07:00.361484 #4796] DEBUG -- : added trigger on output matching /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./
63
+ D, [2010-07-18T09:07:00.361546 #4796] DEBUG -- : waiting for output matching /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./
64
+ D, [2010-07-18T09:07:00.361588 #4796] DEBUG -- : select()
65
+ D, [2010-07-18T09:07:00.361658 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
66
+ D, [2010-07-18T09:07:00.361728 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
67
+ D, [2010-07-18T09:07:00.361820 #4796] DEBUG -- :
68
+ >> east
69
+ D, [2010-07-18T09:07:00.361878 #4796] DEBUG -- : wrote 5 bytes
70
+ D, [2010-07-18T09:07:00.361942 #4796] DEBUG -- : select()
71
+ D, [2010-07-18T09:07:00.362026 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
72
+ D, [2010-07-18T09:07:00.379006 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
73
+ D, [2010-07-18T09:07:00.379142 #4796] DEBUG -- :
74
+ << east
75
+ <<
76
+ << You are inside a building, a well house for a large spring.
77
+ <<
78
+ << There are some keys on the ground here.
79
+ <<
80
+ << There is a shiny brass lamp nearby.
81
+ <<
82
+ << There is food here.
83
+ <<
84
+ << There is a bottle of water here.
85
+ D, [2010-07-18T09:07:00.379182 #4796] DEBUG -- : read 210 bytes
86
+ D, [2010-07-18T09:07:00.379240 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
87
+ D, [2010-07-18T09:07:00.379288 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\neast\r\n\r\nYou are inside a building, a well house for a large spring.\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\n"
88
+ D, [2010-07-18T09:07:00.379321 #4796] DEBUG -- : no match
89
+ D, [2010-07-18T09:07:00.379355 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
90
+ D, [2010-07-18T09:07:00.379394 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\neast\r\n\r\nYou are inside a building, a well house for a large spring.\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\n"
91
+ D, [2010-07-18T09:07:00.379455 #4796] DEBUG -- : no match
92
+ D, [2010-07-18T09:07:00.379497 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
93
+ D, [2010-07-18T09:07:00.379549 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\neast\r\n\r\nYou are inside a building, a well house for a large spring.\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\n"
94
+ D, [2010-07-18T09:07:00.379594 #4796] DEBUG -- : no match
95
+ D, [2010-07-18T09:07:00.379640 #4796] DEBUG -- : checking output against output matching /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./
96
+ D, [2010-07-18T09:07:00.379699 #4796] DEBUG -- : matching /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./ against "\r\neast\r\n\r\nYou are inside a building, a well house for a large spring.\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\n"
97
+ D, [2010-07-18T09:07:00.379758 #4796] DEBUG -- : matched /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./
98
+ D, [2010-07-18T09:07:00.379810 #4796] DEBUG -- : match trigger output matching /You\s+are\s+inside\s+a\s+building,\s+a\s+well\s+house\s+for\s+a\s+large\s+spring\./
99
+ D, [2010-07-18T09:07:00.379858 #4796] DEBUG -- : unblocked
100
+ D, [2010-07-18T09:07:00.379910 #4796] DEBUG -- : trigger removed
101
+ D, [2010-07-18T09:07:00.381659 #4796] DEBUG -- : added trigger on output matching /You're\s+at\s+end\s+of\s+road\s+again\./
102
+ D, [2010-07-18T09:07:00.381736 #4796] DEBUG -- : waiting for output matching /You're\s+at\s+end\s+of\s+road\s+again\./
103
+ D, [2010-07-18T09:07:00.381794 #4796] DEBUG -- : select()
104
+ D, [2010-07-18T09:07:00.381854 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
105
+ D, [2010-07-18T09:07:00.381920 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
106
+ D, [2010-07-18T09:07:00.382004 #4796] DEBUG -- :
107
+ >> west
108
+ D, [2010-07-18T09:07:00.382053 #4796] DEBUG -- : wrote 5 bytes
109
+ D, [2010-07-18T09:07:00.382096 #4796] DEBUG -- : select()
110
+ D, [2010-07-18T09:07:00.382157 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
111
+ D, [2010-07-18T09:07:00.397861 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
112
+ D, [2010-07-18T09:07:00.398226 #4796] DEBUG -- :
113
+ << west
114
+ <<
115
+ << You're at end of road again.
116
+ D, [2010-07-18T09:07:00.398280 #4796] DEBUG -- : read 38 bytes
117
+ D, [2010-07-18T09:07:00.398344 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
118
+ D, [2010-07-18T09:07:00.398412 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\nwest\r\n\r\nYou're at end of road again.\r\n"
119
+ D, [2010-07-18T09:07:00.398458 #4796] DEBUG -- : no match
120
+ D, [2010-07-18T09:07:00.398504 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
121
+ D, [2010-07-18T09:07:00.398556 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\nwest\r\n\r\nYou're at end of road again.\r\n"
122
+ D, [2010-07-18T09:07:00.398598 #4796] DEBUG -- : no match
123
+ D, [2010-07-18T09:07:00.398643 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
124
+ D, [2010-07-18T09:07:00.398695 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\nwest\r\n\r\nYou're at end of road again.\r\n"
125
+ D, [2010-07-18T09:07:00.398777 #4796] DEBUG -- : no match
126
+ D, [2010-07-18T09:07:00.398828 #4796] DEBUG -- : checking output against output matching /You're\s+at\s+end\s+of\s+road\s+again\./
127
+ D, [2010-07-18T09:07:00.398885 #4796] DEBUG -- : matching /You're\s+at\s+end\s+of\s+road\s+again\./ against "\r\n\r\nThere are some keys on the ground here.\r\n\r\nThere is a shiny brass lamp nearby.\r\n\r\nThere is food here.\r\n\r\nThere is a bottle of water here.\r\nwest\r\n\r\nYou're at end of road again.\r\n"
128
+ D, [2010-07-18T09:07:00.398959 #4796] DEBUG -- : matched /You're\s+at\s+end\s+of\s+road\s+again\./
129
+ D, [2010-07-18T09:07:00.399010 #4796] DEBUG -- : match trigger output matching /You're\s+at\s+end\s+of\s+road\s+again\./
130
+ D, [2010-07-18T09:07:00.399053 #4796] DEBUG -- : unblocked
131
+ D, [2010-07-18T09:07:00.399099 #4796] DEBUG -- : trigger removed
132
+ D, [2010-07-18T09:07:00.401301 #4796] DEBUG -- : added trigger on output matching /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./
133
+ D, [2010-07-18T09:07:00.401391 #4796] DEBUG -- : waiting for output matching /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./
134
+ D, [2010-07-18T09:07:00.401444 #4796] DEBUG -- : select()
135
+ D, [2010-07-18T09:07:00.401514 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
136
+ D, [2010-07-18T09:07:00.401581 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
137
+ D, [2010-07-18T09:07:00.401661 #4796] DEBUG -- :
138
+ >> south
139
+ D, [2010-07-18T09:07:00.401710 #4796] DEBUG -- : wrote 6 bytes
140
+ D, [2010-07-18T09:07:00.401754 #4796] DEBUG -- : select()
141
+ D, [2010-07-18T09:07:00.401810 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
142
+ D, [2010-07-18T09:07:00.418999 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
143
+ D, [2010-07-18T09:07:00.419139 #4796] DEBUG -- :
144
+ << south
145
+ <<
146
+ << You are in a valley in the forest beside a stream tumbling along a
147
+ << rocky bed.
148
+ D, [2010-07-18T09:07:00.419189 #4796] DEBUG -- : read 89 bytes
149
+ D, [2010-07-18T09:07:00.419253 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
150
+ D, [2010-07-18T09:07:00.419311 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\nsouth\r\n\r\nYou are in a valley in the forest beside a stream tumbling along a\r\nrocky bed.\r\n"
151
+ D, [2010-07-18T09:07:00.419356 #4796] DEBUG -- : no match
152
+ D, [2010-07-18T09:07:00.419402 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
153
+ D, [2010-07-18T09:07:00.419449 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\nsouth\r\n\r\nYou are in a valley in the forest beside a stream tumbling along a\r\nrocky bed.\r\n"
154
+ D, [2010-07-18T09:07:00.419490 #4796] DEBUG -- : no match
155
+ D, [2010-07-18T09:07:00.419535 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
156
+ D, [2010-07-18T09:07:00.419575 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\nsouth\r\n\r\nYou are in a valley in the forest beside a stream tumbling along a\r\nrocky bed.\r\n"
157
+ D, [2010-07-18T09:07:00.419607 #4796] DEBUG -- : no match
158
+ D, [2010-07-18T09:07:00.419641 #4796] DEBUG -- : checking output against output matching /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./
159
+ D, [2010-07-18T09:07:00.419680 #4796] DEBUG -- : matching /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./ against "\r\nsouth\r\n\r\nYou are in a valley in the forest beside a stream tumbling along a\r\nrocky bed.\r\n"
160
+ D, [2010-07-18T09:07:00.419725 #4796] DEBUG -- : matched /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./
161
+ D, [2010-07-18T09:07:00.419792 #4796] DEBUG -- : match trigger output matching /You\s+are\s+in\s+a\s+valley\s+in\s+the\s+forest\s+beside\s+a\s+stream\s+tumbling\s+along\s+a\s+rocky\s+bed\./
162
+ D, [2010-07-18T09:07:00.419828 #4796] DEBUG -- : unblocked
163
+ D, [2010-07-18T09:07:00.419862 #4796] DEBUG -- : trigger removed
164
+ D, [2010-07-18T09:07:00.462688 #4796] DEBUG -- : added trigger on exit with status 0
165
+ D, [2010-07-18T09:07:00.462995 #4796] DEBUG -- : waiting for exit with status 0
166
+ D, [2010-07-18T09:07:00.463056 #4796] DEBUG -- : select()
167
+ D, [2010-07-18T09:07:00.463119 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
168
+ D, [2010-07-18T09:07:00.463187 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
169
+ D, [2010-07-18T09:07:00.463264 #4796] DEBUG -- :
170
+ >> quit
171
+ D, [2010-07-18T09:07:00.463314 #4796] DEBUG -- : wrote 5 bytes
172
+ D, [2010-07-18T09:07:00.463357 #4796] DEBUG -- : select()
173
+ D, [2010-07-18T09:07:00.463412 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
174
+ D, [2010-07-18T09:07:00.479013 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
175
+ D, [2010-07-18T09:07:00.479151 #4796] DEBUG -- :
176
+ << quit
177
+ <<
178
+ << Do you really want to quit now?
179
+ D, [2010-07-18T09:07:00.479201 #4796] DEBUG -- : read 41 bytes
180
+ D, [2010-07-18T09:07:00.479267 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
181
+ D, [2010-07-18T09:07:00.479321 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against "\r\nquit\r\n\r\nDo you really want to quit now?\r\n"
182
+ D, [2010-07-18T09:07:00.479365 #4796] DEBUG -- : no match
183
+ D, [2010-07-18T09:07:00.479412 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
184
+ D, [2010-07-18T09:07:00.479458 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against "\r\nquit\r\n\r\nDo you really want to quit now?\r\n"
185
+ D, [2010-07-18T09:07:00.479500 #4796] DEBUG -- : no match
186
+ D, [2010-07-18T09:07:00.479546 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
187
+ D, [2010-07-18T09:07:00.479592 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against "\r\nquit\r\n\r\nDo you really want to quit now?\r\n"
188
+ D, [2010-07-18T09:07:00.479642 #4796] DEBUG -- : matched /Do\s+you\s+really\s+want\s+to\s+quit/
189
+ D, [2010-07-18T09:07:00.479712 #4796] DEBUG -- : match trigger output matching /Do\s+you\s+really\s+want\s+to\s+quit/
190
+ D, [2010-07-18T09:07:00.479767 #4796] DEBUG -- : select()
191
+ D, [2010-07-18T09:07:00.479831 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
192
+ D, [2010-07-18T09:07:00.479895 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
193
+ D, [2010-07-18T09:07:00.479968 #4796] DEBUG -- :
194
+ >> yes
195
+ D, [2010-07-18T09:07:00.480017 #4796] DEBUG -- : wrote 4 bytes
196
+ D, [2010-07-18T09:07:00.480060 #4796] DEBUG -- : select()
197
+ D, [2010-07-18T09:07:00.480115 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
198
+ D, [2010-07-18T09:07:00.499047 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
199
+ D, [2010-07-18T09:07:00.499209 #4796] DEBUG -- :
200
+ << yes
201
+ <<
202
+ << OK
203
+ <<
204
+ <<
205
+ <<
206
+ << You scored 32 out of a possible 350 using 4 turns.
207
+ <<
208
+ << You are obviously a rank amateur. Better luck next time.
209
+ << To achieve the next higher rating, you need 4 more points.
210
+ << __GREENLETTERS_PROCESS_ENDED__
211
+ D, [2010-07-18T09:07:00.499249 #4796] DEBUG -- : read 222 bytes
212
+ D, [2010-07-18T09:07:00.499298 #4796] DEBUG -- : checking output against output matching /__GREENLETTERS_PROCESS_ENDED__/
213
+ D, [2010-07-18T09:07:00.499345 #4796] DEBUG -- : matching /__GREENLETTERS_PROCESS_ENDED__/ against " now?\r\nyes\r\n\r\nOK\r\n\r\n\r\n\r\nYou scored 32 out of a possible 350 using 4 turns.\r\n\r\nYou are obviously a rank amateur. Better luck next time.\r\nTo achieve the next higher rating, you need 4 more points.\r\n__GREENLETTERS_PROCESS_ENDED__\r\n"
214
+ D, [2010-07-18T09:07:00.499382 #4796] DEBUG -- : matched /__GREENLETTERS_PROCESS_ENDED__/
215
+ D, [2010-07-18T09:07:00.499444 #4796] DEBUG -- : end marker found
216
+ D, [2010-07-18T09:07:00.499506 #4796] DEBUG -- : end marker expunged from output buffer
217
+ D, [2010-07-18T09:07:00.499540 #4796] DEBUG -- : acknowledging end marker
218
+ D, [2010-07-18T09:07:00.499582 #4796] DEBUG -- : match trigger output matching /__GREENLETTERS_PROCESS_ENDED__/
219
+ D, [2010-07-18T09:07:00.499622 #4796] DEBUG -- : checking output against output matching /Would\s+you\s+like\s+instructions\?/
220
+ D, [2010-07-18T09:07:00.499663 #4796] DEBUG -- : matching /Would\s+you\s+like\s+instructions\?/ against " now?\r\nyes\r\n\r\nOK\r\n\r\n\r\n\r\nYou scored 32 out of a possible 350 using 4 turns.\r\n\r\nYou are obviously a rank amateur. Better luck next time.\r\nTo achieve the next higher rating, you need 4 more points.\r\n"
221
+ D, [2010-07-18T09:07:00.499695 #4796] DEBUG -- : no match
222
+ D, [2010-07-18T09:07:00.499729 #4796] DEBUG -- : checking output against output matching /Do\s+you\s+really\s+want\s+to\s+quit/
223
+ D, [2010-07-18T09:07:00.499783 #4796] DEBUG -- : matching /Do\s+you\s+really\s+want\s+to\s+quit/ against " now?\r\nyes\r\n\r\nOK\r\n\r\n\r\n\r\nYou scored 32 out of a possible 350 using 4 turns.\r\n\r\nYou are obviously a rank amateur. Better luck next time.\r\nTo achieve the next higher rating, you need 4 more points.\r\n"
224
+ D, [2010-07-18T09:07:00.499828 #4796] DEBUG -- : no match
225
+ D, [2010-07-18T09:07:00.499865 #4796] DEBUG -- : flushing triggers matching Greenletters::OutputTrigger
226
+ D, [2010-07-18T09:07:00.499903 #4796] DEBUG -- : select()
227
+ D, [2010-07-18T09:07:00.499949 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [#<File:/dev/pts/7>], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
228
+ D, [2010-07-18T09:07:00.499996 #4796] DEBUG -- : input ready #<File:/dev/pts/7>
229
+ D, [2010-07-18T09:07:00.500048 #4796] DEBUG -- :
230
+
231
+ D, [2010-07-18T09:07:00.500084 #4796] DEBUG -- : wrote 1 bytes
232
+ D, [2010-07-18T09:07:00.500116 #4796] DEBUG -- : select()
233
+ D, [2010-07-18T09:07:00.500175 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
234
+ D, [2010-07-18T09:07:00.509491 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
235
+ D, [2010-07-18T09:07:00.509618 #4796] DEBUG -- :
236
+ <<
237
+ D, [2010-07-18T09:07:00.509668 #4796] DEBUG -- : read 2 bytes
238
+ D, [2010-07-18T09:07:00.509729 #4796] DEBUG -- : flushing triggers matching Greenletters::OutputTrigger
239
+ D, [2010-07-18T09:07:00.509778 #4796] DEBUG -- : select()
240
+ D, [2010-07-18T09:07:00.509838 #4796] DEBUG -- : select() on [[#<File:/dev/pts/7>], [], [#<File:/dev/pts/7>, #<File:/dev/pts/7>]]
241
+ D, [2010-07-18T09:07:00.509898 #4796] DEBUG -- : output ready #<File:/dev/pts/7>
242
+ D, [2010-07-18T09:07:00.510051 #4796] DEBUG -- : Errno::EIO caught
243
+ D, [2010-07-18T09:07:00.510106 #4796] DEBUG -- : waiting for child 4801 to die
244
+ D, [2010-07-18T09:07:00.523528 #4796] DEBUG -- : caught PTY::ChildExited
245
+ D, [2010-07-18T09:07:00.523800 #4796] DEBUG -- : collecting remaining output
246
+ D, [2010-07-18T09:07:00.523953 #4796] DEBUG -- : Input/output error - /dev/pts/7
247
+ D, [2010-07-18T09:07:00.524009 #4796] DEBUG -- : handling exit of process 4801
248
+ D, [2010-07-18T09:07:00.524070 #4796] DEBUG -- : checking exit against exit with status 0
249
+ D, [2010-07-18T09:07:00.524129 #4796] DEBUG -- : match trigger exit with status 0
250
+ D, [2010-07-18T09:07:00.524172 #4796] DEBUG -- : unblocked
251
+ D, [2010-07-18T09:07:00.524216 #4796] DEBUG -- : trigger removed
@@ -0,0 +1,4 @@
1
+ $:.unshift(File.expand_path('../../../lib', File.dirname(__FILE__)))
2
+ require 'greenletters'
3
+ require 'greenletters/cucumber_steps'
4
+
@@ -0,0 +1,68 @@
1
+ require 'cucumber'
2
+
3
+ module Greenletters
4
+ module CucumberHelpers
5
+ def greenletters_prepare_entry(text)
6
+ text.chomp + "\n"
7
+ end
8
+ def greenletters_massage_pattern(text)
9
+ Regexp.new(Regexp.escape(text.strip.tr_s(" \r\n\t", " ")).gsub('\ ', '\s+'))
10
+ end
11
+ end
12
+ end
13
+
14
+ World(Greenletters::CucumberHelpers)
15
+
16
+ Before do
17
+ @greenletters_process_table = Hash.new {|h,k|
18
+ raise "No such process defined: #{k}"
19
+ }
20
+ end
21
+
22
+ Given /^process activity is logged to "([^\"]*)"$/ do |filename|
23
+ logger = ::Logger.new(open(filename, 'w+'))
24
+ #logger.level = ::Logger::INFO
25
+ logger.level = ::Logger::DEBUG
26
+ @greenletters_process_log = logger
27
+ end
28
+
29
+ Given /^a process (?:"([^\"]*)" )?from command "([^\"]*)"$/ do |name, command|
30
+ name ||= "default"
31
+ options = {
32
+ }
33
+ options[:logger] = @greenletters_process_log if @greenletters_process_log
34
+ @greenletters_process_table[name] = Greenletters::Process.new(command, options)
35
+ end
36
+
37
+ Given /^I reply "([^\"]*)" to output "([^\"]*)"(?: from process "([^\"]*)")?$/ do
38
+ |reply, pattern, name|
39
+ name ||= "default"
40
+ pattern = greenletters_massage_pattern(pattern)
41
+ @greenletters_process_table[name].on(:output, pattern) do |process, match_data|
42
+ process << greenletters_prepare_entry(reply)
43
+ end
44
+ end
45
+
46
+ When /^I execute the process(?: "([^\"]*)")?$/ do |name|
47
+ name ||= "default"
48
+ @greenletters_process_table[name].start!
49
+ end
50
+
51
+ Then /^I should see the following output(?: from process "([^\"]*)")?:$/ do
52
+ |name, pattern|
53
+ name ||= "default"
54
+ pattern = greenletters_massage_pattern(pattern)
55
+ @greenletters_process_table[name].wait_for(:output, pattern)
56
+ end
57
+
58
+ When /^I enter "([^\"]*)"(?: into process "([^\"]*)")?$/ do
59
+ |input, name|
60
+ name ||= "default"
61
+ @greenletters_process_table[name] << greenletters_prepare_entry(input)
62
+ end
63
+
64
+ Then /^the process(?: "([^\"]*)")? should exit succesfully$/ do |name|
65
+ name ||= "default"
66
+ @greenletters_process_table[name].wait_for(:exit, 0)
67
+ end
68
+
@@ -0,0 +1,566 @@
1
+ require 'logger'
2
+ require 'pty'
3
+ require 'forwardable'
4
+ require 'stringio'
5
+ require 'shellwords'
6
+ require 'rbconfig'
7
+ require 'strscan'
8
+
9
+ # A better expect.rb
10
+ #
11
+ # Implementation note: because of the way PTY is implemented in Ruby, it is
12
+ # possible when executing a quick non-interactive command for PTY::ChildExited
13
+ # to be raised before ever getting input/output handles to the child
14
+ # process. Without an output handle, it's not possible to read any output the
15
+ # process produced. This is obviously undesirable, especially since when a
16
+ # command is unexpectedly quick and noninteractive it's usually because there
17
+ # was an error and you really want to be able to see what the problem was.
18
+ #
19
+ # Greenletters' solution to this problem is to wrap every command in a short
20
+ # script. The script executes the passed command and on termination, outputs an
21
+ # easily recognizable marker string. Then it waits for acknowledgment (a
22
+ # newline) before exiting. When Greenletters sees the marker string in the
23
+ # output, it automatically performs the acknowledgement and allows the child
24
+ # process to finish. By forcing the child process to wait for acknowledgement,
25
+ # we guarantee that the child will never exit before we have a chance to look at
26
+ # the output.
27
+ module Greenletters
28
+
29
+ # :stopdoc:
30
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
31
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
32
+ # :startdoc:
33
+
34
+ # Returns the version string for the library.
35
+ #
36
+ def self.version
37
+ @version ||= File.read(path('version.txt')).strip
38
+ end
39
+
40
+ # Returns the library path for the module. If any arguments are given,
41
+ # they will be joined to the end of the libray path using
42
+ # <tt>File.join</tt>.
43
+ #
44
+ def self.libpath( *args, &block )
45
+ rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
46
+ if block
47
+ begin
48
+ $LOAD_PATH.unshift LIBPATH
49
+ rv = block.call
50
+ ensure
51
+ $LOAD_PATH.shift
52
+ end
53
+ end
54
+ return rv
55
+ end
56
+
57
+ # Returns the lpath for the module. If any arguments are given,
58
+ # they will be joined to the end of the path using
59
+ # <tt>File.join</tt>.
60
+ #
61
+ def self.path( *args, &block )
62
+ rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
63
+ if block
64
+ begin
65
+ $LOAD_PATH.unshift PATH
66
+ rv = block.call
67
+ ensure
68
+ $LOAD_PATH.shift
69
+ end
70
+ end
71
+ return rv
72
+ end
73
+
74
+ # Utility method used to require all files ending in .rb that lie in the
75
+ # directory below this file that has the same name as the filename passed
76
+ # in. Optionally, a specific _directory_ name can be passed in such that
77
+ # the _filename_ does not have to be equivalent to the directory.
78
+ #
79
+ def self.require_all_libs_relative_to( fname, dir = nil )
80
+ dir ||= ::File.basename(fname, '.*')
81
+ search_me = ::File.expand_path(
82
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
83
+
84
+ Dir.glob(search_me).reject{|fn| fn =~ /cucumber_steps.rb$/}.sort.each {|rb| require rb}
85
+ end
86
+
87
+ LogicError = Class.new(::Exception)
88
+ SystemError = Class.new(RuntimeError)
89
+ TimeoutError = Class.new(SystemError)
90
+ ClientError = Class.new(RuntimeError)
91
+ StateError = Class.new(ClientError)
92
+
93
+ # This class offers a pass-through << operator and saves the most recent 256
94
+ # bytes which have passed through.
95
+ class TranscriptHistoryBuffer
96
+ attr_reader :buffer
97
+
98
+ def initialize(transcript)
99
+ @buffer = String.new
100
+ @transcript = transcript
101
+ end
102
+
103
+ def <<(output)
104
+ @buffer << output
105
+ @transcript << output
106
+ length = [@buffer.length, 256].min
107
+ @buffer = @buffer[-length, length]
108
+ self
109
+ end
110
+ end
111
+
112
+ def Trigger(event, *args, &block)
113
+ klass = trigger_class_for_event(event)
114
+ klass.new(*args, &block)
115
+ end
116
+
117
+ def trigger_class_for_event(event)
118
+ ::Greenletters.const_get("#{event.to_s.capitalize}Trigger")
119
+ end
120
+
121
+ class Trigger
122
+ attr_accessor :time_to_live
123
+ attr_accessor :exclusive
124
+ attr_accessor :logger
125
+ attr_accessor :interruption
126
+
127
+ alias_method :exclusive?, :exclusive
128
+
129
+ def initialize(options={}, &block)
130
+ @block = block || lambda{}
131
+ @exclusive = options.fetch(:exclusive) { false }
132
+ @logger = ::Logger.new($stdout)
133
+ @interruption = :none
134
+ end
135
+
136
+ def call(process)
137
+ @block.call(process)
138
+ true
139
+ end
140
+ end
141
+
142
+ class OutputTrigger < Trigger
143
+ def initialize(pattern=//, options={}, &block)
144
+ super(options, &block)
145
+ @pattern = pattern
146
+ end
147
+
148
+ def to_s
149
+ "output matching #{@pattern.inspect}"
150
+ end
151
+
152
+ def call(process)
153
+ scanner = process.output_buffer
154
+ @logger.debug "matching #{@pattern.inspect} against #{scanner.rest.inspect}"
155
+ if scanner.scan_until(@pattern)
156
+ @logger.debug "matched #{@pattern.inspect}"
157
+ @block.call(process, scanner)
158
+ true
159
+ else
160
+ false
161
+ end
162
+ end
163
+ end
164
+
165
+ class TimeoutTrigger < Trigger
166
+ def to_s
167
+ "timeout"
168
+ end
169
+
170
+ def call(process)
171
+ @block.call(process, process.blocker)
172
+ true
173
+ end
174
+ end
175
+
176
+ class ExitTrigger < Trigger
177
+ attr_reader :pattern
178
+
179
+ def initialize(pattern=0, options={}, &block)
180
+ super(options, &block)
181
+ @pattern = pattern
182
+ end
183
+
184
+ def call(process)
185
+ if pattern === process.status.exitstatus
186
+ @block.call(process, process.status)
187
+ true
188
+ else
189
+ false
190
+ end
191
+ end
192
+
193
+ def to_s
194
+ "exit with status #{pattern}"
195
+ end
196
+ end
197
+
198
+ class UnsatisfiedTrigger < Trigger
199
+ def to_s
200
+ "unsatisfied wait"
201
+ end
202
+
203
+ def call(process)
204
+ @block.call(process, process.interruption, process.blocker)
205
+ true
206
+ end
207
+ end
208
+
209
+ class Process
210
+ END_MARKER = '__GREENLETTERS_PROCESS_ENDED__'
211
+
212
+ # Shamelessly stolen from Rake
213
+ RUBY_EXT =
214
+ ((Config::CONFIG['ruby_install_name'] =~ /\.(com|cmd|exe|bat|rb|sh)$/) ?
215
+ "" :
216
+ Config::CONFIG['EXEEXT'])
217
+ RUBY = File.join(
218
+ Config::CONFIG['bindir'],
219
+ Config::CONFIG['ruby_install_name'] + RUBY_EXT).
220
+ sub(/.*\s.*/m, '"\&"')
221
+
222
+ extend Forwardable
223
+ include ::Greenletters
224
+
225
+ attr_reader :command # Command to run in a subshell
226
+ attr_accessor :blocker # The Trigger currently being waited for, if any
227
+ attr_reader :input_buffer # Input waiting to be written to process
228
+ attr_reader :output_buffer # Output ready to be read from process
229
+ attr_reader :status # :not_started -> :running -> :ended -> :exited
230
+ attr_reader :cwd # Working directory for the command
231
+
232
+ def_delegators :input_buffer, :puts, :write, :print, :printf, :<<
233
+ def_delegators :output_buffer, :read, :readpartial, :read_nonblock, :gets,
234
+ :getline
235
+ def_delegators :blocker, :interruption, :interruption=
236
+
237
+ def initialize(*args)
238
+ options = if args.last.is_a?(Hash) then args.pop else {} end
239
+ @command = args
240
+ @triggers = []
241
+ @blocker = nil
242
+ @input_buffer = StringIO.new
243
+ @output_buffer = StringScanner.new("")
244
+ @env = options.fetch(:env) {{}}
245
+ @cwd = options.fetch(:cwd) {Dir.pwd}
246
+ @logger = options.fetch(:logger) {
247
+ l = ::Logger.new($stdout)
248
+ l.level = ::Logger::WARN
249
+ l
250
+ }
251
+ @state = :not_started
252
+ @shell = options.fetch(:shell) { '/bin/sh' }
253
+ @transcript = options.fetch(:transcript) {
254
+ t = Object.new
255
+ def t.<<(*)
256
+ # NOOP
257
+ end
258
+ t
259
+ }
260
+ @history = TranscriptHistoryBuffer.new(@transcript)
261
+ end
262
+
263
+ def on(event, *args, &block)
264
+ t = add_trigger(event, *args, &block)
265
+ end
266
+
267
+ def wait_for(event, *args, &block)
268
+ raise "Already waiting for #{blocker}" if blocker
269
+ t = add_blocking_trigger(event, *args, &block)
270
+ process_events
271
+ rescue
272
+ unblock!
273
+ triggers.delete(t)
274
+ raise
275
+ end
276
+
277
+ def add_trigger(event, *args, &block)
278
+ t = Trigger(event, *args, &block)
279
+ t.logger = @logger
280
+ triggers << t
281
+ @logger.debug "added trigger on #{t}"
282
+ t
283
+ end
284
+
285
+ def prepend_trigger(event, *args, &block)
286
+ t = Trigger(event, *args, &block)
287
+ t.logger = @logger
288
+ triggers.unshift(t)
289
+ @logger.debug "prepended trigger on #{t}"
290
+ t
291
+ end
292
+
293
+
294
+ def add_blocking_trigger(event, *args, &block)
295
+ t = add_trigger(event, *args, &block)
296
+ t.time_to_live = 1
297
+ @logger.debug "waiting for #{t}"
298
+ self.blocker = t
299
+ t
300
+ end
301
+
302
+ def start!
303
+ raise StateError, "Already started!" unless not_started?
304
+ @logger.debug "installing end marker handler for #{END_MARKER}"
305
+ prepend_trigger(:output, /#{END_MARKER}/, :exclusive => false, :time_to_live => 1) do |process, data|
306
+ handle_end_marker
307
+ end
308
+ handle_child_exit do
309
+ cmd = wrapped_command
310
+ @logger.debug "executing #{cmd.join(' ')}"
311
+ merge_environment(@env) do
312
+ @logger.debug "command environment:\n#{ENV.inspect}"
313
+ @output, @input, @pid = PTY.spawn(*cmd)
314
+ end
315
+ @state = :running
316
+ @logger.debug "spawned pid #{@pid}"
317
+ end
318
+ end
319
+
320
+ def flush_output_buffer!
321
+ @logger.debug "flushing output buffer"
322
+ @output_buffer.terminate
323
+ end
324
+
325
+ def alive?
326
+ ::Process.kill(0, @pid)
327
+ true
328
+ rescue Errno::ESRCH, Errno::ENOENT
329
+ false
330
+ end
331
+
332
+ def blocked?
333
+ @blocker
334
+ end
335
+
336
+ def running?
337
+ @state == :running
338
+ end
339
+
340
+ def not_started?
341
+ @state == :not_started
342
+ end
343
+
344
+ def exited?
345
+ @state == :exited
346
+ end
347
+
348
+ # Have we seen the end marker yet?
349
+ def ended?
350
+ @state == :ended
351
+ end
352
+
353
+ private
354
+
355
+ attr_reader :triggers
356
+
357
+ def wrapped_command
358
+ [RUBY,
359
+ '-C', cwd,
360
+ '-e', "system(*#{command.inspect})",
361
+ '-e', "puts(#{END_MARKER.inspect})",
362
+ '-e', "gets",
363
+ '-e', "exit $?.exitstatus"
364
+ ]
365
+ end
366
+
367
+ def process_events
368
+ raise StateError, "Process not started!" if not_started?
369
+ handle_child_exit do
370
+ while blocked?
371
+ @logger.debug "select()"
372
+ input_handles = input_buffer.string.empty? ? [] : [@input]
373
+ output_handles = [@output]
374
+ error_handles = [@input, @output]
375
+ @logger.debug "select() on #{[output_handles, input_handles, error_handles].inspect}"
376
+ ready_handles = IO.select(
377
+ output_handles, input_handles, error_handles, 1.0)
378
+ if ready_handles.nil?
379
+ process_timeout
380
+ else
381
+ ready_outputs, ready_inputs, ready_errors = *ready_handles
382
+ ready_errors.each do |handle| process_error(handle) end
383
+ ready_outputs.each do |handle| process_output(handle) end
384
+ ready_inputs.each do |handle| process_input(handle) end
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ def process_input(handle)
391
+ @logger.debug "input ready #{handle.inspect}"
392
+ handle.write(input_buffer.string)
393
+ @logger.debug format_output_for_log(input_buffer.string)
394
+ @logger.debug "wrote #{input_buffer.string.size} bytes"
395
+ input_buffer.string = ""
396
+ end
397
+
398
+ def process_output(handle)
399
+ @logger.debug "output ready #{handle.inspect}"
400
+ data = handle.readpartial(1024)
401
+ output_buffer << data
402
+ @history << data
403
+ @logger.debug format_input_for_log(data)
404
+ @logger.debug "read #{data.size} bytes"
405
+ handle_triggers(:output)
406
+ flush_triggers!(OutputTrigger) if ended?
407
+ # flush_output_buffer! unless ended?
408
+ end
409
+
410
+ def collect_remaining_output
411
+ if @output.nil?
412
+ @logger.debug "unable to collect output for missing output handle"
413
+ return
414
+ end
415
+ @logger.debug "collecting remaining output"
416
+ while data = @output.read_nonblock(1024)
417
+ output_buffer << data
418
+ @logger.debug "read #{data.size} bytes"
419
+ end
420
+ rescue EOFError, Errno::EIO => error
421
+ @logger.debug error.message
422
+ end
423
+
424
+ def wait_for_child_to_die
425
+ # Soon we should get a PTY::ChildExited
426
+ while running? || ended?
427
+ @logger.debug "waiting for child #{@pid} to die"
428
+ sleep 0.1
429
+ end
430
+ end
431
+
432
+ def process_error(handle)
433
+ @logger.debug "error on #{handle.inspect}"
434
+ raise NotImplementedError, "process_error()"
435
+ end
436
+
437
+ def process_timeout
438
+ @logger.debug "timeout"
439
+ handle_triggers(:timeout)
440
+ process_interruption(:timeout)
441
+ end
442
+
443
+ def handle_exit(status=status_from_waitpid)
444
+ return false if exited?
445
+ @logger.debug "handling exit of process #{@pid}"
446
+ @state = :exited
447
+ @status = status
448
+ handle_triggers(:exit)
449
+ if status == 0
450
+ process_interruption(:exit)
451
+ else
452
+ process_interruption(:abnormal_exit)
453
+ end
454
+ end
455
+
456
+ def status_from_waitpid
457
+ @logger.debug "waiting for exist status of #{@pid}"
458
+ ::Process.waitpid2(@pid)[1]
459
+ end
460
+
461
+ def handle_triggers(event)
462
+ klass = trigger_class_for_event(event)
463
+ matches = 0
464
+ triggers.grep(klass).each do |t|
465
+ @logger.debug "checking #{event} against #{t}"
466
+ if t.call(self) # match
467
+ matches += 1
468
+ @logger.debug "match trigger #{t}"
469
+ if blocker.equal?(t)
470
+ unblock!
471
+ end
472
+ if t.time_to_live
473
+ if t.time_to_live > 1
474
+ t.time_to_live -= 1
475
+ @logger.debug "trigger ttl reduced to #{t.time_to_live}"
476
+ else
477
+ triggers.delete(t)
478
+ @logger.debug "trigger removed"
479
+ end
480
+ end
481
+ break if t.exclusive?
482
+ else
483
+ @logger.debug "no match"
484
+ end
485
+ end
486
+ matches > 0
487
+ end
488
+
489
+ def handle_end_marker
490
+ return false if ended?
491
+ @logger.debug "end marker found"
492
+ output_buffer.string.gsub!(/#{END_MARKER}\s*/, '')
493
+ output_buffer.unscan
494
+ @state = :ended
495
+ @logger.debug "end marker expunged from output buffer"
496
+ @logger.debug "acknowledging end marker"
497
+ self.puts
498
+ end
499
+
500
+ def unblock!
501
+ @logger.debug "unblocked"
502
+ triggers.delete(@blocker)
503
+ @blocker = nil
504
+ end
505
+
506
+ def handle_child_exit
507
+ handle_eio do
508
+ yield
509
+ end
510
+ rescue PTY::ChildExited => error
511
+ @logger.debug "caught PTY::ChildExited"
512
+ collect_remaining_output
513
+ handle_exit(error.status)
514
+ end
515
+
516
+ def handle_eio
517
+ yield
518
+ rescue Errno::EIO => error
519
+ @logger.debug "Errno::EIO caught"
520
+ wait_for_child_to_die
521
+ end
522
+
523
+ def flush_triggers!(kind)
524
+ @logger.debug "flushing triggers matching #{kind}"
525
+ triggers.delete_if{|t| kind === t}
526
+ end
527
+
528
+ def merge_environment(new_env)
529
+ old_env = new_env.inject({}) do |old, (key, value)|
530
+ old[key] = ENV[key]
531
+ ENV[key] = value
532
+ old
533
+ end
534
+ yield
535
+ ensure
536
+ old_env.each_pair do |key, value|
537
+ if value.nil? then ENV.delete(key) else ENV[key] = value end
538
+ end
539
+ end
540
+
541
+ def process_interruption(reason)
542
+ if blocked?
543
+ self.interruption = reason
544
+ unless handle_triggers(:unsatisfied)
545
+ raise SystemError,
546
+ "Interrupted (#{reason}) while waiting for #{blocker}.\n" \
547
+ "Recent activity:\n" +
548
+ @history.buffer
549
+ end
550
+ unblock!
551
+ end
552
+ end
553
+
554
+ def format_output_for_log(text)
555
+ "\n" + text.split("\n").map{|l| ">> #{l}"}.join("\n")
556
+ end
557
+
558
+ def format_input_for_log(text)
559
+ "\n" + text.split("\n").map{|l| "<< #{l}"}.join("\n")
560
+ end
561
+
562
+ end
563
+ end
564
+
565
+ Greenletters.require_all_libs_relative_to(__FILE__)
566
+
data/script/console ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
3
+ require 'greenletters'
4
+ require 'irb'
5
+ IRB.start
@@ -0,0 +1,6 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Greenletters do
5
+ end
6
+
@@ -0,0 +1,15 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib greenletters]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
File without changes
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: greenletters
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Avdi Grimm
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-19 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bones
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 4
30
+ - 7
31
+ version: 3.4.7
32
+ type: :development
33
+ version_requirements: *id001
34
+ description: " Greenletterrs is a console automation framework, similar to the classic\n utility Expect. You give it a command to execute, and tell it which outputs\n or events to expect and how to respond to them.\n\n Greenletters also includes a set of Cucumber steps which simplify the task\n of spcifying interactive command-line applications.\n"
35
+ email: avdi@avdi.org
36
+ executables:
37
+ - greenletters
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - History.txt
42
+ - bin/greenletters
43
+ - version.txt
44
+ files:
45
+ - .gitignore
46
+ - History.txt
47
+ - README.org
48
+ - Rakefile
49
+ - bin/greenletters
50
+ - examples/adventure.rb
51
+ - examples/cucumber/adventure.feature
52
+ - examples/cucumber/greenletters.log
53
+ - examples/cucumber/support/env.rb
54
+ - lib/greenletters.rb
55
+ - lib/greenletters/cucumber_steps.rb
56
+ - script/console
57
+ - spec/greenletters_spec.rb
58
+ - spec/spec_helper.rb
59
+ - test/test_greenletters.rb
60
+ - version.txt
61
+ has_rdoc: true
62
+ homepage: http://github.com/avdi/greenletters
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --main
68
+ - README.org
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project: greenletters
88
+ rubygems_version: 1.3.6
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: A Ruby console automation framework a la Expect
92
+ test_files:
93
+ - test/test_greenletters.rb