import: a maiden name is written under the note
Assisted-by: GLM-5.3 via pi
diff --git a/lib/pro_tacts/import/macos.rb b/lib/pro_tacts/import/macos.rb
index e74abe2..47e6146 100644
--- a/lib/pro_tacts/import/macos.rb
+++ b/lib/pro_tacts/import/macos.rb
@@ -123,6 +123,7 @@ module ProTacts
first, last = name(carried, source_id, unknown)
nickname = only(carried, "NICKNAME", source_id, unknown)
birthday = only(carried, "BDAY", source_id, unknown)
+ maiden_name = only(carried, "X-MAIDENNAME", source_id, unknown)
labels = labels_by_group(lines)
phones = properties(carried, "TEL").filter_map { |property|
number = property.text
@@ -143,19 +144,23 @@ module ProTacts
photo = !contact.fetch("imageData").nil?
card = Card.new(
first:, last:, nickname:, birthday:, phones:, emails:, addresses:,
- note: noted(note, related_names(lines, carried)), photo:, groups: [], source:
+ note: noted(note, maiden_name, related_names(lines, carried)), photo:, groups: [], source:
)
Plan::Entry.new(id:, source_id:, card:)
end
- # The note, with the people this contact is related to written
- # under it: this address book has no field for a relation, and a
- # spouse's name is worth more in the note than nowhere.
- #: (String? note, Array[String] related) -> String?
- def self.noted(note, related)
- return note if related.empty?
-
- [note, related.join("\n")].compact.reject(&:empty?).join("\n\n")
+ # The note, with the maiden name and the people this contact is
+ # related to written under it: this address book has no field for
+ # either, and a name worth keeping is worth more in the note than
+ # nowhere (the related names' reasoning,
+ # docs/plans/2026-09-16-importing-from-macos.md, "The builder
+ # knows only what it was taught").
+ #: (String? note, String? maiden, Array[String] related) -> String?
+ def self.noted(note, maiden, related)
+ under = [maiden&.then { "Maiden name: #{it}" }, *related].compact
+ return note if under.empty?
+
+ [note, under.join("\n")].compact.reject(&:empty?).join("\n\n")
end
# Each related name as "<label>: <name>", the label being the
@@ -329,7 +334,8 @@ module ProTacts
"item#.EMAIL;type=INTERNET"
],
"ADR" => ["ADR;type=HOME", "item#.ADR;type=HOME"],
- "X-ABRELATEDNAMES" => ["item#.X-ABRELATEDNAMES"]
+ "X-ABRELATEDNAMES" => ["item#.X-ABRELATEDNAMES"],
+ "X-MAIDENNAME" => ["X-MAIDENNAME"]
}.freeze #: Hash[String, Array[String]]
# A number as Contacts hands one over, which is as a person typed
diff --git a/test/pro_tacts/import/test_macos.rb b/test/pro_tacts/import/test_macos.rb
index 597b9c2..56f9f94 100644
--- a/test/pro_tacts/import/test_macos.rb
+++ b/test/pro_tacts/import/test_macos.rb
@@ -311,6 +311,47 @@ class ImportMacosTest < Minitest::Test
end
end
+ def test_a_maiden_name_is_written_under_the_note
+ in_tmpdir do |dir|
+ lines = [
+ "X-MAIDENNAME:Byron",
+ "item2.X-ABRELATEDNAMES;type=pref:Sylvia Lovelace",
+ "item2.X-ABLabel:_$!<Spouse>!$_"
+ ]
+ plan = Macos.plan(dir, [record("A:ABPerson", lines:, note: "Analyst.")], created_at: CREATED_AT)
+
+ assert_equal "Analyst.\n\nMaiden name: Byron\nSpouse: Sylvia Lovelace", plan.card(plan.contacts.first.id).note
+ end
+ end
+
+ def test_a_maiden_name_is_the_whole_note_of_a_contact_with_none
+ in_tmpdir do |dir|
+ plan = Macos.plan(dir, [record("A:ABPerson", lines: ["X-MAIDENNAME:Byron"])], created_at: CREATED_AT)
+
+ assert_equal "Maiden name: Byron", plan.card(plan.contacts.first.id).note
+ end
+ end
+
+ def test_a_second_maiden_name_is_refused
+ in_tmpdir do |dir|
+ records = [record("A:ABPerson", lines: ["X-MAIDENNAME:Byron", "X-MAIDENNAME:King"])]
+
+ error = assert_raises(Macos::Unknown) { Macos.plan(dir, records, created_at: CREATED_AT) }
+
+ assert_includes error.message, "X-MAIDENNAME lines: 2: 1"
+ end
+ end
+
+ def test_a_maiden_name_in_any_other_form_is_refused_under_that_form
+ in_tmpdir do |dir|
+ records = [record("A:ABPerson", lines: ["item1.X-MAIDENNAME:Byron"])]
+
+ error = assert_raises(Macos::Unknown) { Macos.plan(dir, records, created_at: CREATED_AT) }
+
+ assert_includes error.message, "item#.X-MAIDENNAME: 1"
+ end
+ end
+
def test_an_annotation_with_no_line_to_annotate_is_refused
in_tmpdir do |dir|
records = [record("A:ABPerson", lines: ["item5.X-ABADR:us", "X-ABLabel:_$!<Spouse>!$_"])]