discorb 0.13.2 → 0.15.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 (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
  #