discorb 0.6.1 → 0.7.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d2ef47227e1e5895bdcaf6a67641d22319909c0f6a461d72ab35be1e0c9a42b
4
- data.tar.gz: 688a952b571421e8c43ca53b10f9404f6ba2abf8b9071222c35d3a10e34c5b7e
3
+ metadata.gz: c4197e97af48fc47c1062d0327ccc048cb8317701be673a2bce035b108f7cade
4
+ data.tar.gz: 7c48b69868636ca4722e3ec2aee50bb6148174c1cfdcf0b31a2d227110aefa76
5
5
  SHA512:
6
- metadata.gz: 9fd5eb78a1acda90e3c673a8745a2a9954ff8b8817c38210c5c609e6a85b16e4074b59bf8ae7bcc7725f7f45f22dfd785fb5edd321e9f61994bb071e4aa25a43
7
- data.tar.gz: 4bee75498af33d4716e033f51103382d8931c079495d27234cf07cf5e5b288891b40fb7e00902d3c1d7150249d0c820701d9962130890005bea5378e46af5ac8
6
+ metadata.gz: 7215a8dc3b0c3502f1948838aac8c08cc0ae0ac4c7c874dcc695c48fc5ead628f36718f08e7e2854aa46f191e9f0c851ff23a6f96aa82edaa3c7d7c912ff490b
7
+ data.tar.gz: 7ade9dcd2e56efb2513928a021d0f557d827a230b02f2c23ee6691cc9decc919f2e51b19e9e95fab13f535e8cc112cc8f3a29ac36e3a2144651a625e60ea0e25
data/.gitignore CHANGED
@@ -45,9 +45,9 @@ build-iPhoneSimulator/
45
45
 
46
46
  # for a library or gem, you might want to ignore these files since the code is
47
47
  # intended to run in multiple environments; otherwise, check them in:
48
- # Gemfile.lock
49
- # .ruby-version
50
- # .ruby-gemset
48
+ Gemfile.lock
49
+ .ruby-version
50
+ .ruby-gemset
51
51
 
52
52
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
53
  .rvmrc
data/.yardopts CHANGED
@@ -4,6 +4,7 @@
4
4
  --tag flags:"Flags"
5
5
  --verbose
6
6
  --asset docs/assets:assets
7
+ --asset assets:assets
7
8
  -
8
9
  docs/**/*.md
9
10
  Changelog.md
data/Changelog.md CHANGED
@@ -150,3 +150,44 @@
150
150
 
151
151
  - Change: Rename `Event#discriminator` to `Event#metadata`
152
152
  - Add: Add `:override` to `Client#on`
153
+
154
+ ## 0.7.0
155
+
156
+ - Add: Add `error` event
157
+ - Fix: Fix some issues with client without guild intent
158
+ - Add: Add alias for `#fired_by`
159
+ - Change!: Change block usage of `ApplicationCommand::Handler#group`
160
+
161
+ ```ruby
162
+ # before
163
+ client.slash_group do
164
+ slash "help", "Help" do |interaction|
165
+ # ...
166
+ end
167
+ end
168
+
169
+ # after
170
+ client.slash_group do |group|
171
+ group.slash "help", "Help" do |interaction|
172
+ # ...
173
+ end
174
+ end
175
+
176
+ ```
177
+
178
+ ## 0.7.1
179
+
180
+ - Fix: Fix error of responding to interaction
181
+
182
+ ## 0.7.2
183
+
184
+ - Add: Add `Member#owner?`
185
+ - Fix: Fix `Member#permissions`
186
+ - Add: Add `Member#guild_permissions` as alias of `Member#permissions`
187
+ - Add: Add default role to `Member#roles`
188
+ - Fix: Fix error in `Integration#_set_data`
189
+ - Change: Reverse `Member#roles`
190
+
191
+ ## 0.7.3
192
+
193
+ - Add: Improve `discorb init`
data/README.md CHANGED
@@ -1,9 +1,12 @@
1
- # discorb
2
- [![Document](https://img.shields.io/badge/Document-discord--lib.github.io-blue.svg)](https://discorb-lib.github.io/)
3
- [![Gem](https://img.shields.io/gem/dt/discorb?logo=rubygems&logoColor=fff)](https://rubygems.org/gems/discorb)
4
- [![Gem](https://img.shields.io/gem/v/discorb?logo=rubygems&logoColor=fff)](https://rubygems.org/gems/discorb)
5
- [![Discord](https://img.shields.io/discord/863581274916913193?logo=discord&logoColor=fff&color=5865f2&label=Discord)](https://discord.gg/hCP6zq8Vpj)
6
- [![GitHub](https://img.shields.io/github/stars/discorb-lib/discorb?color=24292e&label=Stars&logo=GitHub&logoColor=fff)](https://github.com/discorb-lib/discorb)
1
+ ![discorb](./assets/banner.svg)
2
+
3
+ <div align="center"><a href="https://discorb-lib.github.io/"><img src="https://img.shields.io/badge/Document-discorb--lib.github.io-blue.svg" alt="Document"></a>
4
+ <a href="https://rubygems.org/gems/discorb"><img src="https://img.shields.io/gem/dt/discorb?logo=rubygems&logoColor=fff" alt="Gem"></a>
5
+ <a href="https://rubygems.org/gems/discorb"><img src="https://img.shields.io/gem/v/discorb?logo=rubygems&logoColor=fff" alt="Gem"></a>
6
+ <a href="https://discord.gg/hCP6zq8Vpj"><img src="https://img.shields.io/discord/863581274916913193?logo=discord&logoColor=fff&color=5865f2&label=Discord" alt="Discord"></a>
7
+ <a href="https://github.com/discorb-lib/discorb"><img src="https://img.shields.io/github/stars/discorb-lib/discorb?color=24292e&label=Stars&logo=GitHub&logoColor=fff" alt="GitHub"></a></div>
8
+
9
+ ----
7
10
 
8
11
  discorb is a Discord API wrapper for Ruby.
9
12
 
data/assets/banner.svg ADDED
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
5
+ y="0px" width="1080px" height="150px" viewBox="0 0 1080 150" enable-background="new 0 0 1080 150" xml:space="preserve">
6
+ <g>
7
+ <defs>
8
+ <rect id="SVGID_1_" x="283.667" y="-12.667" width="343.333" height="201.333"/>
9
+ </defs>
10
+ <clipPath id="SVGID_2_">
11
+ <use xlink:href="#SVGID_1_" overflow="visible"/>
12
+ </clipPath>
13
+ <g clip-path="url(#SVGID_2_)">
14
+ <g>
15
+ <g>
16
+ <path fill="#2E3338" d="M370.533,119.061c-13.503,0-21.565-10.312-21.565-27.582c0-18.543,9.872-30.525,25.149-30.525
17
+ c5.186,0,10.446,0.915,14.432,2.509l3.429,1.372V31.79l6.393-1.006v86.997h-4.456l-1.936-12.146l-3.522,4.208
18
+ C383.265,116.045,377.402,119.061,370.533,119.061z M374.501,65.554c-9.191,0-19.013,6.676-19.013,25.413
19
+ c0,13.96,6.559,22.98,16.708,22.98c7.18,0,13.308-3.736,19.286-11.758l0.495-0.665V69.983l-1.358-0.697
20
+ C385.253,66.53,381.035,65.554,374.501,65.554z"/>
21
+ </g>
22
+ <g>
23
+ <path fill="#2E3338" d="M419.624,117.78V61.721h6.393v56.059H419.624z M422.884,44.433c-2.645,0-4.796-2.094-4.796-4.668
24
+ c0-2.6,2.196-4.796,4.796-4.796c2.574,0,4.668,2.152,4.668,4.796C427.552,42.338,425.458,44.433,422.884,44.433z"/>
25
+ </g>
26
+ <g>
27
+ <path fill="#2E3338" d="M463.332,119.061c-7.015,0-14.662-2.282-19.529-4.647l0.809-5.23c4.905,2.794,11.627,5.405,19.616,5.405
28
+ c9.34,0,14.917-3.949,14.917-10.564c0-8.187-6.482-10.382-16.372-12.797c-13.937-3.485-18.19-7.314-18.19-16.388
29
+ c0-8.611,7.638-14.397,19.005-14.397c6.173,0,11.985,1.055,17.305,3.139l-0.902,5.412c-5.417-2.532-11.33-3.95-16.659-3.95
30
+ c-12.06,0-12.997,7.302-12.997,9.54c0,6.302,5.57,8.979,14.559,11.256c15.329,3.897,20.003,7.967,20.003,17.418
31
+ C484.897,113.3,477.037,119.061,463.332,119.061z"/>
32
+ </g>
33
+ <g>
34
+ <path fill="#2E3338" d="M523.746,119.061c-15.986,0-25.917-11.206-25.917-29.246c0-17.843,10.273-29.373,26.173-29.373
35
+ c6.897,0,12.696,1.453,17.263,4.322l-0.821,5.493c-5.086-3.282-10.441-4.83-16.57-4.83c-12.043,0-19.525,9.296-19.525,24.262
36
+ c0,15.271,7.777,24.389,20.805,24.389c6.137,0,11.114-1.451,15.996-4.757l0.746,4.59
37
+ C536.669,117.509,531.15,119.061,523.746,119.061z"/>
38
+ </g>
39
+ <g>
40
+ <path fill="#2E3338" d="M580.834,119.061c-15.511,0-25.533-11.479-25.533-29.246c0-17.843,10.022-29.373,25.533-29.373
41
+ c15.744,0,25.917,11.53,25.917,29.373C606.751,107.581,596.578,119.061,580.834,119.061z M580.834,65.042
42
+ c-11.729,0-19.014,9.492-19.014,24.772c0,15.049,7.463,24.773,19.014,24.773c11.964,0,19.396-9.492,19.396-24.773
43
+ C600.23,74.766,592.617,65.042,580.834,65.042z"/>
44
+ </g>
45
+ <g>
46
+ <path d="M623.652,117.78V61.721h4.444l2.615,16.91l3.563-5.661c3.16-5.019,8.634-11.016,17.176-12.309l0.981,5.953
47
+ c-9.186,1.447-17.664,7.67-22.117,16.437l-0.271,0.533v34.196H623.652z"/>
48
+ </g>
49
+ <g>
50
+ <path d="M688.224,118.549c-8.27,0-14.267-1.167-21.31-3.208V31.79l6.393-1.006V72.56l4.295-4.43
51
+ c5.017-5.173,10.417-7.688,16.51-7.688c13.302,0,21.565,10.569,21.565,27.582C715.677,107.423,705.671,118.549,688.224,118.549z
52
+ M692.447,65.554c-6.539,0-12.794,3.675-18.593,10.923l-0.548,0.685v33.856l1.64,0.601c3.981,1.461,7.108,2.202,13.148,2.202
53
+ c9.608,0,21.062-4.387,21.062-25.285C709.156,74.575,702.598,65.554,692.447,65.554z"/>
54
+ </g>
55
+ </g>
56
+ </g>
57
+ </g>
58
+ <g>
59
+ <defs>
60
+ <rect id="SVGID_3_" x="610.334" y="8" width="268" height="246"/>
61
+ </defs>
62
+ <clipPath id="SVGID_4_">
63
+ <use xlink:href="#SVGID_3_" overflow="visible"/>
64
+ </clipPath>
65
+ <g clip-path="url(#SVGID_4_)">
66
+ <g>
67
+ <path fill="#2E3338" d="M391.782,120.28l-1.408-8.833c-4.608,5.505-10.88,10.113-19.841,10.113
68
+ c-13.185,0-24.065-9.601-24.065-30.082c0-22.272,12.8-33.025,27.649-33.025c6.017,0,11.521,1.152,15.361,2.688v-31.49
69
+ l11.393-1.792v92.42H391.782z M389.478,71.51c-4.736-2.432-8.448-3.456-14.977-3.456c-9.601,0-16.513,7.809-16.513,22.913
70
+ c0,13.441,6.016,20.48,14.208,20.48c7.041,0,12.417-4.224,17.281-10.752V71.51z"/>
71
+ <path fill="#2E3338" d="M422.884,46.933c-3.968,0-7.296-3.2-7.296-7.168s3.328-7.296,7.296-7.296s7.168,3.328,7.168,7.296
72
+ S426.852,46.933,422.884,46.933z M417.124,120.28V59.221h11.393v61.059H417.124z"/>
73
+ <path fill="#2E3338" d="M463.332,121.561c-8.064,0-17.025-2.816-22.273-5.76l1.664-10.754c5.76,3.969,13.185,7.041,21.505,7.041
74
+ c7.808,0,12.417-2.944,12.417-8.064c0-5.633-3.456-7.68-14.465-10.368c-14.336-3.585-20.097-7.937-20.097-18.817
75
+ c0-9.729,8.192-16.897,21.505-16.897c7.552,0,14.336,1.536,20.097,4.096l-1.792,10.752c-5.376-3.072-12.161-5.248-18.561-5.248
76
+ c-6.913,0-10.497,2.688-10.497,7.04c0,4.096,3.072,6.4,12.672,8.832c15.105,3.841,21.889,8.193,21.889,19.842
77
+ C487.397,114.393,479.077,121.561,463.332,121.561z"/>
78
+ <path fill="#2E3338" d="M523.746,121.561c-16.385,0-28.417-11.393-28.417-31.746c0-20.865,12.8-31.873,28.673-31.873
79
+ c8.96,0,15.36,2.304,19.968,5.632l-1.664,11.136c-5.632-4.608-11.392-6.784-18.432-6.784c-9.985,0-17.025,7.552-17.025,21.762
80
+ c0,14.848,7.552,21.889,18.305,21.889c6.145,0,11.521-1.408,17.793-6.785l1.664,10.241
81
+ C538.339,119.768,531.938,121.561,523.746,121.561z"/>
82
+ <path fill="#2E3338" d="M580.834,121.561c-16.258,0-28.033-11.648-28.033-31.746c0-20.097,11.775-31.873,28.033-31.873
83
+ c16.385,0,28.417,11.776,28.417,31.873C609.251,109.912,597.219,121.561,580.834,121.561z M580.834,67.542
84
+ c-11.009,0-16.514,9.472-16.514,22.272c0,12.545,5.761,22.273,16.514,22.273c11.264,0,16.896-9.473,16.896-22.273
85
+ C597.73,77.271,591.842,67.542,580.834,67.542z"/>
86
+ <path fill="#CC342D" d="M632.545,84.183v36.098h-11.393V59.221h9.088l1.92,12.417c4.353-6.913,11.393-13.185,21.377-13.697
87
+ l1.793,10.88C645.217,69.334,636.641,76.118,632.545,84.183z"/>
88
+ <path fill="#CC342D" d="M688.224,121.049c-9.217,0-15.745-1.408-23.81-3.841V29.652l11.393-1.792v38.53
89
+ c4.096-4.224,9.984-8.448,18.305-8.448c13.185,0,24.065,9.729,24.065,30.082C718.177,110.296,705.888,121.049,688.224,121.049z
90
+ M692.447,68.054c-6.4,0-12.032,4.224-16.641,9.984v31.233c3.84,1.408,6.656,2.049,12.288,2.049
91
+ c11.905,0,18.562-7.041,18.562-22.785C706.656,75.222,700.64,68.054,692.447,68.054z"/>
92
+ </g>
93
+ </g>
94
+ </g>
95
+ <g>
96
+ </g>
97
+ <g>
98
+ </g>
99
+ <g>
100
+ </g>
101
+ <g>
102
+ </g>
103
+ <g>
104
+ </g>
105
+ <g>
106
+ </g>
107
+ <g>
108
+ </g>
109
+ <g>
110
+ </g>
111
+ <g>
112
+ </g>
113
+ <g>
114
+ </g>
115
+ <g>
116
+ </g>
117
+ <g>
118
+ </g>
119
+ <g>
120
+ </g>
121
+ <g>
122
+ </g>
123
+ <g>
124
+ </g>
125
+ </svg>
@@ -136,8 +136,8 @@ Since v0.5.1, You can use block for register commands.
136
136
 
137
137
  ```ruby
138
138
 
139
- client.slash_group("settings", "Set settings of bot.") do
140
- slash("message_expand", "Whether bot should expand message.", {
139
+ client.slash_group("settings", "Set settings of bot.") do |group|
140
+ group.slash("message_expand", "Whether bot should expand message.", {
141
141
  "enabled" => {
142
142
  type: :boolean,
143
143
  description: "Whether bot should expand message."
@@ -145,7 +145,7 @@ client.slash_group("settings", "Set settings of bot.") do
145
145
  }) do |interaction|
146
146
  # ...
147
147
  end
148
- slash("bump_alert", "Whether bot should notify DISBOARD bump.", {
148
+ group.slash("bump_alert", "Whether bot should notify DISBOARD bump.", {
149
149
  "enabled" => {
150
150
  type: :boolean,
151
151
  description: "Whether bot should notify DISBOARD bump."
@@ -164,14 +164,14 @@ group = client.slash_group("permission", "Set/Get command permissions.")
164
164
  group_user = group.group("user", "Set/Get user's command permissions.")
165
165
 
166
166
  group_user.slash("set", "Set user's command permissions.", {
167
- "user_id" => {
168
- type: :user,
169
- description: "The user."
170
- },
171
- "value" => {
172
- type: :boolean,
173
- description: "Whether the user can use the command."
174
- }
167
+ "user_id" => {
168
+ type: :user,
169
+ description: "The user."
170
+ },
171
+ "value" => {
172
+ type: :boolean,
173
+ description: "Whether the user can use the command."
174
+ }
175
175
  }) do |interaction, user|
176
176
  # ...
177
177
  end
data/docs/cli/init.md CHANGED
@@ -32,6 +32,18 @@ If true, the command will initialize git and commit the initial files with commi
32
32
  Use `git commit --amend -m "..."` to change the commit message.
33
33
  Default to false.
34
34
 
35
+ ### `--[no-]desc`
36
+
37
+ Whether to create a description file.
38
+ If true, the command will create a `.env.sample` and `README.md` file.
39
+ Default to false.
40
+
41
+ ### `-n` `--name`
42
+
43
+ The name of the project.
44
+ It will be used in the `README.md` file.
45
+ Default to the directory name.
46
+
35
47
  ### `-t`, `--token`
36
48
 
37
49
  The name of token environment variable.
@@ -49,7 +61,9 @@ The following files will be created:
49
61
  | File | Description |
50
62
  | ---- | ----------- |
51
63
  | `.env` | Environment variables. |
64
+ | `main.rb` | Main script. |
52
65
  | `.gitignore` | Git ignore file. Won't be created if `--git` is false. |
53
66
  | `Gemfile` | Gemfile. Won't be created if `--bundle` is false. |
54
67
  | `Gemfile.lock` | Gemfile lock file. Won't be created if `--bundle` is false. |
55
- | `main.rb` | Main script. |
68
+ | `README.md` | Readme file. Won't be created if `--desc` is false. |
69
+ | `.env.sample` | Sample environment variables. Won't be created if `--desc` is false. |
data/docs/events.md CHANGED
@@ -79,6 +79,11 @@ Fires when the client is ready.
79
79
 
80
80
  Fires when the client is resumed connection.
81
81
 
82
+ #### `error(event_name, args, error)`
83
+
84
+ Fires when an error occurs during an event.
85
+ Defaults to printing the error to stderr, override to handle it yourself.
86
+
82
87
  ### Guild events
83
88
 
84
89
  #### `guild_join(guild)`
data/docs/extension.md CHANGED
@@ -46,13 +46,13 @@ module MyExtension
46
46
  # ...
47
47
  end
48
48
 
49
- slash_group("group", "Group") do
50
- slash("subcommand", "Subcommand") do |interaction|
49
+ slash_group("group", "Group") do |group|
50
+ group.slash("subcommand", "Subcommand") do |interaction|
51
51
  # ...
52
52
  end
53
53
 
54
- group("subgroup", "Subcommand group") do
55
- slash("group_subcommand", "Command in Subcommand group") do |interaction|
54
+ group.group("subgroup", "Subcommand group") do |group|
55
+ group.slash("group_subcommand", "Command in Subcommand group") do |interaction|
56
56
  # ...
57
57
  end
58
58
  end
@@ -86,7 +86,7 @@ module MyExtension
86
86
  extend Discorb::Extension
87
87
 
88
88
  event :ready do |message|
89
- puts "Logged in as #{client.user}"
89
+ puts "Logged in as #{@client.user}"
90
90
  end
91
91
  end
92
92
  ```
@@ -46,8 +46,8 @@ module Discorb
46
46
  # @param [String] description Command description.
47
47
  # @param [Array<#to_s>, false, nil] guild_ids Guild IDs to set the command to. `false` to global command, `nil` to use default.
48
48
  #
49
- # @yield Block to execute as the command. It can be used to define sub-commands.
50
- # @yieldself [Discorb::ApplicationCommand::Command::GroupCommand] Group command.
49
+ # @yield Block to yield with the command.
50
+ # @yieldparam [Discorb::ApplicationCommand::Command::GroupCommand] group Group command.
51
51
  #
52
52
  # @return [Discorb::ApplicationCommand::Command::GroupCommand] Command object.
53
53
  #
@@ -56,7 +56,7 @@ module Discorb
56
56
  #
57
57
  def slash_group(command_name, description, guild_ids: nil, &block)
58
58
  command = Discorb::ApplicationCommand::Command::GroupCommand.new(command_name, description, guild_ids, nil, self)
59
- command.instance_eval(&block) if block_given?
59
+ command.yield_self(&block) if block_given?
60
60
  @commands << command
61
61
  command
62
62
  end
@@ -284,8 +284,8 @@ module Discorb
284
284
  # @param [String] command_name Group name.
285
285
  # @param [String] description Group description.
286
286
  #
287
- # @yield Block to execute as the command. It can be used to define sub-commands.
288
- # @yieldself [Discorb::ApplicationCommand::Command::SubcommandGroup] Group command.
287
+ # @yield Block to yield with the command.
288
+ # @yieldparam [Discorb::ApplicationCommand::Command::SubcommandGroup] group Group command.
289
289
  #
290
290
  # @return [Discorb::ApplicationCommand::Command::SubcommandGroup] Command object.
291
291
  #
@@ -293,7 +293,7 @@ module Discorb
293
293
  #
294
294
  def group(command_name, description, &block)
295
295
  command = Discorb::ApplicationCommand::Command::SubcommandGroup.new(command_name, description, @name, @client)
296
- command.instance_eval(&block) if block_given?
296
+ command.yield_self(&block) if block_given?
297
297
  @commands << command
298
298
  command
299
299
  end
@@ -91,6 +91,7 @@ module Discorb
91
91
  @commands = []
92
92
  @bottom_commands = []
93
93
  @status = :initialized
94
+ set_default_events
94
95
  end
95
96
 
96
97
  #
@@ -172,23 +173,17 @@ module Discorb
172
173
  end
173
174
  @log.debug "Dispatching event #{event_name}"
174
175
  events.each do |block|
175
- lambda { |event_args|
176
+ Async do
176
177
  Async(annotation: "Discorb event: #{event_name}") do |task|
177
178
  if block.is_a?(Discorb::Event)
178
179
  @events[event_name].delete(block) if block.metadata[:once]
179
180
  end
180
- block.call(*event_args)
181
+ block.call(*args)
181
182
  @log.debug "Dispatched proc with ID #{block.id.inspect}"
182
183
  rescue StandardError, ScriptError => e
183
- message = "An error occurred while dispatching proc with ID #{block.id.inspect}\n#{e.full_message}"
184
- dispatch(:error, event_name, event_args, e)
185
- if @log.out
186
- @log.error message
187
- else
188
- warn message
189
- end
184
+ dispatch(:error, event_name, args, e)
190
185
  end
191
- }.call(args)
186
+ end
192
187
  end
193
188
  end
194
189
  end
@@ -482,5 +477,12 @@ module Discorb
482
477
  @main_task.stop
483
478
  end
484
479
  end
480
+
481
+ def set_default_events
482
+ on :error, override: true do |event_name, _args, e|
483
+ message = "An error occurred while dispatching #{event_name}:\n#{e.full_message}"
484
+ @log.error message, fallback: $stderr
485
+ end
486
+ end
485
487
  end
486
488
  end
@@ -4,7 +4,7 @@ module Discorb
4
4
  # @return [String] The API base URL.
5
5
  API_BASE_URL = "https://discord.com/api/v9"
6
6
  # @return [String] The version of discorb.
7
- VERSION = "0.6.1"
7
+ VERSION = "0.7.3"
8
8
  # @return [String] The user agent for the bot.
9
9
  USER_AGENT = "DiscordBot (https://github.com/discorb-lib/discorb #{VERSION}) Ruby/#{RUBY_VERSION}"
10
10
 
data/lib/discorb/embed.rb CHANGED
@@ -93,18 +93,18 @@ module Discorb
93
93
  # @return [Hash] Converted embed.
94
94
  #
95
95
  def to_hash
96
- {
97
- title: @title,
98
- description: @description,
99
- url: @url,
100
- timestamp: @timestamp&.iso8601,
101
- color: @color&.to_i,
102
- footer: @footer&.to_hash,
103
- image: @image&.to_hash,
104
- thumbnail: @thumbnail&.to_hash,
105
- author: @author&.to_hash,
106
- fields: @fields&.map { |f| f.to_hash },
107
- }
96
+ ret = { type: "rich" }
97
+ ret[:title] = @title if @title
98
+ ret[:description] = @description if @description
99
+ ret[:url] = @url if @url
100
+ ret[:timestamp] = @timestamp&.iso8601 if @timestamp
101
+ ret[:color] = @color&.to_i if @color
102
+ ret[:footer] = @footer&.to_hash if @footer
103
+ ret[:image] = @image&.to_hash if @image
104
+ ret[:thumbnail] = @thumbnail&.to_hash if @thumbnail
105
+ ret[:author] = @author&.to_hash if @author
106
+ ret[:fields] = @fields&.map { |f| f.to_hash } if @fields.any?
107
+ ret
108
108
  end
109
109
 
110
110
  #
@@ -96,11 +96,46 @@ FILES = {
96
96
  gem "discorb", "~> #{Discorb::VERSION}"
97
97
  gem "dotenv", "~> 2.7"
98
98
  RUBY
99
+ ".env.sample" => <<~BASH,
100
+ %<token>s=
101
+ BASH
102
+ "README.md" => <<~MARKDOWN,
103
+ # %<name>s
104
+
105
+ Welcome to your bot: %<name>s!
106
+
107
+ TODO: Write your bot's description here.
108
+
109
+ ## Usage
110
+
111
+ TODO: Write your bot's usage here.
112
+
113
+ ## Features
114
+
115
+ TODO: Write your bot's features here.
116
+
117
+ ## How to host
118
+
119
+ 1. Clone the repository.
120
+ 2. Run `bundle install`.
121
+ 3. Get your bot's token from the Discord developer portal.
122
+ 4. Copy `.env.sample` to `.env` and fill in the token.
123
+ 5. Run `bundle exec discorb run`.
124
+
125
+ TODO: Write your own customizations here.
126
+
127
+ ## License
128
+
129
+ TODO: Write your bot's license here.
130
+ See https://choosealicense.com/ for more information.
131
+ https://rubygems.org/gems/license-cli may be useful.
132
+
133
+ MARKDOWN
99
134
  }
100
135
 
101
136
  # @!visibility private
102
137
  def create_file(name)
103
- File.write($path + "/#{name}", format(FILES[name], token: $values[:token]), mode: "wb")
138
+ File.write($path + "/#{name}", format(FILES[name], token: $values[:token], name: $values[:name]), mode: "wb")
104
139
  end
105
140
 
106
141
  # @!visibility private
@@ -132,6 +167,14 @@ def git_init
132
167
  " to change commit message of initial commit.\n"
133
168
  end
134
169
 
170
+ # @!visibility private
171
+ def make_descs
172
+ iputs "Making descriptions..."
173
+ create_file(".env.sample")
174
+ create_file("README.md")
175
+ sputs "Made descriptions.\n"
176
+ end
177
+
135
178
  opt = OptionParser.new <<~BANNER
136
179
  A tool to make a new project.
137
180
 
@@ -145,6 +188,8 @@ $values = {
145
188
  git: false,
146
189
  force: false,
147
190
  token: "TOKEN",
191
+ descs: false,
192
+ name: nil,
148
193
  }
149
194
 
150
195
  opt.on("--[no-]bundle", "Whether to use bundle. Default to true.") do |v|
@@ -155,10 +200,18 @@ opt.on("--[no-]git", "Whether to initialize git. Default to false.") do |v|
155
200
  $values[:git] = v
156
201
  end
157
202
 
203
+ opt.on("--[no-]descs", "Whether to put some file for description. Default to false.") do |v|
204
+ $values[:descs] = v
205
+ end
206
+
158
207
  opt.on("-t NAME", "--token NAME", "The name of token environment variable. Default to TOKEN.") do |v|
159
208
  $values[:token] = v
160
209
  end
161
210
 
211
+ opt.on("-n NAME", "--name NAME", "The name of your project. Default to the directory name.") do |v|
212
+ $values[:name] = v
213
+ end
214
+
162
215
  opt.on("-f", "--force", "Whether to force use directory. Default to false.") do |v|
163
216
  $values[:force] = v
164
217
  end
@@ -187,10 +240,14 @@ if (dir = ARGV[0])
187
240
  Dir.chdir($path)
188
241
  end
189
242
 
243
+ $values[:name] ||= Dir.pwd.split("/").last
244
+
190
245
  bundle_init if $values[:bundle]
191
246
 
192
247
  make_files
193
248
 
194
249
  git_init if $values[:git]
195
250
 
251
+ make_descs if $values[:descs]
252
+
196
253
  sputs "\nSuccessfully made a new project at \e[32m#{$path}\e[92m."
@@ -53,6 +53,12 @@ module Discorb
53
53
  attr_reader :member
54
54
  # @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
55
55
  attr_reader :emoji
56
+ # @macro client_cache
57
+ # @return [Discorb::Member, Discorb::User] The user or member who reacted.
58
+ attr_reader :fired_by
59
+
60
+ alias reactor fired_by
61
+ alias from fired_by
56
62
 
57
63
  # @!visibility private
58
64
  def initialize(client, data)
@@ -79,6 +85,8 @@ module Discorb
79
85
  end
80
86
  end
81
87
 
88
+ @fired_by = @member || @user || @client.users[data[:user_id]]
89
+
82
90
  @message = client.messages[data[:message_id]]
83
91
  @emoji = data[:emoji][:id].nil? ? UnicodeEmoji.new(data[:emoji][:name]) : PartialEmoji.new(data[:emoji])
84
92
  end
@@ -355,6 +363,9 @@ module Discorb
355
363
  class TypingStartEvent < GatewayEvent
356
364
  # @return [Discorb::Snowflake] The ID of the channel the user is typing in.
357
365
  attr_reader :user_id
366
+ # @macro client_cache
367
+ # @return [Discorb::Member] The member that is typing.
368
+ attr_reader :member
358
369
 
359
370
  # @!attribute [r] channel
360
371
  # @macro client_cache
@@ -365,6 +376,9 @@ module Discorb
365
376
  # @!attribute [r] user
366
377
  # @macro client_cache
367
378
  # @return [Discorb::User] The user that is typing.
379
+ # @!attribute [r] fired_by
380
+ # @macro client_cache
381
+ # @return [Discorb::Member, Discorb::User] The member or user that started typing.
368
382
 
369
383
  # @!visibility private
370
384
  def initialize(client, data)
@@ -388,6 +402,12 @@ module Discorb
388
402
  def guild
389
403
  @client.guilds[@guild_id]
390
404
  end
405
+
406
+ def fired_by
407
+ @member || user
408
+ end
409
+
410
+ alias from fired_by
391
411
  end
392
412
 
393
413
  #
@@ -584,10 +604,10 @@ module Discorb
584
604
  @session_id = data[:session_id]
585
605
  @user = ClientUser.new(self, data[:user])
586
606
  @uncached_guilds = data[:guilds].map { |g| g[:id] }
587
- if @uncached_guilds == []
607
+ if @uncached_guilds == [] or !@intents.guilds
588
608
  @ready = true
589
609
  dispatch(:ready)
590
- @log.info("Guilds were cached")
610
+ @log.info("Successfully connected to Discord.")
591
611
  end
592
612
  @tasks << handle_heartbeat(@heartbeat_interval)
593
613
  when "GUILD_CREATE"
@@ -597,7 +617,7 @@ module Discorb
597
617
  if @uncached_guilds == []
598
618
  @ready = true
599
619
  dispatch(:ready)
600
- @log.info("Guilds were cached")
620
+ @log.info("Successfully connected to Discord, and cached all guilds.")
601
621
  end
602
622
  elsif @guilds.has?(data[:id])
603
623
  @guilds[data[:id]].send(:_set_data, data)
@@ -80,7 +80,7 @@ module Discorb
80
80
  @enable_emoticons = data[:enable_emoticons]
81
81
  @expire_behavior = self.class.expire_behavior[data[:expire_behavior]]
82
82
  @expire_grace_period = data[:expire_grace_period]
83
- @user = client.users[data[:user].to_i]
83
+ @user = @client.users[data[:user].to_i]
84
84
  @account = Account.new(data[:account])
85
85
  @subscriber_count = data[:subscriber_count]
86
86
  @revoked = data[:revoked]
@@ -64,6 +64,7 @@ module Discorb
64
64
  end
65
65
 
66
66
  alias fired_by target
67
+ alias from target
67
68
 
68
69
  def inspect
69
70
  "#<#{self.class} id=#{@id}>"
@@ -99,6 +100,9 @@ module Discorb
99
100
  #
100
101
  # Response with `DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE`(`5`).
101
102
  #
103
+ # @macro async
104
+ # @macro http
105
+ #
102
106
  # @param [Boolean] ephemeral Whether to make the response ephemeral.
103
107
  #
104
108
  def defer_source(ephemeral: false)
@@ -116,6 +120,9 @@ module Discorb
116
120
  #
117
121
  # Response with `CHANNEL_MESSAGE_WITH_SOURCE`(`4`).
118
122
  #
123
+ # @macro async
124
+ # @macro http
125
+ #
119
126
  # @param [String] content The content of the response.
120
127
  # @param [Boolean] tts Whether to send the message as text-to-speech.
121
128
  # @param [Discorb::Embed] embed The embed to send.
@@ -125,45 +132,48 @@ module Discorb
125
132
  # @param [Boolean] ephemeral Whether to make the response ephemeral.
126
133
  #
127
134
  def post(content = nil, tts: false, embed: nil, embeds: nil, allowed_mentions: nil, components: nil, ephemeral: false)
128
- payload = {}
129
- payload[:content] = content if content
130
- payload[:tts] = tts
131
- tmp_embed = if embed
132
- [embed]
133
- elsif embeds
134
- embeds
135
- end
136
- payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
137
- payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
138
- if components
139
- tmp_components = []
140
- tmp_row = []
141
- components.each do |c|
142
- case c
143
- when Array
144
- tmp_components << tmp_row
145
- tmp_row = []
146
- tmp_components << c
147
- when SelectMenu
148
- tmp_components << tmp_row
149
- tmp_row = []
150
- tmp_components << [c]
151
- else
152
- tmp_row << c
135
+ Async do
136
+ payload = {}
137
+ payload[:content] = content if content
138
+ payload[:tts] = tts
139
+ tmp_embed = if embed
140
+ [embed]
141
+ elsif embeds
142
+ embeds
143
+ end
144
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
145
+ payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
146
+ if components
147
+ tmp_components = []
148
+ tmp_row = []
149
+ components.each do |c|
150
+ case c
151
+ when Array
152
+ tmp_components << tmp_row
153
+ tmp_row = []
154
+ tmp_components << c
155
+ when SelectMenu
156
+ tmp_components << tmp_row
157
+ tmp_row = []
158
+ tmp_components << [c]
159
+ else
160
+ tmp_row << c
161
+ end
153
162
  end
163
+ tmp_components << tmp_row
164
+ payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
154
165
  end
155
- tmp_components << tmp_row
156
- payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
157
- end
158
- payload[:flags] = (ephemeral ? 1 << 6 : 0)
159
- if @responded
160
- @client.http.post("/webhooks/#{@id}/#{@token}", { type: 4, data: payload }).wait
161
- elsif @defered
162
- @client.http.post("/interactions/#{@id}/#{@token}/@original/edit", { type: 4, data: payload }).wait
163
- else
164
- @client.http.post("/interactions/#{@id}/#{@token}/callback", { type: 4, data: payload }).wait
166
+ payload[:flags] = (ephemeral ? 1 << 6 : 0)
167
+
168
+ if @responded
169
+ @client.http.post("/webhooks/#{@application_id}/#{@token}", payload).wait
170
+ elsif @defered
171
+ @client.http.patch("/webhooks/#{@application_id}/#{@token}/messages/@original", payload).wait
172
+ else
173
+ @client.http.post("/interactions/#{@id}/#{@token}/callback", { type: 4, data: payload }).wait
174
+ end
175
+ @responded = true
165
176
  end
166
- @responded = true
167
177
  end
168
178
  end
169
179
 
@@ -190,6 +200,9 @@ module Discorb
190
200
  #
191
201
  # Response with `UPDATE_MESSAGE`(`7`).
192
202
  #
203
+ # @macro async
204
+ # @macro http
205
+ #
193
206
  # @param [String] content The content of the response.
194
207
  # @param [Boolean] tts Whether to send the message as text-to-speech.
195
208
  # @param [Discorb::Embed] embed The embed to send.
@@ -199,38 +212,40 @@ module Discorb
199
212
  # @param [Boolean] ephemeral Whether to make the response ephemeral.
200
213
  #
201
214
  def edit(content, tts: false, embed: nil, embeds: nil, allowed_mentions: nil, components: nil, ephemeral: false)
202
- payload = {}
203
- payload[:content] = content if content
204
- payload[:tts] = tts
205
- tmp_embed = if embed
206
- [embed]
207
- elsif embeds
208
- embeds
209
- end
210
- payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
211
- payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
212
- if components
213
- tmp_components = []
214
- tmp_row = []
215
- components.each do |c|
216
- case c
217
- when Array
218
- tmp_components << tmp_row
219
- tmp_row = []
220
- tmp_components << c
221
- when SelectMenu
222
- tmp_components << tmp_row
223
- tmp_row = []
224
- tmp_components << [c]
225
- else
226
- tmp_row << c
215
+ Async do
216
+ payload = {}
217
+ payload[:content] = content if content
218
+ payload[:tts] = tts
219
+ tmp_embed = if embed
220
+ [embed]
221
+ elsif embeds
222
+ embeds
223
+ end
224
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
225
+ payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
226
+ if components
227
+ tmp_components = []
228
+ tmp_row = []
229
+ components.each do |c|
230
+ case c
231
+ when Array
232
+ tmp_components << tmp_row
233
+ tmp_row = []
234
+ tmp_components << c
235
+ when SelectMenu
236
+ tmp_components << tmp_row
237
+ tmp_row = []
238
+ tmp_components << [c]
239
+ else
240
+ tmp_row << c
241
+ end
227
242
  end
243
+ tmp_components << tmp_row
244
+ payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
228
245
  end
229
- tmp_components << tmp_row
230
- payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
246
+ payload[:flags] = (ephemeral ? 1 << 6 : 0)
247
+ @client.http.post("/interactions/#{@id}/#{@token}/callback", { type: 6, data: payload }).wait
231
248
  end
232
- payload[:flags] = (ephemeral ? 1 << 6 : 0)
233
- @client.http.post("/interactions/#{@id}/#{@token}/callback", { type: 6, data: payload }).wait
234
249
  end
235
250
  end
236
251
 
data/lib/discorb/log.rb CHANGED
@@ -22,34 +22,34 @@ module Discorb
22
22
  raise ArgumentError, "Invalid log level: #{level}" unless @level
23
23
  end
24
24
 
25
- def debug(message)
25
+ def debug(message, fallback: nil)
26
26
  return unless @level <= 0
27
27
 
28
- write_output("DEBUG", "\e[90m", message)
28
+ write_output("DEBUG", "\e[90m", message, fallback)
29
29
  end
30
30
 
31
- def info(message)
31
+ def info(message, fallback: nil)
32
32
  return unless @level <= 1
33
33
 
34
- write_output("INFO", "\e[94m", message)
34
+ write_output("INFO", "\e[94m", message, fallback)
35
35
  end
36
36
 
37
- def warn(message)
37
+ def warn(message, fallback: nil)
38
38
  return unless @level <= 2
39
39
 
40
- write_output("WARN", "\e[93m", message)
40
+ write_output("WARN", "\e[93m", message, fallback)
41
41
  end
42
42
 
43
- def error(message)
43
+ def error(message, fallback: nil)
44
44
  return unless @level <= 3
45
45
 
46
- write_output("ERROR", "\e[31m", message)
46
+ write_output("ERROR", "\e[31m", message, fallback)
47
47
  end
48
48
 
49
- def fatal(message)
49
+ def fatal(message, fallback: nil)
50
50
  return unless @level <= 4
51
51
 
52
- write_output("FATAL", "\e[91m", message)
52
+ write_output("FATAL", "\e[91m", message, fallback)
53
53
  end
54
54
 
55
55
  class << self
@@ -58,8 +58,12 @@ module Discorb
58
58
 
59
59
  private
60
60
 
61
- def write_output(name, color, message)
62
- return unless @out
61
+ def write_output(name, color, message, fallback)
62
+ unless @out
63
+ fallback.puts(message) if fallback
64
+
65
+ return
66
+ end
63
67
 
64
68
  if @colorize_log
65
69
  @out.puts("\e[2;90m[#{Time.now.iso8601}] #{color}#{name}\e[m -- #{message}")
@@ -59,6 +59,8 @@ module Discorb
59
59
  # @!attribute [r] status
60
60
  # @macro client_cache
61
61
  # @return [Symbol] The status of the member. It's from the {#presence}.
62
+ # @!attribute [r] owner?
63
+ # @return [Boolean] Whether the member is the owner of the guild.
62
64
 
63
65
  # @!visibility private
64
66
  def initialize(client, guild_id, user_data, member_data)
@@ -99,18 +101,27 @@ module Discorb
99
101
  guild.voice_states[@id]
100
102
  end
101
103
 
104
+ def owner?
105
+ guild.owner_id == @id
106
+ end
107
+
102
108
  def guild
103
109
  @client.guilds[@guild_id]
104
110
  end
105
111
 
106
112
  def roles
107
- @role_ids.map { |r| guild.roles[r] }
113
+ @role_ids.map { |r| guild.roles[r] }.sort_by(&:position).reverse + [guild.roles[guild.id]]
108
114
  end
109
115
 
110
116
  def permissions
117
+ if owner?
118
+ return Permission.new((1 << 38) - 1)
119
+ end
111
120
  roles.map(&:permissions).sum(Permission.new(0))
112
121
  end
113
122
 
123
+ alias guild_permissions permissions
124
+
114
125
  def hoisted_role
115
126
  @hoisted_role_id && guild.roles[@hoisted_role_id]
116
127
  end
@@ -234,7 +245,7 @@ module Discorb
234
245
  @custom_avatar = member_data[:avatar] && Asset.new(member_data[:avatar])
235
246
  super(user_data)
236
247
  @display_avatar = @avatar || @custom_avatar
237
- @client.guilds[@guild_id].members[@id] = self unless @guild_id.nil?
248
+ @client.guilds[@guild_id].members[@id] = self unless @guild_id.nil? || @client.guilds[@guild_id].nil?
238
249
  @_member_data.update(member_data)
239
250
  end
240
251
  end
@@ -522,11 +522,11 @@ module Discorb
522
522
  if data[:member].nil? && data[:webhook_id]
523
523
  @webhook_id = Snowflake.new(data[:webhook_id])
524
524
  @author = Webhook::Message::Author.new(data[:author])
525
- elsif data[:guild_id].nil? || data[:guild_id].empty?
525
+ elsif data[:guild_id].nil? || data[:guild_id].empty? || data[:member].nil?
526
526
  @author = @client.users[data[:author][:id]] || User.new(@client, data[:author])
527
527
  else
528
- @author = guild.members[data[:author][:id]] || Member.new(@client,
529
- @guild_id, data[:author], data[:member])
528
+ @author = guild&.members&.get(data[:author][:id]) || Member.new(@client,
529
+ @guild_id, data[:author], data[:member])
530
530
  end
531
531
  @content = data[:content]
532
532
  @created_at = Time.iso8601(data[:timestamp])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discorb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - sevenc-nanashi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-17 00:00:00.000000000 Z
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -82,10 +82,10 @@ files:
82
82
  - ".yardopts"
83
83
  - Changelog.md
84
84
  - Gemfile
85
- - Gemfile.lock
86
85
  - LICENSE.txt
87
86
  - README.md
88
87
  - Rakefile
88
+ - assets/banner.svg
89
89
  - bin/console
90
90
  - bin/setup
91
91
  - crowdin.yml
data/Gemfile.lock DELETED
@@ -1,67 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- discorb (0.6.1)
5
- async (~> 1.30.1)
6
- async-http (~> 0.56.5)
7
- async-websocket (~> 0.19.0)
8
- mime-types (~> 3.3)
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- async (1.30.1)
14
- console (~> 1.10)
15
- nio4r (~> 2.3)
16
- timers (~> 4.1)
17
- async-http (0.56.5)
18
- async (>= 1.25)
19
- async-io (>= 1.28)
20
- async-pool (>= 0.2)
21
- protocol-http (~> 0.22.0)
22
- protocol-http1 (~> 0.14.0)
23
- protocol-http2 (~> 0.14.0)
24
- async-io (1.32.2)
25
- async
26
- async-pool (0.3.8)
27
- async (>= 1.25)
28
- async-websocket (0.19.0)
29
- async-http (~> 0.54)
30
- async-io (~> 1.23)
31
- protocol-websocket (~> 0.7.0)
32
- console (1.13.1)
33
- fiber-local
34
- fiber-local (1.0.0)
35
- mime-types (3.3.1)
36
- mime-types-data (~> 3.2015)
37
- mime-types-data (3.2021.0901)
38
- nio4r (2.5.8)
39
- protocol-hpack (1.4.2)
40
- protocol-http (0.22.5)
41
- protocol-http1 (0.14.2)
42
- protocol-http (~> 0.22)
43
- protocol-http2 (0.14.2)
44
- protocol-hpack (~> 1.4)
45
- protocol-http (~> 0.18)
46
- protocol-websocket (0.7.5)
47
- protocol-http (~> 0.2)
48
- protocol-http1 (~> 0.2)
49
- rake (13.0.6)
50
- redcarpet (3.5.1)
51
- rufo (0.13.0)
52
- timers (4.3.3)
53
- yard (0.9.26)
54
-
55
- PLATFORMS
56
- x86-mingw32
57
- x86_64-linux
58
-
59
- DEPENDENCIES
60
- discorb!
61
- rake (~> 13.0)
62
- redcarpet
63
- rufo (~> 0.13.0)
64
- yard (~> 0.9.26)
65
-
66
- BUNDLED WITH
67
- 2.2.22