Re: RFC: DBIx::Counter - Manipulate named counters stored in a database

2005-04-17 Thread Rhesa Rozendaal
Smylers wrote:
OK, I've had a look, it seems like good Perl code to me -- and as a
bonus, from reading your code I learnt about the DBI prepare_cached
method (so that's a wheel that I can stop re-inventing on an ad hoc
basis in my own code).
You mean stuff like $sth ||= $dbh-prepare... ? ;^)
I was surprised to see that both connect_cached and prepare_cached were already introduced in DBI 1.06. It wasn't until I started using 
Class::DBI that I heard of them. And I haven't seen it used much elsewhere, even though it's incredibly useful.

One incredibly trivial thing -- in this code you're copying a bunch of
values from one hash to another using the same keys in both, which can
get a bit repetitive:
[...]
One nice way of dealing with this 
[...]
is simply to bless the options hash, so you'd end up with
something like:
  unshift @_, 'initial' if @_ % 2;
I like that line: one less temporary variable.
  my %opts = (countername = $countername, @_);
[...]
  bless \%opts, $pkg;
But supplying the default values for each individual option means this
technique doesn't avoid having a line listing each option -- it just saves
having to mention the keyname twice on each line -- so may not be worth
doing.
That's one reason; the other is that the way I do it now doesn't introduce unwanted data in my object. Any unknown key-value pairs are 
silently discarded. Blessing the options hash means you ought to check you only have the accepted keys, which leads to more mentioning of 
the keys.
Then again, that's all rather philosophical: if I'd really wanted to be strict, I wouldn't use a hashref as base. Something with closures 
and private variables would be a better way of keeping instance data private. But I think that would be overkill in this case.

always have tests!  One approach would be to use DBD::SQLite for the
database, and skip the tests if that module isn't installed.
You've got it all! It was quite fun writing them, actually.
Wow -- I'm impressed, not least because I wrote the suggestion above
without actually knowing how to implement it myself!
Hehehe. I copied some stuff from tests of CGI::Session (g4_sqlite.t to be 
precise) and went from there.
[...] I'm still not
convinced that overrides the general badness of global variables.  I
think I'd object to them less if they weren't given so prominent in the
documentation -- for example the login parameter is defined in terms of
$LOGIN, forcing the reader to learn about both of them and making the
former seem somehow inferior.
Fair enough. There's one situation where I really like having them available, but I agree with your point. I will tone down their prominence 
in the documentation, and put them in a special section (with appropriate caveats and an emphasis on local).

[...]
That would also enable you to have a specific example of using the
globals, where you could local-ize them and help to promote best
practice in use of global variables in general.  (The main objection to
them is that if you set them without local then they affect unrelated
bits of code, perhaps in other modules out of your direct control.)
Yes, that is a very valid concern. On the one hand, it's nice to be able to set those globals once in a configuration file (which is why 
they're in there in the first place: I use them that way in a larger application). On the other hand, the risk of affecting unrelated code 
is real.
I ran into it once when installing two applications for different customers on the same mod_perl server: the second started trampling all 
over the first's data! The config files had the proper values for each custoemr, but since they were package globals, only the first set 
loaded was used. I guess you have to make this mistake once before you're properly convinced of the dangers...

I still don't like having the globals!  I suspect the OO way of
dealing with this would be to have a 'counter factory' class which takes
parameters and then can create counters using them:
  my $counter_factory = DBIx::Counter-factory(dsn = $whatever);
  my $c_in  = $counter_factory-create('gauge one');
  my $c_out = $counter_factory-create('gauge two');
Or do something like Class::DBI: set the configuration once in a base class (derived from D::C), and use that in the rest of your 
application. All I'd need is add a setup method, so you can do:

  package My::Counter;
  use base qw/DBIx::Counter/;
  __PACKAGE__-setup(dsn=$bar); # this would set vars internally (with 
closures perhaps?)
  1;
and elsewhere:
  my $c = My::Counter-new('gauge three');
That could be overkill. 
For this little module, sure!
But I'm thrilled that a class with only four methods and very little 
functionality can generate this discussion. I really like this :)
Finally, in the doc here:
  http://search.cpan.org/~rhesa/DBIx-Counter-0.01/lib/DBIx/Counter.pm#new
I think it'd be less confusing if the big code block only contained
things that are actually Perl code.  My pod knowledge isn't very good,
but I believe there is 

Re: RFC: DBIx::Counter - Manipulate named counters stored in a database

2005-04-17 Thread A. Pagaltzis
* Smylers [EMAIL PROTECTED] [2005-04-16 14:40]:
 One nice way of dealing with this that I hadn't thought of till
 I recently spotted in Text::VimColor (though it's probably used
 in many places) is simply to bless the options hash, so you'd
 end up with something like:
 
   unshift @_, 'initial' if @_ % 2;
   my %opts = (countername = $countername, @_);
   $opts{dsn}   ||= $DSN,
   $opts{login} ||= $LOGIN,
   $opts{password}  ||= $PASSWORD,
   $opts{tablename} ||= $TABLENAME || 'counters',
   $opts{initial}   ||= '0',
   bless \%opts, $pkg;

unshift @_, 'initial' if @_ % 2;
my %param = @_;

my %default = (
dsn = $DSN,
login   = $LOGIN,
password= $PASSWORD,
tablename   = $TABLENAME || 'counters',
countername = $countername,
initial = '0',
);
my @allowed = ( keys %default, qw( and others more ) );

my %self;
@self{ @allowed } = @param{ @allowed };
$self{ $_ } ||= $default{ $_ } for keys %default;
bless \%self, $pkg;

Voil: each key and each default mentioned exactly once.

Regards,
-- 
#Aristotle
*AUTOLOAD=*_=sub{s/(.*)::(.*)/print$2,(,$\/, )[defined wantarray]/e;$1};
Just-another-Perl-hacker;


Re: RFC: DBIx::Counter - Manipulate named counters stored in a database

2005-04-17 Thread Smylers
Rhesa Rozendaal writes:

 Smylers wrote:
 
my %opts = (countername = $countername, @_);
 [...]
bless \%opts, $pkg;
  
  But supplying the default values for each individual option means
  this technique doesn't avoid having a line listing each option -- it
  just saves having to mention the keyname twice on each line -- so
  may not be worth doing.
 
 That's one reason; the other is that the way I do it now doesn't
 introduce unwanted data in my object. Any unknown key-value pairs are
 silently discarded.

I considered that, and decided it didn't matter.  Theoretically people
shouldn't pass unknown named params to your method; it's undefined what
happens if they do, so I wouldn't worry about it (your way ignores them
straight away; my way stores them in the object for ignoring later, but
the end result is pretty much the same) and just do whatever seems
simpler.  

(Arguably silently ignoring them is not the best thing to do -- the
user's done something pointless, probably a typo or a misunderstanding,
and it might be helpful to tell them, and perhaps using something like
Params::Validate would be better than either way.)

Question: Consider the point of view of the author of a module that
subclasses your module; such a module could well add further named
params for its additional functionality -- is it more useful for the
constructor in the superclass to store 'unknown' named params in the
object or not?  (I can think of arguments either way, and I'm feeling
too lazy today to work out which I'd prefer.)

 But I'm thrilled that a class with only four methods and very little
 functionality can generate this discussion. I really like this :) ...
 You've made me aware of a number of shortcomings that I hadn't given
 much thought.  But most importantly, you've given me the confidence
 that it's quite doable, though by no means trivial, to put a good
 package together.  And I very much enjoyed our conversation too :-)

Good!  I've enjoyed it too -- you've asked questions very politely, and
you've given good consideration to suggestions, that I'd've felt it rude
for me not to put the effort in and examine your code!  I think this is
what open source is _supposed_ to feel like!

Smylers
-- 
May God bless us with enough foolishness to believe that we can make a
difference in this world, so that we can do what others claim cannot be done.



Re: RFC: DBIx::Counter - Manipulate named counters stored in a database

2005-04-17 Thread A. Pagaltzis
* Smylers [EMAIL PROTECTED] [2005-04-17 19:20]:
 Question: Consider the point of view of the author of a module
 that subclasses your module; such a module could well add
 further named params for its additional functionality -- is it
 more useful for the constructor in the superclass to store
 'unknown' named params in the object or not?

Depends on whether that class wants to define additional
defaults. If so, it cant just defer to the superclass.

Regards,
-- 
Aristotle


Re: RFC: Simple Tied Filehandle code

2005-04-17 Thread James E Keenan
James E Keenan wrote:
I am requesting comments on namespace for the following package which I 
would like to upload to CPAN.

package Yet::To::Be::Named;
use strict;
use Carp;
sub TIEHANDLE {
my $class = shift;
my @lines = @_;
bless [EMAIL PROTECTED], $class;
}
sub READLINE {
my $self = shift;
if (@$self) {
shift @$self;
} else {
croak List of prompt responses has been exhausted: $!;
}
}
1;

This was uploaded to CPAN today as Tie::Filehandle::Preempt::Stdin.
jimk