File Coverage

blib/lib/Ascii/Text.pm
Criterion Covered Total %
statement 29 29 100.0
branch n/a
condition n/a
subroutine 11 11 100.0
pod n/a
total 40 40 100.0


line stmt bran cond sub pod time code
1             package Ascii::Text;
2              
3 2     2   171047 use 5.006;
  2         6  
4 2     2   24 use strict;
  2         7  
  2         46  
5 2     2   13 use warnings;
  2         2  
  2         109  
6              
7             our $VERSION = '0.22';
8              
9 2     2   1039 use Rope;
  2         15595  
  2         12  
10 2     2   1170 use Rope::Autoload;
  2         4722  
  2         8  
11 2     2   847 use Term::Size::ReadKey;
  2         4646  
  2         95  
12 2     2   975 use Module::Load;
  2         2050  
  2         12  
13 2     2   1176 use Types::Standard qw/Int Str Enum HashRef FileHandle/;
  2         207296  
  2         28  
14              
15             use overload "&{}" => sub {
16 2     2   2589 my $self = shift;
17 2     2   41 return sub { $self->render(@_); }
18 2     2   5204 };
  2         2  
  2         18  
  2         13  
19              
20             property max_width => (
21             initable => 1,
22             writeable => 1,
23             type => Int,
24             builder => sub {
25             Term::Size::ReadKey::chars *STDOUT{IO};
26             }
27             );
28              
29             property override_empty_space => (
30             initable => 1,
31             writeable => 1,
32             type => Int,
33             value => 0
34             );
35            
36             property pad => (
37             initable => 1,
38             writeable => 1,
39             type => Int,
40             value => 0,
41             );
42              
43             property font => (
44             initable => 1,
45             writeable => 1,
46             type => Str,
47             value => 'Boomer'
48             );
49              
50             property align => (
51             initable => 1,
52             writeable => 1,
53             type => Enum[qw( left center right )],
54             value => 'left'
55             );
56              
57             property color => (
58             initable => 1,
59             type => Str,
60             writeable => 1,
61             );
62              
63             property color_map => (
64             initable => 1,
65             writeable => 1,
66             type => HashRef,
67             builder => sub { return {
68             black => "\e[30m",
69             red => "\e[31m",
70             green => "\e[32m",
71             yellow => "\e[33m",
72             blue => "\e[34m",
73             magenta => "\e[35m",
74             cyan => "\e[36m",
75             white => "\e[37m",
76             bright_black => "\e[90m",
77             bright_red => "\e[91m",
78             bright_green => "\e[92m",
79             bright_yellow => "\e[93m",
80             bright_blue => "\e[94m",
81             bright_magenta => "\e[95m",
82             bright_cyan => "\e[96m",
83             bright_white => "\e[37m",
84             } }
85             );
86              
87             property fh => (
88             initable => 1,
89             writeable => 1,
90             builder => sub {
91             return *STDOUT;
92             }
93             );
94              
95             function font_class => sub {
96             my $class = sprintf "Ascii::Text::Font::%s", $_[0]->font;
97             load $class;
98             return $class;
99             };
100              
101             function stringify => sub {
102             my ($self, $text, $wrap) = @_;
103             my $stringify = [];
104             $self->render($text, $stringify);
105             return join "", grep { $wrap ? $_ !~ m/^\s+$/ : $_ } @{$stringify};
106             };
107              
108             function render => sub {
109             my ($self, $text, $stringify) = @_;
110             $text =~ s/[^ 0-9A-Za-z]//;
111             my $class = $self->font_class->new;
112             my @words = split /\s+/, $text;
113             my %character_map;
114             for (@words) {
115             my @characters = split //, $_;
116             for (@characters) {
117             next if $character_map{$_};
118             my $character = "character_$_";
119             $character = $class->$character;
120             $character_map{$_} = $character;
121             }
122             }
123             my ($width, @line) = $self->new_line();
124             while (@words) {
125             my @characters = split //, shift @words;
126             for (my $i = 0; $i < scalar @characters; $i++) {
127             my $character = $character_map{$characters[$i]};
128             for (my $i = 0; $i < scalar @{$character}; $i++) {
129             push @{$line[$i]}, @{$character->[$i]};
130             }
131             $width -= scalar @{$character->[0]};
132              
133             my $next = $characters[$i + 1];
134             if ($next && $width < scalar @{$character_map{$next}->[0]}) {
135             $self->print_line(\@line, $stringify);
136             ($width, @line) = $self->new_line();
137             }
138             }
139             if ($words[0]) {
140             @characters = split //, $words[0];
141             my $space = $self->_empty_space($class) || $class->space;
142             my $required_width = scalar @{$space->[0]};
143             $required_width += @{$character_map{$_}->[0]} for @characters;
144             if ($width > $required_width) {
145             for (my $i = 0; $i < scalar @{$space}; $i++) {
146             push @{$line[$i]}, @{$space->[$i]}, " ";
147             }
148             $width = $width - scalar @{$space->[0]};
149             next;
150             }
151             }
152             $self->print_line(\@line, $stringify);
153             ($width, @line) = $self->new_line();
154             }
155             if ($self->color && $self->color_map->{$self->color}) {
156             if ($stringify) {
157             push @{$stringify}, "\e[0m";
158             } else {
159             my $fh = $self->fh;
160             print $fh "\e[0m";
161             }
162             }
163             };
164              
165             function new_line => sub {
166             return ($_[0]->max_width, [],[],[],[],[],[]);
167             };
168              
169             function print_line => sub {
170             my ($self, $line, $stringify) = @_;
171             my $line_width = @{$line->[0]};
172             my $pad = $self->align eq 'center'
173             ? ($self->max_width - $line_width) / 2
174             : $self->align eq 'right'
175             ? $self->max_width - $line_width
176             : $self->pad;
177             $pad = $pad && $pad > 0 ? " " x $pad : "";
178             my $fh = $self->fh;
179             for (@{$line}) {
180             next unless scalar @{$_};
181             if ($self->color && $self->color_map->{$self->color}) {
182             if ($stringify) {
183             push @{$stringify}, $self->color_map->{$self->color};
184             } else {
185             print $fh $self->color_map->{$self->color};
186             }
187             }
188             my $l = $pad;
189             $l .= join "", @{$_};
190             $l .= "\n";
191             if ($stringify) {
192             push @{$stringify}, $l;
193             } else {
194             print $fh $l;
195             }
196             }
197             };
198              
199              
200             function list => sub {
201             my ($self) = @_;
202             my $base_path = __FILE__;
203             $base_path =~ s/.pm$//;
204             $base_path .= '/Font';
205             opendir my $dir, $base_path or die $!;
206             my @files = sort grep { $_ =~ s/\.pm$//; $_ !~ m/^\./ } readdir $dir;
207             closedir $dir;
208             return @files;
209             };
210              
211             function _empty_space => sub {
212             my ($self, $font) = @_;
213             return unless $self->override_empty_space;
214             return [$font->default_character($self->override_empty_space)];
215             };
216              
217             1;
218              
219             __END__