discorb 0.13.4 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/codeql-analysis.yml +70 -0
  4. data/.github/workflows/lint-push.yml +18 -0
  5. data/.github/workflows/lint.yml +16 -0
  6. data/.rubocop.yml +70 -0
  7. data/Changelog.md +12 -0
  8. data/Gemfile +7 -3
  9. data/Rakefile +22 -22
  10. data/discorb.gemspec +1 -0
  11. data/examples/commands/bookmarker.rb +2 -1
  12. data/examples/commands/hello.rb +1 -0
  13. data/examples/commands/inspect.rb +3 -2
  14. data/examples/components/authorization_button.rb +2 -1
  15. data/examples/components/select_menu.rb +2 -1
  16. data/examples/extension/main.rb +1 -0
  17. data/examples/extension/message_expander.rb +1 -0
  18. data/examples/simple/eval.rb +3 -2
  19. data/examples/simple/ping_pong.rb +1 -0
  20. data/examples/simple/rolepanel.rb +1 -0
  21. data/examples/simple/wait_for_message.rb +4 -3
  22. data/exe/discorb +8 -7
  23. data/lib/discorb/allowed_mentions.rb +64 -0
  24. data/lib/discorb/app_command/command.rb +274 -0
  25. data/lib/discorb/app_command/handler.rb +168 -0
  26. data/lib/discorb/app_command.rb +2 -426
  27. data/lib/discorb/asset.rb +2 -0
  28. data/lib/discorb/audit_logs.rb +3 -3
  29. data/lib/discorb/channel.rb +19 -4
  30. data/lib/discorb/client.rb +30 -27
  31. data/lib/discorb/common.rb +4 -26
  32. data/lib/discorb/components/button.rb +106 -0
  33. data/lib/discorb/components/select_menu.rb +157 -0
  34. data/lib/discorb/components/text_input.rb +96 -0
  35. data/lib/discorb/components.rb +11 -276
  36. data/lib/discorb/dictionary.rb +3 -0
  37. data/lib/discorb/embed.rb +2 -2
  38. data/lib/discorb/emoji.rb +19 -3
  39. data/lib/discorb/emoji_table.rb +1 -1
  40. data/lib/discorb/error.rb +4 -6
  41. data/lib/discorb/event.rb +9 -7
  42. data/lib/discorb/exe/about.rb +1 -0
  43. data/lib/discorb/exe/irb.rb +4 -3
  44. data/lib/discorb/exe/new.rb +6 -7
  45. data/lib/discorb/exe/run.rb +2 -1
  46. data/lib/discorb/exe/setup.rb +8 -5
  47. data/lib/discorb/exe/show.rb +1 -0
  48. data/lib/discorb/extend.rb +19 -14
  49. data/lib/discorb/extension.rb +5 -1
  50. data/lib/discorb/gateway.rb +28 -30
  51. data/lib/discorb/guild.rb +11 -13
  52. data/lib/discorb/guild_template.rb +2 -2
  53. data/lib/discorb/http.rb +15 -17
  54. data/lib/discorb/integration.rb +1 -1
  55. data/lib/discorb/intents.rb +1 -1
  56. data/lib/discorb/interaction/autocomplete.rb +4 -3
  57. data/lib/discorb/interaction/command.rb +34 -9
  58. data/lib/discorb/interaction/components.rb +5 -2
  59. data/lib/discorb/interaction/modal.rb +33 -0
  60. data/lib/discorb/interaction/response.rb +33 -4
  61. data/lib/discorb/interaction/root.rb +1 -0
  62. data/lib/discorb/interaction.rb +2 -1
  63. data/lib/discorb/log.rb +1 -1
  64. data/lib/discorb/member.rb +1 -3
  65. data/lib/discorb/message.rb +26 -277
  66. data/lib/discorb/message_meta.rb +205 -0
  67. data/lib/discorb/modules.rb +1 -1
  68. data/lib/discorb/permission.rb +2 -2
  69. data/lib/discorb/presence.rb +4 -1
  70. data/lib/discorb/rate_limit.rb +2 -4
  71. data/lib/discorb/user.rb +1 -1
  72. data/lib/discorb/utils/colored_puts.rb +1 -0
  73. data/lib/discorb/voice_state.rb +3 -0
  74. data/lib/discorb/webhook.rb +1 -1
  75. data/lib/discorb.rb +1 -0
  76. data/template-replace/scripts/arrow.rb +1 -0
  77. data/template-replace/scripts/favicon.rb +1 -0
  78. data/template-replace/scripts/index.rb +2 -1
  79. data/template-replace/scripts/locale_ja.rb +5 -4
  80. data/template-replace/scripts/sidebar.rb +1 -0
  81. data/template-replace/scripts/version.rb +7 -10
  82. data/template-replace/scripts/yard_replace.rb +5 -4
  83. metadata +16 -2
@@ -1,428 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
- module Discorb
4
- #
5
- # Handles application commands.
6
- #
7
- module ApplicationCommand
8
- #
9
- # Module to handle application commands.
10
- #
11
- module Handler
12
- #
13
- # Add new top-level command.
14
- #
15
- # @param [String] command_name Command name.
16
- # @param [String] description Command description.
17
- # @param [Hash{String => Hash{:description => String, :optional => Boolean, :type => Object}}] options Command options.
18
- # The key is the option name, the value is a hash with the following keys:
19
- #
20
- # | Key | Type | Description |
21
- # | --- | --- | --- |
22
- # | `:description` | `String` | Description of the option. |
23
- # | `:required` | Whether the argument is required. `optional` will be used if not specified. |
24
- # | `:optional` | Whether the argument is optional. `required` will be used if not specified. |
25
- # | `:type` | `Object` | Type of the option. |
26
- # | `:choice` | `Hash{String => String, Integer, Float}` | Type of the option. |
27
- # | `:default` | `Object` | Default value of the option. |
28
- # | `:channel_types` | `Array<Class<Discorb::Channel>>` | Type of the channel option. |
29
- # | `:autocomplete` | `Proc` | Autocomplete function. |
30
- # | `:range` | `Range` | Range of the option. Only valid for numeric options. (`:int`, `:float`) |
31
- #
32
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
33
- # @param [Proc] block Command block.
34
- #
35
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] Command object.
36
- #
37
- # @see file:docs/application_command.md#register-slash-command Application Comamnds: Register Slash Command
38
- # @see file:docs/cli/setup.md CLI: setup
39
- #
40
- def slash(command_name, description, options = {}, guild_ids: nil, &block)
41
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, guild_ids, block, 1, "")
42
- @commands << command
43
- @bottom_commands << command
44
- command
45
- end
46
-
47
- #
48
- # Add new command with group.
49
- #
50
- # @param [String] command_name Command name.
51
- # @param [String] description Command description.
52
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
53
- #
54
- # @yield Block to yield with the command.
55
- # @yieldparam [Discorb::ApplicationCommand::Command::GroupCommand] group Group command.
56
- #
57
- # @return [Discorb::ApplicationCommand::Command::GroupCommand] Command object.
58
- #
59
- # @see file:docs/application_command.md Application Commands
60
- # @see file:docs/cli/setup.md CLI: setup
61
- #
62
- def slash_group(command_name, description, guild_ids: nil, &block)
63
- command = Discorb::ApplicationCommand::Command::GroupCommand.new(command_name, description, guild_ids, nil, self)
64
- command.yield_self(&block) if block_given?
65
- @commands << command
66
- command
67
- end
68
-
69
- #
70
- # Add message context menu command.
71
- #
72
- # @param [String] command_name Command name.
73
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
74
- # @param [Proc] block Command block.
75
- # @yield [interaction, message] Block to execute.
76
- # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] interaction Interaction object.
77
- # @yieldparam [Discorb::Message] message Message object.
78
- #
79
- # @return [Discorb::ApplicationCommand::Command] Command object.
80
- #
81
- def message_command(command_name, guild_ids: nil, &block)
82
- command = Discorb::ApplicationCommand::Command.new(command_name, guild_ids, block, 3)
83
- @commands << command
84
- command
85
- end
86
-
87
- #
88
- # Add user context menu command.
89
- #
90
- # @param [String] command_name Command name.
91
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
92
- # @param [Proc] block Command block.
93
- # @yield [interaction, user] Block to execute.
94
- # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] interaction Interaction object.
95
- # @yieldparam [Discorb::User] user User object.
96
- #
97
- # @return [Discorb::ApplicationCommand::Command] Command object.
98
- #
99
- def user_command(command_name, guild_ids: nil, &block)
100
- command = Discorb::ApplicationCommand::Command.new(command_name, guild_ids, block, 2)
101
- @commands << command
102
- command
103
- end
104
-
105
- #
106
- # Setup commands.
107
- # @async
108
- # @see Client#initialize
109
- #
110
- # @param [String] token Bot token.
111
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to use as default. If `false` is given, it will be global command.
112
- #
113
- # @note `token` parameter only required if you don't run client.
114
- #
115
- def setup_commands(token = nil, guild_ids: nil)
116
- Async do
117
- @token ||= token
118
- @http = HTTP.new(self)
119
- global_commands = @commands.select { |c| c.guild_ids == false or c.guild_ids == [] }
120
- local_commands = @commands.select { |c| c.guild_ids.is_a?(Array) and c.guild_ids.any? }
121
- default_commands = @commands.select { |c| c.guild_ids.nil? }
122
- if guild_ids.is_a?(Array)
123
- default_commands.each do |command|
124
- command.instance_variable_set(:@guild_ids, guild_ids)
125
- end
126
- local_commands += default_commands
127
- else
128
- global_commands += default_commands
129
- end
130
- final_guild_ids = local_commands.map(&:guild_ids).flatten.map(&:to_s).uniq
131
- app_info = fetch_application.wait
132
- @http.request(
133
- Route.new(
134
- "/applications/#{app_info.id}/commands",
135
- "//applications/:application_id/commands",
136
- :put
137
- ),
138
- global_commands.map(&:to_hash)
139
- ).wait unless global_commands.empty?
140
- if ENV["DISCORB_CLI_FLAG"] == "setup"
141
- sputs "Registered commands for global:"
142
- global_commands.each do |command|
143
- iputs "- #{command.name}"
144
- end
145
- end
146
- final_guild_ids.each do |guild_id|
147
- commands = local_commands.select { |c| c.guild_ids.include?(guild_id) }
148
- @http.request(
149
- Route.new("/applications/#{app_info.id}/guilds/#{guild_id}/commands",
150
- "//applications/:application_id/guilds/:guild_id/commands",
151
- :put),
152
- commands.map(&:to_hash)
153
- ).wait
154
- sputs "Registered commands for #{guild_id}:"
155
- commands.each do |command|
156
- iputs "- #{command.name}"
157
- end
158
- end unless final_guild_ids.empty?
159
- @log.info "Successfully setup commands"
160
- end
161
- end
162
- end
163
-
164
- #
165
- # Represents a application command.
166
- # @abstract
167
- #
168
- class Command < DiscordModel
169
- # @return [String] The name of the command.
170
- attr_reader :name
171
- # @return [Array<#to_s>] The guild ids that the command is enabled in.
172
- attr_reader :guild_ids
173
- # @return [Proc] The block of the command.
174
- attr_reader :block
175
- # @return [:chat_input, :user, :message] The type of the command.
176
- attr_reader :type
177
- # @return [Integer] The raw type of the command.
178
- attr_reader :type_raw
179
- # @return [Discorb::Dictionary{Discorb::Snowflake, :global => Discorb::Snowflake}] The ID mapping.
180
- attr_reader :id_map
181
-
182
- @types = {
183
- 1 => :chat_input,
184
- 2 => :user,
185
- 3 => :message,
186
- }.freeze
187
-
188
- # @private
189
- def initialize(name, guild_ids, block, type)
190
- @name = name
191
- @guild_ids = guild_ids&.map(&:to_s)
192
- @block = block
193
- @raw_type = type
194
- @type = Discorb::ApplicationCommand::Command.types[type]
195
- @type_raw = type
196
- @id_map = Discorb::Dictionary.new
197
- end
198
-
199
- # @private
200
- def replace_block(instance)
201
- current_block = @block.dup
202
- @block = Proc.new do |*args|
203
- instance.instance_exec(*args, &current_block)
204
- end
205
- end
206
-
207
- # @private
208
- def to_hash
209
- {
210
- name: @name,
211
- default_permission: @default_permission,
212
- type: @type_raw,
213
- }
214
- end
215
-
216
- #
217
- # Represents the slash command.
218
- #
219
- class SlashCommand < Command
220
- # @return [String] The description of the command.
221
- attr_reader :description
222
- # @return [Hash{String => Hash}] The options of the command.
223
- attr_reader :options
224
-
225
- # @private
226
- def initialize(name, description, options, guild_ids, block, type, parent)
227
- super(name, guild_ids, block, type)
228
- @description = description
229
- @options = options
230
- @id = nil
231
- @parent = parent
232
- @id_map = Discorb::Dictionary.new
233
- end
234
-
235
- #
236
- # Returns the commands name.
237
- #
238
- # @return [String] The name of the command.
239
- #
240
- def to_s
241
- (@parent + " " + @name).strip
242
- end
243
-
244
- # @private
245
- def to_hash
246
- options_payload = options.map do |name, value|
247
- ret = {
248
- type: case value[:type]
249
- when String, :string, :str
250
- 3
251
- when Integer, :integer, :int
252
- 4
253
- when TrueClass, FalseClass, :boolean, :bool
254
- 5
255
- when Discorb::User, Discorb::Member, :user, :member
256
- 6
257
- when Discorb::Channel, :channel
258
- 7
259
- when Discorb::Role, :role
260
- 8
261
- when :mentionable
262
- 9
263
- when Float, :float
264
- 10
265
- else
266
- raise ArgumentError, "Invalid option type: #{value[:type]}"
267
- end,
268
- name: name,
269
- description: value[:description],
270
- required: value[:required].nil? ? !value[:optional] : value[:required],
271
- }
272
-
273
- ret[:choices] = value[:choices].map { |t| { name: t[0], value: t[1] } } if value[:choices]
274
-
275
- ret[:channel_types] = value[:channel_types].map(&:channel_type) if value[:channel_types]
276
-
277
- ret[:autocomplete] = !!value[:autocomplete] if value[:autocomplete]
278
- if value[:range]
279
- ret[:min_value] = value[:range].begin
280
- ret[:max_value] = value[:range].end
281
- end
282
- ret
283
- end
284
- {
285
- name: @name,
286
- default_permission: true,
287
- description: @description,
288
- options: options_payload,
289
- }
290
- end
291
- end
292
-
293
- #
294
- # Represents the command with subcommands.
295
- #
296
- class GroupCommand < Command
297
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand, Discorb::ApplicationCommand::Command::SubcommandGroup>] The subcommands of the command.
298
- attr_reader :commands
299
- # @return [String] The description of the command.
300
- attr_reader :description
301
-
302
- # @private
303
- def initialize(name, description, guild_ids, type, client)
304
- super(name, guild_ids, block, type)
305
- @description = description
306
- @commands = []
307
- @client = client
308
- @id_map = Discorb::Dictionary.new
309
- end
310
-
311
- #
312
- # Add new subcommand.
313
- #
314
- # @param (see Discorb::ApplicationCommand::Handler#slash)
315
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
316
- #
317
- def slash(command_name, description, options = {}, &block)
318
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @name)
319
- @client.bottom_commands << command
320
- @commands << command
321
- command
322
- end
323
-
324
- #
325
- # Add new subcommand group.
326
- #
327
- # @param [String] command_name Group name.
328
- # @param [String] description Group description.
329
- #
330
- # @yield Block to yield with the command.
331
- # @yieldparam [Discorb::ApplicationCommand::Command::SubcommandGroup] group Group command.
332
- #
333
- # @return [Discorb::ApplicationCommand::Command::SubcommandGroup] Command object.
334
- #
335
- # @see file:docs/application_command.md Application Commands
336
- #
337
- def group(command_name, description, &block)
338
- command = Discorb::ApplicationCommand::Command::SubcommandGroup.new(command_name, description, @name, @client)
339
- command.yield_self(&block) if block_given?
340
- @commands << command
341
- command
342
- end
343
-
344
- #
345
- # Returns the command name.
346
- #
347
- # @return [String] The command name.
348
- #
349
- def to_s
350
- @name
351
- end
352
-
353
- # @private
354
- def block_replace(instance)
355
- super
356
- @commands.each { |c| c.replace_block(instance) }
357
- end
358
-
359
- # @private
360
- def to_hash
361
- options_payload = @commands.map do |command|
362
- if command.is_a?(SlashCommand)
363
- {
364
- name: command.name,
365
- description: command.description,
366
- default_permission: true,
367
- type: 1,
368
- options: command.to_hash[:options],
369
- }
370
- else
371
- {
372
- name: command.name,
373
- description: command.description,
374
- default_permission: true,
375
- type: 2,
376
- options: command.commands.map { |c| c.to_hash.merge(type: 1) },
377
- }
378
- end
379
- end
380
-
381
- {
382
- name: @name,
383
- default_permission: @enabled,
384
- description: @description,
385
- options: options_payload,
386
- }
387
- end
388
- end
389
-
390
- #
391
- # Represents the subcommand group.
392
- #
393
- class SubcommandGroup < GroupCommand
394
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand>] The subcommands of the command.
395
- attr_reader :commands
396
-
397
- # @private
398
- def initialize(name, description, parent, client)
399
- super(name, description, [], 1, client)
400
-
401
- @commands = []
402
- @parent = parent
403
- end
404
-
405
- def to_s
406
- @parent + " " + @name
407
- end
408
-
409
- #
410
- # Add new subcommand.
411
- # @param (see Discorb::ApplicationCommand::Handler#slash)
412
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
413
- #
414
- def slash(command_name, description, options = {}, &block)
415
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @parent + " " + @name)
416
- @commands << command
417
- @client.bottom_commands << command
418
- command
419
- end
420
- end
421
-
422
- class << self
423
- # @private
424
- attr_reader :types
425
- end
426
- end
427
- end
2
+ %w[command handler].each do |file|
3
+ require_relative "app_command/#{file}.rb"
428
4
  end
data/lib/discorb/asset.rb CHANGED
@@ -80,7 +80,9 @@ module Discorb
80
80
  #
81
81
  # @return [String] URL of the avatar.
82
82
  #
83
+ # rubocop: disable Lint/UnusedMethodArgument
83
84
  def url(image_format: nil, size: 1024)
85
+ # rubocop: enable Lint/UnusedMethodArgument
84
86
  "https://cdn.discordapp.com/embed/avatars/#{@discriminator.to_i % 5}.png"
85
87
  end
86
88
 
@@ -226,7 +226,7 @@ module Discorb
226
226
  # @private
227
227
  #
228
228
  def initialize(data)
229
- @data = data.map { |d| [d[:key].to_sym, d] }.to_h
229
+ @data = data.to_h { |d| [d[:key].to_sym, d] }
230
230
  @data.each do |k, v|
231
231
  define_singleton_method(k) { Change.new(v) }
232
232
  end
@@ -287,8 +287,8 @@ module Discorb
287
287
  else
288
288
  ->(v) { v }
289
289
  end
290
- @old_value = method.(data[:old_value])
291
- @new_value = method.(data[:new_value])
290
+ @old_value = method.call(data[:old_value])
291
+ @new_value = method.call(data[:new_value])
292
292
  end
293
293
 
294
294
  #
@@ -211,9 +211,9 @@ module Discorb
211
211
  @guild_id = data[:guild_id]
212
212
  @position = data[:position]
213
213
  @permission_overwrites = if data[:permission_overwrites]
214
- data[:permission_overwrites].map do |ow|
214
+ data[:permission_overwrites].to_h do |ow|
215
215
  [(ow[:type] == 1 ? guild.roles : guild.members)[ow[:id]], PermissionOverwrite.new(ow[:allow], ow[:deny])]
216
- end.to_h
216
+ end
217
217
  else
218
218
  {}
219
219
  end
@@ -759,7 +759,7 @@ module Discorb
759
759
  end
760
760
 
761
761
  def audiences
762
- voice_states.filter { |state| state.suppress? }.map(&:member)
762
+ voice_states.filter(&:suppress?).map(&:member)
763
763
  end
764
764
 
765
765
  private
@@ -990,14 +990,23 @@ module Discorb
990
990
  end
991
991
  end
992
992
 
993
+ #
994
+ # Represents a thread in news channel(aka announcement channel).
995
+ #
993
996
  class News < ThreadChannel
994
997
  @channel_type = 10
995
998
  end
996
999
 
1000
+ #
1001
+ # Represents a public thread in text channel.
1002
+ #
997
1003
  class Public < ThreadChannel
998
1004
  @channel_type = 11
999
1005
  end
1000
1006
 
1007
+ #
1008
+ # Represents a private thread in text channel.
1009
+ #
1001
1010
  class Private < ThreadChannel
1002
1011
  @channel_type = 12
1003
1012
  end
@@ -1007,7 +1016,7 @@ module Discorb
1007
1016
  end
1008
1017
 
1009
1018
  #
1010
- # Repre
1019
+ # Represents a member in a thread.
1011
1020
  #
1012
1021
  class Member < DiscordModel
1013
1022
  attr_reader :joined_at
@@ -1059,6 +1068,9 @@ module Discorb
1059
1068
  end
1060
1069
  end
1061
1070
 
1071
+ #
1072
+ # Represents a category in a guild.
1073
+ #
1062
1074
  class CategoryChannel < GuildChannel
1063
1075
  @channel_type = 4
1064
1076
 
@@ -1099,6 +1111,9 @@ module Discorb
1099
1111
  end
1100
1112
  end
1101
1113
 
1114
+ #
1115
+ # Represents a DM channel.
1116
+ #
1102
1117
  class DMChannel < Channel
1103
1118
  include Messageable
1104
1119
 
@@ -186,10 +186,8 @@ module Discorb
186
186
  @log.debug "Dispatching event #{event_name}"
187
187
  events.each do |block|
188
188
  Async do
189
- Async(annotation: "Discorb event: #{event_name}") do |task|
190
- if block.is_a?(Discorb::EventHandler)
191
- @events[event_name].delete(block) if block.metadata[:once]
192
- end
189
+ Async(annotation: "Discorb event: #{event_name}") do |_task|
190
+ @events[event_name].delete(block) if block.is_a?(Discorb::EventHandler) && block.metadata[:once]
193
191
  block.call(*args)
194
192
  @log.debug "Dispatched proc with ID #{block.id.inspect}"
195
193
  rescue StandardError, ScriptError => e
@@ -261,7 +259,7 @@ module Discorb
261
259
  #
262
260
  # @return [Async::Task<Discorb::Invite>] The invite.
263
261
  #
264
- def fetch_invite(code, with_count: false, with_expiration: false)
262
+ def fetch_invite(code, with_count: true, with_expiration: true)
265
263
  Async do
266
264
  _resp, data = @http.request(Route.new("/invites/#{code}?with_count=#{with_count}&with_expiration=#{with_expiration}", "//invites/:code", :get)).wait
267
265
  Invite.new(self, data, false)
@@ -295,8 +293,8 @@ module Discorb
295
293
  #
296
294
  def fetch_nitro_sticker_packs
297
295
  Async do
298
- _resp, data = @http.request(Route.new("/stickers-packs", "//stickers-packs", :get)).wait
299
- data.map { |pack| Sticker::Pack.new(self, pack) }
296
+ _resp, data = @http.request(Route.new("/sticker-packs", "//sticker-packs", :get)).wait
297
+ data[:sticker_packs].map { |pack| Sticker::Pack.new(self, pack) }
300
298
  end
301
299
  end
302
300
 
@@ -305,18 +303,14 @@ module Discorb
305
303
  #
306
304
  # @param [Discorb::Activity] activity The activity to update.
307
305
  # @param [:online, :idle, :dnd, :invisible] status The status to update.
308
- # @param [String] afk Whether to set the client as AFK.
309
306
  #
310
- def update_presence(activity = nil, status: nil, afk: false)
307
+ def update_presence(activity = nil, status: nil)
311
308
  payload = {
312
309
  activities: [],
313
310
  status: status,
314
- afk: nil,
315
311
  since: nil,
316
312
  }
317
- if !activity.nil?
318
- payload[:activities] = [activity.to_hash]
319
- end
313
+ payload[:activities] = [activity.to_hash] unless activity.nil?
320
314
  payload[:status] = status unless status.nil?
321
315
  if @connection
322
316
  Async do
@@ -374,10 +368,11 @@ module Discorb
374
368
  # @param [Object] ... The arguments to pass to the `ext#initialize`.
375
369
  #
376
370
  def load_extension(ext, ...)
377
- if ext.is_a?(Class)
371
+ case ext
372
+ when Class
378
373
  raise ArgumentError, "#{ext} is not a extension" unless ext < Discorb::Extension
379
374
  ins = ext.new(self, ...)
380
- elsif ext.is_a?(Discorb::Extension)
375
+ when Discorb::Extension
381
376
  ins = ext
382
377
  else
383
378
  raise ArgumentError, "#{ext} is not a extension"
@@ -398,12 +393,20 @@ module Discorb
398
393
  ins.class.commands.each do |cmd|
399
394
  cmd.define_singleton_method(:extension) { ins.class.name }
400
395
  cmd.replace_block(ins)
396
+ cmd.block.define_singleton_method(:self_replaced) { true }
401
397
  @commands << cmd
402
398
  end
403
399
 
404
400
  cls = ins.class
405
401
  cls.loaded(self, ...) if cls.respond_to? :loaded
406
- @bottom_commands += ins.class.bottom_commands
402
+ ins.class.bottom_commands.each do |cmd|
403
+ unless cmd.respond_to? :self_replaced
404
+ cmd.define_singleton_method(:extension) { ins.class.name }
405
+ cmd.replace_block(ins)
406
+ cmd.block.define_singleton_method(:self_replaced) { true }
407
+ end
408
+ @bottom_commands << cmd
409
+ end
407
410
  @extensions[ins.class.name] = ins
408
411
  ins
409
412
  end
@@ -463,7 +466,7 @@ module Discorb
463
466
  ::File.open(options[:log_file], "a")
464
467
  end
465
468
  @log.level = options[:log_level].to_sym
466
- @log.colorize_log = options[:log_color] == nil ? @log.out.isatty : options[:log_color]
469
+ @log.colorize_log = options[:log_color].nil? ? @log.out.isatty : options[:log_color]
467
470
  end
468
471
  end
469
472
  end
@@ -473,29 +476,29 @@ module Discorb
473
476
  if guilds = ENV["DISCORB_SETUP_GUILDS"]
474
477
  guild_ids = guilds.split(",")
475
478
  end
476
- if guild_ids == ["global"]
477
- guild_ids = false
478
- end
479
+ guild_ids = false if guild_ids == ["global"]
479
480
  setup_commands(token, guild_ids: guild_ids).wait
480
- @events[:setup]&.each do |event|
481
- event.call
481
+ if ENV["DISCORB_SETUP_SCRIPT"] == "true"
482
+ @events[:setup]&.each do |event|
483
+ event.call
484
+ end
485
+ self.on_setup if respond_to? :on_setup
482
486
  end
483
- self.on_setup if respond_to? :on_setup
484
487
  end
485
488
 
486
489
  def start_client(token)
487
- Async do |task|
488
- Signal.trap(:SIGINT) {
490
+ Async do |_task|
491
+ Signal.trap(:SIGINT) do
489
492
  @log.info "SIGINT received, closing..."
490
493
  Signal.trap(:SIGINT, "DEFAULT")
491
494
  close!
492
- }
495
+ end
493
496
  @token = token.to_s
494
497
  @close_condition = Async::Condition.new
495
498
  @main_task = Async do
496
499
  @status = :running
497
500
  connect_gateway(false).wait
498
- rescue
501
+ rescue StandardError
499
502
  @status = :stopped
500
503
  @close_condition.signal
501
504
  raise