From 389ccf9b139376724f35064aba9f820055306301 Mon Sep 17 00:00:00 2001
From: Jonas Smedegaard <dr@jones.dk>
Date: Wed, 28 Aug 2024 03:34:08 +0200
Subject: use Feature::Compat::Class to define class Event

---
 bin/events2md.pl | 166 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 89 insertions(+), 77 deletions(-)

diff --git a/bin/events2md.pl b/bin/events2md.pl
index 725e8f5..a83fd13 100755
--- a/bin/events2md.pl
+++ b/bin/events2md.pl
@@ -6,6 +6,7 @@ use utf8;
 use open qw(:std :encoding(UTF-8));
 use autodie;
 use Feature::Compat::Try;
+use Feature::Compat::Class 0.07;
 
 use FindBin qw($Bin);
 
@@ -43,6 +44,90 @@ $CALENDAR_URI ||= shift @ARGV
 $OUTPUT_FILE = shift @ARGV
 	if @ARGV;
 
+class Event {
+	use Encode qw(decode_utf8);    # TODO: modernize CalDAV access instead
+
+	field $log = Log::Any->get_logger;
+
+	field $entry : param;
+
+	field $begin : reader      = $entry->start;
+	field $date_begin : reader = $begin->strftime('%A %e. %B');
+	field $time_begin : reader = $begin->strftime('%k.%M');
+	field $end : reader        = $entry->end;
+	field $date_end : reader;
+	field $time_end : reader;
+	field $datespan : reader;
+	field $timespan : reader;
+	field $time_brief : reader;
+	field $summary : reader
+		= $entry->property('summary')
+		? decode_utf8 $entry->property('summary')->[0]->value
+		: '';
+	field $description : reader
+		= $entry->property('description')
+		? decode_utf8 $entry->property('description')->[0]->value
+		: '';
+	field $location : reader
+		= $entry->property('location')
+		? decode_utf8 $entry->property('location')->[0]->value
+		: '';
+	field $price : reader;
+	field @attendees;
+	field @attachments;
+
+	ADJUST {
+		if ( defined $end ) {
+			$date_end = $end->strftime('%A %e. %B');
+			$time_end = $end->strftime('%k.%M');
+		}
+		$datespan
+			= ( defined $end and $date_end ne $date_begin )
+			? ucfirst("$date_begin - $date_end")
+			: ucfirst("$date_begin");
+		$timespan
+			= ( defined $end and not $entry->all_day )
+			? ucfirst("$date_begin kl. $time_begin-$time_end")
+			: undef;
+		$time_brief
+			= $entry->all_day
+			? $datespan
+			: ucfirst("$date_begin kl. $time_begin");
+		$description =~ s/\n\n[Pp]ris:\s*((?!\n).+)\s*\z//m;
+		$price = $1;
+
+		if ( $entry->property('attendee') ) {
+			for ( @{ $entry->property('attendee') } ) {
+				push @attendees, decode_utf8 $_->parameters->{'CN'}
+					|| $_->value =~ s/^mailto://r;
+			}
+		}
+		if ( $entry->property('attach') ) {
+			for ( @{ $entry->property('attach') } ) {
+				my $uri;
+				try { $uri = URI->new( $_->value ) }
+				catch ($e) {
+					$log->errorf( 'failed to parse URI %s: %s', $uri, $e );
+					next;
+				}
+				$uri->authority and $uri->host
+					or next;
+				push @attachments, $uri;
+			}
+		}
+
+		if ( $log->is_trace ) {
+			use DDP;
+			p $entry;
+			p $begin;
+			p $end;
+		}
+	}
+
+	method attendees   { !!@attendees   ? [@attendees]   : undef }
+	method attachments { !!@attachments ? [@attachments] : undef }
+}
+
 # use system locale to format DateTime objects parsed from iCal data
 DateTime->DefaultLocale( setlocale(LC_TIME) );
 
@@ -148,11 +233,10 @@ my $end = $start->clone->add( months => 6 );
 $log->infof( 'will pick events between %s and %s', $start, $end );
 my $span   = DateTime::Span->from_datetimes( start => $start, end => $end );
 my @events = sort {
-		   DateTime->compare( $a->start, $b->start )
+		   DateTime->compare( $a->begin, $b->begin )
 		|| DateTime->compare( $a->end,   $b->end )
-		|| get_property_string( $a, 'summary' )
-		cmp get_property_string( $b, 'summary' )
-} $calendar->events($span);
+		|| $a->summary cmp $b->summary
+} map { Event->new( entry => $_ ) } $calendar->events($span);
 if ( $log->is_trace ) {
 	use DDP;
 	p @events;
@@ -167,7 +251,7 @@ if ($OUTPUT_FILE) {
 my %vars;
 for (@events) {
 	next unless $_->summary;
-	push @{ $vars{events} }, resolve_event( $_, $_->start, $_->end );
+	push @{ $vars{events} }, $_;
 }
 
 my %tmpl;
@@ -188,76 +272,4 @@ else {
 	print $content;
 }
 
-sub resolve_event ( $entry, $start, $end = undef )
-{
-	if ( $log->is_trace ) {
-		use DDP;
-		p $entry;
-		p $start;
-		p $end;
-	}
-	my $summary     = get_property_string( $entry, 'summary' );
-	my $description = get_property_string( $entry, 'description' );
-	$description =~ s/\n\n[Pp]ris:\s*((?!\n).+)\s*\z//m;
-	my $price = $1;
-	my @attendees;
-	if ( $entry->property('attendee') ) {
-		for ( @{ $entry->property('attendee') } ) {
-			push @attendees, decode_utf8 $_->parameters->{'CN'}
-				|| $_->value =~ s/^mailto://r;
-		}
-	}
-	my $location   = get_property_string( $entry, 'location' );
-	my $date_begin = $start->strftime('%A %e. %B');
-	my $time_begin = $start->strftime('%k.%M');
-	my $date_end   = $end->strftime('%A %e. %B');
-	my $time_end   = $end->strftime('%k.%M');
-	my $datespan
-		= ( defined($end) and $date_end ne $date_begin )
-		? ucfirst("$date_begin - $date_end")
-		: ucfirst("$date_begin");
-	my $timespan
-		= ( defined($end) and not $_->all_day )
-		? ucfirst("$date_begin kl. $time_begin-$time_end")
-		: undef;
-	my $time_brief
-		= $_->all_day
-		? $datespan
-		: ucfirst("$date_begin kl. $time_begin");
-	my @attachments;
-
-	if ( $entry->property('attach') ) {
-		for ( @{ $entry->property('attach') } ) {
-			my $uri;
-			try { $uri = URI->new( $_->value ) }
-			catch ($e) {
-				$log->errorf( 'failed to parse URI %s: %s', $uri, $e );
-				next;
-			}
-			$uri->authority and $uri->host
-				or next;
-			push @attachments, $uri;
-		}
-	}
-
-	return {
-		time_brief  => $time_brief,
-		summary     => $summary,
-		description => $description,
-		attendees   => @attendees ? [@attendees] : undef,
-		location    => $location,
-		timespan    => $timespan,
-		price       => $price,
-		attachments => @attachments ? [@attachments] : undef,
-	};
-}
-
-sub get_property_string ( $entry, $key )
-{
-	return ''
-		unless $entry->property($key);
-
-	return decode_utf8 $entry->property($key)->[0]->value;
-}
-
 1;
-- 
cgit v1.2.3