line-message-builder 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +20 -0
- data/CLAUDE.md +124 -0
- data/README.md +24 -16
- data/claudekit.json +11 -0
- data/docs/rubrics/rdoc.md +169 -0
- data/lib/line/message/builder/actions/message.rb +47 -26
- data/lib/line/message/builder/actions/postback.rb +56 -26
- data/lib/line/message/builder/actions/uri.rb +139 -0
- data/lib/line/message/builder/actions.rb +6 -3
- data/lib/line/message/builder/base.rb +92 -67
- data/lib/line/message/builder/container.rb +55 -60
- data/lib/line/message/builder/context.rb +51 -72
- data/lib/line/message/builder/flex/actionable.rb +53 -32
- data/lib/line/message/builder/flex/box.rb +342 -79
- data/lib/line/message/builder/flex/bubble.rb +73 -46
- data/lib/line/message/builder/flex/builder.rb +39 -28
- data/lib/line/message/builder/flex/button.rb +90 -42
- data/lib/line/message/builder/flex/carousel.rb +48 -20
- data/lib/line/message/builder/flex/icon.rb +152 -0
- data/lib/line/message/builder/flex/image.rb +95 -33
- data/lib/line/message/builder/flex/partial.rb +47 -49
- data/lib/line/message/builder/flex/position.rb +187 -100
- data/lib/line/message/builder/flex/separator.rb +49 -6
- data/lib/line/message/builder/flex/size.rb +67 -47
- data/lib/line/message/builder/flex/span.rb +106 -32
- data/lib/line/message/builder/flex/text.rb +166 -54
- data/lib/line/message/builder/flex.rb +26 -23
- data/lib/line/message/builder/quick_reply.rb +174 -4
- data/lib/line/message/builder/text.rb +70 -3
- data/lib/line/message/builder/version.rb +1 -1
- data/lib/line/message/builder.rb +14 -11
- data/lib/line/message/rspec/matchers/have_flex_bubble.rb +1 -1
- data/lib/line/message/rspec/matchers/have_flex_component.rb +16 -6
- data/lib/line/message/rspec/matchers/have_flex_message.rb +1 -1
- data/lib/line/message/rspec/matchers/have_flex_separator.rb +1 -1
- data/lib/line/message/rspec/matchers/have_quick_reply.rb +1 -1
- data/lib/line/message/rspec/matchers/have_text_message.rb +1 -1
- data/llm.txt +276 -35
- data/release-please-config.json +3 -1
- metadata +9 -3
|
@@ -3,14 +3,109 @@
|
|
|
3
3
|
module Line
|
|
4
4
|
module Message
|
|
5
5
|
module Builder
|
|
6
|
-
# The QuickReply
|
|
6
|
+
# The QuickReply class provides a builder for creating quick reply buttons
|
|
7
|
+
# that can be attached to text messages or flex messages in the LINE Messaging API.
|
|
8
|
+
#
|
|
9
|
+
# Quick reply buttons appear at the bottom of the chat screen and allow users
|
|
10
|
+
# to quickly respond to messages with predefined actions. They provide a
|
|
11
|
+
# convenient way to guide user interactions without requiring typing.
|
|
12
|
+
#
|
|
13
|
+
# Quick replies support:
|
|
14
|
+
# - Message actions that send text messages when tapped
|
|
15
|
+
# - Postback actions that send data to your webhook
|
|
16
|
+
# - Optional image icons for each button (up to 13 buttons total)
|
|
17
|
+
#
|
|
18
|
+
# == Example: Basic quick reply with message actions
|
|
19
|
+
#
|
|
20
|
+
# Line::Message::Builder.with do
|
|
21
|
+
# text "Choose your favorite:" do
|
|
22
|
+
# quick_reply do
|
|
23
|
+
# message "Pizza", label: "Pizza"
|
|
24
|
+
# message "Sushi", label: "Sushi"
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# == Example: Quick reply with postback actions
|
|
30
|
+
#
|
|
31
|
+
# Line::Message::Builder.with do
|
|
32
|
+
# text "What would you like to do?" do
|
|
33
|
+
# quick_reply do
|
|
34
|
+
# postback "action=order", label: "Place Order", display_text: "I want to order"
|
|
35
|
+
# postback "action=track", label: "Track Order"
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# == Example: Quick reply with image icons
|
|
41
|
+
#
|
|
42
|
+
# Line::Message::Builder.with do
|
|
43
|
+
# text "Select a category:" do
|
|
44
|
+
# quick_reply do
|
|
45
|
+
# message "Food", label: "Food", image_url: "https://example.com/food.png"
|
|
46
|
+
# message "Drinks", label: "Drinks", image_url: "https://example.com/drinks.png"
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# See also:
|
|
52
|
+
# - Text
|
|
53
|
+
# - Actions::Message
|
|
54
|
+
# - Actions::Postback
|
|
55
|
+
# - https://developers.line.biz/en/docs/messaging-api/using-quick-reply/
|
|
7
56
|
class QuickReply < Line::Message::Builder::Base
|
|
57
|
+
# Creates a new quick reply builder.
|
|
58
|
+
#
|
|
59
|
+
# Quick reply builders manage a collection of action buttons that appear
|
|
60
|
+
# at the bottom of messages. The builder provides methods to add message
|
|
61
|
+
# and postback actions with optional image icons.
|
|
62
|
+
#
|
|
63
|
+
# [context]
|
|
64
|
+
# An optional context object for method delegation (default: +nil+)
|
|
65
|
+
# [block]
|
|
66
|
+
# Block for configuring quick reply buttons using +message+, +postback+
|
|
67
|
+
# and +uri+ methods
|
|
68
|
+
#
|
|
69
|
+
# == Example
|
|
70
|
+
#
|
|
71
|
+
# quick_reply = QuickReply.new(context: view_context) do
|
|
72
|
+
# message "Yes", label: "Yes"
|
|
73
|
+
# message "No", label: "No"
|
|
74
|
+
# end
|
|
8
75
|
def initialize(context: nil, &)
|
|
9
76
|
@items = []
|
|
10
77
|
|
|
11
78
|
super
|
|
12
79
|
end
|
|
13
80
|
|
|
81
|
+
# Adds a message action button to the quick reply.
|
|
82
|
+
#
|
|
83
|
+
# Message actions send the specified text as a message from the user when
|
|
84
|
+
# the button is tapped. This is useful for providing predefined response
|
|
85
|
+
# options that simplify user interaction.
|
|
86
|
+
#
|
|
87
|
+
# [text]
|
|
88
|
+
# The text message to send when the button is tapped
|
|
89
|
+
# [label]
|
|
90
|
+
# The label text displayed on the button (required)
|
|
91
|
+
# [image_url]
|
|
92
|
+
# Optional icon image URL for the button (default: +nil+)
|
|
93
|
+
# [block]
|
|
94
|
+
# Optional block for additional configuration
|
|
95
|
+
#
|
|
96
|
+
# == Example: Basic message button
|
|
97
|
+
#
|
|
98
|
+
# quick_reply do
|
|
99
|
+
# message "I agree", label: "Yes"
|
|
100
|
+
# message "I disagree", label: "No"
|
|
101
|
+
# end
|
|
102
|
+
#
|
|
103
|
+
# == Example: Message button with icon
|
|
104
|
+
#
|
|
105
|
+
# quick_reply do
|
|
106
|
+
# message "Order pizza", label: "Pizza",
|
|
107
|
+
# image_url: "https://example.com/pizza.png"
|
|
108
|
+
# end
|
|
14
109
|
def message(text, label:, image_url: nil, &)
|
|
15
110
|
action(
|
|
16
111
|
Actions::Message.new(text, context: context, label: label, &),
|
|
@@ -18,6 +113,46 @@ module Line
|
|
|
18
113
|
)
|
|
19
114
|
end
|
|
20
115
|
|
|
116
|
+
# Adds a postback action button to the quick reply.
|
|
117
|
+
#
|
|
118
|
+
# Postback actions send data to your bot's webhook when the button is tapped,
|
|
119
|
+
# allowing you to trigger backend logic without displaying a message. Optionally,
|
|
120
|
+
# you can specify display text that will appear in the chat as if the user
|
|
121
|
+
# sent it.
|
|
122
|
+
#
|
|
123
|
+
# [data]
|
|
124
|
+
# The data payload to send to the webhook (max 300 characters)
|
|
125
|
+
# [label]
|
|
126
|
+
# The label text displayed on the button (default: +nil+)
|
|
127
|
+
# [display_text]
|
|
128
|
+
# Text to display in chat when tapped (default: +nil+)
|
|
129
|
+
# [image_url]
|
|
130
|
+
# Optional icon image URL for the button (default: +nil+)
|
|
131
|
+
# [block]
|
|
132
|
+
# Optional block for additional configuration
|
|
133
|
+
#
|
|
134
|
+
# == Example: Basic postback button
|
|
135
|
+
#
|
|
136
|
+
# quick_reply do
|
|
137
|
+
# postback "action=yes", label: "Yes"
|
|
138
|
+
# postback "action=no", label: "No"
|
|
139
|
+
# end
|
|
140
|
+
#
|
|
141
|
+
# == Example: Postback with display text
|
|
142
|
+
#
|
|
143
|
+
# quick_reply do
|
|
144
|
+
# postback "action=order&item=pizza",
|
|
145
|
+
# label: "Order Pizza",
|
|
146
|
+
# display_text: "I'd like to order a pizza"
|
|
147
|
+
# end
|
|
148
|
+
#
|
|
149
|
+
# == Example: Postback button with icon
|
|
150
|
+
#
|
|
151
|
+
# quick_reply do
|
|
152
|
+
# postback "action=confirm",
|
|
153
|
+
# label: "Confirm",
|
|
154
|
+
# image_url: "https://example.com/check.png"
|
|
155
|
+
# end
|
|
21
156
|
def postback(data, label: nil, display_text: nil, image_url: nil, &)
|
|
22
157
|
action(
|
|
23
158
|
Actions::Postback.new(data, context: context, label: label, display_text: display_text, &),
|
|
@@ -25,9 +160,44 @@ module Line
|
|
|
25
160
|
)
|
|
26
161
|
end
|
|
27
162
|
|
|
163
|
+
# Adds a URI action button to the quick reply.
|
|
164
|
+
#
|
|
165
|
+
# URI actions open the given URI when the button is tapped, without any
|
|
166
|
+
# webhook handling. The <code>altUri.desktop</code> property is not
|
|
167
|
+
# supported in a quick reply, so Actions::Uri#alt_uri_desktop has no
|
|
168
|
+
# effect here.
|
|
169
|
+
#
|
|
170
|
+
# [uri]
|
|
171
|
+
# The URI to open. Schemes +http+, +https+, +line+ and +tel+
|
|
172
|
+
# [label]
|
|
173
|
+
# The label text displayed on the button (required)
|
|
174
|
+
# [image_url]
|
|
175
|
+
# Optional icon image URL for the button (default: +nil+)
|
|
176
|
+
# [block]
|
|
177
|
+
# Optional block for additional configuration
|
|
178
|
+
#
|
|
179
|
+
# == Example: Basic URI button
|
|
180
|
+
#
|
|
181
|
+
# quick_reply do
|
|
182
|
+
# uri "https://example.com/menu", label: "See menu"
|
|
183
|
+
# end
|
|
184
|
+
#
|
|
185
|
+
# == Example: URI button with icon
|
|
186
|
+
#
|
|
187
|
+
# quick_reply do
|
|
188
|
+
# uri "tel:+81312345678", label: "Call us",
|
|
189
|
+
# image_url: "https://example.com/phone.png"
|
|
190
|
+
# end
|
|
191
|
+
def uri(uri, label:, image_url: nil, &)
|
|
192
|
+
action(
|
|
193
|
+
Actions::Uri.new(uri, context: context, label: label, &),
|
|
194
|
+
image_url
|
|
195
|
+
)
|
|
196
|
+
end
|
|
197
|
+
|
|
28
198
|
private
|
|
29
199
|
|
|
30
|
-
def to_api
|
|
200
|
+
def to_api # :nodoc:
|
|
31
201
|
{
|
|
32
202
|
items: @items.map do |item, image_url|
|
|
33
203
|
{
|
|
@@ -39,7 +209,7 @@ module Line
|
|
|
39
209
|
}
|
|
40
210
|
end
|
|
41
211
|
|
|
42
|
-
def to_sdkv2
|
|
212
|
+
def to_sdkv2 # :nodoc:
|
|
43
213
|
{
|
|
44
214
|
items: @items.map do |item, image_url|
|
|
45
215
|
{
|
|
@@ -51,7 +221,7 @@ module Line
|
|
|
51
221
|
}
|
|
52
222
|
end
|
|
53
223
|
|
|
54
|
-
def action(action, image_url)
|
|
224
|
+
def action(action, image_url) # :nodoc:
|
|
55
225
|
@items << [action, image_url]
|
|
56
226
|
end
|
|
57
227
|
end
|
|
@@ -3,10 +3,77 @@
|
|
|
3
3
|
module Line
|
|
4
4
|
module Message
|
|
5
5
|
module Builder
|
|
6
|
-
# Text
|
|
6
|
+
# The Text class provides a builder for creating simple text messages
|
|
7
|
+
# in the LINE Messaging API. Text messages are the most basic message type,
|
|
8
|
+
# consisting of plain text content with optional quick reply buttons and
|
|
9
|
+
# quote tokens for replying to specific messages.
|
|
10
|
+
#
|
|
11
|
+
# Text messages support:
|
|
12
|
+
# - Plain text content (up to 5,000 characters)
|
|
13
|
+
# - Quick reply buttons for user interaction
|
|
14
|
+
# - Quote tokens to reply to specific messages in a conversation
|
|
15
|
+
#
|
|
16
|
+
# == Example: Basic text message
|
|
17
|
+
#
|
|
18
|
+
# Line::Message::Builder.with do
|
|
19
|
+
# text "Hello, world!"
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# == Example: Text with quick reply
|
|
23
|
+
#
|
|
24
|
+
# Line::Message::Builder.with do
|
|
25
|
+
# text "Choose an option:" do
|
|
26
|
+
# quick_reply do
|
|
27
|
+
# button action: :message, label: "Yes", text: "I agree"
|
|
28
|
+
# button action: :message, label: "No", text: "I disagree"
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# == Example: Text with quote token
|
|
34
|
+
#
|
|
35
|
+
# Line::Message::Builder.with do
|
|
36
|
+
# text "This is a reply" do
|
|
37
|
+
# quote_token "sample_quote_token_value"
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
40
|
+
#
|
|
41
|
+
# The Text builder inherits from Base and can be used within the
|
|
42
|
+
# Line::Message::Builder.with block using the +text+ method.
|
|
7
43
|
class Text < Base
|
|
44
|
+
# :method: quote_token
|
|
45
|
+
# :call-seq:
|
|
46
|
+
# quote_token() -> String or nil
|
|
47
|
+
# quote_token(value) -> String
|
|
48
|
+
#
|
|
49
|
+
# Sets or gets the quote token for replying to a specific message.
|
|
50
|
+
#
|
|
51
|
+
# Quote tokens allow your bot to quote and reply to a specific message
|
|
52
|
+
# in the conversation. When set, the original message being replied to
|
|
53
|
+
# will be displayed above the new message.
|
|
54
|
+
#
|
|
55
|
+
# [value]
|
|
56
|
+
# The quote token string obtained from a webhook event
|
|
8
57
|
option :quote_token, default: nil
|
|
9
58
|
|
|
59
|
+
# Creates a new text message builder.
|
|
60
|
+
#
|
|
61
|
+
# [text]
|
|
62
|
+
# The text content of the message (up to 5,000 characters)
|
|
63
|
+
# [context]
|
|
64
|
+
# An optional context object for method delegation (default: +nil+)
|
|
65
|
+
# [option]
|
|
66
|
+
# Additional options to configure the text message
|
|
67
|
+
# [block]
|
|
68
|
+
# Optional block for configuring quick replies or quote token
|
|
69
|
+
#
|
|
70
|
+
# == Example
|
|
71
|
+
#
|
|
72
|
+
# text = Text.new("Hello!", context: view_context) do
|
|
73
|
+
# quick_reply do
|
|
74
|
+
# button action: :message, label: "Hi", text: "Hi back!"
|
|
75
|
+
# end
|
|
76
|
+
# end
|
|
10
77
|
def initialize(text, context: nil, **options, &block)
|
|
11
78
|
@text = text
|
|
12
79
|
|
|
@@ -15,7 +82,7 @@ module Line
|
|
|
15
82
|
|
|
16
83
|
private
|
|
17
84
|
|
|
18
|
-
def to_api
|
|
85
|
+
def to_api # :nodoc:
|
|
19
86
|
{
|
|
20
87
|
type: "text",
|
|
21
88
|
text: @text,
|
|
@@ -24,7 +91,7 @@ module Line
|
|
|
24
91
|
}.compact
|
|
25
92
|
end
|
|
26
93
|
|
|
27
|
-
def to_sdkv2
|
|
94
|
+
def to_sdkv2 # :nodoc:
|
|
28
95
|
{
|
|
29
96
|
type: "text",
|
|
30
97
|
text: @text,
|
data/lib/line/message/builder.rb
CHANGED
|
@@ -35,19 +35,22 @@ module Line
|
|
|
35
35
|
module_function
|
|
36
36
|
|
|
37
37
|
# Entry point for building a message container.
|
|
38
|
-
# This method initializes a new message
|
|
38
|
+
# This method initializes a new message Container and evaluates the
|
|
39
39
|
# provided block within the context of that container.
|
|
40
40
|
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# helper methods or data within the
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
41
|
+
# [context]
|
|
42
|
+
# An optional context object that can be made available within the builder
|
|
43
|
+
# block. This can be useful for accessing helper methods or data within the
|
|
44
|
+
# block.
|
|
45
|
+
# [mode]
|
|
46
|
+
# The mode to use for building messages. Can be either <code>:api</code> (default) for
|
|
47
|
+
# direct LINE Messaging API format or <code>:sdkv2</code> for LINE Bot SDK v2 compatible
|
|
48
|
+
# format.
|
|
49
|
+
#
|
|
50
|
+
# :yields: container
|
|
51
|
+
#
|
|
52
|
+
# == Example
|
|
53
|
+
#
|
|
51
54
|
# message = Line::Message::Builder.with do
|
|
52
55
|
# text "Hello, world!"
|
|
53
56
|
# end
|
|
@@ -69,11 +69,11 @@ module Line
|
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
def have_line_flex_component(&) # rubocop:disable Naming/
|
|
72
|
+
def have_line_flex_component(&) # rubocop:disable Naming/PredicatePrefix
|
|
73
73
|
HaveFlexComponent.new(&)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
def have_line_flex_box(**options) # rubocop:disable Naming/
|
|
76
|
+
def have_line_flex_box(**options) # rubocop:disable Naming/PredicatePrefix
|
|
77
77
|
options = Utils.stringify_keys!(options, deep: true)
|
|
78
78
|
|
|
79
79
|
HaveFlexComponent.new(expected_desc: "box(#{options.inspect})") do |content|
|
|
@@ -83,7 +83,7 @@ module Line
|
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
def have_line_flex_text(text, **options) # rubocop:disable Naming/
|
|
86
|
+
def have_line_flex_text(text, **options) # rubocop:disable Naming/PredicatePrefix
|
|
87
87
|
options = Utils.stringify_keys!(options, deep: true)
|
|
88
88
|
|
|
89
89
|
HaveFlexComponent.new(expected_desc: "text(#{text.inspect})") do |content|
|
|
@@ -93,7 +93,7 @@ module Line
|
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
def have_line_flex_button(type, **options) # rubocop:disable Naming/
|
|
96
|
+
def have_line_flex_button(type, **options) # rubocop:disable Naming/PredicatePrefix
|
|
97
97
|
options = Utils.stringify_keys!(options, deep: true)
|
|
98
98
|
|
|
99
99
|
HaveFlexComponent.new(expected_desc: "#{type} button(#{options.inspect})") do |content|
|
|
@@ -106,7 +106,7 @@ module Line
|
|
|
106
106
|
end
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
def have_line_flex_image(url, **options) # rubocop:disable Naming/
|
|
109
|
+
def have_line_flex_image(url, **options) # rubocop:disable Naming/PredicatePrefix
|
|
110
110
|
options = Utils.stringify_keys!(options, deep: true)
|
|
111
111
|
|
|
112
112
|
HaveFlexComponent.new(expected_desc: "image(#{url.inspect})") do |content|
|
|
@@ -116,7 +116,17 @@ module Line
|
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
-
def
|
|
119
|
+
def have_line_flex_icon(url, **options) # rubocop:disable Naming/PredicatePrefix
|
|
120
|
+
options = Utils.stringify_keys!(options, deep: true)
|
|
121
|
+
|
|
122
|
+
HaveFlexComponent.new(expected_desc: "icon(#{url.inspect})") do |content|
|
|
123
|
+
next false unless content["type"] == "icon"
|
|
124
|
+
|
|
125
|
+
::RSpec::Matchers::BuiltIn::Include.new({ "url" => url, **options }).matches?(content)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def have_line_flex_span(text, **options) # rubocop:disable Naming/PredicatePrefix
|
|
120
130
|
options = Utils.stringify_keys!(options, deep: true)
|
|
121
131
|
|
|
122
132
|
HaveFlexComponent.new(expected_desc: "span(#{text.inspect})") do |content|
|
|
@@ -5,7 +5,7 @@ module Line
|
|
|
5
5
|
module RSpec
|
|
6
6
|
# :nodoc:
|
|
7
7
|
module Matchers
|
|
8
|
-
def have_line_flex_separator(**options) # rubocop:disable Naming/
|
|
8
|
+
def have_line_flex_separator(**options) # rubocop:disable Naming/PredicatePrefix
|
|
9
9
|
options = Utils.stringify_keys!(options, deep: true)
|
|
10
10
|
|
|
11
11
|
HaveFlexComponent.new(expected_desc: "separator(#{options.inspect})") do |content|
|