Config-IOD
view release on metacpan or search on metacpan
lib/Config/IOD/Document.pm view on Meta::CPAN
}
sub dump {
my $self = shift;
my $opts;
if (ref($_[0]) eq 'HASH') {
$opts = shift;
} else {
$opts = {};
}
my $parser = $self->{_parser};
my $linum = 0;
my $merge;
my $cur_section = $parser->{default_section};
my $res = {};
my $arrayified = {};
my $num_seen_section_lines = 0;
my $_merge = sub {
return if $cur_section eq $merge;
die "IOD document:$linum: Can't merge section '$merge' to ".
"'$cur_section': Section '$merge' not seen yet"
unless exists $res->{$merge};
for my $k (keys %{ $res->{$merge} }) {
$res->{$cur_section}{$k} //= $res->{$merge}{$k};
}
};
# TMP HACK. for _decode_expr, this is currently rather hackish because
# Config::IOD::Base expects some state in $parser
local $parser->{_res} = $res if $parser->{enable_expr};
local $parser->{_cur_section} = $cur_section if $parser->{enable_expr};
for my $line (@{ $self->{_parsed} }) {
$linum++;
next if defined($opts->{linum_start}) && $linum < $opts->{linum_start};
next if defined($opts->{linum_end} ) && $linum > $opts->{linum_end};
my $type = $line->[COL_TYPE];
if ($type eq 'D') {
my $directive = $line->[COL_D_DIRECTIVE];
if ($directive eq 'merge') {
my $args = $parser->_parse_command_line(
$line->[COL_D_ARGS_RAW]);
if (!defined($args)) {
die "IOD document:$linum: Invalid arguments syntax '".
$line->[COL_D_ARGS_RAW]."'";
}
$merge = @$args ? $args->[0] : undef;
} # ignore the other directives
} elsif ($type eq 'S') {
$num_seen_section_lines++;
# merge previous section
$_merge->() if defined($merge) && $num_seen_section_lines > 1;
$cur_section = $line->[COL_S_SECTION];
$parser->{_cur_section} = $cur_section if $parser->{enable_expr}; #TMP HACK
$res->{$cur_section} //= {};
} elsif ($type eq 'K') {
# the common case is that value are not decoded or
# quoted/bracketed/braced, so we avoid calling _parse_raw_value here
# to avoid overhead
my $key = $line->[COL_K_KEY];
my $val = $line->[COL_K_VALUE_RAW];
if ($val =~ /\A["!\\[\{]/) {
my ($err, $parse_res, $decoded_val) =
$parser->_parse_raw_value($val);
die "IOD document:$linum: Invalid value: $err" if $err;
$val = $decoded_val;
} else {
$val =~ s/\s*[#;].*//; # strip comment
}
if (exists $res->{$cur_section}{$key}) {
if (!$parser->{allow_duplicate_key}) {
die "IOD document:$linum: Duplicate key: $key ".
"(section $cur_section)";
} elsif ($arrayified->{$cur_section}{$key}++) {
push @{ $res->{$cur_section}{$key} }, $val;
} else {
$res->{$cur_section}{$key} = [
$res->{$cur_section}{$key}, $val];
}
} else {
$res->{$cur_section}{$key} = $val;
}
} # ignore the other line types
}
$_merge->() if defined($merge) && $num_seen_section_lines > 1;;
$res;
}
sub each_key {
my $self = shift;
my $opts;
if (ref($_[0]) eq 'HASH') {
$opts = shift;
} else {
$opts = {};
}
my ($code) = @_;
my $parser = $self->{_parser};
my $linum = 0;
my $cur_section = $parser->{default_section};
my $skip_section;
my %seen_sections;
my %seen_keys;
for my $line (@{ $self->{_parsed} }) {
$linum++;
next if defined($opts->{linum_start}) && $linum < $opts->{linum_start};
next if defined($opts->{linum_end} ) && $linum > $opts->{linum_end};
my $type = $line->[COL_TYPE];
if ($type eq 'S') {
$cur_section = $line->[COL_S_SECTION];
%seen_keys = ();
$skip_section = $opts->{unique_section} &&
$seen_sections{$cur_section}++;
} elsif ($type eq 'K') {
next if $skip_section;
my $key = $line->[COL_K_KEY];
next if $opts->{unique_key} && $seen_keys{$key}++;
my $res = $code->(
$self,
lib/Config/IOD/Document.pm view on Meta::CPAN
# insert at the top of section, instead of at the bottom
$doc->insert_key({top=>1}, 'section', 'key', 'value');
# insert at specific location (line number)
$doc->insert_key({linum=>12}, 'section', 'name', 'value');
Delete a section (and all keys under it):
$doc->delete_section('name');
# delete all occurrences instead of just the first one
$doc->delete_section({all=>1}, 'name');
Delete a key:
$doc->delete_key('section', 'key');
# delete all occurrences instead of just the first one
$doc->delete_key({all=>1}, 'section', 'key');
Empty document:
$doc->empty;
Dump object as IOD document string:
print $doc->as_string;
# or just:
print $doc;
=head1 ATTRIBUTES
=head1 METHODS
=head2 new(%attrs) => obj
=head2 $doc->as_string => str
Return document object rendered as string. Automatically used for
stringification.
=head2 $doc->delete_key([\%opts, ]$section, $name) => $num_deleted
Delete key named C<$name> in section named C<$section>.
Options:
=over
=item * all => bool
If set to 1, then will delete all occurrences. By default only delete the first
occurrence.
=item * cond => code
Will only delete key if C<cond> returns true. C<cond> will be called with C<<
($self, %args) >> where the hash will contain these keys: C<linum> (int, line
number), C<parsed> (array, parsed line), C<key> (string, key name), C<value>
(NOT YET IMPLEMENTED), C<raw_value> (str, raw/undecoded value).
=back
=head2 $doc->delete_section([\%opts, ]$section) => $num_deleted
Delete section named C<$section>.
Options:
=over
=item * all => bool
If set to 1, then will delete all occurrences. By default only delete the first
occurrence.
=item * cond => code
Will only delete section if C<cond> returns true. C<cond> will be called with
C<< ($self, %args) >> where the hash will contain these keys: C<linum_start>
(int, starting line number), C<linum_end> (int, ending line number).
=back
=head2 $doc->dump([ \%opts ]) => hoh
Return a hoh (hash of section names and hashes, where each of the second-level
hash is of keys and values), Values will be decoded and merging will be done,
but includes are not processed (even though C<include> directive is active).
Options:
=over
=item * linum_start => int
Only dump beginning from this line number.
=item * linum_end => int
Only dump until this line number.
=back
=head2 $doc->each_key([ \%opts , ] $code) => LIST
Execute C<$code> for each key found in document, in order of occurrence.
C<$code> will be called with arguments C<< ($self, %args) >> where C<%args> will
contain these keys: C<section> (str, current section name), C<key> (str, key
name), C<value> (any, value, NOT YET IMPLEMENTED/AVAILABLE), C<raw_value> (str,
raw/undecoded value), C<linum> (int, line number, 1-based), C<parsed> (array,
parsed line).
Options:
=over
=item * linum_start => int
Only dump beginning from this line number.
=item * linum_end => int
Only dump until this line number.
=item * unique_section => bool
If set to 1, will only list the first occurence of each section.
=item * unique_key => bool
If set to 1, will only list the first occurence of each key in the same section.
=item * early_exit => bool
If set to 1, then if coderef returns false will return early immediately and not
continue to the next key.
=back
=head2 $doc->each_section([ \%opts , ] $code) => LIST
Execute C<$code> for each section found in document, in order of occurrence.
C<$code> will be called with arguments C<< ($self, %args) >> where C<%args> will
contain these keys: C<section> (str, section name), C<linum> (int, line number,
1-based), C<linum_start> (the same as C<linum>), C<linum_end> (int, line number
of the last line of the section), C<parsed> (array, parsed line).
Options:
=over
=item * unique => bool
If set to 1, will only list the first occurence of each section.
=item * early_exit => bool
If set to 1, then if coderef returns false will return early immediately and not
continue to the next section.
=back
=head2 $doc->empty()
Empty document.
=head2 $doc->get_directive_before_key($section, $key) => array
Find directive right before a key. Directive must directly precede key line
without any blank line, e.g.:
;!lint_prereqs assume-used "undetected, used via Riap"
App::MyApp=0
If found, will return an arrayref containing directive name and arguments.
Otherwise, will return undef.
=head2 $doc->get_value($section, $key) => $value
Get value. Values are decoded and section merging is respected, but includes are
not processed.
Internally, will do a C<dump()> and cache the result so subsequent
C<get_value()> will avoid re-parsing the whole document. (The cache will
automatically be discarded is one of document-modifying methods like
C<delete_section()> is called.)
=head2 $doc->insert_key([\%opts, ]$section, $key, $value) => int
Insert a key named C<$name> with value C<$value> under C<$section>. Return line
number where the key is inserted, or undef if nothing is inserted (e.g. when
C<ignore> option is set to true). Die on failure.
Options:
=over
=item * create_section => bool
If set to 1, will create section (at the end of document) if it doesn't exist.
=item * add => bool
If set to 1, will add another key if key with the same name already exists.
Conflicts with C<ignore> and <replace>.
=item * ignore => bool
If set to 1, will do nothing if key already exists. Conflicts with C<add> and
C<replace>.
=item * replace => bool
If set to 1, will delete (all) previous keys first. Conflicts with C<add> and
C<ignore>.
=item * top => bool
If set to 1, will insert at the top of section before other keys. By default
will add at the end of section.
=item * linum => posint
Optional. Insert at this specific line number. Line number must fall within
section. Ignores C<top>.
=back
=head2 $doc->insert_section([\%opts, ]$name) => int
Insert empty section named C<$name>. Return line number where the section is
inserted, or undef if nothing is inserted (e.g. when C<ignore> option is set to
true). Die on failure.
Options:
=over
=item * ignore => bool
( run in 1.729 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )