File Coverage

blib/lib/Text/MarkdownTable.pm
Criterion Covered Total %
statement 88 88 100.0
branch 34 36 94.4
condition 13 17 76.4
subroutine 16 16 100.0
pod 2 2 100.0
total 153 159 96.2


line stmt bran cond sub pod time code
1             package Text::MarkdownTable;
2 2     2   32045 use strict;
  2         3  
  2         71  
3 2     2   8 use warnings;
  2         3  
  2         49  
4 2     2   46 use 5.010;
  2         9  
  2         106  
5              
6             our $VERSION = '0.3.0';
7              
8 2     2   1048 use Moo;
  2         23033  
  2         10  
9              
10             has file => (
11             is => 'ro',
12             lazy => 1,
13             default => sub { \*STDOUT },
14             );
15              
16 2     2   3422 use IO::File;
  2         14588  
  2         207  
17 2     2   1089 use IO::Handle::Util ();
  2         27684  
  2         1816  
18              
19             has fh => (
20             is => 'ro',
21             lazy => 1,
22             default => sub {
23             my $fh = $_[0]->file;
24             $fh = ref $fh
25             ? IO::Handle::Util::io_from_ref($fh) : IO::File->new($fh, "w");
26             die "invalid option file" if !$fh;
27             binmode $fh, $_[0]->encoding;
28             $fh;
29             }
30             );
31              
32             has encoding => (
33             is => 'ro',
34             default => sub { ':utf8' }
35             );
36              
37             has fields => (
38             is => 'rw',
39             trigger => 1,
40             );
41              
42             # TODO: ensure that number of columns is number of fields
43             has columns => (
44             is => 'lazy',
45             coerce => \&_coerce_list,
46 12     12   1152 builder => sub { $_[0]->fields }
47             );
48              
49             has widths => (
50             is => 'lazy',
51             coerce => \&_coerce_list,
52             builder => sub {
53 12     12   1236 $_[0]->_fixed_width(0);
54 12 100       11 return [map { defined($_) ? length $_ : 0 } @{$_[0]->columns}]
  20         128  
  12         160  
55             },
56             );
57              
58             has header => (is => 'rw', default => sub { 1 });
59              
60             has condense => (is => 'rw');
61              
62             has _fixed_width => (is => 'rw', default => sub { 1 });
63             has _streaming => (is => 'rw');
64              
65             # TODO: duplicated in Catmandu::Exporter::CSV fields-coerce
66             sub _coerce_list {
67 29 100   29   137 if (ref $_[0]) {
68 26 100       577 return $_[0] if ref $_[0] eq 'ARRAY';
69 1 50       3 return [sort keys %{$_[0]}] if ref $_[0] eq 'HASH';
  1         7  
70             }
71 3         53 return [split ',', $_[0]];
72             }
73              
74             sub _trigger_fields {
75 1     1   10 my ($self, $fields) = @_;
76 1         3 $self->{fields} = _coerce_list($fields);
77 1 50 33     7 if (ref $fields and ref $fields eq 'HASH') {
78 1   66     4 $self->{columns} = [ map { $fields->{$_} // $_ } @{$self->{fields}} ];
  3         27  
  1         3  
79             }
80             }
81              
82             sub add {
83 19     19 1 526 my ($self, $data) = @_;
84 19 100       270 unless ($self->fields) {
85 13         889 $self->{fields} = [ sort keys %$data ]
86             }
87 19         307 my $fields = $self->fields;
88 19         293 my $widths = $self->widths; # may set
89 19         118 my $row = [ ];
90              
91 19 100       47 if (!$self->_streaming) {
92 17 100 100     76 if ($self->condense or $self->_fixed_width) {
93 5         10 $self->_streaming(1);
94 5 100       18 $self->_print_header if $self->header;
95             }
96             }
97              
98 19         75 foreach my $col (0..(@$fields-1)) {
99 35         41 my $field = $fields->[$col];
100 35         29 my $width = $widths->[$col];
101              
102 35   100     68 my $value = $data->{$field} // "";
103 35         66 $value =~ s/[\n|]/ /g;
104              
105 35         34 my $w = length $value;
106 35 100       50 if ($self->_fixed_width) {
107 6 100 66     25 if (!$width or $w > $width) {
108 4 100       8 if ($width > 5) {
109 2         3 $value = substr($value, 0, $width-3) . '...';
110             } else {
111 2         5 $value = substr($value, 0, $width);
112             }
113             }
114             } else {
115 29 100 100     103 $widths->[$col] = $w if !$width or $w > $width;
116             }
117 35         67 push @$row, $value;
118             }
119              
120 19         37 $self->_add_row($row);
121 19         116 $self;
122             }
123              
124             sub _add_row {
125 19     19   24 my ($self, $row) = @_;
126              
127 19 100       31 if ($self->_streaming) {
128 7         10 $self->_print_row($row);
129             } else {
130 12         11 push @{$self->{_rows}}, $row;
  12         30  
131             }
132             }
133              
134             sub done {
135 14     14 1 39 my ($self) = @_;
136              
137 14 100       36 if ($self->{_rows}) {
138 9 100       28 $self->_print_header if $self->header;
139 4         32 $self->_print_row($_) for @{$self->{_rows}};
  4         12  
140             }
141             }
142              
143             sub _print_header {
144 12     12   12 my ($self) = @_;
145 12         168 my $fh = $self->fh;
146              
147 7         213 $self->_print_row($self->columns);
148 7 100       106 if ($self->condense) {
149 3         5 $self->_print_row([ map { '-' x length $_ } @{$self->columns} ]);
  6         31  
  3         68  
150             } else {
151 4         5 print $fh '|'.('-' x ($_+2)) for @{$self->widths};
  4         63  
152 4         166 print $fh "|\n";
153             }
154             }
155              
156             has _row_format => (
157             is => 'lazy',
158             builder => sub {
159 8         34 $_[0]->condense
160 4         63 ? join("|",map {"%s"} @{$_[0]->fields})."\n"
  13         52  
161 9 100   9   808 : join("",map {"| %-".$_."s "} @{$_[0]->widths})."|\n";
  5         75  
162             }
163             );
164              
165             sub _print_row {
166 24     24   103 my ($self, $row) = @_;
167 24         19 printf {$self->fh} $self->_row_format, @{$row};
  24         368  
  24         404  
168             }
169              
170             1;
171             __END__