]> Dogcows Code - chaz/git-codeowners/blob - lib/App/Codeowners/Formatter.pm
refactor formatters
[chaz/git-codeowners] / lib / App / Codeowners / Formatter.pm
1 package App::Codeowners::Formatter;
2 # ABSTRACT: Base class for formatting codeowners output
3
4 =head1 SYNOPSIS
5
6 my $formatter = App::Codeowners::Formatter->new(handle => *STDOUT);
7 $formatter->add_result($_) for @results;
8
9 =head1 DESCRIPTION
10
11 This is a base class for formatters. A formatter is a class that takes data records, stringifies
12 them, and prints them to an IO handle.
13
14 This class is mostly abstract, though it is also usable as a null formatter where results are simply
15 discarded if it is instantiated directly. These other formatters do more interesting things:
16
17 =for :list
18 * L<App::Codeowners::Formatter::CSV>
19 * L<App::Codeowners::Formatter::String>
20 * L<App::Codeowners::Formatter::JSON>
21 * L<App::Codeowners::Formatter::TSV>
22 * L<App::Codeowners::Formatter::Table>
23 * L<App::Codeowners::Formatter::YAML>
24
25 =cut
26
27 use warnings;
28 use strict;
29
30 our $VERSION = '9999.999'; # VERSION
31
32 use Module::Load;
33
34 =method new
35
36 $formatter = App::Codeowners::Formatter->new;
37 $formatter = App::Codeowners::Formatter->new(%attributes);
38
39 Construct a new formatter.
40
41 =cut
42
43 sub new {
44 my $class = shift;
45 my $args = {@_ == 1 && ref $_[0] eq 'HASH' ? %{$_[0]} : @_};
46
47 $args->{results} = [];
48
49 # see if we can find a better class to bless into
50 ($class, my $format) = $class->_best_formatter($args->{format}) if $args->{format};
51 $args->{format} = $format;
52
53 my $self = bless $args, $class;
54
55 $self->start;
56
57 return $self;
58 }
59
60 ### _best_formatter
61 # Find a formatter that can handle the format requested.
62 sub _best_formatter {
63 my $class = shift;
64 my $type = shift || '';
65
66 return ($class, $type) if $class ne __PACKAGE__;
67
68 my ($name, $format) = $type =~ /^([A-Za-z]+)(?::(.*))?$/;
69 if (!$name) {
70 $name = '';
71 $format = '';
72 }
73
74 $name = lc($name);
75 $name =~ s/:.*//;
76
77 my @formatters = $class->formatters;
78
79 # default to the string formatter since it has no dependencies
80 my $package = __PACKAGE__.'::String';
81
82 # look for a formatter whose name matches the format
83 for my $formatter (@formatters) {
84 my $module = lc($formatter);
85 $module =~ s/.*:://;
86
87 if ($module eq $name) {
88 $package = $formatter;
89 $type = $format;
90 last;
91 }
92 }
93
94 load $package;
95 return ($package, $type);
96 }
97
98 =method DESTROY
99
100 Destructor calls L</finish>.
101
102 =cut
103
104 sub DESTROY {
105 my $self = shift;
106 my $global_destruction = shift;
107
108 return if $global_destruction;
109
110 my $results = $self->{results};
111 $self->finish($results) if $results;
112 delete $self->{results};
113 }
114
115 =attr handle
116
117 Get the IO handle associated with a formatter.
118
119 =attr format
120
121 Get the format string, which may be used to customize the formatting.
122
123 =attr columns
124
125 Get an arrayref of column headings.
126
127 =attr results
128
129 Get an arrayref of all the results that have been provided to the formatter using L</add_result> but
130 have not yet been formatted.
131
132 =cut
133
134 sub handle { shift->{handle} }
135 sub format { shift->{format} || '' }
136 sub columns { shift->{columns} || [] }
137 sub results { shift->{results} }
138
139 =method add_result
140
141 $formatter->add_result($result);
142
143 Provide an additional lint result to be formatted.
144
145 =cut
146
147 sub add_result {
148 my $self = shift;
149 $self->stream($_) for @_;
150 }
151
152 =method start
153
154 $formatter->start;
155
156 Begin formatting results. Called before any results are passed to the L</stream> method.
157
158 This method may print a header to the L</handle>. This method is used by subclasses and should
159 typically not be called explicitly.
160
161 =method stream
162
163 $formatter->stream(\@result, ...);
164
165 Format one result.
166
167 This method is expected to print a string representation of the result to the L</handle>. This
168 method is used by subclasses and should typically not called be called explicitly.
169
170 The default implementation simply stores the L</results> so they will be available to L</finish>.
171
172 =method finish
173
174 $formatter->finish;
175
176 End formatting results. Called after all results are passed to the L</stream> method.
177
178 This method may print a footer to the L</handle>. This method is used by subclasses and should
179 typically not be called explicitly.
180
181 =cut
182
183 sub start {}
184 sub stream { push @{$_[0]->results}, $_[1] }
185 sub finish {}
186
187 =method formatters
188
189 @formatters = App::Codeowners::Formatter->formatters;
190
191 Get a list of package names of potential formatters within the C<App::Codeowners::Formatter>
192 namespace.
193
194 =cut
195
196 sub formatters {
197 return qw(
198 App::Codeowners::Formatter::CSV
199 App::Codeowners::Formatter::JSON
200 App::Codeowners::Formatter::String
201 App::Codeowners::Formatter::TSV
202 App::Codeowners::Formatter::Table
203 App::Codeowners::Formatter::YAML
204 );
205 }
206
207 1;
This page took 0.04296 seconds and 4 git commands to generate.