line-message-builder 0.3.0 → 0.5.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/.rspec +2 -0
- data/CHANGELOG.md +34 -0
- data/README.md +24 -14
- data/lib/line/message/builder/actions/message.rb +9 -12
- data/lib/line/message/builder/actions/postback.rb +10 -17
- data/lib/line/message/builder/base.rb +3 -2
- data/lib/line/message/builder/container.rb +4 -4
- data/lib/line/message/builder/flex/actionable.rb +24 -0
- data/lib/line/message/builder/flex/box.rb +43 -4
- data/lib/line/message/builder/flex/bubble.rb +7 -2
- data/lib/line/message/builder/flex/builder.rb +2 -2
- data/lib/line/message/builder/flex/button.rb +29 -19
- data/lib/line/message/builder/flex/image.rb +28 -16
- data/lib/line/message/builder/flex/position.rb +68 -0
- data/lib/line/message/builder/flex/text.rb +30 -10
- data/lib/line/message/builder/flex.rb +2 -0
- data/lib/line/message/builder/quick_reply.rb +2 -2
- data/lib/line/message/builder/text.rb +5 -2
- data/lib/line/message/builder/validators/enum.rb +24 -0
- data/lib/line/message/builder/validators/size.rb +39 -0
- data/lib/line/message/builder/validators.rb +13 -0
- data/lib/line/message/builder/version.rb +1 -1
- data/lib/line/message/builder.rb +3 -0
- data/lib/line/message/rspec/matchers/have_flex_bubble.rb +60 -0
- data/lib/line/message/rspec/matchers/have_text_message.rb +13 -9
- data/lib/line/message/rspec/matchers.rb +1 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8051ec09aa3f71ec93dc5cbe685610fd6fe6d5c4a3b086f5b5ddbef6b98e7c3c
|
4
|
+
data.tar.gz: cd043754cc232ed8b4e8cec6751413bf2f87e9cd3ea4b23f521346cb1ca7a86d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d951b1938f6a27ad366e5b4f08e1de7496c5d130ac95e40d4f15c2ca86a928a19a5cfb46184d958dae6afd664dfa68d4c50a2d7e00c172445e42205e3987abc
|
7
|
+
data.tar.gz: 802c37d5e9d2beb7f641046bf8223e9a4fc26290b5e9f1a5a07b1754027509b1b2b63952be93622908674d14321fe9c4cceea770aaf2d56684caaa94b1bb7d69
|
@@ -1 +1 @@
|
|
1
|
-
{".":"0.
|
1
|
+
{".":"0.5.0"}
|
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.5.0](https://github.com/elct9620/line-message-builder/compare/v0.4.0...v0.5.0) (2025-04-07)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* Add Actionable module for flex components with message and postback actions ([9ac4b4a](https://github.com/elct9620/line-message-builder/commit/9ac4b4af591450e8f1925814b5a57e893ffa15db))
|
9
|
+
* Add enum validator for flex text alignment options ([540c58d](https://github.com/elct9620/line-message-builder/commit/540c58d94731adfe91d30e006bb0ee6714755006))
|
10
|
+
* Add justify_content and align_items options to Flex Box builder ([6c2015f](https://github.com/elct9620/line-message-builder/commit/6c2015f0a75a0f541cb52fef647e0bff1a245a28))
|
11
|
+
* Add layout validation for flex box with enum validator ([b1ecba1](https://github.com/elct9620/line-message-builder/commit/b1ecba160db03f94aaebc83b82158e75292c94eb))
|
12
|
+
* Add margin support for flex components in Line message builder ([36043b8](https://github.com/elct9620/line-message-builder/commit/36043b8d7390cb13d60174759fc5906a70aa2507))
|
13
|
+
* Add offset positioning support for flex message components ([1e28336](https://github.com/elct9620/line-message-builder/commit/1e2833656083aa72b0cfffccd5636e80ae41ccc9))
|
14
|
+
* Add padding support for flex box components with validation ([9dcd9d2](https://github.com/elct9620/line-message-builder/commit/9dcd9d20a48aed023440a2abe24e8b44eea8b425))
|
15
|
+
* Add padding support for Line Flex buttons with validation ([ca25a11](https://github.com/elct9620/line-message-builder/commit/ca25a1192c0d611ae064f935fc9335640d123b2d))
|
16
|
+
* Add SimpleCov Cobertura formatter for CI coverage reporting ([bb5bfc8](https://github.com/elct9620/line-message-builder/commit/bb5bfc8344c1b448e61a2857aa36e1f6b5ce0425))
|
17
|
+
* Add validator for spacing option in flex box builder ([06e7b98](https://github.com/elct9620/line-message-builder/commit/06e7b9805f8243c51faaf9c13c264ffb1f35091c))
|
18
|
+
* Add vertical positioning support for Flex message components ([f9ce97b](https://github.com/elct9620/line-message-builder/commit/f9ce97b666cabe47717cdd916722121372cb9bf0))
|
19
|
+
|
20
|
+
|
21
|
+
### Bug Fixes
|
22
|
+
|
23
|
+
* Correct indentation in GitHub Actions workflow file ([1c1cd2d](https://github.com/elct9620/line-message-builder/commit/1c1cd2dfe2e48bd937a04ac25f7b2b772e02e1a6))
|
24
|
+
|
25
|
+
## [0.4.0](https://github.com/elct9620/line-message-builder/compare/v0.3.0...v0.4.0) (2025-04-06)
|
26
|
+
|
27
|
+
|
28
|
+
### Features
|
29
|
+
|
30
|
+
* Add flex and margin options to Line Flex Button with improved error handling ([c8cd142](https://github.com/elct9620/line-message-builder/commit/c8cd1427528d5495d13bf93898da4638588065ae))
|
31
|
+
* Add flex box options and validation for LINE message builder ([133f87d](https://github.com/elct9620/line-message-builder/commit/133f87ddb3fd2a093947db0aef6363cd4c150701))
|
32
|
+
* Add flex bubble options and RSpec matcher for Line message builder ([605ad89](https://github.com/elct9620/line-message-builder/commit/605ad89870a53c55182f96db5f2738b5c347f0dc))
|
33
|
+
* Add margin option to flex text builder ([1d44522](https://github.com/elct9620/line-message-builder/commit/1d44522a44218bedab3d2009ef483ed112784248))
|
34
|
+
* Add quote token support for Line text messages ([7871999](https://github.com/elct9620/line-message-builder/commit/7871999dfc7032e75e5407c8b16bed7ef7dd28b8))
|
35
|
+
* Add support for flex, margin, and align options in Flex image builder ([693d0ab](https://github.com/elct9620/line-message-builder/commit/693d0abf5ef524b2e6d075f3c7e65eca49cf7f27))
|
36
|
+
|
3
37
|
## [0.3.0](https://github.com/elct9620/line-message-builder/compare/v0.2.0...v0.3.0) (2025-04-05)
|
4
38
|
|
5
39
|
|
data/README.md
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
# LINE Message Builder
|
2
2
|
|
3
|
+
[](https://github.com/elct9620/line-message-builder/actions/workflows/main.yml)
|
4
|
+
[](https://codecov.io/gh/elct9620/line-message-builder)
|
5
|
+
|
3
6
|
Build LINE messages using DSL (Domain Specific Language) in Ruby.
|
4
7
|
|
8
|
+
## Features
|
9
|
+
|
10
|
+
- Build LINE messages using DSL
|
11
|
+
- Validation of properties
|
12
|
+
- RSpec matchers for testing
|
13
|
+
|
5
14
|
## Installation
|
6
15
|
|
7
16
|
Install the gem and add to the application's Gemfile by executing:
|
@@ -95,6 +104,7 @@ end
|
|
95
104
|
| --------------------------- | ------------------------------------ |
|
96
105
|
| `have_line_text_message` | Match a text message |
|
97
106
|
| `have_line_flex_message` | Match a flex message |
|
107
|
+
| `have_line_flex_bubble` | Match a flex message with bubble |
|
98
108
|
| `have_line_flex_text` | Match a flex message with text |
|
99
109
|
| `have_line_flex_image` | Match a flex message with image |
|
100
110
|
| `have_line_flex_button` | Match a flex message with button |
|
@@ -154,7 +164,7 @@ end
|
|
154
164
|
|
155
165
|
| Type | Supported |
|
156
166
|
| ---- | --------- |
|
157
|
-
| Text |
|
167
|
+
| Text | 🚧 |
|
158
168
|
| Text v2 | ❌ |
|
159
169
|
| Sticker | ❌ |
|
160
170
|
| Sticker | ❌ |
|
@@ -189,19 +199,19 @@ end
|
|
189
199
|
|
190
200
|
### Flex Components
|
191
201
|
|
192
|
-
| Component | Supported
|
193
|
-
| --------- | ---------
|
194
|
-
| Bubble | 🚧
|
195
|
-
| Carousel | ❌
|
196
|
-
| Box | 🚧
|
197
|
-
| Button | 🚧
|
198
|
-
| Image | 🚧
|
199
|
-
| Video | ❌
|
200
|
-
| Icon | ❌
|
201
|
-
| Text | 🚧
|
202
|
-
| Span | ❌
|
203
|
-
| Separator | ❌
|
204
|
-
| Filler | ❌
|
202
|
+
| Component | Supported |
|
203
|
+
| --------- | --------- |
|
204
|
+
| Bubble | 🚧 |
|
205
|
+
| Carousel | ❌ |
|
206
|
+
| Box | 🚧 |
|
207
|
+
| Button | 🚧 |
|
208
|
+
| Image | 🚧 |
|
209
|
+
| Video | ❌ |
|
210
|
+
| Icon | ❌ |
|
211
|
+
| Text | 🚧 |
|
212
|
+
| Span | ❌ |
|
213
|
+
| Separator | ❌ |
|
214
|
+
| Filler | ❌ Deprecated |
|
205
215
|
|
206
216
|
## Development
|
207
217
|
|
@@ -6,26 +6,23 @@ module Line
|
|
6
6
|
module Actions
|
7
7
|
# The Message class is used to build message actions for quick replies.
|
8
8
|
class Message < Line::Message::Builder::Base
|
9
|
-
|
10
|
-
@text = text
|
11
|
-
@label = label
|
12
|
-
|
13
|
-
super(context: context, &)
|
14
|
-
end
|
9
|
+
attr_reader :text
|
15
10
|
|
16
|
-
|
17
|
-
@label = label
|
18
|
-
end
|
11
|
+
option :label, default: nil
|
19
12
|
|
20
|
-
def
|
13
|
+
def initialize(text, context: nil, **options, &)
|
21
14
|
@text = text
|
15
|
+
|
16
|
+
super(context: context, **options, &)
|
22
17
|
end
|
23
18
|
|
24
19
|
def to_h
|
20
|
+
raise RequiredError, "text is required" if text.nil?
|
21
|
+
|
25
22
|
{
|
26
23
|
type: "message",
|
27
|
-
label:
|
28
|
-
text:
|
24
|
+
label: label,
|
25
|
+
text: text
|
29
26
|
}.compact
|
30
27
|
end
|
31
28
|
end
|
@@ -6,32 +6,25 @@ module Line
|
|
6
6
|
module Actions
|
7
7
|
# The Postback class is used to build postback actions for quick replies.
|
8
8
|
class Postback < Line::Message::Builder::Base
|
9
|
-
|
10
|
-
@data = data
|
11
|
-
@label = label
|
12
|
-
@display_text = display_text
|
13
|
-
|
14
|
-
super(context: context, &)
|
15
|
-
end
|
9
|
+
attr_reader :data
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
11
|
+
option :label, default: nil
|
12
|
+
option :display_text, default: nil
|
20
13
|
|
21
|
-
def
|
14
|
+
def initialize(data, context: nil, **options, &)
|
22
15
|
@data = data
|
23
|
-
end
|
24
16
|
|
25
|
-
|
26
|
-
@display_text = display_text
|
17
|
+
super(context: context, **options, &)
|
27
18
|
end
|
28
19
|
|
29
20
|
def to_h
|
21
|
+
raise RequiredError, "data is required" if data.nil?
|
22
|
+
|
30
23
|
{
|
31
24
|
type: "postback",
|
32
|
-
label:
|
33
|
-
data:
|
34
|
-
displayText:
|
25
|
+
label: label,
|
26
|
+
data: data,
|
27
|
+
displayText: display_text
|
35
28
|
}.compact
|
36
29
|
end
|
37
30
|
end
|
@@ -18,13 +18,14 @@ module Line
|
|
18
18
|
@options ||= []
|
19
19
|
end
|
20
20
|
|
21
|
-
def option(name, default: nil)
|
21
|
+
def option(name, default: nil, validator: nil)
|
22
22
|
options << name
|
23
23
|
|
24
24
|
define_method name do |*args|
|
25
25
|
if args.empty?
|
26
26
|
instance_variable_get("@#{name}") || default
|
27
27
|
else
|
28
|
+
validator&.valid!(args.first)
|
28
29
|
instance_variable_set("@#{name}", args.first)
|
29
30
|
end
|
30
31
|
end
|
@@ -38,7 +39,7 @@ module Line
|
|
38
39
|
@quick_reply = nil
|
39
40
|
|
40
41
|
self.class.options.each do |option|
|
41
|
-
|
42
|
+
send(option, options[option]) if options.key?(option)
|
42
43
|
end
|
43
44
|
|
44
45
|
instance_eval(&block) if ::Kernel.block_given?
|
@@ -13,12 +13,12 @@ module Line
|
|
13
13
|
super
|
14
14
|
end
|
15
15
|
|
16
|
-
def text(text, &)
|
17
|
-
@messages << Text.new(text, context: context, &)
|
16
|
+
def text(text, **options, &)
|
17
|
+
@messages << Text.new(text, context: context, **options, &)
|
18
18
|
end
|
19
19
|
|
20
|
-
def flex(**
|
21
|
-
@messages << Flex::Builder.new(
|
20
|
+
def flex(**options, &)
|
21
|
+
@messages << Flex::Builder.new(context: context, **options, &)
|
22
22
|
end
|
23
23
|
|
24
24
|
def build
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Line
|
4
|
+
module Message
|
5
|
+
module Builder
|
6
|
+
module Flex
|
7
|
+
# The action DSL for flex components.
|
8
|
+
module Actionable
|
9
|
+
def self.included(base)
|
10
|
+
base.attr_reader :action
|
11
|
+
end
|
12
|
+
|
13
|
+
def message(text, **options, &)
|
14
|
+
@action = Actions::Message.new(text, context: context, **options, &)
|
15
|
+
end
|
16
|
+
|
17
|
+
def postback(data, **options, &)
|
18
|
+
@action = Actions::Postback.new(data, context: context, **options, &)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -6,7 +6,24 @@ module Line
|
|
6
6
|
module Flex
|
7
7
|
# The box is a component for the Flex message.
|
8
8
|
class Box < Line::Message::Builder::Base
|
9
|
-
|
9
|
+
include Actionable
|
10
|
+
include Position::Padding
|
11
|
+
include Position::Margin
|
12
|
+
include Position::Offset
|
13
|
+
|
14
|
+
attr_reader :contents
|
15
|
+
|
16
|
+
option :layout, default: :horizontal, validator: Validators::Enum.new(
|
17
|
+
:horizontal, :vertical, :baseline
|
18
|
+
)
|
19
|
+
option :justify_content, default: nil, validator: Validators::Enum.new(
|
20
|
+
:flex_start, :center, :flex_end, :space_between, :space_around, :space_evenly
|
21
|
+
)
|
22
|
+
option :align_items, default: nil, validator: Validators::Enum.new(
|
23
|
+
:flex_start, :center, :flex_end
|
24
|
+
)
|
25
|
+
option :spacing, default: nil, validator: Validators::Size.new
|
26
|
+
option :flex, default: nil
|
10
27
|
|
11
28
|
def initialize(context: nil, **options, &)
|
12
29
|
@contents = []
|
@@ -30,11 +47,33 @@ module Line
|
|
30
47
|
@contents << Flex::Image.new(url, context: context, **options, &)
|
31
48
|
end
|
32
49
|
|
33
|
-
def to_h
|
50
|
+
def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
51
|
+
raise RequiredError, "layout is required" if layout.nil?
|
52
|
+
|
34
53
|
{
|
35
54
|
type: "box",
|
36
|
-
layout:
|
37
|
-
|
55
|
+
layout: layout,
|
56
|
+
# Position
|
57
|
+
justifyContent: justify_content,
|
58
|
+
alignItems: align_items,
|
59
|
+
spacing: spacing,
|
60
|
+
# Position::Padding
|
61
|
+
paddingAll: padding,
|
62
|
+
paddingTop: padding_top,
|
63
|
+
paddingBottom: padding_bottom,
|
64
|
+
paddingStart: padding_start,
|
65
|
+
paddingEnd: padding_end,
|
66
|
+
# Position::Margin
|
67
|
+
margin: margin,
|
68
|
+
# Position::Offset
|
69
|
+
position: position,
|
70
|
+
offsetTop: offset_top,
|
71
|
+
offsetBottom: offset_bottom,
|
72
|
+
offsetStart: offset_start,
|
73
|
+
offsetEnd: offset_end,
|
74
|
+
flex: flex,
|
75
|
+
contents: contents.map(&:to_h),
|
76
|
+
action: action&.to_h
|
38
77
|
}.compact
|
39
78
|
end
|
40
79
|
end
|
@@ -6,7 +6,10 @@ module Line
|
|
6
6
|
module Flex
|
7
7
|
# The bubble is container for the Flex message.
|
8
8
|
class Bubble < Line::Message::Builder::Base
|
9
|
-
|
9
|
+
option :size, default: nil
|
10
|
+
option :styles, default: nil
|
11
|
+
|
12
|
+
def initialize(context: nil, **options, &)
|
10
13
|
@header = nil
|
11
14
|
@hero = nil
|
12
15
|
@body = nil
|
@@ -41,7 +44,9 @@ module Line
|
|
41
44
|
header: @header&.to_h,
|
42
45
|
hero: @hero&.to_h,
|
43
46
|
body: @body&.to_h,
|
44
|
-
footer: @footer&.to_h
|
47
|
+
footer: @footer&.to_h,
|
48
|
+
size: size,
|
49
|
+
styles: styles
|
45
50
|
}.compact
|
46
51
|
end
|
47
52
|
end
|
@@ -14,8 +14,8 @@ module Line
|
|
14
14
|
super
|
15
15
|
end
|
16
16
|
|
17
|
-
def bubble(&)
|
18
|
-
@contents = Line::Message::Builder::Flex::Bubble.new(context: context, &)
|
17
|
+
def bubble(**options, &)
|
18
|
+
@contents = Line::Message::Builder::Flex::Bubble.new(context: context, **options, &)
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_h
|
@@ -6,31 +6,41 @@ module Line
|
|
6
6
|
module Flex
|
7
7
|
# The button is a component of the Flex message.
|
8
8
|
class Button < Line::Message::Builder::Base
|
9
|
+
include Actionable
|
10
|
+
include Position::Vertical
|
11
|
+
include Position::Padding
|
12
|
+
include Position::Margin
|
13
|
+
include Position::Offset
|
14
|
+
|
15
|
+
option :flex, default: nil
|
9
16
|
option :style, default: :link
|
10
17
|
option :height, default: :md
|
11
18
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
super
|
16
|
-
end
|
17
|
-
|
18
|
-
def message(text, label:, display_text: nil, &)
|
19
|
-
@action = Actions::Message.new(text: text, label: label, display_text: display_text, &)
|
20
|
-
end
|
21
|
-
|
22
|
-
def postback(data, label: nil, display_text: nil, &)
|
23
|
-
@action = Actions::Postback.new(data: data, label: label, display_text: display_text, &)
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_h
|
27
|
-
raise Error, "Action is required" unless @action
|
19
|
+
def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
20
|
+
raise RequiredError, "action is required" if action.nil?
|
28
21
|
|
29
22
|
{
|
30
23
|
type: "button",
|
31
|
-
action:
|
32
|
-
|
33
|
-
|
24
|
+
action: action.to_h,
|
25
|
+
# Position
|
26
|
+
grivity: gravity,
|
27
|
+
# Position::Padding
|
28
|
+
paddingAll: padding,
|
29
|
+
paddingTop: padding_top,
|
30
|
+
paddingBottom: padding_bottom,
|
31
|
+
paddingStart: padding_start,
|
32
|
+
paddingEnd: padding_end,
|
33
|
+
# Position::Margin
|
34
|
+
margin: margin,
|
35
|
+
# Position::Offset
|
36
|
+
position: position,
|
37
|
+
offsetTop: offset_top,
|
38
|
+
offsetBottom: offset_bottom,
|
39
|
+
offsetStart: offset_start,
|
40
|
+
offsetEnd: offset_end,
|
41
|
+
flex: flex,
|
42
|
+
style: style,
|
43
|
+
height: height
|
34
44
|
}.compact
|
35
45
|
end
|
36
46
|
end
|
@@ -6,9 +6,18 @@ module Line
|
|
6
6
|
module Flex
|
7
7
|
# The image is a component for the Flex message.
|
8
8
|
class Image < Line::Message::Builder::Base
|
9
|
+
include Actionable
|
10
|
+
include Position::Horizontal
|
11
|
+
include Position::Vertical
|
12
|
+
include Position::Margin
|
13
|
+
include Position::Offset
|
14
|
+
|
15
|
+
attr_reader :url
|
16
|
+
|
9
17
|
option :size, default: nil
|
10
18
|
option :aspect_ratio, default: nil
|
11
19
|
option :aspect_mode, default: nil
|
20
|
+
option :flex, default: nil
|
12
21
|
|
13
22
|
def initialize(url, context: nil, **options, &)
|
14
23
|
@url = url
|
@@ -16,25 +25,28 @@ module Line
|
|
16
25
|
super(context: context, **options, &)
|
17
26
|
end
|
18
27
|
|
19
|
-
def
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def aspect_ratio(aspect_ratio)
|
24
|
-
@aspect_ratio = aspect_ratio
|
25
|
-
end
|
26
|
-
|
27
|
-
def aspect_mode(aspect_mode)
|
28
|
-
@aspect_mode = aspect_mode
|
29
|
-
end
|
28
|
+
def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
29
|
+
raise RequiredError, "url is required" if url.nil?
|
30
30
|
|
31
|
-
def to_h
|
32
31
|
{
|
33
32
|
type: "image",
|
34
|
-
url:
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
url: url,
|
34
|
+
# Position
|
35
|
+
align: align,
|
36
|
+
gravity: gravity,
|
37
|
+
# Position::Margin
|
38
|
+
margin: margin,
|
39
|
+
# Position::Offset
|
40
|
+
position: position,
|
41
|
+
offsetTop: offset_top,
|
42
|
+
offsetBottom: offset_bottom,
|
43
|
+
offsetStart: offset_start,
|
44
|
+
offsetEnd: offset_end,
|
45
|
+
size: size,
|
46
|
+
flex: flex,
|
47
|
+
aspectRatio: aspect_ratio,
|
48
|
+
aspectMode: aspect_mode,
|
49
|
+
action: action&.to_h
|
38
50
|
}.compact
|
39
51
|
end
|
40
52
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Line
|
4
|
+
module Message
|
5
|
+
module Builder
|
6
|
+
module Flex
|
7
|
+
module Position
|
8
|
+
# The horizontal provides "align" options for flex components.
|
9
|
+
module Horizontal
|
10
|
+
def self.included(base)
|
11
|
+
base.option :align,
|
12
|
+
default: :nil,
|
13
|
+
validator: Validators::Enum.new(
|
14
|
+
:start, :center, :end
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# The vertical provides "gatvity" options for flex components.
|
20
|
+
module Vertical
|
21
|
+
def self.included(base)
|
22
|
+
base.option :gravity,
|
23
|
+
default: :nil,
|
24
|
+
validator: Validators::Enum.new(
|
25
|
+
:top, :center, :bottom
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# The padding provides "padding" options for flex components.
|
31
|
+
module Padding
|
32
|
+
def self.included(base)
|
33
|
+
%i[padding padding_top padding_bottom padding_start padding_end].each do |option|
|
34
|
+
base.option option,
|
35
|
+
default: :nil,
|
36
|
+
validator: Validators::PercentageSize.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The margin provides "margin" options for flex components.
|
42
|
+
module Margin
|
43
|
+
def self.included(base)
|
44
|
+
base.option :margin,
|
45
|
+
default: :nil,
|
46
|
+
validator: Validators::Size.new
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# The offset provides "offset" options for flex components.
|
51
|
+
module Offset
|
52
|
+
def self.included(base)
|
53
|
+
base.option :position,
|
54
|
+
default: :nil,
|
55
|
+
validator: Validators::Enum.new(:absolute, :relative)
|
56
|
+
|
57
|
+
%i[offset_top offset_bottom offset_start offset_end].each do |option|
|
58
|
+
base.option option,
|
59
|
+
default: :nil,
|
60
|
+
validator: Validators::Size.new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -6,11 +6,18 @@ module Line
|
|
6
6
|
module Flex
|
7
7
|
# The text is a component of the Flex message.
|
8
8
|
class Text < Line::Message::Builder::Base
|
9
|
+
include Actionable
|
10
|
+
include Position::Horizontal
|
11
|
+
include Position::Vertical
|
12
|
+
include Position::Margin
|
13
|
+
include Position::Offset
|
14
|
+
|
15
|
+
attr_reader :text
|
16
|
+
|
17
|
+
option :size, default: nil
|
9
18
|
option :wrap, default: false
|
10
19
|
option :line_spacing, default: nil
|
11
20
|
option :color, default: nil
|
12
|
-
option :size, default: nil
|
13
|
-
option :align, default: nil
|
14
21
|
option :flex, default: nil
|
15
22
|
|
16
23
|
def initialize(text, context: nil, **options, &)
|
@@ -23,16 +30,29 @@ module Line
|
|
23
30
|
@wrap = true
|
24
31
|
end
|
25
32
|
|
26
|
-
def to_h
|
33
|
+
def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
34
|
+
raise RequiredError, "text is required" if text.nil?
|
35
|
+
|
27
36
|
{
|
28
37
|
type: "text",
|
29
|
-
text:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
text: text,
|
39
|
+
# Position
|
40
|
+
align: align,
|
41
|
+
gravity: gravity,
|
42
|
+
# Position::Margin
|
43
|
+
margin: margin,
|
44
|
+
# Position::Offset
|
45
|
+
position: position,
|
46
|
+
offsetTop: offset_top,
|
47
|
+
offsetBottom: offset_bottom,
|
48
|
+
offsetStart: offset_start,
|
49
|
+
offsetEnd: offset_end,
|
50
|
+
wrap: wrap,
|
51
|
+
lineSpacing: line_spacing,
|
52
|
+
color: color,
|
53
|
+
size: size,
|
54
|
+
flex: flex,
|
55
|
+
action: action&.to_h
|
36
56
|
}.compact
|
37
57
|
end
|
38
58
|
end
|
@@ -13,14 +13,14 @@ module Line
|
|
13
13
|
|
14
14
|
def message(text, label:, image_url: nil, &)
|
15
15
|
action(
|
16
|
-
Actions::Message.new(text
|
16
|
+
Actions::Message.new(text, label: label, &),
|
17
17
|
image_url
|
18
18
|
)
|
19
19
|
end
|
20
20
|
|
21
21
|
def postback(data, label: nil, display_text: nil, image_url: nil, &)
|
22
22
|
action(
|
23
|
-
Actions::Postback.new(data
|
23
|
+
Actions::Postback.new(data, label: label, display_text: display_text, &),
|
24
24
|
image_url
|
25
25
|
)
|
26
26
|
end
|
@@ -5,16 +5,19 @@ module Line
|
|
5
5
|
module Builder
|
6
6
|
# Text message builder.
|
7
7
|
class Text < Base
|
8
|
-
|
8
|
+
option :quote_token, default: nil
|
9
|
+
|
10
|
+
def initialize(text, context: nil, **options, &block)
|
9
11
|
@text = text
|
10
12
|
|
11
|
-
super(context: context, &block)
|
13
|
+
super(context: context, **options, &block)
|
12
14
|
end
|
13
15
|
|
14
16
|
def to_h
|
15
17
|
{
|
16
18
|
type: "text",
|
17
19
|
text: @text,
|
20
|
+
quoteToken: quote_token,
|
18
21
|
quickReply: @quick_reply&.to_h
|
19
22
|
}.compact
|
20
23
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Line
|
4
|
+
module Message
|
5
|
+
module Builder
|
6
|
+
module Validators
|
7
|
+
# Validate values against a set of allowed values.
|
8
|
+
class Enum
|
9
|
+
attr_reader :allowed_values
|
10
|
+
|
11
|
+
def initialize(*allowed_values)
|
12
|
+
@allowed_values = allowed_values
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid!(value)
|
16
|
+
return if allowed_values.include?(value.to_sym)
|
17
|
+
|
18
|
+
raise ValidationError, "Invalid value: #{value}. Allowed values are: #{allowed_values.join(", ")}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Line
|
4
|
+
module Message
|
5
|
+
module Builder
|
6
|
+
module Validators
|
7
|
+
# Validate size values for LINE messages.
|
8
|
+
class Size
|
9
|
+
KEYWORDS = %i[none xs sm md lg xl xxl].freeze
|
10
|
+
|
11
|
+
def valid?(value)
|
12
|
+
is_keyword = KEYWORDS.include?(value.to_sym)
|
13
|
+
is_pixels = value.end_with?("px")
|
14
|
+
is_keyword || is_pixels
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid!(value)
|
18
|
+
return if valid?(value)
|
19
|
+
|
20
|
+
raise ValidationError,
|
21
|
+
"Invalid value: #{value}. Allowed values are: #{KEYWORDS.join(", ")} or a pixel value (e.g., '100px')"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Validate size values with percentage.
|
26
|
+
class PercentageSize < Size
|
27
|
+
def valid!(value)
|
28
|
+
is_percentage = value.end_with?("%")
|
29
|
+
return if is_percentage || valid?(value)
|
30
|
+
|
31
|
+
raise ValidationError,
|
32
|
+
"Invalid value: #{value}. Allowed values are: #{KEYWORDS.join(", ")}, " \
|
33
|
+
"a pixel value (e.g., '100px'), or a percentage (e.g., '50%')"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/line/message/builder.rb
CHANGED
@@ -7,8 +7,11 @@ module Line
|
|
7
7
|
# The Builder module provides a DSL for building LINE messages.
|
8
8
|
module Builder
|
9
9
|
class Error < StandardError; end
|
10
|
+
class RequiredError < Error; end
|
11
|
+
class ValidationError < Error; end
|
10
12
|
|
11
13
|
require_relative "builder/base"
|
14
|
+
require_relative "builder/validators"
|
12
15
|
require_relative "builder/actions"
|
13
16
|
require_relative "builder/quick_reply"
|
14
17
|
require_relative "builder/container"
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Line
|
4
|
+
module Message
|
5
|
+
module RSpec
|
6
|
+
# :nodoc:
|
7
|
+
module Matchers
|
8
|
+
# The flex component matcher for RSpec to search nested flex components in the message array.
|
9
|
+
class HaveFlexBubble
|
10
|
+
def initialize(expected)
|
11
|
+
@expected = Utils.stringify_keys!(expected || {}, deep: true)
|
12
|
+
end
|
13
|
+
|
14
|
+
def description
|
15
|
+
return "have flex bubble" if @expected.empty?
|
16
|
+
|
17
|
+
"have flex bubble matching #{@expected.inspect}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def matches?(actual)
|
21
|
+
@actual = Utils.stringify_keys!(actual, deep: true)
|
22
|
+
@actual.any? { |message| match_flex_component?(message) }
|
23
|
+
end
|
24
|
+
alias == matches?
|
25
|
+
|
26
|
+
def failure_message
|
27
|
+
return "expected to find a flex bubble" if @expected.empty?
|
28
|
+
|
29
|
+
"expected to find a flex bubble matching #{@expected.inspect}"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def match_flex_component?(message)
|
35
|
+
return false unless message["type"] == "flex"
|
36
|
+
|
37
|
+
match_content?(message["contents"])
|
38
|
+
end
|
39
|
+
|
40
|
+
def match_content?(content)
|
41
|
+
return match_options?(content) if content["type"] == "bubble"
|
42
|
+
return false unless content["contents"]
|
43
|
+
|
44
|
+
content["contents"].any? { |nested_content| match_content?(nested_content) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def match_options?(content)
|
48
|
+
return false unless content["type"] == "bubble"
|
49
|
+
|
50
|
+
::RSpec::Matchers::BuiltIn::Include.new(@expected).matches?(content)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def have_line_flex_bubble(expected = nil) # rubocop:disable Naming/PredicateName
|
55
|
+
HaveFlexBubble.new(expected)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -8,33 +8,37 @@ module Line
|
|
8
8
|
# The text message matcher for RSpec to search for text messages in the message array.
|
9
9
|
class HaveTextMessage
|
10
10
|
def initialize(expected)
|
11
|
-
@
|
11
|
+
@text, @options = expected
|
12
|
+
@options = Utils.stringify_keys!(@options || {})
|
12
13
|
end
|
13
14
|
|
14
15
|
def description
|
15
|
-
return "have text message" if @
|
16
|
+
return "have text message" if @text.nil?
|
17
|
+
return "have text message matching #{@text.inspect}" if @options.empty?
|
16
18
|
|
17
|
-
"have text message matching #{@
|
19
|
+
"have text message matching #{@text.inspect} with options #{@options.inspect}"
|
18
20
|
end
|
19
21
|
|
20
22
|
def matches?(actual)
|
21
23
|
@actual = Utils.stringify_keys!(actual, deep: true)
|
22
|
-
@actual.
|
24
|
+
@actual.any? do |message|
|
23
25
|
next unless message["type"] == "text"
|
26
|
+
next true if @text.nil?
|
24
27
|
|
25
|
-
|
28
|
+
message["text"].match?(@text) && ::RSpec::Matchers::BuiltIn::Include.new(@options).matches?(message)
|
26
29
|
end
|
27
|
-
|
28
|
-
false
|
29
30
|
end
|
30
31
|
alias == matches?
|
31
32
|
|
32
33
|
def failure_message
|
33
|
-
"expected to find a text message
|
34
|
+
return "expected to find a text message" if @text.nil?
|
35
|
+
return "expected to find a text message matching #{@text.inspect}" if @options.empty?
|
36
|
+
|
37
|
+
"expected to find a text message matching #{@text.inspect} with options #{@options.inspect}"
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
|
-
def have_line_text_message(expected
|
41
|
+
def have_line_text_message(*expected) # rubocop:disable Naming/PredicateName
|
38
42
|
HaveTextMessage.new(expected)
|
39
43
|
end
|
40
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: line-message-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aotokitsuruya
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The LINE Messaging API message builder.
|
14
14
|
email:
|
@@ -32,17 +32,23 @@ files:
|
|
32
32
|
- lib/line/message/builder/base.rb
|
33
33
|
- lib/line/message/builder/container.rb
|
34
34
|
- lib/line/message/builder/flex.rb
|
35
|
+
- lib/line/message/builder/flex/actionable.rb
|
35
36
|
- lib/line/message/builder/flex/box.rb
|
36
37
|
- lib/line/message/builder/flex/bubble.rb
|
37
38
|
- lib/line/message/builder/flex/builder.rb
|
38
39
|
- lib/line/message/builder/flex/button.rb
|
39
40
|
- lib/line/message/builder/flex/image.rb
|
41
|
+
- lib/line/message/builder/flex/position.rb
|
40
42
|
- lib/line/message/builder/flex/text.rb
|
41
43
|
- lib/line/message/builder/quick_reply.rb
|
42
44
|
- lib/line/message/builder/text.rb
|
45
|
+
- lib/line/message/builder/validators.rb
|
46
|
+
- lib/line/message/builder/validators/enum.rb
|
47
|
+
- lib/line/message/builder/validators/size.rb
|
43
48
|
- lib/line/message/builder/version.rb
|
44
49
|
- lib/line/message/rspec.rb
|
45
50
|
- lib/line/message/rspec/matchers.rb
|
51
|
+
- lib/line/message/rspec/matchers/have_flex_bubble.rb
|
46
52
|
- lib/line/message/rspec/matchers/have_flex_component.rb
|
47
53
|
- lib/line/message/rspec/matchers/have_flex_message.rb
|
48
54
|
- lib/line/message/rspec/matchers/have_quick_reply.rb
|