Acme-TextLayout
view release on metacpan or search on metacpan
lib/Acme/TextLayout.pm view on Meta::CPAN
=cut
sub new {
my $class = shift;
my %opts = @_;
my $self = \%opts;
bless $self, $class;
$.Class = $class;
return $self;
}
=head2 B<instantiate>
$tl->instantiate(text => ??);
-or-
$tl->instantiate(file => ??);
Specify the textual layout pattern we are interested in, either
from a text string or a file.
Returns undef if something wrong with your input.
=cut
sub instantiate {
my ($self, %opts) = @_;
my $file = $opts{file};
my $text = $opts{text};
# reset state on new instantiation
$.textRef = [];
$.Ranges = {};
$.widest = undef;
$.chars = {};
$.Above = $.Below = $.Left = $.Right = undef;
if (defined $file) {
my $fh = FileHandle->new($file);
return unless defined $fh;
my @text = <$fh>;
$fh->close;
chomp foreach @text;
s/^\s+// foreach @text;
$text = [ @text ];
./_widest(\@text);
}
elsif (defined $text) {
my @text = split(/\n{1}/, $text);
s/^\s+// foreach @text;
$text = [ @text ];
./_widest(\@text);
}
else {
return undef;
}
./_whats_in_there($text);
./_widest($text);
$.textRef = $text;
map {
return undef unless length($_) == $.widest;
} @{$.textRef};
my %Ranges;
my %chars = %.chars;
map {
my $C = $_;
my @d = ./range($C);
$Ranges{$C} = \@d;
} keys(%chars);
$.Ranges = \%Ranges;
print STDERR "Pattern appears disjoint\n" if ./_disjoint();
return undef if ./_disjoint();
# signify OK if we got here
return 1;
}
# not a complete test, but tests for the obvious
sub _disjoint {
my ($self) = @_;
my @text = @{$.textRef};
my @chars = ./characters();
my $ok = 1;
map {
my $line = $_;
map {
my $n = 0;
my $t = $line;
$n++ while $t =~ s/$_{1,}//;
$ok = 0 if $n > 1;
} @chars;
} @text;
my $width = ./width();
for (my $i=0; $i < $width; $i++) {
my @new;
push(@new, substr($_, $i, 1)) foreach @text;
my $line = join('', @new);
map {
my $n = 0;
my $t = $line;
$n++ while $t =~ s/$_{1,}//;
$ok = 0 if $n > 1;
} @chars;
}
return $ok ? 0 : 1;
}
sub _widest {
my ($self, $textRef) = @_;
my @text = @$textRef;
my $widest = length($text[0]);
map {
my $len = length($_);
$widest = $len if $len > $widest;
} @text;
$.widest = $widest;
}
sub _height {
my ($self, $textRef) = @_;
my @text = @$textRef;
return scalar(@text);
}
# figure out all characters in our pattern
sub _whats_in_there {
my ($self, $aref) = @_;
my @text = @$aref;
#print "@text", "\n";
my %chars;
map {
my $c = $_;
my $C = chr($c);
map {
my $n;
$chars{$C} = 1 if $_ =~ /\Q$C\E/;
die "$.Class - space unacceptable in pattern\n"
if $C eq " " && defined $chars{$C} && $chars{$C} == 1;
} @text;
} 1 .. 255;
# preserve our character set
$.chars = \%chars;
}
sub _right {
my ($self, $text, $char) = @_;
my @text = split(//, $text);
my $first;
my $last;
if ($text =~ /$char/) {
$first = pos($text);
$last = rindex $text, $char;
}
return ($first, $last);
}
# determine vertical range of a specific character in our pattern
sub _vrange {
my ($self, $textRef, $char) = @_;
my $top;
my $bottom;
my $n = 0;
map {
$top = $n if $_ =~ /$char/ && !defined $top;
$bottom = $n if $_ =~ /$char/;
$n++;
} @$textRef;
return ($top, $bottom);
}
sub _first {
my ($self, $textRef, $char) = @_;
( run in 1.005 second using v1.01-cache-2.11-cpan-140bd7fdf52 )