App-Music-ChordPro/lib/ChordPro/Output/Meta.pm
#! perl
use v5.26;
use Object::Pad;
# Output backend to extract meta data.
class ChordPro::Output::Meta;
use JSON::PP;
use ChordPro::Utils qw( qquote max );
use Ref::Util qw(is_arrayref);
my $sep = "; ";
method generate_songbook :common ($sb) {
my @res = ( "[" );
for my $song ( @{ $sb->{songs} } ) {
my $m = $song->{meta};
my @r;
my $ll = 0;
for ( qw( songindex title subtitle ) ) {
my $v = flatten($m->{$_});
push( @r, [ qquote($_, 1), qquote( $v, !looks_like_number($v) ) ] );
$ll = max( $ll, length($r[-1][0]) );
}
# The rest.
for ( sort keys %$m ) {
next if /^((sub)?title|songindex)$/; # already done
next if /^(chordpro\..*|bookmark|_.*)/; # internal meta
next if /^(num)?chords$/; # internal meta
next if /^key_(actual|from)/; # transient meta
my $v = flatten($m->{$_});
push( @r, [ qquote($_, 1), qquote( $v, !looks_like_number($v) ) ] );
$ll = max( $ll, length($r[-1][0]) );
}
push( @res, " {" );
for ( @r ) {
push( @res, sprintf( " %-${ll}s : %s,", @$_ ) );
}
$res[-1] =~ s/,$//;
push( @res, " }," );
}
$res[-1] =~ s/,$//;
push( @res, "]" );
\@res;
}
sub looks_like_number($v) {
defined($v) && $v =~ /^[-+]?\d+(?:\.\d*)?$/;
}
sub kv( $k, $v ) {
$v = flatten($v);
qquote($k, 1) . " : " . qquote($v, !looks_like_number($v));
}
sub flatten($v) {
return $v unless is_arrayref($v);
return $v->[0] if @$v == 1;
join( $sep, @$v );
}
1;