Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
"cSpell.words": [
"mkpath"
],
"[ruby]": {
"editor.defaultFormatter": "rubocop.vscode-rubocop",
}
}
26 changes: 22 additions & 4 deletions lib/copy_tuner_client/dotted_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ module DottedHash
def to_h(dotted_hash)
hash = {}
dotted_hash.to_h.transform_keys(&:to_s).sort.each do |key, value|
_hash = key.split('.').reverse.inject(value) { |memo, key| { key => memo } }
# Rails i18n標準との互換性のため、特定のキーを適切な型に変換
converted_value = convert_value_type(key, value)
_hash = key.split('.').reverse.inject(converted_value) { |memo, _key| { _key => memo } }
hash.deep_merge!(_hash)
end
hash
Expand All @@ -16,8 +18,8 @@ def conflict_keys(dotted_hash)
all_keys.each_with_index do |key, index|
prefix = "#{key}."
conflict_keys = ((index + 1)..Float::INFINITY)
.take_while { |i| all_keys[i]&.start_with?(prefix) }
.map { |i| all_keys[i] }
.take_while { |i| all_keys[i]&.start_with?(prefix) }
.map { |i| all_keys[i] }

if conflict_keys.present?
results[key] = conflict_keys
Expand All @@ -27,6 +29,22 @@ def conflict_keys(dotted_hash)
results
end

module_function :to_h, :conflict_keys
private

def convert_value_type(key, value)
return value unless value.is_a?(String)

# Rails i18n標準で数値型として扱われるキー
if key.end_with?('.precision')
value.to_i
# Rails i18n標準で真偽値として扱われるキー
elsif key.end_with?('.significant', '.strip_insignificant_zeros')
value == 'true'
else
value
end
end

module_function :to_h, :conflict_keys, :convert_value_type # rubocop:disable Style/AccessModifierDeclarations
end
end
7 changes: 3 additions & 4 deletions lib/copy_tuner_client/i18n_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,9 @@ def lookup(locale, key, scope = [], options = {})
return exact_match
end

# NOTE: 色々考慮する必要があることが分かったため暫定対応として、ツリーキャッシュを使用しないようにしている
# ensure_tree_cache_current
# tree_result = lookup_in_tree_cache(parts)
# return tree_result if tree_result
ensure_tree_cache_current
tree_result = lookup_in_tree_cache(parts)
return tree_result if tree_result

content = super

Expand Down
2 changes: 1 addition & 1 deletion lib/copy_tuner_client/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module CopyTunerClient
# Client version
VERSION = '1.1.2'.freeze
VERSION = '1.1.3'.freeze

# API version being used to communicate with the server
API_VERSION = '2.0'.freeze
Expand Down
92 changes: 83 additions & 9 deletions spec/copy_tuner_client/dotted_hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@
describe ".to_h" do
subject { CopyTunerClient::DottedHash.to_h(dotted_hash) }

context 'empty keys' do
context '空のキーの場合' do
let(:dotted_hash) { {} }

it { is_expected.to eq({}) }
end

context 'with single-level keys' do
context '1階層のキーの場合' do
let(:dotted_hash) { { 'key' => 'test value', other_key: 'other value' } }

it { is_expected.to eq({ 'key' => 'test value', 'other_key' => 'other value' }) }
end

context 'array of key value pairs' do
context 'キーと値の配列の場合' do
let(:dotted_hash) { [['key', 'test value'], ['other_key', 'other value']] }

it { is_expected.to eq({ 'key' => 'test value', 'other_key' => 'other value' }) }
end

context "with multi-level blurb keys" do
context "複数階層のblurbキーの場合" do
let(:dotted_hash) do
{
'en.test.key' => 'en test value',
Expand All @@ -31,7 +31,7 @@
}
end

it do
it "正しくネストされたハッシュに変換されること" do
is_expected.to eq({
'en' => {
'test' => {
Expand All @@ -48,7 +48,7 @@
end
end

context "with conflicting keys" do
context "キーの競合がある場合" do
let(:dotted_hash) do
{
'en.test' => 'invalid value',
Expand All @@ -58,12 +58,86 @@

it { is_expected.to eq({ 'en' => { 'test' => { 'key' => 'en test value' } } }) }
end

context "Rails i18nの数値precisionキーの場合" do
let(:dotted_hash) do
{
'en.number.currency.format.precision' => '2',
'en.number.format.precision' => '3',
}
end

it "precision値を整数に変換する" do
is_expected.to eq({
'en' => {
'number' => {
'currency' => {
'format' => {
'precision' => 2,
},
},
'format' => {
'precision' => 3,
},
},
},
})
end
end

context "Rails i18nのbooleanキーの場合" do
let(:dotted_hash) do
{
'en.number.currency.format.significant' => 'false',
'en.number.format.strip_insignificant_zeros' => 'true',
}
end

it "boolean値を実際の真偽値に変換する" do
is_expected.to eq({
'en' => {
'number' => {
'currency' => {
'format' => {
'significant' => false,
},
},
'format' => {
'strip_insignificant_zeros' => true,
},
},
},
})
end
end

context "Rails i18n以外で似たパターンを含むキーの場合" do
let(:dotted_hash) do
{
'en.custom.precision' => 'custom_value',
'en.other.significant_value' => 'true',
}
end

it "Rails i18nパターンで終わるキーのみ変換する" do
is_expected.to eq({
'en' => {
'custom' => {
'precision' => 0, # .precision suffix triggers conversion
},
'other' => {
'significant_value' => 'true', # no conversion for non-exact match
},
},
})
end
end
end

describe ".conflict_keys" do
subject { CopyTunerClient::DottedHash.conflict_keys(dotted_hash) }

context 'valid keys' do
context '有効なキーの場合' do
let(:dotted_hash) do
{
'ja.hoge.test' => 'test',
Expand All @@ -74,7 +148,7 @@
it { is_expected.to eq({}) }
end

context 'invalid keys' do
context '無効なキーの場合' do
let(:dotted_hash) do
{
'ja.hoge.test' => 'test',
Expand All @@ -85,7 +159,7 @@
}
end

it do
it "競合するキーが正しく検出されること" do
is_expected.to eq({
'ja.fuga.test' => %w[ja.fuga.test.hoge],
'ja.hoge.test' => %w[ja.hoge.test.fuga ja.hoge.test.hoge],
Expand Down
2 changes: 1 addition & 1 deletion spec/copy_tuner_client/i18n_backend_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def build_backend
end

# NOTE: 色々考慮する必要があることが分かったため暫定対応として、ツリーキャッシュを使用しないようにしている
xdescribe 'ツリー構造のlookup' do # rubocop:disable Metrics/BlockLength
describe 'ツリー構造のlookup' do # rubocop:disable Metrics/BlockLength
subject { build_backend }

context '完全一致が存在する場合' do
Expand Down