discorb 0.13.4 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
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