Skip to content

Commit bc96b03

Browse files
authored
Migrate sync_en_localizations command to new tool (#556)
2 parents 8b41b42 + 2c7709c commit bc96b03

File tree

10 files changed

+452
-0
lines changed

10 files changed

+452
-0
lines changed

dev/lib/product_taxonomy.rb

+4
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,18 @@ def data_path = DATA_PATH
2727
require_relative "product_taxonomy/models/mapping_rule"
2828
require_relative "product_taxonomy/models/integration_version"
2929
require_relative "product_taxonomy/models/serializers/category/data/data_serializer"
30+
require_relative "product_taxonomy/models/serializers/category/data/localizations_serializer"
3031
require_relative "product_taxonomy/models/serializers/category/docs/siblings_serializer"
3132
require_relative "product_taxonomy/models/serializers/category/docs/search_serializer"
33+
require_relative "product_taxonomy/models/serializers/attribute/data/localizations_serializer"
3234
require_relative "product_taxonomy/models/serializers/attribute/docs/base_and_extended_serializer"
3335
require_relative "product_taxonomy/models/serializers/attribute/docs/reversed_serializer"
3436
require_relative "product_taxonomy/models/serializers/attribute/docs/search_serializer"
37+
require_relative "product_taxonomy/models/serializers/value/data/localizations_serializer"
3538
require_relative "product_taxonomy/commands/command"
3639
require_relative "product_taxonomy/commands/generate_dist_command"
3740
require_relative "product_taxonomy/commands/find_unmapped_external_categories_command"
3841
require_relative "product_taxonomy/commands/generate_docs_command"
3942
require_relative "product_taxonomy/commands/generate_release_command"
4043
require_relative "product_taxonomy/commands/dump_categories_command"
44+
require_relative "product_taxonomy/commands/sync_en_localizations_command"

dev/lib/product_taxonomy/cli.rb

+6
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,11 @@ def release
4545
def dump_categories
4646
DumpCategoriesCommand.new(options).run
4747
end
48+
49+
desc "sync_en_localizations", "Sync English localizations for categories, attributes, and values"
50+
option :targets, type: :string, desc: "List of targets to sync. Valid targets are: categories, attributes, values"
51+
def sync_en_localizations
52+
SyncEnLocalizationsCommand.new(options).run
53+
end
4854
end
4955
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
module ProductTaxonomy
4+
class SyncEnLocalizationsCommand < Command
5+
PERMITTED_TARGETS = ["categories", "attributes", "values"].freeze
6+
7+
def initialize(options)
8+
super
9+
load_taxonomy
10+
@targets = options[:targets]&.split(",") || PERMITTED_TARGETS
11+
@targets.each do |target|
12+
raise "Invalid target: #{target}. Must be one of: #{PERMITTED_TARGETS.join(', ')}" unless PERMITTED_TARGETS.include?(target)
13+
end
14+
end
15+
16+
def execute
17+
logger.info("Syncing EN localizations")
18+
19+
sync_categories if @targets.include?("categories")
20+
sync_attributes if @targets.include?("attributes")
21+
sync_values if @targets.include?("values")
22+
end
23+
24+
private
25+
26+
def sync_categories
27+
logger.info("Syncing categories...")
28+
localizations = Serializers::Category::Data::LocalizationsSerializer.serialize_all
29+
write_localizations("categories", localizations)
30+
end
31+
32+
def sync_attributes
33+
logger.info("Syncing attributes...")
34+
localizations = Serializers::Attribute::Data::LocalizationsSerializer.serialize_all
35+
write_localizations("attributes", localizations)
36+
end
37+
38+
def sync_values
39+
logger.info("Syncing values...")
40+
localizations = Serializers::Value::Data::LocalizationsSerializer.serialize_all
41+
write_localizations("values", localizations)
42+
end
43+
44+
def write_localizations(type, localizations)
45+
file_path = File.expand_path("localizations/#{type}/en.yml", ProductTaxonomy.data_path)
46+
File.open(file_path, "w") do |file|
47+
file.puts "# This file is auto-generated. Do not edit directly."
48+
file.write(YAML.dump(localizations, line_width: -1))
49+
end
50+
logger.info("Wrote #{type} localizations to #{file_path}")
51+
end
52+
end
53+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
module ProductTaxonomy
4+
module Serializers
5+
module Attribute
6+
module Data
7+
module LocalizationsSerializer
8+
class << self
9+
def serialize_all
10+
attributes = ProductTaxonomy::Attribute.all
11+
12+
{
13+
"en" => {
14+
"attributes" => attributes.sort_by(&:friendly_id).reduce({}) { _1.merge!(serialize(_2)) },
15+
},
16+
}
17+
end
18+
19+
# @param [Attribute] attribute
20+
# @return [Hash]
21+
def serialize(attribute)
22+
{
23+
attribute.friendly_id => {
24+
"name" => attribute.name,
25+
"description" => attribute.description,
26+
},
27+
}
28+
end
29+
end
30+
end
31+
end
32+
end
33+
end
34+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
module ProductTaxonomy
4+
module Serializers
5+
module Category
6+
module Data
7+
module LocalizationsSerializer
8+
class << self
9+
def serialize_all
10+
categories = ProductTaxonomy::Category.all_depth_first
11+
12+
{
13+
"en" => {
14+
"categories" => categories.sort_by(&:id_parts).reduce({}) { _1.merge!(serialize(_2)) },
15+
},
16+
}
17+
end
18+
19+
# @param [Category] category
20+
# @return [Hash]
21+
def serialize(category)
22+
{
23+
category.id => {
24+
"name" => category.name,
25+
"context" => category.full_name,
26+
},
27+
}
28+
end
29+
end
30+
end
31+
end
32+
end
33+
end
34+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
module ProductTaxonomy
4+
module Serializers
5+
module Value
6+
module Data
7+
module LocalizationsSerializer
8+
class << self
9+
def serialize_all
10+
values = ProductTaxonomy::Value.all
11+
12+
{
13+
"en" => {
14+
"values" => values.sort_by(&:friendly_id).reduce({}) { _1.merge!(serialize(_2)) },
15+
},
16+
}
17+
end
18+
19+
# @param [Value] value
20+
# @return [Hash]
21+
def serialize(value)
22+
{
23+
value.friendly_id => {
24+
"name" => value.name,
25+
"context" => value.primary_attribute.name,
26+
},
27+
}
28+
end
29+
end
30+
end
31+
end
32+
end
33+
end
34+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
require "tmpdir"
5+
6+
module ProductTaxonomy
7+
class SyncEnLocalizationsCommandTest < TestCase
8+
setup do
9+
@tmp_base_path = Dir.mktmpdir
10+
@real_base_path = File.expand_path("..", ProductTaxonomy.data_path)
11+
12+
FileUtils.mkdir_p(File.expand_path("data/localizations/categories", @tmp_base_path))
13+
FileUtils.mkdir_p(File.expand_path("data/localizations/attributes", @tmp_base_path))
14+
FileUtils.mkdir_p(File.expand_path("data/localizations/values", @tmp_base_path))
15+
ProductTaxonomy.stubs(:data_path).returns(File.expand_path("data", @tmp_base_path))
16+
17+
Command.any_instance.stubs(:load_taxonomy)
18+
end
19+
20+
teardown do
21+
FileUtils.remove_entry(@tmp_base_path)
22+
end
23+
24+
test "initialize sets targets to all permitted targets when not specified" do
25+
command = SyncEnLocalizationsCommand.new({})
26+
assert_equal ["categories", "attributes", "values"], command.instance_variable_get(:@targets)
27+
end
28+
29+
test "initialize accepts custom targets" do
30+
command = SyncEnLocalizationsCommand.new(targets: "categories,attributes")
31+
assert_equal ["categories", "attributes"], command.instance_variable_get(:@targets)
32+
end
33+
34+
test "initialize raises error for invalid target" do
35+
assert_raises(RuntimeError) do
36+
SyncEnLocalizationsCommand.new(targets: "invalid,categories")
37+
end
38+
end
39+
40+
test "execute syncs categories localizations" do
41+
mock_localizations = { "test" => "data" }
42+
Serializers::Category::Data::LocalizationsSerializer.stubs(:serialize_all)
43+
.returns(mock_localizations)
44+
45+
command = SyncEnLocalizationsCommand.new(targets: "categories")
46+
command.execute
47+
48+
expected_path = File.expand_path("data/localizations/categories/en.yml", @tmp_base_path)
49+
assert File.exist?(expected_path)
50+
expected_content = "# This file is auto-generated. Do not edit directly.\n---\ntest: data\n"
51+
assert_equal expected_content, File.read(expected_path)
52+
end
53+
54+
test "execute syncs attributes localizations" do
55+
mock_localizations = { "test" => "attribute_data" }
56+
Serializers::Attribute::Data::LocalizationsSerializer.stubs(:serialize_all)
57+
.returns(mock_localizations)
58+
59+
command = SyncEnLocalizationsCommand.new(targets: "attributes")
60+
command.execute
61+
62+
expected_path = File.expand_path("data/localizations/attributes/en.yml", @tmp_base_path)
63+
assert File.exist?(expected_path)
64+
expected_content = "# This file is auto-generated. Do not edit directly.\n---\ntest: attribute_data\n"
65+
assert_equal expected_content, File.read(expected_path)
66+
end
67+
68+
test "execute syncs values localizations" do
69+
mock_localizations = { "test" => "value_data" }
70+
Serializers::Value::Data::LocalizationsSerializer.stubs(:serialize_all)
71+
.returns(mock_localizations)
72+
73+
command = SyncEnLocalizationsCommand.new(targets: "values")
74+
command.execute
75+
76+
expected_path = File.expand_path("data/localizations/values/en.yml", @tmp_base_path)
77+
assert File.exist?(expected_path)
78+
expected_content = "# This file is auto-generated. Do not edit directly.\n---\ntest: value_data\n"
79+
assert_equal expected_content, File.read(expected_path)
80+
end
81+
82+
test "execute syncs all targets when none specified" do
83+
Serializers::Category::Data::LocalizationsSerializer.stubs(:serialize_all)
84+
.returns({ "category" => "data" })
85+
Serializers::Attribute::Data::LocalizationsSerializer.stubs(:serialize_all)
86+
.returns({ "attribute" => "data" })
87+
Serializers::Value::Data::LocalizationsSerializer.stubs(:serialize_all)
88+
.returns({ "value" => "data" })
89+
90+
command = SyncEnLocalizationsCommand.new({})
91+
command.execute
92+
93+
categories_path = File.expand_path("data/localizations/categories/en.yml", @tmp_base_path)
94+
attributes_path = File.expand_path("data/localizations/attributes/en.yml", @tmp_base_path)
95+
values_path = File.expand_path("data/localizations/values/en.yml", @tmp_base_path)
96+
97+
assert File.exist?(categories_path)
98+
assert File.exist?(attributes_path)
99+
assert File.exist?(values_path)
100+
101+
expected_categories = "# This file is auto-generated. Do not edit directly.\n---\ncategory: data\n"
102+
expected_attributes = "# This file is auto-generated. Do not edit directly.\n---\nattribute: data\n"
103+
expected_values = "# This file is auto-generated. Do not edit directly.\n---\nvalue: data\n"
104+
105+
assert_equal expected_categories, File.read(categories_path)
106+
assert_equal expected_attributes, File.read(attributes_path)
107+
assert_equal expected_values, File.read(values_path)
108+
end
109+
end
110+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
module ProductTaxonomy
6+
module Serializers
7+
module Attribute
8+
module Data
9+
class LocalizationsSerializerTest < TestCase
10+
setup do
11+
@value = ProductTaxonomy::Value.new(
12+
id: 1,
13+
name: "Black",
14+
friendly_id: "black",
15+
handle: "black"
16+
)
17+
18+
@attribute = ProductTaxonomy::Attribute.new(
19+
id: 1,
20+
name: "Color",
21+
friendly_id: "color",
22+
handle: "color",
23+
description: "The color of the item",
24+
values: [@value]
25+
)
26+
end
27+
28+
test "serialize returns the expected data structure for an attribute" do
29+
expected = {
30+
"color" => {
31+
"name" => "Color",
32+
"description" => "The color of the item"
33+
}
34+
}
35+
36+
assert_equal expected, LocalizationsSerializer.serialize(@attribute)
37+
end
38+
39+
test "serialize_all returns all attributes in localization format" do
40+
ProductTaxonomy::Attribute.stubs(:all).returns([@attribute])
41+
42+
expected = {
43+
"en" => {
44+
"attributes" => {
45+
"color" => {
46+
"name" => "Color",
47+
"description" => "The color of the item"
48+
}
49+
}
50+
}
51+
}
52+
53+
assert_equal expected, LocalizationsSerializer.serialize_all
54+
end
55+
end
56+
end
57+
end
58+
end
59+
end

0 commit comments

Comments
 (0)