Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: Double quoted string as method call

by jarich (Curate)
on May 05, 2004 at 01:51 UTC ( [id://350655]=note: print w/replies, xml ) Need Help??


in reply to Double quoted string as method call

The only way I have found to make this work -- after several SuperSearches and trying perl5.6 and perl5.8 -- is to create a new simple scalar variable and use this as the method call, as such:
$$database_handle = DBI->connect( map { my $s = "database_$_"; exists $arguments{$_} ? $arguments{$_} : $s->() } qw(data_source_name username password taint) ) or die "Could not connect to the ". "database: $DBI::errstr";
The above code compiles fine. It is a bit kludgy though. Is there any way to accomplish a method call that mixes an interpolated variable and some known text, sort of like a double quoted string?

As far as I can work out there isn't such a way. :( In fact, to do what you're doing up there in the map you have to have strict refs turned off. You've probably turned them off for this whole section because otherwise you could well be having trouble with $$database_handle.

I can offer you two alternatives to this problem, however. Both strict compliant. If your database_* subroutines merely return a string value, ie:

sub database_username { return "fred"; }
then hash defaults might be the way to go:
my %defaults = ( data_source_name => ".....", username => "fred", password => "fred", taint => { Taint => 1 } ); # then later... %arguments = (%defaults, %arguments); my $dbh = DBI->connect( @arguments{ qw(data_source_name username password taint) }) or die "Could not connect to the database: ". "$DBI::errstr";
When assigning to hashes, later keys of the same name overwrite the values from the earlier keys. This means that if "data_source_name" is provided in %arguments the %arguments version is kept. Obviously keys which are not included in %arguments remain those of the default hash.

The @arguments{ qw/.../ } structure is a hash slice. This ensures we get the values out in the order we want them to appear.

This ideas works if your database_* subroutines are ONLY returning simple stuff. If you want your database_* subroutines to read these values from a file or something similar and to do so only if needed then you might want to do something like the following:

my %defaults = ( data_source_name => \&database_data_source_name, username => \&database_username, password => \&database_password, taint => \&database_taint, ); # and later: my $dbh = DBI->connect ( map { exists $arguments{$_} ? $arguments{$_} : $defaults{$_}() } qw(data_source_name username password taint) ) or die "Could not connect to the database: ". "$DBI::errstr"; # and somewhere else: sub database_data_source_name { # read stuff from file.. # do other stuff return #something }
This has the added advantage of looking a whole lot nicer than using a string as a coderef. What we're doing here is creating a hash of references to our subroutines. It's not until we do $defaults{$_}() that these subroutines actually get executed.

I hope this helps,

jarich

Update: Heh. I post my node and already stand corrected. Well done Anonymous Monk. If you do wish to make your code strict compliant, however, you may find my suggestions useful.

map { exists $arguments{$_} ? $arguments{$_} : ${\"database_$_"}->() }

Replies are listed 'Best First'.
Re: Re: Double quoted string as method call
by ryantate (Friar) on May 05, 2004 at 18:10 UTC

    Apologies, but it appears you have posted my code incorrectly in the very first part of your post. Particularly, at the alleged $s->(). I am not sure how key this is to your assertion my code is not strict-compliant .

    I have re-read what I posted and cannot find where I ever call $s as the object or class. I call $s as a method to $caller, ie $caller->$s.

    In any case, I have a close relative of the code I posted running fine under strict:

    $$database_handle = DBI->connect(( map { my $s="database_$_"; exists $arguments{$_} ? $arguments{$_} : $caller->$s() } (qw(data_source_name username password)) ), {Taint=>$arguments{taint}||$caller->database_ta +int} ) or die "Could not connect to the database: $DBI:: +errstr" unless defined $$database_handle;

    Please note $$database_handle is not meant to be a symbolic reference. You would need to see the whole module. $database_handle is a reference to a reference (to a handle), which I create earlier in the method because the particular reference (handle) used depends on whether the method is called on a class or an object.

    Thanks for the rest of your post -- I will read it over. But, again, no problems with stricture!

      My apologies, you're completely right.

      I dropped the $caller bit for my testing and then promptly forgot that I had done so and therefore incorrectly concluded that since what I had wasn't strict compliant, what you had couldn't be either.

      I considered that $$database_handle could be either a symbolic reference or a scalar reference and that is why I wrote that it too could cause you problems under strict, rather than it does.

      I should have checked my assumptions.

      All the best,

      jarich

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://350655]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (5)
As of 2024-03-28 20:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found