refspy.navigator
Navigation functions for Reference objects
1"""Navigation functions for Reference objects""" 2 3from refspy.models.book import Book 4from refspy.types.number import Number 5from refspy.models.range import range 6from refspy.models.reference import Reference, reference 7from refspy.models.verse import verse 8 9 10class Navigator: 11 def __init__( 12 self, 13 books: dict[tuple[Number, Number], Book], 14 book_aliases: dict[str, tuple[Number, Number]], 15 ) -> None: 16 """ 17 Note: 18 Taking prev and next from references makes the most sense if ranges 19 are sorted or have been collated by book and chapter. 20 Example: 21 22 Using the Navigator module on its own: 23 24 ``` 25 from refspy.indexers import index_book_aliases, index_books 26 from refspy.libraries.en_US import NT, OT 27 from refspy.navigator import Navigator 28 from refspy.models.reference import chapter_reference 29 30 libraries = [OT, NT] 31 navigator = Navigator( 32 index_books(libraries), 33 index_book_aliases(libraries) 34 ) 35 matt_1 = chapter_reference(NT.id, 1, 1) 36 matt_2 = chapter_reference(NT.id, 1, 2) 37 assert navigator.next_chapter(matt_1) == matt_2 38 assert navigator.prev_chapter(matt_1) is None 39 ``` 40 41 Example: 42 43 Using the navigator within the `refspy` package. 44 45 ``` 46 from refspy import refspy 47 48 __ = refspy() 49 matt_1 = __.bcv('Matt', 1) 50 matt_2 = __.bcv('Matt', 2) 51 assert __.next_chapter(matt_1) == matt_2 52 assert __.prev_chapter(matt_1) is None 53 ``` 54 """ 55 56 self.books: dict[tuple[Number, Number], Book] = books 57 """Lookup `refspy.models.book.Book` by `(library.id, book.id)`.""" 58 59 self.book_aliases: dict[str, tuple[Number, Number]] = book_aliases 60 """Lookup `(library.id, book.id)` by book alias.""" 61 62 def prev_chapter(self, ref: Reference) -> Reference | None: 63 """Find a reference to the previous chapter. 64 65 We step into preceding books but not preceding libraries. 66 67 Returns: 68 None: If this is the first chapter of a `refspy.library.Library`. 69 """ 70 v1 = ref.ranges[0].start 71 if v1.chapter > 1: 72 return reference( 73 range( 74 verse(v1.library, v1.book, v1.chapter - 1, 1), 75 verse(v1.library, v1.book, v1.chapter - 1, 999), 76 ) 77 ) 78 else: 79 if (v1.library, v1.book - 1) not in self.books: 80 return None 81 prev_book = self.books[v1.library, v1.book - 1] 82 end_chapter = prev_book.chapters 83 return reference( 84 range( 85 verse(v1.library, prev_book.id, end_chapter, 1), 86 verse(v1.library, prev_book.id, end_chapter, 999), 87 ) 88 ) 89 90 def next_chapter(self, ref: Reference) -> Reference | None: 91 """Find a reference to the next chapter. 92 93 We step into succeeding books but not succeeding libraries. 94 95 Returns: 96 None: if this is the last chapter of a `refspy.library.Library`. 97 """ 98 v1 = ref.ranges[0].start 99 end_chapter = self.books[v1.library, v1.book].chapters 100 if v1.chapter < end_chapter: 101 return reference( 102 range( 103 verse(v1.library, v1.book, v1.chapter + 1, 1), 104 verse(v1.library, v1.book, v1.chapter + 1, 999), 105 ) 106 ) 107 else: 108 if (v1.library, v1.book + 1) not in self.books: 109 return None 110 next_book = self.books[v1.library, v1.book + 1] 111 return reference( 112 range( 113 verse(v1.library, next_book.id, 1, 1), 114 verse(v1.library, next_book.id, 1, 999), 115 ) 116 )