beerbot 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/run-irc.rb +24 -0
- data/lib/BeerBot.rb +20 -0
- data/lib/BeerBot/00.utils/DataFile.rb +56 -0
- data/lib/BeerBot/00.utils/InOut.rb +46 -0
- data/lib/BeerBot/00.utils/More.rb +68 -0
- data/lib/BeerBot/00.utils/paramExpand.rb +77 -0
- data/lib/BeerBot/00.utils/utils.rb +149 -0
- data/lib/BeerBot/00.utils/world/IRCWorld.rb +47 -0
- data/lib/BeerBot/00.utils/world/World.rb +84 -0
- data/lib/BeerBot/01.connect/Connection.rb +23 -0
- data/lib/BeerBot/01.connect/IRCConnection.rb +133 -0
- data/lib/BeerBot/01.protocols/botmsg.rb +59 -0
- data/lib/BeerBot/01.protocols/irc.rb +250 -0
- data/lib/BeerBot/02.bot/bot.rb +234 -0
- data/lib/BeerBot/03.more/BotMsgMore.rb +34 -0
- data/lib/BeerBot/06.dispatchers/irc.rb +160 -0
- data/lib/BeerBot/70.scheduler/scheduler.rb +22 -0
- data/lib/BeerBot/Config.rb +62 -0
- data/lib/RunIRC.rb +153 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5711f62c9ce4965a324d3578b5555761d8c493ef
|
4
|
+
data.tar.gz: 61bdaff04c5ae69702858f623316671d305b5474
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5551c5b99e88f48ed52bbc6d3ee3581d8842c9e841551919cdeb2fc37034206239543be1228f47b509d83fe6c7a04a09134b06ff09bbb90d8540a95c96b18497
|
7
|
+
data.tar.gz: 4e189c7c8ac1ba58f3874a8e78cebaf7fdb01b29bc3702830fa43aeec1fd0fbce1afc0495eccc0a26c515be398b27b43e70251245f08d1c0cd146ae1912d6385
|
data/bin/run-irc.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
4
|
+
# Copyright (C) 2013,2014 Daniel Bush
|
5
|
+
# This program is distributed under the terms of the GNU
|
6
|
+
# General Public License. A copy of the license should be
|
7
|
+
# enclosed with this project in the file LICENSE. If not
|
8
|
+
# see <http://www.gnu.org/licenses/>.
|
9
|
+
|
10
|
+
raise "Needs ruby 2" if /^1/===RUBY_VERSION
|
11
|
+
require_relative '../lib/RunIRC'
|
12
|
+
|
13
|
+
if ARGV.size == 0 then
|
14
|
+
puts "Usage: ruby beerbot.rb path/to/ircconf.json"
|
15
|
+
puts "See conf/irc.json"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
conffile = ARGV[0]
|
20
|
+
BeerBot::Config.load JSON.load(File.read(conffile))
|
21
|
+
BeerBot::Config.validate!
|
22
|
+
|
23
|
+
$runirc = BeerBot::RunIRC.new BeerBot::Config
|
24
|
+
$runirc.start
|
data/lib/BeerBot.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'CronR' # For scheduler
|
2
|
+
|
3
|
+
require_relative 'BeerBot/00.utils/utils'
|
4
|
+
require_relative 'BeerBot/00.utils/paramExpand'
|
5
|
+
require_relative 'BeerBot/00.utils/DataFile'
|
6
|
+
require_relative 'BeerBot/00.utils/InOut'
|
7
|
+
require_relative 'BeerBot/00.utils/world/IRCWorld'
|
8
|
+
require_relative 'BeerBot/01.connect/IRCConnection'
|
9
|
+
require_relative 'BeerBot/01.protocols/botmsg'
|
10
|
+
require_relative 'BeerBot/01.protocols/irc'
|
11
|
+
require_relative 'BeerBot/02.bot/bot'
|
12
|
+
require_relative 'BeerBot/03.more/BotMsgMore'
|
13
|
+
require_relative 'BeerBot/06.dispatchers/irc'
|
14
|
+
require_relative 'BeerBot/70.scheduler/scheduler'
|
15
|
+
require_relative 'BeerBot/Config'
|
16
|
+
|
17
|
+
module BeerBot
|
18
|
+
module Modules
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
2
|
+
# Copyright (C) 2014 Daniel Bush
|
3
|
+
# This program is distributed under the terms of the GNU
|
4
|
+
# General Public License. A copy of the license should be
|
5
|
+
# enclosed with this project in the file LICENSE. If not
|
6
|
+
# see <http://www.gnu.org/licenses/>.
|
7
|
+
|
8
|
+
require 'json'
|
9
|
+
module BeerBot
|
10
|
+
module Utils
|
11
|
+
# A class that loads data from a file and allows you to access it
|
12
|
+
# using the #data method.
|
13
|
+
#
|
14
|
+
# If the file is updated (after >=1 sec), #data will reload.
|
15
|
+
class DataFile
|
16
|
+
attr_reader :reloaded # true if last call to #data reloaded file
|
17
|
+
def initialize filepath
|
18
|
+
@filepath = filepath
|
19
|
+
@data = File.read(filepath)
|
20
|
+
@mtime = File.stat(filepath).mtime
|
21
|
+
@reloaded = false
|
22
|
+
end
|
23
|
+
def data
|
24
|
+
@reloaded = false
|
25
|
+
return @data unless File.exists?(@filepath)
|
26
|
+
mtime = File.stat(@filepath).mtime
|
27
|
+
return @data if mtime == @mtime
|
28
|
+
puts "Reloading data file #{@filepath}"
|
29
|
+
@mtime = mtime
|
30
|
+
@data = File.read(@filepath)
|
31
|
+
@reloaded = true
|
32
|
+
@data
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# Specialised DataFile that parses json.
|
36
|
+
class JsonDataFile < DataFile
|
37
|
+
attr_reader :json
|
38
|
+
def initialize filepath
|
39
|
+
super
|
40
|
+
@json = JSON.parse(@data)
|
41
|
+
end
|
42
|
+
def data
|
43
|
+
super
|
44
|
+
begin
|
45
|
+
if @reloaded then
|
46
|
+
json = JSON.parse(@data)
|
47
|
+
@json = json
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
return @json
|
51
|
+
end
|
52
|
+
@json
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
2
|
+
# Copyright (C) 2014 Daniel Bush
|
3
|
+
# This program is distributed under the terms of the GNU
|
4
|
+
# General Public License. A copy of the license should be
|
5
|
+
# enclosed with this project in the file LICENSE. If not
|
6
|
+
# see <http://www.gnu.org/licenses/>.
|
7
|
+
|
8
|
+
module BeerBot
|
9
|
+
module Utils
|
10
|
+
|
11
|
+
# Represents a thread that waits on an in-queue, processes any
|
12
|
+
# things received and puts them on an out-queue.
|
13
|
+
|
14
|
+
class InOut
|
15
|
+
|
16
|
+
attr_reader :inq,:outq,:run,:thread
|
17
|
+
|
18
|
+
def initialize inq:nil,outq:nil,&block
|
19
|
+
@inq = inq
|
20
|
+
@outq = outq
|
21
|
+
@run = block
|
22
|
+
raise "No block given" unless block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def start!
|
26
|
+
@thread = Thread.new {
|
27
|
+
loop {
|
28
|
+
begin
|
29
|
+
thing = @inq.deq
|
30
|
+
response = @run.call(thing)
|
31
|
+
if response then
|
32
|
+
@outq.enq(response)
|
33
|
+
else
|
34
|
+
# TODO
|
35
|
+
end
|
36
|
+
rescue => e
|
37
|
+
puts e
|
38
|
+
puts e.backtrace
|
39
|
+
end
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
2
|
+
# Copyright (C) 2014 Daniel Bush
|
3
|
+
# This program is distributed under the terms of the GNU
|
4
|
+
# General Public License. A copy of the license should be
|
5
|
+
# enclosed with this project in the file LICENSE. If not
|
6
|
+
# see <http://www.gnu.org/licenses/>.
|
7
|
+
|
8
|
+
module BeerBot
|
9
|
+
|
10
|
+
module Utils
|
11
|
+
|
12
|
+
# A hash that buffers things by some key.
|
13
|
+
#
|
14
|
+
# If 'things' exceeds a set number, then these are stored in an
|
15
|
+
# array against the key.
|
16
|
+
#
|
17
|
+
# For irc and other messaging the key should probably
|
18
|
+
# be key :to of one or more botmsg's.
|
19
|
+
# @see BotMsgMore
|
20
|
+
|
21
|
+
class More < Hash
|
22
|
+
|
23
|
+
attr_accessor :size
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
super
|
27
|
+
# Default value is empty array.
|
28
|
+
self.default_proc = lambda {|h,k|
|
29
|
+
h[k] = []
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def size
|
34
|
+
@size ||= 5 # lines
|
35
|
+
end
|
36
|
+
|
37
|
+
# Fetch array of items from buffer for key 'key'.
|
38
|
+
#
|
39
|
+
# 'key' should probably be a person or channel you are messaging.
|
40
|
+
#
|
41
|
+
# Should return an array of items (eg of botmsg hashes).
|
42
|
+
|
43
|
+
def more key
|
44
|
+
arr = self[key]
|
45
|
+
self[key] = arr.slice(self.size,arr.size) || []
|
46
|
+
return arr.slice(0,self.size-1)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Filter an array of items allowing only
|
50
|
+
# the first 'n' of these.
|
51
|
+
#
|
52
|
+
# The remainder are stored in this hash and can
|
53
|
+
# be accessed via 'key' using 'self.more'.
|
54
|
+
|
55
|
+
def filter arr,key
|
56
|
+
if arr.size <= self.size then
|
57
|
+
self[key] = [] # reset buffer
|
58
|
+
return arr
|
59
|
+
end
|
60
|
+
self[key] = arr.slice(self.size,size)
|
61
|
+
return arr.slice(0,self.size)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
2
|
+
# Copyright (C) 2014 Daniel Bush
|
3
|
+
# This program is distributed under the terms of the GNU
|
4
|
+
# General Public License. A copy of the license should be
|
5
|
+
# enclosed with this project in the file LICENSE. If not
|
6
|
+
# see <http://www.gnu.org/licenses/>.
|
7
|
+
|
8
|
+
|
9
|
+
module BeerBot
|
10
|
+
|
11
|
+
module Utils
|
12
|
+
|
13
|
+
# Randomly generate sentences.
|
14
|
+
#
|
15
|
+
# See spec examples in spec/.
|
16
|
+
#
|
17
|
+
# Take a spec which is of form
|
18
|
+
# [<sentence>,<hash>]
|
19
|
+
# where <sentence> is a string and
|
20
|
+
# each entry in <hash>
|
21
|
+
# <key> => <value>
|
22
|
+
# where <key> is a symbol, and <value>
|
23
|
+
# is an array of <sentence>'s.
|
24
|
+
#
|
25
|
+
# <sentence> is a sentence or phrase.
|
26
|
+
# If a word starts with ':' it will be looked up
|
27
|
+
# in <hash>, an entry from <value> will be randomly
|
28
|
+
# selected.
|
29
|
+
# The entry from <value> will also undergo the
|
30
|
+
# same ':' substitution.
|
31
|
+
|
32
|
+
module ParamExpand
|
33
|
+
|
34
|
+
# Recursively expand a sentence with parameters starting with
|
35
|
+
# ':' using values sampled from params.
|
36
|
+
#
|
37
|
+
# Split, map and rejoin a sentence (str).
|
38
|
+
#
|
39
|
+
# After splitting, apply expand on parameter words ":word".
|
40
|
+
#
|
41
|
+
# Watch out, throws error, be prepared.
|
42
|
+
|
43
|
+
def self.expand(str,params,raise_error=false)
|
44
|
+
words = str.split(/\s+/) # not great, we lose additional spaces
|
45
|
+
words.map {|word|
|
46
|
+
if word[0] == ':' then
|
47
|
+
if word[1] == ':' then
|
48
|
+
word # let the bot code gsub this; ::from , ::to
|
49
|
+
else
|
50
|
+
self.expand(
|
51
|
+
self.lookup(word[1..-1],params,raise_error),
|
52
|
+
params,raise_error
|
53
|
+
)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
word
|
57
|
+
end
|
58
|
+
}.select{|word| word != nil && word != ""}.join(' ').strip
|
59
|
+
end
|
60
|
+
|
61
|
+
# Randomly select entry from params.
|
62
|
+
|
63
|
+
def self.lookup(str,params,raise_error=false)
|
64
|
+
if not params.has_key?(str) then
|
65
|
+
if raise_error then
|
66
|
+
raise "'#{str}' has no corresponding symbol in params #{params}"
|
67
|
+
else
|
68
|
+
return ""
|
69
|
+
end
|
70
|
+
end
|
71
|
+
result = params[str].sample
|
72
|
+
result ? result : ""
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# The files in this directory are part of BeerBot, a a ruby irc bot library.
|
2
|
+
# Copyright (C) 2014 Daniel Bush
|
3
|
+
# This program is distributed under the terms of the GNU
|
4
|
+
# General Public License. A copy of the license should be
|
5
|
+
# enclosed with this project in the file LICENSE. If not
|
6
|
+
# see <http://www.gnu.org/licenses/>.
|
7
|
+
|
8
|
+
|
9
|
+
module BeerBot
|
10
|
+
|
11
|
+
module Utils
|
12
|
+
|
13
|
+
# Look for parameters in a string.
|
14
|
+
#
|
15
|
+
# Numeric parameters => "... ::1 ... ::2 "
|
16
|
+
# Key parameters => "... ::foo ... ::bar "
|
17
|
+
# Multi => "... ::foo|::1 ... ::bar|::foo|::1 "
|
18
|
+
#
|
19
|
+
# (?: ) is a non-capturing group.
|
20
|
+
|
21
|
+
def self.scan_param msg
|
22
|
+
matches = msg.scan(/(?:::[^\W\s:|]*(?:\|::[^\W\s:|]*)*)/)
|
23
|
+
matches.map{|m|
|
24
|
+
a = m.split('|').map{|m2|
|
25
|
+
m2 = m2.sub('::','')
|
26
|
+
case m2
|
27
|
+
when /\d+/
|
28
|
+
m2.to_i
|
29
|
+
else
|
30
|
+
m2
|
31
|
+
end
|
32
|
+
}
|
33
|
+
[m,a]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return a parser that takes string msg and extracts a specified
|
38
|
+
# prefix at beginning.
|
39
|
+
#
|
40
|
+
# The prefix might be a nick or a command prefix.
|
41
|
+
#
|
42
|
+
# Use this to get commands issued to the bot through a channel.
|
43
|
+
#
|
44
|
+
# TODO: make sure this returns msg without the prefix, or nil
|
45
|
+
# otherwise.
|
46
|
+
|
47
|
+
def self.make_prefix_parser prefix
|
48
|
+
rx = Regexp.new("^#{prefix}\\W?(.*)",'i')
|
49
|
+
lambda {|msg|
|
50
|
+
if m = rx.match(msg) then
|
51
|
+
m[1].strip
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Expand a string with numeric and key parameters using data
|
57
|
+
# provided.
|
58
|
+
#
|
59
|
+
# Parameters should be preceded with a double-colon in the msg.
|
60
|
+
# Numeric parameters are matched to 'args'.
|
61
|
+
# So ::1 => args[0] etc
|
62
|
+
#
|
63
|
+
# 'expand' will return the expanded string as best it can and an
|
64
|
+
# error object.
|
65
|
+
# The error object will tell you if there weren't enough
|
66
|
+
# parameters in args to satisfy the numeric parameters in the
|
67
|
+
# string.
|
68
|
+
#
|
69
|
+
# ("::1 ::foo ::bar|::1",'a',foo:'b') => "a b a"
|
70
|
+
|
71
|
+
def self.expand msg,*args,**kargs
|
72
|
+
errargs = []
|
73
|
+
params = self.scan_param(msg)
|
74
|
+
# Do the big ones first.
|
75
|
+
params = params.sort{|a,b|b[1].size<=>a[1].size}
|
76
|
+
params.each {|i|
|
77
|
+
# pattern: "::1|::foo"
|
78
|
+
# parts: [1,'foo']
|
79
|
+
pattern,parts = i
|
80
|
+
found = false
|
81
|
+
_errargs = []
|
82
|
+
_errkargs = []
|
83
|
+
parts.each {|part|
|
84
|
+
v = nil
|
85
|
+
case part
|
86
|
+
when Fixnum
|
87
|
+
v = args[part-1]
|
88
|
+
_errargs.push(part) unless v
|
89
|
+
else
|
90
|
+
if part == '' then # pattern is or contains '::' which has part ''.
|
91
|
+
v = ''
|
92
|
+
else
|
93
|
+
v = kargs[part.to_sym]
|
94
|
+
_errkargs.push(part) unless v
|
95
|
+
end
|
96
|
+
end
|
97
|
+
if v then
|
98
|
+
if v == '' then
|
99
|
+
#byebug
|
100
|
+
# Squeeze spaces. Not perfect, but it'll do.
|
101
|
+
msg = msg.gsub(/ ?#{pattern.gsub('|','\|')} ?/,' ')
|
102
|
+
else
|
103
|
+
msg = msg.gsub(pattern,v.to_s)
|
104
|
+
end
|
105
|
+
found = true
|
106
|
+
end
|
107
|
+
}
|
108
|
+
unless found then
|
109
|
+
errargs += _errargs
|
110
|
+
end
|
111
|
+
}
|
112
|
+
[msg,errargs]
|
113
|
+
end
|
114
|
+
|
115
|
+
# Regex that looks for a sed command eg
|
116
|
+
# "s/pattern/replacement/flags" in a string.
|
117
|
+
#
|
118
|
+
# This regex doesn't handle backslash escapes, so if pattern or
|
119
|
+
# replacement contain '/' use another delimiter eg s#...#...# etc.
|
120
|
+
#
|
121
|
+
# Non alphanumeric delimiters are allowed.
|
122
|
+
#
|
123
|
+
# Returns: nil or a MatchData instance with symbol keys:
|
124
|
+
# :sed (the whole sed command), :sep (the separator), :pattern,
|
125
|
+
# :replacement, :flags
|
126
|
+
#
|
127
|
+
# If you want to combine this regex, call
|
128
|
+
# sed_regex.source => <string>
|
129
|
+
|
130
|
+
def self.sed_regex
|
131
|
+
%r{
|
132
|
+
^(?<before>.*)
|
133
|
+
\b
|
134
|
+
(?<sed>
|
135
|
+
s
|
136
|
+
(?<sep>[^A-z0-9\s])
|
137
|
+
(?<pattern>(?!\g<sep>)*.*)
|
138
|
+
\k<sep>
|
139
|
+
(?<replacement>(?!\g<sep>)*.*)
|
140
|
+
\k<sep>
|
141
|
+
(?<flags>[A-z]*)
|
142
|
+
)
|
143
|
+
(?<after>.*)$
|
144
|
+
}x
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|