line-message-builder 0.2.0 → 0.3.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: f66fccfc1d5cd52c32662d8e912aac28f79e82d0b86ee837125ebe292fdd5f13
4
- data.tar.gz: b819400dc6c6afbcb85b99335dbbf60c0a8c2cfe71c4f4f2aa3653e56fd5edf5
3
+ metadata.gz: aa7a2c0c112ef20086d81a2c1cf4b1c430ffe291c07ccfc92dfe8d81db1ea980
4
+ data.tar.gz: 163eb284640eeec1e5a035492ebca95b34d703d372f5d472e4330a762d7b2ceb
5
5
  SHA512:
6
- metadata.gz: 2e7a7f40dede7c209dd9d4f581020a2d9cf9b9403675b055382446a440852861ab1585832b9bae31b31a12aaea68f5bd7c32e2ce9cde8950715db38864b726dd
7
- data.tar.gz: 87d0a63d6fdab6a7338745eac2e3b391605c8631ac7cef4226ac17e098b93ac152f39ecfe5bbfbe9f98576ab52fd92e9a1377819c3bfc10238cd95e342ff09fb
6
+ metadata.gz: bcadb195ad72f851fcc648f6641ab547fc2a1885583f64be97f08288f43025246d2a14dd311103a5c64521e636dfb2bd0f89f61deccedec75ebe8bebdc528d2c
7
+ data.tar.gz: 1d612904e46b6e3e87590edf414b7839fa18412fe1c4734cdb961aacc8c1ed2e87a87a425b3cf563cc1eff4ec7337deaf0ff81592b75520dabba78363ec67629
@@ -1 +1 @@
1
- {".":"0.2.0"}
1
+ {".":"0.3.0"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0](https://github.com/elct9620/line-message-builder/compare/v0.2.0...v0.3.0) (2025-04-05)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * release 0.3.0 ([2f0b00c](https://github.com/elct9620/line-message-builder/commit/2f0b00c875a2d547c576e383aaeeae3bf777e898))
9
+
3
10
  ## [0.2.0](https://github.com/elct9620/line-message-builder/compare/v0.1.0...v0.2.0) (2025-04-05)
4
11
 
5
12
 
data/README.md CHANGED
@@ -62,8 +62,8 @@ For Rails, you can use `view_context` to make `Builder` to access Rails helpers.
62
62
  builder = Line::MessageBuilder::Builder.with(view_context) do
63
63
  text "Anything you want?" do
64
64
  quick_reply do
65
- action "Yes", label: "Yes", image_url: image_url("yes.png")
66
- action "No", label: "No", image_url: image_url("no.png")
65
+ message "Yes", label: "Yes", image_url: image_url("yes.png")
66
+ message "No", label: "No", image_url: image_url("no.png")
67
67
  end
68
68
  end
69
69
  end
@@ -82,8 +82,8 @@ context = ActionView::Base.new(
82
82
  builder = Line::MessageBuilder::Builder.with(context) do
83
83
  text "Anything you want?" do
84
84
  quick_reply do
85
- action "Yes", label: "Yes", image_url: image_url("yes.png")
86
- action "No", label: "No", image_url: image_url("no.png")
85
+ message "Yes", label: "Yes", image_url: image_url("yes.png")
86
+ message "No", label: "No", image_url: image_url("no.png")
87
87
  end
88
88
  end
89
89
  end
@@ -91,6 +91,16 @@ end
91
91
 
92
92
  ### RSpec Matcher
93
93
 
94
+ | Matcher | Description |
95
+ | --------------------------- | ------------------------------------ |
96
+ | `have_line_text_message` | Match a text message |
97
+ | `have_line_flex_message` | Match a flex message |
98
+ | `have_line_flex_text` | Match a flex message with text |
99
+ | `have_line_flex_image` | Match a flex message with image |
100
+ | `have_line_flex_button` | Match a flex message with button |
101
+ | `have_line_flex_box` | Match a flex message with box |
102
+
103
+
94
104
  Add `line/message/rspec` to your `spec_helper.rb` or `rails_helper.rb`:
95
105
 
96
106
  ```ruby
@@ -121,6 +131,19 @@ it { is_expected.to have_line_text_message("Hello, world!") }
121
131
  it { is_expected.to have_line_text_message(/Nice to meet you!/) }
122
132
  ```
123
133
 
134
+ The matchers can work with webmock `a_request`:
135
+
136
+ ```ruby
137
+ it "reply with message" do
138
+ expect(a_request(:post, "https://api.line.me/v2/bot/message/reply")
139
+ .with(
140
+ body: hash_including({
141
+ messages: have_line_text_message(/Hello, world!/),
142
+ },
143
+ ))).to have_been_made.once
144
+ end
145
+ ```
146
+
124
147
  ## Capabilities
125
148
 
126
149
  - ✅ Supported
@@ -9,20 +9,22 @@ module Line
9
9
  option :alt_text, default: nil
10
10
 
11
11
  def initialize(context: nil, **options, &)
12
- @contents = []
12
+ @contents = nil
13
13
 
14
14
  super
15
15
  end
16
16
 
17
17
  def bubble(&)
18
- @contents << Line::Message::Builder::Flex::Bubble.new(context: context, &)
18
+ @contents = Line::Message::Builder::Flex::Bubble.new(context: context, &)
19
19
  end
20
20
 
21
21
  def to_h
22
+ raise Error, "contents should be bubble or carousel" if @contents.nil?
23
+
22
24
  {
23
25
  type: "flex",
24
26
  altText: @alt_text,
25
- contents: @contents.map(&:to_h),
27
+ contents: @contents.to_h,
26
28
  quickReply: @quick_reply&.to_h
27
29
  }.compact
28
30
  end
@@ -3,7 +3,7 @@
3
3
  module Line
4
4
  module Message
5
5
  module Builder
6
- VERSION = "0.2.0"
6
+ VERSION = "0.3.0"
7
7
  end
8
8
  end
9
9
  end
@@ -20,9 +20,10 @@ module Line
20
20
  end
21
21
 
22
22
  def matches?(actual)
23
- @actual = actual
23
+ @actual = Utils.stringify_keys!(actual, deep: true)
24
24
  @actual.any? { |message| match_flex_component?(message) }
25
25
  end
26
+ alias == matches?
26
27
 
27
28
  def failure_message
28
29
  return "expected to find a flex component" if @expected.nil?
@@ -34,16 +35,16 @@ module Line
34
35
  private
35
36
 
36
37
  def match_flex_component?(message)
37
- return false unless message[:type] == "flex"
38
+ return false unless message["type"] == "flex"
38
39
 
39
- message[:contents].any? { |content| match_content?(content) }
40
+ match_content?(message["contents"])
40
41
  end
41
42
 
42
43
  def match_content?(content)
43
- return match_bubble?(content) if content[:type] == "bubble"
44
+ return match_bubble?(content) if content["type"] == "bubble"
44
45
 
45
- if content[:contents]
46
- return content[:contents].any? do |nested_content|
46
+ if content["contents"]
47
+ return content["contents"].any? do |nested_content|
47
48
  match_content?(nested_content)
48
49
  end || @expected.call(content)
49
50
  end
@@ -52,7 +53,7 @@ module Line
52
53
  end
53
54
 
54
55
  def match_bubble?(content)
55
- %i[header hero body footer].any? do |key|
56
+ %w[header hero body footer].any? do |key|
56
57
  block = content[key]
57
58
  next unless block
58
59
 
@@ -61,7 +62,7 @@ module Line
61
62
  end
62
63
 
63
64
  def match_bubble_block?(block)
64
- return block[:contents].any? { |nested_content| match_content?(nested_content) } if block[:contents]
65
+ return block["contents"].any? { |nested_content| match_content?(nested_content) } if block["contents"]
65
66
 
66
67
  match_content?(block)
67
68
  end
@@ -72,37 +73,45 @@ module Line
72
73
  end
73
74
 
74
75
  def have_line_flex_box(**options) # rubocop:disable Naming/PredicateName
76
+ options = Utils.stringify_keys!(options, deep: true)
77
+
75
78
  HaveFlexComponent.new(expected_desc: "box(#{options.inspect})") do |content|
76
- next false unless content[:type] == "box"
79
+ next false unless content["type"] == "box"
77
80
 
78
81
  ::RSpec::Matchers::BuiltIn::Include.new(options).matches?(content)
79
82
  end
80
83
  end
81
84
 
82
85
  def have_line_flex_text(text, **options) # rubocop:disable Naming/PredicateName
86
+ options = Utils.stringify_keys!(options, deep: true)
87
+
83
88
  HaveFlexComponent.new(expected_desc: "text(#{text.inspect})") do |content|
84
- next false unless content[:type] == "text"
89
+ next false unless content["type"] == "text"
85
90
 
86
- content[:text].match?(text) && ::RSpec::Matchers::BuiltIn::Include.new(options).matches?(content)
91
+ content["text"].match?(text) && ::RSpec::Matchers::BuiltIn::Include.new(options).matches?(content)
87
92
  end
88
93
  end
89
94
 
90
95
  def have_line_flex_button(type, **options) # rubocop:disable Naming/PredicateName
96
+ options = Utils.stringify_keys!(options, deep: true)
97
+
91
98
  HaveFlexComponent.new(expected_desc: "#{type} button(#{options.inspect})") do |content|
92
- next false unless content[:type] == "button"
99
+ next false unless content["type"] == "button"
93
100
 
94
- ::RSpec::Matchers::BuiltIn::Include.new({ type: type, **options }).matches?(content[:action]) ||
95
- ::RSpec::Matchers::BuiltIn::Include.new({ **options, action: ::RSpec::Matchers::BuiltIn::Include.new(
96
- type: type
101
+ ::RSpec::Matchers::BuiltIn::Include.new({ "type" => type, **options }).matches?(content["action"]) ||
102
+ ::RSpec::Matchers::BuiltIn::Include.new({ **options, "action" => ::RSpec::Matchers::BuiltIn::Include.new(
103
+ "type" => type
97
104
  ) }).matches?(content)
98
105
  end
99
106
  end
100
107
 
101
108
  def have_line_flex_image(url, **options) # rubocop:disable Naming/PredicateName
109
+ options = Utils.stringify_keys!(options, deep: true)
110
+
102
111
  HaveFlexComponent.new(expected_desc: "image(#{url.inspect})") do |content|
103
- next false unless content[:type] == "image"
112
+ next false unless content["type"] == "image"
104
113
 
105
- ::RSpec::Matchers::BuiltIn::Include.new({ url: url, **options }).matches?(content)
114
+ ::RSpec::Matchers::BuiltIn::Include.new({ "url" => url, **options }).matches?(content)
106
115
  end
107
116
  end
108
117
  end
@@ -18,9 +18,10 @@ module Line
18
18
  end
19
19
 
20
20
  def matches?(actual)
21
- @actual = actual
21
+ @actual = Utils.stringify_keys!(actual, deep: true)
22
22
  @actual.any? { |message| match_alt_text?(message) }
23
23
  end
24
+ alias == matches?
24
25
 
25
26
  def failure_message
26
27
  "expected to find a flex message alt text matching #{@expected}"
@@ -29,10 +30,10 @@ module Line
29
30
  private
30
31
 
31
32
  def match_alt_text?(message)
32
- return false unless message[:type] == "flex"
33
+ return false unless message["type"] == "flex"
33
34
  return true if @expected.nil?
34
35
 
35
- message[:altText].match?(@expected)
36
+ message["altText"].match?(@expected)
36
37
  end
37
38
  end
38
39
 
@@ -8,7 +8,7 @@ module Line
8
8
  # The quick reply matcher for RSpec to search for quick reply action in the message array.
9
9
  class HaveQuickReply
10
10
  def initialize(expected)
11
- @expected = expected
11
+ @expected = Utils.stringify_keys!(expected, deep: true)
12
12
  end
13
13
 
14
14
  def description
@@ -18,9 +18,10 @@ module Line
18
18
  end
19
19
 
20
20
  def matches?(actual)
21
- @actual = actual
21
+ @actual = Utils.stringify_keys!(actual, deep: true)
22
22
  @actual.any? { |message| match_message(message) }
23
23
  end
24
+ alias == matches?
24
25
 
25
26
  def failure_message
26
27
  "expected to find a quick reply message matching #{@expected}"
@@ -29,10 +30,10 @@ module Line
29
30
  private
30
31
 
31
32
  def match_message(message)
32
- reply = message[:quickReply]
33
+ reply = message["quickReply"]
33
34
  return false unless reply
34
35
 
35
- reply[:items].any? { |item| match_action(item[:action]) }
36
+ reply["items"].any? { |item| match_action(item["action"]) }
36
37
  end
37
38
 
38
39
  def match_action(action)
@@ -18,15 +18,16 @@ module Line
18
18
  end
19
19
 
20
20
  def matches?(actual)
21
- @actual = actual
21
+ @actual = Utils.stringify_keys!(actual, deep: true)
22
22
  @actual.each do |message|
23
- next unless message[:type] == "text"
23
+ next unless message["type"] == "text"
24
24
 
25
- return true if message[:text].match?(@expected)
25
+ return true if message["text"].match?(@expected)
26
26
  end
27
27
 
28
28
  false
29
29
  end
30
+ alias == matches?
30
31
 
31
32
  def failure_message
32
33
  "expected to find a text message matching #{@expected}"
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Line
4
+ module Message
5
+ module RSpec
6
+ module Matchers
7
+ # :nodoc:
8
+ module Utils
9
+ def self.stringify_keys!(arg, deep: false) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
10
+ case arg
11
+ when Hash
12
+ Hash[
13
+ *arg.map { |key, value| [key.to_s, deep ? stringify_keys!(value, deep: deep) : value] }
14
+ .inject([]) { |memo, pair| memo + pair }
15
+ ]
16
+ when Array
17
+ arg.map { |item| deep ? stringify_keys!(item, deep: deep) : item }
18
+ else
19
+ arg
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "matchers/utils"
3
4
  require_relative "matchers/have_text_message"
4
5
  require_relative "matchers/have_quick_reply"
5
-
6
6
  require_relative "matchers/have_flex_message"
7
7
  require_relative "matchers/have_flex_component"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: line-message-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya
@@ -47,6 +47,7 @@ files:
47
47
  - lib/line/message/rspec/matchers/have_flex_message.rb
48
48
  - lib/line/message/rspec/matchers/have_quick_reply.rb
49
49
  - lib/line/message/rspec/matchers/have_text_message.rb
50
+ - lib/line/message/rspec/matchers/utils.rb
50
51
  - release-please-config.json
51
52
  - sig/line/message/builder.rbs
52
53
  homepage: https://github.com/elct9620/line-message-builder