Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,13 @@ internal class SefariaBookPayloadReader(

val sectionIndex = sectionNames.size - depth
val isReferenceable = referenceableSections.getOrNull(sectionIndex) ?: true
val isNumberedParagraph = depth == 1 && hasNumberedParagraphs(bookEnTitle)
val nextLinePrefix = if (
depth == 1 && isReferenceable && currentAddressType != "Integer" && nonEmptyCount > 1 &&
!hasSelfLabeledSegments(bookEnTitle)
isNumberedParagraph ||
(
depth == 1 && isReferenceable && currentAddressType != "Integer" && nonEmptyCount > 1 &&
!hasSelfLabeledSegments(bookEnTitle)
)
) {
"($letter) "
} else {
Expand Down Expand Up @@ -586,6 +590,7 @@ internal class SefariaBookPayloadReader(
append(", ")
}
val nextRefIndexOffset = childRefOffsets?.getOrNull(idx) ?: 0
val lineCountBefore = output.size

recursiveSections(
sectionNames = sectionNames,
Expand All @@ -604,6 +609,12 @@ internal class SefariaBookPayloadReader(
referenceableSections = referenceableSections,
refIndexOffset = nextRefIndexOffset
)

// The paragraph's TOC entry points at the paragraph line itself, so the
// text gets no extra heading line.
if (isNumberedParagraph && output.size > lineCountBefore) {
headings += Heading(title = "אות $letter", level = level, lineIndex = lineCountBefore)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ private val SELF_LABELED_SEGMENT_BOOKS = setOf("Mishnah Berurah")

internal fun hasSelfLabeledSegments(bookEnTitle: String): Boolean = bookEnTitle in SELF_LABELED_SEGMENT_BOOKS

// Books whose unnamed ("Integer") segments are the printed numbered paragraphs (אותיות)
// readers navigate by: each segment gets its "(letter) " label and its own TOC entry
// (kdroidFilter/Zayit#509).
private val NUMBERED_PARAGRAPH_BOOKS = setOf(
"Bereshit Rabbah",
"Shemot Rabbah",
"Vayikra Rabbah",
"Bamidbar Rabbah",
"Devarim Rabbah",
"Ruth Rabbah",
"Esther Rabbah",
"Eikhah Rabbah",
"Kohelet Rabbah",
"Shir HaShirim Rabbah",
)

internal fun hasNumberedParagraphs(bookEnTitle: String): Boolean = bookEnTitle in NUMBERED_PARAGRAPH_BOOKS

// Some simanim of the Mishnah Berurah (494-529) mark the seif katan as "{א}"
// instead of the printed "(א)".
private val BRACED_SEGMENT_MARKER_REGEX = Regex("""^\{([א-ת]{1,4})\}""")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.github.kdroidfilter.seforimlibrary.sefariasqlite

import co.touchlab.kermit.Logger
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import java.nio.file.Files
import kotlin.test.Test
import kotlin.test.assertEquals

/**
* Regression for kdroidFilter/Zayit#509: the Midrash Rabbah's paragraphs (אותיות)
* are unnamed "Integer" segments, so they had neither a number nor a TOC entry.
*/
class SefariaNumberedParagraphsTest {
@Test
fun midrashRabbahParagraphsGetLabelAndTocEntry() {
val payload = readBook("Bereshit Rabbah", "בראשית רבה")

assertEquals(
listOf(
"<h1>בראשית רבה</h1>",
"<h2>פרק א</h2>",
"(א) רבי הושעיה רבה פתח",
"(ב) רבי יהושע דסכנין",
"<h2>פרק ב</h2>",
"(א) והארץ היתה תהו",
),
payload.lines,
)
assertEquals(
listOf(
Heading("בראשית רבה", 0, 0),
Heading("פרק א", 1, 1),
Heading("אות א", 2, 2),
Heading("אות ב", 2, 3),
Heading("פרק ב", 1, 4),
Heading("אות א", 2, 5),
),
payload.headings,
)
// heRefs (the line id natural keys) are unchanged
assertEquals(
listOf("בראשית רבה א, א", "בראשית רבה א, ב", "בראשית רבה ב, א"),
payload.refEntries.map { it.heRef.replace(Regex(" +"), " ") },
)
}

@Test
fun otherBooksKeepUnlabeledIntegerSegments() {
val payload = readBook("FakeBook", "ספר")

assertEquals("רבי הושעיה רבה פתח", payload.lines[2])
assertEquals(listOf(0, 1, 1), payload.headings.map { it.level })
}

private fun readBook(title: String, heTitle: String) = runBlocking {
val tempDir = Files.createTempDirectory("seforim-numbered-paragraphs")
val schemaDir = Files.createDirectories(tempDir.resolve("schemas"))
val bookDir = Files.createDirectories(tempDir.resolve("json").resolve(title))
Files.writeString(schemaDir.resolve("${title.replace(' ', '_')}.json"), schemaJson(title, heTitle))
Files.writeString(bookDir.resolve("merged.json"), mergedJson(title, heTitle))

val reader = SefariaBookPayloadReader(
Json { ignoreUnknownKeys = true; coerceInputValues = true },
Logger.withTag("SefariaNumberedParagraphsTest"),
)
val schemaLookup = reader.buildSchemaLookup(schemaDir)
reader.readBooksInParallel(tempDir.resolve("json"), schemaDir, schemaLookup).single()
}

private fun schemaJson(title: String, heTitle: String) = """
{
"title": "$title",
"heTitle": "$heTitle",
"schema": {
"nodeType": "JaggedArrayNode",
"depth": 2,
"addressTypes": ["Perek", "Integer"],
"sectionNames": ["Chapter", "Paragraph"],
"title": "$title",
"heTitle": "$heTitle"
}
}
""".trimIndent()

private fun mergedJson(title: String, heTitle: String) = """
{
"title": "$title",
"heTitle": "$heTitle",
"text": [
["רבי הושעיה רבה פתח", "רבי יהושע דסכנין"],
["והארץ היתה תהו"]
]
}
""".trimIndent()
}
Loading