discorb 0.0.1

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