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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/.rubocop.yml +5 -0
  4. data/CHANGELOG.md +41 -0
  5. data/CLAUDE.md +124 -0
  6. data/CONVENTIONS.md +36 -0
  7. data/README.md +61 -43
  8. data/claudekit.json +11 -0
  9. data/docs/rubrics/rdoc.md +169 -0
  10. data/lib/line/message/builder/actions/message.rb +52 -31
  11. data/lib/line/message/builder/actions/postback.rb +63 -33
  12. data/lib/line/message/builder/actions/uri.rb +139 -0
  13. data/lib/line/message/builder/actions.rb +6 -3
  14. data/lib/line/message/builder/base.rb +92 -67
  15. data/lib/line/message/builder/container.rb +64 -69
  16. data/lib/line/message/builder/context.rb +55 -80
  17. data/lib/line/message/builder/flex/actionable.rb +53 -32
  18. data/lib/line/message/builder/flex/box.rb +366 -79
  19. data/lib/line/message/builder/flex/bubble.rb +78 -51
  20. data/lib/line/message/builder/flex/builder.rb +47 -36
  21. data/lib/line/message/builder/flex/button.rb +96 -48
  22. data/lib/line/message/builder/flex/carousel.rb +57 -29
  23. data/lib/line/message/builder/flex/icon.rb +152 -0
  24. data/lib/line/message/builder/flex/image.rb +103 -42
  25. data/lib/line/message/builder/flex/partial.rb +58 -55
  26. data/lib/line/message/builder/flex/position.rb +187 -100
  27. data/lib/line/message/builder/flex/separator.rb +84 -0
  28. data/lib/line/message/builder/flex/size.rb +67 -47
  29. data/lib/line/message/builder/flex/span.rb +184 -0
  30. data/lib/line/message/builder/flex/text.rb +210 -54
  31. data/lib/line/message/builder/flex.rb +31 -26
  32. data/lib/line/message/builder/quick_reply.rb +174 -4
  33. data/lib/line/message/builder/text.rb +70 -3
  34. data/lib/line/message/builder/version.rb +1 -1
  35. data/lib/line/message/builder.rb +16 -13
  36. data/lib/line/message/rspec/matchers/have_flex_bubble.rb +1 -1
  37. data/lib/line/message/rspec/matchers/have_flex_component.rb +26 -5
  38. data/lib/line/message/rspec/matchers/have_flex_message.rb +1 -1
  39. data/lib/line/message/rspec/matchers/have_flex_separator.rb +20 -0
  40. data/lib/line/message/rspec/matchers/have_quick_reply.rb +1 -1
  41. data/lib/line/message/rspec/matchers/have_text_message.rb +1 -1
  42. data/lib/line/message/rspec/matchers.rb +1 -0
  43. data/llm.txt +367 -45
  44. data/release-please-config.json +3 -1
  45. metadata +12 -3
@@ -7,7 +7,7 @@ module Line
7
7
  # Represents a "box" component in a LINE Flex Message.
8
8
  #
9
9
  # A box is a fundamental layout container that arranges its child components
10
- # (`contents`) in a specified direction (`layout`: horizontal, vertical, or
10
+ # (+contents+) in a specified direction (+layout+: horizontal, vertical, or
11
11
  # baseline). It can hold various other components like text, images, buttons,
12
12
  # or even nested boxes, allowing for complex layouts.
13
13
  #
@@ -15,152 +15,374 @@ module Line
15
15
  # arrangement of their children, such as padding, margin, spacing between
16
16
  # items, justification, and alignment.
17
17
  #
18
- # A box can also have an `action` associated with it, making the entire
18
+ # A box can also have an +action+ associated with it, making the entire
19
19
  # box area tappable.
20
20
  #
21
- # @example Creating a horizontal box with two text components
22
- # Line::Message::Builder.with do |root|
23
- # root.flex alt_text: "Box example" do |flex|
24
- # flex.bubble do |bubble|
25
- # bubble.body do |body_box| # body_box is an instance of Flex::Box
26
- # body_box.layout :horizontal
27
- # body_box.spacing :md
28
- # body_box.text "Item 1"
29
- # body_box.text "Item 2"
21
+ # == Example
22
+ #
23
+ # Line::Message::Builder.with do
24
+ # flex alt_text: "Box example" do
25
+ # bubble do
26
+ # body do
27
+ # layout :horizontal
28
+ # spacing :md
29
+ # text "Item 1"
30
+ # text "Item 2"
30
31
  # end
31
32
  # end
32
33
  # end
33
34
  # end
34
35
  #
35
- # @see https://developers.line.biz/en/reference/messaging-api/#box
36
- # @see Actionable For making the box tappable.
37
- # @see HasPartial For including reusable component groups.
38
- # @see Position::Padding For padding properties.
39
- # @see Position::Margin For margin properties.
40
- # @see Position::Offset For offset properties.
41
- # @see Size::Flex For flex sizing property.
42
- class Box < Line::Message::Builder::Base
36
+ # See also:
37
+ # - https://developers.line.biz/en/reference/messaging-api/#box
38
+ # - Actionable for making the box tappable
39
+ # - HasPartial for including reusable component groups
40
+ # - Position::Padding for padding properties
41
+ # - Position::Margin for margin properties
42
+ # - Position::Offset for offset properties
43
+ # - Size::Flex for flex sizing property
44
+ class Box < Line::Message::Builder::Base # rubocop:disable Metrics/ClassLength
43
45
  include HasPartial # Allows including predefined partial component sets.
44
46
  include Actionable # Enables defining an action for the entire box.
45
- include Position::Padding # Adds padding options like `padding_all`, `padding_top`, etc.
46
- include Position::Margin # Adds `margin` option.
47
- include Position::Offset # Adds offset options like `offset_top`, `offset_start`, etc.
48
- include Size::Flex # Adds `flex` option for controlling size within a parent box.
49
-
50
- # @!attribute [r] contents
51
- # @return [Array<Base>] An array holding the child components (e.g.,
52
- # {Text}, {Image}, nested {Box} instances) of this box.
47
+ include Position::Padding # Adds padding options like +padding_all+, +padding_top+, etc.
48
+ include Position::Margin # Adds +margin+ option.
49
+ include Position::Offset # Adds offset options like +offset_top+, +offset_start+, etc.
50
+ include Size::Flex # Adds +flex+ option for controlling size within a parent box.
51
+
52
+ # An array holding the child components (e.g., Text, Image, nested Box instances) of this box.
53
53
  attr_reader :contents
54
54
 
55
+ # :method: layout
56
+ # :call-seq:
57
+ # layout() -> Symbol
58
+ # layout(value) -> Symbol
59
+ #
55
60
  # Specifies the arrangement of child components.
56
- # @!method layout(value)
57
- # @param value [Symbol] `:horizontal` (default), `:vertical`, or `:baseline`.
58
- # @return [Symbol] The current layout.
61
+ #
62
+ # [value]
63
+ # +:horizontal+ (default), +:vertical+, or +:baseline+
59
64
  option :layout, default: :horizontal, validator: Validators::Enum.new(
60
65
  :horizontal, :vertical, :baseline
61
66
  )
62
67
 
68
+ # :method: justify_content
69
+ # :call-seq:
70
+ # justify_content() -> Symbol or nil
71
+ # justify_content(value) -> Symbol
72
+ #
63
73
  # Horizontal alignment of content in a horizontal box; vertical alignment in a vertical box.
64
- # @!method justify_content(value)
65
- # @param value [Symbol, nil] E.g., `:flex_start`, `:center`, `:flex_end`,
66
- # `:space_between`, `:space_around`, `:space_evenly`.
67
- # @return [Symbol, nil] The current justify_content value.
74
+ #
75
+ # [value]
76
+ # +:flex_start+, +:center+, +:flex_end+, +:space_between+, +:space_around+, or +:space_evenly+
68
77
  option :justify_content, default: nil, validator: Validators::Enum.new(
69
78
  :flex_start, :center, :flex_end, :space_between, :space_around, :space_evenly
70
79
  )
71
80
 
81
+ # :method: align_items
82
+ # :call-seq:
83
+ # align_items() -> Symbol or nil
84
+ # align_items(value) -> Symbol
85
+ #
72
86
  # Vertical alignment of content in a horizontal box; horizontal alignment in a vertical box.
73
- # @!method align_items(value)
74
- # @param value [Symbol, nil] E.g., `:flex_start`, `:center`, `:flex_end`.
75
- # @return [Symbol, nil] The current align_items value.
87
+ #
88
+ # [value]
89
+ # +:flex_start+, +:center+, or +:flex_end+
76
90
  option :align_items, default: nil, validator: Validators::Enum.new(
77
91
  :flex_start, :center, :flex_end
78
92
  )
79
93
 
94
+ # :method: spacing
95
+ # :call-seq:
96
+ # spacing() -> String, Symbol, or nil
97
+ # spacing(value) -> String or Symbol
98
+ #
80
99
  # Specifies the minimum spacing between components.
81
- # Not applicable if `layout` is `:baseline` or if the box contains only one component.
82
- # @!method spacing(value)
83
- # @param value [String, Symbol, nil] E.g., `"md"`, `:lg`, `"10px"`.
84
- # Keywords: `:none`, `:xs`, `:sm`, `:md`, `:lg`, `:xl`, `:xxl`.
85
- # @return [String, Symbol, nil] The current spacing value.
100
+ # Not applicable if +layout+ is +:baseline+ or if the box contains only one component.
101
+ #
102
+ # [value]
103
+ # <code>"md"</code>, +:lg+, <code>"10px"</code>, or keywords:
104
+ # +:none+, +:xs+, +:sm+, +:md+, +:lg+, +:xl+, +:xxl+
86
105
  option :spacing, default: nil, validator: Validators::Size.new(:pixel, :keyword)
87
106
 
107
+ # :method: width
108
+ # :call-seq:
109
+ # width() -> String or nil
110
+ # width(value) -> String
111
+ #
88
112
  # Width of the box. Can be a percentage or pixel value.
89
- # @!method width(value)
90
- # @param value [String, nil] E.g., `"100px"`, `"50%"`.
91
- # @return [String, nil] The current width.
113
+ #
114
+ # [value]
115
+ # <code>"100px"</code> or <code>"50%"</code>
92
116
  option :width, default: nil, validator: Validators::Size.new(:pixel, :percentage)
93
117
 
118
+ # :method: max_width
119
+ # :call-seq:
120
+ # max_width() -> String or nil
121
+ # max_width(value) -> String
122
+ #
94
123
  # Maximum width of the box.
95
- # @!method max_width(value)
96
- # @param value [String, nil] E.g., `"100px"`, `"50%"`.
97
- # @return [String, nil] The current maximum width.
124
+ #
125
+ # [value]
126
+ # <code>"100px"</code> or <code>"50%"</code>
98
127
  option :max_width, default: nil, validator: Validators::Size.new(:pixel, :percentage)
99
128
 
129
+ # :method: height
130
+ # :call-seq:
131
+ # height() -> String or nil
132
+ # height(value) -> String
133
+ #
100
134
  # Height of the box.
101
- # @!method height(value)
102
- # @param value [String, nil] E.g., `"100px"`, `"50%"`.
103
- # @return [String, nil] The current height.
135
+ #
136
+ # [value]
137
+ # <code>"100px"</code> or <code>"50%"</code>
104
138
  option :height, default: nil, validator: Validators::Size.new(:pixel, :percentage)
105
139
 
140
+ # :method: max_height
141
+ # :call-seq:
142
+ # max_height() -> String or nil
143
+ # max_height(value) -> String
144
+ #
106
145
  # Maximum height of the box.
107
- # @!method max_height(value)
108
- # @param value [String, nil] E.g., `"100px"`, `"50%"`.
109
- # @return [String, nil] The current maximum height.
146
+ #
147
+ # [value]
148
+ # <code>"100px"</code> or <code>"50%"</code>
110
149
  option :max_height, default: nil, validator: Validators::Size.new(:pixel, :percentage)
111
150
 
151
+ # :method: background_color
152
+ # :call-seq:
153
+ # background_color() -> String or nil
154
+ # background_color(value) -> String
155
+ #
156
+ # Background color of the box. An alpha channel may be included.
157
+ #
158
+ # [value]
159
+ # Hexadecimal color code (e.g., <code>"#RRGGBB"</code>, <code>"#RRGGBBAA"</code>)
160
+ option :background_color, default: nil # API key: backgroundColor
161
+
162
+ # :method: border_color
163
+ # :call-seq:
164
+ # border_color() -> String or nil
165
+ # border_color(value) -> String
166
+ #
167
+ # Color of the box border.
168
+ #
169
+ # [value]
170
+ # Hexadecimal color code (e.g., <code>"#RRGGBB"</code>)
171
+ option :border_color, default: nil # API key: borderColor
172
+
173
+ # :method: border_width
174
+ # :call-seq:
175
+ # border_width() -> String, Symbol, or nil
176
+ # border_width(value) -> String or Symbol
177
+ #
178
+ # Width of the box border. Listed keywords increase in width.
179
+ #
180
+ # [value]
181
+ # <code>"2px"</code>, or one of +:none+, +:light+, +:normal+,
182
+ # +:medium+, <code>:"semi-bold"</code>, +:bold+
183
+ option :border_width, default: nil # API key: borderWidth
184
+
185
+ # :method: corner_radius
186
+ # :call-seq:
187
+ # corner_radius() -> String, Symbol, or nil
188
+ # corner_radius(value) -> String or Symbol
189
+ #
190
+ # Radius used when rounding the corners of the box.
191
+ #
192
+ # [value]
193
+ # <code>"4px"</code>, or one of +:none+, +:xs+, +:sm+, +:md+, +:lg+,
194
+ # +:xl+, +:xxl+
195
+ option :corner_radius, default: nil, # API key: cornerRadius
196
+ validator: Validators::Size.new(:pixel, :keyword)
197
+
198
+ # :method: background_angle
199
+ # :call-seq:
200
+ # background_angle() -> String or nil
201
+ # background_angle(value) -> String
202
+ #
203
+ # Angle at which the linear gradient background moves. +0deg+ runs from
204
+ # bottom to top and the direction rotates clockwise as the angle grows.
205
+ #
206
+ # Required when any other +background_*+ property is set.
207
+ #
208
+ # [value]
209
+ # An angle in the half-open interval [0, 360) (e.g., <code>"90deg"</code>)
210
+ option :background_angle, default: nil
211
+
212
+ # :method: background_start_color
213
+ # :call-seq:
214
+ # background_start_color() -> String or nil
215
+ # background_start_color(value) -> String
216
+ #
217
+ # Color at the starting point of the linear gradient background.
218
+ #
219
+ # Required when any other +background_*+ property is set.
220
+ #
221
+ # [value]
222
+ # Hexadecimal color code (e.g., <code>"#RRGGBB"</code>)
223
+ option :background_start_color, default: nil
224
+
225
+ # :method: background_end_color
226
+ # :call-seq:
227
+ # background_end_color() -> String or nil
228
+ # background_end_color(value) -> String
229
+ #
230
+ # Color at the ending point of the linear gradient background.
231
+ #
232
+ # Required when any other +background_*+ property is set.
233
+ #
234
+ # [value]
235
+ # Hexadecimal color code (e.g., <code>"#RRGGBB"</code>)
236
+ option :background_end_color, default: nil
237
+
238
+ # :method: background_center_color
239
+ # :call-seq:
240
+ # background_center_color() -> String or nil
241
+ # background_center_color(value) -> String
242
+ #
243
+ # Intermediate color of the linear gradient background. Setting it makes
244
+ # the gradient run through three colors.
245
+ #
246
+ # [value]
247
+ # Hexadecimal color code (e.g., <code>"#RRGGBB"</code>)
248
+ option :background_center_color, default: nil
249
+
250
+ # :method: background_center_position
251
+ # :call-seq:
252
+ # background_center_position() -> String or nil
253
+ # background_center_position(value) -> String
254
+ #
255
+ # Position of the intermediate color stop, between the start and end of
256
+ # the gradient. Defaults to <code>"50%"</code>.
257
+ #
258
+ # [value]
259
+ # A percentage between <code>"0%"</code> and <code>"100%"</code>
260
+ option :background_center_position, default: nil
261
+
112
262
  # Initializes a new Flex Message Box component.
113
263
  # The provided block is instance-eval'd, allowing DSL methods for adding
114
- # child components (e.g., {#text}, {#button}, nested {#box}) to be called.
264
+ # child components (e.g., +text+, +button+, nested +box+) to be called.
115
265
  #
116
- # @param context [Object, nil] An optional context for the builder.
117
- # @param options [Hash] A hash of options to set instance variables.
118
- # Corresponds to the `option` definitions in this class and included modules.
119
- # @param block [Proc, nil] A block to define the contents of this box.
266
+ # [context]
267
+ # An optional context for the builder
268
+ # [options]
269
+ # A hash of options to set instance variables.
270
+ # Corresponds to the +option+ definitions in this class and included modules
271
+ # [block]
272
+ # A block to define the contents of this box
120
273
  def initialize(context: nil, **options, &)
121
274
  @contents = [] # Holds child components
122
275
  super # Calls Base#initialize, sets options, and evals block
123
276
  end
124
277
 
125
- # Adds a nested Flex {Box} component to this box's contents.
278
+ # Adds a nested Flex Box component to this box's contents.
279
+ #
280
+ # [options]
281
+ # Options for the nested box (see Box)
282
+ # [block]
283
+ # A block to define the contents of the nested box
126
284
  #
127
- # @param options [Hash] Options for the nested box. See {Box#initialize}.
128
- # @param block [Proc] A block to define the contents of the nested box.
129
- # @return [Flex::Box] The newly created nested Box object.
285
+ # Returns the newly created nested Box object.
130
286
  def box(**options, &)
131
287
  @contents << Flex::Box.new(context: context, **options, &)
132
288
  end
133
289
 
134
- # Adds a Flex {Text} component to this box's contents.
290
+ # Adds a Flex Text component to this box's contents.
291
+ #
292
+ # [text]
293
+ # The text content
294
+ # [options]
295
+ # Options for the text component (see Text)
296
+ # [block]
297
+ # An optional block for the text component. This can be used
298
+ # to define an action for the text or to add Span components within the text
299
+ #
300
+ # Returns the newly created Text object.
301
+ #
302
+ # == Example: Simple text component
303
+ #
304
+ # text "Hello, World!"
305
+ #
306
+ # === Example: Text with an action
307
+ #
308
+ # text "Click me" do
309
+ # message "You clicked me!", label: "Action"
310
+ # end
135
311
  #
136
- # @param text [String] The text content.
137
- # @param options [Hash] Options for the text component. See {Text#initialize}.
138
- # @param block [Proc, nil] An optional block for the text component (e.g., for an action).
139
- # @return [Flex::Text] The newly created Text object.
140
- def text(text, **options, &)
312
+ # === Example: Text with spans
313
+ #
314
+ # text "This has " do
315
+ # span "styled", color: "#FF0000"
316
+ # span " parts"
317
+ # end
318
+ def text(text = nil, **options, &)
141
319
  @contents << Flex::Text.new(text, context: context, **options, &)
142
320
  end
143
321
 
144
- # Adds a Flex {Button} component to this box's contents.
322
+ # Adds a Flex Button component to this box's contents.
323
+ #
324
+ # [options]
325
+ # Options for the button component (see Button)
326
+ # [block]
327
+ # A block to define the button's action and properties
145
328
  #
146
- # @param options [Hash] Options for the button component. See {Button#initialize}.
147
- # @param block [Proc] A block to define the button's action and properties.
148
- # @return [Flex::Button] The newly created Button object.
329
+ # Returns the newly created Button object.
149
330
  def button(**options, &)
150
331
  @contents << Flex::Button.new(context: context, **options, &)
151
332
  end
152
333
 
153
- # Adds a Flex {Image} component to this box's contents.
334
+ # Adds a Flex Image component to this box's contents.
335
+ #
336
+ # [url]
337
+ # The URL of the image
338
+ # [options]
339
+ # Options for the image component (see Image)
340
+ # [block]
341
+ # An optional block for the image component (e.g., for an action)
154
342
  #
155
- # @param url [String] The URL of the image.
156
- # @param options [Hash] Options for the image component. See {Image#initialize}.
157
- # @param block [Proc, nil] An optional block for the image component (e.g., for an action).
158
- # @return [Flex::Image] The newly created Image object.
343
+ # Returns the newly created Image object.
159
344
  def image(url, **options, &)
160
345
  @contents << Flex::Image.new(url, context: context, **options, &)
161
346
  end
162
347
 
163
- def to_h
348
+ # Adds an Icon component to this box's contents.
349
+ #
350
+ # Icons decorate the text next to them and can only be used in a box
351
+ # whose +layout+ is +:baseline+.
352
+ #
353
+ # [url]
354
+ # The HTTPS URL of the icon image
355
+ # [options]
356
+ # Options for the icon component (e.g., +:size+, +:aspect_ratio+)
357
+ # [block]
358
+ # An optional block for further configuration
359
+ #
360
+ # == Example
361
+ #
362
+ # box layout: :baseline do
363
+ # icon "https://example.com/star.png", size: :sm
364
+ # text "4.0", margin: :md
365
+ # end
366
+ def icon(url, **options, &)
367
+ @contents << Flex::Icon.new(url, context: context, **options, &)
368
+ end
369
+
370
+ # Adds a Flex Separator component to this box's contents.
371
+ #
372
+ # A separator is a simple component that draws a horizontal line,
373
+ # creating a visual division between other components in a container.
374
+ #
375
+ # [options]
376
+ # Options for the separator component (see Separator)
377
+ # [block]
378
+ # An optional block for advanced separator configuration
379
+ #
380
+ # Returns the newly created Separator object.
381
+ def separator(**options, &)
382
+ @contents << Flex::Separator.new(context: context, **options, &)
383
+ end
384
+
385
+ def to_h # :nodoc:
164
386
  raise RequiredError, "layout is required" if layout.nil?
165
387
 
166
388
  return to_sdkv2 if context.sdkv2?
@@ -170,10 +392,17 @@ module Line
170
392
 
171
393
  private
172
394
 
395
+ # :nodoc:
173
396
  def to_api # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
174
397
  {
175
398
  type: "box",
176
399
  layout: layout,
400
+ # Appearance
401
+ backgroundColor: background_color,
402
+ borderColor: border_color,
403
+ borderWidth: border_width,
404
+ cornerRadius: corner_radius,
405
+ background: api_background,
177
406
  # Position & Layout
178
407
  justifyContent: justify_content,
179
408
  alignItems: align_items,
@@ -205,10 +434,17 @@ module Line
205
434
  }.compact
206
435
  end
207
436
 
437
+ # :nodoc:
208
438
  def to_sdkv2 # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
209
439
  {
210
440
  type: "box",
211
441
  layout: layout,
442
+ # Appearance
443
+ background_color: background_color,
444
+ border_color: border_color,
445
+ border_width: border_width,
446
+ corner_radius: corner_radius,
447
+ background: sdkv2_background,
212
448
  # Position & Layout
213
449
  justify_content: justify_content,
214
450
  align_items: align_items,
@@ -239,6 +475,57 @@ module Line
239
475
  action: action&.to_h # From Actionable module
240
476
  }.compact
241
477
  end
478
+
479
+ # Builds the nested +background+ object for a linear gradient, or +nil+
480
+ # when no gradient is configured.
481
+ def api_background # :nodoc:
482
+ return if no_gradient?
483
+
484
+ validate_gradient!
485
+
486
+ {
487
+ type: "linearGradient",
488
+ angle: background_angle,
489
+ startColor: background_start_color,
490
+ endColor: background_end_color,
491
+ centerColor: background_center_color,
492
+ centerPosition: background_center_position
493
+ }.compact
494
+ end
495
+
496
+ # :nodoc:
497
+ def sdkv2_background
498
+ return if no_gradient?
499
+
500
+ validate_gradient!
501
+
502
+ {
503
+ type: "linearGradient",
504
+ angle: background_angle,
505
+ start_color: background_start_color,
506
+ end_color: background_end_color,
507
+ center_color: background_center_color,
508
+ center_position: background_center_position
509
+ }.compact
510
+ end
511
+
512
+ def no_gradient? # :nodoc:
513
+ (gradient_required + [background_center_color, background_center_position]).compact.empty?
514
+ end
515
+
516
+ def gradient_required # :nodoc:
517
+ [background_angle, background_start_color, background_end_color]
518
+ end
519
+
520
+ # Raises RequiredError when the gradient is only partly specified, since
521
+ # LINE rejects a background that is missing its angle or end colors.
522
+ def validate_gradient! # :nodoc:
523
+ return unless gradient_required.any?(&:nil?)
524
+
525
+ raise RequiredError,
526
+ "background_angle, background_start_color and background_end_color " \
527
+ "are required for a linear gradient"
528
+ end
242
529
  end
243
530
  end
244
531
  end