From 1ff11db8c7d5023de29c5bc71a705860176100ec Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 2 Feb 2025 21:34:00 +0100
Subject: [PATCH] Minor refactoring.

---
 ledger.py | 50 +++++++++++++++++++++++++++-----------------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/ledger.py b/ledger.py
index dcf1c4d..fb2abcf 100755
--- a/ledger.py
+++ b/ledger.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 """Viewer for ledger .dat files."""
+from abc import ABC, abstractmethod
 from datetime import date as dt_date
 from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
 from os import environ
@@ -78,7 +79,16 @@ class Account:
         return total
 
 
-class DatLine:
+class Line(ABC):
+    """Line abstraction featuring .as_dict property."""
+
+    @property
+    @abstractmethod
+    def as_dict(self) -> dict:
+        """Return as JSON-ready dict."""
+
+
+class DatLine(Line):
     """Line of .dat file parsed into comments and machine-readable data."""
 
     def __init__(self, line: str) -> None:
@@ -90,8 +100,7 @@ class DatLine:
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
-        assert isinstance(self.booking_line, (IntroLine, TransferLine))
+        assert self.booking_line is not None
         return {'comment': self.comment, 'code': self.code,
                 'is_intro': self.is_intro, 'error': self.error,
                 'booking_line': self.booking_line.as_dict}
@@ -135,7 +144,7 @@ class DatLine:
         return self.raw.replace(' ', '&nbsp;')
 
 
-class BookingLine:
+class BookingLine(Line):
     """Parsed code part of a DatLine belonging to a Booking."""
 
     def __init__(self, booking: 'Booking') -> None:
@@ -163,7 +172,6 @@ class IntroLine(BookingLine):
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
         return {'date': self.date, 'target': self.target}
 
 
@@ -199,7 +207,6 @@ class TransferLine(BookingLine):
 
     @property
     def as_dict(self) -> dict:
-        """Return as JSON-ready dict."""
         return {'account': self.account, 'currency': self.currency,
                 'amount': str(self.amount)}
 
@@ -409,23 +416,6 @@ class Server(PlomHttpServer):
             DatLine(line)
             for line in self._path_dat.read_text(encoding='utf8').splitlines()]
         self.last_save_hash = self._hash_dat_lines()
-        self._load_bookings()
-
-    def save(self) -> None:
-        """Save current state to ._path_dat."""
-        self._path_dat.write_text(
-            '\n'.join([line.raw for line in self.dat_lines]), encoding='utf8')
-        self.load()
-
-    def _hash_dat_lines(self) -> int:
-        return hash(tuple(dl.raw for dl in self.dat_lines))
-
-    @property
-    def tainted(self) -> bool:
-        """If .dat_lines different to those of last .load()."""
-        return self._hash_dat_lines() != self.last_save_hash
-
-    def _load_bookings(self) -> None:
         booked_lines: list[DatLine] = []
         gap_lines: list[DatLine] = []
         booking: Optional[Booking] = None
@@ -455,6 +445,20 @@ class Server(PlomHttpServer):
         if booking:
             booking.gap_lines = gap_lines[:-1]
 
+    def save(self) -> None:
+        """Save current state to ._path_dat."""
+        self._path_dat.write_text(
+            '\n'.join([line.raw for line in self.dat_lines]), encoding='utf8')
+        self.load()
+
+    def _hash_dat_lines(self) -> int:
+        return hash(tuple(dl.raw for dl in self.dat_lines))
+
+    @property
+    def tainted(self) -> bool:
+        """If .dat_lines different to those of last .load()."""
+        return self._hash_dat_lines() != self.last_save_hash
+
     def _recalc_dat_lines(self) -> None:
         self.dat_lines = self.initial_gap_lines[:]
         for booking in self.bookings:
-- 
2.30.2