campfire-bot_alexchee 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.autotest +11 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +12 -0
  4. data/README.textile +62 -0
  5. data/TODO +72 -0
  6. data/bin/campfire-bot +59 -0
  7. data/campfire-bot.gemspec +24 -0
  8. data/cfbot-stop.sh +8 -0
  9. data/config.example.yml +32 -0
  10. data/lib/bot.rb +194 -0
  11. data/lib/event.rb +114 -0
  12. data/lib/message.rb +30 -0
  13. data/lib/plugin.rb +77 -0
  14. data/lib/version.rb +3 -0
  15. data/plugins-example/fun.rb +95 -0
  16. data/spec/command_spec.rb +96 -0
  17. data/spec/plugin_spec.rb +43 -0
  18. data/spec/spec.opts +1 -0
  19. data/tmp/.gitignore +0 -0
  20. data/vendor/escape/ChangeLog +30 -0
  21. data/vendor/escape/Makefile +5 -0
  22. data/vendor/escape/README +81 -0
  23. data/vendor/escape/VERSION +1 -0
  24. data/vendor/escape/escape.rb +302 -0
  25. data/vendor/escape/install.rb +109 -0
  26. data/vendor/escape/misc/README.erb +85 -0
  27. data/vendor/escape/rdoc/classes/Escape/HTMLAttrValue.html +113 -0
  28. data/vendor/escape/rdoc/classes/Escape/HTMLEscaped.html +113 -0
  29. data/vendor/escape/rdoc/classes/Escape/PercentEncoded.html +113 -0
  30. data/vendor/escape/rdoc/classes/Escape/ShellEscaped.html +113 -0
  31. data/vendor/escape/rdoc/classes/Escape/StringWrapper.html +242 -0
  32. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000029.html +18 -0
  33. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000030.html +18 -0
  34. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000031.html +18 -0
  35. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000032.html +18 -0
  36. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000033.html +18 -0
  37. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000035.html +18 -0
  38. data/vendor/escape/rdoc/classes/Escape.html +427 -0
  39. data/vendor/escape/rdoc/classes/Escape.src/M000022.html +19 -0
  40. data/vendor/escape/rdoc/classes/Escape.src/M000023.html +32 -0
  41. data/vendor/escape/rdoc/classes/Escape.src/M000024.html +24 -0
  42. data/vendor/escape/rdoc/classes/Escape.src/M000025.html +19 -0
  43. data/vendor/escape/rdoc/classes/Escape.src/M000026.html +48 -0
  44. data/vendor/escape/rdoc/classes/Escape.src/M000027.html +19 -0
  45. data/vendor/escape/rdoc/classes/Escape.src/M000028.html +19 -0
  46. data/vendor/escape/rdoc/classes/TestEscapeHTML.html +182 -0
  47. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000008.html +18 -0
  48. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000009.html +18 -0
  49. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000010.html +18 -0
  50. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000011.html +18 -0
  51. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.html +182 -0
  52. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000012.html +18 -0
  53. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000013.html +19 -0
  54. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000014.html +20 -0
  55. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000015.html +22 -0
  56. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.html +167 -0
  57. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000016.html +18 -0
  58. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000017.html +20 -0
  59. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000018.html +20 -0
  60. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.html +167 -0
  61. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000019.html +20 -0
  62. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000020.html +24 -0
  63. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000021.html +22 -0
  64. data/vendor/escape/rdoc/files/escape_rb.html +136 -0
  65. data/vendor/escape/rdoc/files/install_rb.html +250 -0
  66. data/vendor/escape/rdoc/files/install_rb.src/M000001.html +23 -0
  67. data/vendor/escape/rdoc/files/install_rb.src/M000002.html +31 -0
  68. data/vendor/escape/rdoc/files/install_rb.src/M000003.html +27 -0
  69. data/vendor/escape/rdoc/files/install_rb.src/M000004.html +27 -0
  70. data/vendor/escape/rdoc/files/install_rb.src/M000005.html +21 -0
  71. data/vendor/escape/rdoc/files/install_rb.src/M000006.html +23 -0
  72. data/vendor/escape/rdoc/files/install_rb.src/M000007.html +21 -0
  73. data/vendor/escape/rdoc/files/test/test-escape_rb.html +109 -0
  74. data/vendor/escape/rdoc/fr_class_index.html +36 -0
  75. data/vendor/escape/rdoc/fr_file_index.html +29 -0
  76. data/vendor/escape/rdoc/fr_method_index.html +61 -0
  77. data/vendor/escape/rdoc/index.html +24 -0
  78. data/vendor/escape/rdoc/rdoc-style.css +208 -0
  79. data/vendor/escape/test/test-escape.rb +90 -0
  80. metadata +209 -0
data/lib/plugin.rb ADDED
@@ -0,0 +1,77 @@
1
+ module CampfireBot
2
+ class Plugin
3
+ @registered_plugins = {}
4
+
5
+ @registered_commands = []
6
+ @registered_messages = []
7
+ @registered_speakers = []
8
+ @registered_intervals = []
9
+ @registered_times = []
10
+
11
+ class << self
12
+ attr_reader :registered_plugins,
13
+ :registered_commands,
14
+ :registered_messages,
15
+ :registered_speakers,
16
+ :registered_intervals,
17
+ :registered_times
18
+
19
+ @@config_defaults = {}
20
+
21
+ # Registering plugins
22
+
23
+ def inherited(child)
24
+ Plugin.registered_plugins[child.to_s] = child
25
+ end
26
+
27
+ # Event handlers
28
+
29
+ def on_command(command, *methods)
30
+ methods.each do |method|
31
+ Plugin.registered_commands << Event::Command.new(command, self.to_s, method)
32
+ end
33
+ end
34
+
35
+ def on_message(regexp, *methods)
36
+ methods.each do |method|
37
+ Plugin.registered_messages << Event::Message.new(regexp, self.to_s, method)
38
+ end
39
+ end
40
+
41
+ def on_speaker(speaker, *methods)
42
+ methods.each do |method|
43
+ Plugin.registered_speakers << Event::Speaker.new(speaker, self.to_s, method)
44
+ end
45
+ end
46
+
47
+ def at_interval(interval, *methods)
48
+ methods.each do |method|
49
+ Plugin.registered_intervals << Event::Interval.new(interval, self.to_s, method)
50
+ end
51
+ end
52
+
53
+ def at_time(timestamp, *methods)
54
+ methods.each do |method|
55
+ Plugin.registered_times << Event::Time.new(timestamp, self.to_s, method)
56
+ end
57
+ end
58
+
59
+ # Declare a plugin configuration parameter with its default value
60
+ def config_var(name, default)
61
+ attr_reader name
62
+ @@config_defaults ||= {}
63
+ @@config_defaults[self.name] ||= {}
64
+ @@config_defaults[self.name][name] = default
65
+ end
66
+ end
67
+ def initialize
68
+ # initialize attr_readers setup with config_var
69
+ config_prefix = self.class.to_s.underscore
70
+ (@@config_defaults[self.class.name] || {}).each_pair { |name, default|
71
+ instance_variable_set("@#{name.to_s}",
72
+ bot.config["#{config_prefix}_#{name.to_s}"] ||
73
+ default)
74
+ }
75
+ end
76
+ end
77
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module CampfireBot
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,95 @@
1
+ class Fun < CampfireBot::Plugin
2
+ on_command 'say', :say
3
+ on_message Regexp.new("^#{bot.config['nickname']},\\s+(should|can|will|shall) (i|he|she|we|they) do it\\?", Regexp::IGNORECASE), :do_or_do_not
4
+ on_message Regexp.new("^(good morning|morning|m0ink|hello|hi|hey|whassup|what's up|yo|hola|ola|'sup|sup)(,)*\\s*(#{bot.config['nickname']}).*$", Regexp::IGNORECASE), :greet
5
+ on_message /(how's it|how are|how're) (ya |you )*(going|doing|doin).*/, :howareya
6
+ on_command "blame", :blame
7
+ on_command "trout", :trout
8
+ on_command "slap", :trout
9
+ on_command "troutslap", :trout
10
+ # on_speaker 'Tim R.', :agree_with_tim
11
+ # on_message /undo it/i, :do_it
12
+ # on_message /(^|\s)do it/i, :undo_it
13
+ # at_time 1.minute.from_now, :do_it
14
+
15
+ def initialize
16
+ @last_agreed = 20.minutes.ago
17
+ @log = Logging.logger["CampfireBot::Plugin::Fun"]
18
+ end
19
+
20
+ def say(m)
21
+ m.speak(m[:message])
22
+ end
23
+
24
+ def do_it(m = nil)
25
+ m.speak('Do it!')
26
+ end
27
+
28
+ def undo_it(m)
29
+ m.speak('Undo it!')
30
+ end
31
+
32
+ def do_or_do_not(m)
33
+ responses = ['Do it!', 'Don\'t do it!', 'Undo it!']
34
+ m.speak(responses.choice)
35
+ end
36
+
37
+ def agree_with_tim(m)
38
+ m.speak('I agree with Tim.') unless @last_agreed > 15.minutes.ago
39
+ @last_agreed = Time.now
40
+ end
41
+
42
+ def greet(m)
43
+ messages = ['Howdy', 'Wassup', 'Greets', 'Hello', 'Hey there', "It's a", 'Good day']
44
+ m.speak("#{messages.choice} #{m[:person].split(' ')[0]}")
45
+ end
46
+
47
+ def howareya(m)
48
+ messages = ["just great", "peachy", "mas o menos",
49
+ "you know how it is", "eh, ok", "pretty good. how about you?"]
50
+ m.speak(messages[rand(messages.size)])
51
+ end
52
+
53
+ def blame(m)
54
+ # TODO: capture user-submitted entries to a yaml file and regurgitate them
55
+ # TODO: put all the default ones in a separate yaml
56
+ if m[:message].strip.length > 0
57
+ blamed = m[:message].strip
58
+ else
59
+ users = m[:room].users.delete_if {|u| u[:name] == bot.campfire.me[:name]}.map {|u| u[:name]}
60
+ others = ["nobody", "my", "Microsoft", "Steve Jobs", "the terrorists", "your",
61
+ "Project Management", "Development", "Management", "Corporate", "Cartman", "the user",
62
+ "the liberal media", "Wall Street"]
63
+
64
+ # mostly blame the other users
65
+ if rand(10) >= 2
66
+ blamed = users.choice
67
+ else
68
+ blamed = others.choice
69
+ end
70
+
71
+ end
72
+
73
+ case blamed
74
+ when "nobody"
75
+ blamestring = "It's nobody's fault"
76
+ when "your", "my"
77
+ blamestring = "It's all #{blamed} fault"
78
+ else
79
+ blamestring = "It's all #{blamed}'s fault"
80
+ blamestring = "It's all #{blamed}' fault" if blamed[-1].chr == "s"
81
+ end
82
+
83
+ m.speak blamestring
84
+ end
85
+
86
+ def trout(m)
87
+ if m[:message].strip.length > 0
88
+ selected_user_name = m[:message].strip
89
+ else
90
+ users = m[:room].users.map{|u| u[:name] }
91
+ selected_user_name = users.choice
92
+ end
93
+ m.speak("#{m[:person]} slaps #{selected_user_name} #{["upside the head", "in the face", "on the rear", "where it counts", "in the knees", "ineffectually", "in the elbow", "on the funny bone", "in the ear", "on the nose", "in the teeth"].choice} with a #{%w(good-sized large decaying moldy spiked sabre-toothed surprised disappointed dramatic enraged rabid bug-eyed rotten foul-smelling demonic cluestick-holding).choice} trout")
94
+ end
95
+ end
@@ -0,0 +1,96 @@
1
+ require 'rspec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'development'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ bot = CampfireBot::Bot.instance
7
+ require "#{BOT_ROOT}/lib/event.rb"
8
+
9
+
10
+ class TestingCommand < CampfireBot::Event::Command
11
+
12
+ def filter_message(msg)
13
+ super
14
+ end
15
+ end
16
+
17
+ describe "processing messages" do
18
+
19
+ before(:all) do
20
+ bot = CampfireBot::Bot.instance
21
+ @nickname = bot.config['nickname']
22
+ end
23
+
24
+ before(:each) do
25
+ @command = TestingCommand.new("command", nil, nil)
26
+ end
27
+
28
+ def match?(msg)
29
+ @command.match?({:message => msg})
30
+ end
31
+
32
+ describe "and recognizing a command" do
33
+
34
+ it "should handle a !command" do
35
+ match?("!command").should be_true
36
+ end
37
+
38
+ it "should handle a !command with arguments" do
39
+ match?("!command foo").should be_true
40
+ end
41
+
42
+ it "should handle a command with nickname and a comma" do
43
+ match?("#{@nickname}, command").should be_true
44
+ end
45
+
46
+ it "should handle a command with nickname and a colon" do
47
+ match?("#{@nickname}: command").should be_true
48
+ end
49
+
50
+ it "should handle a command with nickname and arguments" do
51
+ match?("#{@nickname}, command foo").should be_true
52
+ end
53
+
54
+ it "should ignore a non-matching !command" do
55
+ match?("!foo").should be_false
56
+ end
57
+
58
+ it "should ignore an addressed non-command" do
59
+ match?("#{@nickname}, nothing").should be_false
60
+ end
61
+
62
+ it "should ignore things that aren't commands at all" do
63
+ ["nothing", "#{@nickname}, ", " ! command", "hey #{@nickname}", "!command!command", "!command,command"].each do |t|
64
+ match?(t).should be_false
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "and filtering it" do
70
+
71
+ def filter(msg)
72
+ @command.filter_message({:message => msg})[:message]
73
+ end
74
+
75
+ it "should be empty with no arguments" do
76
+ filter("!command").should == ""
77
+ filter("#{@nickname}, command").should == ""
78
+ end
79
+
80
+ it "should return one argument" do
81
+ filter("!command foo").should == "foo"
82
+ filter("#{@nickname}, command foo").should == "foo"
83
+ end
84
+
85
+ it "should return more than one argument" do
86
+ filter("!command foo bar baz").should == "foo bar baz"
87
+ filter("#{@nickname}, command foo bar baz").should == "foo bar baz"
88
+ end
89
+
90
+ it "should deal with some weirdness" do
91
+ filter("!command !command").should == "!command"
92
+ end
93
+
94
+ end
95
+ end
96
+
@@ -0,0 +1,43 @@
1
+ require 'rspec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'test'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ bot = CampfireBot::Bot.instance
7
+
8
+ describe "config_var method" do
9
+ class ExamplePlugin < CampfireBot::Plugin
10
+ config_var :foo, "default foo"
11
+ end
12
+
13
+ def setup_plugin(klass, config={})
14
+ @bot = CampfireBot::Bot.instance
15
+ @bot.stub!(:config).and_return({'nickname' => 'Bot'}.merge(config))
16
+ @plugin = klass.new
17
+ CampfireBot::Plugin.registered_plugins[klass.to_s] = @plugin
18
+ end
19
+
20
+ it "should setup default bug_url value" do
21
+ setup_plugin ExamplePlugin
22
+ @plugin.foo.should == "default foo"
23
+ end
24
+
25
+ it "should allow override of parameter via configuration" do
26
+ setup_plugin ExamplePlugin, 'example_plugin_foo' => 'bar'
27
+ @plugin.foo.should == "bar"
28
+ end
29
+
30
+ it "should keep defaults for two classes separate" do
31
+ class ExamplePlugin2 < CampfireBot::Plugin
32
+ config_var :bar, "default bar"
33
+ end
34
+ setup_plugin ExamplePlugin
35
+ plugin = @plugin
36
+ setup_plugin ExamplePlugin2
37
+ plugin.instance_variable_get(:@foo).should == "default foo"
38
+ @plugin.instance_variable_get(:@bar).should == "default bar"
39
+ # Used to fail with value "default bar"
40
+ plugin.instance_variable_get(:@bar).should == nil
41
+ @plugin.instance_variable_get(:@foo).should == nil
42
+ end
43
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
data/tmp/.gitignore ADDED
File without changes
@@ -0,0 +1,30 @@
1
+ 2007-02-28 Tanaka Akira <akr@fsij.org>
2
+
3
+ * escape.rb: Escape::HTMLAttrValue defined.
4
+ Escape.html_attr_value returns it.
5
+
6
+ 2007-02-27 Tanaka Akira <akr@fsij.org>
7
+
8
+ * escape.rb: make StringWrapper into class.
9
+ Escape::ShellEscaped, Escape::HTMLEscaped and Escape::PercentEncoded
10
+ inherit it.
11
+
12
+ 2007-02-26 Tanaka Akira <akr@fsij.org>
13
+
14
+ * escape.rb: Escape::ShellEscaped defined.
15
+ Escape.shell_command and Escape.shell_single_word returns
16
+ Escape::ShellEscaped object instead of a string.
17
+
18
+ * escape.rb: Escape::HTMLEscaped defined.
19
+ Escape.html_text and Escape.html_attr_value returns
20
+ Escape::HTMLEscaped object instead of a string.
21
+
22
+ * escape.rb: Escape::PercentEncoded defined.
23
+ Escape.uri_segment, Escape.uri_path and Escape.html_form returns
24
+ Escape::PercentEncoded object instead of a string.
25
+
26
+ * escape.rb: rename Escape.html_attr to Escape.html_attr_value.
27
+
28
+ 2007-01-05 Tanaka Akira <akr@fsij.org>
29
+
30
+ * version 0.1 released.
@@ -0,0 +1,5 @@
1
+ rdoc:
2
+ rdoc --op rdoc escape.rb
3
+
4
+ README: misc/README.erb
5
+ erb misc/README.erb > README
@@ -0,0 +1,81 @@
1
+ = escape - HTML/URI/shell escaping utilities
2
+
3
+
4
+ escape library provides several HTML/URI/shell escaping functions.
5
+
6
+ == Author
7
+
8
+ Tanaka Akira <akr@fsij.org>
9
+
10
+ == Home Page
11
+
12
+ ((<URL:http://www.a-k-r.org/escape/>))
13
+
14
+ == Feature
15
+
16
+ * several escaping/composing functions
17
+ * HTML text
18
+ * HTML attribute value
19
+ * HTML form (x-www-form-urlencoded)
20
+ * URI path
21
+ * shell command line
22
+ * dedicated classes for escaped strings
23
+ * escape and compose strongly related strings at once
24
+
25
+ == Usage
26
+
27
+ require 'escape'
28
+
29
+ Escape.shell_command(["echo", "*"]) #=> #<Escape::ShellEscaped: echo '*'>
30
+ Escape.uri_path("a?b/c?d/e?f") #=> #<Escape::PercentEncoded: a%3Fb/c%3Fd/e%3Ff>
31
+ Escape.html_form([["a","b"], ["c","d"]]) #=> #<Escape::PercentEncoded: a=b&c=d>
32
+ Escape.html_form({"a"=>"b", "c"=>"d"}) #=> #<Escape::PercentEncoded: a=b&c=d>
33
+ Escape.html_text("a & b < c > d") #=> #<Escape::HTMLEscaped: a &amp; b &lt; c &gt; d>
34
+ Escape.html_attr_value("ab&<>\"c") #=> #<Escape::HTMLAttrValue: "ab&amp;&lt;&gt;&quot;c">
35
+
36
+ == Requirements
37
+
38
+ * ruby : http://www.ruby-lang.org/
39
+
40
+ == Download
41
+
42
+ * latest release: ((<escape-0.2.tar.gz|URL:escape-0.2.tar.gz>))
43
+
44
+ * development version in Subversion repository:
45
+
46
+ % svn co svn://svn@svn.a-k-r.org/akr/escape/trunk escape
47
+
48
+ == Install
49
+
50
+ % ruby install.rb
51
+
52
+ == Reference Manual
53
+
54
+ See rdoc/classes/Escape.html or
55
+ ((<URL:http://www.a-k-r.org/escape/rdoc/classes/Escape.html>))
56
+
57
+ == License
58
+
59
+ The modified BSD licence
60
+
61
+ Redistribution and use in source and binary forms, with or without
62
+ modification, are permitted provided that the following conditions are met:
63
+
64
+ 1. Redistributions of source code must retain the above copyright notice, this
65
+ list of conditions and the following disclaimer.
66
+ 2. Redistributions in binary form must reproduce the above copyright notice,
67
+ this list of conditions and the following disclaimer in the documentation
68
+ and/or other materials provided with the distribution.
69
+ 3. The name of the author may not be used to endorse or promote products
70
+ derived from this software without specific prior written permission.
71
+
72
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
73
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
74
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
75
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
76
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
77
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
78
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
79
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
80
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
81
+ OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ 0.2