chatrix-bot 1.0.0.pre
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.
- checksums.yaml +7 -0
- data/.editorconfig +12 -0
- data/.gitignore +170 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +11 -0
- data/.yardopts +5 -0
- data/Gemfile +31 -0
- data/Guardfile +67 -0
- data/LICENSE +21 -0
- data/README.md +67 -0
- data/Rakefile +11 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/chatrix-bot.gemspec +32 -0
- data/exe/chatrix-bot +53 -0
- data/lib/chatrix/bot.rb +97 -0
- data/lib/chatrix/bot/command.rb +99 -0
- data/lib/chatrix/bot/config.rb +60 -0
- data/lib/chatrix/bot/errors.rb +16 -0
- data/lib/chatrix/bot/parameter.rb +57 -0
- data/lib/chatrix/bot/pattern.rb +25 -0
- data/lib/chatrix/bot/plugin.rb +149 -0
- data/lib/chatrix/bot/plugin_manager.rb +83 -0
- data/lib/chatrix/bot/plugins.rb +16 -0
- data/lib/chatrix/bot/plugins/echo.rb +36 -0
- data/lib/chatrix/bot/plugins/help.rb +50 -0
- data/lib/chatrix/bot/plugins/hug.rb +22 -0
- data/lib/chatrix/bot/version.rb +8 -0
- metadata +102 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'chatrix/bot/command'
|
|
5
|
+
require 'chatrix/bot/pattern'
|
|
6
|
+
|
|
7
|
+
module Chatrix
|
|
8
|
+
class Bot
|
|
9
|
+
# Base class for bot plugins.
|
|
10
|
+
#
|
|
11
|
+
# Plugins will get their class name (lowercased) as their main
|
|
12
|
+
# command name. Meaning if you make a class as such:
|
|
13
|
+
# class MyPlugin < Plugin
|
|
14
|
+
# It will be called using `!myplugin` in the chat.
|
|
15
|
+
#
|
|
16
|
+
# Additional command aliases can be specified with TODO.
|
|
17
|
+
class Plugin
|
|
18
|
+
# Initializes a new Plugin instance.
|
|
19
|
+
# @param bot [Chatrix::Bot] The bot instance in control of the plugin.
|
|
20
|
+
def initialize(bot)
|
|
21
|
+
@bot = bot
|
|
22
|
+
@log = @bot.log
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Handles a plugin command.
|
|
26
|
+
#
|
|
27
|
+
# @param room [Room] The room the command was sent in.
|
|
28
|
+
# @param sender [User] The user who issued the command.
|
|
29
|
+
# @param name [String] The name of the command.
|
|
30
|
+
# @param body [String] The command body (text after command name).
|
|
31
|
+
def handle_command(room, sender, name, body)
|
|
32
|
+
command = self.class.command name
|
|
33
|
+
|
|
34
|
+
unless @bot.admin? sender
|
|
35
|
+
check_command_permissions(room, command, sender)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
data = command.parse body
|
|
39
|
+
meth = command.handler || :on_command
|
|
40
|
+
send(meth, room, sender, command.name, data) if respond_to? meth
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Parses a message from a room.
|
|
44
|
+
# If there are any patterns registred for the plugin that matches the
|
|
45
|
+
# message body, the relevant handlers on the plugin will be invoked for
|
|
46
|
+
# the message.
|
|
47
|
+
#
|
|
48
|
+
# All messages, regardless of patterns, will be passed to the
|
|
49
|
+
# `:on_message` method, if it is defined.
|
|
50
|
+
#
|
|
51
|
+
# @param room [Room] The room the message was sent in.
|
|
52
|
+
# @param sender [User] The user who sent the message.
|
|
53
|
+
# @param message [Message] The message that was sent.
|
|
54
|
+
def parse_message(room, message)
|
|
55
|
+
send(:on_message, room, message) if respond_to? :on_message
|
|
56
|
+
pattern = self.class.match message.body
|
|
57
|
+
handle_match(room, message, pattern) if pattern
|
|
58
|
+
rescue => e
|
|
59
|
+
@log.error "Error while parsing message in #{self.class}: #{e.inspect}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def handle_match(room, message, pattern)
|
|
65
|
+
meth = pattern.handler || :on_match
|
|
66
|
+
return unless respond_to? meth
|
|
67
|
+
send meth, room, message, pattern.match(message.body)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def check_command_permissions(room, command, sender)
|
|
71
|
+
user_power = sender.power_in room
|
|
72
|
+
raise PermissionError unless user_power >= self.class.command_power
|
|
73
|
+
command.test
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class << self
|
|
77
|
+
attr_reader :commands
|
|
78
|
+
|
|
79
|
+
attr_reader :command_power
|
|
80
|
+
|
|
81
|
+
def inherited(subclass)
|
|
82
|
+
{
|
|
83
|
+
:@commands => [], :@patterns => [], :@command_power => 0
|
|
84
|
+
}.each { |var, val| subclass.instance_variable_set(var, val) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def command?(name)
|
|
88
|
+
!command(name).nil?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Gets the command with the specified name (or alias).
|
|
92
|
+
# @param name [String] The name to search for, can also be an alias.
|
|
93
|
+
# @return [Command] The command with the specified name or alias.
|
|
94
|
+
def command(name)
|
|
95
|
+
@commands.find { |c| c.name_or_alias?(name) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Attempts to match the given string against all the patterns defined
|
|
99
|
+
# for the plugin.
|
|
100
|
+
# @param text [String] The text to check for matches.
|
|
101
|
+
# @return [Pattern, nil] The result of the first successful match,
|
|
102
|
+
# or `nil` if no match was found.
|
|
103
|
+
def match(text)
|
|
104
|
+
@patterns.find { |p| p.match? text }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
protected
|
|
108
|
+
|
|
109
|
+
# Registers a command that the plugin should respond to.
|
|
110
|
+
#
|
|
111
|
+
# @param command [String] The name of the command.
|
|
112
|
+
# @param syntax [String] Command syntax, this is used to determine
|
|
113
|
+
# the parameters accepted by the command. See {Parameter} for more
|
|
114
|
+
# information on parameters and {Command} for more information
|
|
115
|
+
# regarding the structure of the syntax string.
|
|
116
|
+
# @param help [String] Help text for the command.
|
|
117
|
+
# @param opts [Hash] Additional options.
|
|
118
|
+
#
|
|
119
|
+
# @option opts [Symbol] :handler Name of the method in the plugin class
|
|
120
|
+
# that should handle this command.
|
|
121
|
+
# @option opts [Array<String>] :aliases A list of aliases that can be
|
|
122
|
+
# used to call this command in addition to the main name.
|
|
123
|
+
def register_command(command, syntax, help, opts = {})
|
|
124
|
+
@commands.push Command.new command.to_s.downcase, syntax, help, opts
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Registers a RegEx pattern that the plugin should listen to
|
|
128
|
+
# with an optional explicit handler for the match.
|
|
129
|
+
#
|
|
130
|
+
# @param pattern [Regexp] The RegEx pattern to add.
|
|
131
|
+
# @param handler [Symbol, nil] The method to call on the plugin when
|
|
132
|
+
# a matching message is detected.
|
|
133
|
+
def register_pattern(pattern, handler = nil)
|
|
134
|
+
@patterns.push Pattern.new pattern, handler
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Adds RegEx patterns to the plugin.
|
|
138
|
+
# @param patterns [Regexp] RegEx patterns to add.
|
|
139
|
+
def register_patterns(*patterns)
|
|
140
|
+
patterns.each { |p| @patterns.push Pattern.new p }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def command_restriction(level)
|
|
144
|
+
@command_power = level
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'chatrix/bot/plugins'
|
|
5
|
+
|
|
6
|
+
module Chatrix
|
|
7
|
+
class Bot
|
|
8
|
+
# Manages plugins for the bot.
|
|
9
|
+
class PluginManager
|
|
10
|
+
def initialize(bot)
|
|
11
|
+
@bot = bot
|
|
12
|
+
|
|
13
|
+
@log = @bot.log
|
|
14
|
+
|
|
15
|
+
# The plugins hash will have the plugin type as the key, and the
|
|
16
|
+
# instance of the plugin as the value.
|
|
17
|
+
@plugins = {}
|
|
18
|
+
|
|
19
|
+
add_standard_plugins
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add(type)
|
|
23
|
+
unless type < Plugin
|
|
24
|
+
raise ArgumentError, 'Argument must be a plugin type'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return if @plugins.key? type
|
|
28
|
+
|
|
29
|
+
@log.info "Adding new plugin: #{type}"
|
|
30
|
+
|
|
31
|
+
@plugins[type] = type.new @bot
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def remove(type)
|
|
35
|
+
return unless @plugins.key? type
|
|
36
|
+
@log.info "Removing plugin: #{type}"
|
|
37
|
+
plugin = @plugins[type]
|
|
38
|
+
plugin.removed if plugin.respond_to? :removed
|
|
39
|
+
@plugins[type] = nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def types
|
|
43
|
+
@plugins.keys
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def plugins
|
|
47
|
+
@plugins.values
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def parse_message(room, message)
|
|
51
|
+
return parse_command(room, message) if Command.command? message.body
|
|
52
|
+
plugins.each { |p| p.parse_message room, message }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def parse_command(room, message)
|
|
58
|
+
data = Command.parse message.body
|
|
59
|
+
|
|
60
|
+
type = types.find { |t| t.command? data[:name] }
|
|
61
|
+
|
|
62
|
+
plugin = @plugins[type]
|
|
63
|
+
|
|
64
|
+
send_command(plugin, room, message.sender, data) if plugin
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def send_command(plugin, room, sender, data)
|
|
68
|
+
plugin.handle_command(room, sender, data[:name], data[:body])
|
|
69
|
+
rescue PermissionError
|
|
70
|
+
room.messaging.send_notice <<~EOF
|
|
71
|
+
I'm sorry, #{sender}, I cannot let you do that.
|
|
72
|
+
EOF
|
|
73
|
+
rescue => e
|
|
74
|
+
@log.error "Error parsing #{data[:name]} command in #{room}"
|
|
75
|
+
room.messaging.send_notice "Command error: #{e.class}:#{e.message}"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def add_standard_plugins
|
|
79
|
+
Plugins.constants.each { |c| add(Plugins.const_get(c)) }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'chatrix/bot/plugin'
|
|
5
|
+
|
|
6
|
+
module Chatrix
|
|
7
|
+
class Bot
|
|
8
|
+
# Contains a number of standard plugins for the bot.
|
|
9
|
+
module Plugins
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
require 'chatrix/bot/plugins/help'
|
|
15
|
+
require 'chatrix/bot/plugins/echo'
|
|
16
|
+
require 'chatrix/bot/plugins/hug'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Chatrix
|
|
5
|
+
class Bot
|
|
6
|
+
module Plugins
|
|
7
|
+
# Provides a command to make the bot echo what was passed in as
|
|
8
|
+
# argument to the command.
|
|
9
|
+
class Echo < Plugin
|
|
10
|
+
command_restriction 50
|
|
11
|
+
|
|
12
|
+
register_command 'echo', '<text>',
|
|
13
|
+
'Makes the bot echo the specified text to chat',
|
|
14
|
+
aliases: ['say'], handler: :say
|
|
15
|
+
|
|
16
|
+
register_command 'act', '<text>',
|
|
17
|
+
'Makes the bot perform an emote',
|
|
18
|
+
aliases: %w(em emote), handler: :emote
|
|
19
|
+
|
|
20
|
+
register_command 'notice', '<text>', 'Sends a notice', handler: :notice
|
|
21
|
+
|
|
22
|
+
def say(room, _sender, _command, args)
|
|
23
|
+
room.messaging.send_message args[:text]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def emote(room, _sender, _command, args)
|
|
27
|
+
room.messaging.send_emote args[:text]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def notice(room, _sender, _command, args)
|
|
31
|
+
room.messaging.send_notice args[:text]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chatrix
|
|
4
|
+
class Bot
|
|
5
|
+
module Plugins
|
|
6
|
+
# Provides a help command.
|
|
7
|
+
class Help < Plugin
|
|
8
|
+
register_command 'help', '[command]',
|
|
9
|
+
'Gives general help or specific help for a command',
|
|
10
|
+
handler: :help, aliases: ['h']
|
|
11
|
+
|
|
12
|
+
def help(room, sender, _command, args)
|
|
13
|
+
@log.debug "#{sender} is requesting help"
|
|
14
|
+
command = args[:command]
|
|
15
|
+
command.nil? ? general_help(room) : command_help(room, command)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def general_help(room)
|
|
21
|
+
commands = []
|
|
22
|
+
|
|
23
|
+
@bot.plugin_manager.types.each do |type|
|
|
24
|
+
commands.concat type.commands.map(&:name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
room.messaging.send_notice <<~EOF
|
|
28
|
+
Available commands: #{commands.uniq.join ', '}
|
|
29
|
+
For help about a command, type #{Command.stylize('help')} <command>
|
|
30
|
+
EOF
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def command_help(room, command)
|
|
34
|
+
type = @bot.plugin_manager.types.find { |t| t.command? command }
|
|
35
|
+
|
|
36
|
+
cmd = type.command(command) if type
|
|
37
|
+
|
|
38
|
+
if cmd
|
|
39
|
+
room.messaging.send_notice <<~EOF
|
|
40
|
+
Command #{cmd.name} provided by #{type} plugin.
|
|
41
|
+
#{cmd.usage}
|
|
42
|
+
EOF
|
|
43
|
+
else
|
|
44
|
+
room.messaging.send_notice 'No plugin found providing that command'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chatrix
|
|
4
|
+
class Bot
|
|
5
|
+
module Plugins
|
|
6
|
+
# Plugin that hugs sad people!
|
|
7
|
+
class Hug < Plugin
|
|
8
|
+
# Matches :(, :'(, D:, D':, ):, )':, ;-;, ;_;
|
|
9
|
+
register_pattern(/(?<!\S)(?:\:'?\(|D'?:|\)'?:|;[\-_];)(?!\S)/, :hug)
|
|
10
|
+
register_pattern(/(?<!\S)(?:\:'?c)(?!\S)/i, :hug)
|
|
11
|
+
|
|
12
|
+
# Method to handle messages that contain sad faces.
|
|
13
|
+
def hug(room, message, _match)
|
|
14
|
+
sender = message.sender
|
|
15
|
+
@log.debug "#{sender} is in need of some love!"
|
|
16
|
+
room.messaging.send_emote "hugs #{sender.displayname || sender}"
|
|
17
|
+
@log.debug 'Love sent'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: chatrix-bot
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0.pre
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Adam Hellberg
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-07-03 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: chatrix
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.12'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.12'
|
|
41
|
+
description:
|
|
42
|
+
email:
|
|
43
|
+
- sharparam@sharparam.com
|
|
44
|
+
executables:
|
|
45
|
+
- chatrix-bot
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- ".editorconfig"
|
|
50
|
+
- ".gitignore"
|
|
51
|
+
- ".rspec"
|
|
52
|
+
- ".rubocop.yml"
|
|
53
|
+
- ".travis.yml"
|
|
54
|
+
- ".yardopts"
|
|
55
|
+
- Gemfile
|
|
56
|
+
- Guardfile
|
|
57
|
+
- LICENSE
|
|
58
|
+
- README.md
|
|
59
|
+
- Rakefile
|
|
60
|
+
- bin/console
|
|
61
|
+
- bin/setup
|
|
62
|
+
- chatrix-bot.gemspec
|
|
63
|
+
- exe/chatrix-bot
|
|
64
|
+
- lib/chatrix/bot.rb
|
|
65
|
+
- lib/chatrix/bot/command.rb
|
|
66
|
+
- lib/chatrix/bot/config.rb
|
|
67
|
+
- lib/chatrix/bot/errors.rb
|
|
68
|
+
- lib/chatrix/bot/parameter.rb
|
|
69
|
+
- lib/chatrix/bot/pattern.rb
|
|
70
|
+
- lib/chatrix/bot/plugin.rb
|
|
71
|
+
- lib/chatrix/bot/plugin_manager.rb
|
|
72
|
+
- lib/chatrix/bot/plugins.rb
|
|
73
|
+
- lib/chatrix/bot/plugins/echo.rb
|
|
74
|
+
- lib/chatrix/bot/plugins/help.rb
|
|
75
|
+
- lib/chatrix/bot/plugins/hug.rb
|
|
76
|
+
- lib/chatrix/bot/version.rb
|
|
77
|
+
homepage: https://github.com/Sharparam/chatrix-bot
|
|
78
|
+
licenses:
|
|
79
|
+
- MIT
|
|
80
|
+
metadata: {}
|
|
81
|
+
post_install_message:
|
|
82
|
+
rdoc_options: []
|
|
83
|
+
require_paths:
|
|
84
|
+
- lib
|
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 2.3.0
|
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: 1.3.1
|
|
95
|
+
requirements: []
|
|
96
|
+
rubyforge_project:
|
|
97
|
+
rubygems_version: 2.5.1
|
|
98
|
+
signing_key:
|
|
99
|
+
specification_version: 4
|
|
100
|
+
summary: A Ruby chatbot for Matrix with plugin support
|
|
101
|
+
test_files: []
|
|
102
|
+
has_rdoc:
|