package App::Codeowners::Formatter; # ABSTRACT: Base class for formatting codeowners output =head1 SYNOPSIS my $formatter = App::Codeowners::Formatter->new(handle => *STDOUT); $formatter->add_result($_) for @results; =head1 DESCRIPTION This is a base class for formatters. A formatter is a class that takes data records, stringifies them, and prints them to an IO handle. This class is mostly abstract, though it is also usable as a null formatter where results are simply discarded if it is instantiated directly. These other formatters do more interesting things: =for :list * L * L * L * L * L * L =cut use warnings; use strict; our $VERSION = '9999.999'; # VERSION use Module::Load; =method new $formatter = App::Codeowners::Formatter->new; $formatter = App::Codeowners::Formatter->new(%attributes); Construct a new formatter. =cut sub new { my $class = shift; my $args = {@_ == 1 && ref $_[0] eq 'HASH' ? %{$_[0]} : @_}; $args->{results} = []; # see if we can find a better class to bless into ($class, my $format) = $class->_best_formatter($args->{format}) if $args->{format}; $args->{format} = $format; my $self = bless $args, $class; $self->start; return $self; } ### _best_formatter # Find a formatter that can handle the format requested. sub _best_formatter { my $class = shift; my $type = shift || ''; return ($class, $type) if $class ne __PACKAGE__; my ($name, $format) = $type =~ /^([A-Za-z]+)(?::(.*))?$/; if (!$name) { $name = ''; $format = ''; } $name = lc($name); $name =~ s/:.*//; my @formatters = $class->formatters; # default to the string formatter since it has no dependencies my $package = __PACKAGE__.'::String'; # look for a formatter whose name matches the format for my $formatter (@formatters) { my $module = lc($formatter); $module =~ s/.*:://; if ($module eq $name) { $package = $formatter; $type = $format; last; } } load $package; return ($package, $type); } =method DESTROY Destructor calls L. =cut sub DESTROY { my $self = shift; my $global_destruction = shift; return if $global_destruction; my $results = $self->{results}; $self->finish($results) if $results; delete $self->{results}; } =attr handle Get the IO handle associated with a formatter. =attr format Get the format string, which may be used to customize the formatting. =attr columns Get an arrayref of column headings. =attr results Get an arrayref of all the results that have been provided to the formatter using L but have not yet been formatted. =cut sub handle { shift->{handle} } sub format { shift->{format} || '' } sub columns { shift->{columns} || [] } sub results { shift->{results} } =method add_result $formatter->add_result($result); Provide an additional lint result to be formatted. =cut sub add_result { my $self = shift; $self->stream($_) for @_; } =method start $formatter->start; Begin formatting results. Called before any results are passed to the L method. This method may print a header to the L. This method is used by subclasses and should typically not be called explicitly. =method stream $formatter->stream(\@result, ...); Format one result. This method is expected to print a string representation of the result to the L. This method is used by subclasses and should typically not called be called explicitly. The default implementation simply stores the L so they will be available to L. =method finish $formatter->finish; End formatting results. Called after all results are passed to the L method. This method may print a footer to the L. This method is used by subclasses and should typically not be called explicitly. =cut sub start {} sub stream { push @{$_[0]->results}, $_[1] } sub finish {} =method formatters @formatters = App::Codeowners::Formatter->formatters; Get a list of package names of potential formatters within the C namespace. =cut sub formatters { return qw( App::Codeowners::Formatter::CSV App::Codeowners::Formatter::JSON App::Codeowners::Formatter::String App::Codeowners::Formatter::TSV App::Codeowners::Formatter::Table App::Codeowners::Formatter::YAML ); } 1;