-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
scripture_ref.py
131 lines (102 loc) · 4.1 KB
/
scripture_ref.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from __future__ import annotations
from functools import total_ordering
from typing import List, Optional
from ..utils.comparable import Comparable
from .constants import ENGLISH_VERSIFICATION
from .scripture_element import ScriptureElement
from .verse_ref import VerseRef, Versification, are_overlapping_verse_ranges
@total_ordering
class ScriptureRef(Comparable):
def __init__(self, ref: Optional[VerseRef] = None, path: Optional[List[ScriptureElement]] = None) -> None:
self._verse_ref: VerseRef = ref if ref is not None else VerseRef()
self._path: List[ScriptureElement] = path if path is not None else []
_empty: Optional[ScriptureRef] = None
@classmethod
def empty(cls) -> ScriptureRef:
if cls._empty is None:
cls._empty = cls()
return cls._empty
@classmethod
def parse(cls, selection: str, versification: Optional[Versification] = None) -> ScriptureRef:
parts: List[str] = selection.split("/")
if len(parts) == 1:
return cls(
VerseRef.from_string(parts[0], versification if versification is not None else ENGLISH_VERSIFICATION)
)
vref: str = parts[0]
path: List[ScriptureElement] = []
for part in parts[1:]:
elem: List[str] = part.split(":")
if len(elem) == 1:
path.append(ScriptureElement(0, elem[0]))
else:
path.append(ScriptureElement(int(elem[0]), elem[1]))
return cls(
VerseRef.from_string(vref, versification if versification is not None else ENGLISH_VERSIFICATION), path
)
@property
def verse_ref(self) -> VerseRef:
return self._verse_ref
@property
def path(self) -> List[ScriptureElement]:
return self._path
@property
def book_num(self) -> int:
return self.verse_ref.book_num
@property
def chapter_num(self) -> int:
return self.verse_ref.chapter_num
@property
def verse_num(self) -> int:
return self.verse_ref.verse_num
@property
def book(self) -> str:
return self.verse_ref.book
@property
def chapter(self) -> str:
return self.verse_ref.chapter
@property
def verse(self) -> str:
return self.verse_ref.verse
@property
def versification(self) -> Versification:
return self.verse_ref.versification
@property
def is_empty(self) -> bool:
return self.verse_ref.is_default
@property
def is_verse(self) -> bool:
return VerseRef.verse_num != 0 and len(self.path) == 0
def change_versification(self, versification: Versification) -> ScriptureRef:
vr: VerseRef = self.verse_ref.copy()
vr.change_versification(versification)
return ScriptureRef(vr, self.path)
def overlaps(self, other: ScriptureRef) -> bool:
if not are_overlapping_verse_ranges(self.verse_ref, other.verse_ref):
return False
return self.path == other.path
def compare_to(self, other: object, compare_segments: bool = True, strict: bool = True):
if not isinstance(other, ScriptureRef):
raise TypeError("other is not a ScriptureRef object.")
if self is other:
return 0
res = self.verse_ref.compare_to(other.verse_ref, compare_segments=compare_segments)
if res != 0:
return res
for se1, se2 in zip(self.path, other.path):
res = se1.compare_to(se2, strict=strict)
if res != 0:
return res
return len(self.path) - len(other.path)
def __eq__(self, other: object) -> bool:
if not isinstance(other, ScriptureRef):
return NotImplemented
return self.verse_ref == other.verse_ref and self.path == other.path
def __lt__(self, other: object) -> bool:
if not isinstance(other, ScriptureRef):
return NotImplemented
return self.compare_to(other) < 0
def __hash__(self) -> int:
return hash((self.verse_ref, tuple(self.path)))
def __repr__(self) -> str:
return f"{self.verse_ref}/{'/'.join(str(se) for se in self.path)}"