discorb 0.0.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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/.yardopts +6 -0
  4. data/Changelog.md +5 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +70 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +53 -0
  9. data/Rakefile +46 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/discorb.gemspec +37 -0
  13. data/docs/Examples.md +26 -0
  14. data/docs/events.md +480 -0
  15. data/docs/voice_events.md +283 -0
  16. data/examples/components/authorization_button.rb +43 -0
  17. data/examples/components/select_menu.rb +61 -0
  18. data/examples/extension/main.rb +12 -0
  19. data/examples/extension/message_expander.rb +41 -0
  20. data/examples/simple/eval.rb +32 -0
  21. data/examples/simple/ping_pong.rb +16 -0
  22. data/examples/simple/rolepanel.rb +65 -0
  23. data/examples/simple/wait_for_message.rb +30 -0
  24. data/lib/discorb/application.rb +157 -0
  25. data/lib/discorb/asset.rb +57 -0
  26. data/lib/discorb/audit_logs.rb +323 -0
  27. data/lib/discorb/channel.rb +1101 -0
  28. data/lib/discorb/client.rb +363 -0
  29. data/lib/discorb/color.rb +173 -0
  30. data/lib/discorb/common.rb +123 -0
  31. data/lib/discorb/components.rb +290 -0
  32. data/lib/discorb/dictionary.rb +119 -0
  33. data/lib/discorb/embed.rb +345 -0
  34. data/lib/discorb/emoji.rb +218 -0
  35. data/lib/discorb/emoji_table.rb +3799 -0
  36. data/lib/discorb/error.rb +98 -0
  37. data/lib/discorb/event.rb +35 -0
  38. data/lib/discorb/extend.rb +18 -0
  39. data/lib/discorb/extension.rb +54 -0
  40. data/lib/discorb/file.rb +69 -0
  41. data/lib/discorb/flag.rb +109 -0
  42. data/lib/discorb/gateway.rb +967 -0
  43. data/lib/discorb/gateway_requests.rb +47 -0
  44. data/lib/discorb/guild.rb +1244 -0
  45. data/lib/discorb/guild_template.rb +211 -0
  46. data/lib/discorb/image.rb +43 -0
  47. data/lib/discorb/integration.rb +111 -0
  48. data/lib/discorb/intents.rb +137 -0
  49. data/lib/discorb/interaction.rb +333 -0
  50. data/lib/discorb/internet.rb +285 -0
  51. data/lib/discorb/invite.rb +145 -0
  52. data/lib/discorb/log.rb +70 -0
  53. data/lib/discorb/member.rb +232 -0
  54. data/lib/discorb/message.rb +583 -0
  55. data/lib/discorb/modules.rb +138 -0
  56. data/lib/discorb/permission.rb +270 -0
  57. data/lib/discorb/presence.rb +308 -0
  58. data/lib/discorb/reaction.rb +48 -0
  59. data/lib/discorb/role.rb +189 -0
  60. data/lib/discorb/sticker.rb +157 -0
  61. data/lib/discorb/user.rb +163 -0
  62. data/lib/discorb/utils.rb +16 -0
  63. data/lib/discorb/voice_state.rb +251 -0
  64. data/lib/discorb/webhook.rb +420 -0
  65. data/lib/discorb.rb +51 -0
  66. metadata +120 -0
@@ -0,0 +1,16 @@
1
+ require "discorb"
2
+
3
+ client = Discorb::Client.new
4
+
5
+ client.once :ready do
6
+ puts "Logged in as #{client.user}"
7
+ end
8
+
9
+ client.on :message do |_task, message|
10
+ next if message.author.bot?
11
+ next unless message.content == "ping"
12
+
13
+ message.channel.post("Pong!")
14
+ end
15
+
16
+ client.run(ENV["DISCORD_BOT_TOKEN"])
@@ -0,0 +1,65 @@
1
+ require "discorb"
2
+ intents = Discorb::Intents.new
3
+ intents.members = true
4
+ client = Discorb::Client.new(intents: intents, log: $stdout, colorize_log: true)
5
+
6
+ def convert_role(guild, string)
7
+ guild.roles.find do |role|
8
+ role.id == string || role.name == string || role.mention == string
9
+ end
10
+ end
11
+
12
+ client.once :ready do
13
+ puts "Logged in as #{client.user}"
14
+ end
15
+
16
+ client.on :reaction_add do |_task, event|
17
+ next unless event.emoji.value.end_with?(0x0000fe0f.chr("utf-8") + 0x000020e3.chr("utf-8"))
18
+ next if event.member.bot?
19
+
20
+ msg = event.fetch_message.wait
21
+ if msg.embeds.length.positive? && msg.embeds[0].title == "Role panel" && msg.author == client.user
22
+ role_ids = msg.embeds[0].description.scan(/(?<=<@&)\d+(?=>)/)
23
+
24
+ role = event.guild.roles[role_ids[event.emoji.value[0].to_i - 1]]
25
+ next if role.nil?
26
+
27
+ event.member.add_role(role)
28
+ end
29
+ end
30
+
31
+ client.on :reaction_remove do |_task, event|
32
+ next unless event.emoji.value.end_with?(0x0000fe0f.chr("utf-8") + 0x000020e3.chr("utf-8"))
33
+ next if event.member.bot?
34
+
35
+ msg = event.fetch_message.wait
36
+ if msg.embeds.length.positive? && msg.embeds[0].title == "Role panel" && msg.author == client.user
37
+ role_ids = msg.embeds[0].description.scan(/(?<=<@&)\d+(?=>)/)
38
+
39
+ role = event.guild.roles[role_ids[event.emoji.value[0].to_i - 1]]
40
+ next if role.nil?
41
+
42
+ event.member.remove_role(role)
43
+ end
44
+ end
45
+
46
+ client.on :message do |_task, message|
47
+ next unless message.content.start_with?("/rp ")
48
+ next if message.author.bot?
49
+
50
+ message.reply("Too many roles.") if message.content.split.length > 10
51
+ roles = message.content.delete_prefix("/rp ").split.map.with_index { |raw_role, index| [index, convert_role(message.guild, raw_role), raw_role] }
52
+ if (convert_fails = roles.filter { |r| r[1].nil? }).length.positive?
53
+ message.reply("#{convert_fails.map { |r| r[2] }.join(", ")} is not a role.")
54
+ next
55
+ end
56
+ rp_msg = message.channel.post(embed: Discorb::Embed.new(
57
+ "Role panel",
58
+ roles.map.with_index(1) { |r, index| "#{index}\ufe0f\u20e3#{r[1].mention}" }.join("\n")
59
+ )).wait
60
+ 1.upto(roles.length).each do |i|
61
+ rp_msg.add_reaction(Discorb::UnicodeEmoji["#{i}\ufe0f\u20e3"]).wait
62
+ end
63
+ end
64
+
65
+ client.run(ENV["DISCORD_BOT_TOKEN"])
@@ -0,0 +1,30 @@
1
+ require "discorb"
2
+
3
+ client = Discorb::Client.new
4
+
5
+ client.once :ready do
6
+ puts "Logged in as #{client.user}"
7
+ end
8
+
9
+ client.on :message do |_task, message|
10
+ next if message.author.bot?
11
+ next unless message.content == "!quiz"
12
+
13
+ operator = [:+, :-, :*].sample
14
+ num1 = rand(1..10)
15
+ num2 = rand(1..10)
16
+
17
+ val = num1.send(operator, num2)
18
+ message.channel.post("Quiz: `#{num1} #{operator} #{num2}`")
19
+ begin
20
+ msg = client.event_lock(:message, 30) { |m|
21
+ m.content == val.to_s && m.channel == message.channel
22
+ }.wait
23
+ rescue Discorb::TimeoutError
24
+ message.channel.post("No one answered...")
25
+ else
26
+ msg.reply("Correct!")
27
+ end
28
+ end
29
+
30
+ client.run(ENV["DISCORD_BOT_TOKEN"])
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a Discord application.
6
+ #
7
+ class Application < DiscordModel
8
+ # @return [Discorb::Snowflake] The application's ID.
9
+ attr_reader :id
10
+ # @return [String] The application's name.
11
+ attr_reader :name
12
+ # @return [Discorb::Asset] The application's icon.
13
+ attr_reader :icon
14
+ # @return [String] The application's description.
15
+ attr_reader :description
16
+ # @return [String] The application's summary.
17
+ attr_reader :summary
18
+ # @return [String] The application's public key.
19
+ attr_reader :verify_key
20
+ # @return [Discorb::User] The application's owner.
21
+ attr_reader :owner
22
+ # @return [Discorb::Application::Team] The application's team.
23
+ attr_reader :team
24
+ # @return [Boolean] Whether the application's bot is public.
25
+ attr_reader :bot_public
26
+ alias bot_public? bot_public
27
+ # @return [Boolean] Whether the application's bot requires a code grant.
28
+ attr_reader :bot_require_code_grant
29
+ alias bot_require_code_grant? bot_require_code_grant
30
+
31
+ # @!visibility private
32
+ def initialize(client, data)
33
+ @client = client
34
+ @data = data
35
+ @id = Snowflake.new(data[:id])
36
+ @name = data[:name]
37
+ @icon = Asset.new(self, data[:icon])
38
+ @description = data[:description]
39
+ @summary = data[:summary]
40
+ @bot_public = data[:bot_public]
41
+ @bot_require_code_grant = data[:bot_require_code_grant]
42
+ @verify_key = data[:verify_key]
43
+ @owner = @client.users[data[:owner][:id]] || User.new(@client, data[:owner])
44
+ @team = data[:team] && Team.new(@client, data[:team])
45
+ end
46
+
47
+ def inspect
48
+ "#<#{self.class} id=#{@id}>"
49
+ end
50
+
51
+ alias public? bot_public?
52
+
53
+ alias require_code_grant? bot_require_code_grant?
54
+
55
+ #
56
+ # Represents a team for an application.
57
+ #
58
+ class Team < DiscordModel
59
+ # @return [Discorb::Snowflake] The team's ID.
60
+ attr_reader :id
61
+ # @return [Discorb::Asset] The team's icon.
62
+ attr_reader :icon
63
+ # @return [String] The team's name.
64
+ attr_reader :name
65
+ # @return [Discorb::Snowflake] The team's owner's ID.
66
+ attr_reader :owner_user_id
67
+ # @return [Discorb::Application::Team::Member] The team's member.
68
+ attr_reader :members
69
+
70
+ # @!visibility private
71
+ def initialize(client, data)
72
+ @client = client
73
+ @id = Snowflake.new(data[:id])
74
+ @icon = Asset.new(self, data[:icon])
75
+ @name = data[:name]
76
+ @owner_user_id = data[:owner_user_id]
77
+ @members = data[:members].map { |m| Team::Member.new(@client, self, m) }
78
+ end
79
+
80
+ #
81
+ # The team's owner.
82
+ #
83
+ # @return [Discorb::Application::Team::Member] The team's owner.
84
+ #
85
+ def owner
86
+ @members.find { |m| m.user.id == @owner_user_id }
87
+ end
88
+
89
+ def inspect
90
+ "#<#{self.class} id=#{@id}>"
91
+ end
92
+
93
+ #
94
+ # Represents a member of team.
95
+ #
96
+ class Member < DiscordModel
97
+ # @return [Discorb::User] The user.
98
+ attr_reader :user
99
+ # @return [Snowflake] The ID of member's team.
100
+ attr_reader :team_id
101
+ # @return [:invited, :accepted] The member's membership state.
102
+ attr_reader :membership_state
103
+ alias state membership_state
104
+ # @return [Array<Permissions>] The permissions of the member.
105
+ # @note This always return `:*`.
106
+ attr_reader :permissions
107
+
108
+ # @!attribute [r] pending?
109
+ # @return [Boolean] Whether the member is not joined to the team.
110
+ # @!attribute [r] accepted?
111
+ # @return [Boolean] Whether the member accepted joining the team.
112
+ # @!attribute [r] owner?
113
+ # @return [Boolean] Whether the member is the team's owner.
114
+
115
+ @membership_state = {
116
+ 1 => :invited,
117
+ 2 => :accepted,
118
+ }.freeze
119
+
120
+ def initialize(client, team, data)
121
+ @client = client
122
+ @data = data
123
+ @team = team
124
+ @user = client.users[data[:user][:id]] || User.new(client, data[:user])
125
+ @team_id = Snowflake.new(data[:team_id])
126
+ @membership_state = self.class.membership_state[data[:membership_state]]
127
+ @permissions = data[:permissions].map(&:to_sym)
128
+ end
129
+
130
+ def pending?
131
+ @membership_state == :invited
132
+ end
133
+
134
+ def accepted?
135
+ @membership_state == :accepted
136
+ end
137
+
138
+ def inspect
139
+ "#<#{self.class} id=#{@user.id}>"
140
+ end
141
+
142
+ def owner?
143
+ @team.owner_user_id == @user.id
144
+ end
145
+
146
+ def ==(other)
147
+ super || @user == other
148
+ end
149
+
150
+ class << self
151
+ # @!visibility private
152
+ attr_reader :membership_state
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a single asset.
6
+ #
7
+ class Asset < DiscordModel
8
+ # @return [String] The hash of asset.
9
+ attr_reader :hash
10
+
11
+ # @!attribute [r] animated?
12
+ # @return [Boolean] Whether the asset is animated.
13
+
14
+ # @!visibility private
15
+ def initialize(target, hash, path: nil)
16
+ @hash = hash
17
+ @target = target
18
+ @path = path
19
+ end
20
+
21
+ def animated?
22
+ @hash.start_with? "a_"
23
+ end
24
+
25
+ #
26
+ # URL of the asset.
27
+ #
28
+ # @param [String] image_format The image format.
29
+ # @param [Integer] size The size of the image.
30
+ #
31
+ # @return [String] URL of the asset.
32
+ #
33
+ def url(image_format: nil, size: 1024)
34
+ path = @path || "#{endpoint}/#{@target.id}"
35
+ "https://cdn.discordapp.com/#{path}/#{@hash}.#{image_format or (animated? ? "gif" : "webp")}?size=#{size}"
36
+ end
37
+
38
+ def inspect
39
+ "#<#{self.class} #{@target.class} #{@hash}>"
40
+ end
41
+
42
+ private
43
+
44
+ def endpoint
45
+ case @target
46
+ when User, Member, Webhook
47
+ "avatars"
48
+ when Guild, IncomingWebhook::Guild
49
+ "icons"
50
+ when Application
51
+ "app-icons"
52
+ when Application::Team
53
+ "team-icons"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,323 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a Discord audit log.
6
+ #
7
+ class AuditLog < DiscordModel
8
+ # @return [Array<Discorb::Webhook>] The webhooks in this audit log.
9
+ attr_reader :webhooks
10
+ # @return [Array<Discorb::User>] The users in this audit log.
11
+ attr_reader :users
12
+ # @return [Array<Discorb::ThreadChannel>] The threads in this audit log.
13
+ attr_reader :threads
14
+ # @return [Array<Discorb::AuditLog::Entry>] The entries in this audit log.
15
+ attr_reader :entries
16
+
17
+ # @!visibility private
18
+ def initialize(client, data, guild)
19
+ @client = client
20
+ @guild = guild
21
+ @webhooks = data[:webhooks].map { |webhook| Webhook.new([@client, webhook]) }
22
+ @users = data[:users].map { |user| client.users[user[:id]] || User.new(@client, user) }
23
+ @threads = data[:threads].map { |thread| client.channels[thread[:id]] || Channel.make_channel(@client, thread, no_cache: true) }
24
+ @entries = data[:audit_log_entries].map { |entry| AuditLog::Entry.new(@client, entry, guild.id) }
25
+ end
26
+
27
+ #
28
+ # Gets an entry from entries.
29
+ #
30
+ # @param [Integer] index The index of the entry.
31
+ #
32
+ # @return [Discorb::AuditLog::Entry] The entry.
33
+ # @return [nil] If the index is out of range.
34
+ #
35
+ def [](index)
36
+ @entries[index]
37
+ end
38
+
39
+ #
40
+ # Represents an entry in an audit log.
41
+ #
42
+ class Entry < DiscordModel
43
+ # @return [Discorb::Snowflake] The ID of the entry.
44
+ attr_reader :id
45
+ # @return [Discorb::Snowflake] The ID of the user who performed the action.
46
+ attr_reader :user_id
47
+ # @return [Discorb::Snowflake] The ID of the target of the action.
48
+ attr_reader :target_id
49
+ # @return [Symbol] The type of the entry.
50
+ # These symbols will be used:
51
+ #
52
+ # * `:guild_update`
53
+ # * `:channel_create`
54
+ # * `:channel_update`
55
+ # * `:channel_delete`
56
+ # * `:channel_overwrite_create`
57
+ # * `:channel_overwrite_update`
58
+ # * `:channel_overwrite_delete`
59
+ # * `:member_kick`
60
+ # * `:member_prune`
61
+ # * `:member_ban_add`
62
+ # * `:member_ban_remove`
63
+ # * `:member_update`
64
+ # * `:member_role_update`
65
+ # * `:member_move`
66
+ # * `:member_disconnect`
67
+ # * `:bot_add`
68
+ # * `:role_create`
69
+ # * `:role_update`
70
+ # * `:role_delete`
71
+ # * `:invite_create`
72
+ # * `:invite_update`
73
+ # * `:invite_delete`
74
+ # * `:webhook_create`
75
+ # * `:webhook_update`
76
+ # * `:webhook_delete`
77
+ # * `:emoji_create`
78
+ # * `:emoji_update`
79
+ # * `:emoji_delete`
80
+ # * `:message_delete`
81
+ # * `:message_bulk_delete`
82
+ # * `:message_pin`
83
+ # * `:message_unpin`
84
+ # * `:integration_create`
85
+ # * `:integration_update`
86
+ # * `:integration_delete`
87
+ # * `:stage_instance_create`
88
+ # * `:stage_instance_update`
89
+ # * `:stage_instance_delete`
90
+ # * `:sticker_create`
91
+ # * `:sticker_update`
92
+ # * `:sticker_delete`
93
+ # * `:thread_create`
94
+ # * `:thread_update`
95
+ # * `:thread_delete`
96
+ attr_reader :type
97
+ # @return [Discorb::AuditLog::Entry::Changes] The changes in this entry.
98
+ attr_reader :changes
99
+ # @return [Discorb::Channel, Discorb::Role, Discorb::Member, Discorb::Guild, Discorb::Message] The target of the entry.
100
+ attr_reader :target
101
+ # @return [Hash{Symbol => Object}] The optional data for this entry.
102
+ # @note You can use dot notation to access the data.
103
+ attr_reader :options
104
+
105
+ # @!attribute [r] user
106
+ # @return [Discorb::User] The user who performed the action.
107
+
108
+ # @!visibility private
109
+ @events = {
110
+ 1 => :guild_update,
111
+ 10 => :channel_create,
112
+ 11 => :channel_update,
113
+ 12 => :channel_delete,
114
+ 13 => :channel_overwrite_create,
115
+ 14 => :channel_overwrite_update,
116
+ 15 => :channel_overwrite_delete,
117
+ 20 => :member_kick,
118
+ 21 => :member_prune,
119
+ 22 => :member_ban_add,
120
+ 23 => :member_ban_remove,
121
+ 24 => :member_update,
122
+ 25 => :member_role_update,
123
+ 26 => :member_move,
124
+ 27 => :member_disconnect,
125
+ 28 => :bot_add,
126
+ 30 => :role_create,
127
+ 31 => :role_update,
128
+ 32 => :role_delete,
129
+ 40 => :invite_create,
130
+ 41 => :invite_update,
131
+ 42 => :invite_delete,
132
+ 50 => :webhook_create,
133
+ 51 => :webhook_update,
134
+ 52 => :webhook_delete,
135
+ 60 => :emoji_create,
136
+ 61 => :emoji_update,
137
+ 62 => :emoji_delete,
138
+ 72 => :message_delete,
139
+ 73 => :message_bulk_delete,
140
+ 74 => :message_pin,
141
+ 75 => :message_unpin,
142
+ 80 => :integration_create,
143
+ 81 => :integration_update,
144
+ 82 => :integration_delete,
145
+ 83 => :stage_instance_create,
146
+ 84 => :stage_instance_update,
147
+ 85 => :stage_instance_delete,
148
+ 90 => :sticker_create,
149
+ 91 => :sticker_update,
150
+ 92 => :sticker_delete,
151
+ 110 => :thread_create,
152
+ 111 => :thread_update,
153
+ 112 => :thread_delete
154
+ }.freeze
155
+
156
+ # @!visibility private
157
+ @converts = {
158
+ channel: ->(client, id, _guild_id) { client.channels[id] },
159
+ thread: ->(client, id, _guild_id) { client.channels[id] },
160
+ role: ->(client, id, guild_id) { client.guilds[guild_id]&.roles&.[](id) },
161
+ member: ->(client, id, guild_id) { client.guilds[guild_id]&.members&.[](id) },
162
+ guild: ->(client, id, _guild_id) { client.guilds[id] },
163
+ message: ->(client, id, _guild_id) { client.messages[id] }
164
+ }
165
+
166
+ # @!visibility private
167
+ def initialize(client, data, guild_id)
168
+ @client = client
169
+ @guild_id = Snowflake.new(guild_id)
170
+ @id = Snowflake.new(data[:id])
171
+ @user_id = Snowflake.new(data[:user_id])
172
+ @target_id = Snowflake.new(data[:target_id])
173
+ @type = self.class.events[data[:action_type]]
174
+ @target = self.class.converts[@type.to_s.split('_')[0].to_sym]&.call(client, @target_id, @gui)
175
+ @target ||= Snowflake.new(data[:target_id])
176
+ @changes = data[:changes] && Changes.new(data[:changes])
177
+ @reason = data[:reason]
178
+ data[:options]&.each do |option, value|
179
+ define_singleton_method(option) { value }
180
+ if option.end_with?('_id')
181
+ define_singleton_method(option.to_s.sub('_id', '')) do
182
+ self.class.converts[option.to_s.split('_')[0].to_sym]&.call(client, value, @guild_id)
183
+ end
184
+ end
185
+ end
186
+ @options = data[:options] || {}
187
+ end
188
+
189
+ def user
190
+ @client.users[@user_id]
191
+ end
192
+
193
+ #
194
+ # Get a change with the given key.
195
+ #
196
+ # @param [Symbol] key The key to get.
197
+ #
198
+ # @return [Discorb::AuditLog::Entry::Change] The change with the given key.
199
+ # @return [nil] The change with the given key does not exist.
200
+ #
201
+ def [](key)
202
+ @changes[key]
203
+ end
204
+
205
+ def inspect
206
+ "#<#{self.class} #{@changes&.data&.length || 'No'} changes>"
207
+ end
208
+
209
+ class << self
210
+ attr_reader :events, :converts
211
+ end
212
+
213
+ #
214
+ # Represents the changes in an audit log entry.
215
+ #
216
+ class Changes < DiscordModel
217
+ attr_reader :data
218
+
219
+ #
220
+ # @!visibility private
221
+ #
222
+ def initialize(data)
223
+ @data = data.map { |d| [d[:key].to_sym, d] }.to_h
224
+ @data.each do |k, v|
225
+ define_singleton_method(k) { Change.new(v) }
226
+ end
227
+ end
228
+
229
+ def inspect
230
+ "#<#{self.class} #{@data.length} changes>"
231
+ end
232
+
233
+ #
234
+ # Get keys of changes.
235
+ #
236
+ # @return [Array<Symbol>] The keys of the changes.
237
+ #
238
+ def keys
239
+ @data.keys
240
+ end
241
+
242
+ #
243
+ # Get a change with the given key.
244
+ #
245
+ # @param [Symbol] key The key to get.
246
+ #
247
+ # @return [Discorb::AuditLog::Entry::Change] The change with the given key.
248
+ # @return [nil] The change with the given key does not exist.
249
+ #
250
+ def [](key)
251
+ @data[key.to_sym]
252
+ end
253
+ end
254
+
255
+ #
256
+ # Represents a change in an audit log entry.
257
+ # @note This instance will try to call a method of {#new_value} if the method wasn't defined.
258
+ #
259
+ class Change < DiscordModel
260
+ # @return [Symbol] The key of the change.
261
+ attr_reader :key
262
+ # @return [Object] The old value of the change.
263
+ attr_reader :old_value
264
+ # @return [Object] The new value of the change.
265
+ attr_reader :new_value
266
+
267
+ # @!visibility private
268
+ def initialize(data)
269
+ @key = data[:key].to_sym
270
+ method = case @key.to_s
271
+ when /.*_id$/, 'id'
272
+ ->(v) { Snowflake.new(v) }
273
+ when 'permissions'
274
+ ->(v) { Discorb::Permission.new(v.to_i) }
275
+ else
276
+ ->(v) { v }
277
+ end
278
+ @old_value = data[:old_value].then(&method)
279
+ @new_value = data[:new_value].then(&method)
280
+ end
281
+
282
+ def method_missing(method, ...)
283
+ @new_value.__send__(method, ...)
284
+ end
285
+
286
+ def inspect
287
+ "#<#{self.class} #{@key.inspect} #{@old_value.inspect} -> #{@new_value.inspect}>"
288
+ end
289
+
290
+ def respond_to_missing?(method, include_private = false)
291
+ @new_value.respond_to?(method, include_private)
292
+ end
293
+ end
294
+ end
295
+
296
+ #
297
+ # Represents an integration in an audit log entry.
298
+ #
299
+ class Integration < DiscordModel
300
+ # @return [Discorb::Snowflake] The ID of the integration.
301
+ attr_reader :id
302
+ # @return [Symbol] The type of the integration.
303
+ attr_reader :type
304
+ # @return [String] The name of the integration.
305
+ attr_reader :name
306
+ # @return [Discorb::Integration::Account] The account of the integration.
307
+ attr_reader :account
308
+
309
+ # @!visibility private
310
+ def initialize(data)
311
+ @id = Snowflake.new(data[:id])
312
+ @type = data[:type].to_sym
313
+ @name = data[:name]
314
+ @data = data
315
+ @account = Discorb::Integration::Account.new(@data[:account]) if @data[:account]
316
+ end
317
+
318
+ def inspect
319
+ "#<#{self.class} #{@id}>"
320
+ end
321
+ end
322
+ end
323
+ end