vcard, contact: trim what the new comments say
Fourteen lines of comment stood above a three-line find,
re-arguing the layering the class comment had already signed.
The rules stay — a name without case, the first value of a repeat —
the case for them goes to the review, and of_line keeps its own seat.
Assisted-by: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015WjrPJFvetad8vvCHqjujh
diff --git a/lib/pro_tacts/contact.rb b/lib/pro_tacts/contact.rb
index 8d7a359..1c90f4a 100644
--- a/lib/pro_tacts/contact.rb
+++ b/lib/pro_tacts/contact.rb
@@ -341,20 +341,9 @@ module ProTacts
}
end
- # The rows a repeatable property reads as: the lines naming it,
- # in the card's own order, each folded by the block into a typed
- # value, with the nils dropped. Two absences arrive as one that
- # way, which is what every one of these accessors wants — a line
- # that would not read is a row no form can address, and a line
- # the block finds nothing in (a blank value, an ADR blank
- # throughout) is a row with nothing to show; neither is an error,
- # and a card is served from its bytes either way. The unreadable
- # line stays enumerable in VCard#lines regardless.
- #
- # The block takes the parsed property and the line it came from,
- # because a row carries both: the property for what it says, the
- # line for the address a save names the row by
- # (docs/plans/2026-09-05-web-card-editor.md).
+ # The rows a repeatable property reads as: each line naming it
+ # folded by the block, which takes the property and the line it
+ # came from and answers nil for a row with nothing to show.
#: [T] (String name) { (VCard::Parser::Property, VCard::Parser::Line) -> T? } -> Array[T]
def rows(name)
of_line(name).filter_map { |line|
@@ -363,9 +352,11 @@ module ProTacts
}
end
- # The lines naming `name`, parsed beside their bytes — the walk
- # #rows reads over, and the one accessor-facing read that hands
- # back the lines that would not parse along with the rest.
+ # The lines naming `name`, parsed beside their bytes — the walk the
+ # provenance-carrying accessors read from, so a row can carry the
+ # line it was read from as its address. A line that would not
+ # read is a row no form can address and no accessor reads; it
+ # stays enumerable in VCard#lines, served from its bytes.
#: (String name) -> Array[VCard::Parser::Line]
def of_line(name)
vcard.lines.select { it.names?(name) }
@@ -402,12 +393,8 @@ module ProTacts
Address.new(po_box:, extended:, street:, locality:, region:, postal_code:, country:, type: type_of(property), line:)
end
- # A row's type parameter (RFC 2426 section 3.3.1), the first of
- # them where a card lists several — which one that is, and that a
- # name matches without case, is the grammar's and so
- # Property#parameter's. What is this layer's is the downcase: the
- # spelling is the card's, `WORK` and `work` label the same row,
- # and a screen shows one of them.
+ # The first of a row's TYPE parameters (RFC 2426 section 3.3.1),
+ # downcased: the spelling is the card's, and a screen shows one.
#: (VCard::Parser::Property property) -> String?
def type_of(property)
property.parameter("TYPE")&.downcase
diff --git a/lib/pro_tacts/vcard/parser.rb b/lib/pro_tacts/vcard/parser.rb
index 9d6010e..9932bff 100644
--- a/lib/pro_tacts/vcard/parser.rb
+++ b/lib/pro_tacts/vcard/parser.rb
@@ -90,20 +90,10 @@ module ProTacts
#: () -> Array[String]
def components = VCard.split_components(value)
- # The named parameter's first value, or nil when the property
- # carries none. Names compare without case, RFC 2426 section 4
- # making them case-insensitive, and the first value is the
- # answer because a parameter can repeat: section 3.3.1's
- # `TYPE=work;TYPE=voice` and `TYPE=work,voice` are the same
- # thing and both arrive as two pairs, so a caller wanting all
- # of them reads `parameters` itself.
- #
- # Lookup, not meaning: that a parameter name is
- # case-insensitive and that a repeat is a second value are
- # the grammar's rules, which is what keeps this on the shallow
- # side of the line the class comment draws. Which parameters a
- # property may carry, and what any of them says, stays the
- # caller's.
+ # The named parameter's first value, or nil for a property
+ # carrying none. Names match without case (RFC 2426 section
+ # 4); the first value, because a repeat arrives as two pairs
+ # (see above) and a caller wanting both reads `parameters`.
#: (String name) -> String?
def parameter(name)
parameters.find { |parameter, _| parameter.casecmp?(name) }&.last
diff --git a/test/pro_tacts/vcard/test_parser.rb b/test/pro_tacts/vcard/test_parser.rb
index 23f3ba2..3fb7962 100644
--- a/test/pro_tacts/vcard/test_parser.rb
+++ b/test/pro_tacts/vcard/test_parser.rb
@@ -371,8 +371,7 @@ class VCardParserTest < Minitest::Test
## Parameters
# A name matches without case (RFC 2426 section 4), and a parameter
- # a card lists several values for answers with the first of them —
- # both spellings of the repeat reaching here as the same two pairs.
+ # listing several values answers with the first of them.
def test_a_parameter_reads_by_name_without_case
property = properties(card("TEL;type=WORK,voice:+1-555-1234")).fetch(0)