boblawblah has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks! I want to be able to read content from the __DATA__ block in a file from within a BEGIN { } block or a packages 'import' function. Is this something that is possible?

I do a lot of testing against databases, and recently I wrote a module that allows my to easily install and remove database tables from within my test code. Take this for example:
use Test::More 'no_plan'; use Gi::Testing::TestDB; my $testdb = Gi::Testing::TestDB->new( [qw/DBI:mysql:database:address:3306 tester password/], *main::DATA ); $testdb->install; # perform tests $dbh = $testdb->dbh; END { $testdb->uninstall; } __DATA__ CREATE TABLE TestObject ( identifier INT(10) NOT NULL PRIMARY KEY, name VARCHAR(50), attribute VARCHAR(50) );
That does what I want and all, but not as elegantly as I would like. I just want to stick
use Gi::Testing::TestDB DataSource => [qw/DBI:mysql:database:address:3306 tester password/ +], Schema => *main::DATA;
at the top of my file and be done with it. Later in the tests, when I want to access my dbh, I just say
my $dbh = Gi::Testing::TestDB->dbh;
So I made Gi::Testing::TestDB a singleton. I have provided my own import method, so that when the user calls use Gi::Testing::TestDB with parameters - the singleton is constructed and the schema is executed against the database connection. When the singleton is destroyed, it will delete all the tables it created. The problem I am running into with this approach is that the content in *main::DATA is not an open file-handle from within the import method or if you call it from within a BEGIN block. Here is the error message:
tell() on unopened filehandle DATA at C:/camelbox/site/lib/Gi/Installe +r/Database /Schema.pm line 125. readline() on unopened filehandle DATA at C:/camelbox/site/lib/Gi/Inst +aller/Data base/Schema.pm line 126. seek() on unopened filehandle DATA at C:/camelbox/site/lib/Gi/Installe +r/Database /Schema.pm line 127. could not read any data from file handle - the file is empty or you ar +e at the e nd of the file at C:/camelbox/site/lib/Gi/Installer/Database.pm line +20
Does anybody have any suggestions on how to get around this? I really want the schema information in the __DATA__ section of the test script, so all the test information is contained within one file - as opposed to a test script file and schema information file.

One option I have thought about is requiring that Gi::Testing::TestDBI->install be called from within the script - and not parsing the file handle until install was called - which would happen at execution time when the <DATA> file handle is valid. But I really want to keep it to just the singular 'use' statement. Thanks for the help!

Replies are listed 'Best First'.
Re: Reading from <DATA> in import/BEGIN block
by ikegami (Patriarch) on Sep 22, 2009 at 16:28 UTC

    I want to be able to read content from the __DATA__ block in a file from within a BEGIN { } block [...]. Is this something that is possible?

    No. BEGIN blocks are executed as soon as they are parsed, so the parser hasn't reached the __DATA__ token yet.

    Here-docs might be a suitable replacement.

    my $var = <<'__EOI__'; ... ... __EOI__

    I want to be able to read content from the __DATA__ block in a file from within [...] a packages 'import' function. Is this something that is possible?

    No problem at all. The module's has been fully compiled (and executed) before anything can call its import, so it has no problem reading from its DATA handle.


    Keep in mind that

    use Gi::Testing::TestDB DataSource => [qw/DBI:mysql:database:address:3306 tester password/ +], Schema => *main::DATA;

    is basically the same as

    BEGIN { require Gi::Testing::TestDB; import Gi::Testing::TestDB DataSource => [qw/DBI:mysql:database:address:3306 tester passw +ord/], Schema => *main::DATA; }

    And thus the first answer applies.

    Update: Added content after horizontal line.

Re: Reading from <DATA> in import/BEGIN block
by moritz (Cardinal) on Sep 22, 2009 at 16:32 UTC
    use happens at compile time, directly after the use-directive is parsed. At that time the parser hasn't even seen the __DATA__.

    So you have to open the file file from which your import routine is called (caller should give you that information, I think), and parse it yourself, looking for a line that matches ^__DATA__$.

    Or you simply retract from the idea of wanting to use DATA at BEGIN-time.

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Reading from <DATA> in import/BEGIN block
by ccn (Vicar) on Sep 22, 2009 at 17:04 UTC
    You can use INIT { } block for your purposes

    see perldoc perlmod about INIT construct

    Update sorry, I missed something.