Tree-From-Text/lib/Tree/From/TextLines.pm
package Tree::From::TextLines;
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2021-05-06'; # DATE
our $DIST = 'Tree-From-Text'; # DIST
our $VERSION = '0.021'; # VERSION
use 5.010001;
use strict;
use warnings;
use Exporter qw(import);
our @EXPORT_OK = qw(build_tree_from_text_lines);
sub build_tree_from_text_lines {
require Text::Tabs;
require Tree::FromStruct;
my $opts;
if (ref($_[0]) eq 'HASH') {
$opts = shift;
} else {
$opts = {};
}
my $text = Text::Tabs::expand(shift);
my @structs;
my @indents;
my $linum = 0;
for my $line (split /^/m, $text) {
$linum++;
chomp($line);
# ignore blank lines
next unless $line =~ /\S/;
my $indent = length($line =~ s/^(\s+)// ? $1 : "");
# parse line
my %attrs = $line =~ /(\w+):(\S*)/g;
my $struct = \%attrs;
my $i;
for my $j (0..$#indents) {
if ($indent <= $indents[$j]) {
$i = $j; last;
}
}
if (!defined($i)) {
#say "D: line $linum is more indented than previous line so it's a child";
push @structs, $struct;
push @indents, $indent;
if (@structs > 1) {
$structs[-2]{_children} //= [];
push @{ $structs[-2]{_children} }, $struct;
}
} else {
#say "D: line $linum is at level $i";
if ($i == 0) {
die "Line $linum: Multiple roots not allowed: $line";
}
splice @structs, $i;
splice @indents, $i;
$structs[-1]{_children} //= [];
push @{ $structs[-1]{_children} }, $struct;
push @structs, $struct;
push @indents, $indent;
}
}
die "Please specify one or more lines of text" unless @structs;
Tree::FromStruct::build_tree_from_struct($structs[0]);
}
# TODO: option to parse each line as CSV line, LTSV line, JSON, or Perl hash for
# greater flexibility.
1;
# ABSTRACT: Build a tree object from lines of text, each line indented to express structure
__END__
=pod
=encoding UTF-8
=head1 NAME
Tree::From::TextLines - Build a tree object from lines of text, each line indented to express structure
=head1 VERSION
This document describes version 0.021 of Tree::From::TextLines (from Perl distribution Tree-From-Text), released on 2021-05-06.
=head1 SYNOPSIS
use Tree::From::TextLines qw(build_tree_from_text_lines);
use Tree::Object::Hash;
my $tree = build_tree_from_text_lines(<<'_');
id:root _class:Tree::Object::Hash
id:child1 attr1:foo
id:child2 attr1:foo attr2:bar _class:My::Node
id:grandchild1
id:child3
_
=head1 DESCRIPTION
=head1 FUNCTIONS
=head2 build_tree_from_text_lines([ \%opts, ] $text) => obj
This function can be used to build a tree object from text lines. Each line
represents a node and its indentation expresses structure: line that is more
indented than its previous line signifies that the node is child of the previous
node.
This is more convenient than L<Tree::From::Struct>, but actually internally the
the text will be converted to structure to feed to Tree::From::Struct to get the
final tree object.
Each line of text by default must be in form of name-value pairs separated by
whitespaces (it will be parsed simply using Perl code C<< %attrs =
/(\w+):(\S*)/g >>), e.g.:
id:root attr1:foo attr2:bar
The names will become object attributes, except special names that begin with
underscore (C<_>), like C<_class>, C<_constructor>, etc. They mean the same as
in L<Tree::From::Struct>.
To use this function, you must have at least one tree node class. Any class will
do as long as it responds to C<parent> and C<children> (see
L<Role::TinyCommons::Tree::Node> for more details on the requirement). Supply
the class name in C<_class> in the first line.
Available options:
=over
=back
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Tree-From-Text>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Tree-From-Text>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://github.com/perlancar/perl-Tree-From-Text/issues>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Tree::From::Struct>, L<Tree::From::ObjArray>
=head1 AUTHOR
perlancar <perlancar@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2021 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut