line-message-builder 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bbeb0eeec944a0886b6e6dec3b171c88182c0097ad31c03cc16d7270f1eb471
4
- data.tar.gz: 8f08afeab2e40b152e8e4218b00f03f725be5f3cfa70b687ebaf20e7d1dd2d7e
3
+ metadata.gz: 8051ec09aa3f71ec93dc5cbe685610fd6fe6d5c4a3b086f5b5ddbef6b98e7c3c
4
+ data.tar.gz: cd043754cc232ed8b4e8cec6751413bf2f87e9cd3ea4b23f521346cb1ca7a86d
5
5
  SHA512:
6
- metadata.gz: 0afd2ab03e4bbe7df364ebc27764380e48b9fd00a0a78ba345655f9227b7ff1cac00831024fd4ca923d2df1fb195c7e3c4947e6290f530a3466d002b325af4f3
7
- data.tar.gz: 91455d81ccc9d6aa646e5a5851ad55baa19e89d4c427b4c9e4fa951676f6cf5d6e8005983d5a76610c05ced666a353d06f54ef7020516ad67250000cb4379ba7
6
+ metadata.gz: 4d951b1938f6a27ad366e5b4f08e1de7496c5d130ac95e40d4f15c2ca86a928a19a5cfb46184d958dae6afd664dfa68d4c50a2d7e00c172445e42205e3987abc
7
+ data.tar.gz: 802c37d5e9d2beb7f641046bf8223e9a4fc26290b5e9f1a5a07b1754027509b1b2b63952be93622908674d14321fe9c4cceea770aaf2d56684caaa94b1bb7d69
@@ -1 +1 @@
1
- {".":"0.4.0"}
1
+ {".":"0.5.0"}
data/.rspec CHANGED
@@ -1,3 +1,5 @@
1
1
  --format documentation
2
+ --format RspecJunitFormatter
3
+ --out junit.xml
2
4
  --color
3
5
  --require spec_helper
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
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
+
3
25
  ## [0.4.0](https://github.com/elct9620/line-message-builder/compare/v0.3.0...v0.4.0) (2025-04-06)
4
26
 
5
27
 
data/README.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # LINE Message Builder
2
2
 
3
+ [![.github/workflows/main.yml](https://github.com/elct9620/line-message-builder/actions/workflows/main.yml/badge.svg)](https://github.com/elct9620/line-message-builder/actions/workflows/main.yml)
4
+ [![codecov](https://codecov.io/gh/elct9620/line-message-builder/graph/badge.svg?token=9TJTSRIL0X)](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:
@@ -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
- def initialize(text, label: nil, context: nil, &)
10
- @text = text
11
- @label = label
12
-
13
- super(context: context, &)
14
- end
9
+ attr_reader :text
15
10
 
16
- def label(label)
17
- @label = label
18
- end
11
+ option :label, default: nil
19
12
 
20
- def text(text)
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: @label,
28
- text: @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
- def initialize(data, label: nil, display_text: nil, context: nil, &)
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
- def label(label)
18
- @label = label
19
- end
11
+ option :label, default: nil
12
+ option :display_text, default: nil
20
13
 
21
- def data(data)
14
+ def initialize(data, context: nil, **options, &)
22
15
  @data = data
23
- end
24
16
 
25
- def display_text(display_text)
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: @label,
33
- data: @data,
34
- displayText: @display_text
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
- instance_variable_set("@#{option}", options[option]) if options.key?(option)
42
+ send(option, options[option]) if options.key?(option)
42
43
  end
43
44
 
44
45
  instance_eval(&block) if ::Kernel.block_given?
@@ -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,10 +6,23 @@ 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
+ include Actionable
10
+ include Position::Padding
11
+ include Position::Margin
12
+ include Position::Offset
13
+
9
14
  attr_reader :contents
10
15
 
11
- option :layout, default: :horizontal
12
- option :spacing, default: nil
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
13
26
  option :flex, default: nil
14
27
 
15
28
  def initialize(context: nil, **options, &)
@@ -34,16 +47,33 @@ module Line
34
47
  @contents << Flex::Image.new(url, context: context, **options, &)
35
48
  end
36
49
 
37
- def to_h
50
+ def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
38
51
  raise RequiredError, "layout is required" if layout.nil?
39
- raise RequiredError, "contents is required" if contents.empty?
40
52
 
41
53
  {
42
54
  type: "box",
43
55
  layout: layout,
56
+ # Position
57
+ justifyContent: justify_content,
58
+ alignItems: align_items,
44
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,
45
74
  flex: flex,
46
- contents: contents.map(&:to_h)
75
+ contents: contents.map(&:to_h),
76
+ action: action&.to_h
47
77
  }.compact
48
78
  end
49
79
  end
@@ -6,35 +6,39 @@ 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
- attr_reader :action
9
+ include Actionable
10
+ include Position::Vertical
11
+ include Position::Padding
12
+ include Position::Margin
13
+ include Position::Offset
10
14
 
11
15
  option :flex, default: nil
12
- option :margin, default: nil
13
16
  option :style, default: :link
14
17
  option :height, default: :md
15
18
 
16
- def initialize(context: nil, **options, &)
17
- @action = nil
18
-
19
- super
20
- end
21
-
22
- def message(text, label:, display_text: nil, &)
23
- @action = Actions::Message.new(text, label: label, display_text: display_text, &)
24
- end
25
-
26
- def postback(data, label: nil, display_text: nil, &)
27
- @action = Actions::Postback.new(data, label: label, display_text: display_text, &)
28
- end
29
-
30
- def to_h
19
+ def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
31
20
  raise RequiredError, "action is required" if action.nil?
32
21
 
33
22
  {
34
23
  type: "button",
35
24
  action: action.to_h,
36
- flex: flex,
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
37
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,
38
42
  style: style,
39
43
  height: height
40
44
  }.compact
@@ -6,14 +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
+
9
15
  attr_reader :url
10
16
 
11
17
  option :size, default: nil
12
18
  option :aspect_ratio, default: nil
13
19
  option :aspect_mode, default: nil
14
20
  option :flex, default: nil
15
- option :margin, default: nil
16
- option :align, default: nil
17
21
 
18
22
  def initialize(url, context: nil, **options, &)
19
23
  @url = url
@@ -21,18 +25,28 @@ module Line
21
25
  super(context: context, **options, &)
22
26
  end
23
27
 
24
- def to_h # rubocop:disable Metrics/MethodLength
28
+ def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
25
29
  raise RequiredError, "url is required" if url.nil?
26
30
 
27
31
  {
28
32
  type: "image",
29
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,
30
45
  size: size,
31
46
  flex: flex,
32
- margin: margin,
33
- align: align,
34
47
  aspectRatio: aspect_ratio,
35
- aspectMode: aspect_mode
48
+ aspectMode: aspect_mode,
49
+ action: action&.to_h
36
50
  }.compact
37
51
  end
38
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,15 +6,19 @@ 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
+
9
15
  attr_reader :text
10
16
 
11
17
  option :size, default: nil
12
18
  option :wrap, default: false
13
19
  option :line_spacing, default: nil
14
20
  option :color, default: nil
15
- option :align, default: nil
16
21
  option :flex, default: nil
17
- option :margin, default: nil
18
22
 
19
23
  def initialize(text, context: nil, **options, &)
20
24
  @text = text
@@ -26,19 +30,29 @@ module Line
26
30
  @wrap = true
27
31
  end
28
32
 
29
- def to_h # rubocop:disable Metrics/MethodLength
33
+ def to_h # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
30
34
  raise RequiredError, "text is required" if text.nil?
31
35
 
32
36
  {
33
37
  type: "text",
34
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,
35
50
  wrap: wrap,
36
51
  lineSpacing: line_spacing,
37
52
  color: color,
38
53
  size: size,
39
- align: align,
40
- margin: margin,
41
- flex: flex
54
+ flex: flex,
55
+ action: action&.to_h
42
56
  }.compact
43
57
  end
44
58
  end
@@ -6,6 +6,8 @@ module Line
6
6
  # The Flex module allows to build Flex messages.
7
7
  module Flex
8
8
  require_relative "flex/builder"
9
+ require_relative "flex/actionable"
10
+ require_relative "flex/position"
9
11
 
10
12
  # Container
11
13
  require_relative "flex/bubble"
@@ -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
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Line
4
+ module Message
5
+ module Builder
6
+ # :nodoc:
7
+ module Validators
8
+ require_relative "validators/enum"
9
+ require_relative "validators/size"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -3,7 +3,7 @@
3
3
  module Line
4
4
  module Message
5
5
  module Builder
6
- VERSION = "0.4.0"
6
+ VERSION = "0.5.0"
7
7
  end
8
8
  end
9
9
  end
@@ -8,8 +8,10 @@ module Line
8
8
  module Builder
9
9
  class Error < StandardError; end
10
10
  class RequiredError < Error; end
11
+ class ValidationError < Error; end
11
12
 
12
13
  require_relative "builder/base"
14
+ require_relative "builder/validators"
13
15
  require_relative "builder/actions"
14
16
  require_relative "builder/quick_reply"
15
17
  require_relative "builder/container"
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.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-06 00:00:00.000000000 Z
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,14 +32,19 @@ 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