randrews-toast 0.0.4
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/bin/toastconsole +12 -0
- data/example/hangman_responder.rb +83 -0
- data/example/simple_responder.rb +12 -0
- data/example/wait_responder.rb +6 -0
- data/lib/channel.rb +31 -0
- data/lib/console_channel.rb +96 -0
- data/lib/console_utils.rb +52 -0
- data/lib/cont.rb +14 -0
- data/lib/responder.rb +43 -0
- data/lib/test_channel.rb +20 -0
- data/lib/toast.rb +7 -0
- data/lib/util.rb +35 -0
- metadata +74 -0
data/bin/toastconsole
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
class HangmanResponder < Toast::Responder
|
|
2
|
+
attr_accessor :word
|
|
3
|
+
attr_accessor :solved_word
|
|
4
|
+
attr_accessor :alphabet
|
|
5
|
+
attr_accessor :body_parts
|
|
6
|
+
|
|
7
|
+
def say_wait msg ; say msg ; wait ; end
|
|
8
|
+
|
|
9
|
+
def respond msg
|
|
10
|
+
say 'Welcome to hangman!'
|
|
11
|
+
@alphabet='abcdefghijklmnopqrstuvwxyz'
|
|
12
|
+
@body_parts=6
|
|
13
|
+
@word=find_word
|
|
14
|
+
@solved_word='_'*word.length
|
|
15
|
+
|
|
16
|
+
say status_msg
|
|
17
|
+
|
|
18
|
+
while(@solved_word!=@word && @body_parts>0)
|
|
19
|
+
letter=get_letter
|
|
20
|
+
|
|
21
|
+
@alphabet[@alphabet.index(letter)]='_'
|
|
22
|
+
|
|
23
|
+
if @word.index(letter)
|
|
24
|
+
@word.split('').each_with_index do |l, i|
|
|
25
|
+
@solved_word[i]=letter if(l==letter)
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
@body_parts-= 1
|
|
29
|
+
say "Oops, the word doesn't contain the letter #{letter}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
say status_msg
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if(@body_parts>0)
|
|
36
|
+
"Congratulations, you win! Send any message to play again."
|
|
37
|
+
else
|
|
38
|
+
"Sorry, you were hung. The word was #{@word}. Send any message to play again."
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_letter
|
|
43
|
+
letter=say_wait "Choose a letter"
|
|
44
|
+
letter_good=false
|
|
45
|
+
|
|
46
|
+
loop do
|
|
47
|
+
letter=letter.downcase
|
|
48
|
+
|
|
49
|
+
unless letter=~/^[a-z]$/
|
|
50
|
+
letter=say_wait "That's not a letter, choose again"
|
|
51
|
+
next
|
|
52
|
+
end
|
|
53
|
+
unless @alphabet.index letter
|
|
54
|
+
letter=say_wait "You've already used that letter, choose again"
|
|
55
|
+
next
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return letter
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def find_word
|
|
63
|
+
max=(`wc -l /usr/share/dict/words`).split[0].to_i
|
|
64
|
+
line=rand(max)
|
|
65
|
+
|
|
66
|
+
word=nil
|
|
67
|
+
file=File.new('/usr/share/dict/words')
|
|
68
|
+
|
|
69
|
+
line.times do
|
|
70
|
+
word=file.gets
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
word.chomp
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def status_msg
|
|
77
|
+
"#{@solved_word.split('').join(' ')}\n#{body_part_msg} remaining\n#{@alphabet.split('').join(' ')}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def body_part_msg
|
|
81
|
+
@body_parts==1 ? "#{@body_parts} body part" : "#{@body_parts} body parts"
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/channel.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
class Channel
|
|
3
|
+
attr_accessor :responder_class
|
|
4
|
+
attr_accessor :responders
|
|
5
|
+
|
|
6
|
+
def initialize responder_class
|
|
7
|
+
@responder_class=responder_class
|
|
8
|
+
@responders={}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def handle msg
|
|
12
|
+
responder_for(msg.from).handle msg.text
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def next_msg
|
|
16
|
+
Message.new("Override #{self.class.name}.next_msg",
|
|
17
|
+
'nobody')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def responder_for from
|
|
21
|
+
unless @responders[from]
|
|
22
|
+
@responders[from]= @responder_class.new self, from
|
|
23
|
+
end
|
|
24
|
+
@responders[from]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def send msg, to
|
|
28
|
+
puts "#{to}: #{msg.text}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
class ConsoleChannel < Channel
|
|
3
|
+
def initialize responder_class
|
|
4
|
+
super responder_class
|
|
5
|
+
@hear_commands=true
|
|
6
|
+
@exit_now=false
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def send msg, to
|
|
10
|
+
puts ""
|
|
11
|
+
puts msg unless msg.nil?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def next_line
|
|
15
|
+
line = Readline::readline('> ')
|
|
16
|
+
return nil unless line
|
|
17
|
+
Readline::HISTORY.push(line)
|
|
18
|
+
line
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.run responder_class
|
|
22
|
+
channel=ConsoleChannel.new responder_class
|
|
23
|
+
channel.run
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
send "Type .exit or ctrl-D to leave",""
|
|
28
|
+
loop do
|
|
29
|
+
msg=next_line
|
|
30
|
+
break unless msg
|
|
31
|
+
handle_line msg
|
|
32
|
+
break if @exit_now
|
|
33
|
+
end
|
|
34
|
+
send nil,nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def handle_line line
|
|
38
|
+
if (line[0,1]=='.' && @hear_commands) ||
|
|
39
|
+
line=~/\.commands\s+on/
|
|
40
|
+
|
|
41
|
+
result=special_cmd line
|
|
42
|
+
return if @exit_now
|
|
43
|
+
send result,'' if result
|
|
44
|
+
|
|
45
|
+
else
|
|
46
|
+
handle Toast::Message.new(line,'console@localhost')
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def special_cmd cmd
|
|
51
|
+
if cmd=='.exit'
|
|
52
|
+
@exit_now=true
|
|
53
|
+
return nil
|
|
54
|
+
|
|
55
|
+
elsif cmd=~/^\.srand\s+([0-9]+)/
|
|
56
|
+
srand $1.to_i
|
|
57
|
+
return "Random seed is #{$1}"
|
|
58
|
+
|
|
59
|
+
elsif cmd=~/^\.commands\s+(on|off)/
|
|
60
|
+
@hear_commands=($1=='on')
|
|
61
|
+
return "Commands are #{$1}"
|
|
62
|
+
|
|
63
|
+
elsif cmd=~/^.script\s+(\S+)/
|
|
64
|
+
old_dir=@current_dir
|
|
65
|
+
|
|
66
|
+
file=$1
|
|
67
|
+
unless file=~/^\// # if it's a relative path, then tack @current_dir on
|
|
68
|
+
file=File.expand_path(@current_dir+"/"+file)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
@current_dir=File.dirname(file)
|
|
72
|
+
|
|
73
|
+
File.new(file).each do |line|
|
|
74
|
+
handle_line line.strip unless line.blank? || line=~/^\s*#/
|
|
75
|
+
break if @exit_now
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@current_dir=old_dir
|
|
79
|
+
return nil
|
|
80
|
+
|
|
81
|
+
elsif cmd=~/^.send\s+(.*)/
|
|
82
|
+
args=$1.strip.split(/\s+/)
|
|
83
|
+
fn=args.shift.to_sym
|
|
84
|
+
begin
|
|
85
|
+
response=responder_for('console@localhost').send(fn, *args)
|
|
86
|
+
rescue
|
|
87
|
+
response=$!.to_s
|
|
88
|
+
end
|
|
89
|
+
return response
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
return "Bad command #{cmd}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
module ConsoleUtils
|
|
3
|
+
def self.get_bot_class_for_name bot_name=nil
|
|
4
|
+
|
|
5
|
+
# If it's nil, show a menu for .
|
|
6
|
+
if bot_name.nil?
|
|
7
|
+
file=show_menu_for_directory '.'
|
|
8
|
+
load file
|
|
9
|
+
return class_for_file_name(file)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# If it's a file, then we just use it
|
|
13
|
+
if File.file? bot_name
|
|
14
|
+
load bot_name
|
|
15
|
+
return class_for_file_name(bot_name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# if it's not a .rb file, but is present, it's a directory
|
|
19
|
+
if File.directory? bot_name
|
|
20
|
+
file=show_menu_for_directory(bot_name)
|
|
21
|
+
load file
|
|
22
|
+
return class_for_file_name(file)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
raise "Can't find #{bot_name}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.show_menu_for_directory path
|
|
29
|
+
n=0
|
|
30
|
+
Dir.glob("#{path}/*.rb").each do |file|
|
|
31
|
+
n+=1
|
|
32
|
+
name=File.basename(file,'.rb')
|
|
33
|
+
puts "- #{name}"
|
|
34
|
+
Readline::HISTORY.push(name)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if n==0
|
|
38
|
+
path="current directory" if path=='.'
|
|
39
|
+
raise "No .rb files found in #{path}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
bot_name=Readline::readline('Which bot: ')
|
|
43
|
+
n.times {Readline::HISTORY.shift}
|
|
44
|
+
|
|
45
|
+
return "#{path}/#{bot_name}.rb"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.class_for_file_name file
|
|
49
|
+
File.basename(file,'.rb').classify.constantize
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/cont.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
##################################################
|
|
2
|
+
### Pipe: read from stdin, write to stdout #######
|
|
3
|
+
##################################################
|
|
4
|
+
|
|
5
|
+
# class StdChannel < Channel
|
|
6
|
+
# def initialize responder_class
|
|
7
|
+
# super responder_class
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
# def send msg, to
|
|
11
|
+
# puts StdChannel.escape(to)
|
|
12
|
+
# puts StdChannel.escape(msg)
|
|
13
|
+
# end
|
|
14
|
+
# end
|
data/lib/responder.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
class Responder
|
|
3
|
+
attr_accessor :from
|
|
4
|
+
|
|
5
|
+
def initialize channel, from
|
|
6
|
+
@channel=channel
|
|
7
|
+
@from=from
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def handle msg
|
|
11
|
+
callcc do |back_to_channel|
|
|
12
|
+
@back_to_channel = back_to_channel
|
|
13
|
+
|
|
14
|
+
if @leftoff
|
|
15
|
+
@leftoff.call(msg)
|
|
16
|
+
else
|
|
17
|
+
response=respond(msg)
|
|
18
|
+
say response unless response.nil?
|
|
19
|
+
@leftoff=nil
|
|
20
|
+
@back_to_channel.call
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
### Override me to handle messages!
|
|
26
|
+
def respond msg
|
|
27
|
+
say "Override #{self.class.name}.respond to have your bot do something."
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def wait
|
|
32
|
+
callcc do |cc|
|
|
33
|
+
@leftoff=cc
|
|
34
|
+
@back_to_channel.call
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def say msg
|
|
39
|
+
@channel.send msg, @from
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/test_channel.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
class TestChannel < Channel
|
|
3
|
+
attr_accessor :output
|
|
4
|
+
|
|
5
|
+
def initialize responder_class
|
|
6
|
+
super responder_class
|
|
7
|
+
self.output=[]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def send msg,to
|
|
11
|
+
@output << Message.new(msg,to)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run script
|
|
15
|
+
script.each do |text|
|
|
16
|
+
handle Message.new(text,'test@localhost')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/toast.rb
ADDED
data/lib/util.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Toast
|
|
2
|
+
Message = Struct.new(:text, :from)
|
|
3
|
+
|
|
4
|
+
class Message
|
|
5
|
+
def to_s ; @text ; end
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class String
|
|
10
|
+
def escape
|
|
11
|
+
gsub("\\","\\\\").gsub("\n","\\n")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def unescape
|
|
15
|
+
gsub("\\n","\n").gsub("\\\\","\\")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Symbol
|
|
20
|
+
def to_proc
|
|
21
|
+
Proc.new {|_| _.send self}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def delete_emacs_temp dir="."
|
|
26
|
+
Dir.glob(dir+"/*").each do |file|
|
|
27
|
+
if File.directory? file
|
|
28
|
+
delete_emacs_temp file
|
|
29
|
+
end
|
|
30
|
+
if file=~/~$/
|
|
31
|
+
puts "deleting #{file}"
|
|
32
|
+
File.delete file
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: randrews-toast
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.4
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ross Andrews
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-07-27 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: activesupport
|
|
17
|
+
type: :runtime
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 2.1.0
|
|
24
|
+
version:
|
|
25
|
+
description: A framework for making Jabber bots
|
|
26
|
+
email: randrews@geekfu.org
|
|
27
|
+
executables:
|
|
28
|
+
- toastconsole
|
|
29
|
+
extensions: []
|
|
30
|
+
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
|
|
33
|
+
files:
|
|
34
|
+
- lib/channel.rb
|
|
35
|
+
- lib/console_channel.rb
|
|
36
|
+
- lib/console_utils.rb
|
|
37
|
+
- lib/cont.rb
|
|
38
|
+
- lib/responder.rb
|
|
39
|
+
- lib/test_channel.rb
|
|
40
|
+
- lib/toast.rb
|
|
41
|
+
- lib/util.rb
|
|
42
|
+
- bin/toastconsole
|
|
43
|
+
- example/hangman_responder.rb
|
|
44
|
+
- example/simple_responder.rb
|
|
45
|
+
- example/wait_responder.rb
|
|
46
|
+
has_rdoc: false
|
|
47
|
+
homepage: http://toastwiki.yellownote.info
|
|
48
|
+
licenses:
|
|
49
|
+
post_install_message:
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: "0"
|
|
59
|
+
version:
|
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">="
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: "0"
|
|
65
|
+
version:
|
|
66
|
+
requirements: []
|
|
67
|
+
|
|
68
|
+
rubyforge_project:
|
|
69
|
+
rubygems_version: 1.3.5
|
|
70
|
+
signing_key:
|
|
71
|
+
specification_version: 2
|
|
72
|
+
summary: A framework for making Jabber bots
|
|
73
|
+
test_files: []
|
|
74
|
+
|