1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
use Cache::FileCache; $cache = new Cache::FileCache( ); # this subroutine works just fine sub stockInfoFresh { my $tick = $_[0]; $tick =~ tr/a-z/A-Z/; my $first_let = substr($tick,0,1); my $name = "Ticker not found"; my $exch = ''; my $sth = $dbh->prepare("SELECT * FROM `Stock` WHERE `Ticker` = '$tick'"); $sth->execute; my @stockid = $sth->fetchrow_array; if ($stockid[0]) { $name = $stockid[2]; $exch = $stockid[3]; } $sth->finish; my @out; return($tick, $first_let, $name, $exch, @stockid); } # this subroutine fails sub stockInfo { my $tick = $_[0]; my @stockInfo = $cache->get( "stockInfo" . $tick ); if( not defined @stockInfo ) { @stockInfo = &stockInfoFresh($tick); $cache->set( "stockInfo" . $tick, \@stockInfo, "1 hour" ); } # at this point, $stockInfo[0] is empty return @stockInfo; } # this fails my($tick, $first_let, $name, $exch, @stockid) = &stockInfo($t);
Refactorings
No refactoring yet !
Marco Valtas
October 12, 2007, October 12, 2007 02:34, permalink
Hi, I made some modifications in your code I believe will work, here some mock tests worked. The problem probably was how you tested how get() returned. I made some obs inside the code as well.
Some tips:
Avoid the * inside a SQL, you never know when someone will add a column and make your code fail.
If you know that your SQL will return one and only one row (your code implies this condition) you can avoid the prepare and execute with
selectcol_arrayref(), here is one example from my legacy code:
my($domain_id) = @{$self->{dbh}->selectcol_arrayref("
SELECT domain_id FROM domain_project
WHERE project_id='$project_id'
")};
Hope that helps.
perl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
# always use strict and warnings, this can solve hours of debuging! use strict; use warnings; use Cache::FileCache; # defined somewere else... my $dbh; my $t; my $cache = new Cache::FileCache( ); # $cache->clear(); # clear all cached information.` # this subroutine works just fine sub stockInfoFresh { my ($tick) = @_; # this is a better way to get arguments $tick =~ tr/a-z/A-Z/; # to uppercase my $first_let = substr($tick,0,1); my $name = "Ticker not found"; my $exch = ''; my $sth = $dbh->prepare("SELECT * FROM `Stock` WHERE `Ticker` = '$tick'"); $sth->execute; # this implies that you will work with one and only one row. # if multiple rows this should be inside a while loop. my @stockid = $sth->fetchrow_array; if ($stockid[0]) { $name = $stockid[1]; $exch = $stockid[2]; } $sth->finish; # when returning a array try to avoid return a array as # ($one, $two, @three), this syntax can raise difficult bugs. return($tick, $first_let, $name, $exch, $stockid[0]); } # this subroutine fails sub stockInfo { my ($tick) = @_; # this is a better way to get a argument # get returns a array reference, you should get in a scalar # just to test if FileCache returned something my $stockInfo = $cache->get( "stockInfo" . $tick ); # I will save the result in this array. my @stockInfo; if( not $stockInfo ) { @stockInfo = &stockInfoFresh($tick); $cache->set( "stockInfo" . $tick, \@stockInfo, "1 hour" ); } else { # if FileCache returned something is a reference to an array # so now lets dereference it. @stockInfo = @{$stockInfo}; } # at this point, $stockInfo[0] is empty return @stockInfo; } my($tick, $first_let, $name, $exch, $stockid) = &stockInfo($t); print "$tick $first_let $name $exch $stockid\n";
I'm having serious trouble with Perl's syntactic niceties... I can get a function like this to work with a single scalar or a single array but this doesn't work. Please help me figure out where my syntax is wrong (and if we can make this cleaner, all the better!)