discorb 0.18.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_version.yml +2 -2
  3. data/.rubocop.yml +12 -75
  4. data/Changelog.md +25 -0
  5. data/Gemfile +4 -4
  6. data/README.md +2 -1
  7. data/Rakefile +482 -459
  8. data/Steepfile +8 -6
  9. data/docs/application_command.md +1 -0
  10. data/docs/events.md +2 -2
  11. data/docs/voice_events.md +6 -6
  12. data/lib/discorb/allowed_mentions.rb +68 -72
  13. data/lib/discorb/app_command/command.rb +466 -394
  14. data/lib/discorb/app_command/common.rb +65 -25
  15. data/lib/discorb/app_command/handler.rb +304 -265
  16. data/lib/discorb/app_command.rb +5 -5
  17. data/lib/discorb/application.rb +198 -197
  18. data/lib/discorb/asset.rb +101 -101
  19. data/lib/discorb/attachment.rb +134 -119
  20. data/lib/discorb/audit_logs.rb +412 -385
  21. data/lib/discorb/automod.rb +279 -269
  22. data/lib/discorb/channel/base.rb +107 -108
  23. data/lib/discorb/channel/category.rb +32 -32
  24. data/lib/discorb/channel/container.rb +44 -44
  25. data/lib/discorb/channel/dm.rb +26 -28
  26. data/lib/discorb/channel/guild.rb +311 -246
  27. data/lib/discorb/channel/stage.rb +156 -140
  28. data/lib/discorb/channel/text.rb +430 -336
  29. data/lib/discorb/channel/thread.rb +374 -325
  30. data/lib/discorb/channel/voice.rb +85 -79
  31. data/lib/discorb/channel.rb +5 -5
  32. data/lib/discorb/client.rb +635 -623
  33. data/lib/discorb/color.rb +178 -182
  34. data/lib/discorb/common.rb +168 -164
  35. data/lib/discorb/components/button.rb +107 -106
  36. data/lib/discorb/components/select_menu.rb +157 -145
  37. data/lib/discorb/components/text_input.rb +103 -106
  38. data/lib/discorb/components.rb +68 -66
  39. data/lib/discorb/dictionary.rb +135 -135
  40. data/lib/discorb/embed.rb +404 -398
  41. data/lib/discorb/emoji.rb +309 -302
  42. data/lib/discorb/emoji_table.rb +16099 -8857
  43. data/lib/discorb/error.rb +131 -131
  44. data/lib/discorb/event.rb +360 -314
  45. data/lib/discorb/event_handler.rb +39 -39
  46. data/lib/discorb/exe/about.rb +17 -17
  47. data/lib/discorb/exe/irb.rb +72 -67
  48. data/lib/discorb/exe/new.rb +323 -315
  49. data/lib/discorb/exe/run.rb +69 -68
  50. data/lib/discorb/exe/setup.rb +57 -55
  51. data/lib/discorb/exe/show.rb +12 -12
  52. data/lib/discorb/extend.rb +25 -45
  53. data/lib/discorb/extension.rb +89 -83
  54. data/lib/discorb/flag.rb +126 -128
  55. data/lib/discorb/gateway.rb +984 -794
  56. data/lib/discorb/gateway_events.rb +670 -638
  57. data/lib/discorb/gateway_requests.rb +45 -48
  58. data/lib/discorb/guild.rb +2115 -1626
  59. data/lib/discorb/guild_template.rb +280 -241
  60. data/lib/discorb/http.rb +247 -232
  61. data/lib/discorb/image.rb +42 -42
  62. data/lib/discorb/integration.rb +169 -161
  63. data/lib/discorb/intents.rb +161 -163
  64. data/lib/discorb/interaction/autocomplete.rb +76 -62
  65. data/lib/discorb/interaction/command.rb +279 -224
  66. data/lib/discorb/interaction/components.rb +114 -104
  67. data/lib/discorb/interaction/modal.rb +36 -32
  68. data/lib/discorb/interaction/response.rb +379 -330
  69. data/lib/discorb/interaction/root.rb +271 -118
  70. data/lib/discorb/interaction.rb +5 -5
  71. data/lib/discorb/invite.rb +154 -153
  72. data/lib/discorb/member.rb +344 -311
  73. data/lib/discorb/message.rb +615 -544
  74. data/lib/discorb/message_meta.rb +197 -186
  75. data/lib/discorb/modules.rb +371 -290
  76. data/lib/discorb/permission.rb +305 -289
  77. data/lib/discorb/presence.rb +352 -346
  78. data/lib/discorb/rate_limit.rb +81 -76
  79. data/lib/discorb/reaction.rb +55 -54
  80. data/lib/discorb/role.rb +272 -240
  81. data/lib/discorb/shard.rb +76 -74
  82. data/lib/discorb/sticker.rb +193 -171
  83. data/lib/discorb/user.rb +205 -188
  84. data/lib/discorb/utils/colored_puts.rb +16 -16
  85. data/lib/discorb/utils.rb +12 -16
  86. data/lib/discorb/voice_state.rb +305 -281
  87. data/lib/discorb/webhook.rb +537 -507
  88. data/lib/discorb.rb +62 -56
  89. data/sig/discorb/activity.rbs +1 -0
  90. data/sig/discorb/allowed_mentions.rbs +1 -0
  91. data/sig/discorb/app_command/base.rbs +7 -1
  92. data/sig/discorb/application.rbs +6 -0
  93. data/sig/discorb/asset.rbs +2 -0
  94. data/sig/discorb/attachment.rbs +8 -0
  95. data/sig/discorb/audit_log.rbs +7 -0
  96. data/sig/discorb/automod.rbs +32 -6
  97. data/sig/discorb/avatar.rbs +1 -0
  98. data/sig/discorb/channel/base.rbs +8 -1
  99. data/sig/discorb/channel/category.rbs +1 -0
  100. data/sig/discorb/channel/container.rbs +4 -0
  101. data/sig/discorb/channel/stage.rbs +4 -0
  102. data/sig/discorb/channel/text.rbs +2 -2
  103. data/sig/discorb/channel/thread.rbs +11 -0
  104. data/sig/discorb/channel/voice.rbs +2 -0
  105. data/sig/discorb/client.rbs +21 -20
  106. data/sig/discorb/color.rbs +6 -0
  107. data/sig/discorb/component/base.rbs +1 -0
  108. data/sig/discorb/component/button.rbs +2 -0
  109. data/sig/discorb/component/select_menu.rbs +4 -0
  110. data/sig/discorb/component/text_input.rbs +1 -0
  111. data/sig/discorb/custom_emoji.rbs +5 -1
  112. data/sig/discorb/dictionary.rbs +2 -0
  113. data/sig/discorb/discord_model.rbs +2 -0
  114. data/sig/discorb/embed.rbs +7 -0
  115. data/sig/discorb/emoji.rbs +1 -0
  116. data/sig/discorb/event_handler.rbs +2 -1
  117. data/sig/discorb/extension.rbs +13 -12
  118. data/sig/discorb/flag.rbs +2 -0
  119. data/sig/discorb/gateway.rbs +5 -0
  120. data/sig/discorb/guild.rbs +8 -4
  121. data/sig/discorb/guild_template.rbs +1 -1
  122. data/sig/discorb/http.rbs +4 -1
  123. data/sig/discorb/image.rbs +2 -0
  124. data/sig/discorb/integration.rbs +1 -1
  125. data/sig/discorb/intents.rbs +4 -3
  126. data/sig/discorb/interaction/base.rbs +36 -0
  127. data/sig/discorb/interaction/message_component.rbs +1 -2
  128. data/sig/discorb/interaction/modal.rbs +1 -2
  129. data/sig/discorb/interaction/responder.rbs +49 -49
  130. data/sig/discorb/invite.rbs +1 -1
  131. data/sig/discorb/member.rbs +2 -0
  132. data/sig/discorb/message.rbs +8 -1
  133. data/sig/discorb/messageable.rbs +1 -4
  134. data/sig/discorb/partial_emoji.rbs +3 -0
  135. data/sig/discorb/permissions.rbs +7 -0
  136. data/sig/discorb/presence.rbs +2 -0
  137. data/sig/discorb/reaction.rbs +5 -1
  138. data/sig/discorb/role.rbs +7 -1
  139. data/sig/discorb/scheduled_event.rbs +2 -1
  140. data/sig/discorb/shard.rbs +2 -1
  141. data/sig/discorb/snowflake.rbs +2 -0
  142. data/sig/discorb/stage_instance.rbs +9 -3
  143. data/sig/discorb/sticker.rbs +1 -1
  144. data/sig/discorb/unicode_emoji.rbs +4 -0
  145. data/sig/discorb/user.rbs +24 -20
  146. data/sig/discorb/webhook.rbs +17 -6
  147. data/sig/discorb/welcome_screen.rbs +1 -0
  148. data/sig/override.rbs +2 -0
  149. metadata +3 -3
data/lib/discorb/emoji.rb CHANGED
@@ -1,302 +1,309 @@
1
- # frozen_string_literal: true
2
-
3
- require "uri"
4
-
5
- module Discorb
6
- # Represents a Discord emoji.
7
- # @abstract
8
- class Emoji
9
- def eql?(other)
10
- other.is_a?(self.class) && other.to_uri == to_uri
11
- end
12
-
13
- def ==(other)
14
- eql?(other)
15
- end
16
-
17
- def inspect
18
- "#<#{self.class}>"
19
- end
20
- end
21
-
22
- # Represents a custom emoji in discord.
23
- class CustomEmoji < Emoji
24
- # @return [Discorb::Snowflake] The ID of the emoji.
25
- attr_reader :id
26
- # @return [String] The name of the emoji.
27
- attr_reader :name
28
- # @return [Array<Discorb::Role>] The roles that can use this emoji.
29
- attr_reader :roles
30
- # @return [Discorb::User] The user that created this emoji.
31
- attr_reader :user
32
- # @return [Discorb::Guild] The guild that owns this emoji.
33
- attr_reader :guild
34
- # @return [Boolean] whether the emoji is managed by integration (ex: Twitch).
35
- attr_reader :managed
36
- alias managed? managed
37
- # @return [Boolean] whether the emoji requires colons.
38
- attr_reader :require_colons
39
- alias require_colons? require_colons
40
- # @return [Boolean] whether the emoji is available.
41
- attr_reader :available
42
- alias available? available
43
-
44
- # @!attribute [r] roles?
45
- # @return [Boolean] whether or not this emoji is restricted to certain roles.
46
-
47
- #
48
- # Initialize a new custom emoji.
49
- # @private
50
- #
51
- # @param [Discorb::Client] client The client that owns this emoji.
52
- # @param [Discorb::Guild] guild The guild that owns this emoji.
53
- # @param [Hash] data The data of the emoji.
54
- #
55
- def initialize(client, guild, data)
56
- @client = client
57
- @guild = guild
58
- @data = {}
59
- _set_data(data)
60
- end
61
-
62
- #
63
- # Format the emoji for sending.
64
- #
65
- # @return [String] the formatted emoji.
66
- #
67
- def to_s
68
- "<#{@animated ? "a" : ""}:#{@name}:#{id}>"
69
- end
70
-
71
- #
72
- # Format the emoji for URI.
73
- #
74
- # @return [String] the formatted emoji.
75
- #
76
- def to_uri
77
- "#{@name}:#{@id}"
78
- end
79
-
80
- def roles?
81
- @roles != []
82
- end
83
-
84
- alias role? roles?
85
-
86
- def inspect
87
- "#<#{self.class} id=#{@id} :#{@name}:>"
88
- end
89
-
90
- #
91
- # Edit the emoji.
92
- # @async
93
- # @macro edit
94
- #
95
- # @param [String] name The new name of the emoji.
96
- # @param [Array<Discorb::Role>] roles The new roles that can use this emoji.
97
- # @param [String] reason The reason for editing the emoji.
98
- #
99
- # @return [Async::Task<self>] The edited emoji.
100
- #
101
- def edit(name: Discorb::Unset, roles: Discorb::Unset, reason: nil)
102
- Async do
103
- payload = {}
104
- payload[:name] = name if name != Discorb::Unset
105
- payload[:roles] = roles.map { |r| Discorb::Utils.try(r, :id) } if roles != Discorb::Unset
106
- @client.http.request(
107
- Route.new("/guilds/#{@guild.id}/emojis/#{@id}", "//guilds/:guild_id/emojis/:emoji_id",
108
- :patch), payload, audit_log_reason: reason,
109
- )
110
- self
111
- end
112
- end
113
-
114
- alias modify edit
115
-
116
- #
117
- # Delete the emoji.
118
- # @async
119
- #
120
- # @param [String] reason The reason for deleting the emoji.
121
- #
122
- # @return [Async::Task<self>] The deleted emoji.
123
- #
124
- def delete!(reason: nil)
125
- Async do
126
- @client.http.request(
127
- Route.new("/guilds/#{@guild.id}/emojis/#{@id}", "//guilds/:guild_id/emojis/:emoji_id",
128
- :delete), {}, audit_log_reason: reason,
129
- ).wait
130
- @available = false
131
- self
132
- end
133
- end
134
-
135
- alias destroy! delete!
136
-
137
- #
138
- # Converts the object to a hash.
139
- # @private
140
- #
141
- # @return [Hash] The hash represents the object.
142
- #
143
- def to_hash
144
- {
145
- name: @name,
146
- id: @id,
147
- animated: @animated,
148
- }
149
- end
150
-
151
- private
152
-
153
- def _set_data(data)
154
- @id = Snowflake.new(data[:id])
155
- @name = data[:name]
156
- @roles = data[:role] ? data[:role].map { |r| Role.new(@client, guild, r) } : []
157
- @user = User.new(@client, data[:user]) if data[:user]
158
- @require_colons = data[:require_colons]
159
- @managed = data[:managed]
160
- @animated = data[:animated]
161
- @available = data[:available]
162
- @guild.emojis[@id] = self unless data[:no_cache]
163
- @data.update(data)
164
- end
165
- end
166
-
167
- #
168
- # Represents a partial custom emoji in discord.
169
- #
170
- class PartialEmoji < DiscordModel
171
- # @return [Discorb::Snowflake] The ID of the emoji.
172
- attr_reader :id
173
- # @return [String] The name of the emoji.
174
- attr_reader :name
175
- # @return [Boolean] Whether the emoji is deleted.
176
- attr_reader :deleted
177
- alias deleted? deleted
178
-
179
- #
180
- # Initialize a new partial custom emoji.
181
- # @private
182
- #
183
- # @param [Hash] data The data of the emoji.
184
- #
185
- def initialize(data)
186
- @id = Snowflake.new(data[:id])
187
- @name = data[:name]
188
- @animated = data[:animated]
189
- @deleted = @name.nil?
190
- end
191
-
192
- #
193
- # Format the emoji for URI.
194
- #
195
- # @return [String] the formatted emoji.
196
- #
197
- def to_uri
198
- "#{@name}:#{@id}"
199
- end
200
-
201
- def inspect
202
- "#<#{self.class} id=#{@id} :#{@name}:>"
203
- end
204
-
205
- #
206
- # Format the emoji for sending.
207
- #
208
- # @return [String] the formatted emoji.
209
- #
210
- def to_s
211
- "<#{@animated ? "a" : ""}:#{@name}:#{@id}>"
212
- end
213
- end
214
-
215
- #
216
- # Represents a unicode emoji (default emoji) in discord.
217
- #
218
- class UnicodeEmoji < Emoji
219
- # @return [String] The name of the emoji. (e.g. :grinning:)
220
- attr_reader :name
221
- # @return [String] The unicode value of the emoji. (e.g. U+1F600)
222
- attr_reader :value
223
- # @return [Integer] The skin tone of the emoji.
224
- attr_reader :skin_tone
225
-
226
- #
227
- # Initialize a new unicode emoji.
228
- #
229
- # @param [String] name The name of the emoji.
230
- # @param [Integer] tone The skin tone of the emoji.
231
- #
232
- def initialize(name, tone: 0)
233
- if EmojiTable::DISCORD_TO_UNICODE.key?(name)
234
- @name = name
235
- @value = EmojiTable::DISCORD_TO_UNICODE[name]
236
- elsif EmojiTable::UNICODE_TO_DISCORD.key?(name)
237
- @name = EmojiTable::UNICODE_TO_DISCORD[name][0]
238
- @value = name
239
- elsif EmojiTable::SKIN_TONES.any? { |t| name.include?(t) }
240
- name2 = name.dup
241
- EmojiTable::SKIN_TONES.each.with_index do |t, i|
242
- next unless name2.include?(t)
243
-
244
- @skin_tone = i
245
- name2.sub!(t, "")
246
- break
247
- end
248
- raise ArgumentError, "Invalid skin tone: #{tone}" unless @skin_tone
249
-
250
- @name = EmojiTable::UNICODE_TO_DISCORD[name2].first
251
- @value = name
252
- else
253
- raise ArgumentError, "No such emoji: #{name}"
254
- end
255
- if tone.positive?
256
- unless @value = EmojiTable::DISCORD_TO_UNICODE["#{name}_tone#{tone}"]
257
- raise ArgumentError,
258
- "Invalid skin tone for emoji: #{name}"
259
- end
260
-
261
- @name = "#{name}_tone#{tone}"
262
- @skin_tone = tone
263
- end
264
- end
265
-
266
- # @return [String] The unicode string of the emoji.
267
- def to_s
268
- @value
269
- end
270
-
271
- #
272
- # Format the emoji for URI.
273
- #
274
- # @return [String] the formatted emoji.
275
- #
276
- def to_uri
277
- URI.encode_www_form_component(@value)
278
- end
279
-
280
- def inspect
281
- "#<#{self.class} :#{@name}:>"
282
- end
283
-
284
- #
285
- # Converts the object to a hash.
286
- # @private
287
- #
288
- # @return [Hash] The hash represents the object.
289
- #
290
- def to_hash
291
- {
292
- name: @value,
293
- id: nil,
294
- animated: false,
295
- }
296
- end
297
-
298
- class << self
299
- alias [] new
300
- end
301
- end
302
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Discorb
6
+ # Represents a Discord emoji.
7
+ # @abstract
8
+ class Emoji
9
+ def eql?(other)
10
+ other.is_a?(self.class) && other.to_uri == to_uri
11
+ end
12
+
13
+ def ==(other)
14
+ eql?(other)
15
+ end
16
+
17
+ def inspect
18
+ "#<#{self.class}>"
19
+ end
20
+ end
21
+
22
+ # Represents a custom emoji in discord.
23
+ class CustomEmoji < Emoji
24
+ # @return [Discorb::Snowflake] The ID of the emoji.
25
+ attr_reader :id
26
+ # @return [String] The name of the emoji.
27
+ attr_reader :name
28
+ # @return [Array<Discorb::Role>] The roles that can use this emoji.
29
+ attr_reader :roles
30
+ # @return [Discorb::User] The user that created this emoji.
31
+ attr_reader :user
32
+ # @return [Discorb::Guild] The guild that owns this emoji.
33
+ attr_reader :guild
34
+ # @return [Boolean] whether the emoji is managed by integration (ex: Twitch).
35
+ attr_reader :managed
36
+ alias managed? managed
37
+ # @return [Boolean] whether the emoji requires colons.
38
+ attr_reader :require_colons
39
+ alias require_colons? require_colons
40
+ # @return [Boolean] whether the emoji is available.
41
+ attr_reader :available
42
+ alias available? available
43
+
44
+ # @!attribute [r] roles?
45
+ # @return [Boolean] whether or not this emoji is restricted to certain roles.
46
+
47
+ #
48
+ # Initialize a new custom emoji.
49
+ # @private
50
+ #
51
+ # @param [Discorb::Client] client The client that owns this emoji.
52
+ # @param [Discorb::Guild] guild The guild that owns this emoji.
53
+ # @param [Hash] data The data of the emoji.
54
+ #
55
+ def initialize(client, guild, data)
56
+ @client = client
57
+ @guild = guild
58
+ @data = {}
59
+ _set_data(data)
60
+ end
61
+
62
+ #
63
+ # Format the emoji for sending.
64
+ #
65
+ # @return [String] the formatted emoji.
66
+ #
67
+ def to_s
68
+ "<#{@animated ? "a" : ""}:#{@name}:#{id}>"
69
+ end
70
+
71
+ #
72
+ # Format the emoji for URI.
73
+ #
74
+ # @return [String] the formatted emoji.
75
+ #
76
+ def to_uri
77
+ "#{@name}:#{@id}"
78
+ end
79
+
80
+ def roles?
81
+ @roles != []
82
+ end
83
+
84
+ alias role? roles?
85
+
86
+ def inspect
87
+ "#<#{self.class} id=#{@id} :#{@name}:>"
88
+ end
89
+
90
+ #
91
+ # Edit the emoji.
92
+ # @async
93
+ # @macro edit
94
+ #
95
+ # @param [String] name The new name of the emoji.
96
+ # @param [Array<Discorb::Role>] roles The new roles that can use this emoji.
97
+ # @param [String] reason The reason for editing the emoji.
98
+ #
99
+ # @return [Async::Task<self>] The edited emoji.
100
+ #
101
+ def edit(name: Discorb::Unset, roles: Discorb::Unset, reason: nil)
102
+ Async do
103
+ payload = {}
104
+ payload[:name] = name if name != Discorb::Unset
105
+ payload[:roles] = roles.map do |r|
106
+ Discorb::Utils.try(r, :id)
107
+ end if roles != Discorb::Unset
108
+ @client.http.request(
109
+ Route.new(
110
+ "/guilds/#{@guild.id}/emojis/#{@id}",
111
+ "//guilds/:guild_id/emojis/:emoji_id",
112
+ :patch
113
+ ),
114
+ payload,
115
+ audit_log_reason: reason
116
+ )
117
+ self
118
+ end
119
+ end
120
+
121
+ alias modify edit
122
+
123
+ #
124
+ # Delete the emoji.
125
+ # @async
126
+ #
127
+ # @param [String] reason The reason for deleting the emoji.
128
+ #
129
+ # @return [Async::Task<self>] The deleted emoji.
130
+ #
131
+ def delete(reason: nil)
132
+ Async do
133
+ @client
134
+ .http
135
+ .request(
136
+ Route.new(
137
+ "/guilds/#{@guild.id}/emojis/#{@id}",
138
+ "//guilds/:guild_id/emojis/:emoji_id",
139
+ :delete
140
+ ),
141
+ {},
142
+ audit_log_reason: reason
143
+ )
144
+ .wait
145
+ @available = false
146
+ self
147
+ end
148
+ end
149
+
150
+ alias destroy delete
151
+
152
+ #
153
+ # Converts the object to a hash.
154
+ # @private
155
+ #
156
+ # @return [Hash] The hash represents the object.
157
+ #
158
+ def to_hash
159
+ { name: @name, id: @id, animated: @animated }
160
+ end
161
+
162
+ private
163
+
164
+ def _set_data(data)
165
+ @id = Snowflake.new(data[:id])
166
+ @name = data[:name]
167
+ @roles =
168
+ data[:role] ? data[:role].map { |r| Role.new(@client, guild, r) } : []
169
+ @user = User.new(@client, data[:user]) if data[:user]
170
+ @require_colons = data[:require_colons]
171
+ @managed = data[:managed]
172
+ @animated = data[:animated]
173
+ @available = data[:available]
174
+ @guild.emojis[@id] = self unless data[:no_cache]
175
+ @data.update(data)
176
+ end
177
+ end
178
+
179
+ #
180
+ # Represents a partial custom emoji in discord.
181
+ #
182
+ class PartialEmoji < DiscordModel
183
+ # @return [Discorb::Snowflake] The ID of the emoji.
184
+ attr_reader :id
185
+ # @return [String] The name of the emoji.
186
+ attr_reader :name
187
+ # @return [Boolean] Whether the emoji is deleted.
188
+ attr_reader :deleted
189
+ alias deleted? deleted
190
+
191
+ #
192
+ # Initialize a new partial custom emoji.
193
+ # @private
194
+ #
195
+ # @param [Hash] data The data of the emoji.
196
+ #
197
+ def initialize(data)
198
+ @id = Snowflake.new(data[:id])
199
+ @name = data[:name]
200
+ @animated = data[:animated]
201
+ @deleted = @name.nil?
202
+ end
203
+
204
+ #
205
+ # Format the emoji for URI.
206
+ #
207
+ # @return [String] the formatted emoji.
208
+ #
209
+ def to_uri
210
+ "#{@name}:#{@id}"
211
+ end
212
+
213
+ def inspect
214
+ "#<#{self.class} id=#{@id} :#{@name}:>"
215
+ end
216
+
217
+ #
218
+ # Format the emoji for sending.
219
+ #
220
+ # @return [String] the formatted emoji.
221
+ #
222
+ def to_s
223
+ "<#{@animated ? "a" : ""}:#{@name}:#{@id}>"
224
+ end
225
+ end
226
+
227
+ #
228
+ # Represents a unicode emoji (default emoji) in discord.
229
+ #
230
+ class UnicodeEmoji < Emoji
231
+ # @return [String] The name of the emoji. (e.g. :grinning:)
232
+ attr_reader :name
233
+ # @return [String] The unicode value of the emoji. (e.g. U+1F600)
234
+ attr_reader :value
235
+ # @return [Integer] The skin tone of the emoji.
236
+ attr_reader :skin_tone
237
+
238
+ #
239
+ # Initialize a new unicode emoji.
240
+ #
241
+ # @param [String] name The name of the emoji.
242
+ # @param [Integer] tone The skin tone of the emoji.
243
+ #
244
+ def initialize(name, tone: 0)
245
+ if EmojiTable::DISCORD_TO_UNICODE.key?(name)
246
+ @name = name
247
+ @value = EmojiTable::DISCORD_TO_UNICODE[name]
248
+ elsif EmojiTable::UNICODE_TO_DISCORD.key?(name)
249
+ @name = EmojiTable::UNICODE_TO_DISCORD[name][0]
250
+ @value = name
251
+ elsif EmojiTable::SKIN_TONES.any? { |t| name.include?(t) }
252
+ name2 = name.dup
253
+ EmojiTable::SKIN_TONES.each.with_index do |t, i|
254
+ next unless name2.include?(t)
255
+
256
+ @skin_tone = i
257
+ name2.sub!(t, "")
258
+ break
259
+ end
260
+ raise ArgumentError, "Invalid skin tone: #{tone}" unless @skin_tone
261
+
262
+ @name = EmojiTable::UNICODE_TO_DISCORD[name2].first
263
+ @value = name
264
+ else
265
+ raise ArgumentError, "No such emoji: #{name}"
266
+ end
267
+ if tone.positive?
268
+ unless @value = EmojiTable::DISCORD_TO_UNICODE["#{name}_tone#{tone}"]
269
+ raise ArgumentError, "Invalid skin tone for emoji: #{name}"
270
+ end
271
+
272
+ @name = "#{name}_tone#{tone}"
273
+ @skin_tone = tone
274
+ end
275
+ end
276
+
277
+ # @return [String] The unicode string of the emoji.
278
+ def to_s
279
+ @value
280
+ end
281
+
282
+ #
283
+ # Format the emoji for URI.
284
+ #
285
+ # @return [String] the formatted emoji.
286
+ #
287
+ def to_uri
288
+ URI.encode_www_form_component(@value)
289
+ end
290
+
291
+ def inspect
292
+ "#<#{self.class} :#{@name}:>"
293
+ end
294
+
295
+ #
296
+ # Converts the object to a hash.
297
+ # @private
298
+ #
299
+ # @return [Hash] The hash represents the object.
300
+ #
301
+ def to_hash
302
+ { name: @value, id: nil, animated: false }
303
+ end
304
+
305
+ class << self
306
+ alias [] new
307
+ end
308
+ end
309
+ end