discorb 0.13.4 → 0.15.1

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 (93) 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 +74 -0
  8. data/Changelog.md +30 -0
  9. data/Gemfile +7 -3
  10. data/Rakefile +28 -22
  11. data/discorb.gemspec +1 -0
  12. data/docs/events.md +50 -0
  13. data/docs/faq.md +8 -8
  14. data/examples/commands/bookmarker.rb +2 -1
  15. data/examples/commands/hello.rb +1 -0
  16. data/examples/commands/inspect.rb +3 -2
  17. data/examples/components/authorization_button.rb +2 -1
  18. data/examples/components/select_menu.rb +2 -1
  19. data/examples/extension/main.rb +1 -0
  20. data/examples/extension/message_expander.rb +1 -0
  21. data/examples/simple/eval.rb +3 -2
  22. data/examples/simple/ping_pong.rb +1 -0
  23. data/examples/simple/rolepanel.rb +1 -0
  24. data/examples/simple/wait_for_message.rb +4 -3
  25. data/exe/discorb +8 -7
  26. data/lib/discorb/allowed_mentions.rb +71 -0
  27. data/lib/discorb/app_command/command.rb +336 -0
  28. data/lib/discorb/app_command/handler.rb +168 -0
  29. data/lib/discorb/app_command.rb +2 -426
  30. data/lib/discorb/application.rb +16 -7
  31. data/lib/discorb/asset.rb +11 -0
  32. data/lib/discorb/{file.rb → attachment.rb} +55 -33
  33. data/lib/discorb/audit_logs.rb +45 -7
  34. data/lib/discorb/channel.rb +65 -15
  35. data/lib/discorb/client.rb +34 -27
  36. data/lib/discorb/common.rb +19 -27
  37. data/lib/discorb/components/button.rb +105 -0
  38. data/lib/discorb/components/select_menu.rb +143 -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 +5 -0
  42. data/lib/discorb/embed.rb +73 -40
  43. data/lib/discorb/emoji.rb +48 -5
  44. data/lib/discorb/error.rb +9 -5
  45. data/lib/discorb/event.rb +36 -24
  46. data/lib/discorb/exe/about.rb +1 -0
  47. data/lib/discorb/exe/irb.rb +4 -3
  48. data/lib/discorb/exe/new.rb +6 -7
  49. data/lib/discorb/exe/run.rb +2 -1
  50. data/lib/discorb/exe/setup.rb +8 -5
  51. data/lib/discorb/exe/show.rb +1 -0
  52. data/lib/discorb/extend.rb +19 -14
  53. data/lib/discorb/extension.rb +5 -1
  54. data/lib/discorb/gateway.rb +112 -51
  55. data/lib/discorb/gateway_requests.rb +4 -7
  56. data/lib/discorb/guild.rb +73 -41
  57. data/lib/discorb/guild_template.rb +26 -5
  58. data/lib/discorb/http.rb +38 -18
  59. data/lib/discorb/integration.rb +24 -9
  60. data/lib/discorb/intents.rb +16 -11
  61. data/lib/discorb/interaction/autocomplete.rb +6 -5
  62. data/lib/discorb/interaction/command.rb +66 -12
  63. data/lib/discorb/interaction/components.rb +19 -3
  64. data/lib/discorb/interaction/modal.rb +33 -0
  65. data/lib/discorb/interaction/response.rb +45 -4
  66. data/lib/discorb/interaction/root.rb +16 -0
  67. data/lib/discorb/interaction.rb +2 -1
  68. data/lib/discorb/invite.rb +11 -7
  69. data/lib/discorb/log.rb +5 -5
  70. data/lib/discorb/member.rb +22 -3
  71. data/lib/discorb/message.rb +39 -234
  72. data/lib/discorb/message_meta.rb +186 -0
  73. data/lib/discorb/modules.rb +39 -15
  74. data/lib/discorb/permission.rb +16 -7
  75. data/lib/discorb/presence.rb +45 -9
  76. data/lib/discorb/rate_limit.rb +7 -4
  77. data/lib/discorb/reaction.rb +6 -0
  78. data/lib/discorb/role.rb +12 -0
  79. data/lib/discorb/sticker.rb +22 -14
  80. data/lib/discorb/user.rb +12 -1
  81. data/lib/discorb/utils/colored_puts.rb +1 -0
  82. data/lib/discorb/voice_state.rb +23 -2
  83. data/lib/discorb/webhook.rb +54 -3
  84. data/lib/discorb.rb +5 -2
  85. data/sig/discorb.rbs +838 -702
  86. data/template-replace/scripts/arrow.rb +1 -0
  87. data/template-replace/scripts/favicon.rb +1 -0
  88. data/template-replace/scripts/index.rb +2 -1
  89. data/template-replace/scripts/locale_ja.rb +5 -4
  90. data/template-replace/scripts/sidebar.rb +1 -0
  91. data/template-replace/scripts/version.rb +7 -10
  92. data/template-replace/scripts/yard_replace.rb +5 -4
  93. metadata +17 -3
@@ -1,428 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
- module Discorb
4
- #
5
- # Handles application commands.
6
- #
7
- module ApplicationCommand
8
- #
9
- # Module to handle application commands.
10
- #
11
- module Handler
12
- #
13
- # Add new top-level command.
14
- #
15
- # @param [String] command_name Command name.
16
- # @param [String] description Command description.
17
- # @param [Hash{String => Hash{:description => String, :optional => Boolean, :type => Object}}] options Command options.
18
- # The key is the option name, the value is a hash with the following keys:
19
- #
20
- # | Key | Type | Description |
21
- # | --- | --- | --- |
22
- # | `:description` | `String` | Description of the option. |
23
- # | `:required` | Whether the argument is required. `optional` will be used if not specified. |
24
- # | `:optional` | Whether the argument is optional. `required` will be used if not specified. |
25
- # | `:type` | `Object` | Type of the option. |
26
- # | `:choice` | `Hash{String => String, Integer, Float}` | Type of the option. |
27
- # | `:default` | `Object` | Default value of the option. |
28
- # | `:channel_types` | `Array<Class<Discorb::Channel>>` | Type of the channel option. |
29
- # | `:autocomplete` | `Proc` | Autocomplete function. |
30
- # | `:range` | `Range` | Range of the option. Only valid for numeric options. (`:int`, `:float`) |
31
- #
32
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
33
- # @param [Proc] block Command block.
34
- #
35
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] Command object.
36
- #
37
- # @see file:docs/application_command.md#register-slash-command Application Comamnds: Register Slash Command
38
- # @see file:docs/cli/setup.md CLI: setup
39
- #
40
- def slash(command_name, description, options = {}, guild_ids: nil, &block)
41
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, guild_ids, block, 1, "")
42
- @commands << command
43
- @bottom_commands << command
44
- command
45
- end
46
-
47
- #
48
- # Add new command with group.
49
- #
50
- # @param [String] command_name Command name.
51
- # @param [String] description Command description.
52
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
53
- #
54
- # @yield Block to yield with the command.
55
- # @yieldparam [Discorb::ApplicationCommand::Command::GroupCommand] group Group command.
56
- #
57
- # @return [Discorb::ApplicationCommand::Command::GroupCommand] Command object.
58
- #
59
- # @see file:docs/application_command.md Application Commands
60
- # @see file:docs/cli/setup.md CLI: setup
61
- #
62
- def slash_group(command_name, description, guild_ids: nil, &block)
63
- command = Discorb::ApplicationCommand::Command::GroupCommand.new(command_name, description, guild_ids, nil, self)
64
- command.yield_self(&block) if block_given?
65
- @commands << command
66
- command
67
- end
68
-
69
- #
70
- # Add message context menu command.
71
- #
72
- # @param [String] command_name Command name.
73
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
74
- # @param [Proc] block Command block.
75
- # @yield [interaction, message] Block to execute.
76
- # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] interaction Interaction object.
77
- # @yieldparam [Discorb::Message] message Message object.
78
- #
79
- # @return [Discorb::ApplicationCommand::Command] Command object.
80
- #
81
- def message_command(command_name, guild_ids: nil, &block)
82
- command = Discorb::ApplicationCommand::Command.new(command_name, guild_ids, block, 3)
83
- @commands << command
84
- command
85
- end
86
-
87
- #
88
- # Add user context menu command.
89
- #
90
- # @param [String] command_name Command name.
91
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
92
- # @param [Proc] block Command block.
93
- # @yield [interaction, user] Block to execute.
94
- # @yieldparam [Discorb::CommandInteraction::UserMenuCommand] interaction Interaction object.
95
- # @yieldparam [Discorb::User] user User object.
96
- #
97
- # @return [Discorb::ApplicationCommand::Command] Command object.
98
- #
99
- def user_command(command_name, guild_ids: nil, &block)
100
- command = Discorb::ApplicationCommand::Command.new(command_name, guild_ids, block, 2)
101
- @commands << command
102
- command
103
- end
104
-
105
- #
106
- # Setup commands.
107
- # @async
108
- # @see Client#initialize
109
- #
110
- # @param [String] token Bot token.
111
- # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to use as default. If `false` is given, it will be global command.
112
- #
113
- # @note `token` parameter only required if you don't run client.
114
- #
115
- def setup_commands(token = nil, guild_ids: nil)
116
- Async do
117
- @token ||= token
118
- @http = HTTP.new(self)
119
- global_commands = @commands.select { |c| c.guild_ids == false or c.guild_ids == [] }
120
- local_commands = @commands.select { |c| c.guild_ids.is_a?(Array) and c.guild_ids.any? }
121
- default_commands = @commands.select { |c| c.guild_ids.nil? }
122
- if guild_ids.is_a?(Array)
123
- default_commands.each do |command|
124
- command.instance_variable_set(:@guild_ids, guild_ids)
125
- end
126
- local_commands += default_commands
127
- else
128
- global_commands += default_commands
129
- end
130
- final_guild_ids = local_commands.map(&:guild_ids).flatten.map(&:to_s).uniq
131
- app_info = fetch_application.wait
132
- @http.request(
133
- Route.new(
134
- "/applications/#{app_info.id}/commands",
135
- "//applications/:application_id/commands",
136
- :put
137
- ),
138
- global_commands.map(&:to_hash)
139
- ).wait unless global_commands.empty?
140
- if ENV["DISCORB_CLI_FLAG"] == "setup"
141
- sputs "Registered commands for global:"
142
- global_commands.each do |command|
143
- iputs "- #{command.name}"
144
- end
145
- end
146
- final_guild_ids.each do |guild_id|
147
- commands = local_commands.select { |c| c.guild_ids.include?(guild_id) }
148
- @http.request(
149
- Route.new("/applications/#{app_info.id}/guilds/#{guild_id}/commands",
150
- "//applications/:application_id/guilds/:guild_id/commands",
151
- :put),
152
- commands.map(&:to_hash)
153
- ).wait
154
- sputs "Registered commands for #{guild_id}:"
155
- commands.each do |command|
156
- iputs "- #{command.name}"
157
- end
158
- end unless final_guild_ids.empty?
159
- @log.info "Successfully setup commands"
160
- end
161
- end
162
- end
163
-
164
- #
165
- # Represents a application command.
166
- # @abstract
167
- #
168
- class Command < DiscordModel
169
- # @return [String] The name of the command.
170
- attr_reader :name
171
- # @return [Array<#to_s>] The guild ids that the command is enabled in.
172
- attr_reader :guild_ids
173
- # @return [Proc] The block of the command.
174
- attr_reader :block
175
- # @return [:chat_input, :user, :message] The type of the command.
176
- attr_reader :type
177
- # @return [Integer] The raw type of the command.
178
- attr_reader :type_raw
179
- # @return [Discorb::Dictionary{Discorb::Snowflake, :global => Discorb::Snowflake}] The ID mapping.
180
- attr_reader :id_map
181
-
182
- @types = {
183
- 1 => :chat_input,
184
- 2 => :user,
185
- 3 => :message,
186
- }.freeze
187
-
188
- # @private
189
- def initialize(name, guild_ids, block, type)
190
- @name = name
191
- @guild_ids = guild_ids&.map(&:to_s)
192
- @block = block
193
- @raw_type = type
194
- @type = Discorb::ApplicationCommand::Command.types[type]
195
- @type_raw = type
196
- @id_map = Discorb::Dictionary.new
197
- end
198
-
199
- # @private
200
- def replace_block(instance)
201
- current_block = @block.dup
202
- @block = Proc.new do |*args|
203
- instance.instance_exec(*args, &current_block)
204
- end
205
- end
206
-
207
- # @private
208
- def to_hash
209
- {
210
- name: @name,
211
- default_permission: @default_permission,
212
- type: @type_raw,
213
- }
214
- end
215
-
216
- #
217
- # Represents the slash command.
218
- #
219
- class SlashCommand < Command
220
- # @return [String] The description of the command.
221
- attr_reader :description
222
- # @return [Hash{String => Hash}] The options of the command.
223
- attr_reader :options
224
-
225
- # @private
226
- def initialize(name, description, options, guild_ids, block, type, parent)
227
- super(name, guild_ids, block, type)
228
- @description = description
229
- @options = options
230
- @id = nil
231
- @parent = parent
232
- @id_map = Discorb::Dictionary.new
233
- end
234
-
235
- #
236
- # Returns the commands name.
237
- #
238
- # @return [String] The name of the command.
239
- #
240
- def to_s
241
- (@parent + " " + @name).strip
242
- end
243
-
244
- # @private
245
- def to_hash
246
- options_payload = options.map do |name, value|
247
- ret = {
248
- type: case value[:type]
249
- when String, :string, :str
250
- 3
251
- when Integer, :integer, :int
252
- 4
253
- when TrueClass, FalseClass, :boolean, :bool
254
- 5
255
- when Discorb::User, Discorb::Member, :user, :member
256
- 6
257
- when Discorb::Channel, :channel
258
- 7
259
- when Discorb::Role, :role
260
- 8
261
- when :mentionable
262
- 9
263
- when Float, :float
264
- 10
265
- else
266
- raise ArgumentError, "Invalid option type: #{value[:type]}"
267
- end,
268
- name: name,
269
- description: value[:description],
270
- required: value[:required].nil? ? !value[:optional] : value[:required],
271
- }
272
-
273
- ret[:choices] = value[:choices].map { |t| { name: t[0], value: t[1] } } if value[:choices]
274
-
275
- ret[:channel_types] = value[:channel_types].map(&:channel_type) if value[:channel_types]
276
-
277
- ret[:autocomplete] = !!value[:autocomplete] if value[:autocomplete]
278
- if value[:range]
279
- ret[:min_value] = value[:range].begin
280
- ret[:max_value] = value[:range].end
281
- end
282
- ret
283
- end
284
- {
285
- name: @name,
286
- default_permission: true,
287
- description: @description,
288
- options: options_payload,
289
- }
290
- end
291
- end
292
-
293
- #
294
- # Represents the command with subcommands.
295
- #
296
- class GroupCommand < Command
297
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand, Discorb::ApplicationCommand::Command::SubcommandGroup>] The subcommands of the command.
298
- attr_reader :commands
299
- # @return [String] The description of the command.
300
- attr_reader :description
301
-
302
- # @private
303
- def initialize(name, description, guild_ids, type, client)
304
- super(name, guild_ids, block, type)
305
- @description = description
306
- @commands = []
307
- @client = client
308
- @id_map = Discorb::Dictionary.new
309
- end
310
-
311
- #
312
- # Add new subcommand.
313
- #
314
- # @param (see Discorb::ApplicationCommand::Handler#slash)
315
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
316
- #
317
- def slash(command_name, description, options = {}, &block)
318
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @name)
319
- @client.bottom_commands << command
320
- @commands << command
321
- command
322
- end
323
-
324
- #
325
- # Add new subcommand group.
326
- #
327
- # @param [String] command_name Group name.
328
- # @param [String] description Group description.
329
- #
330
- # @yield Block to yield with the command.
331
- # @yieldparam [Discorb::ApplicationCommand::Command::SubcommandGroup] group Group command.
332
- #
333
- # @return [Discorb::ApplicationCommand::Command::SubcommandGroup] Command object.
334
- #
335
- # @see file:docs/application_command.md Application Commands
336
- #
337
- def group(command_name, description, &block)
338
- command = Discorb::ApplicationCommand::Command::SubcommandGroup.new(command_name, description, @name, @client)
339
- command.yield_self(&block) if block_given?
340
- @commands << command
341
- command
342
- end
343
-
344
- #
345
- # Returns the command name.
346
- #
347
- # @return [String] The command name.
348
- #
349
- def to_s
350
- @name
351
- end
352
-
353
- # @private
354
- def block_replace(instance)
355
- super
356
- @commands.each { |c| c.replace_block(instance) }
357
- end
358
-
359
- # @private
360
- def to_hash
361
- options_payload = @commands.map do |command|
362
- if command.is_a?(SlashCommand)
363
- {
364
- name: command.name,
365
- description: command.description,
366
- default_permission: true,
367
- type: 1,
368
- options: command.to_hash[:options],
369
- }
370
- else
371
- {
372
- name: command.name,
373
- description: command.description,
374
- default_permission: true,
375
- type: 2,
376
- options: command.commands.map { |c| c.to_hash.merge(type: 1) },
377
- }
378
- end
379
- end
380
-
381
- {
382
- name: @name,
383
- default_permission: @enabled,
384
- description: @description,
385
- options: options_payload,
386
- }
387
- end
388
- end
389
-
390
- #
391
- # Represents the subcommand group.
392
- #
393
- class SubcommandGroup < GroupCommand
394
- # @return [Array<Discorb::ApplicationCommand::Command::SlashCommand>] The subcommands of the command.
395
- attr_reader :commands
396
-
397
- # @private
398
- def initialize(name, description, parent, client)
399
- super(name, description, [], 1, client)
400
-
401
- @commands = []
402
- @parent = parent
403
- end
404
-
405
- def to_s
406
- @parent + " " + @name
407
- end
408
-
409
- #
410
- # Add new subcommand.
411
- # @param (see Discorb::ApplicationCommand::Handler#slash)
412
- # @return [Discorb::ApplicationCommand::Command::SlashCommand] The added subcommand.
413
- #
414
- def slash(command_name, description, options = {}, &block)
415
- command = Discorb::ApplicationCommand::Command::SlashCommand.new(command_name, description, options, [], block, 1, @parent + " " + @name)
416
- @commands << command
417
- @client.bottom_commands << command
418
- command
419
- end
420
- end
421
-
422
- class << self
423
- # @private
424
- attr_reader :types
425
- end
426
- end
427
- end
2
+ %w[command handler].each do |file|
3
+ require_relative "app_command/#{file}.rb"
428
4
  end
@@ -29,7 +29,13 @@ module Discorb
29
29
  alias bot_require_code_grant? bot_require_code_grant
30
30
  # @return [Discorb::Application::Flag] The application's flags.
31
31
  attr_reader :flags
32
+ #
33
+ # Initializes a new instance of the Application class.
32
34
  # @private
35
+ #
36
+ # @param [Discorb::Client] client The client that instantiated the object.
37
+ # @param [Hash] data The data of the object.
38
+ #
33
39
  def initialize(client, data)
34
40
  @client = client
35
41
  @data = data
@@ -97,7 +103,13 @@ module Discorb
97
103
  # @return [Discorb::Application::Team::Member] The team's member.
98
104
  attr_reader :members
99
105
 
106
+ #
107
+ # Initializes a new instance of the Team class.
100
108
  # @private
109
+ #
110
+ # @param [Discorb::Client] client The client that instantiated the object.
111
+ # @param [Hash] data The data of the object.
112
+ #
101
113
  def initialize(client, data)
102
114
  @client = client
103
115
  @id = Snowflake.new(data[:id])
@@ -142,7 +154,9 @@ module Discorb
142
154
  # @!attribute [r] owner?
143
155
  # @return [Boolean] Whether the member is the team's owner.
144
156
 
145
- @membership_state = {
157
+ # @private
158
+ # @return [{Integer => Symbol}] The permission map.
159
+ MEMBERSHIP_STATE = {
146
160
  1 => :invited,
147
161
  2 => :accepted,
148
162
  }.freeze
@@ -153,7 +167,7 @@ module Discorb
153
167
  @team = team
154
168
  @user = client.users[data[:user][:id]] || User.new(client, data[:user])
155
169
  @team_id = Snowflake.new(data[:team_id])
156
- @membership_state = self.class.membership_state[data[:membership_state]]
170
+ @membership_state = MEMBERSHIP_STATE[data[:membership_state]]
157
171
  @permissions = data[:permissions].map(&:to_sym)
158
172
  end
159
173
 
@@ -176,11 +190,6 @@ module Discorb
176
190
  def ==(other)
177
191
  super || @user == other
178
192
  end
179
-
180
- class << self
181
- # @private
182
- attr_reader :membership_state
183
- end
184
193
  end
185
194
  end
186
195
  end
data/lib/discorb/asset.rb CHANGED
@@ -11,7 +11,13 @@ module Discorb
11
11
  # @!attribute [r] animated?
12
12
  # @return [Boolean] Whether the asset is animated.
13
13
 
14
+ #
15
+ # Initialize a new instance of the Asset class.
14
16
  # @private
17
+ #
18
+ # @param [Discorb::Client] client The client that instantiated the object.
19
+ # @param [Hash] data The data of the object.
20
+ #
15
21
  def initialize(target, hash, path: nil)
16
22
  @hash = hash
17
23
  @target = target
@@ -63,7 +69,10 @@ module Discorb
63
69
  # @!attribute [r] animated?
64
70
  # @return [false] For compatibility with {Asset}, always `false`.
65
71
 
72
+ #
73
+ # Initialize a new instance of the DefaultAvatar class.
66
74
  # @private
75
+ #
67
76
  def initialize(discriminator)
68
77
  @discriminator = discriminator.to_s.rjust(4, "0")
69
78
  end
@@ -80,7 +89,9 @@ module Discorb
80
89
  #
81
90
  # @return [String] URL of the avatar.
82
91
  #
92
+ # rubocop: disable Lint/UnusedMethodArgument
83
93
  def url(image_format: nil, size: 1024)
94
+ # rubocop: enable Lint/UnusedMethodArgument
84
95
  "https://cdn.discordapp.com/embed/avatars/#{@discriminator.to_i % 5}.png"
85
96
  end
86
97
 
@@ -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,44 @@ 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
+ # @return [Boolean] Whether the attachment will be closed after it is sent.
37
+ attr_reader :will_close
31
38
 
32
39
  # @!attribute [r] image?
33
40
  # @return [Boolean] whether the file is an image.
34
41
 
42
+ #
43
+ # Creates a new attachment.
44
+ #
45
+ # @param [#read, String] source The Source of the attachment.
46
+ # @param [String] filename The filename of the attachment. If not set, path or object_id of the IO is used.
47
+ # @param [String] description The description of the attachment.
48
+ # @param [String] content_type The content type of the attachment. If not set, it is guessed from the filename.
49
+ # If failed to guess, it is set to `application/octet-stream`.
50
+ # @param [Boolean] will_close Whether the IO will be closed after the attachment is sent.
51
+ #
52
+ def initialize(source, filename = nil, description: nil, content_type: nil, will_close: true)
53
+ @io = if source.respond_to?(:read)
54
+ source
55
+ else
56
+ File.open(source, "rb")
57
+ end
58
+ @filename = filename || (@io.respond_to?(:path) ? @io.path : @io.object_id)
59
+ @description = description
60
+ @content_type = content_type || MIME::Types.type_for(@filename.to_s)[0].to_s
61
+ @content_type = "application/octet-stream" if @content_type == ""
62
+ @will_close = will_close
63
+ @created_by = :client
64
+ end
65
+
66
+ #
67
+ # Initializes the object from a hash.
35
68
  # @private
36
- def initialize(data)
69
+ #
70
+ def initialize_hash(data)
37
71
  @id = Snowflake.new(data[:id])
38
72
  @filename = data[:filename]
39
73
  @content_type = data[:content_type]
@@ -42,37 +76,29 @@ module Discorb
42
76
  @proxy_url = data[:proxy_url]
43
77
  @height = data[:height]
44
78
  @width = data[:width]
79
+ @created_by = :discord
45
80
  end
46
81
 
47
82
  def image?
48
83
  @content_type.start_with? "image/"
49
84
  end
50
- end
51
85
 
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
86
+ def inspect
87
+ if @created_by == :discord
88
+ "<#{self.class} #{@id}: #{@filename}>"
89
+ else
90
+ "<#{self.class} #{io.fileno}: #{@filename}>"
91
+ end
92
+ end
62
93
 
63
94
  #
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`.
95
+ # Creates a new file from a hash.
96
+ # @private
70
97
  #
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 == ""
98
+ def self.from_hash(data)
99
+ inst = allocate
100
+ inst.initialize_hash(data)
101
+ inst
76
102
  end
77
103
 
78
104
  #
@@ -82,16 +108,12 @@ module Discorb
82
108
  # @param [String] filename The filename of the file. object_id of the string is used if not set.
83
109
  # @param [String] content_type The content type of the file. If not set, it is guessed from the filename.
84
110
  #
85
- # @return [File] The new file.
111
+ # @return [Discorb::Attachment] The new file.
86
112
  #
87
- def self.from_string(string, filename: nil, content_type: nil)
113
+ def self.from_string(string, filename = nil, content_type: nil, description: nil)
88
114
  io = StringIO.new(string)
89
115
  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}>"
116
+ new(io, filename, content_type: content_type, description: description, will_close: true)
95
117
  end
96
118
  end
97
119
  end