Skip to content

Commit 60a6b7b

Browse files
authored
Fix unnecessary camelize issue (line#567)
fix line#562 This solves the problem of camelizing API fields that should not be camelized. In short, when using `TextV2` messages, the user can specify their own key in the `substituion`, but the bug occurs when snake_case is used there. This should be set in the request class side, but since request body specification by hash without request class is also accepted, we have to deal with this workaround. This is fine for now because there is only `substitution`, but if a pattern caramelizes and does not caramelize the same key name in the future, a major modification or breaking change may be necessary.
1 parent 826c9f4 commit 60a6b7b

File tree

6 files changed

+59
-11
lines changed

6 files changed

+59
-11
lines changed

.rubocop.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Metrics/AbcSize:
7777
Enabled: false
7878
Metrics/CyclomaticComplexity:
7979
Enabled: false
80+
Metrics/ModuleLength:
81+
Enabled: false
8082
Metrics/PerceivedComplexity:
8183
Enabled: false
8284

lib/line/bot/v2/utils.rb

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ module Line
22
module Bot
33
module V2
44
module Utils
5+
# NOTE: Although it should be set in the request class side,
6+
# it can only be set here because requests in Hash are also permitted.
7+
# If there is a mix of camelize and non-camelize cases even with the same key name,
8+
# breaking change that does not allow Hash requests will be necessary.
9+
NO_CAMELIZE_PARENT_KEYS = %w(substitution).freeze
10+
511
# NOTE: line-bot-sdk-ruby users should not use this. Breaking changes may occur, so use at your own risk.
612
def self.deep_underscore(hash)
713
hash.each_with_object({}) do |(key, value), result| # steep:ignore UnannotatedEmptyCollection
@@ -57,12 +63,16 @@ def self.deep_camelize(object)
5763
object.map { |item| deep_camelize(item) }
5864
when Hash
5965
object.each_with_object({}) do |(k, v), new_object| # steep:ignore UnannotatedEmptyCollection
60-
camel_key = camelize(k)
61-
next if camel_key.nil?
62-
63-
camel_key = camel_key.to_sym
64-
new_value = v.is_a?(Array) || v.is_a?(Hash) ? deep_camelize(v) : v
65-
new_object[camel_key] = new_value
66+
if NO_CAMELIZE_PARENT_KEYS.include?(k.to_s)
67+
new_object[k.to_sym] = if v.is_a?(Hash)
68+
v.transform_keys(&:to_sym).transform_values { deep_camelize(_1) }
69+
else
70+
v
71+
end
72+
else
73+
camel_key = camelize(k)&.to_sym
74+
new_object[camel_key] = v.is_a?(Array) || v.is_a?(Hash) ? deep_camelize(v) : v if camel_key
75+
end
6676
end
6777
else
6878
object

line-openapi

sig/line/bot/v2/utils.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module Line
22
module Bot
33
module V2
44
module Utils
5+
NO_CAMELIZE_PARENT_KEYS: Array[String]
6+
57
def self.deep_underscore: (Hash[untyped, untyped]) -> Hash[Symbol, untyped]
68

79
def self.deep_symbolize: (untyped) -> untyped

spec/line/bot/v2/misc_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,9 @@
654654
"messages" => [
655655
{
656656
"type" => "textV2",
657-
"text" => " Hello, world! {name} san!",
657+
"text" => " Hello, world! {user_name} san!",
658658
"substitution" => {
659-
"name" => {
659+
"user_name" => {
660660
"type" => "mention",
661661
"mentionee" => {
662662
"type" => "user",
@@ -675,9 +675,9 @@
675675
to: 'USER_ID',
676676
messages: [
677677
Line::Bot::V2::MessagingApi::TextMessageV2.new(
678-
text: ' Hello, world! {name} san!',
678+
text: ' Hello, world! {user_name} san!',
679679
substitution: {
680-
"name": Line::Bot::V2::MessagingApi::MentionSubstitutionObject.new(
680+
user_name: Line::Bot::V2::MessagingApi::MentionSubstitutionObject.new(
681681
mentionee: Line::Bot::V2::MessagingApi::UserMentionTarget.new(
682682
user_id: 'U1234567890'
683683
)

spec/line/bot/v2/utils_spec.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,40 @@ def initialize(name)
121121
expected_output = { key: ['array', 'of', 'values'] }
122122
expect(Line::Bot::V2::Utils.deep_camelize(input)).to eq(expected_output)
123123
end
124+
125+
it "doesn't modify no_camelize_parent_keys children" do
126+
stub_const("Line::Bot::V2::Utils::NO_CAMELIZE_PARENT_KEYS", %w(substitution))
127+
128+
input = {
129+
type: "textV2",
130+
text: "Hello, world! {user_name} san!",
131+
substitution: { # This key should not be camelized
132+
user_name: {
133+
type: "mention",
134+
mentionee: {
135+
type: "user",
136+
"user_id": "U1234567890abcdef1234567890abcdef"
137+
}
138+
}
139+
}
140+
}
141+
142+
expected_output = {
143+
type: "textV2",
144+
text: "Hello, world! {user_name} san!",
145+
substitution: {
146+
user_name: {
147+
type: "mention",
148+
mentionee: {
149+
type: "user",
150+
"userId": "U1234567890abcdef1234567890abcdef" # Only this key should be camelized
151+
}
152+
}
153+
}
154+
}
155+
156+
expect(Line::Bot::V2::Utils.deep_camelize(input)).to eq(expected_output)
157+
end
124158
end
125159

126160
describe '.deep_compact' do

0 commit comments

Comments
 (0)