discorb 0.0.6 → 0.2.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.
@@ -8,7 +8,7 @@ module MessageExpander
8
8
  "(?<guild>[0-9]{18})/(?<channel>[0-9]{18})/(?<message>[0-9]{18})(?!>)"
9
9
  )
10
10
 
11
- event :message do |_task, message|
11
+ event :message do |message|
12
12
  next if message.author.bot?
13
13
 
14
14
  message.content.to_enum(:scan, @message_regex).map { Regexp.last_match }.each do |match|
@@ -2,11 +2,11 @@ require "discorb"
2
2
 
3
3
  client = Discorb::Client.new
4
4
 
5
- client.once :ready do |_task|
5
+ client.once :ready do
6
6
  puts "Logged in as #{client.user}"
7
7
  end
8
8
 
9
- client.on :message do |_task, message|
9
+ client.on :message do |message|
10
10
  next if message.author.bot?
11
11
  next unless message.content.start_with?("eval ")
12
12
 
@@ -6,7 +6,7 @@ client.once :ready do
6
6
  puts "Logged in as #{client.user}"
7
7
  end
8
8
 
9
- client.on :message do |_task, message|
9
+ client.on :message do |message|
10
10
  next if message.author.bot?
11
11
  next unless message.content == "ping"
12
12
 
@@ -13,7 +13,7 @@ client.once :ready do
13
13
  puts "Logged in as #{client.user}"
14
14
  end
15
15
 
16
- client.on :reaction_add do |_task, event|
16
+ client.on :reaction_add do |event|
17
17
  next unless event.emoji.value.end_with?(0x0000fe0f.chr("utf-8") + 0x000020e3.chr("utf-8"))
18
18
  next if event.member.bot?
19
19
 
@@ -28,7 +28,7 @@ client.on :reaction_add do |_task, event|
28
28
  end
29
29
  end
30
30
 
31
- client.on :reaction_remove do |_task, event|
31
+ client.on :reaction_remove do |event|
32
32
  next unless event.emoji.value.end_with?(0x0000fe0f.chr("utf-8") + 0x000020e3.chr("utf-8"))
33
33
  next if event.member.bot?
34
34
 
@@ -43,7 +43,7 @@ client.on :reaction_remove do |_task, event|
43
43
  end
44
44
  end
45
45
 
46
- client.on :message do |_task, message|
46
+ client.on :message do |message|
47
47
  next unless message.content.start_with?("/rp ")
48
48
  next if message.author.bot?
49
49
 
@@ -6,7 +6,7 @@ client.once :ready do
6
6
  puts "Logged in as #{client.user}"
7
7
  end
8
8
 
9
- client.on :message do |_task, message|
9
+ client.on :message do |message|
10
10
  next if message.author.bot?
11
11
  next unless message.content == "!quiz"
12
12
 
data/exe/discord-irb ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "io/console"
4
+ require "discorb"
5
+ require "optparse"
6
+
7
+ intents_value = Discorb::Intents.all.value
8
+ token_file = "token"
9
+
10
+ opt = OptionParser.new
11
+ opt.on("-i", "--intents", "intents to use, default to all") { |v| intents_value = v }
12
+ opt.on("-t", "--token-file", "token file to load, default to \"token\"") { |v| token_file = v }
13
+ opt.parse(ARGV)
14
+
15
+ client = Discorb::Client.new(intents: Discorb::Intents.from_value(intents_value))
16
+ $messages = []
17
+
18
+ client.on :ready do
19
+ puts "\e[96mLogged in as #{client.user}\e[m"
20
+
21
+ def message
22
+ $messages.last
23
+ end
24
+
25
+ def dirb_help
26
+ puts <<~EOS
27
+ \e[96mDiscord-IRB\e[m
28
+ This is a debug client for Discord.
29
+ \e[90mmessage\e[m to get latest message.
30
+
31
+ \e[36mhttps://rubydoc.info/gems/discorb/file/docs/discord_irb.md\e[m for more information.
32
+ EOS
33
+ end
34
+
35
+ puts <<~FIRST_MESSAGE
36
+ Running on \e[31mRuby #{RUBY_VERSION}\e[m, disco\e[31mrb #{Discorb::VERSION}\e[m
37
+ Type \e[90mdirb_help\e[m to help.
38
+ FIRST_MESSAGE
39
+
40
+ binding.irb
41
+
42
+ client.close!
43
+ end
44
+
45
+ client.on :message do |message|
46
+ $messages << message
47
+ end
48
+
49
+ token = ENV["DISCORD_BOT_TOKEN"] || ENV["DISCORD_TOKEN"]
50
+ if token.nil?
51
+ if File.exists?(token_file)
52
+ token = File.read(token_file)
53
+ else
54
+ print "\e[90mToken?\e[m : "
55
+ token = $stdin.noecho(&:gets).chomp
56
+ puts
57
+ end
58
+ end
59
+
60
+ client.run token
data/lib/discorb/asset.rb CHANGED
@@ -54,4 +54,38 @@ module Discorb
54
54
  end
55
55
  end
56
56
  end
57
+
58
+ #
59
+ # Represents a default avatar.
60
+ #
61
+ class DefaultAvatar < DiscordModel
62
+
63
+ # @!attribute [r] animated?
64
+ # @return [false] For compatibility with {Asset}, always `false`.
65
+
66
+ # @!visibility private
67
+ def initialize(discriminator)
68
+ @discriminator = discriminator.to_s.rjust(4, "0")
69
+ end
70
+
71
+ def animated?
72
+ false
73
+ end
74
+
75
+ #
76
+ # Returns the URL of the avatar.
77
+ #
78
+ # @param [String] image_format The image format. This is compatible with {Asset#url}, will be ignored.
79
+ # @param [Integer] size The size of the image. This is compatible with {Asset#url}, will be ignored.
80
+ #
81
+ # @return [String] URL of the avatar.
82
+ #
83
+ def url(image_format: nil, size: 1024)
84
+ "https://cdn.discordapp.com/embed/avatars/#{@discriminator.to_i % 5}.png"
85
+ end
86
+
87
+ def inspect
88
+ "#<#{self.class} #{@discriminator}>"
89
+ end
90
+ end
57
91
  end
@@ -68,9 +68,9 @@ module Discorb
68
68
  end
69
69
 
70
70
  # @!visibility private
71
- def base_url
71
+ def channel_id
72
72
  Async do
73
- "/channels/#{@id}"
73
+ @id
74
74
  end
75
75
  end
76
76
 
@@ -1090,9 +1090,9 @@ module Discorb
1090
1090
  include Messageable
1091
1091
 
1092
1092
  # @!visibility private
1093
- def base_url
1093
+ def channel_id
1094
1094
  Async do
1095
- "/channels/#{@id}"
1095
+ @id
1096
1096
  end
1097
1097
  end
1098
1098
 
@@ -41,6 +41,14 @@ module Discorb
41
41
  attr_reader :messages
42
42
  # @return [Discorb::Logger] The logger.
43
43
  attr_reader :log
44
+ # @return [Array<Discorb::Command::Command>] The commands that the client is using.
45
+ attr_reader :commands
46
+ # @return [Float] The ping of the client.
47
+ # @note This will be calculated from heartbeat and heartbeat_ack.
48
+ # @return [nil] If not connected to the gateway.
49
+ attr_reader :ping
50
+ # @return [:initialized, :running, :closed] The status of the client.
51
+ attr_reader :status
44
52
 
45
53
  #
46
54
  # Initializes a new client.
@@ -52,8 +60,13 @@ module Discorb
52
60
  # @param [Boolean] colorize_log Whether to colorize the log.
53
61
  # @param [:debug, :info, :warn, :error, :critical] log_level The log level.
54
62
  # @param [Boolean] wait_until_ready Whether to delay event dispatch until ready.
63
+ # @param [Boolean] overwrite_application_commands Whether to overwrite application commands on ready.
55
64
  #
56
- def initialize(allowed_mentions: nil, intents: nil, message_caches: 1000, log: nil, colorize_log: false, log_level: :info, wait_until_ready: true)
65
+ def initialize(
66
+ allowed_mentions: nil, intents: nil, message_caches: 1000,
67
+ log: nil, colorize_log: false, log_level: :info,
68
+ wait_until_ready: true, overwrite_application_commands: true
69
+ )
57
70
  @allowed_mentions = allowed_mentions || AllowedMentions.new(everyone: true, roles: true, users: true)
58
71
  @intents = (intents or Intents.default)
59
72
  @events = {}
@@ -72,6 +85,9 @@ module Discorb
72
85
  @ready = false
73
86
  @tasks = []
74
87
  @conditions = {}
88
+ @commands = []
89
+ @overwrite_application_commands = overwrite_application_commands
90
+ @status = :initialized
75
91
  end
76
92
 
77
93
  #
@@ -124,7 +140,7 @@ module Discorb
124
140
  # @param [Object] args The arguments to pass to the event.
125
141
  #
126
142
  def dispatch(event_name, *args)
127
- Async do |_task|
143
+ Async do
128
144
  if (conditions = @conditions[event_name])
129
145
  ids = Set[*conditions.map(&:first).map(&:object_id)]
130
146
  conditions.delete_if do |condition|
@@ -148,7 +164,7 @@ module Discorb
148
164
  lambda { |event_args|
149
165
  Async(annotation: "Discorb event: #{event_name}") do |task|
150
166
  @events[event_name].delete(block) if block.discriminator[:once]
151
- block.call(task, *event_args)
167
+ block.call(*event_args)
152
168
  @log.debug "Dispatched proc with ID #{block.id.inspect}"
153
169
  rescue StandardError, ScriptError => e
154
170
  message = "An error occurred while dispatching proc with ID #{block.id.inspect}\n#{e.full_message}"
@@ -164,16 +180,6 @@ module Discorb
164
180
  end
165
181
  end
166
182
 
167
- #
168
- # Starts the client.
169
- #
170
- # @param [String] token The token to use.
171
- #
172
- def run(token)
173
- @token = token.to_s
174
- connect_gateway(true)
175
- end
176
-
177
183
  #
178
184
  # Fetch user from ID.
179
185
  # @macro async
@@ -293,7 +299,7 @@ module Discorb
293
299
  end
294
300
  payload[:status] = status unless status.nil?
295
301
  if @connection
296
- Async do |_task|
302
+ Async do
297
303
  send_gateway(3, **payload)
298
304
  end
299
305
  else
@@ -306,7 +312,7 @@ module Discorb
306
312
  #
307
313
  # Method to wait for a event.
308
314
  #
309
- # @param [Symbol] event_name The name of the event.
315
+ # @param [Symbol] event The name of the event.
310
316
  # @param [Integer] timeout The timeout in seconds.
311
317
  # @param [Proc] check The check to use.
312
318
  #
@@ -347,6 +353,9 @@ module Discorb
347
353
  #
348
354
  def extend(mod)
349
355
  if mod.respond_to?(:events)
356
+ @events.each_value do |event|
357
+ event.delete_if { |c| c.discriminator[:extension] == mod.name }
358
+ end
350
359
  mod.events.each do |name, events|
351
360
  @events[name] = [] if @events[name].nil?
352
361
  events.each do |event|
@@ -358,6 +367,39 @@ module Discorb
358
367
  super(mod)
359
368
  end
360
369
 
361
- include Discorb::GatewayHandler
370
+ include Discorb::Gateway::Handler
371
+ include Discorb::Command::Handler
372
+
373
+ #
374
+ # Starts the client.
375
+ #
376
+ # @param [String] token The token to use.
377
+ #
378
+ def run(token)
379
+ Async do |task|
380
+ @token = token.to_s
381
+ @close_condition = Async::Condition.new
382
+ main_task = Async do
383
+ @status = :running
384
+ connect_gateway(true).wait
385
+ rescue
386
+ @status = :stopped
387
+ @close_condition.signal
388
+ raise
389
+ end
390
+ @close_condition.wait
391
+ main_task.stop
392
+ end
393
+ end
394
+
395
+ #
396
+ # Stops the client.
397
+ #
398
+ def close!
399
+ @connection.send_close
400
+ @tasks.each(&:stop)
401
+ @status = :closed
402
+ @close_condition.signal
403
+ end
362
404
  end
363
405
  end
@@ -0,0 +1,393 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Handles application commands.
6
+ #
7
+ module Command
8
+ #
9
+ # Module to handle 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
+ # | `:optional` | `Boolean` | Whether the option is optional or not. |
24
+ # | `:type` | `Object` | Type of the option. |
25
+ # | `:choice` | `Hash{String => String, Integer, Float}` | Type of the option. |
26
+ #
27
+ # @param [Array<#to_s>] guild_ids Guild IDs to restrict the command to.
28
+ # @param [Proc] block Command block.
29
+ #
30
+ # @return [Discorb::Command::Command::SlashCommand]
31
+ #
32
+ # @see file:docs/application_command.md#register-slash-command
33
+ #
34
+ def slash(command_name, description, options = {}, guild_ids: [], &block)
35
+ command = Discorb::Command::Command::SlashCommand.new(command_name, description, options, guild_ids, block, 1, "")
36
+ @commands << command
37
+ command
38
+ end
39
+
40
+ #
41
+ # Add new command with group.
42
+ #
43
+ # @param [String] command_name Command name.
44
+ # @param [String] description Command description.
45
+ # @param [Array<#to_s>] guild_ids Guild IDs to restrict the command to.
46
+ #
47
+ # @return [Discorb::Command::Command::GroupCommand] Command object.
48
+ #
49
+ # @see file:docs/slash_command.md
50
+ #
51
+ def slash_group(command_name, description, guild_ids: [])
52
+ command = Discorb::Command::Command::GroupCommand.new(command_name, description, guild_ids, nil)
53
+ @commands << command
54
+ command
55
+ end
56
+
57
+ #
58
+ # Add message context menu command.
59
+ #
60
+ # @param [String] command_name Command name.
61
+ # @param [Array<#to_s>] guild_ids Guild IDs to restrict the command to.
62
+ # @param [Proc] block Command block.
63
+ # @yield [interaction, message] Block to execute.
64
+ # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] Interaction object.
65
+ # @yieldparam [Discorb::Message] user Message object.
66
+ #
67
+ # @return [Discorb::Command::Command] Command object.
68
+ #
69
+ def message_command(command_name, guild_ids: [], &block)
70
+ command = Discorb::Command::Command.new(command_name, guild_ids, block, 3)
71
+ @commands << command
72
+ command
73
+ end
74
+
75
+ #
76
+ # Add user context menu command.
77
+ #
78
+ # @param [String] command_name Command name.
79
+ # @param [Array<#to_s>] guild_ids Guild IDs to restrict the command to.
80
+ # @param [Proc] block Command block.
81
+ # @yield [interaction, user] Block to execute.
82
+ # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] Interaction object.
83
+ # @yieldparam [Discorb::User] user User object.
84
+ #
85
+ # @return [Discorb::Command::Command] Command object.
86
+ #
87
+ def user_command(command_name, guild_ids: [], &block)
88
+ command = Discorb::Command::Command.new(command_name, guild_ids, block, 2)
89
+ @commands << command
90
+ command
91
+ end
92
+
93
+ #
94
+ # Setup commands.
95
+ # @note This method is called automatically if overwrite_application_commands is set to true.
96
+ # @see Client#initialize
97
+ #
98
+ # @param [String] token Bot token.
99
+ # @note `token` parameter only required if you don't run client.
100
+ #
101
+ def setup_commands(token = nil)
102
+ Async do
103
+ @token ||= token
104
+ @http = HTTP.new(self)
105
+ global_commands = @commands.select { |c| c.guild_ids.empty? }
106
+ guild_ids = Set[*@commands.map(&:guild_ids).flatten]
107
+ app_info = fetch_application.wait
108
+ http.put("/applications/#{app_info.id}/commands", global_commands.map(&:to_hash)).wait unless global_commands.empty?
109
+ guild_ids.each do |guild_id|
110
+ commands = @commands.select { |c| c.guild_ids.include?(guild_id) }
111
+ http.put("/applications/#{app_info.id}/guilds/#{guild_id}/commands", commands.map(&:to_hash)).wait
112
+ end unless guild_ids.empty?
113
+ @log.info "Successfully setup commands"
114
+ end
115
+ end
116
+ end
117
+
118
+ #
119
+ # Represents a application command.
120
+ # @abstract
121
+ #
122
+ class Command < DiscordModel
123
+ # @return [String] The name of the command.
124
+ attr_reader :name
125
+ # @return [Array<#to_s>] The guild ids that the command is enabled in.
126
+ attr_reader :guild_ids
127
+ # @return [Proc] The block of the command.
128
+ attr_reader :block
129
+ # @return [:chat_input, :user, :message] The type of the command.
130
+ attr_reader :type
131
+ # @return [Integer] The raw type of the command.
132
+ attr_reader :type_raw
133
+ # @return [Discorb::Dictionary{Discorb::Snowflake, :global => Discorb::Snowflake}] The ID mapping.
134
+ attr_reader :id_map
135
+
136
+ @types = {
137
+ 1 => :chat_input,
138
+ 2 => :user,
139
+ 3 => :message,
140
+ }.freeze
141
+
142
+ # @!visibility private
143
+ def initialize(name, guild_ids, block, type)
144
+ @name = name
145
+ @guild_ids = guild_ids.map(&:to_s)
146
+ @block = block
147
+ @raw_type = type
148
+ @type = Discorb::Command::Command.types[type]
149
+ @type_raw = type
150
+ @id_map = Discorb::Dictionary.new
151
+ end
152
+
153
+ # @!visibility private
154
+ def to_hash
155
+ {
156
+ name: @name,
157
+ default_permission: @default_permission,
158
+ type: @type_raw,
159
+ }
160
+ end
161
+
162
+ #
163
+ # Represents the slash command.
164
+ #
165
+ class SlashCommand < Command
166
+ # @return [String] The description of the command.
167
+ attr_reader :description
168
+ # @return [Hash{String => Hash}] The options of the command.
169
+ attr_reader :options
170
+
171
+ # @!visibility private
172
+ def initialize(name, description, options, guild_ids, block, type, parent)
173
+ @description = description
174
+ @name = name
175
+ @guild_ids = guild_ids.map(&:to_s)
176
+ @block = block
177
+ @type = Discorb::Command::Command.types[type]
178
+ @options = options
179
+ @id = nil
180
+ @parent = parent
181
+ @id_map = Discorb::Dictionary.new
182
+ end
183
+
184
+ #
185
+ # Returns the commands name.
186
+ #
187
+ # @return [String] The name of the command.
188
+ #
189
+ def to_s
190
+ (@parent + " " + @name).strip
191
+ end
192
+
193
+ # @!visibility private
194
+ def to_hash
195
+ options_payload = options.map do |name, value|
196
+ ret = {
197
+ type: case value[:type]
198
+ when String, :string, :str
199
+ 3
200
+ when Integer, :integer, :int
201
+ 4
202
+ when TrueClass, FalseClass, :boolean, :bool
203
+ 5
204
+ when Discorb::User, Discorb::Member, :user, :member
205
+ 6
206
+ when Discorb::Channel, :channel
207
+ 7
208
+ when Discorb::Role, :role
209
+ 8
210
+ when :mentionable
211
+ 9
212
+ when Float, :float
213
+ 10
214
+ else
215
+ raise ArgumentError, "Invalid option type: #{value[:type]}"
216
+ end,
217
+ name: name,
218
+ description: value[:description],
219
+ required: !value[:optional],
220
+ }
221
+ if value[:choices]
222
+ ret[:choices] = value[:choices].map { |t| { name: t[0], value: t[1] } }
223
+ end
224
+ ret
225
+ end
226
+ {
227
+ name: @name,
228
+ default_permission: true,
229
+ description: @description,
230
+ options: options_payload,
231
+ }
232
+ end
233
+ end
234
+
235
+ #
236
+ # Represents the command with subcommands.
237
+ #
238
+ class GroupCommand < Command
239
+ # @return [Array<Discorb::Command::Command::SlashCommand, Discorb::Command::Command::SubcommandGroup>] The subcommands of the command.
240
+ attr_reader :commands
241
+ # @return [String] The description of the command.
242
+ attr_reader :description
243
+
244
+ # @!visibility private
245
+ def initialize(name, description, guild_ids, type)
246
+ super(name, guild_ids, block, type)
247
+ @description = description
248
+ @commands = []
249
+ @id_map = Discorb::Dictionary.new
250
+ end
251
+
252
+ #
253
+ # Add new subcommand.
254
+ #
255
+ # @param (see Discorb::Command::Handler#slash)
256
+ # @return [Discorb::Command::Command::SlashCommand] The added subcommand.
257
+ #
258
+ def slash(command_name, description, options = {}, &block)
259
+ command = Discorb::Command::Command::SlashCommand.new(command_name, description, options, [], block, 1, @name)
260
+ options_payload = options.map do |name, value|
261
+ ret = {
262
+ type: case (value[:type].is_a?(Array) ? value[:type].first : value[:type])
263
+ when String, :string
264
+ 3
265
+ when Integer
266
+ 4
267
+ when TrueClass, FalseClass, :boolean
268
+ 5
269
+ when Discorb::User, Discorb::Member, :user, :member
270
+ 6
271
+ when Discorb::Channel, :channel
272
+ 7
273
+ when Discorb::Role, :role
274
+ 8
275
+ when :mentionable
276
+ 9
277
+ when Float
278
+ 10
279
+ end,
280
+ name: name,
281
+ description: value[:description],
282
+ required: !value[:optional],
283
+ }
284
+ if value[:type].is_a?(Array)
285
+ ret[:choices] = value[:type]
286
+ end
287
+
288
+ ret
289
+ end
290
+ {
291
+ name: @name,
292
+ default_permission: true,
293
+ description: @description,
294
+ options: options_payload,
295
+ }
296
+ @commands << command
297
+ command
298
+ end
299
+
300
+ #
301
+ # Add new subcommand group.
302
+ #
303
+ # @param [String] command_name Group name.
304
+ # @param [String] description Group description.
305
+ #
306
+ # @return [Discorb::Command::Command::SubcommandGroup] Command object.
307
+ #
308
+ # @see file:docs/slash_command.md
309
+ #
310
+ def group(command_name, description)
311
+ command = Discorb::Command::Command::SubcommandGroup.new(command_name, description, @name)
312
+ @commands << command
313
+ command
314
+ end
315
+
316
+ #
317
+ # Returns the command name.
318
+ #
319
+ # @return [String] The command name.
320
+ #
321
+ def to_s
322
+ @name
323
+ end
324
+
325
+ # @!visibility private
326
+ def to_hash
327
+ options_payload = @commands.map do |command|
328
+ if command.is_a?(SlashCommand)
329
+ {
330
+ name: command.name,
331
+ description: command.description,
332
+ default_permission: command.enabled,
333
+ type: 1,
334
+ options: command.to_hash[:options],
335
+ }
336
+ else
337
+ {
338
+ name: command.name,
339
+ description: command.description,
340
+ default_permission: command.enabled,
341
+ type: 2,
342
+ options: command.commands.map { |c| c.to_hash.merge(type: 1) },
343
+ }
344
+ end
345
+ end
346
+
347
+ {
348
+ name: @name,
349
+ default_permission: @enabled,
350
+ description: @description,
351
+ options: options_payload,
352
+ }
353
+ end
354
+ end
355
+
356
+ #
357
+ # Represents the subcommand group.
358
+ #
359
+ class SubcommandGroup < GroupCommand
360
+ # @return [Array<Discorb::Command::Command::SlashCommand>] The subcommands of the command.
361
+ attr_reader :commands
362
+
363
+ # @!visibility private
364
+ def initialize(name, description, enabled, parent)
365
+ super(name, description, [], enabled, 1)
366
+
367
+ @commands = []
368
+ @parent = parent
369
+ end
370
+
371
+ def to_s
372
+ @parent + " " + @name
373
+ end
374
+
375
+ #
376
+ # Add new subcommand.
377
+ # @param (see Discorb::Command::Handler#slash)
378
+ # @return [Discorb::Command::Command::SlashCommand] The added subcommand.
379
+ #
380
+ def slash(command_name, description, options = {}, enabled: true, &block)
381
+ command = Discorb::Command::Command::SlashCommand.new(command_name, description, options, [], enabled, block, 1, @parent + " " + @name)
382
+ @commands << command
383
+ command
384
+ end
385
+ end
386
+
387
+ class << self
388
+ # @!visibility private
389
+ attr_reader :types
390
+ end
391
+ end
392
+ end
393
+ end