discorb 0.19.0 → 0.20.0

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 (88) 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 +10 -0
  5. data/Rakefile +482 -454
  6. data/lib/discorb/allowed_mentions.rb +68 -72
  7. data/lib/discorb/app_command/command.rb +466 -398
  8. data/lib/discorb/app_command/common.rb +65 -25
  9. data/lib/discorb/app_command/handler.rb +304 -266
  10. data/lib/discorb/app_command.rb +5 -5
  11. data/lib/discorb/application.rb +198 -197
  12. data/lib/discorb/asset.rb +101 -101
  13. data/lib/discorb/attachment.rb +134 -119
  14. data/lib/discorb/audit_logs.rb +412 -385
  15. data/lib/discorb/automod.rb +279 -269
  16. data/lib/discorb/channel/base.rb +107 -108
  17. data/lib/discorb/channel/category.rb +32 -32
  18. data/lib/discorb/channel/container.rb +44 -44
  19. data/lib/discorb/channel/dm.rb +26 -28
  20. data/lib/discorb/channel/guild.rb +311 -246
  21. data/lib/discorb/channel/stage.rb +156 -140
  22. data/lib/discorb/channel/text.rb +430 -336
  23. data/lib/discorb/channel/thread.rb +374 -325
  24. data/lib/discorb/channel/voice.rb +85 -79
  25. data/lib/discorb/channel.rb +5 -5
  26. data/lib/discorb/client.rb +635 -621
  27. data/lib/discorb/color.rb +178 -182
  28. data/lib/discorb/common.rb +168 -164
  29. data/lib/discorb/components/button.rb +107 -106
  30. data/lib/discorb/components/select_menu.rb +157 -145
  31. data/lib/discorb/components/text_input.rb +103 -106
  32. data/lib/discorb/components.rb +68 -66
  33. data/lib/discorb/dictionary.rb +135 -135
  34. data/lib/discorb/embed.rb +404 -398
  35. data/lib/discorb/emoji.rb +309 -302
  36. data/lib/discorb/emoji_table.rb +16099 -8857
  37. data/lib/discorb/error.rb +131 -131
  38. data/lib/discorb/event.rb +360 -314
  39. data/lib/discorb/event_handler.rb +39 -39
  40. data/lib/discorb/exe/about.rb +17 -17
  41. data/lib/discorb/exe/irb.rb +72 -67
  42. data/lib/discorb/exe/new.rb +323 -315
  43. data/lib/discorb/exe/run.rb +69 -68
  44. data/lib/discorb/exe/setup.rb +57 -55
  45. data/lib/discorb/exe/show.rb +12 -12
  46. data/lib/discorb/extend.rb +25 -45
  47. data/lib/discorb/extension.rb +89 -83
  48. data/lib/discorb/flag.rb +126 -128
  49. data/lib/discorb/gateway.rb +984 -804
  50. data/lib/discorb/gateway_events.rb +670 -638
  51. data/lib/discorb/gateway_requests.rb +45 -48
  52. data/lib/discorb/guild.rb +2115 -1626
  53. data/lib/discorb/guild_template.rb +280 -241
  54. data/lib/discorb/http.rb +247 -232
  55. data/lib/discorb/image.rb +42 -42
  56. data/lib/discorb/integration.rb +169 -161
  57. data/lib/discorb/intents.rb +161 -163
  58. data/lib/discorb/interaction/autocomplete.rb +76 -62
  59. data/lib/discorb/interaction/command.rb +279 -224
  60. data/lib/discorb/interaction/components.rb +114 -104
  61. data/lib/discorb/interaction/modal.rb +36 -32
  62. data/lib/discorb/interaction/response.rb +379 -336
  63. data/lib/discorb/interaction/root.rb +271 -257
  64. data/lib/discorb/interaction.rb +5 -5
  65. data/lib/discorb/invite.rb +154 -153
  66. data/lib/discorb/member.rb +344 -311
  67. data/lib/discorb/message.rb +615 -544
  68. data/lib/discorb/message_meta.rb +197 -186
  69. data/lib/discorb/modules.rb +371 -290
  70. data/lib/discorb/permission.rb +305 -291
  71. data/lib/discorb/presence.rb +352 -346
  72. data/lib/discorb/rate_limit.rb +81 -76
  73. data/lib/discorb/reaction.rb +55 -54
  74. data/lib/discorb/role.rb +272 -240
  75. data/lib/discorb/shard.rb +76 -74
  76. data/lib/discorb/sticker.rb +193 -171
  77. data/lib/discorb/user.rb +205 -188
  78. data/lib/discorb/utils/colored_puts.rb +16 -16
  79. data/lib/discorb/utils.rb +12 -16
  80. data/lib/discorb/voice_state.rb +305 -281
  81. data/lib/discorb/webhook.rb +537 -507
  82. data/lib/discorb.rb +62 -56
  83. data/sig/discorb/application.rbs +2 -0
  84. data/sig/discorb/automod.rbs +10 -1
  85. data/sig/discorb/guild.rbs +2 -0
  86. data/sig/discorb/message.rbs +2 -0
  87. data/sig/discorb/user.rbs +22 -20
  88. metadata +2 -2
data/Rakefile CHANGED
@@ -1,454 +1,482 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require_relative "lib/discorb/utils/colored_puts"
5
- require "parallel_tests"
6
- task default: %i[]
7
-
8
- # @private
9
- def current_version
10
- require_relative "lib/discorb/common"
11
- tag = `git tag --points-at HEAD`.force_encoding("utf-8").strip
12
- if tag.empty?
13
- "main"
14
- else
15
- Discorb::VERSION
16
- end
17
- end
18
-
19
- desc "Run spec with parallel_rspec"
20
- task :spec do
21
- sh "parallel_rspec spec/*.spec.rb spec/**/*.spec.rb"
22
- end
23
-
24
- desc "Build emoji_table.rb"
25
- task :emoji_table do
26
- require_relative "lib/discorb"
27
-
28
- iputs "Building emoji_table.rb"
29
- res = {}
30
- Discorb::EmojiTable::DISCORD_TO_UNICODE.each do |discord, unicode|
31
- res[unicode] ||= []
32
- res[unicode] << discord
33
- end
34
-
35
- res_text = +""
36
- res.each do |unicode, discord|
37
- res_text << %(#{unicode.unpack("C*").pack("C*").inspect} => %w[#{discord.join(" ")}],\n)
38
- end
39
-
40
- table_script = File.read("lib/discorb/emoji_table.rb")
41
-
42
- table_script.gsub!(/(?<=UNICODE_TO_DISCORD = {\n)[\s\S]+(?=}\.freeze)/, res_text)
43
-
44
- File.open("lib/discorb/emoji_table.rb", "w") do |f|
45
- f.print(table_script)
46
- end
47
- `rufo lib/discorb/emoji_table.rb`
48
- sputs "Successfully made emoji_table.rb"
49
- end
50
-
51
- desc "Format files"
52
- task :format do
53
- Dir.glob("**/*.rb").each do |file|
54
- next if file.start_with?("vendor")
55
-
56
- iputs "Formatting #{file}"
57
- `rufo ./#{file}`
58
- content = ""
59
- File.open(file, "rb") do |f|
60
- content = f.read
61
- end
62
- content.gsub!("\r\n", "\n")
63
- File.open(file, "wb") do |f|
64
- f.print(content)
65
- end
66
- end
67
- end
68
-
69
- desc "Generate document and replace"
70
- namespace :document do
71
- version = current_version
72
- desc "Just generate document"
73
- task :yard do
74
- sh "bundle exec yardoc -o doc/#{version} --locale #{ENV.fetch("rake_locale", nil) or "en"}"
75
- end
76
-
77
- desc "Replace files"
78
- namespace :replace do
79
- require "fileutils"
80
-
81
- desc "Replace CSS"
82
- task :css do
83
- iputs "Replacing css"
84
- Dir.glob("template-replace/files/**/*.*")
85
- .map { |f| f.delete_prefix("template-replace/files") }.each do |file|
86
- FileUtils.cp("template-replace/files" + file, "doc/#{version}/#{file}")
87
- end
88
- sputs "Successfully replaced css"
89
- end
90
-
91
- desc "Replace HTML"
92
- task :html do
93
- require_relative "template-replace/scripts/sidebar"
94
- require_relative "template-replace/scripts/version"
95
- require_relative "template-replace/scripts/index"
96
- require_relative "template-replace/scripts/yard_replace"
97
- require_relative "template-replace/scripts/favicon"
98
- require_relative "template-replace/scripts/arrow"
99
- iputs "Resetting changes"
100
- Dir.glob("doc/#{version}/**/*.html") do |f|
101
- next if (m = f.match(/[0-9]+\.[0-9]+\.[0-9]+(-[a-z]+)?/)) && m[0] != version
102
-
103
- content = File.read(f)
104
- content.gsub!(/<!--od-->[\s\S]*<!--eod-->/, "")
105
- File.write(f, content)
106
- end
107
- iputs "Adding version tab"
108
- %w[file_list class_list method_list].each do |f|
109
- replace_sidebar("doc/#{version}/#{f}.html")
110
- end
111
-
112
- iputs "Building version tab"
113
- build_version_sidebar("doc/#{version}", version)
114
- iputs "Replacing _index.html"
115
- replace_index("doc/#{version}", version)
116
- iputs "Replacing YARD credits"
117
- yard_replace("doc/#{version}", version)
118
- iputs "Adding favicon"
119
- add_favicon("doc/#{version}")
120
- iputs "Replacing arrow"
121
- replace_arrow("doc/#{version}")
122
- iputs "Successfully replaced htmls"
123
- end
124
-
125
- desc "Replace EOL"
126
- task :eol do
127
- iputs "Replacing CRLF with LF"
128
- Dir.glob("doc/**/*.*") do |file|
129
- next unless File.file?(file)
130
- next unless %w[html css js].include? file.split(".").last
131
-
132
- content = ""
133
- File.open(file, "rb") do |f|
134
- content = f.read
135
- end
136
- content.gsub!("\r\n", "\n")
137
- File.open(file, "wb") do |f|
138
- f.print(content)
139
- end
140
- end
141
- sputs "Successfully replaced CRLF with LF"
142
- end
143
-
144
- desc "change locale of current document"
145
- task :locale do
146
- next if ENV["rake_locale"].nil?
147
-
148
- require_relative "template-replace/scripts/locale_#{ENV.fetch("rake_locale", nil)}.rb"
149
- replace_locale("doc/main")
150
- end
151
- end
152
- task replace: %i[replace:css replace:html replace:eol]
153
-
154
- desc "Build all versions"
155
- task :build_all do
156
- require "fileutils"
157
-
158
- iputs "Building all versions"
159
- begin
160
- FileUtils.rm_rf("doc")
161
- rescue StandardError
162
- nil
163
- end
164
- FileUtils.cp_r("./template-replace/.", "./tmp-template-replace")
165
- Rake::Task["document:yard"].execute
166
- Rake::Task["document:replace:html"].execute
167
- Rake::Task["document:replace:css"].execute
168
- Rake::Task["document:replace:eol"].execute
169
- Rake::Task["document:replace:locale"].execute
170
- tags = `git tag`.force_encoding("utf-8").split("\n").sort_by { |t| t[1..].split(".").map(&:to_i) }
171
- tags.each do |tag|
172
- sh "git checkout #{tag} -f"
173
- iputs "Building #{tag}"
174
- FileUtils.cp_r("./tmp-template-replace/.", "./template-replace")
175
- version = tag.delete_prefix("v")
176
- Rake::Task["document:yard"].execute
177
- Rake::Task["document:replace:html"].execute
178
- Rake::Task["document:replace:css"].execute
179
- Rake::Task["document:replace:eol"].execute
180
- Rake::Task["document:replace:locale"].execute
181
- FileUtils.cp_r("./doc/.", "./tmp-doc")
182
- FileUtils.rm_rf("doc")
183
- end
184
- sh "git switch main -f"
185
- FileUtils.cp_r("./tmp-doc/.", "./doc")
186
- FileUtils.cp_r("./doc/#{tags.last.delete_prefix("v")}/.", "./doc")
187
- sputs "Successfully built all versions"
188
- rescue StandardError => e
189
- sh "git switch main -f"
190
- raise e
191
- end
192
-
193
- desc "Push to discorb-lib/discorb-lib.github.io"
194
- task :push do
195
- iputs "Pushing documents"
196
- Dir.chdir("doc") do
197
- sh "git init"
198
- sh "git remote add origin git@github.com:discorb-lib/discorb-lib.github.io"
199
- sh "git add ."
200
- sh "git commit -m \"Update: Update document\""
201
- sh "git push -f"
202
- end
203
- sputs "Successfully pushed documents"
204
- end
205
-
206
- namespace :locale do
207
- desc "Generate Japanese document"
208
- task :ja do
209
- require "crowdin-api"
210
- require "zip"
211
- crowdin = Crowdin::Client.new do |config|
212
- config.api_token = ENV.fetch("CROWDIN_PERSONAL_TOKEN", nil)
213
- config.project_id = ENV["CROWDIN_PROJECT_ID"].to_i
214
- end
215
- build = crowdin.build_project_translation["data"]["id"]
216
- crowdin.download_project_translations("./tmp.zip", build)
217
-
218
- Zip::File.open("tmp.zip") do |zip|
219
- zip.each do |entry|
220
- zip.extract(entry, entry.name) { true }
221
- end
222
- end
223
- ENV["rake_locale"] = "ja"
224
- Rake::Task["document:yard"].execute
225
- Rake::Task["document:replace"].execute
226
- end
227
-
228
- desc "Generate English document"
229
- task :en do
230
- Rake::Task["document"].execute("locale:en")
231
- end
232
- end
233
- end
234
-
235
- desc "Generate rbs file"
236
- namespace :rbs do
237
- desc "Generate event signature"
238
- task :event do
239
- require "syntax_tree/rbs"
240
- client_rbs = File.read("sig/discorb/client.rbs")
241
- extension_rbs = File.read("sig/discorb/extension.rbs")
242
- event_document = File.read("./docs/events.md")
243
- voice_event_document = File.read("./docs/voice_events.md")
244
- event_reference = event_document.split("## Event reference")[1]
245
- event_reference += voice_event_document.split("# Voice Events")[1]
246
- event_reference.gsub!(/^### (.*)$/, "")
247
- events = []
248
- event_reference.split("#### `")[1..].each do |event|
249
- header, content = event.split("`\n", 2)
250
- name = header.split("(")[0]
251
- description = content.split("| Parameter", 2)[0].strip
252
- parameters = if content.include?("| Parameter")
253
- content.scan(/\| `(.*?)` +\| (.*?) +\| (.*?) +\|/)
254
- else
255
- []
256
- end
257
- events << {
258
- name: name,
259
- description: description,
260
- parameters: parameters.map { |p| { name: p[0], type: p[1], description: p[2] } },
261
- }
262
- end
263
- event_sig = +""
264
- event_lock_sig = +""
265
- extension_sig = +""
266
- events.each do |event|
267
- args = []
268
- event[:parameters].each do |parameter|
269
- args << {
270
- name: parameter[:name],
271
- type: if parameter[:type].start_with?("?")
272
- parameter[:type][1..]
273
- else
274
- parameter[:type]
275
- end.tr("{}`", "").tr("<>", "[]").gsub(", ", " | ").then do |t|
276
- if event[:name] == "event_receive"
277
- case t
278
- when "Hash"
279
- next "Discorb::json"
280
- end
281
- end
282
- t
283
- end,
284
- }
285
- end
286
- sig = args.map { |a| "#{a[:type]} #{a[:name]}" }.join(", ")
287
- tuple_sig = args.map { |a| a[:type] }.join(", ")
288
- tuple_sig = "[" + tuple_sig + "]" if args.length > 1
289
- tuple_sig = "void" if args.length.zero?
290
- event_sig << <<~RBS
291
- | (:#{event[:name]} event_name, ?id: Symbol?, **untyped metadata) { (#{sig}) -> void } -> Discorb::EventHandler
292
- RBS
293
- event_lock_sig << <<~RBS
294
- | (:#{event[:name]} event, ?Integer? timeout) { (#{sig}) -> boolish } -> Async::Task[#{tuple_sig}]
295
- RBS
296
- extension_sig << <<~RBS
297
- | (:#{event[:name]} event_name, ?id: Symbol?, **untyped metadata) { (#{sig}) -> void } -> void
298
- RBS
299
- end
300
- event_sig << <<~RBS
301
- | (Symbol event_name, ?id: Symbol?, **untyped metadata) { (*untyped) -> void } -> Discorb::EventHandler
302
- RBS
303
- event_lock_sig << <<~RBS
304
- | (Symbol event, ?Integer? timeout) { (*untyped) -> boolish } -> Async::Task[untyped]
305
- RBS
306
- extension_sig << <<~RBS
307
- | (Symbol event_name, ?id: Symbol?, **untyped metadata) { (*untyped) -> void } -> void
308
- RBS
309
- event_sig.sub!("| ", " ").rstrip!
310
- event_lock_sig.sub!("| ", " ").rstrip!
311
- extension_sig.sub!("| ", " ").rstrip!
312
- res = client_rbs.gsub!(/(?<=def on:\n)(?:[\s\S]*?)(?=\n\n)/, event_sig)
313
- raise "Failed to generate Client#on" unless res
314
-
315
- res = client_rbs.gsub!(/(?<=def once:\n)(?:[\s\S]*?)(?=\n\n)/, event_sig)
316
- raise "Failed to generate Client#once" unless res
317
-
318
- res = client_rbs.gsub!(/(?<=def event_lock:\n)(?:[\s\S]*?)(?=\n\n)/, event_lock_sig)
319
- raise "Failed to generate Client#event_lock" unless res
320
-
321
- res = extension_rbs.gsub!(/(?<=def event:\n)(?:[\s\S]*?)(?=\n\n)/, extension_sig)
322
- raise "Failed to generate Extension.event" unless res
323
-
324
- res = extension_rbs.gsub!(/(?<=def once_event:\n)(?:[\s\S]*?)(?=\n\n)/, extension_sig)
325
- raise "Failed to generate Extension.once_event" unless res
326
-
327
- File.write("sig/discorb/client.rbs", SyntaxTree::RBS.format(client_rbs), mode: "wb")
328
- File.write("sig/discorb/extension.rbs", SyntaxTree::RBS.format(extension_rbs), mode: "wb")
329
- end
330
-
331
- desc "Generate rbs file using sord"
332
- task :sord do
333
- require "open3"
334
- # rubocop: disable Layout/LineLength
335
- type_errors = {
336
- "SORD_ERROR_SymbolSymbolSymbolInteger" => "{ r: Integer, g: Integer, b: Integer}",
337
- "SORD_ERROR_DiscorbRoleDiscorbMemberDiscorbPermissionOverwrite" => "Hash[Discorb::Role | Discorb::Member, Discorb::PermissionOverwrite]",
338
- "SORD_ERROR_DiscorbRoleDiscorbMemberPermissionOverwrite" => "Hash[Discorb::Role | Discorb::Member, Discorb::PermissionOverwrite]",
339
- "SORD_ERROR_f | SORD_ERROR_F | SORD_ERROR_d | SORD_ERROR_D | SORD_ERROR_t | SORD_ERROR_T | SORD_ERROR_R" => '"f" | "F" | "d" | "D" | "t" | "T" | "R"',
340
- "SORD_ERROR_dark | SORD_ERROR_light" => '"dark" | "light"',
341
- "SORD_ERROR_SymbolStringSymbolboolSymbolObject" => "String | Integer | Float",
342
- }
343
- # rubocop: enable Layout/LineLength
344
- regenerate = ARGV.include?("--regenerate") || ARGV.include?("-r")
345
-
346
- sh "sord gen sig/discorb.rbs --keep-original-comments --no-sord-comments" +
347
- (regenerate ? " --regenerate" : " --no-regenerate")
348
- base = File.read("sig/discorb.rbs")
349
- base.gsub!(/\n +def _set_data: \(.+\) -> untyped\n\n/, "\n")
350
- # base.gsub!(/( )?( *)# @private.+?(?:\n\n(?=\1\2#)|(?=\n\2end))/sm, "")
351
- base.gsub!(/untyped ([a-z_]*id)/, "_ToS \\1")
352
- # #region rbs dictionary
353
- base.gsub!(/ class Dictionary.+?end\n/ms, <<-RBS)
354
- class Dictionary[K, V]
355
- #
356
- # Initialize a new Dictionary.
357
- #
358
- # @param [Hash] hash A hash of items to add to the dictionary.
359
- # @param [Integer] limit The maximum number of items in the dictionary.
360
- # @param [false, Proc] sort Whether to sort the items in the dictionary.
361
- def initialize: (?::Hash[untyped, untyped] hash, ?limit: Integer?, ?sort: (bool | Proc)) -> void
362
-
363
- #
364
- # Registers a new item in the dictionary.
365
- #
366
- # @param [#to_s] id The ID of the item.
367
- # @param [Object] body The item to register.
368
- #
369
- # @return [self] The dictionary.
370
- def register: (_ToS id, Object body) -> self
371
-
372
- #
373
- # Merges another dictionary into this one.
374
- #
375
- # @param [Discorb::Dictionary] other The dictionary to merge.
376
- def merge: (Discorb::Dictionary other) -> untyped
377
-
378
- #
379
- # Removes an item from the dictionary.
380
- #
381
- # @param [#to_s] id The ID of the item to remove.
382
- def remove: (_ToS id) -> untyped
383
-
384
- #
385
- # Get an item from the dictionary.
386
- #
387
- # @param [#to_s] id The ID of the item.
388
- # @return [Object] The item.
389
- # @return [nil] if the item was not found.
390
- #
391
- # @overload get(index)
392
- # @param [Integer] index The index of the item.
393
- #
394
- # @return [Object] The item.
395
- # @return [nil] if the item is not found.
396
- def get: (K id) -> V?
397
-
398
- #
399
- # Returns the values of the dictionary.
400
- #
401
- # @return [Array] The values of the dictionary.
402
- def values: () -> ::Array[V]
403
-
404
- #
405
- # Checks if the dictionary has an ID.
406
- #
407
- # @param [#to_s] id The ID to check.
408
- #
409
- # @return [Boolean] `true` if the dictionary has the ID, `false` otherwise.
410
- def has?: (_ToS id) -> bool
411
-
412
- #
413
- # Send a message to the array of values.
414
- def method_missing: (untyped name) -> untyped
415
-
416
- def respond_to_missing?: (untyped name, untyped args, untyped kwargs) -> bool
417
-
418
- def inspect: () -> String
419
-
420
- # @return [Integer] The maximum number of items in the dictionary.
421
- attr_accessor limit: Integer
422
- end
423
- RBS
424
- # #endregion
425
- type_errors.each do |error, type|
426
- base.gsub!(error, type)
427
- end
428
- base.gsub!("end\n\n\nend", "end\n")
429
- base.gsub!(/ +$/m, "")
430
- File.write("sig/discorb.rbs", base)
431
- end
432
-
433
- desc "Lint rbs with stree"
434
- task :lint do
435
- sh "stree check --plugins=rbs sig/**/*.rbs"
436
- end
437
-
438
- desc "Autofix rbs with stree"
439
- task "lint:fix" do
440
- sh "stree write --plugins=rbs sig/**/*.rbs"
441
- end
442
- end
443
-
444
- task document: %i[document:yard document:replace]
445
-
446
- desc "Lint code with rubocop"
447
- task :lint do
448
- sh "rubocop lib spec Rakefile"
449
- end
450
-
451
- desc "Autofix code with rubocop"
452
- task "lint:fix" do
453
- sh "rubocop lib spec Rakefile -A"
454
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require_relative "lib/discorb/utils/colored_puts"
5
+ task default: %i[]
6
+
7
+ # @private
8
+ def current_version
9
+ require_relative "lib/discorb/common"
10
+ tag = `git tag --points-at HEAD`.force_encoding("utf-8").strip
11
+ tag.empty? ? "main" : Discorb::VERSION
12
+ end
13
+
14
+ desc "Run spec with parallel_rspec"
15
+ task :spec do
16
+ sh "parallel_rspec spec/*.spec.rb spec/**/*.spec.rb"
17
+ end
18
+
19
+ desc "Build emoji_table.rb"
20
+ task :emoji_table do
21
+ require_relative "lib/discorb"
22
+
23
+ iputs "Building emoji_table.rb"
24
+ res = {}
25
+ Discorb::EmojiTable::DISCORD_TO_UNICODE.each do |discord, unicode|
26
+ res[unicode] ||= []
27
+ res[unicode] << discord
28
+ end
29
+
30
+ res_text = +""
31
+ res.each do |unicode, discord|
32
+ res_text << %(#{unicode.unpack("C*").pack("C*").inspect} => %w[#{discord.join(" ")}],\n)
33
+ end
34
+
35
+ table_script = File.read("lib/discorb/emoji_table.rb")
36
+
37
+ table_script.gsub!(
38
+ /(?<=UNICODE_TO_DISCORD = {\n)[\s\S]+(?=}\.freeze)/,
39
+ res_text
40
+ )
41
+
42
+ File.open("lib/discorb/emoji_table.rb", "w") { |f| f.print(table_script) }
43
+ `rufo lib/discorb/emoji_table.rb`
44
+ sputs "Successfully made emoji_table.rb"
45
+ end
46
+
47
+ desc "Format files"
48
+ task :format do
49
+ Dir
50
+ .glob("**/*.rb")
51
+ .each do |file|
52
+ next if file.start_with?("vendor")
53
+
54
+ iputs "Formatting #{file}"
55
+ `rufo ./#{file}`
56
+ content = ""
57
+ File.open(file, "rb") { |f| content = f.read }
58
+ content.gsub!("\r\n", "\n")
59
+ File.open(file, "wb") { |f| f.print(content) }
60
+ end
61
+ end
62
+
63
+ desc "Generate document and replace"
64
+ namespace :document do
65
+ version = current_version
66
+ desc "Just generate document"
67
+ task :yard do
68
+ sh "yard -o doc/#{version} --locale #{ENV.fetch("rake_locale", nil) or "en"}"
69
+ end
70
+
71
+ desc "Replace files"
72
+ namespace :replace do
73
+ require "fileutils"
74
+
75
+ desc "Replace CSS"
76
+ task :css do
77
+ iputs "Replacing css"
78
+ Dir
79
+ .glob("template-replace/files/**/*.*")
80
+ .map { |f| f.delete_prefix("template-replace/files") }
81
+ .each do |file|
82
+ FileUtils.cp(
83
+ "template-replace/files#{file}",
84
+ "doc/#{version}/#{file}"
85
+ )
86
+ end
87
+ sputs "Successfully replaced css"
88
+ end
89
+
90
+ desc "Replace HTML"
91
+ task :html do
92
+ require_relative "template-replace/scripts/sidebar"
93
+ require_relative "template-replace/scripts/version"
94
+ require_relative "template-replace/scripts/index"
95
+ require_relative "template-replace/scripts/yard_replace"
96
+ require_relative "template-replace/scripts/favicon"
97
+ require_relative "template-replace/scripts/arrow"
98
+ iputs "Resetting changes"
99
+ Dir.glob("doc/#{version}/**/*.html") do |f|
100
+ if (m = f.match(/[0-9]+\.[0-9]+\.[0-9]+(-[a-z]+)?/)) && m[0] != version
101
+ next
102
+ end
103
+
104
+ content = File.read(f)
105
+ content.gsub!(/<!--od-->[\s\S]*<!--eod-->/, "")
106
+ File.write(f, content)
107
+ end
108
+ iputs "Adding version tab"
109
+ %w[file_list class_list method_list].each do |f|
110
+ replace_sidebar("doc/#{version}/#{f}.html")
111
+ end
112
+
113
+ iputs "Building version tab"
114
+ build_version_sidebar("doc/#{version}", version)
115
+ iputs "Replacing _index.html"
116
+ replace_index("doc/#{version}", version)
117
+ iputs "Replacing YARD credits"
118
+ yard_replace("doc/#{version}", version)
119
+ iputs "Adding favicon"
120
+ add_favicon("doc/#{version}")
121
+ iputs "Replacing arrow"
122
+ replace_arrow("doc/#{version}")
123
+ iputs "Successfully replaced htmls"
124
+ end
125
+
126
+ desc "Replace EOL"
127
+ task :eol do
128
+ iputs "Replacing CRLF with LF"
129
+ Dir.glob("doc/**/*.*") do |file|
130
+ next unless File.file?(file)
131
+ next unless %w[html css js].include? file.split(".").last
132
+
133
+ content = ""
134
+ File.open(file, "rb") { |f| content = f.read }
135
+ content.gsub!("\r\n", "\n")
136
+ File.open(file, "wb") { |f| f.print(content) }
137
+ end
138
+ sputs "Successfully replaced CRLF with LF"
139
+ end
140
+
141
+ desc "change locale of current document"
142
+ task :locale do
143
+ next if ENV["rake_locale"].nil?
144
+
145
+ require_relative "template-replace/scripts/locale_#{ENV.fetch("rake_locale", nil)}.rb"
146
+ replace_locale("doc/main")
147
+ end
148
+ end
149
+ task replace: %i[replace:css replace:html replace:eol]
150
+
151
+ desc "Build all versions"
152
+ task :build_all do
153
+ require "fileutils"
154
+
155
+ iputs "Building all versions"
156
+ begin
157
+ FileUtils.rm_rf("doc")
158
+ rescue StandardError
159
+ nil
160
+ end
161
+ FileUtils.cp_r("./template-replace/.", "./tmp-template-replace")
162
+ Rake::Task["document:yard"].execute
163
+ Rake::Task["document:replace:html"].execute
164
+ Rake::Task["document:replace:css"].execute
165
+ Rake::Task["document:replace:eol"].execute
166
+ Rake::Task["document:replace:locale"].execute
167
+ tags =
168
+ `git tag`.force_encoding("utf-8")
169
+ .split("\n")
170
+ .sort_by { |t| t[1..].split(".").map(&:to_i) }
171
+ tags.each do |tag|
172
+ sh "git checkout #{tag} -f"
173
+ iputs "Building #{tag}"
174
+ FileUtils.cp_r("./tmp-template-replace/.", "./template-replace")
175
+ version = tag.delete_prefix("v")
176
+ Rake::Task["document:yard"].execute
177
+ Rake::Task["document:replace:html"].execute
178
+ Rake::Task["document:replace:css"].execute
179
+ Rake::Task["document:replace:eol"].execute
180
+ Rake::Task["document:replace:locale"].execute
181
+ FileUtils.cp_r("./doc/.", "./tmp-doc")
182
+ FileUtils.rm_rf("doc")
183
+ end
184
+ sh "git switch main -f"
185
+ FileUtils.cp_r("./tmp-doc/.", "./doc")
186
+ FileUtils.cp_r("./doc/#{tags.last.delete_prefix("v")}/.", "./doc")
187
+ sputs "Successfully built all versions"
188
+ rescue StandardError => e
189
+ sh "git switch main -f"
190
+ raise e
191
+ end
192
+
193
+ desc "Push to discorb-lib/discorb-lib.github.io"
194
+ task :push do
195
+ iputs "Pushing documents"
196
+ Dir.chdir("doc") do
197
+ sh "git init"
198
+ sh "git remote add origin git@github.com:discorb-lib/discorb-lib.github.io"
199
+ sh "git add ."
200
+ sh "git commit -m \"Update: Update document\""
201
+ sh "git push -f"
202
+ end
203
+ sputs "Successfully pushed documents"
204
+ end
205
+
206
+ namespace :locale do
207
+ desc "Generate Japanese document"
208
+ task :ja do
209
+ require "crowdin-api"
210
+ require "zip"
211
+ crowdin =
212
+ Crowdin::Client.new do |config|
213
+ config.api_token = ENV.fetch("CROWDIN_PERSONAL_TOKEN", nil)
214
+ config.project_id = ENV["CROWDIN_PROJECT_ID"].to_i
215
+ end
216
+ build = crowdin.build_project_translation["data"]["id"]
217
+ crowdin.download_project_translations("./tmp.zip", build)
218
+
219
+ Zip::File.open("tmp.zip") do |zip|
220
+ zip.each { |entry| zip.extract(entry, entry.name) { true } }
221
+ end
222
+ ENV["rake_locale"] = "ja"
223
+ Rake::Task["document:yard"].execute
224
+ Rake::Task["document:replace"].execute
225
+ end
226
+
227
+ desc "Generate English document"
228
+ task :en do
229
+ Rake::Task["document"].execute("locale:en")
230
+ end
231
+ end
232
+ end
233
+
234
+ desc "Generate rbs file"
235
+ namespace :rbs do
236
+ desc "Generate event signature"
237
+ task :event do
238
+ require "syntax_tree/rbs"
239
+ client_rbs = File.read("sig/discorb/client.rbs")
240
+ extension_rbs = File.read("sig/discorb/extension.rbs")
241
+ event_document = File.read("./docs/events.md")
242
+ voice_event_document = File.read("./docs/voice_events.md")
243
+ event_reference = event_document.split("## Event reference")[1]
244
+ event_reference += voice_event_document.split("# Voice Events")[1]
245
+ event_reference.gsub!(/^### (.*)$/, "")
246
+ events = []
247
+ event_reference.split("#### `")[1..].each do |event|
248
+ header, content = event.split("`\n", 2)
249
+ name = header.split("(")[0]
250
+ description = content.split("| Parameter", 2)[0].strip
251
+ parameters =
252
+ if content.include?("| Parameter")
253
+ content.scan(/\| `(.*?)` +\| (.*?) +\| (.*?) +\|/)
254
+ else
255
+ []
256
+ end
257
+ events << {
258
+ name: name,
259
+ description: description,
260
+ parameters:
261
+ parameters.map { |p| { name: p[0], type: p[1], description: p[2] } }
262
+ }
263
+ end
264
+ event_sig = +""
265
+ event_lock_sig = +""
266
+ extension_sig = +""
267
+ events.each do |event|
268
+ args = []
269
+ event[:parameters].each do |parameter|
270
+ args << {
271
+ name: parameter[:name],
272
+ type:
273
+ if parameter[:type].start_with?("?")
274
+ parameter[:type][1..]
275
+ else
276
+ parameter[:type]
277
+ end.tr("{}`", "")
278
+ .tr("<>", "[]")
279
+ .gsub(", ", " | ")
280
+ .then do |t|
281
+ if event[:name] == "event_receive"
282
+ case t
283
+ when "Hash"
284
+ next "Discorb::json"
285
+ end
286
+ end
287
+ t
288
+ end
289
+ }
290
+ end
291
+ sig = args.map { |a| "#{a[:type]} #{a[:name]}" }.join(", ")
292
+ tuple_sig = args.map { |a| a[:type] }.join(", ")
293
+ tuple_sig = "[#{tuple_sig}]" if args.length > 1
294
+ tuple_sig = "void" if args.length.zero?
295
+ event_sig << <<~RBS
296
+ | (:#{event[:name]} event_name, ?id: Symbol?, **untyped metadata) { (#{sig}) -> void } -> Discorb::EventHandler
297
+ RBS
298
+ event_lock_sig << <<~RBS
299
+ | (:#{event[:name]} event, ?Integer? timeout) { (#{sig}) -> boolish } -> Async::Task[#{tuple_sig}]
300
+ RBS
301
+ extension_sig << <<~RBS
302
+ | (:#{event[:name]} event_name, ?id: Symbol?, **untyped metadata) { (#{sig}) -> void } -> void
303
+ RBS
304
+ end
305
+ event_sig << <<~RBS
306
+ | (Symbol event_name, ?id: Symbol?, **untyped metadata) { (*untyped) -> void } -> Discorb::EventHandler
307
+ RBS
308
+ event_lock_sig << <<~RBS
309
+ | (Symbol event, ?Integer? timeout) { (*untyped) -> boolish } -> Async::Task[untyped]
310
+ RBS
311
+ extension_sig << <<~RBS
312
+ | (Symbol event_name, ?id: Symbol?, **untyped metadata) { (*untyped) -> void } -> void
313
+ RBS
314
+ event_sig.sub!("| ", " ").rstrip!
315
+ event_lock_sig.sub!("| ", " ").rstrip!
316
+ extension_sig.sub!("| ", " ").rstrip!
317
+ res = client_rbs.gsub!(/(?<=def on:\n)(?:[\s\S]*?)(?=\n\n)/, event_sig)
318
+ raise "Failed to generate Client#on" unless res
319
+
320
+ res = client_rbs.gsub!(/(?<=def once:\n)(?:[\s\S]*?)(?=\n\n)/, event_sig)
321
+ raise "Failed to generate Client#once" unless res
322
+
323
+ res =
324
+ client_rbs.gsub!(
325
+ /(?<=def event_lock:\n)(?:[\s\S]*?)(?=\n\n)/,
326
+ event_lock_sig
327
+ )
328
+ raise "Failed to generate Client#event_lock" unless res
329
+
330
+ res =
331
+ extension_rbs.gsub!(
332
+ /(?<=def event:\n)(?:[\s\S]*?)(?=\n\n)/,
333
+ extension_sig
334
+ )
335
+ raise "Failed to generate Extension.event" unless res
336
+
337
+ res =
338
+ extension_rbs.gsub!(
339
+ /(?<=def once_event:\n)(?:[\s\S]*?)(?=\n\n)/,
340
+ extension_sig
341
+ )
342
+ raise "Failed to generate Extension.once_event" unless res
343
+
344
+ File.write(
345
+ "sig/discorb/client.rbs",
346
+ SyntaxTree::RBS.format(client_rbs),
347
+ mode: "wb"
348
+ )
349
+ File.write(
350
+ "sig/discorb/extension.rbs",
351
+ SyntaxTree::RBS.format(extension_rbs),
352
+ mode: "wb"
353
+ )
354
+ end
355
+
356
+ desc "Generate rbs file using sord"
357
+ task :sord do
358
+ require "open3"
359
+ type_errors = {
360
+ "SORD_ERROR_SymbolSymbolSymbolInteger" =>
361
+ "{ r: Integer, g: Integer, b: Integer}",
362
+ "SORD_ERROR_DiscorbRoleDiscorbMemberDiscorbPermissionOverwrite" =>
363
+ "Hash[Discorb::Role | Discorb::Member, Discorb::PermissionOverwrite]",
364
+ "SORD_ERROR_DiscorbRoleDiscorbMemberPermissionOverwrite" =>
365
+ "Hash[Discorb::Role | Discorb::Member, Discorb::PermissionOverwrite]",
366
+ "SORD_ERROR_f | SORD_ERROR_F | SORD_ERROR_d | SORD_ERROR_D | SORD_ERROR_t | SORD_ERROR_T | SORD_ERROR_R" =>
367
+ '"f" | "F" | "d" | "D" | "t" | "T" | "R"',
368
+ "SORD_ERROR_dark | SORD_ERROR_light" => '"dark" | "light"',
369
+ "SORD_ERROR_SymbolStringSymbolboolSymbolObject" =>
370
+ "String | Integer | Float"
371
+ }
372
+ regenerate = ARGV.include?("--regenerate") || ARGV.include?("-r")
373
+
374
+ sh(
375
+ "sord gen sig/discorb.rbs --keep-original-comments " \
376
+ "--no-sord-comments#{regenerate ? " --regenerate" : " --no-regenerate"}"
377
+ )
378
+ base = File.read("sig/discorb.rbs")
379
+ base.gsub!(/\n +def _set_data: \(.+\) -> untyped\n\n/, "\n")
380
+ # base.gsub!(/( )?( *)# @private.+?(?:\n\n(?=\1\2#)|(?=\n\2end))/sm, "")
381
+ base.gsub!(/untyped ([a-z_]*id)/, "_ToS \\1")
382
+ # #region rbs dictionary
383
+ base.gsub!(/ class Dictionary.+?end\n/ms, <<-RBS)
384
+ class Dictionary[K, V]
385
+ #
386
+ # Initialize a new Dictionary.
387
+ #
388
+ # @param [Hash] hash A hash of items to add to the dictionary.
389
+ # @param [Integer] limit The maximum number of items in the dictionary.
390
+ # @param [false, Proc] sort Whether to sort the items in the dictionary.
391
+ def initialize: (?::Hash[untyped, untyped] hash, ?limit: Integer?, ?sort: (bool | Proc)) -> void
392
+
393
+ #
394
+ # Registers a new item in the dictionary.
395
+ #
396
+ # @param [#to_s] id The ID of the item.
397
+ # @param [Object] body The item to register.
398
+ #
399
+ # @return [self] The dictionary.
400
+ def register: (_ToS id, Object body) -> self
401
+
402
+ #
403
+ # Merges another dictionary into this one.
404
+ #
405
+ # @param [Discorb::Dictionary] other The dictionary to merge.
406
+ def merge: (Discorb::Dictionary other) -> untyped
407
+
408
+ #
409
+ # Removes an item from the dictionary.
410
+ #
411
+ # @param [#to_s] id The ID of the item to remove.
412
+ def remove: (_ToS id) -> untyped
413
+
414
+ #
415
+ # Get an item from the dictionary.
416
+ #
417
+ # @param [#to_s] id The ID of the item.
418
+ # @return [Object] The item.
419
+ # @return [nil] if the item was not found.
420
+ #
421
+ # @overload get(index)
422
+ # @param [Integer] index The index of the item.
423
+ #
424
+ # @return [Object] The item.
425
+ # @return [nil] if the item is not found.
426
+ def get: (K id) -> V?
427
+
428
+ #
429
+ # Returns the values of the dictionary.
430
+ #
431
+ # @return [Array] The values of the dictionary.
432
+ def values: () -> ::Array[V]
433
+
434
+ #
435
+ # Checks if the dictionary has an ID.
436
+ #
437
+ # @param [#to_s] id The ID to check.
438
+ #
439
+ # @return [Boolean] `true` if the dictionary has the ID, `false` otherwise.
440
+ def has?: (_ToS id) -> bool
441
+
442
+ #
443
+ # Send a message to the array of values.
444
+ def method_missing: (untyped name) -> untyped
445
+
446
+ def respond_to_missing?: (untyped name, untyped args, untyped kwargs) -> bool
447
+
448
+ def inspect: () -> String
449
+
450
+ # @return [Integer] The maximum number of items in the dictionary.
451
+ attr_accessor limit: Integer
452
+ end
453
+ RBS
454
+ # #endregion
455
+ type_errors.each { |error, type| base.gsub!(error, type) }
456
+ base.gsub!("end\n\n\nend", "end\n")
457
+ base.gsub!(/ +$/m, "")
458
+ File.write("sig/discorb.rbs", base)
459
+ end
460
+
461
+ desc "Lint rbs with stree"
462
+ task :lint do
463
+ sh "stree check --plugins=rbs sig/**/*.rbs"
464
+ end
465
+
466
+ desc "Autofix rbs with stree"
467
+ task "lint:fix" do
468
+ sh "stree write --plugins=rbs sig/**/*.rbs"
469
+ end
470
+ end
471
+
472
+ task document: %i[document:yard document:replace]
473
+
474
+ desc "Lint code with rubocop"
475
+ task :lint do
476
+ sh "rubocop lib spec Rakefile"
477
+ end
478
+
479
+ desc "Autofix code with rubocop"
480
+ task "lint:fix" do
481
+ sh "rubocop lib spec Rakefile -A"
482
+ end