line-message-builder 0.7.0 → 0.8.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.
@@ -4,10 +4,23 @@ require_relative "builder/version"
4
4
 
5
5
  module Line
6
6
  module Message
7
- # The Builder module provides a DSL for building LINE messages.
7
+ # The Builder module provides a Domain Specific Language (DSL) for constructing
8
+ # and validating LINE messages. It offers a structured and intuitive way to
9
+ # define various message types, such as text, flex messages, and quick replies,
10
+ # ensuring they adhere to the LINE Messaging API specifications.
11
+ #
12
+ # This module simplifies the process of creating complex message structures
13
+ # by providing a set of builder classes and helper methods.
8
14
  module Builder
15
+ # Base error class for all errors raised by the Line::Message::Builder module.
16
+ # This allows for rescuing any specific builder error or all builder errors.
9
17
  class Error < StandardError; end
18
+ # Error raised when a required attribute or element is missing during message construction.
19
+ # For example, if a text message is created without specifying the text content.
10
20
  class RequiredError < Error; end
21
+ # Error raised when an attribute or element fails validation rules.
22
+ # For example, if a URL provided for an action is invalid or if a text
23
+ # message exceeds the maximum allowed length.
11
24
  class ValidationError < Error; end
12
25
 
13
26
  require_relative "builder/context"
@@ -21,8 +34,25 @@ module Line
21
34
 
22
35
  module_function
23
36
 
24
- def with(context = nil, &)
25
- Container.new(context: context, &)
37
+ # Entry point for building a message container.
38
+ # This method initializes a new message {Container} and evaluates the
39
+ # provided block within the context of that container.
40
+ #
41
+ # @param context [Object, nil] An optional context object that can be made
42
+ # available within the builder block. This can be useful for accessing
43
+ # helper methods or data within the block.
44
+ # @param mode [Symbol] The mode to use for building messages. Can be either
45
+ # `:api` (default) for direct LINE Messaging API format or `:sdkv2` for
46
+ # LINE Bot SDK v2 compatible format.
47
+ # @yield [container] The block is yielded with the newly created {Container}
48
+ # instance, allowing you to define the message structure using the DSL.
49
+ # @return [Container] The initialized message container with the defined structure.
50
+ # @example
51
+ # message = Line::Message::Builder.with do |root|
52
+ # root.text "Hello, world!"
53
+ # end
54
+ def with(context = nil, mode: :api, &)
55
+ Container.new(context: context, mode: mode, &)
26
56
  end
27
57
  end
28
58
  end
@@ -1,3 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # This file serves as the main entry point for RSpec matchers related to the
4
+ # `line-message` gem. When `require "line/message/rspec"` is used in a
5
+ # RSpec test suite, this file is loaded, and it, in turn, loads the
6
+ # necessary files to make the custom matchers available for testing
7
+ # `Line::Message::Builder` objects and their outputs.
8
+ #
9
+ # By requiring this file, developers gain access to specialized matchers
10
+ # designed to simplify the testing of message structures built with
11
+ # `line-message`.
12
+ #
13
+ # @example in `spec_helper.rb` or a specific test file
14
+ # require "line/message/rspec"
15
+ #
16
+ # @see Line::Message::Rspec::Matchers
3
17
  require "line/message/rspec/matchers"
data/llm.txt ADDED
@@ -0,0 +1,356 @@
1
+ # Line Message Builder DSL Documentation
2
+
3
+ This document provides a comprehensive guide on using the Line Message Builder DSL to construct various types of LINE messages.
4
+
5
+ ## Basic Usage
6
+
7
+ To start building messages, use the `Line::Message::Builder.with` method. This method accepts an optional context object and a block where you define your messages.
8
+
9
+ ```ruby
10
+ require 'line/message/builder'
11
+
12
+ messages = Line::Message::Builder.with do
13
+ # ... message definitions go here ...
14
+ end
15
+
16
+ # The `messages` variable will now hold an array of LINE message objects.
17
+ # You can convert them to JSON for sending to the LINE API:
18
+ # json_output = messages.to_json
19
+ ```
20
+
21
+ ### Context
22
+
23
+ The builder can accept a context object. Methods called within the builder block will first attempt to resolve against this context object. This allows for dynamic message content based on your application's data.
24
+
25
+ ```ruby
26
+ class MyCustomContext
27
+ def user_name
28
+ "Alex"
29
+ end
30
+
31
+ def order_status
32
+ "shipped"
33
+ end
34
+ end
35
+
36
+ context = MyCustomContext.new
37
+
38
+ Line::Message::Builder.with(context) do
39
+ text "Hello, #{user_name}! Your order status is: #{order_status}."
40
+ end
41
+ # Generates: "Hello, Alex! Your order status is: shipped."
42
+ ```
43
+ If a method is not found in your custom context, the builder will check its own methods.
44
+
45
+ ### Loops and Conditionals
46
+
47
+ Standard Ruby loops (e.g., `each`, `times`) and conditionals (`if`, `unless`, `case`) can be used directly within the DSL to generate messages dynamically.
48
+
49
+ ```ruby
50
+ Line::Message::Builder.with do
51
+ # Loop example
52
+ ['apple', 'banana', 'cherry'].each do |fruit|
53
+ text "I like #{fruit}."
54
+ end
55
+
56
+ # Conditional example
57
+ user_is_premium = true
58
+ if user_is_premium
59
+ text "Welcome to our premium service!"
60
+ else
61
+ text "Consider upgrading to premium."
62
+ end
63
+ end
64
+ ```
65
+
66
+ ## Text Messages
67
+
68
+ Create simple text messages using the `text` method.
69
+
70
+ ```ruby
71
+ Line::Message::Builder.with do
72
+ text "This is a plain text message."
73
+ text "Another one here."
74
+ end
75
+ ```
76
+ You can also include emojis in text messages. A `quick_reply` can be attached (see Quick Replies section).
77
+
78
+ ## Actions
79
+
80
+ Actions define what happens when a user interacts with a button or a tappable area in a message. They are used in Flex Message components (like buttons, or even entire boxes/images) and Quick Reply buttons.
81
+
82
+ The primary action types defined by helper methods are:
83
+
84
+ ### Message Action
85
+ Sends a text message from the user's perspective.
86
+ - `label`: (String, Required for Flex Buttons, Optional for Quick Reply if `text` is short) The text displayed on the button.
87
+ - `text`: (String, Required) The text message to be sent when the button is tapped.
88
+
89
+ ```ruby
90
+ # Example in a Flex Button (action is a required parameter for button)
91
+ button label: "Say Hello", action: message(label: "Say Hello", text: "Hello there!")
92
+
93
+ # Example in a Quick Reply
94
+ # For quick reply, the first argument to `message` is the text to be sent.
95
+ quick_reply do
96
+ message "Yes, please!", label: "Yes" # label is optional if text is short
97
+ end
98
+ ```
99
+
100
+ ### Postback Action
101
+ Sends a postback event to your bot's webhook. This is useful for triggering backend logic without displaying a message in the chat.
102
+ - `label`: (String, Required for Flex Buttons, Optional for Quick Reply) The text displayed on the button.
103
+ - `data`: (String, Required) The data string sent in the postback event to your webhook.
104
+ - `display_text`: (String, Optional) Text displayed in the chat as if the user had typed it after tapping the button.
105
+
106
+ ```ruby
107
+ # Example in a Flex Button
108
+ button label: "Add to Cart", action: postback(label: "Add to Cart", data: "action=add_item&item_id=101", display_text: "Added to cart!")
109
+
110
+ # Example in a Quick Reply
111
+ quick_reply do
112
+ postback "action=view_profile", label: "View Profile"
113
+ end
114
+ ```
115
+ Other action types like URI, Datetime Picker, Camera, Camera Roll, Location can also be defined by passing a hash that conforms to the LINE API's action object structure directly to the `action` parameter of a component (e.g., `action: { type: :uri, label: "Visit Website", uri: "https://example.com" }`).
116
+
117
+ ## Quick Replies
118
+
119
+ Quick Replies provide users with suggested responses or actions they can tap. They appear at the bottom of the chat screen and are dismissed once a button is tapped. Quick Replies are attached to a message (e.g., `text`, `flex`).
120
+
121
+ To add Quick Replies, nest a `quick_reply` block within a message definition (e.g., inside a `text` or `flex` message block).
122
+
123
+ ```ruby
124
+ Line::Message::Builder.with do
125
+ text "How can I help you today?" do
126
+ quick_reply do
127
+ # Quick Reply buttons defined here
128
+ message "Show products", label: "Products"
129
+ postback "action=contact_support", label: "Support", display_text: "Contacting support..."
130
+ # You can add an optional image_url to quick reply buttons
131
+ message "Special Offers", label: "Offers", image_url: "https://example.com/offer_icon.png"
132
+ end
133
+ end
134
+ end
135
+ ```
136
+
137
+ ### Quick Reply Buttons
138
+ Inside the `quick_reply` block:
139
+ - `message(text, label:, image_url: nil)`:
140
+ - `text`: The message sent by the user.
141
+ - `label:`: The label for the button.
142
+ - `image_url:`: (Optional) URL of an icon for the button (HTTPS, max 1MB, 24x24 pixels recommended).
143
+ - `postback(data, label:, display_text: nil, image_url: nil)`:
144
+ - `data`: Data sent in the postback event.
145
+ - `label:`: The label for the button.
146
+ - `display_text:`: (Optional) Text displayed in chat after tap.
147
+ - `image_url:`: (Optional) URL of an icon.
148
+
149
+ A maximum of 13 quick reply buttons can be attached to a message.
150
+
151
+ ## Flex Messages
152
+
153
+ Flex Messages allow for rich, customizable layouts. They are built using a hierarchy of containers and components. Start a Flex Message with the `flex` method, providing `alt_text` (alternative text shown in chat lists and notifications). A `quick_reply` can also be attached.
154
+
155
+ ```ruby
156
+ Line::Message::Builder.with do
157
+ flex alt_text: "Your order confirmation" do
158
+ # Flex container (bubble or carousel) goes here
159
+ end
160
+ end
161
+ ```
162
+
163
+ ### Flex Message Containers
164
+
165
+ Containers hold the structure of your Flex Message.
166
+
167
+ #### Carousel Container
168
+ A `carousel` holds multiple `bubble` containers, allowing users to swipe horizontally. Maximum of 12 bubbles.
169
+ ```ruby
170
+ flex alt_text: "Product Showcase" do
171
+ carousel do
172
+ bubble do # First bubble
173
+ body { text "First Item" }
174
+ end
175
+ bubble do # Second bubble
176
+ body { text "Second Item" }
177
+ end
178
+ # ... up to 12 bubbles
179
+ end
180
+ end
181
+ ```
182
+
183
+ #### Bubble Container
184
+ A `bubble` is a single message unit within a Flex Message. It can have a header, hero (image/video), body, and footer.
185
+ - `size`: (Symbol, Optional) Specifies the size of the bubble. Common values based on LINE API: `:nano`, `:micro`, `:kilo`, `:mega`, `:giga`. Default size varies depending on context (e.g., a bubble in a carousel might default differently than a standalone bubble).
186
+ - `styles`: (Hash, Optional) Advanced styling for `block` (the bubble itself), `header`, `hero`, `body`, `footer`. Allows specifying CSS-like properties, e.g., `{ footer: { separator: true, separatorColor: '#FF0000' } }`. Refer to official LINE documentation for details on the style object structure.
187
+
188
+ ```ruby
189
+ flex alt_text: "Recipe Card" do
190
+ bubble size: :mega, styles: { footer: { separator: true } } do
191
+ header do
192
+ text "Delicious Pasta", weight: :bold, size: :xl
193
+ end
194
+ # hero_image is a shorthand for a hero box containing a single image component
195
+ hero_image "https://example.com/pasta.jpg", aspect_ratio: "16:9"
196
+ # Alternatively, for a more complex hero:
197
+ # hero do
198
+ # box layout: :vertical do
199
+ # # ... components for hero ...
200
+ # end
201
+ # end
202
+ body do
203
+ box layout: :vertical, spacing: :md do
204
+ text "A classic pasta recipe everyone will love."
205
+ # ... more components ...
206
+ end
207
+ end
208
+ footer do
209
+ button label: "View Recipe", action: { type: :uri, label: "View Recipe", uri: "http://example.com/recipe" }
210
+ end
211
+ end
212
+ end
213
+ ```
214
+
215
+ ### Flex Message Components
216
+
217
+ Components are the building blocks placed inside container sections (`header`, `hero`, `body`, `footer`) or within other `box` components.
218
+
219
+ #### Box Component
220
+ A `box` arranges other components.
221
+ - `layout`: (Symbol, Required) Defines the orientation of children. Valid values: `:horizontal`, `:vertical`, `:baseline`.
222
+ - `contents`: (Array) Implicitly defined by nesting other components within the `box` block.
223
+ - Layout options:
224
+ - `justify_content`: (Symbol, Optional) Horizontal alignment of children within the box. Valid values: `:flex_start`, `:center`, `:flex_end`, `:space_between`, `:space_around`, `:space_evenly`.
225
+ - `align_items`: (Symbol, Optional) Vertical alignment of children within the box. Valid values: `:flex_start`, `:center`, `:flex_end`.
226
+ - `spacing`: (Symbol or String, Optional) Spacing between components within the box. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'10px'`).
227
+ - Positioning:
228
+ - `padding_all`, `padding_top`, `padding_bottom`, `padding_start`, `padding_end`: (Symbol or String, Optional) Padding around the content. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'5px'`).
229
+ - `margin`: (Symbol or String, Optional) Margin around the box itself. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'10px'`).
230
+ - `position`: (Symbol, Optional) Positioning method. Valid values: `:relative`, `:absolute`.
231
+ - `offset_top`, `offset_bottom`, `offset_start`, `offset_end`: (String, Optional) Offset from the edges. E.g., `'10px'`, `'5%'`.
232
+ - Sizing:
233
+ - `width`, `max_width`, `height`, `max_height`: (String, Optional) Pixel or percentage strings (e.g., `'100px'`, `'50%'`).
234
+ - `flex`: (Integer, Optional) Flex factor determining how much space this box takes relative to siblings.
235
+ - `action`: (Action Object, Optional) Makes the entire box tappable. See Actions section.
236
+
237
+ ```ruby
238
+ box layout: :vertical, spacing: :md, padding_all: :lg, action: message(text: "Box tapped!") do
239
+ text "Item 1"
240
+ text "Item 2"
241
+ end
242
+ ```
243
+
244
+ #### Text Component
245
+ Displays text.
246
+ - `text`: (String, Required) The text content.
247
+ - Styling:
248
+ - `wrap`: (Boolean, Optional) `true` to allow text to wrap. Default `false`.
249
+ - `line_spacing`: (String, Optional) Spacing between lines, e.g., `'4px'`, `'1.5em'`.
250
+ - `color`: (String, Optional) Hex color code (e.g., `'#RRGGBB'`, `'#RRGGBBAA'`).
251
+ - Layout:
252
+ - `align`: (Symbol, Optional) Horizontal alignment of the text. Valid values: `:start`, `:center`, `:end`.
253
+ - `gravity`: (Symbol, Optional) Vertical alignment of the text within its allocated space. Valid values: `:top`, `:center`, `:bottom`.
254
+ - `margin`: (Symbol or String, Optional) Margin around the text component. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'10px'`).
255
+ - Sizing:
256
+ - `size`: (Symbol or String, Optional) Font size. Valid keywords: `:xxs`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`, `:3xl`, `:4xl`, `:5xl`. Also accepts pixel values (e.g., `'16px'`).
257
+ - `weight`: (Symbol, Optional) Font weight. Valid values: `:regular`, `:bold`.
258
+ - `flex`: (Integer, Optional) Flex factor.
259
+ - `adjust_mode`: (Symbol, Optional) How text adjusts when it overflows. Valid value: `:shrink_to_fit` (reduces font size).
260
+ - `action`: (Action Object, Optional) Makes the text tappable.
261
+
262
+ ```ruby
263
+ text "Special Offer!", size: :xl, weight: :bold, color: "#FF0000", align: :center, action: postback(data: "offer_details")
264
+ ```
265
+
266
+ #### Button Component
267
+ An actionable button.
268
+ - `action`: (Action Object, **Required**) Defines the action performed on tap. See Actions section.
269
+ - `style`: (Symbol, Optional) Visual style of the button. Valid values: `:primary`, `:secondary`, `:link`. Default is `:link`.
270
+ - `height`: (Symbol, Optional) Height of the button. Valid values: `:sm`, `:md`. Default is `:md`.
271
+ - Layout:
272
+ - `gravity`: (Symbol, Optional) Vertical alignment if the box containing it has extra space. Valid values: `:top`, `:center`, `:bottom`.
273
+ - `margin`: (Symbol or String, Optional) Margin around the button. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'10px'`).
274
+ - Sizing:
275
+ - `flex`: (Integer, Optional) Flex factor.
276
+ - `adjust_mode`: (Symbol, Optional) How the button adjusts its content. Valid value: `:shrink_to_fit`.
277
+
278
+ ```ruby
279
+ button label: "Confirm", style: :primary, height: :md, action: postback(data: "confirm_order", label: "Confirm")
280
+ ```
281
+
282
+ #### Image Component
283
+ Displays an image.
284
+ - `url`: (String, Required) URL of the image (HTTPS).
285
+ - Styling:
286
+ - `aspect_ratio`: (String, Optional) Aspect ratio as `"width:height"`, e.g., `"1:1"`, `"16:9"`, `"4:3"`.
287
+ - `aspect_mode`: (Symbol, Optional) How the image fits the `aspect_ratio`. Valid values: `:cover` (default, crops to fill) or `:fit` (fits within, may letterbox).
288
+ - Layout:
289
+ - `align`: (Symbol, Optional) Horizontal alignment of the image. Valid values: `:start`, `:center`, `:end`.
290
+ - `gravity`: (Symbol, Optional) Vertical alignment of the image. Valid values: `:top`, `:center`, `:bottom`.
291
+ - `margin`: (Symbol or String, Optional) Margin around the image. Valid keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`. Also accepts pixel values (e.g., `'10px'`).
292
+ - Sizing:
293
+ - `size`: (Symbol or String, Optional) Size of the image. Valid keywords: `:xxs`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`, `:3xl`, `:4xl`, `:5xl`, `:full`. Also accepts pixel or percentage strings (e.g. `'100px'`, `'50%'`).
294
+ - `flex`: (Integer, Optional) Flex factor.
295
+ - `action`: (Action Object, Optional) Makes the image tappable.
296
+
297
+ ```ruby
298
+ image "https://example.com/product_image.png", size: :full, aspect_ratio: "1:1", aspect_mode: :cover, action: message(text: "View product")
299
+ ```
300
+
301
+ #### Separators and Spacers
302
+
303
+ The LINE Flex Message specification includes `separator` and `spacer` component types. This DSL does not provide explicit `separator()` or `spacer()` methods. Instead:
304
+
305
+ - **Separators**: Achieve a visual line by using a `box` component styled to look like a separator. Set its `height` (for horizontal line) or `width` (for vertical line) to a small value (e.g., `"1px"`) and give it a `background_color`.
306
+ ```ruby
307
+ # Example of a horizontal separator
308
+ box layout: :vertical, padding_all: :md do # Outer box for content
309
+ text "Content above separator"
310
+ box height: "1px", background_color: "#CCCCCC", margin: :md # This is the separator
311
+ text "Content below separator"
312
+ end
313
+ ```
314
+ - **Spacers**: Create space between components using:
315
+ - `spacing` property on a parent `box` container.
316
+ - `margin` property on individual components (e.g., `text "Hello", margin: :xl`).
317
+ - An empty `box` with a defined `flex` value or `height`/`width` (e.g., `box height: "30px"`).
318
+
319
+ ### Flex Message Partials
320
+
321
+ Partials allow you to define reusable segments of Flex Message layouts. This is useful for complex components that appear multiple times.
322
+
323
+ 1. **Define a Partial Class**: Create a class that inherits from `Line::Message::Builder::Flex::Partial`. Implement a `call` method where you use the DSL to define the partial's content.
324
+ ```ruby
325
+ class MyCustomPartial < Line::Message::Builder::Flex::Partial
326
+ def call
327
+ # You can use Flex DSL methods here (box, text, button, etc.)
328
+ # Access passed variables via methods (e.g., `title_text`, `button_label`)
329
+ # which are made available from the `assigns` hash passed to `partial!`.
330
+ box layout: :vertical do
331
+ text title_text, weight: :bold # 'title_text' from assigns
332
+ button label: button_label, action: message(text: "Action for #{title_text}") # 'button_label' from assigns
333
+ end
334
+ end
335
+ end
336
+ ```
337
+
338
+ 2. **Use the Partial**: Call `partial!` within a Flex container or component block. Pass variables to the partial as keyword arguments (assigns).
339
+ ```ruby
340
+ Line::Message::Builder.with do
341
+ flex alt_text: "Partials Example" do
342
+ bubble do
343
+ body do
344
+ # Using the partial
345
+ partial! MyCustomPartial, title_text: "Section 1", button_label: "Go to 1"
346
+ # Separator Box
347
+ box height: "1px", background_color: "#EEEEEE", margin: :md
348
+ partial! MyCustomPartial, title_text: "Section 2", button_label: "Explore 2"
349
+ end
350
+ end
351
+ end
352
+ end
353
+ ```
354
+ Inside the partial, variables passed via `partial!` (e.g., `title_text`, `button_label`) are accessible as methods.
355
+
356
+ This comprehensive guide should help in effectively using the Line Message Builder DSL. For very specific or advanced features, always refer to the official LINE Messaging API documentation for Flex Messages.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: line-message-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya
@@ -16,6 +16,7 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".document"
19
20
  - ".release-please-manifest.json"
20
21
  - ".rspec"
21
22
  - ".rubocop.yml"
@@ -57,6 +58,7 @@ files:
57
58
  - lib/line/message/rspec/matchers/have_quick_reply.rb
58
59
  - lib/line/message/rspec/matchers/have_text_message.rb
59
60
  - lib/line/message/rspec/matchers/utils.rb
61
+ - llm.txt
60
62
  - release-please-config.json
61
63
  - sig/line/message/builder.rbs
62
64
  homepage: https://github.com/elct9620/line-message-builder