rubord 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +39 -0
- data/lib/rubord/components/actionRow.rb +93 -0
- data/lib/rubord/components/button.rb +125 -0
- data/lib/rubord/components/componentsV2.rb +4 -0
- data/lib/rubord/components/containers/base.rb +15 -0
- data/lib/rubord/components/containers/container.rb +39 -0
- data/lib/rubord/components/containers/section.rb +26 -0
- data/lib/rubord/components/containers/separator.rb +51 -0
- data/lib/rubord/components/containers/text.rb +23 -0
- data/lib/rubord/components/modal.rb +134 -0
- data/lib/rubord/components/select_menu.rb +147 -0
- data/lib/rubord/models/channel.rb +50 -0
- data/lib/rubord/models/collection.rb +70 -0
- data/lib/rubord/models/commands/base.rb +111 -0
- data/lib/rubord/models/commands/command.rb +3 -0
- data/lib/rubord/models/commands/loader.rb +36 -0
- data/lib/rubord/models/commands/registry.rb +26 -0
- data/lib/rubord/models/components.rb +5 -0
- data/lib/rubord/models/embed.rb +87 -0
- data/lib/rubord/models/flags.rb +249 -0
- data/lib/rubord/models/guild.rb +78 -0
- data/lib/rubord/models/interaction.rb +136 -0
- data/lib/rubord/models/member.rb +63 -0
- data/lib/rubord/models/mention.rb +47 -0
- data/lib/rubord/models/message.rb +88 -0
- data/lib/rubord/models/role.rb +15 -0
- data/lib/rubord/models/user.rb +21 -0
- data/lib/rubord/structs/client.rb +364 -0
- data/lib/rubord/structs/gateway.rb +363 -0
- data/lib/rubord/structs/logger.rb +19 -0
- data/lib/rubord/structs/models.rb +19 -0
- data/lib/rubord/structs/parser.rb +68 -0
- data/lib/rubord/structs/rate_limiter.rb +163 -0
- data/lib/rubord/structs/rest.rb +353 -0
- data/lib/rubord.rb +8 -0
- metadata +105 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 73d40380336ec0be54afd05fa19a6177fcfc25d16d335c7748da02de95da4538
|
|
4
|
+
data.tar.gz: ad7c6cb4f6ab3aae3019e213bda0d4dc0d5dc6307aaa89626f4e2e594daad7e3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 893c48fbcba9541e21c95d47076c6e427d6191638b11064ae59d99f4b8ec82bb606bbcb8a396c5da62c517c60d2a4ac85dfd91540270d1621fc2150337675ce1
|
|
7
|
+
data.tar.gz: c6b3a468ebf4fa9e9631fb1459e618908102d4c1820c70142d73cc7d0bbda27c23f874db774fc3be973ae88d72b4743d936e19b9a6442913e6d5f4492970a455
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kauã Eduardo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Rubord
|
|
2
|
+
|
|
3
|
+
Rubord is a modern Ruby library for building Discord bots.
|
|
4
|
+
|
|
5
|
+
It provides:
|
|
6
|
+
- Gateway (WebSocket)
|
|
7
|
+
- REST API
|
|
8
|
+
- Interactions (Buttons, Modals, Select Menus)
|
|
9
|
+
- Components v2 support
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
gem install rubord
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or in your Gemfile:
|
|
18
|
+
|
|
19
|
+
```rb
|
|
20
|
+
gem "rubord"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Basic Example
|
|
24
|
+
|
|
25
|
+
```rb
|
|
26
|
+
client = Rubord::Client.new(intents: 3276799)
|
|
27
|
+
|
|
28
|
+
client.on(:ready) do |client|
|
|
29
|
+
puts "Logged in: " + client.username
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
client.on(:message_create) do |message|
|
|
33
|
+
if message.content == "!hello"
|
|
34
|
+
message.reply("Hello!")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
client.login("Your discord bot token")
|
|
39
|
+
```
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# components/actionRow.rb
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
# Represents a Discord action row container.
|
|
5
|
+
#
|
|
6
|
+
# Action rows are containers for message components (buttons, select menus).
|
|
7
|
+
# They can hold up to 5 buttons or 1 select menu per row.
|
|
8
|
+
#
|
|
9
|
+
# @example Creating an action row with buttons
|
|
10
|
+
# row = Rubord::ActionRow.new(
|
|
11
|
+
# Rubord::Button.new(label: "Yes", custom_id: "yes"),
|
|
12
|
+
# Rubord::Button.new(label: "No", custom_id: "no")
|
|
13
|
+
# )
|
|
14
|
+
#
|
|
15
|
+
# @example Creating an empty row and adding components
|
|
16
|
+
# row = Rubord::ActionRow.new
|
|
17
|
+
# row.add(Rubord::Button.new(label: "Click", custom_id: "click"))
|
|
18
|
+
#
|
|
19
|
+
# @since 1.0.0
|
|
20
|
+
# @see https://discord.com/developers/docs/interactions/message-components#action-rows
|
|
21
|
+
class ActionRow
|
|
22
|
+
# @return [Integer] Component type (always 1 for action rows).
|
|
23
|
+
attr_accessor :type
|
|
24
|
+
|
|
25
|
+
# @return [Array<Button, SelectMenu>] Components in this action row.
|
|
26
|
+
attr_accessor :components
|
|
27
|
+
|
|
28
|
+
# Creates a new action row.
|
|
29
|
+
#
|
|
30
|
+
# @param components [Array<Button, SelectMenu>] Components to include in the row.
|
|
31
|
+
# Can be empty.
|
|
32
|
+
#
|
|
33
|
+
# @example Empty action row
|
|
34
|
+
# ActionRow.new
|
|
35
|
+
#
|
|
36
|
+
# @example With initial buttons
|
|
37
|
+
# ActionRow.new(
|
|
38
|
+
# Button.new(label: "Save", custom_id: "save"),
|
|
39
|
+
# Button.new(label: "Cancel", custom_id: "cancel")
|
|
40
|
+
# )
|
|
41
|
+
#
|
|
42
|
+
# @note Action rows can contain either:
|
|
43
|
+
# - Up to 5 buttons
|
|
44
|
+
# - OR 1 select menu
|
|
45
|
+
# Not a mixture of both.
|
|
46
|
+
def initialize(*components)
|
|
47
|
+
@type = 1
|
|
48
|
+
@components = components
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Adds a component to the action row.
|
|
52
|
+
#
|
|
53
|
+
# @param component [Button, SelectMenu] Component to add.
|
|
54
|
+
#
|
|
55
|
+
# @return [Rubord::ActionRow] Self for method chaining.
|
|
56
|
+
#
|
|
57
|
+
# @raise [ArgumentError] If adding component would violate Discord limits.
|
|
58
|
+
#
|
|
59
|
+
# @example
|
|
60
|
+
# row = ActionRow.new
|
|
61
|
+
# row.add(Button.new(label: "Test", custom_id: "test"))
|
|
62
|
+
def add(component)
|
|
63
|
+
@components << component
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Converts the action row to a Discord API-compatible hash.
|
|
68
|
+
#
|
|
69
|
+
# @return [Hash] Action row data in Discord API format.
|
|
70
|
+
#
|
|
71
|
+
# @example
|
|
72
|
+
# row = ActionRow.new(Button.new(label: "Btn", custom_id: "btn"))
|
|
73
|
+
# row.to_h
|
|
74
|
+
# # => {type: 1, components: [{type: 2, style: 1, label: "Btn", custom_id: "btn", disabled: false}]}
|
|
75
|
+
def to_h
|
|
76
|
+
{
|
|
77
|
+
type: @type,
|
|
78
|
+
components: @components.map(&:to_h)
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Factory method for creating ActionRow instances.
|
|
84
|
+
#
|
|
85
|
+
# @param args [Array<Button, SelectMenu>] Components to include.
|
|
86
|
+
# @return [Rubord::ActionRow] New action row instance.
|
|
87
|
+
#
|
|
88
|
+
# @example
|
|
89
|
+
# row = Rubord.ActionRow(button1, button2)
|
|
90
|
+
def self.ActionRow(*args)
|
|
91
|
+
ActionRow.new(*args)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# components/button.rb
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
# Represents a Discord interactive button component.
|
|
5
|
+
#
|
|
6
|
+
# Buttons are interactive elements that users can click to trigger actions.
|
|
7
|
+
# They can be used in messages, modals, and action rows.
|
|
8
|
+
#
|
|
9
|
+
# @example Creating a primary button
|
|
10
|
+
# button = Rubord::Button.new(
|
|
11
|
+
# label: "Click Me",
|
|
12
|
+
# style: 1,
|
|
13
|
+
# custom_id: "my_button"
|
|
14
|
+
# )
|
|
15
|
+
#
|
|
16
|
+
# @example Creating a link button
|
|
17
|
+
# link_button = Rubord::Button.new(
|
|
18
|
+
# label: "Visit Website",
|
|
19
|
+
# style: 5,
|
|
20
|
+
# url: "https://example.com"
|
|
21
|
+
# )
|
|
22
|
+
#
|
|
23
|
+
# @since 1.0.0
|
|
24
|
+
# @see https://discord.com/developers/docs/interactions/message-components#buttons
|
|
25
|
+
class Button
|
|
26
|
+
# @return [Integer] Component type (always 2 for buttons).
|
|
27
|
+
attr_accessor :type
|
|
28
|
+
|
|
29
|
+
# @return [Integer] Button style (1-5).
|
|
30
|
+
# - 1: Primary (blurple)
|
|
31
|
+
# - 2: Secondary (grey)
|
|
32
|
+
# - 3: Success (green)
|
|
33
|
+
# - 4: Danger (red)
|
|
34
|
+
# - 5: Link (grey, navigates to URL)
|
|
35
|
+
attr_accessor :style
|
|
36
|
+
|
|
37
|
+
# @return [String] Text displayed on the button (max 80 characters).
|
|
38
|
+
attr_accessor :label
|
|
39
|
+
|
|
40
|
+
# @return [String, nil] Developer-defined identifier for the button.
|
|
41
|
+
# Required for non-link buttons, must be unique per message.
|
|
42
|
+
attr_accessor :custom_id
|
|
43
|
+
|
|
44
|
+
# @return [String, nil] URL for link buttons (style 5).
|
|
45
|
+
attr_accessor :url
|
|
46
|
+
|
|
47
|
+
# @return [Boolean] Whether the button is disabled.
|
|
48
|
+
attr_accessor :disabled
|
|
49
|
+
|
|
50
|
+
# @return [Hash, nil] Emoji to display on the button.
|
|
51
|
+
# Format: `{name: "emoji_name", id: "emoji_id", animated: false}`
|
|
52
|
+
attr_accessor :emoji
|
|
53
|
+
|
|
54
|
+
# Creates a new button component.
|
|
55
|
+
#
|
|
56
|
+
# @param label [String] Text label displayed on the button.
|
|
57
|
+
# @param style [Integer] Button style (1-5).
|
|
58
|
+
# Defaults to 1 (primary).
|
|
59
|
+
# @param custom_id [String, nil] Developer-defined identifier.
|
|
60
|
+
# Required for non-link buttons.
|
|
61
|
+
# @param url [String, nil] URL for link buttons (style 5).
|
|
62
|
+
# @param disabled [Boolean] Whether the button is disabled.
|
|
63
|
+
# Defaults to false.
|
|
64
|
+
# @param emoji [Hash, nil] Emoji to display on the button.
|
|
65
|
+
#
|
|
66
|
+
# @raise [ArgumentError] If required parameters are missing.
|
|
67
|
+
#
|
|
68
|
+
# @example Primary button with emoji
|
|
69
|
+
# Button.new(
|
|
70
|
+
# label: "Submit",
|
|
71
|
+
# style: 1,
|
|
72
|
+
# custom_id: "submit_btn",
|
|
73
|
+
# emoji: { name: "✅" }
|
|
74
|
+
# )
|
|
75
|
+
#
|
|
76
|
+
# @example Disabled danger button
|
|
77
|
+
# Button.new(
|
|
78
|
+
# label: "Delete",
|
|
79
|
+
# style: 4,
|
|
80
|
+
# custom_id: "delete_btn",
|
|
81
|
+
# disabled: true
|
|
82
|
+
# )
|
|
83
|
+
def initialize(label:, style: 1, custom_id: nil, url: nil, disabled: false, emoji: nil)
|
|
84
|
+
@type = 2
|
|
85
|
+
@style = style
|
|
86
|
+
@label = label
|
|
87
|
+
@custom_id = custom_id
|
|
88
|
+
@url = url
|
|
89
|
+
@disabled = disabled
|
|
90
|
+
@emoji = emoji
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Converts the button to a Discord API-compatible hash.
|
|
94
|
+
#
|
|
95
|
+
# @return [Hash] Button data in Discord API format.
|
|
96
|
+
#
|
|
97
|
+
# @example
|
|
98
|
+
# button = Button.new(label: "Test", custom_id: "test")
|
|
99
|
+
# button.to_h
|
|
100
|
+
# # => {type: 2, style: 1, label: "Test", custom_id: "test", disabled: false}
|
|
101
|
+
def to_h
|
|
102
|
+
h = {
|
|
103
|
+
type: @type,
|
|
104
|
+
style: @style,
|
|
105
|
+
label: @label,
|
|
106
|
+
disabled: @disabled
|
|
107
|
+
}
|
|
108
|
+
h[:custom_id] = @custom_id if @custom_id
|
|
109
|
+
h[:url] = @url if @url
|
|
110
|
+
h[:emoji] = @emoji if @emoji
|
|
111
|
+
h
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Factory method for creating Button instances.
|
|
116
|
+
#
|
|
117
|
+
# @param args [Hash] Button initialization parameters.
|
|
118
|
+
# @return [Rubord::Button] New button instance.
|
|
119
|
+
#
|
|
120
|
+
# @example
|
|
121
|
+
# button = Rubord.Button(label: "Click", custom_id: "click")
|
|
122
|
+
def self.Button(**args)
|
|
123
|
+
Button.new(**args)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
module Components
|
|
5
|
+
class Container < BaseComponent
|
|
6
|
+
attr_reader :components, :color
|
|
7
|
+
|
|
8
|
+
def initialize(*components, color: nil)
|
|
9
|
+
super(17)
|
|
10
|
+
@color = Rubord.Parser.color(color)
|
|
11
|
+
@components = []
|
|
12
|
+
components.each { |c| add(c) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add(component)
|
|
16
|
+
unless component.respond_to?(:to_h)
|
|
17
|
+
raise ArgumentError, "Invalid component inside Container: #{component.inspect}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
@components << component
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_h
|
|
25
|
+
payload = {
|
|
26
|
+
type: @type,
|
|
27
|
+
components: @components.map(&:to_h)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
payload[:accent_color] = @color if @color
|
|
31
|
+
payload
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.Container(*components, **opts)
|
|
37
|
+
Components::Container.new(*components, **opts)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
module Components
|
|
5
|
+
class Section < BaseComponent
|
|
6
|
+
def initialize(text:, accessory: nil)
|
|
7
|
+
super(9)
|
|
8
|
+
@text = text
|
|
9
|
+
@accessory = accessory
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
h = {
|
|
14
|
+
type: @type,
|
|
15
|
+
text: @text.is_a?(String) ? { type: 10, content: @text } : @text.to_h
|
|
16
|
+
}
|
|
17
|
+
h[:accessory] = @accessory.to_h if @accessory
|
|
18
|
+
h
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.Section(**args)
|
|
24
|
+
Components::Section.new(**args)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
module Components
|
|
5
|
+
class Separator < BaseComponent
|
|
6
|
+
SPACING = {
|
|
7
|
+
small: 1,
|
|
8
|
+
large: 2
|
|
9
|
+
}.freeze
|
|
10
|
+
|
|
11
|
+
attr_reader :divider, :spacing
|
|
12
|
+
|
|
13
|
+
def initialize(divider: true, spacing: :small)
|
|
14
|
+
super(14)
|
|
15
|
+
|
|
16
|
+
@divider = !!divider
|
|
17
|
+
@spacing = parse_spacing(spacing)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_h
|
|
21
|
+
{
|
|
22
|
+
type: @type,
|
|
23
|
+
divider: @divider,
|
|
24
|
+
spacing: @spacing
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def parse_spacing(value)
|
|
31
|
+
case value
|
|
32
|
+
when Integer
|
|
33
|
+
unless SPACING.value?(value)
|
|
34
|
+
raise ArgumentError, "Invalid spacing value: #{value}"
|
|
35
|
+
end
|
|
36
|
+
value
|
|
37
|
+
when Symbol, String
|
|
38
|
+
spacing = SPACING[value.to_sym]
|
|
39
|
+
raise ArgumentError, "Invalid spacing: #{value.inspect}" unless spacing
|
|
40
|
+
spacing
|
|
41
|
+
else
|
|
42
|
+
raise ArgumentError, "Invalid spacing type: #{value.class}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.Separator(**opts)
|
|
49
|
+
Components::Separator.new(**opts)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
module Components
|
|
5
|
+
class Text < BaseComponent
|
|
6
|
+
def initialize(content)
|
|
7
|
+
super(10)
|
|
8
|
+
@content = content
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_h
|
|
12
|
+
{
|
|
13
|
+
type: @type,
|
|
14
|
+
content: @content
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.Text(content)
|
|
21
|
+
Components::Text.new(content)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# components/modal.rb
|
|
2
|
+
|
|
3
|
+
module Rubord
|
|
4
|
+
# Represents a Discord modal dialog component.
|
|
5
|
+
#
|
|
6
|
+
# Modals are pop-up dialog windows that can contain text inputs.
|
|
7
|
+
# They're triggered by interactions and allow for more complex user input.
|
|
8
|
+
#
|
|
9
|
+
# @example Creating a simple modal
|
|
10
|
+
# modal = Rubord::Modal.new(
|
|
11
|
+
# custom_id: "feedback_form",
|
|
12
|
+
# title: "Submit Feedback"
|
|
13
|
+
# )
|
|
14
|
+
# modal.add_text_input(
|
|
15
|
+
# custom_id: "feedback",
|
|
16
|
+
# label: "Your feedback",
|
|
17
|
+
# style: 2,
|
|
18
|
+
# placeholder: "Type your feedback here..."
|
|
19
|
+
# )
|
|
20
|
+
#
|
|
21
|
+
# @since 1.0.0
|
|
22
|
+
# @see https://discord.com/developers/docs/interactions/modals
|
|
23
|
+
class Modal
|
|
24
|
+
# @return [Integer] Component type (always 1 for modals).
|
|
25
|
+
attr_accessor :type
|
|
26
|
+
|
|
27
|
+
# @return [String] Developer-defined identifier.
|
|
28
|
+
attr_accessor :custom_id
|
|
29
|
+
|
|
30
|
+
# @return [String] Modal title (max 45 characters).
|
|
31
|
+
attr_accessor :title
|
|
32
|
+
|
|
33
|
+
# @return [Array<Hash>] List of text input components.
|
|
34
|
+
attr_accessor :components
|
|
35
|
+
|
|
36
|
+
# Creates a new modal dialog.
|
|
37
|
+
#
|
|
38
|
+
# @param custom_id [String] Developer-defined identifier.
|
|
39
|
+
# @param title [String] Modal title (max 45 characters).
|
|
40
|
+
#
|
|
41
|
+
# @example
|
|
42
|
+
# Modal.new(
|
|
43
|
+
# custom_id: "user_registration",
|
|
44
|
+
# title: "Register Account"
|
|
45
|
+
# )
|
|
46
|
+
def initialize(custom_id:, title:)
|
|
47
|
+
@type = 1
|
|
48
|
+
@custom_id = custom_id
|
|
49
|
+
@title = title
|
|
50
|
+
@components = []
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Adds a text input field to the modal.
|
|
54
|
+
#
|
|
55
|
+
# @param custom_id [String] Developer-defined identifier for the input.
|
|
56
|
+
# @param label [String] Label displayed above the input (max 45 characters).
|
|
57
|
+
# @param style [Integer] Input style (1=single-line, 2=multi-line).
|
|
58
|
+
# Defaults to 1.
|
|
59
|
+
# @param min_length [Integer, nil] Minimum input length.
|
|
60
|
+
# @param max_length [Integer, nil] Maximum input length.
|
|
61
|
+
# @param required [Boolean] Whether the input is required.
|
|
62
|
+
# Defaults to true.
|
|
63
|
+
# @param value [String, nil] Pre-filled value.
|
|
64
|
+
# @param placeholder [String, nil] Placeholder text.
|
|
65
|
+
#
|
|
66
|
+
# @return [Rubord::Modal] Self for method chaining.
|
|
67
|
+
#
|
|
68
|
+
# @example Single-line required input
|
|
69
|
+
# modal.add_text_input(
|
|
70
|
+
# custom_id: "username",
|
|
71
|
+
# label: "Username",
|
|
72
|
+
# required: true,
|
|
73
|
+
# min_length: 3,
|
|
74
|
+
# max_length: 20
|
|
75
|
+
# )
|
|
76
|
+
#
|
|
77
|
+
# @example Multi-line optional input
|
|
78
|
+
# modal.add_text_input(
|
|
79
|
+
# custom_id: "bio",
|
|
80
|
+
# label: "Biography",
|
|
81
|
+
# style: 2,
|
|
82
|
+
# required: false,
|
|
83
|
+
# placeholder: "Tell us about yourself...",
|
|
84
|
+
# max_length: 500
|
|
85
|
+
# )
|
|
86
|
+
def add_text_input(custom_id:, label:, style: 1, min_length: nil, max_length: nil, required: true, value: nil, placeholder: nil)
|
|
87
|
+
@components << {
|
|
88
|
+
type: 4,
|
|
89
|
+
custom_id: custom_id,
|
|
90
|
+
style: style,
|
|
91
|
+
label: label,
|
|
92
|
+
min_length: min_length,
|
|
93
|
+
max_length: max_length,
|
|
94
|
+
required: required,
|
|
95
|
+
value: value,
|
|
96
|
+
placeholder: placeholder
|
|
97
|
+
}.compact
|
|
98
|
+
self
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Converts the modal to a Discord API-compatible hash.
|
|
102
|
+
#
|
|
103
|
+
# @return [Hash] Modal data in Discord API format.
|
|
104
|
+
#
|
|
105
|
+
# @example
|
|
106
|
+
# modal = Modal.new(custom_id: "test", title: "Test Modal")
|
|
107
|
+
# modal.to_h
|
|
108
|
+
# # => {type: 1, custom_id: "test", title: "Test Modal", components: [{type: 1, components: []}]}
|
|
109
|
+
def to_h
|
|
110
|
+
{
|
|
111
|
+
type: @type,
|
|
112
|
+
custom_id: @custom_id,
|
|
113
|
+
title: @title,
|
|
114
|
+
components: [
|
|
115
|
+
{
|
|
116
|
+
type: 1,
|
|
117
|
+
components: @components
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Factory method for creating Modal instances.
|
|
125
|
+
#
|
|
126
|
+
# @param args [Hash] Modal initialization parameters.
|
|
127
|
+
# @return [Rubord::Modal] New modal instance.
|
|
128
|
+
#
|
|
129
|
+
# @example
|
|
130
|
+
# modal = Rubord.Modal(custom_id: "form", title: "Feedback Form")
|
|
131
|
+
def self.Modal(**args)
|
|
132
|
+
Modal.new(**args)
|
|
133
|
+
end
|
|
134
|
+
end
|