ircbot 0.0.2 → 0.1.0
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/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
|
+
|