ircbot 0.1.5 → 0.2.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/.gitignore +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +71 -0
- data/README +72 -3
- data/bin/ircbot +3 -0
- data/config/samples/postgres.yml +19 -0
- data/config/{sama-zu.yml → samples/sama-zu.yml} +1 -1
- data/config/{yml.erb → samples/yml.erb} +0 -0
- data/ircbot.gemspec +13 -0
- data/lib/ircbot.rb +3 -1
- data/lib/ircbot/client.rb +6 -0
- data/lib/ircbot/client/config.rb +9 -0
- data/lib/ircbot/client/plugins.rb +14 -1
- data/lib/ircbot/core_ext/message.rb +4 -1
- data/lib/ircbot/plugin.rb +17 -0
- data/lib/ircbot/plugins.rb +68 -13
- data/lib/ircbot/utils/html_parser.rb +26 -0
- data/lib/ircbot/utils/watcher.rb +36 -0
- data/lib/ircbot/version.rb +1 -1
- data/old/plugins/summary.cpi +267 -0
- data/plugins/plugins.rb +1 -1
- data/plugins/reminder.rb +79 -175
- data/plugins/summary/ch2.rb +272 -0
- data/plugins/summary/engines.rb +30 -0
- data/plugins/summary/engines/base.rb +105 -0
- data/plugins/summary/engines/ch2.rb +14 -0
- data/plugins/summary/engines/https.rb +6 -0
- data/plugins/summary/engines/none.rb +10 -0
- data/plugins/summary/engines/twitter.rb +16 -0
- data/plugins/summary/spec/ch2_spec.rb +64 -0
- data/plugins/summary/spec/spec_helper.rb +19 -0
- data/plugins/summary/spec/summarizers_none_spec.rb +15 -0
- data/plugins/summary/spec/summarizers_spec.rb +23 -0
- data/plugins/summary/summary.rb +58 -0
- data/plugins/watchdog/db.rb +80 -0
- data/plugins/watchdog/exceptions.rb +4 -0
- data/plugins/watchdog/updater.rb +21 -0
- data/plugins/watchdog/watchdog.rb +82 -0
- data/spec/plugin_spec.rb +11 -0
- data/spec/plugins_spec.rb +35 -1
- data/spec/utils/html_parser_spec.rb +30 -0
- data/spec/utils/spec_helper.rb +1 -0
- metadata +190 -13
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ircbot (0.2.0)
|
5
|
+
chawan
|
6
|
+
data_objects
|
7
|
+
dm-core
|
8
|
+
dm-migrations
|
9
|
+
dm-postgres-adapter
|
10
|
+
dm-sqlite-adapter
|
11
|
+
dm-timestamps
|
12
|
+
do_sqlite3
|
13
|
+
dsl_accessor (>= 0.4.0)
|
14
|
+
extlib (>= 0.9.14)
|
15
|
+
net-irc (>= 0.0.9)
|
16
|
+
night-time
|
17
|
+
pg
|
18
|
+
sqlite3
|
19
|
+
|
20
|
+
GEM
|
21
|
+
remote: https://rubygems.org/
|
22
|
+
specs:
|
23
|
+
addressable (2.2.8)
|
24
|
+
blankslate (2.1.2.4)
|
25
|
+
chawan (0.0.4)
|
26
|
+
data_objects (0.10.8)
|
27
|
+
addressable (~> 2.1)
|
28
|
+
diff-lcs (1.1.3)
|
29
|
+
dm-core (1.2.0)
|
30
|
+
addressable (~> 2.2.6)
|
31
|
+
dm-do-adapter (1.2.0)
|
32
|
+
data_objects (~> 0.10.6)
|
33
|
+
dm-core (~> 1.2.0)
|
34
|
+
dm-migrations (1.2.0)
|
35
|
+
dm-core (~> 1.2.0)
|
36
|
+
dm-postgres-adapter (1.2.0)
|
37
|
+
dm-do-adapter (~> 1.2.0)
|
38
|
+
do_postgres (~> 0.10.6)
|
39
|
+
dm-sqlite-adapter (1.2.0)
|
40
|
+
dm-do-adapter (~> 1.2.0)
|
41
|
+
do_sqlite3 (~> 0.10.6)
|
42
|
+
dm-timestamps (1.2.0)
|
43
|
+
dm-core (~> 1.2.0)
|
44
|
+
do_postgres (0.10.8)
|
45
|
+
data_objects (= 0.10.8)
|
46
|
+
do_sqlite3 (0.10.8)
|
47
|
+
data_objects (= 0.10.8)
|
48
|
+
dsl_accessor (0.4.1)
|
49
|
+
blankslate (>= 2.1.2)
|
50
|
+
optionize (>= 0.1.0)
|
51
|
+
extlib (0.9.15)
|
52
|
+
net-irc (0.0.9)
|
53
|
+
night-time (1.0.1)
|
54
|
+
optionize (0.1.1)
|
55
|
+
pg (0.14.0)
|
56
|
+
rspec (2.10.0)
|
57
|
+
rspec-core (~> 2.10.0)
|
58
|
+
rspec-expectations (~> 2.10.0)
|
59
|
+
rspec-mocks (~> 2.10.0)
|
60
|
+
rspec-core (2.10.1)
|
61
|
+
rspec-expectations (2.10.0)
|
62
|
+
diff-lcs (~> 1.1.3)
|
63
|
+
rspec-mocks (2.10.1)
|
64
|
+
sqlite3 (1.3.6)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
ircbot!
|
71
|
+
rspec (>= 2.9.0)
|
data/README
CHANGED
@@ -23,7 +23,11 @@ Config
|
|
23
23
|
Usage
|
24
24
|
=====
|
25
25
|
|
26
|
-
|
26
|
+
(installed gem)
|
27
|
+
% ircbot -f config/xxx.yml
|
28
|
+
|
29
|
+
(in source dir)
|
30
|
+
% ruby -Ku -rubygems -Ilib bin/ircbot -f config/xxx.yml
|
27
31
|
|
28
32
|
|
29
33
|
Plugin
|
@@ -34,9 +38,10 @@ Plugin
|
|
34
38
|
Instance methods:
|
35
39
|
* reply : this method is called when privmsg event is fired,
|
36
40
|
and reply message(the returned string) to the channel.
|
37
|
-
|
38
|
-
|
41
|
+
args: [text, nick, message object]
|
42
|
+
* setup : used for initializer
|
39
43
|
* help : used from "plugins" plugin
|
44
|
+
* [ANY] : any methods can be invoked by "<NICK>.<PLUGN_NAME>.<METHOD_NAME>"
|
40
45
|
|
41
46
|
Accessor methods:
|
42
47
|
|
@@ -45,6 +50,14 @@ Plugin
|
|
45
50
|
* config : hash of given config file
|
46
51
|
|
47
52
|
|
53
|
+
Setup
|
54
|
+
=====
|
55
|
+
|
56
|
+
Install gems via bundler like this.
|
57
|
+
|
58
|
+
% bundle install --path vendor
|
59
|
+
|
60
|
+
|
48
61
|
Example
|
49
62
|
=======
|
50
63
|
|
@@ -83,6 +96,62 @@ Advanced
|
|
83
96
|
BPlugin#reply will be never invoked.
|
84
97
|
|
85
98
|
|
99
|
+
Daemons
|
100
|
+
=======
|
101
|
+
|
102
|
+
Plugin initializer automatically calls "setup" method.
|
103
|
+
So you can start daemon in it.
|
104
|
+
|
105
|
+
plugins/time_signal.rb:
|
106
|
+
|
107
|
+
class TimeSignalPlugin < Ircbot::Plugin
|
108
|
+
def setup
|
109
|
+
@daemon = Thread.new {
|
110
|
+
sleep 60
|
111
|
+
self.bot.broadcast Time.now
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def stop
|
116
|
+
@daemon.kill
|
117
|
+
return "Stopped time signal"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
When the bot name is 'airi', this will act as following.
|
122
|
+
|
123
|
+
05:11 <airi> Mon Apr 09 05:11:22 +0900 2012
|
124
|
+
05:12 <airi> Mon Apr 09 05:12:22 +0900 2012
|
125
|
+
05:12 <maiha> airi.time_signal.stop
|
126
|
+
05:12 <airi> Stopped time signal
|
127
|
+
|
128
|
+
|
129
|
+
PluginAttributes
|
130
|
+
================
|
131
|
+
|
132
|
+
When you want to give options or attributes to plugins,
|
133
|
+
write it into config.plugins as Array(Hash)
|
134
|
+
|
135
|
+
config/xxx.yml
|
136
|
+
plugins:
|
137
|
+
- irc
|
138
|
+
-
|
139
|
+
name: watchdog
|
140
|
+
db: "postgres://localhost/ircbot"
|
141
|
+
|
142
|
+
This will generate two plugins
|
143
|
+
1. Ircbot::Plugin(name:irc)
|
144
|
+
2. Ircbot::Plugin(name:watchdog, attrs=>{name=>watchdog,db=>postgres...})
|
145
|
+
|
146
|
+
And the given options can be found in plugin by [] method.
|
147
|
+
|
148
|
+
class Watchdog < Ircbot::Plugin
|
149
|
+
def setup
|
150
|
+
db = self[:db]
|
151
|
+
puts "connecting to #{db}"
|
152
|
+
...
|
153
|
+
|
154
|
+
|
86
155
|
Required
|
87
156
|
========
|
88
157
|
|
data/bin/ircbot
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
host: localhost
|
2
|
+
port: 6667
|
3
|
+
nick: sama-zu
|
4
|
+
user: samazu
|
5
|
+
real: sama~zu
|
6
|
+
channels: "#test"
|
7
|
+
plugins:
|
8
|
+
- irc
|
9
|
+
- plugins
|
10
|
+
-
|
11
|
+
name: watchdog
|
12
|
+
db: "postgres://localhost/ircbot"
|
13
|
+
-
|
14
|
+
name: reminder
|
15
|
+
db: "postgres://localhost/ircbot"
|
16
|
+
- summary
|
17
|
+
reminder
|
18
|
+
multiline: true
|
19
|
+
timeout: 500
|
File without changes
|
data/ircbot.gemspec
CHANGED
@@ -22,6 +22,19 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_dependency "dsl_accessor", ">= 0.4.0"
|
23
23
|
s.add_dependency "extlib", ">= 0.9.14"
|
24
24
|
s.add_dependency "net-irc", ">= 0.0.9"
|
25
|
+
s.add_dependency 'chawan'
|
26
|
+
s.add_dependency 'night-time'
|
27
|
+
|
28
|
+
s.add_dependency 'pg'
|
29
|
+
s.add_dependency 'sqlite3'
|
30
|
+
|
31
|
+
s.add_dependency 'dm-core'
|
32
|
+
s.add_dependency 'dm-migrations'
|
33
|
+
s.add_dependency 'dm-timestamps'
|
34
|
+
s.add_dependency 'do_sqlite3'
|
35
|
+
s.add_dependency 'data_objects'
|
36
|
+
s.add_dependency 'dm-sqlite-adapter'
|
37
|
+
s.add_dependency 'dm-postgres-adapter'
|
25
38
|
|
26
39
|
s.add_development_dependency "rspec", ">= 2.9.0"
|
27
40
|
end
|
data/lib/ircbot.rb
CHANGED
@@ -18,8 +18,10 @@ $LOAD_PATH.unshift __DIR__ unless
|
|
18
18
|
require "ircbot/framework"
|
19
19
|
require "ircbot/version"
|
20
20
|
|
21
|
-
Ircbot.push_path(:plugin, Ircbot.system_root + 'plugins')
|
22
21
|
Ircbot.push_path(:config, Ircbot.system_root + 'config')
|
22
|
+
Ircbot.push_path(:plugin, Ircbot.system_root + 'plugins')
|
23
|
+
Ircbot.push_path(:plugin, Ircbot.root + 'plugins')
|
24
|
+
$:.unshift((Ircbot.root + 'plugins').to_s)
|
23
25
|
Ircbot.toplevel_binding = binding
|
24
26
|
|
25
27
|
######################################################################
|
data/lib/ircbot/client.rb
CHANGED
@@ -17,3 +17,9 @@ require "ircbot/client/config/channels"
|
|
17
17
|
require "ircbot/client/config/plugins"
|
18
18
|
require "ircbot/client/timeout"
|
19
19
|
require "ircbot/client/plugins"
|
20
|
+
|
21
|
+
######################################################################
|
22
|
+
### Irctob::Utils
|
23
|
+
|
24
|
+
require "ircbot/utils/watcher"
|
25
|
+
require "ircbot/utils/html_parser"
|
data/lib/ircbot/client/config.rb
CHANGED
@@ -53,6 +53,15 @@ module Ircbot
|
|
53
53
|
@config = Config.new(hash)
|
54
54
|
end
|
55
55
|
|
56
|
+
def trim(text, size = 120)
|
57
|
+
a = text.to_s.split(//)
|
58
|
+
if a.size > size
|
59
|
+
return a[0..size].join + "..."
|
60
|
+
else
|
61
|
+
return text.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
56
65
|
attr_reader :config
|
57
66
|
end
|
58
67
|
end
|
@@ -19,10 +19,23 @@ module Ircbot
|
|
19
19
|
text = decode(m.params[1].to_s)
|
20
20
|
args = [text, m.prefix.nick, m]
|
21
21
|
|
22
|
+
plugins_call_command(args, m)
|
22
23
|
plugins_call_replies(args, m)
|
23
24
|
}
|
24
25
|
|
25
26
|
private
|
27
|
+
def plugins_call_command(args, m)
|
28
|
+
case m.message.to_s # text
|
29
|
+
when /^#{config.nick}\.(#{plugins.active_names.join('|')})\./
|
30
|
+
plugin = plugins[$1]
|
31
|
+
command, arg = $'.to_s.split(/\b/, 2)
|
32
|
+
args = [arg.to_s.strip]
|
33
|
+
if plugin.class.command?(command)
|
34
|
+
plugins_call_action(command, plugin, args, m, :reply=>true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
26
39
|
def plugins_call_replies(args, m)
|
27
40
|
text = catch(:done) do
|
28
41
|
plugins.active.each do |plugin|
|
@@ -54,7 +67,7 @@ module Ircbot
|
|
54
67
|
|
55
68
|
def plugins_rescue_action(type, plugin, e)
|
56
69
|
p [e.class, e.message, type, plugin]
|
57
|
-
at = e.
|
70
|
+
at = e.backtrace rescue '(no backtraces)'
|
58
71
|
puts at
|
59
72
|
end
|
60
73
|
|
@@ -12,7 +12,10 @@ class Net::IRC::Message
|
|
12
12
|
|
13
13
|
def reply(client, text)
|
14
14
|
to = (client.config.nick == params[0]) ? prefix.nick : params[0]
|
15
|
-
|
15
|
+
unless text.to_s.empty?
|
16
|
+
text = client.trim(text)
|
17
|
+
client.privmsg to, text
|
18
|
+
end
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
data/lib/ircbot/plugin.rb
CHANGED
@@ -19,10 +19,19 @@ module Ircbot
|
|
19
19
|
attr_accessor :running
|
20
20
|
attr_accessor :plugin_name
|
21
21
|
|
22
|
+
def self.command?(name)
|
23
|
+
@commands ||= (public_instance_methods - Plugin.public_instance_methods).inject({"setup"=>1, "help"=>1}) {|h,k| h[k.to_s] = 1; h }
|
24
|
+
!! @commands[name.to_s]
|
25
|
+
end
|
26
|
+
|
22
27
|
def initialize(plugins = nil)
|
23
28
|
@plugins = plugins || Plugins.new
|
24
29
|
@message = InitialMessage.new(self.class.name)
|
25
30
|
@running = false
|
31
|
+
@attrs = Mash.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup
|
26
35
|
end
|
27
36
|
|
28
37
|
######################################################################
|
@@ -31,6 +40,10 @@ module Ircbot
|
|
31
40
|
delegate :plugin!, :client, :bot, :config, :to=>"@plugins"
|
32
41
|
delegate :debug, :to=>"@plugins"
|
33
42
|
|
43
|
+
def [](key)
|
44
|
+
@attrs[key]
|
45
|
+
end
|
46
|
+
|
34
47
|
def plugin_name
|
35
48
|
@plugin_name ||= Extlib::Inflection.foreign_key(self.class.name).sub(/(_plugin)?_id$/,'')
|
36
49
|
end
|
@@ -43,6 +56,10 @@ module Ircbot
|
|
43
56
|
"%s%s" % [running ? '*' : '', plugin_name]
|
44
57
|
end
|
45
58
|
|
59
|
+
def attrs=(hash)
|
60
|
+
@attrs = Mash.new(hash)
|
61
|
+
end
|
62
|
+
|
46
63
|
######################################################################
|
47
64
|
### Operations
|
48
65
|
|
data/lib/ircbot/plugins.rb
CHANGED
@@ -11,8 +11,9 @@ module Ircbot
|
|
11
11
|
def initialize(client = nil, plugins = nil)
|
12
12
|
@client = client || Client::Standalone.new
|
13
13
|
@plugins = Dictionary.new
|
14
|
+
@cache = {}
|
14
15
|
|
15
|
-
|
16
|
+
load Array(plugins)
|
16
17
|
end
|
17
18
|
|
18
19
|
######################################################################
|
@@ -24,9 +25,35 @@ module Ircbot
|
|
24
25
|
plugins.values.__send__(:each, &block)
|
25
26
|
end
|
26
27
|
|
28
|
+
######################################################################
|
29
|
+
### Caching
|
30
|
+
|
31
|
+
def clear_cache
|
32
|
+
@cache = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def cache(key = nil, &block)
|
36
|
+
key = key.to_s
|
37
|
+
return @cache ||= {} if key.empty?
|
38
|
+
|
39
|
+
if @cache.has_key?(key)
|
40
|
+
@cache[key]
|
41
|
+
else
|
42
|
+
@cache[key] = block.call
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
27
46
|
######################################################################
|
28
47
|
### Accessors
|
29
48
|
|
49
|
+
def active_names
|
50
|
+
cache(:active_names) { active.map(&:plugin_name) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def active
|
54
|
+
cache(:active) { select(&:running) }
|
55
|
+
end
|
56
|
+
|
30
57
|
def plugin!(plugin)
|
31
58
|
case plugin
|
32
59
|
when String, Symbol
|
@@ -52,22 +79,29 @@ module Ircbot
|
|
52
79
|
|
53
80
|
def start(plugin)
|
54
81
|
plugin!(plugin).running = true
|
82
|
+
changed!
|
55
83
|
end
|
56
84
|
|
57
85
|
def stop(plugin)
|
58
86
|
plugin!(plugin).running = false
|
87
|
+
changed!
|
59
88
|
end
|
60
89
|
|
61
90
|
def delete(plugin)
|
62
91
|
name = plugin.is_a?(Plugin) ? plugin.name : plugin.to_s
|
63
92
|
plugin!(name)
|
64
93
|
@plugins.delete(name)
|
94
|
+
changed!
|
95
|
+
end
|
96
|
+
|
97
|
+
def changed!
|
98
|
+
clear_cache
|
65
99
|
end
|
66
100
|
|
67
101
|
######################################################################
|
68
102
|
### IO
|
69
103
|
|
70
|
-
def
|
104
|
+
def load(plugin)
|
71
105
|
case plugin
|
72
106
|
when Array
|
73
107
|
plugin.each do |name|
|
@@ -77,6 +111,7 @@ module Ircbot
|
|
77
111
|
plugin.plugins = self
|
78
112
|
plugins[plugin.plugin_name] = plugin
|
79
113
|
plugin.running = true
|
114
|
+
plugin.setup
|
80
115
|
when Class
|
81
116
|
if plugin.ancestors.include?(Ircbot::Plugin)
|
82
117
|
self << plugin.new(self)
|
@@ -84,44 +119,64 @@ module Ircbot
|
|
84
119
|
raise ArgumentError, "#{plugin} is not Ircbot::Plugin"
|
85
120
|
end
|
86
121
|
when String, Symbol
|
122
|
+
self << {"name" => plugin.to_s}
|
123
|
+
when Hash
|
87
124
|
begin
|
88
|
-
|
89
|
-
|
125
|
+
attrs = Mash.new(plugin)
|
126
|
+
name = attrs["name"]
|
127
|
+
if name.blank?
|
128
|
+
raise "no names: #{attrs.inspect}"
|
129
|
+
end
|
130
|
+
plugin = eval_plugin(name)
|
131
|
+
plugin.attrs = attrs
|
132
|
+
self << plugin
|
90
133
|
rescue Exception => e
|
91
|
-
|
134
|
+
invalid_plugin_found "Plugin error(#{name}): #{e}[#{e.class}]"
|
92
135
|
end
|
93
136
|
else
|
94
137
|
raise NotImplementedError, "#<< for #{plugin.class}"
|
95
138
|
end
|
139
|
+
changed!
|
96
140
|
return self
|
97
141
|
end
|
98
|
-
alias :<< :
|
142
|
+
alias :<< :load
|
143
|
+
|
144
|
+
def eval_plugin(name)
|
145
|
+
class_name = plugin_class_name(name)
|
146
|
+
|
147
|
+
if Object.const_defined?(class_name)
|
148
|
+
Object.send(:remove_const, class_name)
|
149
|
+
end
|
99
150
|
|
100
|
-
def load(name)
|
101
151
|
path = Ircbot.glob_for(:plugin, name).first or
|
102
152
|
raise PluginNotFound, name.to_s
|
103
153
|
|
104
154
|
script = path.read{}
|
105
|
-
|
155
|
+
Dir.chdir(path.parent) do
|
156
|
+
eval(script, Ircbot.toplevel_binding)
|
157
|
+
end
|
106
158
|
|
107
|
-
class_name = Extlib::Inflection.camelize(name) + "Plugin"
|
108
159
|
return Object.const_get(class_name).new
|
109
160
|
|
110
161
|
rescue NameError => e
|
111
162
|
raise LoadError, "Expected #{path} to define #{class_name} (#{e})"
|
112
163
|
end
|
113
164
|
|
114
|
-
def active
|
115
|
-
select(&:running)
|
116
|
-
end
|
117
|
-
|
118
165
|
def inspect
|
119
166
|
plugins.values.inspect
|
120
167
|
end
|
121
168
|
|
169
|
+
def invalid_plugin_found(text)
|
170
|
+
broadcast text
|
171
|
+
end
|
172
|
+
|
122
173
|
private
|
123
174
|
def broadcast(text)
|
124
175
|
p text
|
125
176
|
end
|
177
|
+
|
178
|
+
def plugin_class_name(name)
|
179
|
+
Extlib::Inflection.camelize(name) + "Plugin"
|
180
|
+
end
|
126
181
|
end
|
127
182
|
end
|