开发者

Perl: do and eval result in different answers?

开发者 https://www.devze.com 2023-02-06 03:34 出处:网络
I have a file with the following statements in it: { %{do \'/tmp/personcontact.pl\'}, %{do \'/tmp/address.pl\'}

I have a file with the following statements in it:

    {
        %{do '/tmp/personcontact.pl'},
        %{do '/tmp/address.pl'}
    }

Now, the temp files are as follows: Personcontact.pl :

            {
        'firstname' => {
            '__type' => 'String'
            },
        'lastname' =>  {
            '__type' => 'String'
            }
    }

Address.pl:

     {
        'address' => {
            'street' => {
                '__type' => 'Strin开发者_JAVA百科g'
                },
            'unit' => {
                '__type' => 'String',
            },
            'suburb' => {
                '__type' => 'String'
            },
            '__type' => 'HASH'
        }
    }

Now, when I do :

    open(SCHEMAFILE, "<", $schema) or return undef; 
my $schemafile;     
while(my $line = <SCHEMAFILE>) { $schemafile .= $line;}
my $tempref = eval $schemafile;
print Dumper $tempref;

The result is $VAR1 = '1/8'

And when I do :

    print Dumper do "/tmp/schemawithinschema.pl";

The result is

                    $VAR1 = 'firstname';
        $VAR2 = {
            '__type' => 'String'
            };
        $VAR3 = 'address';
        $VAR4 = {
            'suburb' => {
                    '__type' => 'String'
                },
            'unit' => {
                '__type' => 'String'
                },
            'street' => {
                    '__type' => 'String'
                },
            '__type' => 'ARRAY'
            };
        $VAR5 = 'lastname';
        $VAR6 = {
            '__type' => 'String'
            };

What's wrong here? Thanks!


Alright, to keep this from perpetuating forever, here is a module-based solution for you:

Foo.pm:

package Foo;

use strict;
use warnings;

BEGIN {
    require Exporter;
    our @ISA = qw( Exporter );
    our @EXPORT_OK = qw( get_person get_address get_all );
    our $VERSION = '0.01';
}

my %person = (
    firstname => {
        __type => 'String',
    },
    lastname => {
        __type => 'String',
    },
);

my %address = (
    address => {
        street => {
            __type => 'String',
        },
        unit => {
            __type => 'String',
        },
        suburb => {
            __type => 'String',
        },
        __type => 'HASH',
    },
);

sub get_person
{
    return \%person;
}

sub get_address
{
    return \%address;
}

sub get_all
{
    return( { %person, %address } );
}

1;

__END__

bar.pl:

#!/usr/bin/perl

use Data::Dumper;
use strict;
use warnings;
use lib '.';
use Foo qw( get_person get_address get_all );

my $junk = get_all();

print Dumper $junk;

But really, for the sake of your maintenance programmer (often yourself in 6 months), use JSON or YAML (or the faster YAML::XS), so that the data can be maintained as a simple-ish text file, instead of a series of nested data-disguised-as-code references.

To quote Perl Best Practices (not sure if it was Damian originally):

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.


EDIT: For completeness, here is the equivalent solution using YAML (from CPAN):

data.yml:

---
firstname:
  __type: String
lastname:
  __type: String
address:
  __type: HASH
  street:
    __type: String
  suburb:
    __type: String
  unit:
    __type: String

baz.pl:

#!/usr/bin/perl

use YAML qw( Load Dump LoadFile DumpFile );
use Data::Dumper;
use strict;
use warnings;

my $data = LoadFile( 'data.yml' );
print Dumper $data;


One small pointer. That '1/8' is what you get when you evaluate a hash in a scalar context. The 8 is the number of buckets assigned to the hash and the 1 is the number of buckets that are in use.

It's generally useless, other than as a flag that you're doing something wrong.


While the intent of the question makes me cry, the difference between your two code snippets has nothing to do with do or eval and everything to do with context. And since that is a legitimate Perl topic, I'll briefly answer it.

In

my $tempref = eval $schemafile;

, the eval takes place in scalar context (imposed by the assignment to $tempref). $schemafile, however, contains a hash, created by the hash reference dereference operator %{}. When that hash is evaluated as a scalar it produces 1/8, normal behavior for a hash.

In

print Dumper do "/tmp/schemawithinschema.pl";

, the do takes place in the list context imposed by the Dumper call (which in turn is in the list context of the print). do creates the same hash that the eval did, but now it's being evaluated in list context, in fact as a list of arguments to Dumper. The top-level hash gets flattened into a list of Label => HashRef pairs, but that's not enough to stop Dumper from being able to show you something that looks a lot like the hash you were trying to create.

For future reference, it is helpful when trying to pinpoint a strange difference of behavior to present exactly the same call in both cases. The more variables between two test cases, the more things that you weren't expecting to matter will wind up mattering and confuse you.

All of that said, the real answer to "What's wrong here?" remains "Trying to do this at all.".

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号