discordrb 3.3.0 → 3.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +126 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
  5. data/.github/pull_request_template.md +37 -0
  6. data/.rubocop.yml +34 -37
  7. data/.travis.yml +5 -6
  8. data/CHANGELOG.md +504 -347
  9. data/Gemfile +2 -0
  10. data/LICENSE.txt +1 -1
  11. data/README.md +61 -79
  12. data/Rakefile +2 -0
  13. data/bin/console +1 -0
  14. data/discordrb-webhooks.gemspec +6 -6
  15. data/discordrb.gemspec +18 -18
  16. data/lib/discordrb/allowed_mentions.rb +36 -0
  17. data/lib/discordrb/api/channel.rb +62 -39
  18. data/lib/discordrb/api/invite.rb +3 -3
  19. data/lib/discordrb/api/server.rb +57 -50
  20. data/lib/discordrb/api/user.rb +9 -8
  21. data/lib/discordrb/api/webhook.rb +6 -6
  22. data/lib/discordrb/api.rb +40 -15
  23. data/lib/discordrb/await.rb +0 -1
  24. data/lib/discordrb/bot.rb +175 -73
  25. data/lib/discordrb/cache.rb +4 -2
  26. data/lib/discordrb/colour_rgb.rb +43 -0
  27. data/lib/discordrb/commands/command_bot.rb +30 -9
  28. data/lib/discordrb/commands/container.rb +20 -23
  29. data/lib/discordrb/commands/parser.rb +18 -18
  30. data/lib/discordrb/commands/rate_limiter.rb +3 -2
  31. data/lib/discordrb/container.rb +77 -17
  32. data/lib/discordrb/data/activity.rb +271 -0
  33. data/lib/discordrb/data/application.rb +50 -0
  34. data/lib/discordrb/data/attachment.rb +56 -0
  35. data/lib/discordrb/data/audit_logs.rb +345 -0
  36. data/lib/discordrb/data/channel.rb +849 -0
  37. data/lib/discordrb/data/embed.rb +251 -0
  38. data/lib/discordrb/data/emoji.rb +82 -0
  39. data/lib/discordrb/data/integration.rb +83 -0
  40. data/lib/discordrb/data/invite.rb +137 -0
  41. data/lib/discordrb/data/member.rb +297 -0
  42. data/lib/discordrb/data/message.rb +334 -0
  43. data/lib/discordrb/data/overwrite.rb +102 -0
  44. data/lib/discordrb/data/profile.rb +91 -0
  45. data/lib/discordrb/data/reaction.rb +33 -0
  46. data/lib/discordrb/data/recipient.rb +34 -0
  47. data/lib/discordrb/data/role.rb +191 -0
  48. data/lib/discordrb/data/server.rb +1002 -0
  49. data/lib/discordrb/data/user.rb +204 -0
  50. data/lib/discordrb/data/voice_region.rb +45 -0
  51. data/lib/discordrb/data/voice_state.rb +41 -0
  52. data/lib/discordrb/data/webhook.rb +145 -0
  53. data/lib/discordrb/data.rb +25 -4180
  54. data/lib/discordrb/errors.rb +2 -1
  55. data/lib/discordrb/events/bans.rb +7 -5
  56. data/lib/discordrb/events/channels.rb +2 -0
  57. data/lib/discordrb/events/guilds.rb +16 -9
  58. data/lib/discordrb/events/invites.rb +125 -0
  59. data/lib/discordrb/events/members.rb +6 -2
  60. data/lib/discordrb/events/message.rb +69 -27
  61. data/lib/discordrb/events/presence.rb +14 -4
  62. data/lib/discordrb/events/raw.rb +1 -3
  63. data/lib/discordrb/events/reactions.rb +49 -3
  64. data/lib/discordrb/events/typing.rb +6 -4
  65. data/lib/discordrb/events/voice_server_update.rb +47 -0
  66. data/lib/discordrb/events/voice_state_update.rb +15 -10
  67. data/lib/discordrb/events/webhooks.rb +9 -6
  68. data/lib/discordrb/gateway.rb +72 -57
  69. data/lib/discordrb/id_object.rb +39 -0
  70. data/lib/discordrb/light/integrations.rb +1 -1
  71. data/lib/discordrb/light/light_bot.rb +1 -1
  72. data/lib/discordrb/logger.rb +4 -4
  73. data/lib/discordrb/paginator.rb +57 -0
  74. data/lib/discordrb/permissions.rb +103 -8
  75. data/lib/discordrb/version.rb +1 -1
  76. data/lib/discordrb/voice/encoder.rb +16 -7
  77. data/lib/discordrb/voice/network.rb +84 -43
  78. data/lib/discordrb/voice/sodium.rb +96 -0
  79. data/lib/discordrb/voice/voice_bot.rb +34 -26
  80. data/lib/discordrb.rb +73 -0
  81. metadata +98 -60
  82. /data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
@@ -24,7 +24,7 @@ module Discordrb::Commands
24
24
 
25
25
  # Creates a new CommandBot and logs in to Discord.
26
26
  # @param attributes [Hash] The attributes to initialize the CommandBot with.
27
- # @see {Discordrb::Bot#initialize} for other attributes that should be used to create the underlying regular bot.
27
+ # @see Discordrb::Bot#initialize Discordrb::Bot#initialize for other attributes that should be used to create the underlying regular bot.
28
28
  # @option attributes [String, Array<String>, #call] :prefix The prefix that should trigger this bot's commands. It
29
29
  # can be:
30
30
  #
@@ -39,14 +39,15 @@ module Discordrb::Commands
39
39
  # complicated dynamic prefixes (e. g. based on server), or even something else entirely (suffixes, or most
40
40
  # adventurous, infixes).
41
41
  # @option attributes [true, false] :advanced_functionality Whether to enable advanced functionality (very powerful
42
- # way to nest commands into chains, see https://github.com/meew0/discordrb/wiki/Commands#command-chain-syntax
42
+ # way to nest commands into chains, see https://github.com/shardlab/discordrb/wiki/Commands#command-chain-syntax
43
43
  # for info. Default is false.
44
44
  # @option attributes [Symbol, Array<Symbol>, false] :help_command The name of the command that displays info for
45
45
  # other commands. Use an array if you want to have aliases. Default is "help". If none should be created, use
46
46
  # `false` as the value.
47
- # @option attributes [String] :command_doesnt_exist_message The message that should be displayed if a user attempts
47
+ # @option attributes [String, #call] :command_doesnt_exist_message The message that should be displayed if a user attempts
48
48
  # to use a command that does not exist. If none is specified, no message will be displayed. In the message, you
49
- # can use the string '%command%' that will be replaced with the name of the command.
49
+ # can use the string '%command%' that will be replaced with the name of the command. Anything responding to call
50
+ # such as a proc will be called with the event, and is expected to return a String or nil.
50
51
  # @option attributes [String] :no_permission_message The message to be displayed when `NoPermission` error is raised.
51
52
  # @option attributes [true, false] :spaces_allowed Whether spaces are allowed to occur between the prefix and the
52
53
  # command. Default is false.
@@ -83,7 +84,9 @@ module Discordrb::Commands
83
84
  num_shards: attributes[:num_shards],
84
85
  redact_token: attributes.key?(:redact_token) ? attributes[:redact_token] : true,
85
86
  ignore_bots: attributes[:ignore_bots],
86
- compress_mode: attributes[:compress_mode])
87
+ compress_mode: attributes[:compress_mode],
88
+ intents: attributes[:intents]
89
+ )
87
90
 
88
91
  @prefix = attributes[:prefix]
89
92
  @attributes = {
@@ -140,6 +143,7 @@ module Discordrb::Commands
140
143
  }
141
144
 
142
145
  return unless @attributes[:help_command]
146
+
143
147
  command(@attributes[:help_command], max_args: 1, description: 'Shows a list of all the commands available or displays help for a specific command.', usage: 'help [command name]') do |event, command_name|
144
148
  if command_name
145
149
  command = @commands[command_name.to_sym]
@@ -148,6 +152,7 @@ module Discordrb::Commands
148
152
  command_name = command.name
149
153
  end
150
154
  return "The command `#{command_name}` does not exist!" unless command
155
+
151
156
  desc = command.attributes[:description] || '*No description available*'
152
157
  usage = command.attributes[:usage]
153
158
  parameters = command.attributes[:parameters]
@@ -206,15 +211,22 @@ module Discordrb::Commands
206
211
  def execute_command(name, event, arguments, chained = false, check_permissions = true)
207
212
  debug("Executing command #{name} with arguments #{arguments}")
208
213
  return unless @commands
214
+
209
215
  command = @commands[name]
210
216
  command = command.aliased_command if command.is_a?(CommandAlias)
211
217
  return unless !check_permissions || channels?(event.channel, @attributes[:channels]) ||
212
218
  (command && !command.attributes[:channels].nil?)
219
+
213
220
  unless command
214
- event.respond @attributes[:command_doesnt_exist_message].gsub('%command%', name.to_s) if @attributes[:command_doesnt_exist_message]
221
+ if @attributes[:command_doesnt_exist_message]
222
+ message = @attributes[:command_doesnt_exist_message]
223
+ message = message.call(event) if message.respond_to?(:call)
224
+ event.respond message.gsub('%command%', name.to_s) if message
225
+ end
215
226
  return
216
227
  end
217
228
  return unless !check_permissions || channels?(event.channel, command.attributes[:channels])
229
+
218
230
  arguments = arg_check(arguments, command.attributes[:arg_types], event.server) if check_permissions
219
231
  if (check_permissions &&
220
232
  permission?(event.author, command.attributes[:permission_level], event.server) &&
@@ -238,11 +250,13 @@ module Discordrb::Commands
238
250
  # For example, `['1', '10..14']` with types `[Integer, Range]` would turn into `[1, 10..14]`.
239
251
  def arg_check(args, types = nil, server = nil)
240
252
  return args unless types
253
+
241
254
  args.each_with_index.map do |arg, i|
242
255
  next arg if types[i].nil? || types[i] == String
256
+
243
257
  if types[i] == Integer
244
258
  begin
245
- Integer(arg)
259
+ Integer(arg, 10)
246
260
  rescue ArgumentError
247
261
  nil
248
262
  end
@@ -304,7 +318,7 @@ module Discordrb::Commands
304
318
  elsif types[i].respond_to?(:from_argument)
305
319
  begin
306
320
  types[i].from_argument arg
307
- rescue
321
+ rescue StandardError
308
322
  nil
309
323
  end
310
324
  else
@@ -319,6 +333,7 @@ module Discordrb::Commands
319
333
  # @return [String, nil] the command's result, if there is any.
320
334
  def simple_execute(chain, event)
321
335
  return nil if chain.empty?
336
+
322
337
  args = chain.split(' ')
323
338
  execute_command(args[0].to_sym, event, args[1..-1])
324
339
  end
@@ -369,6 +384,7 @@ module Discordrb::Commands
369
384
  # @param channel [String, Integer, Channel] The channel name, integer ID, or `Channel` object to be added
370
385
  def add_channel(channel)
371
386
  return if @attributes[:channels].find { |c| channel.resolve_id == c.resolve_id }
387
+
372
388
  @attributes[:channels] << channel
373
389
  end
374
390
 
@@ -426,6 +442,7 @@ module Discordrb::Commands
426
442
 
427
443
  def standard_prefix_trigger(message, prefix)
428
444
  return nil unless message.start_with? prefix
445
+
429
446
  message[prefix.length..-1]
430
447
  end
431
448
 
@@ -437,11 +454,13 @@ module Discordrb::Commands
437
454
 
438
455
  def required_roles?(member, required)
439
456
  return true if member.webhook? || member.is_a?(Discordrb::Recipient) || required.nil? || required.empty?
457
+
440
458
  required.is_a?(Array) ? check_multiple_roles(member, required) : member.role?(role)
441
459
  end
442
460
 
443
461
  def allowed_roles?(member, required)
444
462
  return true if member.webhook? || member.is_a?(Discordrb::Recipient) || required.nil? || required.empty?
463
+
445
464
  required.is_a?(Array) ? check_multiple_roles(member, required, false) : member.role?(role)
446
465
  end
447
466
 
@@ -459,9 +478,11 @@ module Discordrb::Commands
459
478
 
460
479
  def channels?(channel, channels)
461
480
  return true if channels.nil? || channels.empty?
481
+
462
482
  channels.any? do |c|
463
483
  # if c is string, make sure to remove the "#" from channel names in case it was specified
464
484
  return true if c.is_a?(String) && c.delete('#') == channel.name
485
+
465
486
  c.resolve_id == channel.resolve_id
466
487
  end
467
488
  end
@@ -480,7 +501,7 @@ module Discordrb::Commands
480
501
  else
481
502
  event.respond result unless result.nil? || result.empty?
482
503
  end
483
- rescue => e
504
+ rescue StandardError => e
484
505
  log_exception(e)
485
506
  ensure
486
507
  @event_threads.delete(t)
@@ -9,22 +9,25 @@ 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 must 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
26
29
  # (user must have all of them).
27
- # @option attributes [Array<Role>, Array<#resolve_id>] :allowed_roles Roles that user should have to use this command
30
+ # @option attributes [Array<Role>, Array<String, Integer>] :allowed_roles Roles, or their IDs, that user should have to use this command
28
31
  # (user should have at least one of them).
29
32
  # @option attributes [Array<String, Integer, Channel>] :channels The channels that this command can be used on. An
30
33
  # empty array indicates it can be used on any channel. Supersedes the command bot attribute.
@@ -55,26 +58,22 @@ module Discordrb::Commands
55
58
  # @note `LocalJumpError`s are rescued from internally, giving bots the opportunity to use `return` or `break` in
56
59
  # their blocks without propagating an exception.
57
60
  # @return [Command] The command that was added.
58
- # @deprecated The command name argument will no longer support arrays in the next release.
59
- # Use the `aliases` attribute instead.
60
61
  def command(name, attributes = {}, &block)
61
62
  @commands ||= {}
62
- if name.is_a? Array
63
- new_command = nil
64
63
 
65
- name.each do |e|
66
- new_command = Command.new(e, attributes, &block)
67
- @commands[e] = new_command
68
- 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
69
71
 
70
- new_command
71
- else
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)
75
- end
76
- @commands[name] = new_command
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)
77
75
  end
76
+ @commands[name] = new_command
78
77
  end
79
78
 
80
79
  # Removes a specific command from this container.
@@ -100,9 +99,7 @@ module Discordrb::Commands
100
99
  container_modules = container.singleton_class.included_modules
101
100
 
102
101
  # If the container is an EventContainer and we can include it, then do that
103
- if container_modules.include?(Discordrb::EventContainer) && respond_to?(:include_events)
104
- include_events(container)
105
- end
102
+ include_events(container) if container_modules.include?(Discordrb::EventContainer) && respond_to?(:include_events)
106
103
 
107
104
  if container_modules.include? Discordrb::Commands::CommandContainer
108
105
  include_commands(container)
@@ -81,45 +81,43 @@ module Discordrb::Commands
81
81
  # @return [String] the result of the execution.
82
82
  def call(event, arguments, chained = false, check_permissions = true)
83
83
  if arguments.length < @attributes[:min_args]
84
- event.respond "Too few arguments for command `#{name}`!"
85
- 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)
86
87
  return
87
88
  end
88
89
  if @attributes[:max_args] >= 0 && arguments.length > @attributes[:max_args]
89
- event.respond "Too many arguments for command `#{name}`!"
90
- 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)
91
93
  return
92
94
  end
93
- unless @attributes[:chain_usable]
94
- if chained
95
- event.respond "Command `#{name}` cannot be used in a command chain!"
96
- return
97
- end
95
+ unless @attributes[:chain_usable] && !chained
96
+ event.respond "Command `#{name}` cannot be used in a command chain!"
97
+ return
98
98
  end
99
99
 
100
100
  if check_permissions
101
101
  rate_limited = event.bot.rate_limited?(@attributes[:bucket], event.author)
102
102
  if @attributes[:bucket] && rate_limited
103
- if @attributes[:rate_limit_message]
104
- event.respond @attributes[:rate_limit_message].gsub('%time%', rate_limited.round(2).to_s)
105
- end
103
+ event.respond @attributes[:rate_limit_message].gsub('%time%', rate_limited.round(2).to_s) if @attributes[:rate_limit_message]
106
104
  return
107
105
  end
108
106
  end
109
107
 
110
108
  result = @block.call(event, *arguments)
111
109
  event.drain_into(result)
112
- rescue LocalJumpError => ex # occurs when breaking
113
- result = ex.exit_value
110
+ rescue LocalJumpError => e # occurs when breaking
111
+ result = e.exit_value
114
112
  event.drain_into(result)
115
- rescue => exception # Something went wrong inside our @block!
113
+ rescue StandardError => e # Something went wrong inside our @block!
116
114
  rescue_value = @attributes[:rescue] || event.bot.attributes[:rescue]
117
115
  if rescue_value
118
- event.respond(rescue_value.gsub('%exception%', exception.message)) if rescue_value.is_a?(String)
119
- rescue_value.call(event, exception) if rescue_value.respond_to?(:call)
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)
120
118
  end
121
119
 
122
- raise exception
120
+ raise e
123
121
  end
124
122
  end
125
123
 
@@ -209,8 +207,10 @@ module Discordrb::Commands
209
207
  result += char if b_level <= 0
210
208
 
211
209
  next unless char == @attributes[:sub_chain_end] && !quoted
210
+
212
211
  b_level -= 1
213
212
  next unless b_level.zero?
213
+
214
214
  nested = @chain[b_start + 1..index - 1]
215
215
  subchain = CommandChain.new(nested, @bot, true)
216
216
  result += subchain.execute(event)
@@ -35,7 +35,7 @@ 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
40
  # @param increment [Integer] How much to increment the rate-limit counter. Default is 1.
41
41
  # @return [Integer, false] the waiting time until the next request, in seconds, or false if the request succeeded
@@ -83,6 +83,7 @@ module Discordrb::Commands
83
83
  def resolve_key(thing)
84
84
  return thing.resolve_id if thing.respond_to?(:resolve_id) && !thing.is_a?(String)
85
85
  return thing if thing.is_a?(Integer) || thing.is_a?(Symbol)
86
+
86
87
  raise ArgumentError, "Cannot use a #{thing.class} as a rate limiting key!"
87
88
  end
88
89
  end
@@ -104,7 +105,7 @@ module Discordrb::Commands
104
105
 
105
106
  # Performs a rate limit request.
106
107
  # @param key [Symbol] Which bucket to perform the request for.
107
- # @param thing [#resolve_id, Integer, Symbol] What should be rate-limited.
108
+ # @param thing [String, Integer, Symbol] What should be rate-limited.
108
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.
@@ -5,6 +5,7 @@ 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'
@@ -89,7 +90,7 @@ module Discordrb
89
90
 
90
91
  # This **event** is raised when a message is edited in a channel.
91
92
  # @param attributes [Hash] The event's attributes.
92
- # @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.
93
94
  # @option attributes [String, Integer, Channel] :in Matches the channel the message was edited in.
94
95
  # @yield The block is executed when the event is raised.
95
96
  # @yieldparam event [MessageEditEvent] The event that was raised.
@@ -100,7 +101,7 @@ module Discordrb
100
101
 
101
102
  # This **event** is raised when a message is deleted in a channel.
102
103
  # @param attributes [Hash] The event's attributes.
103
- # @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.
104
105
  # @option attributes [String, Integer, Channel] :in Matches the channel the message was deleted in.
105
106
  # @yield The block is executed when the event is raised.
106
107
  # @yieldparam event [MessageDeleteEvent] The event that was raised.
@@ -109,9 +110,26 @@ module Discordrb
109
110
  register_event(MessageDeleteEvent, attributes, block)
110
111
  end
111
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
+
112
127
  # This **event** is raised when somebody reacts to a message.
113
128
  # @param attributes [Hash] The event's attributes.
114
- # @option attributes [Integer, String] :emoji Matches the ID of the emoji that was reacted with, or its name.
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.
115
133
  # @yield The block is executed when the event is raised.
116
134
  # @yieldparam event [ReactionAddEvent] The event that was raised.
117
135
  # @return [ReactionAddEventHandler] The event handler that was registered.
@@ -121,8 +139,11 @@ module Discordrb
121
139
 
122
140
  # This **event** is raised when somebody removes a reaction from a message.
123
141
  # @param attributes [Hash] The event's attributes.
124
- # @option attributes [Integer, String] :emoji Matches the ID of the emoji that was removed from the reactions, or
142
+ # @option attributes [String, Integer] :emoji Matches the ID of the emoji that was removed from the reactions, or
125
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.
126
147
  # @yield The block is executed when the event is raised.
127
148
  # @yieldparam event [ReactionRemoveEvent] The event that was raised.
128
149
  # @return [ReactionRemoveEventHandler] The event handler that was registered.
@@ -132,6 +153,9 @@ module Discordrb
132
153
 
133
154
  # This **event** is raised when somebody removes all reactions from a message.
134
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.
135
159
  # @yield The block is executed when the event is raised.
136
160
  # @yieldparam event [ReactionRemoveAllEvent] The event that was raised.
137
161
  # @return [ReactionRemoveAllEventHandler] The event handler that was registered.
@@ -143,6 +167,8 @@ module Discordrb
143
167
  # @param attributes [Hash] The event's attributes.
144
168
  # @option attributes [String, Integer, User] :from Matches the user whose status changed.
145
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
146
172
  # @yield The block is executed when the event is raised.
147
173
  # @yieldparam event [PresenceEvent] The event that was raised.
148
174
  # @return [PresenceEventHandler] the event handler that was registered.
@@ -216,8 +242,8 @@ module Discordrb
216
242
  # This **event** is raised when a recipient is added to a group channel.
217
243
  # @param attributes [Hash] The event's attributes.
218
244
  # @option attributes [String] :name Matches the name of the group channel that the recipient is added to.
219
- # @option attributes [#resolve_id] :owner_id Matches the id of the group channel's owner.
220
- # @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.
221
247
  # @yield The block is executed when the event is raised.
222
248
  # @yieldparam event [ChannelRecipientAddEvent] The event that was raised.
223
249
  # @return [ChannelRecipientAddHandler] the event handler that was registered.
@@ -228,8 +254,8 @@ module Discordrb
228
254
  # This **event** is raised when a recipient is removed from a group channel.
229
255
  # @param attributes [Hash] The event's attributes.
230
256
  # @option attributes [String] :name Matches the name of the group channel that the recipient is added to.
231
- # @option attributes [#resolve_id] :owner_id Matches the id of the group channel's owner.
232
- # @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.
233
259
  # @yield The block is executed when the event is raised.
234
260
  # @yieldparam event [ChannelRecipientRemoveEvent] The event that was raised.
235
261
  # @return [ChannelRecipientRemoveHandler] the event handler that was registered.
@@ -254,6 +280,16 @@ module Discordrb
254
280
  register_event(VoiceStateUpdateEvent, attributes, block)
255
281
  end
256
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
+
257
293
  # This **event** is raised when a new user joins a server.
258
294
  # @param attributes [Hash] The event's attributes.
259
295
  # @option attributes [String] :username Matches the username of the joined user.
@@ -352,7 +388,7 @@ module Discordrb
352
388
  # This **event** is raised when an emoji is created.
353
389
  # @param attributes [Hash] The event's attributes.
354
390
  # @option attributes [String, Integer, Server] :server Matches the server.
355
- # @option attributes [String, Integer] :id Matches the id of the emoji.
391
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
356
392
  # @option attributes [String] :name Matches the name of the emoji.
357
393
  # @yield The block is executed when the event is raised.
358
394
  # @yieldparam event [ServerEmojiCreateEvent] The event that was raised.
@@ -364,7 +400,7 @@ module Discordrb
364
400
  # This **event** is raised when an emoji is deleted.
365
401
  # @param attributes [Hash] The event's attributes.
366
402
  # @option attributes [String, Integer, Server] :server Matches the server.
367
- # @option attributes [String, Integer] :id Matches the id of the emoji.
403
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
368
404
  # @option attributes [String] :name Matches the name of the emoji.
369
405
  # @yield The block is executed when the event is raised.
370
406
  # @yieldparam event [ServerEmojiDeleteEvent] The event that was raised.
@@ -376,7 +412,7 @@ module Discordrb
376
412
  # This **event** is raised when an emoji is updated.
377
413
  # @param attributes [Hash] The event's attributes.
378
414
  # @option attributes [String, Integer, Server] :server Matches the server.
379
- # @option attributes [String, Integer] :id Matches the id of the emoji.
415
+ # @option attributes [String, Integer] :id Matches the ID of the emoji.
380
416
  # @option attributes [String] :name Matches the name of the emoji.
381
417
  # @option attributes [String] :old_name Matches the name of the emoji before the update.
382
418
  # @yield The block is executed when the event is raised.
@@ -398,7 +434,7 @@ module Discordrb
398
434
 
399
435
  # This **event** is raised when a role is deleted.
400
436
  # @param attributes [Hash] The event's attributes.
401
- # @option attributes [#resolve_id] :id Matches the role id.
437
+ # @option attributes [String, Integer] :id Matches the role ID.
402
438
  # @yield The block is executed when the event is raised.
403
439
  # @yieldparam event [ServerRoleDeleteEvent] The event that was raised.
404
440
  # @return [ServerRoleDeleteEventHandler] the event handler that was registered.
@@ -418,9 +454,9 @@ module Discordrb
418
454
 
419
455
  # This **event** is raised when a webhook is updated.
420
456
  # @param attributes [Hash] The event's attributes.
421
- # @option attributes [String, Integer, Server] :server Matches the server by name, id or instance.
422
- # @option attributes [String, Integer, Channel] :channel Matches the channel by name, id or instance.
423
- # @option attribute [String, Integer, Webhook] :webhook Matches the webhook by name, id or instance.
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.
424
460
  # @yield The block is executed when the event is raised.
425
461
  # @yieldparam event [WebhookUpdateEvent] The event that was raised.
426
462
  # @return [WebhookUpdateEventHandler] the event handler that was registered.
@@ -462,6 +498,30 @@ module Discordrb
462
498
  alias_method :direct_message, :pm
463
499
  alias_method :dm, :pm
464
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
+
465
525
  # This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
466
526
  # @param attributes [Hash] The event's attributes.
467
527
  # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
@@ -494,7 +554,7 @@ module Discordrb
494
554
 
495
555
  # Removes all events from this event handler.
496
556
  def clear!
497
- @event_handlers.clear if @event_handlers
557
+ @event_handlers&.clear
498
558
  end
499
559
 
500
560
  # Adds an event handler to this container. Usually, it's more expressive to just use one of the shorthand adder
@@ -525,7 +585,7 @@ module Discordrb
525
585
  # @param event_class [Class] The event type
526
586
  # @return [Class] the handler type
527
587
  def self.handler_class(event_class)
528
- class_from_string(event_class.to_s + 'Handler')
588
+ class_from_string("#{event_class}Handler")
529
589
  end
530
590
 
531
591
  # Returns the event class for a handler class type