discorb 0.13.2 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/build_version.yml +1 -1
  4. data/.github/workflows/codeql-analysis.yml +70 -0
  5. data/.github/workflows/lint-push.yml +20 -0
  6. data/.github/workflows/lint.yml +16 -0
  7. data/.rubocop.yml +70 -0
  8. data/CODE_OF_CONDUCT.md +128 -0
  9. data/Changelog.md +34 -0
  10. data/Gemfile +7 -3
  11. data/README.md +1 -1
  12. data/Rakefile +22 -22
  13. data/discorb.gemspec +13 -1
  14. data/docs/faq.md +8 -8
  15. data/examples/commands/bookmarker.rb +2 -1
  16. data/examples/commands/hello.rb +1 -0
  17. data/examples/commands/inspect.rb +3 -2
  18. data/examples/components/authorization_button.rb +2 -1
  19. data/examples/components/select_menu.rb +2 -1
  20. data/examples/extension/main.rb +1 -0
  21. data/examples/extension/message_expander.rb +1 -0
  22. data/examples/simple/eval.rb +3 -2
  23. data/examples/simple/ping_pong.rb +1 -0
  24. data/examples/simple/rolepanel.rb +1 -0
  25. data/examples/simple/wait_for_message.rb +4 -3
  26. data/exe/discorb +8 -7
  27. data/lib/discorb/allowed_mentions.rb +64 -0
  28. data/lib/discorb/app_command/command.rb +274 -0
  29. data/lib/discorb/app_command/handler.rb +168 -0
  30. data/lib/discorb/app_command.rb +2 -404
  31. data/lib/discorb/asset.rb +3 -1
  32. data/lib/discorb/{file.rb → attachment.rb} +42 -35
  33. data/lib/discorb/audit_logs.rb +3 -3
  34. data/lib/discorb/channel.rb +65 -61
  35. data/lib/discorb/client.rb +36 -33
  36. data/lib/discorb/common.rb +29 -22
  37. data/lib/discorb/components/button.rb +106 -0
  38. data/lib/discorb/components/select_menu.rb +157 -0
  39. data/lib/discorb/components/text_input.rb +96 -0
  40. data/lib/discorb/components.rb +11 -276
  41. data/lib/discorb/dictionary.rb +13 -2
  42. data/lib/discorb/embed.rb +40 -33
  43. data/lib/discorb/emoji.rb +21 -5
  44. data/lib/discorb/emoji_table.rb +1 -1
  45. data/lib/discorb/error.rb +4 -6
  46. data/lib/discorb/event.rb +13 -11
  47. data/lib/discorb/exe/about.rb +1 -0
  48. data/lib/discorb/exe/irb.rb +4 -3
  49. data/lib/discorb/exe/new.rb +6 -7
  50. data/lib/discorb/exe/run.rb +2 -1
  51. data/lib/discorb/exe/setup.rb +8 -5
  52. data/lib/discorb/exe/show.rb +1 -0
  53. data/lib/discorb/extend.rb +19 -14
  54. data/lib/discorb/extension.rb +5 -1
  55. data/lib/discorb/gateway.rb +82 -29
  56. data/lib/discorb/guild.rb +58 -80
  57. data/lib/discorb/guild_template.rb +5 -5
  58. data/lib/discorb/http.rb +52 -170
  59. data/lib/discorb/integration.rb +32 -3
  60. data/lib/discorb/intents.rb +9 -4
  61. data/lib/discorb/interaction/autocomplete.rb +5 -4
  62. data/lib/discorb/interaction/command.rb +34 -9
  63. data/lib/discorb/interaction/components.rb +5 -2
  64. data/lib/discorb/interaction/modal.rb +33 -0
  65. data/lib/discorb/interaction/response.rb +41 -12
  66. data/lib/discorb/interaction/root.rb +1 -0
  67. data/lib/discorb/interaction.rb +2 -1
  68. data/lib/discorb/invite.rb +1 -1
  69. data/lib/discorb/log.rb +4 -3
  70. data/lib/discorb/member.rb +4 -6
  71. data/lib/discorb/message.rb +38 -241
  72. data/lib/discorb/message_meta.rb +157 -0
  73. data/lib/discorb/modules.rb +47 -23
  74. data/lib/discorb/permission.rb +2 -2
  75. data/lib/discorb/presence.rb +6 -3
  76. data/lib/discorb/rate_limit.rb +15 -21
  77. data/lib/discorb/role.rb +3 -3
  78. data/lib/discorb/sticker.rb +2 -2
  79. data/lib/discorb/user.rb +3 -3
  80. data/lib/discorb/utils/colored_puts.rb +1 -0
  81. data/lib/discorb/voice_state.rb +7 -2
  82. data/lib/discorb/webhook.rb +9 -6
  83. data/lib/discorb.rb +2 -1
  84. data/sig/discorb.rbs +5836 -6714
  85. data/template-replace/scripts/arrow.rb +1 -0
  86. data/template-replace/scripts/favicon.rb +1 -0
  87. data/template-replace/scripts/index.rb +2 -1
  88. data/template-replace/scripts/locale_ja.rb +5 -4
  89. data/template-replace/scripts/sidebar.rb +1 -0
  90. data/template-replace/scripts/version.rb +7 -10
  91. data/template-replace/scripts/yard_replace.rb +5 -4
  92. metadata +30 -5
@@ -1,406 +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.put("/applications/#{app_info.id}/commands", global_commands.map(&:to_hash)).wait unless global_commands.empty?
133
- final_guild_ids.each do |guild_id|
134
- commands = local_commands.select { |c| c.guild_ids.include?(guild_id) }
135
- http.put("/applications/#{app_info.id}/guilds/#{guild_id}/commands", commands.map(&:to_hash)).wait
136
- end unless final_guild_ids.empty?
137
- @log.info "Successfully setup commands"
138
- end
139
- end
140
- end
141
-
142
- #
143
- # Represents a application command.
144
- # @abstract
145
- #
146
- class Command < DiscordModel
147
- # @return [String] The name of the command.
148
- attr_reader :name
149
- # @return [Array<#to_s>] The guild ids that the command is enabled in.
150
- attr_reader :guild_ids
151
- # @return [Proc] The block of the command.
152
- attr_reader :block
153
- # @return [:chat_input, :user, :message] The type of the command.
154
- attr_reader :type
155
- # @return [Integer] The raw type of the command.
156
- attr_reader :type_raw
157
- # @return [Discorb::Dictionary{Discorb::Snowflake, :global => Discorb::Snowflake}] The ID mapping.
158
- attr_reader :id_map
159
-
160
- @types = {
161
- 1 => :chat_input,
162
- 2 => :user,
163
- 3 => :message,
164
- }.freeze
165
-
166
- # @private
167
- def initialize(name, guild_ids, block, type)
168
- @name = name
169
- @guild_ids = guild_ids&.map(&:to_s)
170
- @block = block
171
- @raw_type = type
172
- @type = Discorb::ApplicationCommand::Command.types[type]
173
- @type_raw = type
174
- @id_map = Discorb::Dictionary.new
175
- end
176
-
177
- # @private
178
- def replace_block(instance)
179
- current_block = @block.dup
180
- @block = Proc.new do |*args|
181
- instance.instance_exec(*args, &current_block)
182
- end
183
- end
184
-
185
- # @private
186
- def to_hash
187
- {
188
- name: @name,
189
- default_permission: @default_permission,
190
- type: @type_raw,
191
- }
192
- end
193
-
194
- #
195
- # Represents the slash command.
196
- #
197
- class SlashCommand < Command
198
- # @return [String] The description of the command.
199
- attr_reader :description
200
- # @return [Hash{String => Hash}] The options of the command.
201
- attr_reader :options
202
-
203
- # @private
204
- def initialize(name, description, options, guild_ids, block, type, parent)
205
- super(name, guild_ids, block, type)
206
- @description = description
207
- @options = options
208
- @id = nil
209
- @parent = parent
210
- @id_map = Discorb::Dictionary.new
211
- end
212
-
213
- #
214
- # Returns the commands name.
215
- #
216
- # @return [String] The name of the command.
217
- #
218
- def to_s
219
- (@parent + " " + @name).strip
220
- end
221
-
222
- # @private
223
- def to_hash
224
- options_payload = options.map do |name, value|
225
- ret = {
226
- type: case value[:type]
227
- when String, :string, :str
228
- 3
229
- when Integer, :integer, :int
230
- 4
231
- when TrueClass, FalseClass, :boolean, :bool
232
- 5
233
- when Discorb::User, Discorb::Member, :user, :member
234
- 6
235
- when Discorb::Channel, :channel
236
- 7
237
- when Discorb::Role, :role
238
- 8
239
- when :mentionable
240
- 9
241
- when Float, :float
242
- 10
243
- else
244
- raise ArgumentError, "Invalid option type: #{value[:type]}"
245
- end,
246
- name: name,
247
- description: value[:description],
248
- required: value[:required].nil? ? !value[:optional] : value[:required],
249
- }
250
-
251
- ret[:choices] = value[:choices].map { |t| { name: t[0], value: t[1] } } if value[:choices]
252
-
253
- ret[:channel_types] = value[:channel_types].map(&:channel_type) if value[:channel_types]
254
-
255
- ret[:autocomplete] = !!value[:autocomplete] if value[:autocomplete]
256
- if value[:range]
257
- ret[:min_value] = value[:range].begin
258
- ret[:max_value] = value[:range].end
259
- end
260
- ret
261
- end
262
- {
263
- name: @name,
264
- default_permission: true,
265
- description: @description,
266
- options: options_payload,
267
- }
268
- end
269
- end
270
-
271
- #
272
- # Represents the command with subcommands.
273
- #
274
- class GroupCommand < Command
275
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand, Discorb::ApplicationCommand::Command::SubcommandGroup>] The subcommands of the command.
276
- attr_reader :commands
277
- # @return [String] The description of the command.
278
- attr_reader :description
279
-
280
- # @private
281
- def initialize(name, description, guild_ids, type, client)
282
- super(name, guild_ids, block, type)
283
- @description = description
284
- @commands = []
285
- @client = client
286
- @id_map = Discorb::Dictionary.new
287
- end
288
-
289
- #
290
- # Add new subcommand.
291
- #
292
- # @param (see Discorb::ApplicationCommand::Handler#slash)
293
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
294
- #
295
- def slash(command_name, description, options = {}, &block)
296
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @name)
297
- @client.bottom_commands << command
298
- @commands << command
299
- command
300
- end
301
-
302
- #
303
- # Add new subcommand group.
304
- #
305
- # @param [String] command_name Group name.
306
- # @param [String] description Group description.
307
- #
308
- # @yield Block to yield with the command.
309
- # @yieldparam [Discorb::ApplicationCommand::Command::SubcommandGroup] group Group command.
310
- #
311
- # @return [Discorb::ApplicationCommand::Command::SubcommandGroup] Command object.
312
- #
313
- # @see file:docs/application_command.md Application Commands
314
- #
315
- def group(command_name, description, &block)
316
- command = Discorb::ApplicationCommand::Command::SubcommandGroup.new(command_name, description, @name, @client)
317
- command.yield_self(&block) if block_given?
318
- @commands << command
319
- command
320
- end
321
-
322
- #
323
- # Returns the command name.
324
- #
325
- # @return [String] The command name.
326
- #
327
- def to_s
328
- @name
329
- end
330
-
331
- # @private
332
- def block_replace(instance)
333
- super
334
- @commands.each { |c| c.replace_block(instance) }
335
- end
336
-
337
- # @private
338
- def to_hash
339
- options_payload = @commands.map do |command|
340
- if command.is_a?(SlashCommand)
341
- {
342
- name: command.name,
343
- description: command.description,
344
- default_permission: true,
345
- type: 1,
346
- options: command.to_hash[:options],
347
- }
348
- else
349
- {
350
- name: command.name,
351
- description: command.description,
352
- default_permission: true,
353
- type: 2,
354
- options: command.commands.map { |c| c.to_hash.merge(type: 1) },
355
- }
356
- end
357
- end
358
-
359
- {
360
- name: @name,
361
- default_permission: @enabled,
362
- description: @description,
363
- options: options_payload,
364
- }
365
- end
366
- end
367
-
368
- #
369
- # Represents the subcommand group.
370
- #
371
- class SubcommandGroup < GroupCommand
372
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand>] The subcommands of the command.
373
- attr_reader :commands
374
-
375
- # @private
376
- def initialize(name, description, parent, client)
377
- super(name, description, [], 1, client)
378
-
379
- @commands = []
380
- @parent = parent
381
- end
382
-
383
- def to_s
384
- @parent + " " + @name
385
- end
386
-
387
- #
388
- # Add new subcommand.
389
- # @param (see Discorb::ApplicationCommand::Handler#slash)
390
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
391
- #
392
- def slash(command_name, description, options = {}, &block)
393
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @parent + " " + @name)
394
- @commands << command
395
- @client.bottom_commands << command
396
- command
397
- end
398
- end
399
-
400
- class << self
401
- # @private
402
- attr_reader :types
403
- end
404
- end
405
- end
2
+ %w[command handler].each do |file|
3
+ require_relative "app_command/#{file}.rb"
406
4
  end
data/lib/discorb/asset.rb CHANGED
@@ -47,7 +47,7 @@ module Discorb
47
47
  "avatars"
48
48
  when Guild, IncomingWebhook::Guild
49
49
  "icons"
50
- when Application
50
+ when Application, Integration::Application
51
51
  "app-icons"
52
52
  when Application::Team
53
53
  "team-icons"
@@ -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
 
@@ -7,15 +7,17 @@ module Discorb
7
7
  #
8
8
  # Represents a attachment file.
9
9
  #
10
- class Attachment < DiscordModel
10
+ class Attachment
11
11
  # @return [#read] The file content.
12
12
  attr_reader :io
13
- # @return [Discorb::Snowflake] The attachment id.
14
- attr_reader :id
15
13
  # @return [String] The attachment filename.
16
14
  attr_reader :filename
17
15
  # @return [String] The attachment content type.
18
16
  attr_reader :content_type
17
+ # @return [String] The attachment description.
18
+ attr_reader :description
19
+ # @return [Discorb::Snowflake] The attachment id.
20
+ attr_reader :id
19
21
  # @return [Integer] The attachment size in bytes.
20
22
  attr_reader :size
21
23
  # @return [String] The attachment url.
@@ -28,12 +30,40 @@ module Discorb
28
30
  # @return [Integer] The image width.
29
31
  # @return [nil] If the attachment is not an image.
30
32
  attr_reader :width
33
+ # @return [:client, :discord] The attachment was created by.
34
+ attr_reader :created_by
35
+ # @private
36
+ attr_reader :will_close
31
37
 
32
38
  # @!attribute [r] image?
33
39
  # @return [Boolean] whether the file is an image.
34
40
 
41
+ #
42
+ # Creates a new attachment.
43
+ #
44
+ # @param [#read, String] source The Source of the attachment.
45
+ # @param [String] filename The filename of the attachment. If not set, path or object_id of the IO is used.
46
+ # @param [String] description The description of the attachment.
47
+ # @param [String] content_type The content type of the attachment. If not set, it is guessed from the filename.
48
+ # If failed to guess, it is set to `application/octet-stream`.
49
+ # @param [Boolean] will_close Whether the IO will be closed after the attachment is sent.
50
+ #
51
+ def initialize(source, filename = nil, description: nil, content_type: nil, will_close: true)
52
+ @io = if source.respond_to?(:read)
53
+ source
54
+ else
55
+ File.open(source, "rb")
56
+ end
57
+ @filename = filename || (@io.respond_to?(:path) ? @io.path : @io.object_id)
58
+ @description = description
59
+ @content_type = content_type || MIME::Types.type_for(@filename.to_s)[0].to_s
60
+ @content_type = "application/octet-stream" if @content_type == ""
61
+ @will_close = will_close
62
+ @created_by = :client
63
+ end
64
+
35
65
  # @private
36
- def initialize(data)
66
+ def initialize_hash(data)
37
67
  @id = Snowflake.new(data[:id])
38
68
  @filename = data[:filename]
39
69
  @content_type = data[:content_type]
@@ -42,37 +72,18 @@ module Discorb
42
72
  @proxy_url = data[:proxy_url]
43
73
  @height = data[:height]
44
74
  @width = data[:width]
75
+ @created_by = :discord
45
76
  end
46
77
 
47
78
  def image?
48
79
  @content_type.start_with? "image/"
49
80
  end
50
- end
51
81
 
52
- #
53
- # Represents a file to send as an attachment.
54
- #
55
- class File
56
- # @return [#read] The IO of the file.
57
- attr_accessor :io
58
- # @return [String] The filename of the file. If not set, path or object_id of the IO is used.
59
- attr_accessor :filename
60
- # @return [String] The content type of the file. If not set, it is guessed from the filename.
61
- attr_accessor :content_type
62
-
63
- #
64
- # Creates a new file from IO.
65
- #
66
- # @param [#read] io The IO of the file.
67
- # @param [String] filename The filename of the file. If not set, path or object_id of the IO is used.
68
- # @param [String] content_type The content type of the file. If not set, it is guessed from the filename.
69
- # If failed to guess, it is set to `application/octet-stream`.
70
- #
71
- def initialize(io, filename = nil, content_type: nil)
72
- @io = io
73
- @filename = filename || (io.respond_to?(:path) ? io.path : io.object_id)
74
- @content_type = content_type || MIME::Types.type_for(@filename.to_s)[0].to_s
75
- @content_type = "application/octet-stream" if @content_type == ""
82
+ # @private
83
+ def self.from_hash(data)
84
+ inst = allocate
85
+ inst.initialize_hash(data)
86
+ inst
76
87
  end
77
88
 
78
89
  #
@@ -84,14 +95,10 @@ module Discorb
84
95
  #
85
96
  # @return [File] The new file.
86
97
  #
87
- def self.from_string(string, filename: nil, content_type: nil)
98
+ def self.from_string(string, filename = nil, content_type: nil, description: nil)
88
99
  io = StringIO.new(string)
89
100
  filename ||= string.object_id.to_s + ".txt"
90
- new(io, filename, content_type: content_type)
91
- end
92
-
93
- def inspect
94
- "#<#{self.class} filename=#{@filename} content_type=#{@content_type}>"
101
+ new(io, filename, content_type: content_type, description: description, will_close: true)
95
102
  end
96
103
  end
97
104
  end
@@ -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
  #