Re[2]: each considered harmful?
Hello Marcin Kasperski, Tuesday, June 17, 2003, 3:13:23 AM, you wrote: >> > sub handler { >> >> > my $r = shift; >> > my $uri = $r->uri; >> > ... detecting dynamic handlers ... >> > while( my($url, $dirs) = each %STATIC_FILES ) { >> > if( $uri =~ m{$url/(.*)$} ) { >> > foreach my $d (@$dirs) { >> > my $file = "$d/$1"; >> > if( -f $file ) { >> >$r->filename($file); >> >return OK; >> > } >> > } >> > } >> > } >> > } >> >> ah, a real-world example. Just what we need. Care to write a short pod >> section using this example, explaining the problem and the solution? >> plain text or pod will do. we will add it to the coding chapter. MK> Hmm, let's use my english-like language... MK> The problem: MK> - the application static files are installed in /myapp/img, MK> /myapp/css, ... MK> - local site customization can be made by installing customized files MK> in /custom/img, /custom/css... MK> - in both cases they are accessed via /img/..., /css/... urls MK> The solution - we use custom transhandler to check whether the MK> customized version exists and use it if so. In our setup we use mod_rewrite for things like that. It checks for static resources in the few places and if there is no custom version finally looks in the some standard location (images, css, javascripts, any static resources etc ...). In the dual frontend/backend setup I think this approach is better -- requests for static resources may still be served by light frontend server. -- WBR, Mike P. Mikhailov mailto: [EMAIL PROTECTED] ICQ:280990142 Who is "General Failure", and what is he doing reading my hard disk ?
Re: each considered harmful?
Marcin Kasperski wrote: sub handler { my $r = shift; my $uri = $r->uri; ... detecting dynamic handlers ... while( my($url, $dirs) = each %STATIC_FILES ) { if( $uri =~ m{$url/(.*)$} ) { foreach my $d (@$dirs) { my $file = "$d/$1"; if( -f $file ) { $r->filename($file); return OK; } } } } } ah, a real-world example. Just what we need. Care to write a short pod section using this example, explaining the problem and the solution? plain text or pod will do. we will add it to the coding chapter. Hmm, let's use my english-like language... The problem: - the application static files are installed in /myapp/img, /myapp/css, ... - local site customization can be made by installing customized files in /custom/img, /custom/css... - in both cases they are accessed via /img/..., /css/... urls The solution - we use custom transhandler to check whether the customized version exists and use it if so. Yes, but can you write a section to be added to the documentation, explaining the problem, providing an example and a solution. Something that you'd have loved to find in the docs, when you first discovered it? Of course digesting all the helpful comments from others in this thread. Good docs don't grow on the trees, someone has to put them together. __ Stas BekmanJAm_pH --> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: each considered harmful?
> > sub handler { > > > my $r = shift; > > my $uri = $r->uri; > > ... detecting dynamic handlers ... > > while( my($url, $dirs) = each %STATIC_FILES ) { > > if( $uri =~ m{$url/(.*)$} ) { > > foreach my $d (@$dirs) { > > my $file = "$d/$1"; > > if( -f $file ) { > >$r->filename($file); > >return OK; > > } > > } > > } > > } > > } > > ah, a real-world example. Just what we need. Care to write a short pod > section using this example, explaining the problem and the solution? > plain text or pod will do. we will add it to the coding chapter. Hmm, let's use my english-like language... The problem: - the application static files are installed in /myapp/img, /myapp/css, ... - local site customization can be made by installing customized files in /custom/img, /custom/css... - in both cases they are accessed via /img/..., /css/... urls The solution - we use custom transhandler to check whether the customized version exists and use it if so. -- ( Marcin Kasperski | Working overtime sucks the spirit and motivation ) ( http://www.mk.w.pl | out of a team. (Wells) ) () ( O CVS i zarządzaniu wersjami: http://www.mk.w.pl/narzedzia/narzedzia_cvs )
Re: each considered harmful?
> "Randal" == Randal L Schwartz <[EMAIL PROTECTED]> writes: Randal> our @STATIC_FILES = ( Randal> [ qr{^/img/(.*)$} => [ qw(/alternative/img /myapp/install/img) ], Randal> [ qr{^/css/(.*)$} => [ qw(/alternative/css /myapp/install/css) ], Argh. extra left bracket snuck in. [ qr{^/img/(.*)$} => qw(/alternative/img /myapp/install/img) ], [ qr{^/css/(.*)$} => qw(/alternative/css /myapp/install/css) ], Randal> ... Randal> ); Randal> sub handler { Randal> my $r = shift; Randal> my $uri = $r->uri; Randal> for (@STATIC_FILES) { Randal> my ($pat, @dirs) = @$_; Randal> if ($uri =~ $pat) { Randal> my $tail = $1; Randal> foreach my $dir (@dirs) { Randal> my $file = "$dir/$tail"; Randal> if (-f $file) { Randal> $r->filename($file); Randal> return OK; Randal> } Randal> } Randal> } Randal> } Randal> return DECLINED; Randal> } Randal> -- Randal> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 Randal> <[EMAIL PROTECTED]> http://www.stonehenge.com/merlyn/> Randal> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. Randal> See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training! -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[EMAIL PROTECTED]> http://www.stonehenge.com/merlyn/> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Re: each considered harmful?
> "Marcin" == Marcin Kasperski <[EMAIL PROTECTED]> writes: Marcin> Maybe it could be of some interest where I happened to get this Marcin> problem. I got it in my custom TransHandler implemented to reduce stat Marcin> calls and to obtain 'select from multiple directories' effect. Marcin> ... (config file) Marcin> our %STATIC_FILES = ( Marcin> '/img' = [ '/alternative/img', '/myapp/install/img' ], Marcin> '/css' = [ '/alternative/css', '/myapp/install/css' ], Marcin> ... Marcin> ) Marcin> ... (transhandler file, simplified of course) ... Marcin> sub handler { Marcin> my $r = shift; Marcin> my $uri = $r->uri; Marcin> ... detecting dynamic handlers ... Marcin> while( my($url, $dirs) = each %STATIC_FILES ) { Marcin> if( $uri =~ m{$url/(.*)$} ) { Marcin> foreach my $d (@$dirs) { Marcin> my $file = "$d/$1"; Marcin> if( -f $file ) { Marcin>$r->filename($file); Marcin>return OK; Marcin> } Marcin> } Marcin> } Marcin> } Marcin> } That's actually the wrong data structure then. What you want if you're only ever accessing it as a list, is a list! And, you're needlessly recompiling the regex each time. Here's a much better way to do that... our @STATIC_FILES = ( [ qr{^/img/(.*)$} => [ qw(/alternative/img /myapp/install/img) ], [ qr{^/css/(.*)$} => [ qw(/alternative/css /myapp/install/css) ], ... ); sub handler { my $r = shift; my $uri = $r->uri; for (@STATIC_FILES) { my ($pat, @dirs) = @$_; if ($uri =~ $pat) { my $tail = $1; foreach my $dir (@dirs) { my $file = "$dir/$tail"; if (-f $file) { $r->filename($file); return OK; } } } } return DECLINED; } -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[EMAIL PROTECTED]> http://www.stonehenge.com/merlyn/> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Re: each considered harmful?
Ged Haywood wrote: [...] Most people when iterating over a hash will say something like foreach $scalar_name ( keys %hash_name ) { ... } which automatically resets the iterator and is safe in a perisitent Perl environment like mod_perl. I hope. That's a good point, Ged. Marcin, please include this preferred solution in the possible solutions section (assuming that you are going to write it ;). __ Stas BekmanJAm_pH --> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: each considered harmful?
Hi guys, On Mon, 16 Jun 2003, Stas Bekman wrote: [snip,snip] > keys %hash; > > does the trick > > interesting that I don't remember this issue being reported earlier. Probably because we all read the Camel Book, section 5.4.3, the bit about FIRSTKEY. All except Randal that is... :) Most people when iterating over a hash will say something like foreach $scalar_name ( keys %hash_name ) { ... } which automatically resets the iterator and is safe in a perisitent Perl environment like mod_perl. I hope. 73, Ged.
Re: each considered harmful?
Marcin Kasperski wrote: Calling keys() (or values()) in void context is quite efficient. Nice to now. So it seems the correct idiom for using each is: keys %hash; while( my($k,$v) = each %hash ) { ... } Looks like it. probably with a comment so you (or other readers) won't forget why you did that. p.s. I've shown an example, so we can have this issue documented together with other mod_perl gotchas. It's interesting that I don't remember this issue being reported earlier. Maybe it could be of some interest where I happened to get this problem. I got it in my custom TransHandler implemented to reduce stat calls and to obtain 'select from multiple directories' effect. ... (config file) our %STATIC_FILES = ( '/img' = [ '/alternative/img', '/myapp/install/img' ], '/css' = [ '/alternative/css', '/myapp/install/css' ], ... ) ... (transhandler file, simplified of course) ... sub handler { my $r = shift; my $uri = $r->uri; ... detecting dynamic handlers ... while( my($url, $dirs) = each %STATIC_FILES ) { if( $uri =~ m{$url/(.*)$} ) { foreach my $d (@$dirs) { my $file = "$d/$1"; if( -f $file ) { $r->filename($file); return OK; } } } } } ah, a real-world example. Just what we need. Care to write a short pod section using this example, explaining the problem and the solution? plain text or pod will do. we will add it to the coding chapter. Thanks. __ Stas BekmanJAm_pH --> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: each considered harmful?
> Calling keys() (or values()) in void context is quite efficient. Nice to now. So it seems the correct idiom for using each is: keys %hash; while( my($k,$v) = each %hash ) { ... } > p.s. I've shown an example, so we can have this issue documented > together with other mod_perl gotchas. It's interesting that I don't > remember this issue being reported earlier. Maybe it could be of some interest where I happened to get this problem. I got it in my custom TransHandler implemented to reduce stat calls and to obtain 'select from multiple directories' effect. ... (config file) our %STATIC_FILES = ( '/img' = [ '/alternative/img', '/myapp/install/img' ], '/css' = [ '/alternative/css', '/myapp/install/css' ], ... ) ... (transhandler file, simplified of course) ... sub handler { my $r = shift; my $uri = $r->uri; ... detecting dynamic handlers ... while( my($url, $dirs) = each %STATIC_FILES ) { if( $uri =~ m{$url/(.*)$} ) { foreach my $d (@$dirs) { my $file = "$d/$1"; if( -f $file ) { $r->filename($file); return OK; } } } } }
Re: each considered harmful?
Paul Johnson wrote: On Sun, Jun 15, 2003 at 09:35:38PM +0200, Marcin Kasperski wrote: Does there exist some way to protect before this problem (some kind of auto-destructor, finally, whatever which would automatically rewind the hash internal iterator while leaving the context)? Not really a mod_perl problem, but you can read about the solution in the docs for each. There is a single iterator for each hash, shared by all "each", "keys", and "values" function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating "keys HASH" or "values HASH". I found this note before asking, believe me... But it seems to me that this solution is not satisfactory - calling 'keys' or 'values' is inefficient and destroys most gains from iterating over the hash using each... Calling keys() (or values()) in void context is quite efficient. Whether or not you appreciate the aesthetics is perhaps quite another matter. I think the point that Marcin is trying to make is that under normal circumstances (a script is run once) this problem doesn't occur. However under mod_perl the code persists and therefore doesn't DWIM, till you start thinking in mod_perl terms and not one-time run script terms. The problem can be classified into "the global variables usage under mod_perl" category. Consider: #!/usr/bin/perl -T our %hash; %hash = map {$_ => 1 } 'a'..'c' unless %hash; print "Content-type: text/plain\n\n"; for (my ($k, $v) = each %hash) { print "$k $v\n"; last; } that script prints different values on the first 3 invocations and prints nothing on the 4th, and then repeats the loop. (when you run with httpd -X). there are 3 hash key/value pairs in that example. As Paul has suggested you need to reset the iterator as documented for the operator each(). So adding: keys %has; does the trick for the above example. p.s. I've shown an example, so we can have this issue documented together with other mod_perl gotchas. It's interesting that I don't remember this issue being reported earlier. __ Stas BekmanJAm_pH --> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: each considered harmful?
On Sun, Jun 15, 2003 at 09:35:38PM +0200, Marcin Kasperski wrote: > > > Does there exist some way to protect before this problem (some kind of > > > auto-destructor, finally, whatever which would automatically rewind > > > the hash internal iterator while leaving the context)? > > > > Not really a mod_perl problem, but you can read about the solution in > > the docs for each. > > > > There is a single iterator for each hash, shared by all "each", > > "keys", and "values" function calls in the program; it can be reset > > by reading all the elements from the hash, or by evaluating "keys > > HASH" or "values HASH". > > I found this note before asking, believe me... > But it seems to me that this solution is not satisfactory - calling > 'keys' or 'values' is inefficient and destroys most gains from > iterating over the hash using each... Calling keys() (or values()) in void context is quite efficient. Whether or not you appreciate the aesthetics is perhaps quite another matter. -- Paul Johnson - [EMAIL PROTECTED] http://www.pjcj.net
Re: each considered harmful?
> > Does there exist some way to protect before this problem (some kind of > > auto-destructor, finally, whatever which would automatically rewind > > the hash internal iterator while leaving the context)? > > Not really a mod_perl problem, but you can read about the solution in > the docs for each. > > There is a single iterator for each hash, shared by all "each", > "keys", and "values" function calls in the program; it can be reset > by reading all the elements from the hash, or by evaluating "keys > HASH" or "values HASH". I found this note before asking, believe me... But it seems to me that this solution is not satisfactory - calling 'keys' or 'values' is inefficient and destroys most gains from iterating over the hash using each... -- ( Marcin Kasperski | Communication takes place between people, documents ) ( http://www.mk.w.pl |are secondary. (Booch) ) () ( Porady dla twórców serwisów WWW: http://www.mk.w.pl/porady/porady_www )
Re: each considered harmful?
> "Marcin" == Marcin Kasperski <[EMAIL PROTECTED]> writes: Marcin> You probably see the problem - when this code is re-executed (next Marcin> request), the loop iterates just over 'the rest' of the hash. This is similar to the problem that shows up when you use glob in a scalar context... it also has lexically-attached state. And now that I think about it, so does the flip-flop scalar dot-dot operator. These are all examples of where it is non-trivial to take a CGI-based script and just "drop it in" as Apache::Registry. There's really nothing A::R can do about it. You must still use your Branes. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <[EMAIL PROTECTED]> http://www.stonehenge.com/merlyn/> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Re: each considered harmful?
On Sat, Jun 14, 2003 at 11:33:17PM +0200, Marcin Kasperski wrote: > Hmm, probably well known but ... I have not met any direct warning of > this problem so far. > > our %SOME_CONFIG = ( > a => 1, > b => 2, > c => 3, > ); > > ... > while (my($k,$v) = each %SOME_CONFIG) { > if( ... ) { > return; # or last, or throw exception > } > } > > You probably see the problem - when this code is re-executed (next > request), the loop iterates just over 'the rest' of the hash. > > Does there exist some way to protect before this problem (some kind of > auto-destructor, finally, whatever which would automatically rewind > the hash internal iterator while leaving the context)? Not really a mod_perl problem, but you can read about the solution in the docs for each. There is a single iterator for each hash, shared by all "each", "keys", and "values" function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating "keys HASH" or "values HASH". perldoc -f each -- Paul Johnson - [EMAIL PROTECTED] http://www.pjcj.net
each considered harmful?
Hmm, probably well known but ... I have not met any direct warning of this problem so far. our %SOME_CONFIG = ( a => 1, b => 2, c => 3, ); ... while (my($k,$v) = each %SOME_CONFIG) { if( ... ) { return; # or last, or throw exception } } You probably see the problem - when this code is re-executed (next request), the loop iterates just over 'the rest' of the hash. Does there exist some way to protect before this problem (some kind of auto-destructor, finally, whatever which would automatically rewind the hash internal iterator while leaving the context)?