このコミットが含まれているのは:
2026-10-17 16:47:08 +09:00
コミット b945ceef60
91個のファイルの変更、4652行の追加、822行の削除
+2 -3
ファイルの表示
@@ -1,7 +1,7 @@
require 'rails_helper'
RSpec.describe PostBulkCreator do
include_context 'English locale'
include_context 'Ainu locale'
it 'limits workers to two and keeps failures in their request slots' do
locale = Locale.nipponese
@@ -67,8 +67,7 @@ RSpec.describe PostBulkCreator do
expect(results[3].dig(:post, :id)).to eq(4)
end
it 'passes a future English locale to preflight and creation in every worker' do
pending '日本語以外の Locale 有効化は別課題で実装する'
it 'passes a future Ainu locale to preflight and creation in every worker' do
locale
actor = instance_double(User, id: 123)
allow(User).to receive(:find).with(123).and_return(actor)
+19 -21
ファイルの表示
@@ -11,23 +11,22 @@ RSpec.describe PostCreatePlan do
end
context 'with an explicit locale' do
include_context 'English locale'
include_context 'Ainu locale'
it 'resolves the matching language identity and its parents' do
pending '日本語以外の Locale 有効化は別課題で実装する'
locale
english_name = create(:tag_name, name: 'shared_name',
language_code: 'en', script_code: 'Latn')
english = create(:tag, primary_tag_name: english_name, category: :character)
ainu_name = create(:tag_name, name: 'shared_name',
language_code: 'ain', script_code: 'Kana')
ainu = create(:tag, primary_tag_name: ainu_name, category: :character)
nipponese = create(:tag, primary_name: 'temporary_nipponese', category: :general)
# The DB permits this identity; validation has its own contract spec.
primary_tag_name_for(nipponese, 'ja').update_columns(name: 'shared_name')
english_parent_name = create(:tag_name, name: 'english_parent',
language_code: 'en', script_code: 'Latn')
english_parent = create(:tag, primary_tag_name: english_parent_name,
ainu_parent_name = create(:tag_name, name: 'ainu_parent',
language_code: 'ain', script_code: 'Kana')
ainu_parent = create(:tag, primary_tag_name: ainu_parent_name,
category: :material)
nipponese_parent = create(:tag, primary_name: 'nipponese_parent', category: :general)
TagImplication.create!(tag: english, parent_tag: english_parent)
TagImplication.create!(tag: ainu, parent_tag: ainu_parent)
TagImplication.create!(tag: nipponese, parent_tag: nipponese_parent)
plan = described_class.new(attributes: { tags: 'shared_name' }).build!(locale)
@@ -35,35 +34,34 @@ RSpec.describe PostCreatePlan do
expect(plan[:direct_tag_specs]).to eq(
[{ name: 'shared_name', category: :character }])
expect(plan[:post_tag_specs]).to include(
{ name: primary_tag_name_for(english_parent, 'en').name, category: :material })
{ name: primary_tag_name_for(ainu_parent, 'ain').name, category: :material })
expect(plan[:post_tag_specs].pluck(:name))
.not_to include(primary_tag_name_for(nipponese_parent, 'ja').name)
end
it 'resolves aliases within the requested language' do
pending '日本語以外の Locale 有効化は別課題で実装する'
locale
nipponese = create(:tag, primary_name: 'nipponese_canonical')
english_name = create(:tag_name, name: 'english_canonical',
language_code: 'en', script_code: 'Latn')
english = create(:tag, primary_tag_name: english_name, category: :character)
ainu_name = create(:tag_name, name: 'ainu_canonical',
language_code: 'ain', script_code: 'Kana')
ainu = create(:tag, primary_tag_name: ainu_name, category: :character)
nipponese_alias = create(:tag_name, :alias, name: 'shared_alias',
tag: nipponese)
english_alias = create(:tag_name, :alias, name: 'shared_alias',
tag: english,
language_code: 'en', script_code: 'Latn')
ainu_alias = create(:tag_name, :alias, name: 'shared_alias',
tag: ainu,
language_code: 'ain', script_code: 'Kana')
expect(nipponese_alias.reload).to have_attributes(
tag_id: nipponese.id,
primary_flg: false, language_code: 'ja')
expect(english_alias.reload).to have_attributes(
tag_id: english.id,
primary_flg: false, language_code: 'en')
expect(ainu_alias.reload).to have_attributes(
tag_id: ainu.id,
primary_flg: false, language_code: 'ain')
plan = described_class.new(attributes: { tags: 'shared_alias' }).build!(locale)
expect(plan[:direct_tag_specs]).to eq(
[{ name: english_name.name, category: :character }])
[{ name: ainu_name.name, category: :character }])
end
end
+3 -4
ファイルの表示
@@ -77,11 +77,10 @@ RSpec.describe PostCreator do
end
context 'with an explicit locale' do
include_context 'English locale'
include_context 'Ainu locale'
[false, true].each do |planned|
it "passes locale to tag creation with planned attributes: #{ planned }" do
pending '日本語以外の Locale 有効化は別課題で実装する'
locale
attributes = {
title: 'Locale propagation',
@@ -97,8 +96,8 @@ RSpec.describe PostCreator do
expect(Tag).to have_received(:find_or_create_by_tag_name!)
.with(locale, 'locale_character', category: :character).at_least(:once)
tag_name = TagName.find_by!(language_code: 'en', name: 'locale_character')
expect(tag_name).to have_attributes(script_code: 'Latn', primary_flg: true)
tag_name = TagName.find_by!(language_code: 'ain', name: 'locale_character')
expect(tag_name).to have_attributes(script_code: 'Kana', primary_flg: true)
expect(post.tags).to include(tag_name.tag)
end
end
+68
ファイルの表示
@@ -0,0 +1,68 @@
require 'rails_helper'
RSpec.describe TagNameCompletion do
let!(:language) { Language.create!(code: 'ain', name: 'ain') }
let!(:script) { Script.create!(code: 'Kana', name: 'Kana') }
let(:locale) do
Locale.create!(code: 'ain-Kana', language_code: 'ain', script_code: 'Kana',
region_code: 392, variants: '', name: 'ain-Kana')
end
it 'generates a phonetic primary with the required identity and provenance' do
tag = create(:tag, primary_name: '漢字あカ')
locale
expect(tag.reload.tag_name('ain')).to have_attributes(
name: 'カンチ_ア_カ', language_code: 'ain', script_code: 'Kana',
primary_flg: true, auto_generated: true, tag_id: tag.id)
end
it 'uses the exact fallback when the input cannot be converted' do
tag = create(:tag, primary_name: '😀')
locale
expect(tag.reload.name('ain')).to eq("Tag_##{ tag.id }")
end
it 'uses the exact fallback when a generated name collides with a human name' do
other = create(:tag, primary_name: 'other')
create(:tag_name, tag: other, name: 'AbC', language_code: 'ain', script_code: 'Kana')
tag = create(:tag, primary_name: 'AbC')
locale
expect(tag.reload.name('ain')).to eq("Tag_##{ tag.id }")
expect(other.reload.name('ain')).to eq('AbC')
end
it 'uses the exact fallback for a transcription that fails name validation' do
tag = create(:tag, primary_name: 'base')
source = TagName.new(name: 'nico:invalid', language_code: 'ja')
expect(TagName.generate_name(locale, tag, source)).to eq("Tag_##{ tag.id }")
end
it 'preserves human confirmation and is idempotent across repeated completion' do
locale
tag = Tag.find_or_create_by_tag_name!(Locale.nipponese, 'あいぬ', category: :general)
primary = tag.tag_name('ain')
primary.update!(name: 'human_confirmed', auto_generated: false)
snapshot = tag.tag_names.order(:id).map(&:attributes)
2.times { described_class.for_tag!(tag) }
expect(tag.tag_names.order(:id).map(&:attributes)).to eq(snapshot)
end
it 'creates one primary per active language through the production creation path' do
locale
tag = Tag.find_or_create_by_tag_name!(Locale.nipponese, 'アイヌ', category: :general)
expect(tag.tag_names.where(primary_flg: true).pluck(:language_code, :name))
.to contain_exactly(['ja', 'アイヌ'], ['ain', 'アイヌ'])
expect(Tag.find_or_create_by_tag_name!(locale, 'アイヌ', category: :general)).to eq(tag)
end
end
+34
ファイルの表示
@@ -0,0 +1,34 @@
require 'rails_helper'
RSpec.describe TagNameTranscription do
{
'AbCdXYZ' => 'AbCdXYZ',
'あいぬ' => 'アイヌ',
'アイヌ' => 'アイヌ',
'日本語' => 'ニチホンコ',
'漢字' => 'カンチ',
'漢あカ' => 'カン_ア_カ',
'漢字あいうカナ' => 'カンチ_アイウ_カナ',
'Ab漢あカZ' => 'Abカン_ア_カZ',
'りゃリュリョ' => 'リヤ_リユリヨ',
'キャット' => 'キヤット',
'コーヒー' => 'コヒ',
'コウコオケイケエカア' => 'コウコオケイケエカア',
'ガギグゲゴダヂヅデド' => 'カキクケコタチチュテト',
'バビブベボパピプペポ' => 'パピプペポパピプペポ',
'ザジズゼゾ' => 'チャチチュチェチョ',
'ジャジュジョ' => 'チヤチユチヨ',
'アㇰアㇱアッアンアㇺアㇷ゚' => 'アㇰアㇱアッアンアㇺアㇷ゚',
'アㇻイㇼウㇽエㇾオㇿ' => 'アㇻイㇼウㇽエㇾオㇿ',
'漢Aあ' => 'カンAア' }.each do |source, expected|
it "transcribes #{ source } as #{ expected }" do
expect(described_class.ainu(source)).to eq(expected)
end
end
['😀', 'ヴ', 'ティ', 'ㇵ', '魑', '𠮷', 'ー', '々'].each do |source|
it "rejects unsupported input #{ source }" do
expect { described_class.ainu(source) }.to raise_error(described_class::Unconvertible)
end
end
end
+14 -17
ファイルの表示
@@ -1,7 +1,7 @@
require 'rails_helper'
RSpec.describe TagVersionRecorder do
include_context 'English locale'
include_context 'Ainu locale'
let(:user) { create_member_user! }
let!(:tag) { create(:tag, primary_name: '日本語名') }
@@ -17,11 +17,11 @@ RSpec.describe TagVersionRecorder do
{ 'name' => 'alias_z', 'script_code' => 'Jpan' }] }
end
def prepare_english_names!
def prepare_ainu_names!
locale
primary_tag_name_for(tag, 'en').update!(name: 'English name', auto_generated: false)
create(:tag_name, :alias, tag:, language_code: 'en', script_code: 'Latn',
name: 'English alias')
primary_tag_name_for(tag, 'ain').update!(name: 'Ainu name', auto_generated: false)
create(:tag_name, :alias, tag:, language_code: 'ain', script_code: 'Kana',
name: 'Ainu alias')
end
it 'snapshots the Nipponese primary and sorted aliases in grouped names' do
@@ -62,35 +62,32 @@ RSpec.describe TagVersionRecorder do
end
it 'snapshots future languages together without a request locale argument' do
pending '日本語以外の Locale 有効化は別課題で実装する'
prepare_english_names!
prepare_ainu_names!
version = described_class.record!(tag:, event_type: :create, created_by_user: user)
expect(version.names).to eq(
'ja' => nipponese_snapshot,
'en' => { 'name' => 'English name', 'script_code' => 'Latn',
'ain' => { 'name' => 'Ainu name', 'script_code' => 'Kana',
'auto_generated' => false,
'aliases' => [{ 'name' => 'English alias', 'script_code' => 'Latn' }] })
'aliases' => [{ 'name' => 'Ainu alias', 'script_code' => 'Kana' }] })
end
it 'creates a version for an English-only change and preserves prior names' do
pending '日本語以外の Locale 有効化は別課題で実装する'
prepare_english_names!
it 'creates a version for an Ainu-only change and preserves prior names' do
prepare_ainu_names!
original = described_class.record!(tag:, event_type: :create, created_by_user: user)
primary_tag_name_for(tag, 'en').update!(name: 'Renamed')
primary_tag_name_for(tag, 'ain').update!(name: 'Renamed')
updated = described_class.record!(tag:, event_type: :update, created_by_user: user)
expect(updated.version_no).to eq(2)
expect(original.reload.names.fetch('en')).to include('name' => 'English name')
expect(updated.names.fetch('en')).to include('name' => 'Renamed')
expect(original.reload.names.fetch('ain')).to include('name' => 'Ainu name')
expect(updated.names.fetch('ain')).to include('name' => 'Renamed')
expect(updated.names.fetch('ja')).to eq(nipponese_snapshot)
end
it 'does not create a version for an unchanged multilingual snapshot' do
pending '日本語以外の Locale 有効化は別課題で実装する'
prepare_english_names!
prepare_ainu_names!
described_class.record!(tag:, event_type: :create, created_by_user: user)
unchanged = described_class.record!(tag:, event_type: :update, created_by_user: user)