ircbot 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +43 -21
- data/Rakefile +9 -6
- data/bin/ircbot +3 -27
- data/lib/ircbot.rb +12 -15
- data/lib/ircbot/client.rb +32 -0
- data/lib/ircbot/client/commands.rb +34 -0
- data/lib/ircbot/client/config.rb +55 -0
- data/lib/ircbot/client/config/channels.rb +40 -0
- data/lib/ircbot/client/config/plugins.rb +16 -0
- data/lib/ircbot/client/encoding.rb +17 -0
- data/lib/ircbot/client/plugins.rb +64 -0
- data/lib/ircbot/core_ext/delegation.rb +135 -0
- data/lib/ircbot/core_ext/extending.rb +80 -0
- data/lib/ircbot/core_ext/message.rb +18 -0
- data/lib/ircbot/framework.rb +22 -40
- data/lib/ircbot/plugin.rb +63 -0
- data/lib/ircbot/plugins.rb +141 -0
- data/lib/ircbot/version.rb +4 -0
- data/plugins/echo.rb +14 -0
- data/plugins/irc.rb +19 -0
- data/plugins/plugins.rb +59 -0
- data/spec/config_spec.rb +83 -0
- data/spec/fixtures/sama-zu.yml +8 -0
- data/spec/framework_spec.rb +18 -0
- data/spec/its_helper.rb +15 -0
- data/spec/plugin_spec.rb +70 -0
- data/spec/plugins_spec.rb +30 -0
- data/spec/provide_helper.rb +36 -0
- data/spec/spec_helper.rb +16 -0
- metadata +40 -19
- data/lib/irc/agent.rb +0 -177
- data/lib/irc/client.rb +0 -476
- data/lib/irc/const.rb +0 -242
- data/lib/irc/irc.rb +0 -324
- data/lib/irc/localize.rb +0 -260
- data/lib/ircbot/agent_manager.rb +0 -89
- data/lib/ircbot/config_client.rb +0 -369
- data/lib/ircbot/core_ext/digest.rb +0 -14
- data/lib/ircbot/core_ext/irc.rb +0 -61
- data/lib/ircbot/core_ext/rand-polimorphism.rb +0 -23
- data/lib/ircbot/core_ext/writefile.rb +0 -45
- data/lib/ircbot/ordered_hash.rb +0 -91
- data/lib/ircbot/reply_client.rb +0 -328
data/README
CHANGED
@@ -1,47 +1,69 @@
|
|
1
1
|
ircbot
|
2
|
-
|
2
|
+
======
|
3
3
|
|
4
|
-
|
4
|
+
An irc bot framework that offers easy-to-use by plugins
|
5
5
|
|
6
6
|
|
7
7
|
Config
|
8
8
|
======
|
9
9
|
|
10
|
-
Edit "config/xxx.
|
10
|
+
Edit "config/xxx.yml" as your environment.
|
11
|
+
|
12
|
+
* host: irc server host
|
13
|
+
* port: irc server port
|
14
|
+
* nick: nick name for this bot
|
15
|
+
* user: user name for this bot
|
16
|
+
* real: real name for this bot
|
17
|
+
* help: help message for this bot
|
18
|
+
* channels: startup channel names
|
19
|
+
* plugins: plugin names
|
11
20
|
|
12
21
|
|
13
22
|
Usage
|
14
23
|
=====
|
15
24
|
|
16
|
-
ircbot -f config/xxx.
|
25
|
+
ircbot -f config/xxx.yml
|
17
26
|
|
18
27
|
|
19
|
-
|
20
|
-
|
28
|
+
Plugin
|
29
|
+
======
|
21
30
|
|
22
|
-
|
23
|
-
# same as `arg > (nick|realname).COMMAND'
|
24
|
-
* (nick|realname).help
|
25
|
-
* (nick|realname).restart(CPI_NAME = nil)
|
26
|
-
* (nick|realname).register(CPI_NAME)
|
27
|
-
* (nick|realname).remove(CPI_NAME)
|
31
|
+
In ircbot world, we define functions as plugin (Ircbot::Plugin).
|
28
32
|
|
33
|
+
Instance methods:
|
34
|
+
* reply : this method is called when privmsg event is fired,
|
35
|
+
and reply message(the returned string) to the channel.
|
36
|
+
args: [text, nick, message object]
|
29
37
|
|
30
|
-
|
31
|
-
===
|
38
|
+
* help : used from "plugins" plugin
|
32
39
|
|
33
|
-
|
40
|
+
Accessor methods:
|
34
41
|
|
42
|
+
* message : message object same as 3rd argument
|
43
|
+
* direct? : whether the message is directly toward to the bot or not
|
44
|
+
* config : hash of given config file
|
35
45
|
|
36
46
|
|
37
|
-
|
38
|
-
|
47
|
+
Example
|
48
|
+
=======
|
39
49
|
|
40
|
-
|
50
|
+
When you want echo bot, define the function as plugin first.
|
41
51
|
|
52
|
+
plugins/echo.rb:
|
42
53
|
|
43
|
-
|
44
|
-
|
54
|
+
class EchoPlugin < Ircbot::Plugin
|
55
|
+
def reply(text)
|
56
|
+
text
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
Required
|
63
|
+
========
|
64
|
+
|
65
|
+
* irc-net gem
|
45
66
|
|
46
|
-
maiha@wota.jp
|
47
67
|
|
68
|
+
Authors: maiha@wota.jp
|
69
|
+
Links: http://github.com/maiha/ircbot
|
data/Rakefile
CHANGED
@@ -7,9 +7,11 @@ require 'rake/gempackagetask'
|
|
7
7
|
GEM_NAME = "ircbot"
|
8
8
|
AUTHOR = "maiha"
|
9
9
|
EMAIL = "maiha@wota.jp"
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
SUMMARY = "easy irc bot framework"
|
11
|
+
|
12
|
+
require File.dirname(__FILE__) + '/lib/ircbot/version'
|
13
|
+
GEM_VERSION = Ircbot::VERSION
|
14
|
+
HOMEPAGE = Ircbot::HOMEPAGE
|
13
15
|
|
14
16
|
spec = Gem::Specification.new do |s|
|
15
17
|
s.rubyforge_project = 'asakusarb'
|
@@ -20,13 +22,14 @@ spec = Gem::Specification.new do |s|
|
|
20
22
|
s.has_rdoc = true
|
21
23
|
s.extra_rdoc_files = ["README", "MIT-LICENSE"]
|
22
24
|
s.summary = SUMMARY
|
23
|
-
s.description =
|
25
|
+
s.description = "An irc bot framework that offers easy-to-use by plugins"
|
24
26
|
s.author = AUTHOR
|
25
27
|
s.email = EMAIL
|
26
28
|
s.homepage = HOMEPAGE
|
27
29
|
s.require_path = 'lib'
|
28
|
-
s.add_dependency('
|
29
|
-
s.
|
30
|
+
s.add_dependency('extlib', '>= 0.9.14')
|
31
|
+
s.add_dependency('net-irc', '>= 0.0.9')
|
32
|
+
s.files = %w(MIT-LICENSE README Rakefile) + Dir.glob("{lib,spec,plugins}/**/*")
|
30
33
|
end
|
31
34
|
|
32
35
|
Rake::GemPackageTask.new(spec) do |pkg|
|
data/bin/ircbot
CHANGED
@@ -1,21 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# clear ARGV for Irb
|
3
2
|
|
4
3
|
require 'ircbot'
|
5
4
|
|
6
|
-
$KCODE = 'e'
|
7
|
-
|
8
|
-
# Sync
|
9
|
-
STDOUT.sync = true
|
10
|
-
STDERR.sync = true
|
11
|
-
|
12
|
-
debug = nil
|
13
5
|
config = nil
|
14
|
-
|
6
|
+
plugin = Pathname(Dir.getwd) + "plugins"
|
15
7
|
|
16
8
|
while (arg = ARGV.shift)
|
17
9
|
case arg
|
18
|
-
when /^-d$/ ; debug = true
|
19
10
|
when /^-f$/ ; config = ARGV.shift
|
20
11
|
when /^-c$/ ; cpi = ARGV.shift
|
21
12
|
else
|
@@ -28,23 +19,8 @@ unless config
|
|
28
19
|
raise "Specify your config file\nusage: #{$0} -f config/xxx.dat"
|
29
20
|
end
|
30
21
|
|
31
|
-
|
32
|
-
Ircbot.push_path :cpi, cpi, "**/*.cpi"
|
33
|
-
|
34
|
-
|
35
|
-
module Ircbot
|
36
|
-
class Kicker < Ircbot::ReplyClient
|
37
|
-
rescue_from(SocketError) {
|
38
|
-
raise Ircbot::Recover, 30.minutes
|
39
|
-
}
|
40
|
-
|
41
|
-
rescue_from(Errno::EPIPE, Errno::ECONNRESET, Errno::ETIMEDOUT, IRC::AbnormalTerminated) {
|
42
|
-
raise Ircbot::Recover, 300.minutes
|
43
|
-
}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
22
|
+
Ircbot.push_path(:plugin, plugin)
|
47
23
|
|
48
|
-
irc = Ircbot::
|
24
|
+
irc = Ircbot::Client.from_file(config)
|
49
25
|
irc.start
|
50
26
|
puts "Bye"
|
data/lib/ircbot.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
1
|
require 'nkf'
|
3
2
|
require 'pathname'
|
4
3
|
require 'rubygems'
|
5
|
-
require '
|
4
|
+
require 'extlib'
|
5
|
+
require 'extlib/dictionary'
|
6
6
|
|
7
7
|
######################################################################
|
8
8
|
### Load path
|
@@ -14,28 +14,25 @@ $LOAD_PATH.unshift __DIR__ unless
|
|
14
14
|
$LOAD_PATH.include?(__DIR__) ||
|
15
15
|
$LOAD_PATH.include?(File.expand_path(__DIR__))
|
16
16
|
|
17
|
-
require
|
17
|
+
require "ircbot/framework"
|
18
|
+
require "ircbot/version"
|
18
19
|
|
20
|
+
Ircbot.push_path(:plugin, Ircbot.system_root + 'plugins')
|
21
|
+
Ircbot.toplevel_binding = binding
|
19
22
|
|
20
23
|
######################################################################
|
21
24
|
### IRC library
|
22
25
|
|
23
|
-
require
|
24
|
-
require 'irc/agent'
|
25
|
-
require 'irc/client'
|
26
|
-
|
26
|
+
require "net/irc"
|
27
27
|
|
28
28
|
######################################################################
|
29
|
-
###
|
30
|
-
|
31
|
-
require 'ircbot/core_ext/rand-polimorphism'
|
32
|
-
require 'ircbot/core_ext/writefile'
|
33
|
-
require 'ircbot/core_ext/digest'
|
34
|
-
require 'ircbot/core_ext/irc'
|
29
|
+
### Core ext
|
35
30
|
|
31
|
+
require "ircbot/core_ext/delegation" # from activesupport-2.3.5
|
32
|
+
require "ircbot/core_ext/extending" # from activesupport-2.3.5
|
33
|
+
require "ircbot/core_ext/message"
|
36
34
|
|
37
35
|
######################################################################
|
38
36
|
### Ircbot
|
39
37
|
|
40
|
-
require
|
41
|
-
|
38
|
+
require "ircbot/client"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require "ircbot/plugin"
|
4
|
+
require "ircbot/plugins"
|
5
|
+
|
6
|
+
module Ircbot
|
7
|
+
class Client < Net::IRC::Client
|
8
|
+
|
9
|
+
# escape from nil black hole
|
10
|
+
def method_missing(name, *args)
|
11
|
+
case name.to_s
|
12
|
+
when /^on_/
|
13
|
+
# nop for calling super from subclass
|
14
|
+
else
|
15
|
+
raise NameError, "undefined local variable or method `#{name}' for #{self}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Standalone < Client
|
20
|
+
def initialize(*)
|
21
|
+
super({})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "ircbot/client/encoding"
|
28
|
+
require "ircbot/client/commands"
|
29
|
+
require "ircbot/client/config"
|
30
|
+
require "ircbot/client/config/channels"
|
31
|
+
require "ircbot/client/config/plugins"
|
32
|
+
require "ircbot/client/plugins"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Ircbot
|
4
|
+
class Client
|
5
|
+
######################################################################
|
6
|
+
### Convinient access to commands
|
7
|
+
|
8
|
+
def post(command, *params)
|
9
|
+
if params[1]
|
10
|
+
params[1] = encode(params[1]).strip
|
11
|
+
if config.multiline
|
12
|
+
params[1].split(/\n/).compact.each do |text|
|
13
|
+
params[1] = text
|
14
|
+
super(command, *params)
|
15
|
+
end
|
16
|
+
return
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
super(command, *params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def notice(channel, text)
|
24
|
+
text = encode(text)
|
25
|
+
post NOTICE, channel, text
|
26
|
+
end
|
27
|
+
|
28
|
+
def privmsg(channel, text)
|
29
|
+
text = encode(text)
|
30
|
+
post PRIVMSG, channel, text
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Ircbot
|
4
|
+
class Client
|
5
|
+
class Config
|
6
|
+
######################################################################
|
7
|
+
### Reader
|
8
|
+
def self.read(path)
|
9
|
+
path = Pathname(path)
|
10
|
+
ext = path.extname.delete(".")
|
11
|
+
ext = "yml" if ext.empty?
|
12
|
+
|
13
|
+
reader = "read_#{ext}"
|
14
|
+
if respond_to?(reader)
|
15
|
+
Mash.new(__send__(reader, path))
|
16
|
+
else
|
17
|
+
raise NotImplementedError, "Cannot read #{path}: Format(#{ext})is not supported"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.read_yml(path)
|
22
|
+
require 'yaml'
|
23
|
+
path = Pathname(path)
|
24
|
+
YAML.load(path.read{})
|
25
|
+
end
|
26
|
+
|
27
|
+
######################################################################
|
28
|
+
### Config
|
29
|
+
def initialize(obj)
|
30
|
+
@obj = obj
|
31
|
+
end
|
32
|
+
|
33
|
+
def [](key)
|
34
|
+
__send__(key)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def method_missing(*args)
|
39
|
+
@obj.__send__(*args)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.from_file(path)
|
44
|
+
new(Config.read(path))
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(hash)
|
48
|
+
super(hash[:host], hash[:port], hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
def config
|
52
|
+
@config ||= Config.new(opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Ircbot
|
4
|
+
class Client
|
5
|
+
|
6
|
+
######################################################################
|
7
|
+
### Config
|
8
|
+
|
9
|
+
class Config
|
10
|
+
def channels
|
11
|
+
case (val = super)
|
12
|
+
when Array
|
13
|
+
val
|
14
|
+
else
|
15
|
+
val.to_s.split
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
######################################################################
|
21
|
+
### Event
|
22
|
+
|
23
|
+
def on_rpl_welcome(m)
|
24
|
+
super
|
25
|
+
|
26
|
+
config.channels.each do |channel|
|
27
|
+
post JOIN, channel
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
######################################################################
|
32
|
+
### Command
|
33
|
+
|
34
|
+
def broadcast(text)
|
35
|
+
config.channels.each do |channel|
|
36
|
+
privmsg channel, text
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Ircbot
|
4
|
+
class Client
|
5
|
+
######################################################################
|
6
|
+
### Character conversions
|
7
|
+
|
8
|
+
def decode(text)
|
9
|
+
NKF.nkf('-w', text.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode(text)
|
13
|
+
NKF.nkf('-j', text.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Ircbot
|
4
|
+
class Client
|
5
|
+
######################################################################
|
6
|
+
### Accessors
|
7
|
+
|
8
|
+
def plugins
|
9
|
+
@plugins ||= Plugins.new(self, config.plugins)
|
10
|
+
end
|
11
|
+
|
12
|
+
delegate :plugin!, :plugin, :to=>"plugins"
|
13
|
+
|
14
|
+
|
15
|
+
######################################################################
|
16
|
+
### Events
|
17
|
+
|
18
|
+
def on_privmsg(m)
|
19
|
+
super
|
20
|
+
|
21
|
+
text = decode(m.params[1].to_s)
|
22
|
+
args = [text, m.prefix.nick, m]
|
23
|
+
|
24
|
+
plugins_call_replies(args, m)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def plugins_call_replies(args, m)
|
29
|
+
text = catch(:halt) do
|
30
|
+
plugins.active.each do |plugin|
|
31
|
+
plugins_call_action(:reply, plugin, args, m, :reply=>true)
|
32
|
+
end
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
m.reply(self, text) if text
|
36
|
+
end
|
37
|
+
|
38
|
+
def plugins_call_logs(args)
|
39
|
+
raise NotImplementedError, "obsoleted"
|
40
|
+
plugins.active.each do |plugin|
|
41
|
+
plugins_call_action(:log, plugin, args)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def plugins_call_action(type, plugin, args, m, opts = {})
|
46
|
+
plugin.message = m
|
47
|
+
arity = plugin.method(type).arity rescue return
|
48
|
+
reply = plugin.__send__(type, *args[0,arity])
|
49
|
+
m.reply(self, reply) if opts[:reply]
|
50
|
+
rescue Exception => e
|
51
|
+
type = (e.class == RuntimeError) ? 'Error' : "#{e.class}"
|
52
|
+
m.reply(self, "#{type}: #{e.message}")
|
53
|
+
plugins_rescue_action type, plugin, e
|
54
|
+
end
|
55
|
+
|
56
|
+
def plugins_rescue_action(type, plugin, e)
|
57
|
+
p [e.class, e.message, type, plugin]
|
58
|
+
at = e.backtraces rescue '(no backtraces)'
|
59
|
+
puts at
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|