Give Contact and Group a console-readable inspect
Assisted-by: GLM-5.3 via pi
diff --git a/lib/pro_tacts/contact.rb b/lib/pro_tacts/contact.rb
index af9d2b9..f66b610 100644
--- a/lib/pro_tacts/contact.rb
+++ b/lib/pro_tacts/contact.rb
@@ -188,6 +188,18 @@ module ProTacts
@etag = self.class.etag_for(vcard)
end
+ # What a console session sees for one (console.rb): the default
+ # would carry the stored card's whole bytes through @stored, which
+ # makes a listing of contacts unreadable at a prompt. #name
+ # composes and parses the card; no app path inspects a contact,
+ # so the parse is a session's price alone.
+ #: () -> String
+ def inspect
+ parts = ["id=#{id.inspect}"]
+ parts << "name=#{name.inspect}" if name
+ "#<#{self.class.name} #{parts.join(" ")}>"
+ end
+
# The image formats a decoded PHOTO is recognized by, prefix to
# mime type. A picture's type is read off the decoded bytes rather
# than the TYPE parameter because magic bytes cannot mislabel what
diff --git a/lib/pro_tacts/store.rb b/lib/pro_tacts/store.rb
index 751e59c..b38989f 100644
--- a/lib/pro_tacts/store.rb
+++ b/lib/pro_tacts/store.rb
@@ -121,6 +121,14 @@ module ProTacts
def version
Digest::SHA256.hexdigest([name, lines, members].to_json)
end
+
+ # What a console session sees for one (console.rb): the Data
+ # class's own inspect would carry every lent line and every
+ # member id, and a listing of groups is unreadable at a prompt.
+ #: () -> String
+ def inspect
+ "#<#{self.class.name} id=#{id.inspect} label=#{label.inspect} members=#{members.length}>"
+ end
end
# SQLite has no ON UPDATE, so the column default stamps a row on
diff --git a/test/pro_tacts/test_contact.rb b/test/pro_tacts/test_contact.rb
index e44fd49..91ac99d 100644
--- a/test/pro_tacts/test_contact.rb
+++ b/test/pro_tacts/test_contact.rb
@@ -95,6 +95,16 @@ class ContactTest < Minitest::Test
assert_equal "Ada Lovelace", contact(STRUCTURED).name
end
+ def test_inspect_shows_the_id_and_name_and_not_the_card
+ assert_equal %(#<ProTacts::Contact id="aiden" name="Aiden">), contact.inspect
+ end
+
+ def test_inspect_without_a_name_shows_only_the_id
+ bare = "BEGIN:VCARD\r\nVERSION:3.0\r\nUID:none\r\nEND:VCARD\r\n"
+
+ assert_equal %(#<ProTacts::Contact id="aiden">), contact(bare).inspect
+ end
+
def test_reads_the_name_components
assert_equal ["Lovelace", "Ada", nil, nil, nil], contact(STRUCTURED).name_components
end
diff --git a/test/pro_tacts/test_store.rb b/test/pro_tacts/test_store.rb
index 23e1013..bb50c1c 100644
--- a/test/pro_tacts/test_store.rb
+++ b/test/pro_tacts/test_store.rb
@@ -1179,6 +1179,16 @@ class StoreTest < Minitest::Test
# spelled the name. Everything else is refused — a phone or an email
# reaches a person rather than a household, and a grouped ADR is half
# of a labeled property whose other half no group may hold.
+ def test_a_group_inspects_to_its_label_and_member_count
+ with_store({"aiden" => AIDEN, "znorth" => ZED}) do |store|
+ id = FixtureData.seed_group(store, name: "Household", members: %w[znorth aiden])
+ nameless = store.create_group
+
+ assert_equal %(#<ProTacts::Store::Group id="#{id}" label="Household" members=2>), store.group(id).inspect
+ assert_equal %(#<ProTacts::Store::Group id="#{nameless}" label="#{nameless}" members=0>), store.group(nameless).inspect
+ end
+ end
+
def test_a_group_holds_only_addresses_and_notes
with_store({"aiden" => AIDEN}) do |store|
properties = database(store)[:group_properties]