summer 1.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/LICENSE +20 -0
- data/README.markdown +96 -0
- data/lib/ext/array.rb +5 -0
- data/lib/ext/object.rb +5 -0
- data/lib/ext/string.rb +5 -0
- data/lib/summer.rb +149 -0
- data/lib/summer/handlers.rb +10 -0
- metadata +101 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ryan Bigg
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Summer
|
2
|
+
|
3
|
+
Summer is an IRC Bot "framework" "inspired" by [http://github.com/RISCFuture/autumn](Autumn). Its goal is to be tiny.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
The project is currently in "preview" state 'cause that's all the rage nowadays. No there's no invites, BUT everybody gets access to it.
|
8
|
+
Sorry to inform you that you'll have to clone it and then run `rake install` if you want to use it.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
To use summer, create a file like this:
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'summer'
|
16
|
+
|
17
|
+
class Bot < Summer::Connection
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
Bot.new("localhost")
|
22
|
+
|
23
|
+
Running it will make your bot attempt to connect to the server on localhost. For those of you who do not have an IRC server running locally, I would suggest trying irc.freenode.net instead.
|
24
|
+
|
25
|
+
## Configuration
|
26
|
+
|
27
|
+
In the same directory create a directory called _config_ and in that put _summer.yml_ which can have the following keys:
|
28
|
+
|
29
|
+
* nick: The nickname of the bot.
|
30
|
+
* channel: A channel to join on startup.
|
31
|
+
* channels: Channels to join on startup.
|
32
|
+
* auto_rejoin: Set this to true if you want the bot to re-join any channel it's kicked from.
|
33
|
+
|
34
|
+
## `did_start_up`
|
35
|
+
|
36
|
+
Called when the bot has received the final MOTD line (376 or 422) and has finished joining all the channels.
|
37
|
+
|
38
|
+
## `channel_message(sender, channel, message)`
|
39
|
+
|
40
|
+
Called when the bot receives a channel message.
|
41
|
+
|
42
|
+
sender (`Hash`): Contains `nick` and `hostname`
|
43
|
+
channel (`String`): The channel name: e.g. "#logga"
|
44
|
+
message (`String`): The message that was received
|
45
|
+
|
46
|
+
## `private_message(sender, bot, message)`
|
47
|
+
|
48
|
+
Called when the bot receives a private message.
|
49
|
+
|
50
|
+
sender (`Hash`): Contains `nick` and `hostname`
|
51
|
+
bot (`String`): The bot's name.
|
52
|
+
message (`String`): The message that was received
|
53
|
+
|
54
|
+
## `join(sender, channel)`
|
55
|
+
|
56
|
+
Called when the bot sees someone join a channel.
|
57
|
+
|
58
|
+
sender (`Hash`): Contains `nick` and `hostname`
|
59
|
+
channel (`String`): The channel name: e.g. "#logga"
|
60
|
+
|
61
|
+
## `part(sender, channel, message)`
|
62
|
+
|
63
|
+
Called when someone parts a channel:
|
64
|
+
|
65
|
+
sender (`Hash`): Contains `nick` and `hostname`
|
66
|
+
channel (`String`): The channel name: e.g. "#logga"
|
67
|
+
message (`String`): The message that was received
|
68
|
+
|
69
|
+
## `quit(sender, message)`
|
70
|
+
|
71
|
+
Called when someone quits the server:
|
72
|
+
|
73
|
+
sender (`Hash`): Contains `nick` and `hostname`
|
74
|
+
message (`String`): The message that was received.
|
75
|
+
|
76
|
+
|
77
|
+
## `kick(kicker, channel, victim, message)`
|
78
|
+
|
79
|
+
Called when someone quits the server:
|
80
|
+
|
81
|
+
kicker (`Hash`): Contains `nick` and `hostname`
|
82
|
+
channel (`String`): The channel name: e.g. "#logga"
|
83
|
+
victim (`String`): Just the nick of whoever was kicked.
|
84
|
+
message (`String`): The message that was received.
|
85
|
+
|
86
|
+
|
87
|
+
## Handling raw messages
|
88
|
+
|
89
|
+
If you wish to handle raw messages that come into your bot you can define a `handle_xxx` method for that where `xxx` is the three-digit representation of the raw you wish to handle.
|
90
|
+
|
91
|
+
|
92
|
+
### Upcoming
|
93
|
+
|
94
|
+
`mode` method to detect mode changes
|
95
|
+
Auto-rejoin after kick (configuration options)
|
96
|
+
|
data/lib/ext/array.rb
ADDED
data/lib/ext/object.rb
ADDED
data/lib/ext/string.rb
ADDED
data/lib/summer.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'yaml'
|
3
|
+
require 'active_support/hash_with_indifferent_access'
|
4
|
+
require 'active_support/core_ext/object/try'
|
5
|
+
|
6
|
+
Dir[File.dirname(__FILE__) + '/ext/*.rb'].each { |f| require f }
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + "/summer/handlers"
|
9
|
+
|
10
|
+
module Summer
|
11
|
+
class Connection
|
12
|
+
include Handlers
|
13
|
+
attr_accessor :connection, :ready, :started, :config, :server, :port
|
14
|
+
def initialize(server, port=6667, dry=false)
|
15
|
+
@ready = false
|
16
|
+
@started = false
|
17
|
+
|
18
|
+
@server = server
|
19
|
+
@port = port
|
20
|
+
|
21
|
+
load_config
|
22
|
+
connect!
|
23
|
+
|
24
|
+
unless dry
|
25
|
+
loop do
|
26
|
+
startup! if @ready && !@started
|
27
|
+
message = @connection.gets
|
28
|
+
if message
|
29
|
+
parse(message)
|
30
|
+
else
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def load_config
|
40
|
+
@config = HashWithIndifferentAccess.new(YAML::load_file(File.dirname($0) + "/config/summer.yml"))
|
41
|
+
@config[:channels] ||= []
|
42
|
+
@config[:channels] << @config.delete(:channel) if @config[:channel]
|
43
|
+
end
|
44
|
+
|
45
|
+
def connect!
|
46
|
+
@connection = TCPSocket.open(server, port)
|
47
|
+
response("USER #{config[:nick]} #{config[:nick]} #{config[:nick]} #{config[:nick]}")
|
48
|
+
response("NICK #{config[:nick]}")
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Will join channels specified in configuration.
|
53
|
+
def startup!
|
54
|
+
nickserv_identify if @config[:nickserv_password]
|
55
|
+
config[:channels].each do |channel|
|
56
|
+
join(channel)
|
57
|
+
end
|
58
|
+
@started = true
|
59
|
+
really_try(:did_start_up) if respond_to?(:did_start_up)
|
60
|
+
end
|
61
|
+
|
62
|
+
def nickserv_identify
|
63
|
+
privmsg("nickserv", "register #{@config[:nickserv_password]} #{@config[:nickserv_email]}")
|
64
|
+
privmsg("nickserv", "identify #{@config[:nickserv_password]}")
|
65
|
+
end
|
66
|
+
# Go somewhere.
|
67
|
+
def join(channel)
|
68
|
+
response("JOIN #{channel}")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Leave somewhere
|
72
|
+
def part(channel)
|
73
|
+
response("PART #{channel}")
|
74
|
+
end
|
75
|
+
|
76
|
+
# What did they say?
|
77
|
+
def parse(message)
|
78
|
+
puts "<< #{message.to_s.strip}"
|
79
|
+
words = message.split(" ")
|
80
|
+
sender = words[0]
|
81
|
+
raw = words[1]
|
82
|
+
channel = words[2]
|
83
|
+
# Handling pings
|
84
|
+
if /^PING (.*?)\s$/.match(message)
|
85
|
+
response("PONG #{$1}")
|
86
|
+
# Handling raws
|
87
|
+
elsif /\d+/.match(raw)
|
88
|
+
send("handle_#{raw}", message) if raws_to_handle.include?(raw)
|
89
|
+
# Privmsgs
|
90
|
+
elsif raw == "PRIVMSG"
|
91
|
+
message = words[3..-1].clean
|
92
|
+
# Parse commands
|
93
|
+
if /^!(\w+)\s*(.*)/.match(message) && respond_to?("#{$1}_command")
|
94
|
+
really_try("#{$1}_command", parse_sender(sender), channel, $2)
|
95
|
+
# Plain and boring message
|
96
|
+
else
|
97
|
+
sender = parse_sender(sender)
|
98
|
+
method, channel = channel == me ? [:private_message, sender[:nick]] : [:channel_message, channel]
|
99
|
+
really_try(method, sender, channel, message)
|
100
|
+
end
|
101
|
+
# Joins
|
102
|
+
elsif raw == "JOIN"
|
103
|
+
really_try(:join, parse_sender(sender), channel)
|
104
|
+
elsif raw == "PART"
|
105
|
+
really_try(:part, parse_sender(sender), channel, words[3..-1].clean)
|
106
|
+
elsif raw == "QUIT"
|
107
|
+
really_try(:quit, parse_sender(sender), words[2..-1].clean)
|
108
|
+
elsif raw == "KICK"
|
109
|
+
really_try(:kick, parse_sender(sender), channel, words[3], words[4..-1].clean)
|
110
|
+
join(channel) if words[3] == me && config[:auto_rejoin]
|
111
|
+
elsif raw == "MODE"
|
112
|
+
really_try(:mode, parse_sender(sender), channel, words[3], words[4..-1].clean)
|
113
|
+
elsif raw == "TOPIC"
|
114
|
+
really_try(:topic, parse_sender(sender), channel, words[3..-1].clean)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_sender(sender)
|
120
|
+
nick, hostname = sender.split("!")
|
121
|
+
{ :nick => nick.clean, :hostname => hostname }
|
122
|
+
end
|
123
|
+
|
124
|
+
# These are the raws we care about.
|
125
|
+
def raws_to_handle
|
126
|
+
["422", "376"]
|
127
|
+
end
|
128
|
+
|
129
|
+
def privmsg(message, to)
|
130
|
+
response("PRIVMSG #{to} :#{message}")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Output something to the console and to the socket.
|
134
|
+
def response(message)
|
135
|
+
puts ">> #{message.strip}"
|
136
|
+
@connection.puts(message)
|
137
|
+
end
|
138
|
+
|
139
|
+
def me
|
140
|
+
config[:nick]
|
141
|
+
end
|
142
|
+
|
143
|
+
def log(message)
|
144
|
+
File.open(config[:log_file]) { |file| file.write(message) } if config[:log_file]
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: summer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Bigg
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: shoulda
|
16
|
+
requirement: &2153293060 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2153293060
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rdoc
|
27
|
+
requirement: &2153292580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.12'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2153292580
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: bundler
|
38
|
+
requirement: &2153292100 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2153292100
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: jeweler
|
49
|
+
requirement: &2153291620 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.8.3
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2153291620
|
58
|
+
description: Tiny IRC Bot Frameowkr
|
59
|
+
email: radarlistener@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE
|
64
|
+
- README.markdown
|
65
|
+
files:
|
66
|
+
- lib/ext/array.rb
|
67
|
+
- lib/ext/object.rb
|
68
|
+
- lib/ext/string.rb
|
69
|
+
- lib/summer.rb
|
70
|
+
- lib/summer/handlers.rb
|
71
|
+
- LICENSE
|
72
|
+
- README.markdown
|
73
|
+
homepage: http://github.com/radar/summer
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
hash: -3637726515248804584
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.8.11
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: Tiny IRC Bot Framework
|
101
|
+
test_files: []
|