File Coverage

blib/lib/Text/MarkdownTable.pm
Criterion Covered Total %
statement 96 96 100.0
branch 36 38 94.7
condition 15 20 75.0
subroutine 16 16 100.0
pod 2 2 100.0
total 165 172 95.9


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