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   239566 use 5.006;
  2         9  
4 2     2   11 use strict;
  2         13  
  2         68  
5 2     2   11 use warnings;
  2         4  
  2         214  
6              
7             our $VERSION = '0.21';
8              
9 2     2   2660 use Rope;
  2         24566  
  2         11  
10 2     2   1583 use Rope::Autoload;
  2         6505  
  2         13  
11 2     2   1076 use Term::Size::ReadKey;
  2         7011  
  2         127  
12 2     2   1093 use Module::Load;
  2         2943  
  2         12  
13 2     2   1383 use Types::Standard qw/Int Str Enum HashRef FileHandle/;
  2         323432  
  2         32  
14              
15             use overload "&{}" => sub {
16 2     2   3820 my $self = shift;
17 2     2   38 return sub { $self->render(@_); }
18 2     2   8769 };
  2         5  
  2         22  
  2         26  
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 pad => (
30             initable => 1,
31             writeable => 1,
32             type => Int,
33             value => 0,
34             );
35              
36             property font => (
37             initable => 1,
38             writeable => 1,
39             type => Str,
40             value => 'Boomer'
41             );
42              
43             property align => (
44             initable => 1,
45             writeable => 1,
46             type => Enum[qw( left center right )],
47             value => 'left'
48             );
49              
50             property color => (
51             initable => 1,
52             type => Str,
53             writeable => 1,
54             );
55              
56             property color_map => (
57             initable => 1,
58             writeable => 1,
59             type => HashRef,
60             builder => sub { return {
61             black => "\e[30m",
62             red => "\e[31m",
63             green => "\e[32m",
64             yellow => "\e[33m",
65             blue => "\e[34m",
66             magenta => "\e[35m",
67             cyan => "\e[36m",
68             white => "\e[37m",
69             bright_black => "\e[90m",
70             bright_red => "\e[91m",
71             bright_green => "\e[92m",
72             bright_yellow => "\e[93m",
73             bright_blue => "\e[94m",
74             bright_magenta => "\e[95m",
75             bright_cyan => "\e[96m",
76             bright_white => "\e[37m",
77             } }
78             );
79              
80             property fh => (
81             initable => 1,
82             writeable => 1,
83             builder => sub {
84             return *STDOUT;
85             }
86             );
87              
88             function font_class => sub {
89             my $class = sprintf "Ascii::Text::Font::%s", $_[0]->font;
90             load $class;
91             return $class;
92             };
93              
94             function stringify => sub {
95             my ($self, $text, $wrap) = @_;
96             my $stringify = [];
97             $self->render($text, $stringify);
98             return join "", grep { $wrap ? $_ !~ m/^\s+$/ : $_ } @{$stringify};
99             };
100              
101             function render => sub {
102             my ($self, $text, $stringify) = @_;
103             $text =~ s/[^ 0-9A-Za-z]//;
104             my $class = $self->font_class->new;
105             my @words = split /\s+/, $text;
106             my %character_map;
107             for (@words) {
108             my @characters = split //, $_;
109             for (@characters) {
110             next if $character_map{$_};
111             my $character = "character_$_";
112             $character = $class->$character;
113             $character_map{$_} = $character;
114             }
115             }
116             my ($width, @line) = $self->new_line();
117             while (@words) {
118             my @characters = split //, shift @words;
119             for (my $i = 0; $i < scalar @characters; $i++) {
120             my $character = $character_map{$characters[$i]};
121             for (my $i = 0; $i < scalar @{$character}; $i++) {
122             push @{$line[$i]}, @{$character->[$i]};
123             }
124             $width -= scalar @{$character->[0]};
125              
126             my $next = $characters[$i + 1];
127             if ($next && $width < scalar @{$character_map{$next}->[0]}) {
128             $self->print_line(\@line, $stringify);
129             ($width, @line) = $self->new_line();
130             }
131             }
132             if ($words[0]) {
133             @characters = split //, $words[0];
134             my $space = $class->space;
135             my $required_width = scalar @{$space->[0]};
136             $required_width += @{$character_map{$_}->[0]} for @characters;
137             if ($width > $required_width) {
138             for (my $i = 0; $i < scalar @{$space}; $i++) {
139             push @{$line[$i]}, @{$space->[$i]}, " ";
140             }
141             $width = $width - scalar @{$space->[0]};
142             next;
143             }
144             }
145             $self->print_line(\@line, $stringify);
146             ($width, @line) = $self->new_line();
147             }
148             if ($self->color && $self->color_map->{$self->color}) {
149             if ($stringify) {
150             push @{$stringify}, "\e[0m";
151             } else {
152             my $fh = $self->fh;
153             print $fh "\e[0m";
154             }
155             }
156             };
157              
158             function new_line => sub {
159             return ($_[0]->max_width, [],[],[],[],[],[]);
160             };
161              
162             function print_line => sub {
163             my ($self, $line, $stringify) = @_;
164             my $line_width = @{$line->[0]};
165             my $pad = $self->align eq 'center'
166             ? ($self->max_width - $line_width) / 2
167             : $self->align eq 'right'
168             ? $self->max_width - $line_width
169             : $self->pad;
170             $pad = $pad && $pad > 0 ? " " x $pad : "";
171             my $fh = $self->fh;
172             for (@{$line}) {
173             next unless scalar @{$_};
174             if ($self->color && $self->color_map->{$self->color}) {
175             if ($stringify) {
176             push @{$stringify}, $self->color_map->{$self->color};
177             } else {
178             print $fh $self->color_map->{$self->color};
179             }
180             }
181             my $l = $pad;
182             $l .= join "", @{$_};
183             $l .= "\n";
184             if ($stringify) {
185             push @{$stringify}, $l;
186             } else {
187             print $fh $l;
188             }
189             }
190             };
191              
192             1;
193              
194             __END__