File Coverage

blib/lib/Text/MarkdownTable.pm
Criterion Covered Total %
statement 88 88 100.0
branch 30 32 93.7
condition 13 17 76.4
subroutine 16 16 100.0
pod 2 2 100.0
total 149 155 96.1


line stmt bran cond sub pod time code
1             package Text::MarkdownTable;
2 2     2   29791 use strict;
  2         3  
  2         67  
3 2     2   9 use warnings;
  2         3  
  2         56  
4 2     2   42 use 5.010;
  2         11  
  2         104  
5              
6             our $VERSION = '0.2.4';
7              
8 2     2   2426 use Moo;
  2         25716  
  2         10  
9              
10             has file => (
11             is => 'ro',
12             lazy => 1,
13             default => sub { \*STDOUT },
14             );
15              
16 2     2   3764 use IO::File;
  2         15229  
  2         201  
17 2     2   1024 use IO::Handle::Util ();
  2         26529  
  2         1740  
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 10     10   1162 builder => sub { $_[0]->fields }
47             );
48              
49             has widths => (
50             is => 'lazy',
51             coerce => \&_coerce_list,
52             builder => sub {
53 10     10   971 $_[0]->_fixed_width(0);
54 10 100       11 return [map { defined($_) ? length $_ : 0 } @{$_[0]->columns}]
  17         105  
  10         126  
55             },
56             );
57              
58             has condense => (is => 'rw');
59              
60             has _fixed_width => (is => 'rw', default => sub { 1 });
61             has _streaming => (is => 'rw');
62              
63             # TODO: duplicated in Catmandu::Exporter::CSV fields-coerce
64             sub _coerce_list {
65 25 100   25   124 if (ref $_[0]) {
66 22 100       330 return $_[0] if ref $_[0] eq 'ARRAY';
67 1 50       4 return [sort keys %{$_[0]}] if ref $_[0] eq 'HASH';
  1         5  
68             }
69 3         52 return [split ',', $_[0]];
70             }
71              
72             sub _trigger_fields {
73 1     1   10 my ($self, $fields) = @_;
74 1         2 $self->{fields} = _coerce_list($fields);
75 1 50 33     8 if (ref $fields and ref $fields eq 'HASH') {
76 1   66     1 $self->{columns} = [ map { $fields->{$_} // $_ } @{$self->{fields}} ];
  3         26  
  1         3  
77             }
78             }
79              
80             sub add {
81 15     15 1 557 my ($self, $data) = @_;
82 15 100       210 unless ($self->fields) {
83 11         849 $self->{fields} = [ sort keys %$data ]
84             }
85 15         241 my $fields = $self->fields;
86 15         221 my $widths = $self->widths; # may set
87 15         89 my $row = [ ];
88              
89 15 100       40 if (!$self->_streaming) {
90 14 100 100     58 if ($self->condense or $self->_fixed_width) {
91 4         10 $self->_streaming(1);
92 4         6 $self->_print_header;
93             }
94             }
95              
96 15         79 foreach my $col (0..(@$fields-1)) {
97 29         31 my $field = $fields->[$col];
98 29         28 my $width = $widths->[$col];
99              
100 29   100     56 my $value = $data->{$field} // "";
101 29         38 $value =~ s/[\n|]/ /g;
102              
103 29         26 my $w = length $value;
104 29 100       59 if ($self->_fixed_width) {
105 6 100 66     24 if (!$width or $w > $width) {
106 4 100       6 if ($width > 5) {
107 2         3 $value = substr($value, 0, $width-3) . '...';
108             } else {
109 2         6 $value = substr($value, 0, $width);
110             }
111             }
112             } else {
113 23 100 100     77 $widths->[$col] = $w if !$width or $w > $width;
114             }
115 29         50 push @$row, $value;
116             }
117              
118 15         28 $self->_add_row($row);
119 15         82 $self;
120             }
121              
122             sub _add_row {
123 15     15   20 my ($self, $row) = @_;
124              
125 15 100       27 if ($self->_streaming) {
126 5         9 $self->_print_row($row);
127             } else {
128 10         6 push @{$self->{_rows}}, $row;
  10         20  
129             }
130             }
131              
132             sub done {
133 12     12 1 34 my ($self) = @_;
134              
135 12 100       27 if ($self->{_rows}) {
136 8         15 $self->_print_header;
137 3         31 $self->_print_row($_) for @{$self->{_rows}};
  3         7  
138             }
139             }
140              
141             sub _print_header {
142 12     12   9 my ($self) = @_;
143 12         167 my $fh = $self->fh;
144              
145 7         135 $self->_print_row($self->columns);
146 7 100       102 if ($self->condense) {
147 3         3 $self->_print_row([ map { '-' x length $_ } @{$self->columns} ]);
  6         29  
  3         52  
148             } else {
149 4         5 print $fh '|'.('-' x ($_+2)) for @{$self->widths};
  4         65  
150 4         164 print $fh "|\n";
151             }
152             }
153              
154             has _row_format => (
155             is => 'lazy',
156             builder => sub {
157 6         26 $_[0]->condense
158 3         48 ? join("|",map {"%s"} @{$_[0]->fields})."\n"
  12         44  
159 7 100   7   823 : join("",map {"| %-".$_."s "} @{$_[0]->widths})."|\n";
  4         59  
160             }
161             );
162              
163             sub _print_row {
164 20     20   80 my ($self, $row) = @_;
165 20         16 printf {$self->fh} $self->_row_format, @{$row};
  20         306  
  20         332  
166             }
167              
168             1;
169             __END__