Pure perl trick that Apache::Table might be doing in C (fwd)

Dave Rolsky <[email protected]> Sat, 11 Jul 2009 23:36:03 -0500 (CDT)
Newsgroups gmane.comp.web.mason.devel
Message-ID <[email protected]>
  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--------------000801010106000704020802
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII; FORMAT=flowed
Content-ID: <[email protected]>

---------- Forwarded message ----------
Date: Sat, 11 Jul 2009 15:03:03 +0930
From: Andrew Kirkpatrick <[email protected]>
To: [email protected]
Subject: Pure perl trick that Apache::Table might be doing in C

Hi David,

Perhaps this belongs on the Mason mailing lists, but I'm not sure which one, 
anyway if so let me know and I'll post there.

Around here: 
http://search.cpan.org/~drolsky/HTML-Mason-1.42/lib/HTML/Mason/CGIHandler.pm#HTML::Mason::FakeTable_Methods

There is the statement:

"HTML::Mason::FakeTable is designed to behave exactly like Apache::Table, and 
differs in only one respect. When a given key has multiple values in an 
Apache::Table object, one can fetch each of the values for that key using 
Perl's each operator"

I took that as an interesting exercise, and not having written a tie since the 
late 90s thought to give it a go. The result is a class that achieves the 
interface of Apache::Table, at least in that respect (see attached). I made it 
a modulino so you can give it a spin easily.

Hopefully it proves useful to someone. I've been striving to modernize the perl 
environment at the University of Adelaide, and while I think Catalyst is a 
clear winner for some apps I'm considering doing some CMS work in Mason.

Cheers,
Andrew Kirkpatrick
--------------000801010106000704020802
Content-Type: APPLICATION/X-PERL; NAME=MultiHash.pm
Content-ID: <[email protected]>
Content-Description: 
Content-Disposition: INLINE; FILENAME=MultiHash.pm

# Author: Andrew Kirkpatrick
# License: Artistic License 2.0
# see http://www.opensource.org/licenses/artistic-license-2.0.php

package MultiHash;

use strict;
use warnings;

sub TIEHASH {
  my ($class, $attr) = @_;
  return bless { attr => $attr }, $class;
}

sub FETCH {
  my ($self, $key) = @_;
  my $result;
  if (my $val = $self->{data}{$key}) {
    my $index = $self->{indx}{$key};
    $index = 0 if $index > $#$val;
    $result = $val->[$index];
    $index++;
    $self->{indx}{$key} = $index;
  }
  return $result;
}

sub STORE {
  my ($self, $key, $value) = @_;
  push @{$self->{data}{$key}}, $value;
  $self->{indx}{$key} ||= 0;
}

sub DELETE {
  my ($self, $key) = @_;
  if (my $data = $self->{data}{$key}) {
    my $result = $self->{attr}{fifo} ? shift @$data : pop @$data;
    unless (@$data) {
      delete $self->{data}{$key};
      delete $self->{indx}{$key};
    }
    return $result;
  } else {
    return;
  }
}

sub CLEAR {
  my ($self) = @_;
  $self->{data} = {};
  $self->{indx} = {};
}

sub EXISTS {
  my ($self, $key) = @_;
  return exists $self->{data}{$key};
}

sub FIRSTKEY {
  my ($self) = @_;
  my $dummy = keys %{$self->{data}};
  return each %{$self->{data}};
}

sub NEXTKEY {
  my ($self, $lastkey) = @_;
  if ($self->{indx}{$lastkey} < @{$self->{data}{$lastkey}}) {
    #my $count = @{$self->{data}{$lastkey}};
    #warn "key $lastkey: $self->{indx}{$lastkey} < $count\n";
    return wantarray ? ($lastkey, $self->FETCH($lastkey)) : $lastkey;
  } else {
    return each %{$self->{data}};
  }
}

sub SCALAR {
  my ($self) = @_;
  # this won't count multi values but should suffice
  return scalar %{$self->{data}};
}

sub UNTIE {
  my ($self) = @_;
  if ($self->{attr}{debug}) {
    require Data::Dumper;
    warn Data::Dumper::Dumper($self);
  }
}

1;

package main;

sub main {
  $| = 1;
  print "Testing $0\n";
  tie(my %mh, 'MultiHash', {debug => 1, fifo => 1});

  %mh = (
         one    => 1,
         two    => 2,
         two    => 3,
         two    => 4,
         three  => 5,
         three  => 6,
         seven  => 7,
        );

  my @two_values = map { $mh{two} } 1..12;
  print "\nConsecutive values of the key 'two': @two_values\n";

  print "\nEach loop:\n";
  while (my ($k, $v) = each %mh) {
    no warnings;
    print "$k => $v\n";
  }

  my @two_was = delete @mh{qw(two two two)};
  print "\nFrom deleting 'two' thrice: @two_was\n";

  print "\nDebug dump:\n";
  untie %mh;
}

# I knew I'd write a modulino one day :)
main() unless caller;

1;

--------------000801010106000704020802
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize  
details at: http://p.sf.net/sfu/Challenge
--------------000801010106000704020802
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Mason-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mason-devel

--------------000801010106000704020802--