Data-Rebuilder

 view release on metacpan or  search on metacpan

lib/Data/Rebuilder.pm  view on Meta::CPAN

                    );
               }
               else {
                 push( @vars,
                       sprintf ( "  my \%s = undef;\n".
                                 '  Lexical::Alias::alias_r( %s , \%s );',
                                 $key,
                                 $self->freeze($val),
                                 $key ) );
               }

             }

             my %info = $dp->coderef2textX($cv);

             foreach my $stash ( $b->STASH->NAME , @{$info{stashes}} ){
               $self->_stashes->{$stash} = 1;
             }

             join( "\n",
                   "do{",
                   '  # CodeRef',
                   (map{ sprintf('  %s = %s;',$_,$_) }@{$info{globals}}),
                   ( @vars ? '  require Lexical::Alias;' : () ),
                   @vars,
                   sprintf('  sub %s', _indent $info{code}),
                   "}",
                 );
           },

           #################################
           'ArrayRef' => sub{

             my $ref    = shift;
             my $target = shift || $ref;
             my $var    = $self->ref_to_var($target);

             my @body = ();
             my @tied = ();
             my @weak = ();
             local $_;

             for( my $i = 0; $i < @{$ref} ; $i++ ) {
               my $v = $ref->[$i];
               my $tied = tied ( $ref->[$i] );
               push @body, sprintf('    # %s', refaddr( \$ref->[$i] ));
               if( $tied ){

                 push @body, "    undef,";
                 push @tied , [$i => $tied];

               }
               elsif( $self->_is_cycled($v) ) {

                 push @body, "    undef,";
                 my $lazy = $self->_lazy->{ refaddr $v } ||= [];
                 push( @$lazy ,
                       sprintf('%s->[%s] = %s;',
                               $var, $i, $self->freeze($v)));
                 push( @$lazy ,
                       sprintf('Scalar::Util::weaken(%s->[%s]);',
                               $var, $i))
                   if isweak($ref->[$i]);

               }
               elsif( $self->poly->type($v) eq 'RefRef'  and
                      $self->_is_cycled($$v)){
                 push @body, "    undef, #cycled RefRef ";
                 my $lazy = $self->_lazy->{refaddr $$v} ||= [];
                 push @{$lazy}, sprintf('%s->[%s] = %s;',
                                        $var,
                                        $i,
                                        $self->poly->apply( $v => 'freeze'));
                 push( @$lazy ,
                       sprintf('Scalar::Util::weaken(%s->[%s]);',
                               $var, $i))
                   if isweak($ref->[$i]);
               }
               else {

                 push @body , "    ". $self->freeze($v).",";
                 push @weak , $i , if isweak( $ref->[$i] );

               }
             }

             join
               (
                "\n" ,
                "do{ ",
                '  # ArrayRef',
                "  my \$__tmp = [",
                @body ,
                "  ];",
                "  "._indent( join "\n",
                              map{ $self->tier('$__tmp->['.$_->[0].']',
                                               'TIESCALAR',
                                               $_->[1]) } @tied ),
                "  "._indent( join "\n",
                              map{ sprintf(' Scalar::Util::weaken('.
                                           '  $__tmp->[%s] );' ,
                                           $_) } @weak ),
                '  $__tmp;',
                "}"
               );
           },

           #################################
           'HashRef' => sub{
             my $ref    = shift;
             my $target = shift || $ref;
             my $var    = $self->ref_to_var($target);
             my @body = ();
             my @tied = ();
             my @weak = ();

             foreach my $key ( sort keys %{$ref} ){
               my $v = $ref->{$key};
               my $tied = tied ( $ref->{$key} );
               if( $tied ){
                 push @body ,
                   sprintf('      %s => undef,',  $self->freeze($key)),
                 push @tied , [$key => $tied];
               }
               elsif( $self->_is_cycled($v) ) {

                 push @body ,
                   sprintf('      %s => undef, # cycled', $self->freeze($key));

                 my $lazy = $self->_lazy->{ refaddr $v } ||= [];

                 push( @$lazy , sprintf('%s->{%s} = %s;',
                                         $var,
                                         $self->freeze($key),
                                         $self->freeze($v)));

                 push( @$lazy ,
                       sprintf('Scalar::Util::weaken(%s->{%s});',
                               $var,
                               $self->freeze($key)
                              )) if isweak($ref->{$key});

               }
               elsif( $self->poly->type($v) eq 'RefRef'  and
                      $self->_is_cycled($$v)){

                 push @body, sprintf('      %s => undef, # cycled RefRef',
                                    $self->freeze($key));

                 my $lazy = $self->_lazy->{refaddr $$v} ||= [];

                 push @{$lazy}, sprintf('%s->{%s} = %s;',
                                        $var,
                                        $self->freeze($key),
                                        $self->freeze($v));

                 push( @$lazy ,
                       sprintf('Scalar::Util::weaken(%s->{%s});',
                               $var,
                               $self->freeze($key),
                              )) if isweak($ref->{$key});

               }
               else {
                 push @body ,
                   sprintf('      %s => %s,',
                           $self->freeze($key), $self->freeze($v));
                 push @weak , $key, if isweak( $ref->{$key} );
               }
             }

             join
               (
                "\n" ,
                "do{ ",
                '  # HashRef',
                "  my \$__tmp = {",
                @body ,
                "  };",
                ( map{ $self->tier('$__tmp->{'.$self->freeze($_->[0]).'}',
                                   'TIESCALAR',
                                   $_->[1]) } @tied ),
                ( map{ sprintf(' Scalar::Util::weaken( \ $__tmp->{%s} );' ,
                               $self->freeze($_)) }
                  @weak ),
                '  $__tmp;',
                "}"
               );
           },

           #################################
           'GlobRef' => sub{
             my $glob   = shift;
             my $target = shift;
             my $var    = $self->ref_to_var($target);
             my $name = "".$$glob;

             return '\\ '.$name
               if( $name =~ /\*main::(STD(?:IN|OUT|ERR)|ARGV)/ &&
                   refaddr( $glob ) == refaddr( \$main::{$1} ) );

             my @slots = ();
             foreach my $slot ( qw(SCALAR HASH ARRAY CODE)) {

               next unless my $ref = *{$glob}{$slot};

               if( $self->poly->type($slot) eq 'RefRef' &&
                   $self->_is_cycled($$slot) ) {
                 my $lazy = ($self->_lazy->{refaddr $$slot} ||= []);
                 push @$lazy,
                   sprintf('  *{%s} = %s;',
                           $var,
                           $self->freeze(*{$glob}{$slot}) );
               }
               else {
                 push @slots,
                   sprintf('  *{$__tmp} = %s;',
                           $self->freeze(*{$glob}{$slot}) );
               }

             }
             join ("\n",
                   'do {',
                   '  require Symbol;',
                   sprintf('  my $__tmp = Symbol::gensym();', $name),
                   @slots,
                   '  $__tmp;',
                   '}',
                  );
           },

           ###
           'RefRef' => sub{
             my $ref    = shift;
             my $target = shift || $ref;
             "\\ ". $self->freeze( ${$ref} , ${$target} );
           },

           ###
           UNIVERSAL => sub {
             my $obj    = shift;
             my $target = shift || $obj;
             $self->_stashes->{blessed $obj} = 1;



( run in 1.870 second using v1.01-cache-2.11-cpan-39bf76dae61 )