mirror of
https://github.com/kennethreitz/rhymepad.org.git
synced 2026-06-11 17:08:33 +00:00
Repetition is refrain, not rhyme
Identical words/phrases no longer form a color group on their own — a group colors only once a differing word rhymes into it. Repeated endings still share a scheme letter (refrains scan), and a repeated unrhymed ending no longer flags as "unanswered". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -621,9 +621,9 @@ def analyze(draft: Draft):
|
||||
# distinctness by anchor word, so "fire burns" can't pose as a
|
||||
# rhyme partner for the "fire" it starts with
|
||||
distinct = {t["word"].split()[0].lower() for t in toks}
|
||||
end_count = sum(t["is_end"] for t in toks)
|
||||
if len(distinct) < 2 and end_count < 2:
|
||||
continue # the same word repeated mid-line isn't a rhyme
|
||||
if len(distinct) < 2:
|
||||
continue # repetition is refrain, not rhyme — a group only
|
||||
# colors once a DIFFERING word rhymes into it
|
||||
if all(" " in t["word"] and t["word"].split()[0] in STOPWORDS
|
||||
for t in toks):
|
||||
continue # stopword-anchored phrases need a real-word partner
|
||||
@@ -994,6 +994,10 @@ def analyze(draft: Draft):
|
||||
for t in [*tokens, *phrases]:
|
||||
if t["is_end"] and t["gid"] is not None:
|
||||
end_gid.setdefault(t["line"], t["gid"])
|
||||
last_tok = {}
|
||||
for t in tokens:
|
||||
if t["is_end"]:
|
||||
last_tok[t["line"]] = t
|
||||
stanza_lines = defaultdict(list)
|
||||
for i, s in enumerate(sids):
|
||||
if s is not None:
|
||||
@@ -1004,7 +1008,13 @@ def analyze(draft: Draft):
|
||||
letters, order = [], {}
|
||||
for i in stanza_lines[s]:
|
||||
gid = end_gid.get(i)
|
||||
key = gid if gid is not None else f"solo:{i}"
|
||||
if gid is not None:
|
||||
key = gid
|
||||
elif i in last_tok:
|
||||
# refrains share a letter even though they don't color
|
||||
key = "w:" + last_tok[i]["word"].lower()
|
||||
else:
|
||||
key = f"solo:{i}"
|
||||
if key not in order:
|
||||
order[key] = len(order)
|
||||
letters.append(order[key])
|
||||
@@ -1110,12 +1120,9 @@ def analyze(draft: Draft):
|
||||
# unanswered endings: line-ends still waiting for a rhyme partner —
|
||||
# the open loops that tell a writer where to strike next
|
||||
open_out = []
|
||||
last_tok = {}
|
||||
for t in tokens:
|
||||
if t["is_end"]:
|
||||
last_tok[t["line"]] = t
|
||||
end_word_counts = Counter(t["word"].lower() for t in last_tok.values())
|
||||
for i, t in last_tok.items():
|
||||
if i not in end_gid:
|
||||
if i not in end_gid and end_word_counts[t["word"].lower()] < 2:
|
||||
open_out.append({"l": i, "s": t["start"], "e": t["end"]})
|
||||
|
||||
return {"lines": lines, "tokens": toks_out, "groups": groups_out,
|
||||
|
||||
@@ -599,3 +599,18 @@ def test_repeated_this_joins_the_hook_chain():
|
||||
"flickin' that wrist\n"
|
||||
"now they fuckin' with this")
|
||||
group_with(text, "shit", "assist", "wrist", "this")
|
||||
|
||||
|
||||
def test_repetition_alone_does_not_color():
|
||||
text = ("Six-foot, seven-foot, eight-foot bunch\n"
|
||||
"Six-foot, seven-foot, eight-foot bunch")
|
||||
assert highlighted(text) == set()
|
||||
assert scheme(text) == "aa" # ...but refrains share a scheme letter
|
||||
# and a repeated unrhymed ending isn't flagged "unanswered" either
|
||||
res = analyze(Draft(text=text))
|
||||
assert res["open"] == []
|
||||
|
||||
|
||||
def test_repetition_colors_once_a_differing_word_joins():
|
||||
text = "it was Tammy\npure whammy\nstill Tammy"
|
||||
group_with(text, "tammy", "whammy")
|
||||
|
||||
Reference in New Issue
Block a user