discorb 0.14.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_version.yml +1 -1
  3. data/.github/workflows/lint-push.yml +4 -2
  4. data/.rubocop.yml +6 -2
  5. data/Changelog.md +27 -0
  6. data/Rakefile +6 -0
  7. data/docs/events.md +71 -5
  8. data/docs/faq.md +8 -8
  9. data/examples/simple/rolepanel.rb +1 -1
  10. data/examples/simple/shard.rb +17 -0
  11. data/lib/discorb/allowed_mentions.rb +7 -0
  12. data/lib/discorb/app_command/command.rb +64 -2
  13. data/lib/discorb/app_command/handler.rb +1 -1
  14. data/lib/discorb/application.rb +16 -7
  15. data/lib/discorb/asset.rb +9 -0
  16. data/lib/discorb/{file.rb → attachment.rb} +55 -33
  17. data/lib/discorb/audit_logs.rb +42 -4
  18. data/lib/discorb/channel.rb +47 -12
  19. data/lib/discorb/client.rb +135 -51
  20. data/lib/discorb/common.rb +18 -4
  21. data/lib/discorb/components/button.rb +5 -6
  22. data/lib/discorb/components/select_menu.rb +2 -16
  23. data/lib/discorb/dictionary.rb +2 -0
  24. data/lib/discorb/embed.rb +71 -38
  25. data/lib/discorb/emoji.rb +29 -2
  26. data/lib/discorb/emoji_table.rb +1 -1
  27. data/lib/discorb/error.rb +7 -1
  28. data/lib/discorb/event.rb +27 -17
  29. data/lib/discorb/exe/new.rb +5 -5
  30. data/lib/discorb/exe/run.rb +1 -15
  31. data/lib/discorb/gateway.rb +262 -161
  32. data/lib/discorb/gateway_requests.rb +4 -7
  33. data/lib/discorb/guild.rb +67 -33
  34. data/lib/discorb/guild_template.rb +24 -3
  35. data/lib/discorb/http.rb +25 -3
  36. data/lib/discorb/integration.rb +23 -8
  37. data/lib/discorb/intents.rb +15 -10
  38. data/lib/discorb/interaction/autocomplete.rb +4 -4
  39. data/lib/discorb/interaction/command.rb +34 -5
  40. data/lib/discorb/interaction/components.rb +15 -2
  41. data/lib/discorb/interaction/response.rb +12 -0
  42. data/lib/discorb/interaction/root.rb +16 -1
  43. data/lib/discorb/invite.rb +11 -7
  44. data/lib/discorb/member.rb +21 -0
  45. data/lib/discorb/message.rb +59 -3
  46. data/lib/discorb/message_meta.rb +36 -55
  47. data/lib/discorb/modules.rb +38 -14
  48. data/lib/discorb/permission.rb +14 -5
  49. data/lib/discorb/presence.rb +41 -8
  50. data/lib/discorb/rate_limit.rb +7 -2
  51. data/lib/discorb/reaction.rb +6 -0
  52. data/lib/discorb/role.rb +12 -0
  53. data/lib/discorb/shard.rb +74 -0
  54. data/lib/discorb/sticker.rb +22 -14
  55. data/lib/discorb/user.rb +11 -0
  56. data/lib/discorb/voice_state.rb +20 -2
  57. data/lib/discorb/webhook.rb +53 -2
  58. data/lib/discorb.rb +5 -3
  59. data/sig/discorb.rbs +7234 -6714
  60. metadata +5 -4
  61. data/lib/discorb/log.rb +0 -81
@@ -14,7 +14,10 @@ module Discorb
14
14
  # @return [Array<Discorb::AuditLog::Entry>] The entries in this audit log.
15
15
  attr_reader :entries
16
16
 
17
+ #
18
+ # Initializes a new instance of the AuditLog class.
17
19
  # @private
20
+ #
18
21
  def initialize(client, data, guild)
19
22
  @client = client
20
23
  @guild = guild
@@ -24,6 +27,10 @@ module Discorb
24
27
  @entries = data[:audit_log_entries].map { |entry| AuditLog::Entry.new(@client, entry, guild.id) }
25
28
  end
26
29
 
30
+ def inspect
31
+ "<#{self.class} #{@entries.length} entries>"
32
+ end
33
+
27
34
  #
28
35
  # Gets an entry from entries.
29
36
  #
@@ -108,8 +115,11 @@ module Discorb
108
115
  # @!attribute [r] user
109
116
  # @return [Discorb::User] The user who performed the action.
110
117
 
118
+ #
119
+ # @return [{Integer => Symbol}] The map of events to their respective changes.
111
120
  # @private
112
- @events = {
121
+ #
122
+ EVENTS = {
113
123
  1 => :guild_update,
114
124
  10 => :channel_create,
115
125
  11 => :channel_update,
@@ -159,24 +169,30 @@ module Discorb
159
169
  112 => :thread_delete,
160
170
  }.freeze
161
171
 
172
+ #
173
+ # The converter for the change.
162
174
  # @private
163
- @converts = {
175
+ #
176
+ CONVERTERS = {
164
177
  channel: ->(client, id, _guild_id) { client.channels[id] },
165
178
  thread: ->(client, id, _guild_id) { client.channels[id] },
166
179
  role: ->(client, id, guild_id) { client.guilds[guild_id]&.roles&.[](id) },
167
180
  member: ->(client, id, guild_id) { client.guilds[guild_id]&.members&.[](id) },
168
181
  guild: ->(client, id, _guild_id) { client.guilds[id] },
169
182
  message: ->(client, id, _guild_id) { client.messages[id] },
170
- }
183
+ }.freeze
171
184
 
185
+ #
186
+ # Initializes a new AuditLog entry.
172
187
  # @private
188
+ #
173
189
  def initialize(client, data, guild_id)
174
190
  @client = client
175
191
  @guild_id = Snowflake.new(guild_id)
176
192
  @id = Snowflake.new(data[:id])
177
193
  @user_id = Snowflake.new(data[:user_id])
178
194
  @target_id = Snowflake.new(data[:target_id])
179
- @type = self.class.events[data[:action_type]]
195
+ @type = EVENTS[data[:action_type]]
180
196
  @target = self.class.converts[@type.to_s.split("_")[0].to_sym]&.call(client, @target_id, @gui)
181
197
  @target ||= Snowflake.new(data[:target_id])
182
198
  @changes = data[:changes] && Changes.new(data[:changes])
@@ -223,8 +239,11 @@ module Discorb
223
239
  attr_reader :data
224
240
 
225
241
  #
242
+ # Initializes a new changes object.
226
243
  # @private
227
244
  #
245
+ # @param [Hash] data The data to initialize with.
246
+ #
228
247
  def initialize(data)
229
248
  @data = data.to_h { |d| [d[:key].to_sym, d] }
230
249
  @data.each do |k, v|
@@ -232,6 +251,9 @@ module Discorb
232
251
  end
233
252
  end
234
253
 
254
+ #
255
+ # Formats the changes into a string.
256
+ #
235
257
  def inspect
236
258
  "#<#{self.class} #{@data.length} changes>"
237
259
  end
@@ -270,7 +292,10 @@ module Discorb
270
292
  # @return [Object] The new value of the change.
271
293
  attr_reader :new_value
272
294
 
295
+ #
296
+ # Initializes a new change object.
273
297
  # @private
298
+ #
274
299
  def initialize(data)
275
300
  @key = data[:key].to_sym
276
301
  method = case @key.to_s
@@ -298,10 +323,20 @@ module Discorb
298
323
  @new_value.__send__(method, ...)
299
324
  end
300
325
 
326
+ #
327
+ # Format the change into a string.
328
+ #
329
+ # @return [String] The string representation of the change.
330
+ #
301
331
  def inspect
302
332
  "#<#{self.class} #{@key.inspect} #{@old_value.inspect} -> #{@new_value.inspect}>"
303
333
  end
304
334
 
335
+ #
336
+ # Whether the change responds to the given method.
337
+ #
338
+ # @return [Boolean] Whether the change responds to the given method.
339
+ #
305
340
  def respond_to_missing?(method, include_private = false)
306
341
  @new_value.respond_to?(method, include_private)
307
342
  end
@@ -321,7 +356,10 @@ module Discorb
321
356
  # @return [Discorb::Integration::Account] The account of the integration.
322
357
  attr_reader :account
323
358
 
359
+ #
360
+ # Initializes a new integration object.
324
361
  # @private
362
+ #
325
363
  def initialize(data)
326
364
  @id = Snowflake.new(data[:id])
327
365
  @type = data[:type].to_sym
@@ -19,7 +19,10 @@ module Discorb
19
19
  @channel_type = nil
20
20
  @subclasses = []
21
21
 
22
+ #
23
+ # Initializes a new instance of the Channel class.
22
24
  # @private
25
+ #
23
26
  def initialize(client, data, no_cache: false)
24
27
  @client = client
25
28
  @data = {}
@@ -44,22 +47,35 @@ module Discorb
44
47
  "#<#{self.class} \"##{@name}\" id=#{@id}>"
45
48
  end
46
49
 
50
+ #
51
+ # Returns the descendants of the Channel class.
47
52
  # @private
53
+ #
48
54
  def self.descendants
49
55
  ObjectSpace.each_object(Class).select { |klass| klass < self }
50
56
  end
51
57
 
58
+ #
59
+ # Creates a new instance of the Channel class or instance of its descendants.
52
60
  # @private
61
+ #
62
+ # @param [Discorb::Client] client The client that instantiated the object.
63
+ # @param [Hash] data The data of the object.
64
+ # @param [Boolean] no_cache Whether to disable cache the object.
65
+ #
53
66
  def self.make_channel(client, data, no_cache: false)
54
67
  descendants.each do |klass|
55
68
  return klass.new(client, data, no_cache: no_cache) if !klass.channel_type.nil? && klass.channel_type == data[:type]
56
69
  end
57
- client.log.warn("Unknown channel type #{data[:type]}, initialized GuildChannel")
70
+ client.logger.warn("Unknown channel type #{data[:type]}, initialized GuildChannel")
58
71
  GuildChannel.new(client, data)
59
72
  end
60
73
 
61
74
  class << self
75
+ #
62
76
  # @private
77
+ # @return [Integer] The type of the channel.
78
+ #
63
79
  attr_reader :channel_type
64
80
  end
65
81
 
@@ -67,7 +83,12 @@ module Discorb
67
83
  self.class.channel_type
68
84
  end
69
85
 
86
+ #
87
+ # Returns the channel id to request.
70
88
  # @private
89
+ #
90
+ # @return [Async::Task<Discorb::Snowflake>] A task that resolves to the channel id.
91
+ #
71
92
  def channel_id
72
93
  Async do
73
94
  @id
@@ -114,7 +135,7 @@ module Discorb
114
135
  #
115
136
  # @param [Discorb::GuildChannel] other The channel to compare.
116
137
  #
117
- # @return [-1, 1] -1 if the channel is at lower than the other, 1 if the channel is at highter than the other.
138
+ # @return [-1, 0, 1] -1 if the channel is at lower than the other, 1 if the channel is at highter than the other.
118
139
  #
119
140
  def <=>(other)
120
141
  return 0 unless other.respond_to?(:position)
@@ -239,17 +260,15 @@ module Discorb
239
260
  # @return [Time] The time when the last pinned message was pinned.
240
261
  attr_reader :last_pin_timestamp
241
262
  alias last_pinned_at last_pin_timestamp
242
- # @return [Array<Discorb::ThreadChannel>] The threads in the channel.
243
- attr_reader :threads
244
263
 
245
264
  include Messageable
246
265
 
247
266
  @channel_type = 0
248
267
 
249
- # @private
250
- def initialize(client, data, no_cache: false)
251
- super
252
- @threads = Dictionary.new
268
+ # @!attribute [r] threads
269
+ # @return [Array<Discorb::ThreadChannel>] The threads in the channel.
270
+ def threads
271
+ guild.threads.select { |thread| thread.parent == self }
253
272
  end
254
273
 
255
274
  #
@@ -421,7 +440,7 @@ module Discorb
421
440
  def fetch_invites
422
441
  Async do
423
442
  _resp, data = @client.http.request(Route.new("/channels/#{@id}/invites", "//channels/:channel_id/invites", :get)).wait
424
- data.map { |invite| Invite.new(@client, invite) }
443
+ data.map { |invite| Invite.new(@client, invite, false) }
425
444
  end
426
445
  end
427
446
 
@@ -446,7 +465,7 @@ module Discorb
446
465
  temporary: temporary,
447
466
  unique: unique,
448
467
  }, audit_log_reason: reason).wait
449
- Invite.new(@client, data)
468
+ Invite.new(@client, data, false)
450
469
  end
451
470
  end
452
471
 
@@ -666,7 +685,10 @@ module Discorb
666
685
  attr_reader :bitrate
667
686
  # @return [Integer] The user limit of the voice channel.
668
687
  attr_reader :user_limit
688
+ #
669
689
  # @private
690
+ # @return [Discorb::Dictionary{Discorb::Snowflake => StageInstance}] The stage instances associated with the stage channel.
691
+ #
670
692
  attr_reader :stage_instances
671
693
 
672
694
  include Connectable
@@ -675,7 +697,10 @@ module Discorb
675
697
  # @return [Discorb::StageInstance] The stage instance of the channel.
676
698
 
677
699
  @channel_type = 13
700
+ #
701
+ # Initialize a new stage channel.
678
702
  # @private
703
+ #
679
704
  def initialize(...)
680
705
  @stage_instances = Dictionary.new
681
706
  super(...)
@@ -825,12 +850,17 @@ module Discorb
825
850
  include Messageable
826
851
  @channel_type = nil
827
852
 
853
+ #
854
+ # Initialize a new thread channel.
828
855
  # @private
856
+ #
857
+ # @param [Discorb::Client] client The client.
858
+ # @param [Hash] data The data of the thread channel.
859
+ # @param [Boolean] no_cache Whether to disable the cache.
860
+ #
829
861
  def initialize(client, data, no_cache: false)
830
862
  @members = Dictionary.new
831
863
  super
832
- @client.channels[@parent_id].threads[@id] = self
833
-
834
864
  @client.channels[@id] = self unless no_cache
835
865
  end
836
866
 
@@ -1117,7 +1147,12 @@ module Discorb
1117
1147
  class DMChannel < Channel
1118
1148
  include Messageable
1119
1149
 
1150
+ #
1151
+ # Returns the channel id to request.
1120
1152
  # @private
1153
+ #
1154
+ # @return [Async::Task<Discorb::Snowflake>] A task that resolves to the channel id.
1155
+ #
1121
1156
  def channel_id
1122
1157
  Async do
1123
1158
  @id
@@ -40,8 +40,6 @@ module Discorb
40
40
  attr_reader :emojis
41
41
  # @return [Discorb::Dictionary{Discorb::Snowflake => Discorb::Message}] A dictionary of messages.
42
42
  attr_reader :messages
43
- # @return [Discorb::Logger] The logger.
44
- attr_reader :log
45
43
  # @return [Array<Discorb::ApplicationCommand::Command>] The commands that the client is using.
46
44
  attr_reader :commands
47
45
  # @return [Float] The ping of the client.
@@ -50,12 +48,28 @@ module Discorb
50
48
  attr_reader :ping
51
49
  # @return [:initialized, :running, :closed] The status of the client.
52
50
  attr_reader :status
53
- # @return [Integer] The session ID of connection.
54
- attr_reader :session_id
55
51
  # @return [Hash{String => Discorb::Extension}] The loaded extensions.
56
52
  attr_reader :extensions
53
+ # @return [Hash{Integer => Discorb::Shard}] The shards of the client.
54
+ attr_reader :shards
57
55
  # @private
56
+ # @return [Hash{Discorb::Snowflake => Discorb::ApplicationCommand::Command}] The commands on the top level.
58
57
  attr_reader :bottom_commands
58
+ # @private
59
+ # @return [{String => Thread::Mutex}] A hash of mutexes.
60
+ attr_reader :mutex
61
+
62
+ # @!attribute [r] session_id
63
+ # @return [String] The session ID of the client or current shard.
64
+ # @return [nil] If not connected to the gateway.
65
+ # @!attribute [r] shard
66
+ # @return [Discorb::Shard] The current shard. This is implemented with Thread variables.
67
+ # @return [nil] If client has no shard.
68
+ # @!attribute [r] shard_id
69
+ # @return [Discorb::Shard] The current shard ID. This is implemented with Thread variables.
70
+ # @return [nil] If client has no shard.
71
+ # @!attribute [r] logger
72
+ # @return [Logger] The logger.
59
73
 
60
74
  #
61
75
  # Initializes a new client.
@@ -63,8 +77,7 @@ module Discorb
63
77
  # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions that the client is using.
64
78
  # @param [Discorb::Intents] intents The intents that the client is currently using.
65
79
  # @param [Integer] message_caches The number of messages to cache.
66
- # @param [#write] log The IO object to use for logging.
67
- # @param [Boolean] colorize_log Whether to colorize the log.
80
+ # @param [Logger] logger The IO object to use for logging.
68
81
  # @param [:debug, :info, :warn, :error, :critical] log_level The log level.
69
82
  # @param [Boolean] wait_until_ready Whether to delay event dispatch until ready.
70
83
  # @param [Boolean] fetch_member Whether to fetch member on ready. This may slow down the client. Default to `false`.
@@ -72,7 +85,7 @@ module Discorb
72
85
  #
73
86
  def initialize(
74
87
  allowed_mentions: nil, intents: nil, message_caches: 1000,
75
- log: nil, colorize_log: false, log_level: :info,
88
+ logger: nil,
76
89
  wait_until_ready: true, fetch_member: false,
77
90
  title: nil
78
91
  )
@@ -80,7 +93,7 @@ module Discorb
80
93
  @intents = (intents or Intents.default)
81
94
  @events = {}
82
95
  @api_version = nil
83
- @log = Logger.new(log, colorize_log, log_level)
96
+ @logger = logger || Logger.new($stdout, progname: "discorb")
84
97
  @user = nil
85
98
  @users = Discorb::Dictionary.new
86
99
  @channels = Discorb::Dictionary.new
@@ -100,6 +113,8 @@ module Discorb
100
113
  @fetch_member = fetch_member
101
114
  @title = title
102
115
  @extensions = {}
116
+ @mutex = {}
117
+ @shards = {}
103
118
  set_default_events
104
119
  end
105
120
 
@@ -180,16 +195,16 @@ module Discorb
180
195
  events << event_method
181
196
  end
182
197
  if events.nil?
183
- @log.debug "Event #{event_name} doesn't have any proc, skipping"
198
+ logger.debug "Event #{event_name} doesn't have any proc, skipping"
184
199
  next
185
200
  end
186
- @log.debug "Dispatching event #{event_name}"
201
+ logger.debug "Dispatching event #{event_name}"
187
202
  events.each do |block|
188
203
  Async do
189
204
  Async(annotation: "Discorb event: #{event_name}") do |_task|
190
205
  @events[event_name].delete(block) if block.is_a?(Discorb::EventHandler) && block.metadata[:once]
191
206
  block.call(*args)
192
- @log.debug "Dispatched proc with ID #{block.id.inspect}"
207
+ logger.debug "Dispatched proc with ID #{block.id.inspect}"
193
208
  rescue StandardError, ScriptError => e
194
209
  dispatch(:error, event_name, args, e)
195
210
  end
@@ -309,10 +324,11 @@ module Discorb
309
324
  activities: [],
310
325
  status: status,
311
326
  since: nil,
327
+ afk: nil,
312
328
  }
313
329
  payload[:activities] = [activity.to_hash] unless activity.nil?
314
330
  payload[:status] = status unless status.nil?
315
- if @connection
331
+ if connection
316
332
  Async do
317
333
  send_gateway(3, **payload)
318
334
  end
@@ -423,15 +439,15 @@ module Discorb
423
439
  #
424
440
  # @note If the token is nil, you should use `discorb run` with the `-e` or `--env` option.
425
441
  #
426
- def run(token = nil)
442
+ def run(token = nil, shards: nil, shard_count: nil)
427
443
  token ||= ENV["DISCORB_CLI_TOKEN"]
428
444
  raise ArgumentError, "Token is not specified, and -e/--env is not specified" if token.nil?
429
445
  case ENV["DISCORB_CLI_FLAG"]
430
446
  when nil
431
- start_client(token)
447
+ start_client(token, shards: shards, shard_count: shard_count)
432
448
  when "run"
433
449
  before_run(token)
434
- start_client(token)
450
+ start_client(token, shards: shards, shard_count: shard_count)
435
451
  when "setup"
436
452
  run_setup(token)
437
453
  end
@@ -441,10 +457,33 @@ module Discorb
441
457
  # Stops the client.
442
458
  #
443
459
  def close!
444
- @connection.send_close
460
+ if @shards.any?
461
+ @shards.each(&:close!)
462
+ else
463
+ @connection.send_close
464
+ end
445
465
  @tasks.each(&:stop)
446
466
  @status = :closed
447
- @close_condition.signal
467
+ end
468
+
469
+ def session_id
470
+ if shard
471
+ shard.session_id
472
+ else
473
+ @session_id
474
+ end
475
+ end
476
+
477
+ def logger
478
+ shard&.logger || @logger
479
+ end
480
+
481
+ def shard
482
+ Thread.current.thread_variable_get("shard")
483
+ end
484
+
485
+ def shard_id
486
+ Thread.current.thread_variable_get("shard_id")
448
487
  end
449
488
 
450
489
  private
@@ -453,22 +492,6 @@ module Discorb
453
492
  require "json"
454
493
  options = JSON.parse(ENV["DISCORB_CLI_OPTIONS"], symbolize_names: true)
455
494
  setup_commands(token) if options[:setup]
456
- if options[:log_level]
457
- if options[:log_level] == "none"
458
- @log.out = nil
459
- else
460
- @log.out = case options[:log_file]
461
- when nil, "stderr"
462
- $stderr
463
- when "stdout"
464
- $stdout
465
- else
466
- ::File.open(options[:log_file], "a")
467
- end
468
- @log.level = options[:log_level].to_sym
469
- @log.colorize_log = options[:log_color].nil? ? @log.out.isatty : options[:log_color]
470
- end
471
- end
472
495
  end
473
496
 
474
497
  def run_setup(token)
@@ -486,32 +509,93 @@ module Discorb
486
509
  end
487
510
  end
488
511
 
489
- def start_client(token)
490
- Async do |_task|
491
- Signal.trap(:SIGINT) do
492
- @log.info "SIGINT received, closing..."
493
- Signal.trap(:SIGINT, "DEFAULT")
494
- close!
512
+ def set_status(status, shard)
513
+ if shard.nil?
514
+ @status = status
515
+ else
516
+ @shards[shard].status = status
517
+ end
518
+ end
519
+
520
+ def connection
521
+ if shard_id
522
+ @shards[shard_id].connection
523
+ else
524
+ @connection
525
+ end
526
+ end
527
+
528
+ def connection=(value)
529
+ if shard_id
530
+ @shards[shard_id].connection = value
531
+ else
532
+ @connection = value
533
+ end
534
+ end
535
+
536
+ def session_id=(value)
537
+ if shard_id
538
+ @shards[shard_id].session_id = value
539
+ else
540
+ @session_id = value
541
+ end
542
+ end
543
+
544
+ def start_client(token, shards: nil, shard_count: nil)
545
+ @token = token.to_s
546
+ @shard_count = shard_count
547
+ Signal.trap(:SIGINT) do
548
+ logger.info "SIGINT received, closing..."
549
+ Signal.trap(:SIGINT, "DEFAULT")
550
+ close!
551
+ end
552
+ if shards.nil?
553
+ main_loop(nil)
554
+ else
555
+ @shards = shards.map.with_index do |shard, i|
556
+ Shard.new(self, shard, shard_count, i)
495
557
  end
496
- @token = token.to_s
497
- @close_condition = Async::Condition.new
498
- @main_task = Async do
499
- @status = :running
500
- connect_gateway(false).wait
501
- rescue StandardError
502
- @status = :stopped
503
- @close_condition.signal
504
- raise
558
+ @shards[..-1].each_with_index do |shard, i|
559
+ shard.next_shard = @shards[i + 1]
505
560
  end
506
- @close_condition.wait
507
- @main_task.stop
561
+ @shards.each { |s| s.thread.join }
562
+ end
563
+ end
564
+
565
+ def main_loop(shard)
566
+ close_condition = Async::Condition.new
567
+ self.main_task = Async do
568
+ set_status(:running, shard)
569
+ connect_gateway(false).wait
570
+ rescue StandardError
571
+ set_status(:running, shard)
572
+ close_condition.signal
573
+ raise
574
+ end
575
+ close_condition.wait
576
+ main_task.stop
577
+ end
578
+
579
+ def main_task
580
+ if shard_id
581
+ shard.main_task
582
+ else
583
+ @main_task
584
+ end
585
+ end
586
+
587
+ def main_task=(value)
588
+ if shard_id
589
+ shard.main_task = value
590
+ else
591
+ @main_task = value
508
592
  end
509
593
  end
510
594
 
511
595
  def set_default_events
512
596
  on :error, override: true do |event_name, _args, e|
513
597
  message = "An error occurred while dispatching #{event_name}:\n#{e.full_message}"
514
- @log.error message, fallback: $stderr
598
+ logger.error message, fallback: $stderr
515
599
  end
516
600
 
517
601
  once :standby do
@@ -2,9 +2,11 @@
2
2
 
3
3
  module Discorb
4
4
  # @return [String] The API base URL.
5
- API_BASE_URL = "https://discord.com/api/v9"
5
+ API_BASE_URL = "https://discord.com/api/v10"
6
6
  # @return [String] The version of discorb.
7
- VERSION = "0.14.0"
7
+ VERSION = "0.16.0"
8
+ # @return [Array<Integer>] The version array of discorb.
9
+ VERSION_ARRAY = VERSION.split(".").map(&:to_i).freeze
8
10
  # @return [String] The user agent for the bot.
9
11
  USER_AGENT = "DiscordBot (https://discorb-lib.github.io #{VERSION}) Ruby/#{RUBY_VERSION}".freeze
10
12
 
@@ -25,8 +27,11 @@ module Discorb
25
27
  end
26
28
  end
27
29
 
28
- # @private
30
+ def inspect
31
+ "#<#{self.class}: #{@id}>"
32
+ end
29
33
 
34
+ # @private
30
35
  def hash
31
36
  @id.hash
32
37
  end
@@ -37,7 +42,12 @@ module Discorb
37
42
  #
38
43
  # @see https://discord.com/developers/docs/reference#snowflakes Official Discord API docs
39
44
  class Snowflake < String
45
+ #
46
+ # Initialize new snowflake.
40
47
  # @private
48
+ #
49
+ # @param [#to_s] value The value of the snowflake.
50
+ #
41
51
  def initialize(value)
42
52
  @value = value.to_i
43
53
  super(@value.to_s)
@@ -92,7 +102,7 @@ module Discorb
92
102
  end
93
103
 
94
104
  def timestamp
95
- Time.at(((@value >> 22) + 1_420_070_400_000) / 1000)
105
+ Time.at(((@value >> 22) + 1_420_070_400_000) / 1000.0)
96
106
  end
97
107
 
98
108
  def worker_id
@@ -127,6 +137,10 @@ module Discorb
127
137
  @method = method
128
138
  end
129
139
 
140
+ def inspect
141
+ "#<#{self.class} #{self.identifier}>"
142
+ end
143
+
130
144
  def hash
131
145
  @url.hash
132
146
  end
@@ -21,7 +21,9 @@ module Discorb
21
21
  attr_accessor :disabled
22
22
  alias disabled? disabled
23
23
 
24
- @styles = {
24
+ # @private
25
+ # @return [{Symbol => Integer}] The mapping of button styles.
26
+ STYLES = {
25
27
  primary: 1,
26
28
  secondary: 2,
27
29
  success: 3,
@@ -59,7 +61,7 @@ module Discorb
59
61
  {
60
62
  type: 2,
61
63
  label: @label,
62
- style: self.class.styles[@style],
64
+ style: STYLES[@style],
63
65
  url: @url,
64
66
  emoji: @emoji&.to_hash,
65
67
  disabled: @disabled,
@@ -68,7 +70,7 @@ module Discorb
68
70
  {
69
71
  type: 2,
70
72
  label: @label,
71
- style: self.class.styles[@style],
73
+ style: STYLES[@style],
72
74
  custom_id: @custom_id,
73
75
  emoji: @emoji&.to_hash,
74
76
  disabled: @disabled,
@@ -81,9 +83,6 @@ module Discorb
81
83
  end
82
84
 
83
85
  class << self
84
- # @private
85
- attr_reader :styles
86
-
87
86
  #
88
87
  # Creates a new button from a hash.
89
88
  #