I think this is more along the lines of what i should have (but i
still don't have it working):



On Sun, Nov 10, 2013 at 6:10 PM, shawn wilson <ag4ve...@gmail.com> wrote:
> I'm having a bit of trouble writing a trace array for a structure
> traversal function.
>
> Before someone points out Data::Walker and the like, here is my
> limitation: this is for a script to generate iptables / ipset save
> files - it needs to run on machines with perl 5.10+ without needing
> anything else (including MakeMaker - nothing - just runs out of the
> box). So, if a module isn't in core, I can't really use it.
>
> Nevermind the function name 'flatten' - I just want to get $path to
> work correctly.
>
> Thanks
>
>
> #!/usr/bin/env perl
>
> use strict;
> use warnings;
>
> use Data::Dumper;
>
> my $deep = {
>   'foo' => [qw/
>       ugh
>       umm
>       arr
>   /],
>   'bar' => [qw/
>     aaa
>     bbb
>     ccc
>   /],
>   'baz' => [
>     'fi' => [qw/
>       one
>       two
>       three
>     /],
>       'fo' => [qw/
>         four
>         five
>         six
>       /],
>       'fum' => [qw/
>         seven
>         eight
>         nine
>       /],
>   ],
> };
>
> my ($new) = into_me($deep, undef, 'flatten_els');
>
> print Dumper($new);
>
> sub flatten_els
> {
>   my ($var, @etc) = @_;
>   my ($path, $type) = @etc;
>
>   print "path [" . join('] [', @$path) . "]\n";
>
>   return $var, @etc unless ($type =~ /^H /);
>
>   $var = join(' ', values %$var);
>
>   return $var, @etc;
> }
>
>
>
> # Traverse a variable with callbacks
> sub into_me
> {
>   my ($vals, $kfunc, $vfunc, @etc) = @_;
>   no strict 'refs';
>
>   # This should be private - you probably shouldn't call into_me with a path
>   my $path;
>   if (scalar(@etc) >= 1 and ref($etc[-1]) eq 'ARRAY' and $etc[-1]->[0]
> eq 'BASE')
>   {
>     $path = pop @etc;
>   }
>   else
>   {
>     push @$path, 'BASE';
>   }
>
>   my $rtype = (ref(\$vals) eq 'SCALAR' ? 'SCALAR' : ref($vals));
>
>   my $ret;
>
>   if ($rtype eq 'ARRAY')
>   {
    push @$path, 'A ';
    for my $num (0 .. $#$vals)
    {
      next unless (defined($vals->[$num]));
      my $val = $vals->[$num];
      my ($anum, $aval);
      ($anum, @etc) = $kfunc->($num, @etc, 'EL') if (defined($kfunc));
      $anum //= $num;
      $path->[-1] =~ s/^A .*/A $anum/;
      push @etc, $path;
      ($aval, @etc) = $vfunc->($val, @etc, 'VAL') if (defined($vfunc));
      $aval //= $val;
      ($ret->[$anum], @etc) = into_me($aval, $kfunc, $vfunc, @etc);
>     }
>   }
>   elsif ($rtype eq 'HASH')
>   {
    push @$path, 'H ';
    foreach my $key (keys %$vals)
    {
      next unless (defined($vals->{$key}));
      my $val = $vals->{$key};
      my ($akey, $aval);
      ($akey, @etc) = $kfunc->($key, @etc, 'KEY') if (defined($kfunc));
      $akey //= $key;
      $path->[-1] =~ s/^H .*/H $akey/;
      push @etc, $path;
      ($aval, @etc) = $vfunc->($val, @etc, 'VAL') if (defined($vfunc));
      $aval //= $val;
      ($ret->{$akey}, @etc) = into_me($aval, $kfunc, $vfunc, @etc);
>     }
>   }
>   elsif ($rtype eq 'SCALAR')
>   {
>     push @$path, "S $vals";
>     push @etc, $path;
>     ($ret, @etc) = $vfunc->($vals, @etc);
>     pop @$path;
>   }
>   else
>   {
>     $ret = $vals;
>   }
>
pop @$path;
>   push @etc, $path;
>
>   use strict 'refs';
>   return $ret, @etc;
> }

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to