cogbot 0.0.2
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 +3 -0
- data/.rvmrc +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +74 -0
- data/LICENSE +22 -0
- data/README.md +47 -0
- data/Rakefile +15 -0
- data/bin/cogbot +12 -0
- data/cogbot.gemspec +39 -0
- data/config/cogbot.yml.defaults +26 -0
- data/lib/cogbot/server.rb +22 -0
- data/lib/cogbot/setup.rb +70 -0
- data/lib/cogbot/utils.rb +9 -0
- data/lib/cogbot/version.rb +3 -0
- data/lib/cogbot.rb +106 -0
- data/plugins/dice.rb +24 -0
- data/plugins/exec.rb +56 -0
- data/plugins/fortune.rb +32 -0
- data/plugins/gitlistener.rb +38 -0
- data/plugins/google.rb +40 -0
- data/plugins/manager.rb +102 -0
- data/plugins/redmine.rb +61 -0
- data/plugins/rubygems.rb +51 -0
- data/plugins/shorturl.rb +32 -0
- data/plugins/stackoverflow.rb +37 -0
- data/plugins/tests.rb +18 -0
- data/plugins/tweet.rb +54 -0
- data/plugins/urban.rb +36 -0
- data/plugins/users.rb +39 -0
- data/test/helper.rb +13 -0
- metadata +372 -0
data/plugins/manager.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# thx dominikh for this code :) (then slightly modified)
|
2
|
+
module Cinch
|
3
|
+
module Plugins
|
4
|
+
class Manager
|
5
|
+
include Cinch::Plugin
|
6
|
+
|
7
|
+
match(/m list/, method: :list_plugins)
|
8
|
+
match(/m load (\S+)/, method: :load_plugin)
|
9
|
+
match(/m unload (\S+)/, method: :unload_plugin)
|
10
|
+
match(/m reload (\S+)/, method: :reload_plugin)
|
11
|
+
match(/m set (\S+) (\S+) (.+)$/, method: :set_option)
|
12
|
+
|
13
|
+
def list_plugins(m)
|
14
|
+
back = ''
|
15
|
+
@bot.plugins.each { |p| back += "#{p.class.name.split('::').last.downcase} " }
|
16
|
+
m.reply back
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_plugin(m, mapping)
|
20
|
+
plugin = mapping.downcase.camelize
|
21
|
+
p plugin
|
22
|
+
p mapping
|
23
|
+
|
24
|
+
file_name = "#{ROOT_DIR}/plugins/#{mapping.downcase}.rb"
|
25
|
+
unless File.exist?(file_name)
|
26
|
+
m.reply "Could not load #{plugin} because #{file_name} does not exist."
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
load(file_name)
|
32
|
+
rescue Exception
|
33
|
+
m.reply "Could not load #{plugin}."
|
34
|
+
raise
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
const = Cinch::Plugins.const_get(plugin)
|
39
|
+
rescue NameError
|
40
|
+
m.reply "Could not load #{plugin} because no matching class was found."
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
@bot.plugins.register_plugin(const)
|
45
|
+
m.reply "Successfully loaded #{plugin}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def unload_plugin(m, plugin)
|
49
|
+
begin
|
50
|
+
plugin_class = Cinch::Plugins.const_get(plugin.downcase.camelize)
|
51
|
+
rescue NameError
|
52
|
+
m.reply "Could not unload #{plugin} because no matching class was found."
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
@bot.plugins.select {|p| p.class == plugin_class}.each do |p|
|
57
|
+
@bot.plugins.unregister_plugin(p)
|
58
|
+
end
|
59
|
+
|
60
|
+
## FIXME not doing this at the moment because it'll break
|
61
|
+
## plugin options. This means, however, that reloading a
|
62
|
+
## plugin is relatively dirty: old methods will not be removed
|
63
|
+
## but only overwritten by new ones. You will also not be able
|
64
|
+
## to change a classes superclass this way.
|
65
|
+
# Cinch::Plugins.__send__(:remove_const, plugin)
|
66
|
+
|
67
|
+
# Because we're not completely removing the plugin class,
|
68
|
+
# reset everything to the starting values.
|
69
|
+
plugin_class.hooks.clear
|
70
|
+
plugin_class.matchers.clear
|
71
|
+
plugin_class.listeners.clear
|
72
|
+
plugin_class.timers.clear
|
73
|
+
plugin_class.ctcps.clear
|
74
|
+
plugin_class.react_on = :message
|
75
|
+
plugin_class.plugin_name = nil
|
76
|
+
plugin_class.help = nil
|
77
|
+
plugin_class.prefix = nil
|
78
|
+
plugin_class.suffix = nil
|
79
|
+
plugin_class.required_options.clear
|
80
|
+
|
81
|
+
m.reply "Successfully unloaded #{plugin}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def reload_plugin(m, plugin)
|
85
|
+
unload_plugin(m, plugin)
|
86
|
+
load_plugin(m, plugin)
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_option(m, plugin, option, value)
|
90
|
+
begin
|
91
|
+
const = Cinch::Plugins.const_get(plugin.downcase.camelize)
|
92
|
+
rescue NameError
|
93
|
+
m.reply "Could not set plugin option for #{plugin} because no matching class was found."
|
94
|
+
return
|
95
|
+
end
|
96
|
+
@bot.config.plugins.options[const][option.to_sym] = eval(value)
|
97
|
+
|
98
|
+
m.reply "Successfuly set option."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/plugins/redmine.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'yajl'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Cinch
|
6
|
+
module Plugins
|
7
|
+
class Redmine
|
8
|
+
include Cinch::Plugin
|
9
|
+
|
10
|
+
timer 60, method: :check_redmine
|
11
|
+
|
12
|
+
set :plugin_name, 'redmine'
|
13
|
+
set :help, <<EOT
|
14
|
+
Redmine plugins checks the new issues in the specified redmine instance
|
15
|
+
EOT
|
16
|
+
|
17
|
+
def check_redmine
|
18
|
+
@issues ||= Array.new
|
19
|
+
api_key = @bot.config.options['cogconf']['redmine']['api_key']
|
20
|
+
redmine_url = "%s/issues.json?project_id=%s&limit=20" % [
|
21
|
+
@bot.config.options['cogconf']['redmine']['url'],
|
22
|
+
@bot.config.options['cogconf']['redmine']['project']
|
23
|
+
]
|
24
|
+
res = Yajl::Parser.parse(open(redmine_url, "X-Redmine-API-Key" => api_key))
|
25
|
+
subjs = Hash[ res['issues'].map { |i| [ i['id'], i['subject'] ] } ]
|
26
|
+
issues = subjs.keys
|
27
|
+
newones = Array.new
|
28
|
+
if @issues.count == 0
|
29
|
+
@issues = issues
|
30
|
+
else
|
31
|
+
issues.each { |i| newones << i unless @issues.include? i }
|
32
|
+
if newones.count > 0
|
33
|
+
newones.each do |i|
|
34
|
+
@issues.push i
|
35
|
+
@bot.config.options['cogconf']['main']['channels'].each do |channel|
|
36
|
+
Channel(channel).msg "[%s] >>> %s - %s/issues/%s" % [
|
37
|
+
@bot.config.options['cogconf']['redmine']['project'],
|
38
|
+
subjs[i],
|
39
|
+
@bot.config.options['cogconf']['redmine']['url'],
|
40
|
+
i
|
41
|
+
]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@issues = @issues[0..50]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# puts "redmine: done #{newones.count} new issues, #{@issues.count} cached"
|
48
|
+
rescue Exception => e
|
49
|
+
puts "*** #{e.class}\n"
|
50
|
+
puts e.to_s
|
51
|
+
puts e.backtrace
|
52
|
+
end
|
53
|
+
|
54
|
+
def new(bot)
|
55
|
+
@bot = bot
|
56
|
+
@issues = Array.new
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/plugins/rubygems.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'yajl'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Cinch
|
6
|
+
module Plugins
|
7
|
+
class Rubygems
|
8
|
+
include Cinch::Plugin
|
9
|
+
|
10
|
+
match /r (.*)$/
|
11
|
+
|
12
|
+
set :plugin_name, 'rubygems'
|
13
|
+
set :help, <<EOT
|
14
|
+
Rubygems queries http://rubygems.org for finding gems
|
15
|
+
EOT
|
16
|
+
|
17
|
+
def query(query)
|
18
|
+
url = "https://rubygems.org/api/v1/search.json?query=#{CGI.escape(query)}"
|
19
|
+
back = "Requesting ... \n"
|
20
|
+
begin
|
21
|
+
file = open(url)
|
22
|
+
if file.class == StringIO
|
23
|
+
json = Yajl::Parser.parse(file)
|
24
|
+
if json.empty?
|
25
|
+
return "Nothing matches '#{query}'"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
json = Yajl::Parser.parse(File.read(file))
|
29
|
+
end
|
30
|
+
4.times do |it|
|
31
|
+
back += "#{json[it]['name']} : #{json[it]['homepage_uri']}\n"
|
32
|
+
end
|
33
|
+
rescue Exception => e
|
34
|
+
p file.class
|
35
|
+
back = "*** #{e.class}\n"
|
36
|
+
back += e.to_s
|
37
|
+
end
|
38
|
+
return back
|
39
|
+
end
|
40
|
+
|
41
|
+
def new(bot)
|
42
|
+
@bot = bot
|
43
|
+
end
|
44
|
+
|
45
|
+
def execute(m,words)
|
46
|
+
m.reply(query(words.strip))
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/plugins/shorturl.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
module Plugins
|
5
|
+
class Shorturl
|
6
|
+
include Cinch::Plugin
|
7
|
+
|
8
|
+
match /(http:\/\/[^ ]*)/, :use_prefix => false
|
9
|
+
|
10
|
+
set :plugin_name, 'shorturl'
|
11
|
+
set :help, <<EOT
|
12
|
+
Shorturl catches urls said on channel and shorten then
|
13
|
+
EOT
|
14
|
+
|
15
|
+
def shorten(url)
|
16
|
+
url = open("http://tinyurl.com/api-create.php?url=#{URI.escape(url)}").read
|
17
|
+
url == "Error" ? nil : url
|
18
|
+
rescue OpenURI::HTTPError
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def new(bot)
|
23
|
+
@bot = bot
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute(m,url)
|
27
|
+
m.reply("Shortening: " + shorten(url))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class Stackoverflow
|
5
|
+
include Cinch::Plugin
|
6
|
+
|
7
|
+
match /s (.+)/
|
8
|
+
|
9
|
+
set :plugin_name, 'stackoverflow'
|
10
|
+
set :help, <<EOT
|
11
|
+
Stackoverflow returns the first match on a search
|
12
|
+
.s <keywords> : searches on those keywords
|
13
|
+
EOT
|
14
|
+
|
15
|
+
def new(bot)
|
16
|
+
@bot = bot
|
17
|
+
end
|
18
|
+
|
19
|
+
def search(query)
|
20
|
+
url = "http://api.stackoverflow.com/docs/search#site=stackoverflow&sort=activity&intitle=#{CGI.escape(query)}"
|
21
|
+
p url
|
22
|
+
res = JSON.parse(open(url))
|
23
|
+
p res
|
24
|
+
res.items.each do |i|
|
25
|
+
title = i.title
|
26
|
+
link = i.link
|
27
|
+
desc = i.tags.join(', ')
|
28
|
+
end
|
29
|
+
"#{title} - #{desc} (#{link})"
|
30
|
+
rescue
|
31
|
+
"No results found"
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute(m, query)
|
35
|
+
m.reply(search(query))
|
36
|
+
end
|
37
|
+
end
|
data/plugins/tests.rb
ADDED
data/plugins/tweet.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'twitter'
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
module Plugins
|
5
|
+
class Tweet
|
6
|
+
include Cinch::Plugin
|
7
|
+
|
8
|
+
match /t ?([^ ]*)?( ?.*)/
|
9
|
+
|
10
|
+
set :plugin_name, 'tweet'
|
11
|
+
set :help, <<EOT
|
12
|
+
Tweet makes the bot can query twittter API
|
13
|
+
.t search <term> : searches the public timelines
|
14
|
+
EOT
|
15
|
+
|
16
|
+
=begin
|
17
|
+
Twitter.configure do |c|
|
18
|
+
c.consumer_key = @bot.config.options.cogconf['tweet']['consumer_key']
|
19
|
+
c.consumer_secret = @bot.config.options.cogconf['tweet']['consumer_secret']
|
20
|
+
c.oauth_token = @bot.config.options.cogconf['tweet']['oauth_token']
|
21
|
+
c.oauth_token_secret = @bot.config.options.cogconf['tweet']['oauth_token_secret']
|
22
|
+
end
|
23
|
+
=end
|
24
|
+
|
25
|
+
def new(bot)
|
26
|
+
@bot = bot
|
27
|
+
end
|
28
|
+
|
29
|
+
def exec(command,args)
|
30
|
+
back = ''
|
31
|
+
#back += "command: #{command} / args: #{args}\n"
|
32
|
+
begin
|
33
|
+
case command
|
34
|
+
when 'search'
|
35
|
+
Twitter.search(args, { :lang => 'en', :rpp => '3' }).each do|status|
|
36
|
+
back += status.full_text + "\n"
|
37
|
+
end
|
38
|
+
else
|
39
|
+
back += Twitter.send(command,args.split(','))
|
40
|
+
end
|
41
|
+
rescue Exception => e
|
42
|
+
back += "Bad request\n"
|
43
|
+
back += e.inspect
|
44
|
+
end
|
45
|
+
return back
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute(m,command,args)
|
49
|
+
m.reply(exec(command,args.strip))
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/plugins/urban.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Cinch
|
6
|
+
module Plugins
|
7
|
+
class Urban
|
8
|
+
include Cinch::Plugin
|
9
|
+
|
10
|
+
match /u (.*)$/
|
11
|
+
|
12
|
+
set :plugin_name, 'urban'
|
13
|
+
set :help, <<EOT
|
14
|
+
Urban connects to urban dictionary and returns the first result for a given query, replying with the result directly to the sender
|
15
|
+
EOT
|
16
|
+
|
17
|
+
def query(query)
|
18
|
+
url = "http://www.urbandictionary.com/define.php?term=#{CGI.escape(query)}"
|
19
|
+
begin
|
20
|
+
CGI.unescape_html Nokogiri::HTML(open(url)).at("div.definition").text.gsub(/\s+/, ' ')
|
21
|
+
rescue
|
22
|
+
"no result found"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def new(bot)
|
27
|
+
@bot = bot
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute(m,words)
|
31
|
+
m.reply(query(words.strip))
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/plugins/users.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
module Cinch
|
3
|
+
module Plugins
|
4
|
+
class Users
|
5
|
+
|
6
|
+
class UserStruct < Struct.new(:user, :channel, :text, :time)
|
7
|
+
end
|
8
|
+
|
9
|
+
include Cinch::Plugin
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
storage[:users] ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
match /u (.+ )?([^\s]+)( .+)/
|
17
|
+
|
18
|
+
def exec(query,nick)
|
19
|
+
back ''
|
20
|
+
query.strip! rescue ''
|
21
|
+
nick.strip! rescue ''
|
22
|
+
if query.blank?
|
23
|
+
else
|
24
|
+
case query
|
25
|
+
when 'add'
|
26
|
+
else
|
27
|
+
back = "Unknown command #{query}."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return back
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute(m, query, nick, msg)
|
34
|
+
m.reply(exec(query, nick, msg))
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'minitest/ci'
|
2
|
+
require 'simplecov'
|
3
|
+
require 'simplecov-rcov'
|
4
|
+
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
6
|
+
SimpleCov.start
|
7
|
+
|
8
|
+
if $0 == __FILE__
|
9
|
+
TestHelpers::load_env
|
10
|
+
puts ENV.inspect
|
11
|
+
end
|
12
|
+
|
13
|
+
MiniTest::Ci.auto_clean = false
|