discordrb 3.1.1 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of discordrb might be problematic. Click here for more details.

Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +126 -0
  3. data/.codeclimate.yml +16 -0
  4. data/.github/CONTRIBUTING.md +13 -0
  5. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
  7. data/.github/pull_request_template.md +37 -0
  8. data/.gitignore +5 -0
  9. data/.rubocop.yml +39 -33
  10. data/.travis.yml +27 -2
  11. data/.yardopts +1 -1
  12. data/CHANGELOG.md +808 -208
  13. data/Gemfile +4 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +108 -53
  16. data/Rakefile +14 -1
  17. data/bin/console +1 -0
  18. data/bin/travis_build_docs.sh +17 -0
  19. data/discordrb-webhooks.gemspec +26 -0
  20. data/discordrb.gemspec +24 -15
  21. data/lib/discordrb.rb +75 -2
  22. data/lib/discordrb/allowed_mentions.rb +36 -0
  23. data/lib/discordrb/api.rb +126 -27
  24. data/lib/discordrb/api/channel.rb +165 -43
  25. data/lib/discordrb/api/invite.rb +10 -7
  26. data/lib/discordrb/api/server.rb +240 -61
  27. data/lib/discordrb/api/user.rb +26 -24
  28. data/lib/discordrb/api/webhook.rb +83 -0
  29. data/lib/discordrb/await.rb +1 -2
  30. data/lib/discordrb/bot.rb +417 -149
  31. data/lib/discordrb/cache.rb +42 -10
  32. data/lib/discordrb/colour_rgb.rb +43 -0
  33. data/lib/discordrb/commands/command_bot.rb +186 -31
  34. data/lib/discordrb/commands/container.rb +30 -16
  35. data/lib/discordrb/commands/parser.rb +102 -47
  36. data/lib/discordrb/commands/rate_limiter.rb +18 -17
  37. data/lib/discordrb/container.rb +245 -41
  38. data/lib/discordrb/data.rb +27 -2511
  39. data/lib/discordrb/data/activity.rb +264 -0
  40. data/lib/discordrb/data/application.rb +50 -0
  41. data/lib/discordrb/data/attachment.rb +56 -0
  42. data/lib/discordrb/data/audit_logs.rb +345 -0
  43. data/lib/discordrb/data/channel.rb +849 -0
  44. data/lib/discordrb/data/embed.rb +251 -0
  45. data/lib/discordrb/data/emoji.rb +82 -0
  46. data/lib/discordrb/data/integration.rb +83 -0
  47. data/lib/discordrb/data/invite.rb +137 -0
  48. data/lib/discordrb/data/member.rb +297 -0
  49. data/lib/discordrb/data/message.rb +334 -0
  50. data/lib/discordrb/data/overwrite.rb +102 -0
  51. data/lib/discordrb/data/profile.rb +91 -0
  52. data/lib/discordrb/data/reaction.rb +33 -0
  53. data/lib/discordrb/data/recipient.rb +34 -0
  54. data/lib/discordrb/data/role.rb +191 -0
  55. data/lib/discordrb/data/server.rb +1002 -0
  56. data/lib/discordrb/data/user.rb +204 -0
  57. data/lib/discordrb/data/voice_region.rb +45 -0
  58. data/lib/discordrb/data/voice_state.rb +41 -0
  59. data/lib/discordrb/data/webhook.rb +145 -0
  60. data/lib/discordrb/errors.rb +36 -2
  61. data/lib/discordrb/events/bans.rb +7 -5
  62. data/lib/discordrb/events/channels.rb +2 -0
  63. data/lib/discordrb/events/generic.rb +19 -3
  64. data/lib/discordrb/events/guilds.rb +129 -6
  65. data/lib/discordrb/events/invites.rb +125 -0
  66. data/lib/discordrb/events/members.rb +6 -2
  67. data/lib/discordrb/events/message.rb +86 -36
  68. data/lib/discordrb/events/presence.rb +23 -16
  69. data/lib/discordrb/events/raw.rb +47 -0
  70. data/lib/discordrb/events/reactions.rb +159 -0
  71. data/lib/discordrb/events/roles.rb +7 -6
  72. data/lib/discordrb/events/typing.rb +9 -5
  73. data/lib/discordrb/events/voice_server_update.rb +47 -0
  74. data/lib/discordrb/events/voice_state_update.rb +29 -9
  75. data/lib/discordrb/events/webhooks.rb +64 -0
  76. data/lib/discordrb/gateway.rb +219 -88
  77. data/lib/discordrb/id_object.rb +39 -0
  78. data/lib/discordrb/light.rb +1 -1
  79. data/lib/discordrb/light/integrations.rb +1 -1
  80. data/lib/discordrb/light/light_bot.rb +1 -1
  81. data/lib/discordrb/logger.rb +12 -11
  82. data/lib/discordrb/paginator.rb +57 -0
  83. data/lib/discordrb/permissions.rb +148 -14
  84. data/lib/discordrb/version.rb +1 -1
  85. data/lib/discordrb/voice/encoder.rb +14 -15
  86. data/lib/discordrb/voice/network.rb +86 -45
  87. data/lib/discordrb/voice/sodium.rb +96 -0
  88. data/lib/discordrb/voice/voice_bot.rb +52 -40
  89. data/lib/discordrb/webhooks.rb +12 -0
  90. data/lib/discordrb/websocket.rb +2 -2
  91. metadata +137 -34
@@ -9,20 +9,26 @@ module Discordrb::Commands
9
9
  module CommandContainer
10
10
  include RateLimiter
11
11
 
12
- # @return [Hash<Symbol, Command>] hash of command names and commands this container has.
12
+ # @return [Hash<Symbol, Command, CommandAlias>] hash of command names and commands this container has.
13
13
  attr_reader :commands
14
14
 
15
15
  # Adds a new command to the container.
16
- # @param name [Symbol, Array<Symbol>] The name of the command to add, or an array of multiple names for the command
16
+ # @param name [Symbol] The name of the command to add.
17
17
  # @param attributes [Hash] The attributes to initialize the command with.
18
+ # @option attributes [Array<Symbol>] :aliases A list of additional names for this command. This in effect
19
+ # creates {CommandAlias} objects in the container ({#commands}) that refer to the newly created command.
20
+ # Additionally, the default help command will identify these command names as an alias where applicable.
18
21
  # @option attributes [Integer] :permission_level The minimum permission level that can use this command, inclusive.
19
22
  # See {CommandBot#set_user_permission} and {CommandBot#set_role_permission}.
20
23
  # @option attributes [String, false] :permission_message Message to display when a user does not have sufficient
21
24
  # permissions to execute a command. %name% in the message will be replaced with the name of the command. Disable
22
25
  # the message by setting this option to false.
23
26
  # @option attributes [Array<Symbol>] :required_permissions Discord action permissions (e.g. `:kick_members`) that
24
- # should be required to use this command. See {Discordrb::Permissions::Flags} for a list.
25
- # @option attributes [Array<Role>, Array<#resolve_id>] :required_roles Roles that user should have to use this command.
27
+ # should be required to use this command. See {Discordrb::Permissions::FLAGS} for a list.
28
+ # @option attributes [Array<Role>, Array<String, Integer>] :required_roles Roles, or their IDs, that user must have to use this command
29
+ # (user must have all of them).
30
+ # @option attributes [Array<Role>, Array<String, Integer>] :allowed_roles Roles, or their IDs, that user should have to use this command
31
+ # (user should have at least one of them).
26
32
  # @option attributes [Array<String, Integer, Channel>] :channels The channels that this command can be used on. An
27
33
  # empty array indicates it can be used on any channel. Supersedes the command bot attribute.
28
34
  # @option attributes [true, false] :chain_usable Whether this command is able to be used inside of a command chain
@@ -33,6 +39,9 @@ module Discordrb::Commands
33
39
  # command if the user asks for it.
34
40
  # @option attributes [String] :usage A short description of how this command should be used. Will be displayed in
35
41
  # the help command or if the user uses it wrong.
42
+ # @option attributes [Array<Class>] :arg_types An array of argument classes which will be used for type-checking.
43
+ # Hard-coded for some native classes, but can be used with any class that implements static
44
+ # method `from_argument`.
36
45
  # @option attributes [Integer] :min_args The minimum number of arguments this command should have. If a user
37
46
  # attempts to call the command with fewer arguments, the usage information will be displayed, if it exists.
38
47
  # @option attributes [Integer] :max_args The maximum number of arguments the command should have.
@@ -41,23 +50,30 @@ module Discordrb::Commands
41
50
  # command will be available again.
42
51
  # @option attributes [Symbol] :bucket The rate limit bucket that should be used for rate limiting. No rate limiting
43
52
  # will be done if unspecified or nil.
53
+ # @option attributes [String, #call] :rescue A string to respond with, or a block to be called in the event an exception
54
+ # is raised internally. If given a String, `%exception%` will be substituted with the exception's `#message`. If given
55
+ # a `Proc`, it will be passed the `CommandEvent` along with the `Exception`.
44
56
  # @yield The block is executed when the command is executed.
45
57
  # @yieldparam event [CommandEvent] The event of the message that contained the command.
58
+ # @note `LocalJumpError`s are rescued from internally, giving bots the opportunity to use `return` or `break` in
59
+ # their blocks without propagating an exception.
46
60
  # @return [Command] The command that was added.
47
61
  def command(name, attributes = {}, &block)
48
62
  @commands ||= {}
49
- if name.is_a? Array
50
- new_command = nil
51
63
 
52
- name.each do |e|
53
- new_command = Command.new(e, attributes, &block)
54
- @commands[e] = new_command
55
- end
64
+ # TODO: Remove in 4.0
65
+ if name.is_a?(Array)
66
+ name, *aliases = name
67
+ attributes[:aliases] = aliases if attributes[:aliases].nil?
68
+ Discordrb::LOGGER.warn("While registering command #{name.inspect}")
69
+ Discordrb::LOGGER.warn('Arrays for command aliases is removed. Please use `aliases` argument instead.')
70
+ end
56
71
 
57
- new_command
58
- else
59
- @commands[name] = Command.new(name, attributes, &block)
72
+ new_command = Command.new(name, attributes, &block)
73
+ new_command.attributes[:aliases].each do |aliased_name|
74
+ @commands[aliased_name] = CommandAlias.new(aliased_name, new_command)
60
75
  end
76
+ @commands[name] = new_command
61
77
  end
62
78
 
63
79
  # Removes a specific command from this container.
@@ -83,9 +99,7 @@ module Discordrb::Commands
83
99
  container_modules = container.singleton_class.included_modules
84
100
 
85
101
  # If the container is an EventContainer and we can include it, then do that
86
- if container_modules.include?(Discordrb::EventContainer) && respond_to?(:include_events)
87
- include_events(container)
88
- end
102
+ include_events(container) if container_modules.include?(Discordrb::EventContainer) && respond_to?(:include_events)
89
103
 
90
104
  if container_modules.include? Discordrb::Commands::CommandContainer
91
105
  include_commands(container)
@@ -22,9 +22,12 @@ module Discordrb::Commands
22
22
  # Discord action permissions required to use this command
23
23
  required_permissions: attributes[:required_permissions] || [],
24
24
 
25
- # Roles required to use this command
25
+ # Roles required to use this command (all? comparison)
26
26
  required_roles: attributes[:required_roles] || [],
27
27
 
28
+ # Roles allowed to use this command (any? comparison)
29
+ allowed_roles: attributes[:allowed_roles] || [],
30
+
28
31
  # Channels this command can be used on
29
32
  channels: attributes[:channels] || nil,
30
33
 
@@ -40,6 +43,9 @@ module Discordrb::Commands
40
43
  # Usage description (for help command and error messages)
41
44
  usage: attributes[:usage] || nil,
42
45
 
46
+ # Array of arguments (for type-checking)
47
+ arg_types: attributes[:arg_types] || nil,
48
+
43
49
  # Parameter list (for help command and error messages)
44
50
  parameters: attributes[:parameters] || nil,
45
51
 
@@ -54,7 +60,13 @@ module Discordrb::Commands
54
60
  rate_limit_message: attributes[:rate_limit_message],
55
61
 
56
62
  # Rate limiting bucket (nil for no rate limiting)
57
- bucket: attributes[:bucket]
63
+ bucket: attributes[:bucket],
64
+
65
+ # Block for handling internal exceptions, or a string to respond with
66
+ rescue: attributes[:rescue],
67
+
68
+ # A list of aliases that reference this command
69
+ aliases: attributes[:aliases] || []
58
70
  }
59
71
 
60
72
  @block = block
@@ -69,36 +81,57 @@ module Discordrb::Commands
69
81
  # @return [String] the result of the execution.
70
82
  def call(event, arguments, chained = false, check_permissions = true)
71
83
  if arguments.length < @attributes[:min_args]
72
- event.respond "Too few arguments for command `#{name}`!"
73
- event.respond "Usage: `#{@attributes[:usage]}`" if @attributes[:usage]
84
+ response = "Too few arguments for command `#{name}`!"
85
+ response += "\nUsage: `#{@attributes[:usage]}`" if @attributes[:usage]
86
+ event.respond(response)
74
87
  return
75
88
  end
76
89
  if @attributes[:max_args] >= 0 && arguments.length > @attributes[:max_args]
77
- event.respond "Too many arguments for command `#{name}`!"
78
- event.respond "Usage: `#{@attributes[:usage]}`" if @attributes[:usage]
90
+ response = "Too many arguments for command `#{name}`!"
91
+ response += "\nUsage: `#{@attributes[:usage]}`" if @attributes[:usage]
92
+ event.respond(response)
79
93
  return
80
94
  end
81
- unless @attributes[:chain_usable]
82
- if chained
83
- event.respond "Command `#{name}` cannot be used in a command chain!"
84
- return
85
- end
95
+ unless @attributes[:chain_usable] && !chained
96
+ event.respond "Command `#{name}` cannot be used in a command chain!"
97
+ return
86
98
  end
87
99
 
88
100
  if check_permissions
89
101
  rate_limited = event.bot.rate_limited?(@attributes[:bucket], event.author)
90
102
  if @attributes[:bucket] && rate_limited
91
- if @attributes[:rate_limit_message]
92
- event.respond @attributes[:rate_limit_message].gsub('%time%', rate_limited.round(2).to_s)
93
- end
103
+ event.respond @attributes[:rate_limit_message].gsub('%time%', rate_limited.round(2).to_s) if @attributes[:rate_limit_message]
94
104
  return
95
105
  end
96
106
  end
97
107
 
98
108
  result = @block.call(event, *arguments)
99
109
  event.drain_into(result)
100
- rescue LocalJumpError # occurs when breaking
101
- nil
110
+ rescue LocalJumpError => e # occurs when breaking
111
+ result = e.exit_value
112
+ event.drain_into(result)
113
+ rescue StandardError => e # Something went wrong inside our @block!
114
+ rescue_value = @attributes[:rescue] || event.bot.attributes[:rescue]
115
+ if rescue_value
116
+ event.respond(rescue_value.gsub('%exception%', e.message)) if rescue_value.is_a?(String)
117
+ rescue_value.call(event, e) if rescue_value.respond_to?(:call)
118
+ end
119
+
120
+ raise e
121
+ end
122
+ end
123
+
124
+ # A command that references another command
125
+ class CommandAlias
126
+ # @return [Symbol] the name of this alias
127
+ attr_reader :name
128
+
129
+ # @return [Command] the command this alias points to
130
+ attr_reader :aliased_command
131
+
132
+ def initialize(name, aliased_command)
133
+ @name = name
134
+ @aliased_command = aliased_command
102
135
  end
103
136
  end
104
137
 
@@ -123,46 +156,61 @@ module Discordrb::Commands
123
156
  b_level = 0
124
157
  result = ''
125
158
  quoted = false
126
- hacky_delim, hacky_space, hacky_prev = [0xe001, 0xe002, 0xe003].pack('U*').chars
159
+ escaped = false
160
+ hacky_delim, hacky_space, hacky_prev, hacky_newline = [0xe001, 0xe002, 0xe003, 0xe004].pack('U*').chars
127
161
 
128
162
  @chain.each_char.each_with_index do |char, index|
129
- # Quote begin
130
- if char == @attributes[:quote_start] && !quoted
131
- quoted = true
163
+ # Escape character
164
+ if char == '\\' && !escaped
165
+ escaped = true
132
166
  next
133
- end
134
-
135
- # Quote end
136
- if char == @attributes[:quote_end] && quoted
137
- quoted = false
138
- next
139
- end
140
-
141
- if char == @attributes[:chain_delimiter] && quoted
142
- result += hacky_delim
143
- next
144
- end
145
-
146
- if char == @attributes[:previous] && quoted
147
- result += hacky_prev
167
+ elsif escaped && b_level <= 0
168
+ result += char
169
+ escaped = false
148
170
  next
149
171
  end
150
172
 
151
- if char == ' ' && quoted
152
- result += hacky_space
153
- next
154
- end
173
+ if quoted
174
+ # Quote end
175
+ if char == @attributes[:quote_end]
176
+ quoted = false
177
+ next
178
+ end
155
179
 
156
- if char == @attributes[:sub_chain_start] && !quoted
157
- b_start = index if b_level.zero?
158
- b_level += 1
180
+ if b_level <= 0
181
+ case char
182
+ when @attributes[:chain_delimiter]
183
+ result += hacky_delim
184
+ next
185
+ when @attributes[:previous]
186
+ result += hacky_prev
187
+ next
188
+ when ' '
189
+ result += hacky_space
190
+ next
191
+ when "\n"
192
+ result += hacky_newline
193
+ next
194
+ end
195
+ end
196
+ else
197
+ case char
198
+ when @attributes[:quote_start] # Quote begin
199
+ quoted = true
200
+ next
201
+ when @attributes[:sub_chain_start]
202
+ b_start = index if b_level.zero?
203
+ b_level += 1
204
+ end
159
205
  end
160
206
 
161
207
  result += char if b_level <= 0
162
208
 
163
209
  next unless char == @attributes[:sub_chain_end] && !quoted
210
+
164
211
  b_level -= 1
165
212
  next unless b_level.zero?
213
+
166
214
  nested = @chain[b_start + 1..index - 1]
167
215
  subchain = CommandChain.new(nested, @bot, true)
168
216
  result += subchain.execute(event)
@@ -179,10 +227,14 @@ module Discordrb::Commands
179
227
  chain_to_split = @chain
180
228
 
181
229
  # Don't break if a command is called the same thing as the chain delimiter
182
- chain_to_split.slice!(1..-1) if chain_to_split.start_with?(@attributes[:chain_delimiter])
230
+ chain_to_split = chain_to_split.slice(1..-1) if !@attributes[:chain_delimiter].empty? && chain_to_split.start_with?(@attributes[:chain_delimiter])
183
231
 
184
232
  first = true
185
- split_chain = chain_to_split.split(@attributes[:chain_delimiter])
233
+ split_chain = if @attributes[:chain_delimiter].empty?
234
+ [chain_to_split]
235
+ else
236
+ chain_to_split.split(@attributes[:chain_delimiter])
237
+ end
186
238
  split_chain.each do |command|
187
239
  command = @attributes[:chain_delimiter] + command if first && @chain.start_with?(@attributes[:chain_delimiter])
188
240
  first = false
@@ -205,13 +257,16 @@ module Discordrb::Commands
205
257
 
206
258
  arguments = arguments.split ' '
207
259
 
208
- # Replace the hacky spaces with actual spaces
260
+ # Replace the hacky spaces/newlines with actual ones
209
261
  arguments.map! do |elem|
210
- elem.gsub hacky_space, ' '
262
+ elem.gsub(hacky_space, ' ').gsub(hacky_newline, "\n")
211
263
  end
212
264
 
213
265
  # Finally execute the command
214
266
  prev = @bot.execute_command(command_name.to_sym, event, arguments, split_chain.length > 1 || @subchain)
267
+
268
+ # Stop chain if execute_command failed (maybe the command doesn't exist, or permissions failed, etc.)
269
+ break unless prev
215
270
  end
216
271
 
217
272
  prev
@@ -251,7 +306,7 @@ module Discordrb::Commands
251
306
  private
252
307
 
253
308
  def divide_chain(chain)
254
- chain_args_index = chain.index @attributes[:chain_args_delim]
309
+ chain_args_index = chain.index(@attributes[:chain_args_delim]) unless @attributes[:chain_args_delim].empty?
255
310
  chain_args = []
256
311
 
257
312
  if chain_args_index
@@ -35,10 +35,11 @@ module Discordrb::Commands
35
35
  end
36
36
 
37
37
  # Performs a rate limiting request
38
- # @param thing [#resolve_id, Integer, Symbol] The particular thing that should be rate-limited (usually a user/channel, but you can also choose arbitrary integers or symbols)
38
+ # @param thing [String, Integer, Symbol] The particular thing that should be rate-limited (usually a user/channel, but you can also choose arbitrary integers or symbols)
39
39
  # @param rate_limit_time [Time] The time to base the rate limiting on, only useful for testing.
40
+ # @param increment [Integer] How much to increment the rate-limit counter. Default is 1.
40
41
  # @return [Integer, false] the waiting time until the next request, in seconds, or false if the request succeeded
41
- def rate_limited?(thing, rate_limit_time = nil)
42
+ def rate_limited?(thing, rate_limit_time = nil, increment: 1)
42
43
  key = resolve_key thing
43
44
  limit_hash = @bucket[key]
44
45
 
@@ -47,7 +48,7 @@ module Discordrb::Commands
47
48
  @bucket[key] = {
48
49
  last_time: Time.now,
49
50
  set_time: Time.now,
50
- count: 1
51
+ count: increment
51
52
  }
52
53
 
53
54
  return false
@@ -56,16 +57,14 @@ module Discordrb::Commands
56
57
  # Define the time at which we're being rate limited once so it doesn't get inaccurate
57
58
  rate_limit_time ||= Time.now
58
59
 
59
- if @limit && (limit_hash[:count] + 1) > @limit
60
- if @time_span && rate_limit_time < (limit_hash[:set_time] + @time_span)
61
- # Second case: Count is over the limit and the time has not run out yet
62
- return (limit_hash[:set_time] + @time_span) - rate_limit_time
63
- else
64
- # Third case: Count is over the limit but the time has run out
65
- # Don't return anything here because there may still be delay-based limiting
66
- limit_hash[:set_time] = rate_limit_time
67
- limit_hash[:count] = 0
68
- end
60
+ if @limit && (limit_hash[:count] + increment) > @limit
61
+ # Second case: Count is over the limit and the time has not run out yet
62
+ return (limit_hash[:set_time] + @time_span) - rate_limit_time if @time_span && rate_limit_time < (limit_hash[:set_time] + @time_span)
63
+
64
+ # Third case: Count is over the limit but the time has run out
65
+ # Don't return anything here because there may still be delay-based limiting
66
+ limit_hash[:set_time] = rate_limit_time
67
+ limit_hash[:count] = 0
69
68
  end
70
69
 
71
70
  if @delay && rate_limit_time < (limit_hash[:last_time] + @delay)
@@ -74,7 +73,7 @@ module Discordrb::Commands
74
73
  else
75
74
  # Fifth case: no rate limiting at all! Increment the count, set the last_time, and return false
76
75
  limit_hash[:last_time] = rate_limit_time
77
- limit_hash[:count] += 1
76
+ limit_hash[:count] += increment
78
77
  false
79
78
  end
80
79
  end
@@ -84,6 +83,7 @@ module Discordrb::Commands
84
83
  def resolve_key(thing)
85
84
  return thing.resolve_id if thing.respond_to?(:resolve_id) && !thing.is_a?(String)
86
85
  return thing if thing.is_a?(Integer) || thing.is_a?(Symbol)
86
+
87
87
  raise ArgumentError, "Cannot use a #{thing.class} as a rate limiting key!"
88
88
  end
89
89
  end
@@ -105,14 +105,15 @@ module Discordrb::Commands
105
105
 
106
106
  # Performs a rate limit request.
107
107
  # @param key [Symbol] Which bucket to perform the request for.
108
- # @param thing [#resolve_id, Integer, Symbol] What should be rate-limited.
108
+ # @param thing [String, Integer, Symbol] What should be rate-limited.
109
+ # @param increment (see Bucket#rate_limited?)
109
110
  # @see Bucket#rate_limited?
110
111
  # @return [Integer, false] How much time to wait or false if the request succeeded.
111
- def rate_limited?(key, thing)
112
+ def rate_limited?(key, thing, increment: 1)
112
113
  # Check whether the bucket actually exists
113
114
  return false unless @buckets && @buckets[key]
114
115
 
115
- @buckets[key].rate_limited?(thing)
116
+ @buckets[key].rate_limited?(thing, increment: increment)
116
117
  end
117
118
 
118
119
  # Cleans all buckets
@@ -5,12 +5,14 @@ require 'discordrb/events/typing'
5
5
  require 'discordrb/events/lifetime'
6
6
  require 'discordrb/events/presence'
7
7
  require 'discordrb/events/voice_state_update'
8
+ require 'discordrb/events/voice_server_update'
8
9
  require 'discordrb/events/channels'
9
10
  require 'discordrb/events/members'
10
11
  require 'discordrb/events/roles'
11
12
  require 'discordrb/events/guilds'
12
13
  require 'discordrb/events/await'
13
14
  require 'discordrb/events/bans'
15
+ require 'discordrb/events/reactions'
14
16
 
15
17
  require 'discordrb/await'
16
18
 
@@ -31,17 +33,17 @@ module Discordrb
31
33
  # @option attributes [Boolean] :private Matches whether or not the channel is private.
32
34
  # @yield The block is executed when the event is raised.
33
35
  # @yieldparam event [MessageEvent] The event that was raised.
34
- # @return [MessageEventHandler] The event handler that was registered.
36
+ # @return [MessageEventHandler] the event handler that was registered.
35
37
  def message(attributes = {}, &block)
36
38
  register_event(MessageEvent, attributes, block)
37
39
  end
38
40
 
39
- # This **event** is raised when the READY packet is received, i. e. servers and channels have finished
41
+ # This **event** is raised when the READY packet is received, i.e. servers and channels have finished
40
42
  # initialization. It's the recommended way to do things when the bot has finished starting up.
41
43
  # @param attributes [Hash] Event attributes, none in this particular case
42
44
  # @yield The block is executed when the event is raised.
43
45
  # @yieldparam event [ReadyEvent] The event that was raised.
44
- # @return [ReadyEventHandler] The event handler that was registered.
46
+ # @return [ReadyEventHandler] the event handler that was registered.
45
47
  def ready(attributes = {}, &block)
46
48
  register_event(ReadyEvent, attributes, block)
47
49
  end
@@ -51,7 +53,7 @@ module Discordrb
51
53
  # @param attributes [Hash] Event attributes, none in this particular case
52
54
  # @yield The block is executed when the event is raised.
53
55
  # @yieldparam event [DisconnectEvent] The event that was raised.
54
- # @return [DisconnectEventHandler] The event handler that was registered.
56
+ # @return [DisconnectEventHandler] the event handler that was registered.
55
57
  def disconnected(attributes = {}, &block)
56
58
  register_event(DisconnectEvent, attributes, block)
57
59
  end
@@ -66,7 +68,7 @@ module Discordrb
66
68
  # @param attributes [Hash] Event attributes, none in this particular case
67
69
  # @yield The block is executed when the event is raised.
68
70
  # @yieldparam event [HeartbeatEvent] The event that was raised.
69
- # @return [HeartbeatEventHandler] The event handler that was registered.
71
+ # @return [HeartbeatEventHandler] the event handler that was registered.
70
72
  def heartbeat(attributes = {}, &block)
71
73
  register_event(HeartbeatEvent, attributes, block)
72
74
  end
@@ -81,40 +83,95 @@ module Discordrb
81
83
  # @option attributes [Time] :before Matches a time before the time the typing started.
82
84
  # @yield The block is executed when the event is raised.
83
85
  # @yieldparam event [TypingEvent] The event that was raised.
84
- # @return [TypingEventHandler] The event handler that was registered.
86
+ # @return [TypingEventHandler] the event handler that was registered.
85
87
  def typing(attributes = {}, &block)
86
88
  register_event(TypingEvent, attributes, block)
87
89
  end
88
90
 
89
91
  # This **event** is raised when a message is edited in a channel.
90
92
  # @param attributes [Hash] The event's attributes.
91
- # @option attributes [#resolve_id] :id Matches the ID of the message that was edited.
93
+ # @option attributes [String, Integer] :id Matches the ID of the message that was edited.
92
94
  # @option attributes [String, Integer, Channel] :in Matches the channel the message was edited in.
93
95
  # @yield The block is executed when the event is raised.
94
96
  # @yieldparam event [MessageEditEvent] The event that was raised.
95
- # @return [MessageEditEventHandler] The event handler that was registered.
97
+ # @return [MessageEditEventHandler] the event handler that was registered.
96
98
  def message_edit(attributes = {}, &block)
97
99
  register_event(MessageEditEvent, attributes, block)
98
100
  end
99
101
 
100
102
  # This **event** is raised when a message is deleted in a channel.
101
103
  # @param attributes [Hash] The event's attributes.
102
- # @option attributes [#resolve_id] :id Matches the ID of the message that was deleted.
104
+ # @option attributes [String, Integer] :id Matches the ID of the message that was deleted.
103
105
  # @option attributes [String, Integer, Channel] :in Matches the channel the message was deleted in.
104
106
  # @yield The block is executed when the event is raised.
105
107
  # @yieldparam event [MessageDeleteEvent] The event that was raised.
106
- # @return [MessageDeleteEventHandler] The event handler that was registered.
108
+ # @return [MessageDeleteEventHandler] the event handler that was registered.
107
109
  def message_delete(attributes = {}, &block)
108
110
  register_event(MessageDeleteEvent, attributes, block)
109
111
  end
110
112
 
113
+ # This **event** is raised whenever a message is updated. Message updates can be triggered from
114
+ # a user editing their own message, or from Discord automatically attaching embeds to the
115
+ # user's message for URLs contained in the message's content. If you only want to listen
116
+ # for users editing their own messages, use the {message_edit} handler instead.
117
+ # @param attributes [Hash] The event's attributes.
118
+ # @option attributes [String, Integer] :id Matches the ID of the message that was updated.
119
+ # @option attributes [String, Integer, Channel] :in Matches the channel the message was updated in.
120
+ # @yield The block is executed when the event is raised.
121
+ # @yieldparam event [MessageUpdateEvent] The event that was raised.
122
+ # @return [MessageUpdateEventHandler] the event handler that was registered.
123
+ def message_update(attributes = {}, &block)
124
+ register_event(MessageUpdateEvent, attributes, block)
125
+ end
126
+
127
+ # This **event** is raised when somebody reacts to a message.
128
+ # @param attributes [Hash] The event's attributes.
129
+ # @option attributes [String, Integer] :emoji Matches the ID of the emoji that was reacted with, or its name.
130
+ # @option attributes [String, Integer, User] :from Matches the user who added the reaction.
131
+ # @option attributes [String, Integer, Message] :message Matches the message to which the reaction was added.
132
+ # @option attributes [String, Integer, Channel] :in Matches the channel the reaction was added in.
133
+ # @yield The block is executed when the event is raised.
134
+ # @yieldparam event [ReactionAddEvent] The event that was raised.
135
+ # @return [ReactionAddEventHandler] The event handler that was registered.
136
+ def reaction_add(attributes = {}, &block)
137
+ register_event(ReactionAddEvent, attributes, block)
138
+ end
139
+
140
+ # This **event** is raised when somebody removes a reaction from a message.
141
+ # @param attributes [Hash] The event's attributes.
142
+ # @option attributes [String, Integer] :emoji Matches the ID of the emoji that was removed from the reactions, or
143
+ # its name.
144
+ # @option attributes [String, Integer, User] :from Matches the user who removed the reaction.
145
+ # @option attributes [String, Integer, Message] :message Matches the message to which the reaction was removed.
146
+ # @option attributes [String, Integer, Channel] :in Matches the channel the reaction was removed in.
147
+ # @yield The block is executed when the event is raised.
148
+ # @yieldparam event [ReactionRemoveEvent] The event that was raised.
149
+ # @return [ReactionRemoveEventHandler] The event handler that was registered.
150
+ def reaction_remove(attributes = {}, &block)
151
+ register_event(ReactionRemoveEvent, attributes, block)
152
+ end
153
+
154
+ # This **event** is raised when somebody removes all reactions from a message.
155
+ # @param attributes [Hash] The event's attributes.
156
+ # @option attributes [Hash] The event's attributes.
157
+ # @option attributes [String, Integer, Message] :message Matches the message to which the reactions were removed.
158
+ # @option attributes [String, Integer, Channel] :in Matches the channel the reactions were removed in.
159
+ # @yield The block is executed when the event is raised.
160
+ # @yieldparam event [ReactionRemoveAllEvent] The event that was raised.
161
+ # @return [ReactionRemoveAllEventHandler] The event handler that was registered.
162
+ def reaction_remove_all(attributes = {}, &block)
163
+ register_event(ReactionRemoveAllEvent, attributes, block)
164
+ end
165
+
111
166
  # This **event** is raised when a user's status (online/offline/idle) changes.
112
167
  # @param attributes [Hash] The event's attributes.
113
168
  # @option attributes [String, Integer, User] :from Matches the user whose status changed.
114
169
  # @option attributes [:offline, :idle, :online] :status Matches the status the user has now.
170
+ # @option attributes [Hash<Symbol, Symbol>] :client_status Matches the current online status (`:online`, `:idle` or `:dnd`) of the user
171
+ # on various device types (`:desktop`, `:mobile`, or `:web`). The value will be `nil` when the user is offline or invisible
115
172
  # @yield The block is executed when the event is raised.
116
173
  # @yieldparam event [PresenceEvent] The event that was raised.
117
- # @return [PresenceEventHandler] The event handler that was registered.
174
+ # @return [PresenceEventHandler] the event handler that was registered.
118
175
  def presence(attributes = {}, &block)
119
176
  register_event(PresenceEvent, attributes, block)
120
177
  end
@@ -126,7 +183,7 @@ module Discordrb
126
183
  # @option attributes [Integer] :type Matches the type of game object (0 game, 1 Twitch stream)
127
184
  # @yield The block is executed when the event is raised.
128
185
  # @yieldparam event [PlayingEvent] The event that was raised.
129
- # @return [PlayingEventHandler] The event handler that was registered.
186
+ # @return [PlayingEventHandler] the event handler that was registered.
130
187
  def playing(attributes = {}, &block)
131
188
  register_event(PlayingEvent, attributes, block)
132
189
  end
@@ -144,7 +201,7 @@ module Discordrb
144
201
  # @option attributes [Boolean] :private Matches whether or not the channel is private.
145
202
  # @yield The block is executed when the event is raised.
146
203
  # @yieldparam event [MentionEvent] The event that was raised.
147
- # @return [MentionEventHandler] The event handler that was registered.
204
+ # @return [MentionEventHandler] the event handler that was registered.
148
205
  def mention(attributes = {}, &block)
149
206
  register_event(MentionEvent, attributes, block)
150
207
  end
@@ -155,7 +212,7 @@ module Discordrb
155
212
  # @option attributes [String] :name Matches the name of the created channel.
156
213
  # @yield The block is executed when the event is raised.
157
214
  # @yieldparam event [ChannelCreateEvent] The event that was raised.
158
- # @return [ChannelCreateEventHandler] The event handler that was registered.
215
+ # @return [ChannelCreateEventHandler] the event handler that was registered.
159
216
  def channel_create(attributes = {}, &block)
160
217
  register_event(ChannelCreateEvent, attributes, block)
161
218
  end
@@ -166,7 +223,7 @@ module Discordrb
166
223
  # @option attributes [String] :name Matches the new name of the channel.
167
224
  # @yield The block is executed when the event is raised.
168
225
  # @yieldparam event [ChannelUpdateEvent] The event that was raised.
169
- # @return [ChannelUpdateEventHandler] The event handler that was registered.
226
+ # @return [ChannelUpdateEventHandler] the event handler that was registered.
170
227
  def channel_update(attributes = {}, &block)
171
228
  register_event(ChannelUpdateEvent, attributes, block)
172
229
  end
@@ -177,7 +234,7 @@ module Discordrb
177
234
  # @option attributes [String] :name Matches the name of the deleted channel.
178
235
  # @yield The block is executed when the event is raised.
179
236
  # @yieldparam event [ChannelDeleteEvent] The event that was raised.
180
- # @return [ChannelDeleteEventHandler] The event handler that was registered.
237
+ # @return [ChannelDeleteEventHandler] the event handler that was registered.
181
238
  def channel_delete(attributes = {}, &block)
182
239
  register_event(ChannelDeleteEvent, attributes, block)
183
240
  end
@@ -185,11 +242,11 @@ module Discordrb
185
242
  # This **event** is raised when a recipient is added to a group channel.
186
243
  # @param attributes [Hash] The event's attributes.
187
244
  # @option attributes [String] :name Matches the name of the group channel that the recipient is added to.
188
- # @option attributes [#resolve_id] :owner_id Matches the id of the group channel's owner.
189
- # @option attributes [#resolve_id] :id Matches the id of the recipient added to the group channel.
245
+ # @option attributes [String, Integer] :owner_id Matches the ID of the group channel's owner.
246
+ # @option attributes [String, Integer] :id Matches the ID of the recipient added to the group channel.
190
247
  # @yield The block is executed when the event is raised.
191
248
  # @yieldparam event [ChannelRecipientAddEvent] The event that was raised.
192
- # @return [ChannelRecipientAddHandler] The event handler that was registered.
249
+ # @return [ChannelRecipientAddHandler] the event handler that was registered.
193
250
  def channel_recipient_add(attributes = {}, &block)
194
251
  register_event(ChannelRecipientAddEvent, attributes, block)
195
252
  end
@@ -197,46 +254,59 @@ module Discordrb
197
254
  # This **event** is raised when a recipient is removed from a group channel.
198
255
  # @param attributes [Hash] The event's attributes.
199
256
  # @option attributes [String] :name Matches the name of the group channel that the recipient is added to.
200
- # @option attributes [#resolve_id] :owner_id Matches the id of the group channel's owner.
201
- # @option attributes [#resolve_id] :id Matches the id of the recipient removed from the group channel.
257
+ # @option attributes [String, Integer] :owner_id Matches the ID of the group channel's owner.
258
+ # @option attributes [String, Integer] :id Matches the ID of the recipient removed from the group channel.
202
259
  # @yield The block is executed when the event is raised.
203
260
  # @yieldparam event [ChannelRecipientRemoveEvent] The event that was raised.
204
- # @return [ChannelRecipientRemoveHandler] The event handler that was registered.
261
+ # @return [ChannelRecipientRemoveHandler] the event handler that was registered.
205
262
  def channel_recipient_remove(attributes = {}, &block)
206
263
  register_event(ChannelRecipientRemoveEvent, attributes, block)
207
264
  end
208
265
 
209
- # This **event** is raised when a user's voice state changes.
266
+ # This **event** is raised when a user's voice state changes. This includes when a user joins, leaves, or
267
+ # moves between voice channels, as well as their mute and deaf status for themselves and on the server.
210
268
  # @param attributes [Hash] The event's attributes.
211
269
  # @option attributes [String, Integer, User] :from Matches the user that sent the message.
212
270
  # @option attributes [String, Integer, Channel] :channel Matches the voice channel the user has joined.
271
+ # @option attributes [String, Integer, Channel] :old_channel Matches the voice channel the user was in previously.
213
272
  # @option attributes [true, false] :mute Matches whether or not the user is muted server-wide.
214
273
  # @option attributes [true, false] :deaf Matches whether or not the user is deafened server-wide.
215
274
  # @option attributes [true, false] :self_mute Matches whether or not the user is muted by the bot.
216
275
  # @option attributes [true, false] :self_deaf Matches whether or not the user is deafened by the bot.
217
276
  # @yield The block is executed when the event is raised.
218
277
  # @yieldparam event [VoiceStateUpdateEvent] The event that was raised.
219
- # @return [VoiceStateUpdateEventHandler] The event handler that was registered.
278
+ # @return [VoiceStateUpdateEventHandler] the event handler that was registered.
220
279
  def voice_state_update(attributes = {}, &block)
221
280
  register_event(VoiceStateUpdateEvent, attributes, block)
222
281
  end
223
282
 
283
+ # This **event** is raised when first connecting to a server's voice channel.
284
+ # @param attributes [Hash] The event's attributes.
285
+ # @option attributes [String, Integer, User] :from Matches the server that the update is for.
286
+ # @yield The block is executed when the event is raised.
287
+ # @yieldparam event [VoiceServerUpdateEvent] The event that was raised.
288
+ # @return [VoiceServerUpdateEventHandler] The event handler that was registered.
289
+ def voice_server_update(attributes = {}, &block)
290
+ register_event(VoiceServerUpdateEvent, attributes, block)
291
+ end
292
+
224
293
  # This **event** is raised when a new user joins a server.
225
294
  # @param attributes [Hash] The event's attributes.
226
295
  # @option attributes [String] :username Matches the username of the joined user.
227
296
  # @yield The block is executed when the event is raised.
228
297
  # @yieldparam event [ServerMemberAddEvent] The event that was raised.
229
- # @return [ServerMemberAddEventHandler] The event handler that was registered.
298
+ # @return [ServerMemberAddEventHandler] the event handler that was registered.
230
299
  def member_join(attributes = {}, &block)
231
300
  register_event(ServerMemberAddEvent, attributes, block)
232
301
  end
233
302
 
234
- # This **event** is raised when a member update happens.
303
+ # This **event** is raised when a member update happens. This includes when a members nickname
304
+ # or roles are updated.
235
305
  # @param attributes [Hash] The event's attributes.
236
306
  # @option attributes [String] :username Matches the username of the updated user.
237
307
  # @yield The block is executed when the event is raised.
238
308
  # @yieldparam event [ServerMemberUpdateEvent] The event that was raised.
239
- # @return [ServerMemberUpdateEventHandler] The event handler that was registered.
309
+ # @return [ServerMemberUpdateEventHandler] the event handler that was registered.
240
310
  def member_update(attributes = {}, &block)
241
311
  register_event(ServerMemberUpdateEvent, attributes, block)
242
312
  end
@@ -246,7 +316,7 @@ module Discordrb
246
316
  # @option attributes [String] :username Matches the username of the member.
247
317
  # @yield The block is executed when the event is raised.
248
318
  # @yieldparam event [ServerMemberDeleteEvent] The event that was raised.
249
- # @return [ServerMemberDeleteEventHandler] The event handler that was registered.
319
+ # @return [ServerMemberDeleteEventHandler] the event handler that was registered.
250
320
  def member_leave(attributes = {}, &block)
251
321
  register_event(ServerMemberDeleteEvent, attributes, block)
252
322
  end
@@ -257,7 +327,7 @@ module Discordrb
257
327
  # @option attributes [String, Integer, Server] :server Matches the server from which the user was banned.
258
328
  # @yield The block is executed when the event is raised.
259
329
  # @yieldparam event [UserBanEvent] The event that was raised.
260
- # @return [UserBanEventHandler] The event handler that was registered.
330
+ # @return [UserBanEventHandler] the event handler that was registered.
261
331
  def user_ban(attributes = {}, &block)
262
332
  register_event(UserBanEvent, attributes, block)
263
333
  end
@@ -268,19 +338,18 @@ module Discordrb
268
338
  # @option attributes [String, Integer, Server] :server Matches the server from which the user was unbanned.
269
339
  # @yield The block is executed when the event is raised.
270
340
  # @yieldparam event [UserUnbanEvent] The event that was raised.
271
- # @return [UserUnbanEventHandler] The event handler that was registered.
341
+ # @return [UserUnbanEventHandler] the event handler that was registered.
272
342
  def user_unban(attributes = {}, &block)
273
343
  register_event(UserUnbanEvent, attributes, block)
274
344
  end
275
345
 
276
- # This **event** is raised when a server is created respective to the bot, i. e. the bot joins a server or creates
277
- # a new one itself. It should never be necessary to listen to this event as it will only ever be triggered by
278
- # things the bot itself does, but one can never know.
346
+ # This **event** is raised when a server is created respective to the bot, i.e. the bot joins a server or creates
347
+ # a new one itself.
279
348
  # @param attributes [Hash] The event's attributes.
280
349
  # @option attributes [String, Integer, Server] :server Matches the server that was created.
281
350
  # @yield The block is executed when the event is raised.
282
351
  # @yieldparam event [ServerCreateEvent] The event that was raised.
283
- # @return [ServerCreateEventHandler] The event handler that was registered.
352
+ # @return [ServerCreateEventHandler] the event handler that was registered.
284
353
  def server_create(attributes = {}, &block)
285
354
  register_event(ServerCreateEvent, attributes, block)
286
355
  end
@@ -290,7 +359,7 @@ module Discordrb
290
359
  # @option attributes [String, Integer, Server] :server Matches the server that was updated.
291
360
  # @yield The block is executed when the event is raised.
292
361
  # @yieldparam event [ServerUpdateEvent] The event that was raised.
293
- # @return [ServerUpdateEventHandler] The event handler that was registered.
362
+ # @return [ServerUpdateEventHandler] the event handler that was registered.
294
363
  def server_update(attributes = {}, &block)
295
364
  register_event(ServerUpdateEvent, attributes, block)
296
365
  end
@@ -301,11 +370,100 @@ module Discordrb
301
370
  # @option attributes [String, Integer, Server] :server Matches the server that was deleted.
302
371
  # @yield The block is executed when the event is raised.
303
372
  # @yieldparam event [ServerDeleteEvent] The event that was raised.
304
- # @return [ServerDeleteEventHandler] The event handler that was registered.
373
+ # @return [ServerDeleteEventHandler] the event handler that was registered.
305
374
  def server_delete(attributes = {}, &block)
306
375
  register_event(ServerDeleteEvent, attributes, block)
307
376
  end
308
377
 
378
+ # This **event** is raised when an emoji or collection of emojis is created/deleted/updated.
379
+ # @param attributes [Hash] The event's attributes.
380
+ # @option attributes [String, Integer, Server] :server Matches the server.
381
+ # @yield The block is executed when the event is raised.
382
+ # @yieldparam event [ServerEmojiChangeEvent] The event that was raised.
383
+ # @return [ServerEmojiChangeEventHandler] the event handler that was registered.
384
+ def server_emoji(attributes = {}, &block)
385
+ register_event(ServerEmojiChangeEvent, attributes, block)
386
+ end
387
+
388
+ # This **event** is raised when an emoji is created.
389
+ # @param attributes [Hash] The event's attributes.
390
+ # @option attributes [String, Integer, Server] :server Matches the server.
391
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
392
+ # @option attributes [String] :name Matches the name of the emoji.
393
+ # @yield The block is executed when the event is raised.
394
+ # @yieldparam event [ServerEmojiCreateEvent] The event that was raised.
395
+ # @return [ServerEmojiCreateEventHandler] the event handler that was registered.
396
+ def server_emoji_create(attributes = {}, &block)
397
+ register_event(ServerEmojiCreateEvent, attributes, block)
398
+ end
399
+
400
+ # This **event** is raised when an emoji is deleted.
401
+ # @param attributes [Hash] The event's attributes.
402
+ # @option attributes [String, Integer, Server] :server Matches the server.
403
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
404
+ # @option attributes [String] :name Matches the name of the emoji.
405
+ # @yield The block is executed when the event is raised.
406
+ # @yieldparam event [ServerEmojiDeleteEvent] The event that was raised.
407
+ # @return [ServerEmojiDeleteEventHandler] the event handler that was registered.
408
+ def server_emoji_delete(attributes = {}, &block)
409
+ register_event(ServerEmojiDeleteEvent, attributes, block)
410
+ end
411
+
412
+ # This **event** is raised when an emoji is updated.
413
+ # @param attributes [Hash] The event's attributes.
414
+ # @option attributes [String, Integer, Server] :server Matches the server.
415
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
416
+ # @option attributes [String] :name Matches the name of the emoji.
417
+ # @option attributes [String] :old_name Matches the name of the emoji before the update.
418
+ # @yield The block is executed when the event is raised.
419
+ # @yieldparam event [ServerEmojiUpdateEvent] The event that was raised.
420
+ # @return [ServerEmojiUpdateEventHandler] the event handler that was registered.
421
+ def server_emoji_update(attributes = {}, &block)
422
+ register_event(ServerEmojiUpdateEvent, attributes, block)
423
+ end
424
+
425
+ # This **event** is raised when a role is created.
426
+ # @param attributes [Hash] The event's attributes.
427
+ # @option attributes [String] :name Matches the role name.
428
+ # @yield The block is executed when the event is raised.
429
+ # @yieldparam event [ServerRoleCreateEvent] The event that was raised.
430
+ # @return [ServerRoleCreateEventHandler] the event handler that was registered.
431
+ def server_role_create(attributes = {}, &block)
432
+ register_event(ServerRoleCreateEvent, attributes, block)
433
+ end
434
+
435
+ # This **event** is raised when a role is deleted.
436
+ # @param attributes [Hash] The event's attributes.
437
+ # @option attributes [String, Integer] :id Matches the role ID.
438
+ # @yield The block is executed when the event is raised.
439
+ # @yieldparam event [ServerRoleDeleteEvent] The event that was raised.
440
+ # @return [ServerRoleDeleteEventHandler] the event handler that was registered.
441
+ def server_role_delete(attributes = {}, &block)
442
+ register_event(ServerRoleDeleteEvent, attributes, block)
443
+ end
444
+
445
+ # This **event** is raised when a role is updated.
446
+ # @param attributes [Hash] The event's attributes.
447
+ # @option attributes [String] :name Matches the role name.
448
+ # @yield The block is executed when the event is raised.
449
+ # @yieldparam event [ServerRoleUpdateEvent] The event that was raised.
450
+ # @return [ServerRoleUpdateEventHandler] the event handler that was registered.
451
+ def server_role_update(attributes = {}, &block)
452
+ register_event(ServerRoleUpdateEvent, attributes, block)
453
+ end
454
+
455
+ # This **event** is raised when a webhook is updated.
456
+ # @param attributes [Hash] The event's attributes.
457
+ # @option attributes [String, Integer, Server] :server Matches the server by name, ID or instance.
458
+ # @option attributes [String, Integer, Channel] :channel Matches the channel by name, ID or instance.
459
+ # @option attribute [String, Integer, Webhook] :webhook Matches the webhook by name, ID or instance.
460
+ # @yield The block is executed when the event is raised.
461
+ # @yieldparam event [WebhookUpdateEvent] The event that was raised.
462
+ # @return [WebhookUpdateEventHandler] the event handler that was registered.
463
+ def webhook_update(attributes = {}, &block)
464
+ register_event(WebhookUpdateEvent, attributes, block)
465
+ end
466
+
309
467
  # This **event** is raised when an {Await} is triggered. It provides an easy way to execute code
310
468
  # on an await without having to rely on the await's block.
311
469
  # @param attributes [Hash] The event's attributes.
@@ -313,7 +471,7 @@ module Discordrb
313
471
  # @option attributes [Class] :type Exactly matches the event's type.
314
472
  # @yield The block is executed when the event is raised.
315
473
  # @yieldparam event [AwaitEvent] The event that was raised.
316
- # @return [AwaitEventHandler] The event handler that was registered.
474
+ # @return [AwaitEventHandler] the event handler that was registered.
317
475
  def await(attributes = {}, &block)
318
476
  register_event(AwaitEvent, attributes, block)
319
477
  end
@@ -331,7 +489,7 @@ module Discordrb
331
489
  # @option attributes [Boolean] :private Matches whether or not the channel is private.
332
490
  # @yield The block is executed when the event is raised.
333
491
  # @yieldparam event [PrivateMessageEvent] The event that was raised.
334
- # @return [PrivateMessageEventHandler] The event handler that was registered.
492
+ # @return [PrivateMessageEventHandler] the event handler that was registered.
335
493
  def pm(attributes = {}, &block)
336
494
  register_event(PrivateMessageEvent, attributes, block)
337
495
  end
@@ -340,6 +498,51 @@ module Discordrb
340
498
  alias_method :direct_message, :pm
341
499
  alias_method :dm, :pm
342
500
 
501
+ # This **event** is raised when an invite is created.
502
+ # @param attributes [Hash] The event's attributes.
503
+ # @option attributes [String, Integer, User] :inviter Matches the user that created the invite.
504
+ # @option attributes [String, Integer, Channel] :channel Matches the channel the invite was created for.
505
+ # @option attributes [String, Integer, Server] :server Matches the server the invite was created for.
506
+ # @option attributes [true, false] :temporary Matches whether the invite is temporary or not.
507
+ # @yield The block is executed when the event is raised.
508
+ # @yieldparam event [InviteCreateEvent] The event that was raised.
509
+ # @return [InviteCreateEventHandler] The event handler that was registered.
510
+ def invite_create(attributes = {}, &block)
511
+ register_event(InviteCreateEvent, attributes, block)
512
+ end
513
+
514
+ # This **event** is raised when an invite is deleted.
515
+ # @param attributes [Hash] The event's attributes.
516
+ # @option attributes [String, Integer, Channel] :channel Matches the channel the deleted invite was for.
517
+ # @option attributes [String, Integer, Server] :server Matches the server the deleted invite was for.
518
+ # @yield The block is executed when the event is raised
519
+ # @yieldparam event [InviteDeleteEvent] The event that was raised.
520
+ # @return [InviteDeleteEventHandler] The event handler that was registered.
521
+ def invite_delete(attributes = {}, &block)
522
+ register_event(InviteDeleteEvent, attributes, block)
523
+ end
524
+
525
+ # This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
526
+ # @param attributes [Hash] The event's attributes.
527
+ # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
528
+ # @yield The block is executed when the event is raised.
529
+ # @yieldparam event [RawEvent] The event that was raised.
530
+ # @return [RawEventHandler] The event handler that was registered.
531
+ def raw(attributes = {}, &block)
532
+ register_event(RawEvent, attributes, block)
533
+ end
534
+
535
+ # This **event** is raised for a dispatch received over the gateway that is not currently handled otherwise by
536
+ # discordrb.
537
+ # @param attributes [Hash] The event's attributes.
538
+ # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
539
+ # @yield The block is executed when the event is raised.
540
+ # @yieldparam event [UnknownEvent] The event that was raised.
541
+ # @return [UnknownEventHandler] The event handler that was registered.
542
+ def unknown(attributes = {}, &block)
543
+ register_event(UnknownEvent, attributes, block)
544
+ end
545
+
343
546
  # Removes an event handler from this container. If you're looking for a way to do temporary events, I recommend
344
547
  # {Await}s instead of this.
345
548
  # @param handler [Discordrb::Events::EventHandler] The handler to remove.
@@ -351,7 +554,7 @@ module Discordrb
351
554
 
352
555
  # Removes all events from this event handler.
353
556
  def clear!
354
- @event_handlers.clear if @event_handlers
557
+ @event_handlers&.clear
355
558
  end
356
559
 
357
560
  # Adds an event handler to this container. Usually, it's more expressive to just use one of the shorthand adder
@@ -360,6 +563,7 @@ module Discordrb
360
563
  def add_handler(handler)
361
564
  clazz = EventContainer.event_class(handler.class)
362
565
  @event_handlers ||= {}
566
+ @event_handlers[clazz] ||= []
363
567
  @event_handlers[clazz] << handler
364
568
  end
365
569
 
@@ -381,13 +585,13 @@ module Discordrb
381
585
  # @param event_class [Class] The event type
382
586
  # @return [Class] the handler type
383
587
  def self.handler_class(event_class)
384
- class_from_string(event_class.to_s + 'Handler')
588
+ class_from_string("#{event_class}Handler")
385
589
  end
386
590
 
387
591
  # Returns the event class for a handler class type
388
592
  # @see #handler_class
389
593
  # @param handler_class [Class] The handler type
390
- # @return [Class, nil] the event type, or nil if the handler_class isn't a handler class (i. e. ends with Handler)
594
+ # @return [Class, nil] the event type, or nil if the handler_class isn't a handler class (i.e. ends with Handler)
391
595
  def self.event_class(handler_class)
392
596
  class_name = handler_class.to_s
393
597
  return nil unless class_name.end_with? 'Handler'