line-message-builder 0.8.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 +41 -0
- data/CLAUDE.md +124 -0
- data/CONVENTIONS.md +36 -0
- data/README.md +61 -43
- data/claudekit.json +11 -0
- data/docs/rubrics/rdoc.md +169 -0
- data/lib/line/message/builder/actions/message.rb +52 -31
- data/lib/line/message/builder/actions/postback.rb +63 -33
- 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 +64 -69
- data/lib/line/message/builder/context.rb +55 -80
- data/lib/line/message/builder/flex/actionable.rb +53 -32
- data/lib/line/message/builder/flex/box.rb +366 -79
- data/lib/line/message/builder/flex/bubble.rb +78 -51
- data/lib/line/message/builder/flex/builder.rb +47 -36
- data/lib/line/message/builder/flex/button.rb +96 -48
- data/lib/line/message/builder/flex/carousel.rb +57 -29
- data/lib/line/message/builder/flex/icon.rb +152 -0
- data/lib/line/message/builder/flex/image.rb +103 -42
- data/lib/line/message/builder/flex/partial.rb +58 -55
- data/lib/line/message/builder/flex/position.rb +187 -100
- data/lib/line/message/builder/flex/separator.rb +84 -0
- data/lib/line/message/builder/flex/size.rb +67 -47
- data/lib/line/message/builder/flex/span.rb +184 -0
- data/lib/line/message/builder/flex/text.rb +210 -54
- data/lib/line/message/builder/flex.rb +31 -26
- 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 +16 -13
- data/lib/line/message/rspec/matchers/have_flex_bubble.rb +1 -1
- data/lib/line/message/rspec/matchers/have_flex_component.rb +26 -5
- data/lib/line/message/rspec/matchers/have_flex_message.rb +1 -1
- data/lib/line/message/rspec/matchers/have_flex_separator.rb +20 -0
- 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/lib/line/message/rspec/matchers.rb +1 -0
- data/llm.txt +367 -45
- data/release-please-config.json +3 -1
- metadata +12 -3
|
@@ -4,67 +4,93 @@ module Line
|
|
|
4
4
|
module Message
|
|
5
5
|
module Builder
|
|
6
6
|
module Flex
|
|
7
|
-
# Represents a
|
|
8
|
-
# A carousel is a horizontally scrollable sequence of
|
|
7
|
+
# Represents a carousel container in a LINE Flex Message.
|
|
8
|
+
# A carousel is a horizontally scrollable sequence of Bubble components.
|
|
9
9
|
# Each bubble in the carousel is a distinct message unit. Users can swipe
|
|
10
10
|
# left or right to view the different bubbles.
|
|
11
11
|
#
|
|
12
12
|
# Carousels are ideal for presenting multiple items, such as products,
|
|
13
13
|
# articles, or options, in a compact and interactive way.
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
15
|
+
# == Example
|
|
16
|
+
#
|
|
17
|
+
# Line::Message::Builder.with do
|
|
18
|
+
# flex alt_text: "Product Showcase" do
|
|
19
|
+
# carousel do
|
|
20
|
+
# bubble size: :mega do
|
|
21
|
+
# hero_image "https://example.com/product1.jpg"
|
|
22
|
+
# body { text "Product 1" }
|
|
22
23
|
# end
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
24
|
+
# bubble size: :mega do
|
|
25
|
+
# hero_image "https://example.com/product2.jpg"
|
|
26
|
+
# body { text "Product 2" }
|
|
26
27
|
# end
|
|
27
28
|
# end
|
|
28
29
|
# end
|
|
29
30
|
# end
|
|
30
31
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
32
|
+
# See also:
|
|
33
|
+
# - https://developers.line.biz/en/reference/messaging-api/#carousel
|
|
34
|
+
# - Bubble for the structure of individual items within the carousel
|
|
35
|
+
# - HasPartial (included but direct usage on Carousel is limited; partials
|
|
36
|
+
# are more commonly used within bubbles)
|
|
35
37
|
class Carousel < Line::Message::Builder::Base
|
|
36
|
-
include HasPartial
|
|
38
|
+
include HasPartial
|
|
37
39
|
|
|
38
|
-
#
|
|
39
|
-
# @return [Array<Flex::Bubble>] An array holding the {Bubble} components
|
|
40
|
-
# that form the items of this carousel.
|
|
40
|
+
# An array holding the Bubble components that form the items of this carousel.
|
|
41
41
|
attr_reader :contents
|
|
42
42
|
|
|
43
43
|
# Initializes a new Flex Message Carousel container.
|
|
44
44
|
# The provided block is instance-eval'd, allowing DSL methods like
|
|
45
|
-
#
|
|
45
|
+
# +bubble+ to be called to add bubbles to the carousel.
|
|
46
|
+
#
|
|
47
|
+
# [context]
|
|
48
|
+
# An optional context for the builder
|
|
49
|
+
# [options]
|
|
50
|
+
# A hash of options (currently none specific to Carousel itself,
|
|
51
|
+
# but available for future extensions or via Base)
|
|
52
|
+
# [block]
|
|
53
|
+
# A block to define the bubbles within this carousel
|
|
54
|
+
#
|
|
55
|
+
# == Example
|
|
46
56
|
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
57
|
+
# carousel = Carousel.new do
|
|
58
|
+
# bubble { body { text "First" } }
|
|
59
|
+
# bubble { body { text "Second" } }
|
|
60
|
+
# end
|
|
51
61
|
def initialize(context: nil, **options, &)
|
|
52
62
|
@contents = [] # Holds an array of Bubble objects
|
|
53
63
|
|
|
54
64
|
super # Calls Base#initialize, sets options, and evals block
|
|
55
65
|
end
|
|
56
66
|
|
|
57
|
-
# Adds a new
|
|
67
|
+
# Adds a new Bubble to this carousel's contents.
|
|
58
68
|
# Each call to this method appends another bubble to the horizontal sequence.
|
|
59
69
|
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
70
|
+
# [options]
|
|
71
|
+
# Options for the Bubble (see Bubble#initialize)
|
|
72
|
+
# [block]
|
|
73
|
+
# A block to define the sections and content of the Bubble
|
|
74
|
+
#
|
|
75
|
+
# [return]
|
|
76
|
+
# The newly created Bubble object that was added to the carousel
|
|
77
|
+
#
|
|
78
|
+
# == Example
|
|
79
|
+
#
|
|
80
|
+
# carousel do
|
|
81
|
+
# bubble size: :mega do
|
|
82
|
+
# body { text "Product 1" }
|
|
83
|
+
# end
|
|
84
|
+
# bubble size: :mega do
|
|
85
|
+
# body { text "Product 2" }
|
|
86
|
+
# end
|
|
87
|
+
# end
|
|
63
88
|
def bubble(**options, &)
|
|
64
89
|
# The maximum number of bubbles is validated in `to_h` as per LINE API limits.
|
|
65
90
|
@contents << Line::Message::Builder::Flex::Bubble.new(context: context, **options, &)
|
|
66
91
|
end
|
|
67
92
|
|
|
93
|
+
# :nodoc:
|
|
68
94
|
def to_h
|
|
69
95
|
raise RequiredError, "Carousel contents must have at least 1 bubble." if @contents.empty?
|
|
70
96
|
# LINE API as of 2023-10-10 allows up to 12 bubbles in a carousel.
|
|
@@ -77,6 +103,7 @@ module Line
|
|
|
77
103
|
|
|
78
104
|
private
|
|
79
105
|
|
|
106
|
+
# :nodoc:
|
|
80
107
|
def to_api
|
|
81
108
|
{
|
|
82
109
|
type: "carousel",
|
|
@@ -84,6 +111,7 @@ module Line
|
|
|
84
111
|
}.compact # compact is likely unnecessary here as contents is always present.
|
|
85
112
|
end
|
|
86
113
|
|
|
114
|
+
# :nodoc:
|
|
87
115
|
def to_sdkv2
|
|
88
116
|
{
|
|
89
117
|
type: "carousel",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Line
|
|
4
|
+
module Message
|
|
5
|
+
module Builder
|
|
6
|
+
module Flex
|
|
7
|
+
# Represents an "icon" component in a LINE Flex Message.
|
|
8
|
+
#
|
|
9
|
+
# Icons render a small image that decorates the text next to them. They are
|
|
10
|
+
# the standard way to build rating stars, labelled metadata rows, and other
|
|
11
|
+
# icon-and-text pairs.
|
|
12
|
+
#
|
|
13
|
+
# An icon can only be placed in a box whose +layout+ is +:baseline+. Unlike
|
|
14
|
+
# Image, an icon cannot have an action attached to it.
|
|
15
|
+
#
|
|
16
|
+
# == Example: Rating stars beside a score
|
|
17
|
+
#
|
|
18
|
+
# Line::Message::Builder.with do
|
|
19
|
+
# flex alt_text: "Review" do
|
|
20
|
+
# bubble do
|
|
21
|
+
# body do
|
|
22
|
+
# box layout: :baseline do
|
|
23
|
+
# icon "https://example.com/star_on.png", size: :sm
|
|
24
|
+
# icon "https://example.com/star_on.png", size: :sm
|
|
25
|
+
# icon "https://example.com/star_off.png", size: :sm
|
|
26
|
+
# text "3.0", size: :sm, margin: :md
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# === Example: Following the reader's font size
|
|
34
|
+
#
|
|
35
|
+
# box layout: :baseline do
|
|
36
|
+
# icon "https://example.com/pin.png", scaling: true
|
|
37
|
+
# text "Taipei", scaling: true
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# See also:
|
|
41
|
+
# - https://developers.line.biz/en/reference/messaging-api/#icon
|
|
42
|
+
# - Position::Margin for +margin+ property
|
|
43
|
+
# - Position::Offset for offset properties
|
|
44
|
+
# - Size::Shared for common +size+ keywords (e.g., +:sm+, +:xl+)
|
|
45
|
+
class Icon < Line::Message::Builder::Base
|
|
46
|
+
include Position::Margin # Adds `margin` option.
|
|
47
|
+
include Position::Offset # Adds offset options.
|
|
48
|
+
include Size::Shared # Adds `size` option (e.g., :sm, :md, :xl).
|
|
49
|
+
|
|
50
|
+
# The URL of the icon image (must be HTTPS). This is a required attribute.
|
|
51
|
+
attr_reader :url
|
|
52
|
+
|
|
53
|
+
# :method: aspect_ratio
|
|
54
|
+
# :call-seq:
|
|
55
|
+
# aspect_ratio() -> String or nil
|
|
56
|
+
# aspect_ratio(value) -> String
|
|
57
|
+
#
|
|
58
|
+
# Sets or gets the aspect ratio of the icon (width:height).
|
|
59
|
+
#
|
|
60
|
+
# [value]
|
|
61
|
+
# The aspect ratio string (e.g., <code>"1:1"</code>, <code>"2:1"</code>).
|
|
62
|
+
# Default is <code>"1:1"</code>
|
|
63
|
+
option :aspect_ratio, default: nil # API key: aspectRatio
|
|
64
|
+
|
|
65
|
+
# :method: scaling
|
|
66
|
+
# :call-seq:
|
|
67
|
+
# scaling() -> Boolean or nil
|
|
68
|
+
# scaling(value) -> Boolean
|
|
69
|
+
#
|
|
70
|
+
# Sets or gets whether the icon size follows the font size setting of the
|
|
71
|
+
# LINE app.
|
|
72
|
+
#
|
|
73
|
+
# [value]
|
|
74
|
+
# +true+ to scale the icon, +false+ (default) to keep it fixed
|
|
75
|
+
option :scaling, default: nil
|
|
76
|
+
|
|
77
|
+
# Initializes a new Flex Message Icon component.
|
|
78
|
+
#
|
|
79
|
+
# [url]
|
|
80
|
+
# The HTTPS URL of the icon image (required)
|
|
81
|
+
# [context]
|
|
82
|
+
# An optional context for the builder (default: +nil+)
|
|
83
|
+
# [options]
|
|
84
|
+
# A hash of options to set instance variables (e.g., +:size+,
|
|
85
|
+
# +:aspect_ratio+, and options from included modules)
|
|
86
|
+
# [block]
|
|
87
|
+
# An optional block for further configuration
|
|
88
|
+
#
|
|
89
|
+
# Raises RequiredError if +url+ is +nil+ when building the message.
|
|
90
|
+
#
|
|
91
|
+
# == Example
|
|
92
|
+
#
|
|
93
|
+
# Line::Message::Builder::Flex::Icon.new(
|
|
94
|
+
# "https://example.com/star.png",
|
|
95
|
+
# size: :sm
|
|
96
|
+
# )
|
|
97
|
+
def initialize(url, context: nil, **options, &)
|
|
98
|
+
@url = url # The icon URL is mandatory.
|
|
99
|
+
|
|
100
|
+
super(context: context, **options, &)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
# :nodoc:
|
|
106
|
+
def to_api # rubocop:disable Metrics/MethodLength
|
|
107
|
+
raise RequiredError, "url is required for an icon component" if url.nil?
|
|
108
|
+
|
|
109
|
+
{
|
|
110
|
+
type: "icon",
|
|
111
|
+
url: url,
|
|
112
|
+
# Position::Margin
|
|
113
|
+
margin: margin,
|
|
114
|
+
# Position::Offset
|
|
115
|
+
position: position,
|
|
116
|
+
offsetTop: offset_top,
|
|
117
|
+
offsetBottom: offset_bottom,
|
|
118
|
+
offsetStart: offset_start,
|
|
119
|
+
offsetEnd: offset_end,
|
|
120
|
+
# Size::Shared
|
|
121
|
+
size: size,
|
|
122
|
+
aspectRatio: aspect_ratio, # From option (maps to API key)
|
|
123
|
+
scaling: scaling # From option
|
|
124
|
+
}.compact
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# :nodoc:
|
|
128
|
+
def to_sdkv2 # rubocop:disable Metrics/MethodLength
|
|
129
|
+
raise RequiredError, "url is required for an icon component" if url.nil?
|
|
130
|
+
|
|
131
|
+
{
|
|
132
|
+
type: "icon",
|
|
133
|
+
url: url,
|
|
134
|
+
# Position::Margin
|
|
135
|
+
margin: margin,
|
|
136
|
+
# Position::Offset
|
|
137
|
+
position: position,
|
|
138
|
+
offset_top: offset_top,
|
|
139
|
+
offset_bottom: offset_bottom,
|
|
140
|
+
offset_start: offset_start,
|
|
141
|
+
offset_end: offset_end,
|
|
142
|
+
# Size::Shared
|
|
143
|
+
size: size,
|
|
144
|
+
aspect_ratio: aspect_ratio, # From option (maps to API key)
|
|
145
|
+
scaling: scaling # From option
|
|
146
|
+
}.compact
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -8,34 +8,47 @@ module Line
|
|
|
8
8
|
#
|
|
9
9
|
# Images are specified by a URL and can be included in various parts of a
|
|
10
10
|
# Flex Message, such as a box, a bubble's hero section, etc. They offer
|
|
11
|
-
# several properties to control their appearance, including
|
|
12
|
-
#
|
|
13
|
-
#
|
|
11
|
+
# several properties to control their appearance, including +size+,
|
|
12
|
+
# +aspect_ratio+, +aspect_mode+ and +background_color+. An image can also
|
|
13
|
+
# have an action to make it tappable.
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
15
|
+
# == Example
|
|
16
|
+
#
|
|
17
|
+
# Line::Message::Builder.with do
|
|
18
|
+
# flex alt_text: "Image Example" do
|
|
19
|
+
# bubble do
|
|
20
|
+
# body do
|
|
21
|
+
# image "https://example.com/image.png",
|
|
22
|
+
# aspect_ratio: "16:9",
|
|
23
|
+
# aspect_mode: :cover,
|
|
24
|
+
# size: :full
|
|
25
25
|
# end
|
|
26
26
|
# end
|
|
27
27
|
# end
|
|
28
28
|
# end
|
|
29
29
|
# end
|
|
30
30
|
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
31
|
+
# === Example: Playing an animated image on a tinted backdrop
|
|
32
|
+
#
|
|
33
|
+
# Line::Message::Builder.with do
|
|
34
|
+
# flex alt_text: "Image Example" do
|
|
35
|
+
# bubble do
|
|
36
|
+
# hero_image "https://example.com/loading.png",
|
|
37
|
+
# animated: true,
|
|
38
|
+
# background_color: "#FFFFFF"
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# See also:
|
|
44
|
+
# - https://developers.line.biz/en/reference/messaging-api/#image
|
|
45
|
+
# - Actionable for making the image tappable
|
|
46
|
+
# - Position::Horizontal for +align+ property
|
|
47
|
+
# - Position::Vertical for +gravity+ property
|
|
48
|
+
# - Position::Margin for +margin+ property
|
|
49
|
+
# - Position::Offset for offset properties
|
|
50
|
+
# - Size::Flex for +flex+ sizing property
|
|
51
|
+
# - Size::Image for +size+, +aspect_ratio+, and +aspect_mode+ properties
|
|
39
52
|
class Image < Line::Message::Builder::Base
|
|
40
53
|
include Actionable # Enables defining an action for the image.
|
|
41
54
|
include Position::Horizontal # Adds `align` option for horizontal alignment.
|
|
@@ -45,35 +58,77 @@ module Line
|
|
|
45
58
|
include Size::Flex # Adds `flex` option for sizing within a parent box.
|
|
46
59
|
include Size::Image # Adds image-specific sizing options like `size`, `aspect_ratio`, `aspect_mode`.
|
|
47
60
|
|
|
48
|
-
#
|
|
49
|
-
# @return [String] The URL of the image. Must be HTTPS.
|
|
50
|
-
# This is a required attribute.
|
|
61
|
+
# The URL of the image (must be HTTPS). This is a required attribute.
|
|
51
62
|
attr_reader :url
|
|
52
63
|
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
64
|
+
# :method: aspect_ratio
|
|
65
|
+
# :call-seq:
|
|
66
|
+
# aspect_ratio() -> String or nil
|
|
67
|
+
# aspect_ratio(value) -> String
|
|
68
|
+
#
|
|
69
|
+
# Sets or gets the aspect ratio of the image (width:height).
|
|
70
|
+
#
|
|
71
|
+
# [value]
|
|
72
|
+
# The aspect ratio string (e.g., <code>"1:1"</code>, <code>"16:9"</code>,
|
|
73
|
+
# <code>"20:13"</code>). Default is <code>"1:1"</code>.
|
|
58
74
|
option :aspect_ratio, default: nil
|
|
59
75
|
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
76
|
+
# :method: aspect_mode
|
|
77
|
+
# :call-seq:
|
|
78
|
+
# aspect_mode() -> Symbol or nil
|
|
79
|
+
# aspect_mode(value) -> Symbol
|
|
80
|
+
#
|
|
81
|
+
# Sets or gets how the image should be displayed within the area defined by +aspect_ratio+.
|
|
82
|
+
#
|
|
83
|
+
# [value]
|
|
84
|
+
# The aspect mode (can be +:cover+ (default) or +:fit+)
|
|
65
85
|
option :aspect_mode, default: nil # :cover, :fit
|
|
66
86
|
|
|
87
|
+
# :method: background_color
|
|
88
|
+
# :call-seq:
|
|
89
|
+
# background_color() -> String or nil
|
|
90
|
+
# background_color(value) -> String
|
|
91
|
+
#
|
|
92
|
+
# Sets or gets the background color shown behind the image.
|
|
93
|
+
#
|
|
94
|
+
# [value]
|
|
95
|
+
# Hexadecimal color code (e.g., <code>"#RRGGBB"</code>)
|
|
96
|
+
option :background_color, default: nil # API key: backgroundColor
|
|
97
|
+
|
|
98
|
+
# :method: animated
|
|
99
|
+
# :call-seq:
|
|
100
|
+
# animated() -> Boolean or nil
|
|
101
|
+
# animated(value) -> Boolean
|
|
102
|
+
#
|
|
103
|
+
# Sets or gets whether an animated image (APNG) is played back. A single
|
|
104
|
+
# message may mark at most 10 images as animated, and frames larger than
|
|
105
|
+
# 300 KB are not played.
|
|
106
|
+
#
|
|
107
|
+
# [value]
|
|
108
|
+
# +true+ to play the animation, +false+ (default) to show a still frame
|
|
109
|
+
option :animated, default: nil
|
|
110
|
+
|
|
67
111
|
# Initializes a new Flex Message Image component.
|
|
68
112
|
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
113
|
+
# [url]
|
|
114
|
+
# The HTTPS URL of the image (required)
|
|
115
|
+
# [context]
|
|
116
|
+
# An optional context for the builder (default: +nil+)
|
|
117
|
+
# [options]
|
|
118
|
+
# A hash of options to set instance variables (e.g., +:aspect_ratio+,
|
|
119
|
+
# +:aspect_mode+, +:size+, and options from included modules)
|
|
120
|
+
# [block]
|
|
121
|
+
# An optional block, typically used to define an action for the image
|
|
122
|
+
#
|
|
123
|
+
# Raises RequiredError if +url+ is +nil+ when building the message.
|
|
124
|
+
#
|
|
125
|
+
# == Example
|
|
126
|
+
#
|
|
127
|
+
# image = Line::Message::Builder::Flex::Image.new(
|
|
128
|
+
# "https://example.com/image.png",
|
|
129
|
+
# aspect_ratio: "16:9",
|
|
130
|
+
# aspect_mode: :cover
|
|
131
|
+
# )
|
|
77
132
|
def initialize(url, context: nil, **options, &)
|
|
78
133
|
@url = url # The image URL is mandatory.
|
|
79
134
|
|
|
@@ -82,6 +137,7 @@ module Line
|
|
|
82
137
|
|
|
83
138
|
private
|
|
84
139
|
|
|
140
|
+
# :nodoc:
|
|
85
141
|
def to_api # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
86
142
|
raise RequiredError, "url is required for an image component" if url.nil?
|
|
87
143
|
|
|
@@ -105,11 +161,14 @@ module Line
|
|
|
105
161
|
size: size,
|
|
106
162
|
aspectRatio: aspect_ratio, # From option
|
|
107
163
|
aspectMode: aspect_mode, # From option
|
|
164
|
+
backgroundColor: background_color, # From option (maps to API key)
|
|
165
|
+
animated: animated, # From option
|
|
108
166
|
# Actionable
|
|
109
167
|
action: action&.to_h # From Actionable module
|
|
110
168
|
}.compact
|
|
111
169
|
end
|
|
112
170
|
|
|
171
|
+
# :nodoc:
|
|
113
172
|
def to_sdkv2 # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
114
173
|
raise RequiredError, "url is required for an image component" if url.nil?
|
|
115
174
|
|
|
@@ -133,6 +192,8 @@ module Line
|
|
|
133
192
|
size: size,
|
|
134
193
|
aspect_ratio: aspect_ratio, # From option
|
|
135
194
|
aspect_mode: aspect_mode, # From option
|
|
195
|
+
background_color: background_color, # From option (maps to API key)
|
|
196
|
+
animated: animated, # From option
|
|
136
197
|
# Actionable
|
|
137
198
|
action: action&.to_h # From Actionable module
|
|
138
199
|
}.compact
|
|
@@ -4,44 +4,52 @@ module Line
|
|
|
4
4
|
module Message
|
|
5
5
|
module Builder
|
|
6
6
|
module Flex
|
|
7
|
-
# The
|
|
8
|
-
# (like
|
|
9
|
-
# by creating classes that inherit from
|
|
7
|
+
# The HasPartial module provides functionality for Flex Message components
|
|
8
|
+
# (like Box, Bubble) to render reusable "partials". Partials are defined
|
|
9
|
+
# by creating classes that inherit from Partial.
|
|
10
10
|
#
|
|
11
|
-
# Including this module into a component class gives it the
|
|
11
|
+
# Including this module into a component class gives it the +partial!+ method.
|
|
12
|
+
#
|
|
13
|
+
# == Example
|
|
12
14
|
#
|
|
13
|
-
# @example Defining and using a partial
|
|
14
15
|
# # Define a reusable partial
|
|
15
16
|
# class MyButtonPartial < Line::Message::Builder::Flex::Partial
|
|
16
|
-
# def call
|
|
17
|
-
# #
|
|
18
|
-
# button style: :primary do
|
|
19
|
-
#
|
|
17
|
+
# def call
|
|
18
|
+
# # +button+ method is available from the context (e.g., a Box)
|
|
19
|
+
# button style: :primary do
|
|
20
|
+
# # +data+ and +label+ are available from <code>context.assigns</code>
|
|
21
|
+
# postback data, label: label
|
|
20
22
|
# end
|
|
21
23
|
# end
|
|
22
24
|
# end
|
|
23
25
|
#
|
|
24
26
|
# # Use the partial within a Box component
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
27
|
+
# Line::Message::Builder.with do
|
|
28
|
+
# flex do
|
|
29
|
+
# bubble do
|
|
30
|
+
# body do
|
|
31
|
+
# partial! MyButtonPartial, label: "Action", data: "action=do_something"
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
# end
|
|
29
35
|
# end
|
|
30
36
|
#
|
|
31
|
-
#
|
|
37
|
+
# See also:
|
|
38
|
+
# - Partial
|
|
32
39
|
module HasPartial
|
|
33
|
-
# Renders a given
|
|
40
|
+
# Renders a given Partial class within the current component's context.
|
|
34
41
|
#
|
|
35
|
-
# This method temporarily makes the provided
|
|
36
|
-
# partial through the
|
|
37
|
-
#
|
|
42
|
+
# This method temporarily makes the provided +assigns+ available to the
|
|
43
|
+
# partial through the <code>context.assigns</code> mechanism. After the partial's
|
|
44
|
+
# +call+ method completes, the original <code>context.assigns</code> are restored.
|
|
38
45
|
#
|
|
39
|
-
#
|
|
40
|
-
# subclass of
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
46
|
+
# [partial_class]
|
|
47
|
+
# The class of the partial to render. Must be a subclass of Partial.
|
|
48
|
+
# [assigns]
|
|
49
|
+
# A hash of key-value pairs that will be made available as +assigns+
|
|
50
|
+
# within the partial's +call+ method.
|
|
51
|
+
#
|
|
52
|
+
# Raises ArgumentError if +partial_class+ is not a subclass of Partial.
|
|
45
53
|
def partial!(partial_class, **assigns)
|
|
46
54
|
unless partial_class < Partial
|
|
47
55
|
raise ArgumentError,
|
|
@@ -57,60 +65,55 @@ module Line
|
|
|
57
65
|
end
|
|
58
66
|
end
|
|
59
67
|
|
|
60
|
-
# The
|
|
68
|
+
# The Partial class is an abstract base for creating reusable snippets
|
|
61
69
|
# of Flex Message content. To define a partial, create a new class that
|
|
62
|
-
# inherits from
|
|
70
|
+
# inherits from Partial and implements the +call+ instance method.
|
|
63
71
|
#
|
|
64
|
-
# Within the
|
|
65
|
-
# DSL methods (e.g.,
|
|
72
|
+
# Within the +call+ method, you can use the standard Flex Message builder
|
|
73
|
+
# DSL methods (e.g., +text+, +box+, +button+) as if you were directly inside
|
|
66
74
|
# the component where the partial is being rendered. This is possible because
|
|
67
|
-
# the
|
|
68
|
-
# instance that is rendering it (passed as
|
|
75
|
+
# the Partial instance delegates unknown method calls to the component
|
|
76
|
+
# instance that is rendering it (passed as +context+ during initialization).
|
|
77
|
+
#
|
|
78
|
+
# Subclass and implement +call+ to create a concrete partial.
|
|
69
79
|
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
80
|
+
# See also:
|
|
81
|
+
# - HasPartial for how to render partials
|
|
72
82
|
class Partial
|
|
73
83
|
# Initializes a new Partial instance.
|
|
74
|
-
# This is typically called by the
|
|
84
|
+
# This is typically called by the HasPartial#partial! method.
|
|
75
85
|
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
# the DSL methods (like
|
|
86
|
+
# [context]
|
|
87
|
+
# The component instance (e.g., Box, Bubble) within which this partial
|
|
88
|
+
# is being rendered. This context provides the DSL methods (like +text+,
|
|
89
|
+
# +box+) used in the partial's +call+ method.
|
|
79
90
|
def initialize(context:)
|
|
80
91
|
@context = context # The component (e.g., Box, Bubble) rendering this partial
|
|
81
92
|
end
|
|
82
93
|
|
|
83
94
|
# This method must be implemented by subclasses to define the content of
|
|
84
95
|
# the partial. Inside this method, use the Flex Message builder DSL methods
|
|
85
|
-
# (e.g.,
|
|
86
|
-
# rendering context.
|
|
96
|
+
# (e.g., <code>text "Hello"</code>, <code>button { ... }</code>) which will be
|
|
97
|
+
# delegated to the rendering context.
|
|
98
|
+
#
|
|
99
|
+
# Any arguments passed to +partial!+ as +assigns+ are available via
|
|
100
|
+
# <code>context.assigns</code> or directly if the rendering context's +method_missing+
|
|
101
|
+
# handles +assigns+ lookup (as Line::Message::Builder::Context does).
|
|
87
102
|
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# handles `assigns` lookup (as {Line::Message::Builder::Context} does).
|
|
103
|
+
# Arguments passed from the +partial!+ call's +assigns+ can be explicitly defined
|
|
104
|
+
# as parameters here, or accessed via <code>context.assigns</code>.
|
|
91
105
|
#
|
|
92
|
-
#
|
|
93
|
-
# can be explicitly defined as parameters here, or accessed via `context.assigns`.
|
|
94
|
-
# @raise [NotImplementedError] if a subclass does not implement this method.
|
|
106
|
+
# Raises NotImplementedError if a subclass does not implement this method.
|
|
95
107
|
def call(*)
|
|
96
108
|
raise NotImplementedError,
|
|
97
109
|
"The #{self.class.name} class must implement the #call method to define its content."
|
|
98
110
|
end
|
|
99
111
|
|
|
100
|
-
#
|
|
101
|
-
# Part of Ruby's dynamic method dispatch. It's overridden here to declare
|
|
102
|
-
# that instances of `Partial` can respond to methods to which the
|
|
103
|
-
# wrapped `@context` object responds.
|
|
104
|
-
def respond_to_missing?(method_name, include_private = false)
|
|
112
|
+
def respond_to_missing?(method_name, include_private = false) # :nodoc:
|
|
105
113
|
@context.respond_to?(method_name, include_private) || super
|
|
106
114
|
end
|
|
107
115
|
|
|
108
|
-
#
|
|
109
|
-
# Handles calls to methods not explicitly defined on the `Partial` class
|
|
110
|
-
# by delegating them to the wrapped `@context` object (the rendering component).
|
|
111
|
-
# This allows the `call` method of a partial to use DSL methods like `text`,
|
|
112
|
-
# `box`, `button`, etc., as if they were defined directly in the partial.
|
|
113
|
-
def method_missing(method_name, ...)
|
|
116
|
+
def method_missing(method_name, ...) # :nodoc:
|
|
114
117
|
if @context.respond_to?(method_name)
|
|
115
118
|
@context.public_send(method_name, ...)
|
|
116
119
|
else
|