Hi melguin
I agree *totally and completely* with everything that tachyon and maverick said.
If you agree, too, your question might be: where do I start?
I would suggest that you read up on eXtreme Programming , especially about code
refactoring and unit testing. Also search the PM site here for eXtreme Programming.
Your code saute_0_0_2 looks neat and well organized,
so it should not be difficult to morph it.
Let me try to suggest a recipe (untested) for putting the OO advice into the practice.
You have 2 perl files -
dbsetup.pl, 152 lines - uses DBI - creates the database schema
saute.pl, 1435 lines - uses Gnome and DBI - main program, creates Gnome main window and accessories, lets the user view and edit recipes
If I were you, I would start with making a module (a.k.a. package a.k.a. class) that wraps all your interactions
with the database. This would separate your data storage and maintenance from your GUI application,
and let you develop each separately, perhaps by different participants.
In particular, all subs (or their inner code chunks) in the main program that interact with the db
should become methods of this module.
Step 1
Create a module file RecipeDb.pm containing this
#!/usr/bin/perl -w
use strict;
package RecipeDb;
sub new {
my ($class, %args) = @_;
my $self = {
dbname => $args{dbname},
dbuser => $args{dbuser},
dbpasswd => $args{dbpasswd},
# more options if needed ...
#workspace
dbh => undef,
};
bless $self, $class;
$self->{dbh} = DBI->connect("DBI:mysql:$self->{dbname}","$self->{d
+buser}","$self->{dbpasswd}", {
PrintError => 1,
RaiseError => 0,
}) || die "Can't connect to $self->{datasource}: $DBI::errstr";
return $self;
}
sub DESTROY {
$self->{dbh}->disconnect();
}
# your code from saute.pl, slightly modified
sub get_recipe_info {
my ($self, $recipeID)=@_; # notice $self
my %recipe;
#get main recipe parts
my $sth = $self{dbh}->prepare("SELECT name,descr,instruct,
preptime,notes,source
FROM recipes
WHERE PriKey=$recipeID"); # notice $self{dbh}
$sth->execute();
while (my @row = $sth->fetchrow_array) {
$recipe{"recipeID"}=$recipeID;
$recipe{"name"}=$row[0];
$recipe{"descr"}=$row[1];
$recipe{"instruct"}=$row[2];
$recipe{"preptime"}=$row[3];
$recipe{"notes"}=$row[4];
$recipe{"source"}=$row[5];
}
$sth->finish();
#get ingredients
my @ingredients_list;
$sth = $self{dbh}->prepare("SELECT
recipeIngredients.quantity,units.name,
ingredients.name
FROM recipeIngredients,ingredients,units
WHERE (recipeIngredients.recipe=$recipeID)
AND (ingredients.PriKey=recipeIngredients.ingredient)
AND (units.PriKey=recipeIngredients.units)"); # notic
+e $self{dbh}
$sth->execute();
while (my @row = $sth->fetchrow_array) {
push (@ingredients_list, [$row[0],$row[1],$row[2]]);
}
$sth->finish();
$recipe{"ingredients"}=\@ingredients_list;
#get categories
my @categories_list;
$sth = $self{dbh}->prepare("SELECT
categories.name
FROM recipeCategories,categories
WHERE (recipeCategories.recipe=$recipeID)
AND (categories.PriKey=recipeCategories.category)");
+# notice $self{dbh}
$sth->execute();
while (my @row = $sth->fetchrow_array) {
push (@categories_list, $row[0]);
}
$sth->finish();
$recipe{"categories"}=\@categories_list;
return \%recipe;
}
# more methods here
1; # true enough
Run this file to make sure that it compiles.
Step 2
Write a little test program, say TestRecipeDb.pl
use RecipeDb;
my $rdb = new RecipeDbase(
dbname => $DBNAME,
dbuser => $DBUSER,
dbpasswd => $DBPASSWD,
);
my $ID = ""; # please fill in
my $recipe = $rdb->get_recipe_info($ID);
Use Data::Dumper;
print Dumper $recipe;
Does it work? Is the dumped recipe what you expected? If not, fix it.
Step 3
Now copy the code from TestRecipeDb.pl into your main program, saute.pl.
Replace all calls to get_recipe_info() by calls to $rdb->get_recipe_info() .
Test thoroughly. Does it work as before? If not, fix it.
OK? Now remove sub get_recipe_info() from saute.pl.
Step 4..N
Repeat for all other subs that interact with the database what you did for get_recipe_info() :
make a clone in RecipeDb, test it, call it from main program, remove the original sub from the main program.
When done, remove use DBI; from the main program.
What next?
Above should leave you with a considerably smaller saute.pl, a module RecipeDb.pm and a test program for it.
And enough OO experience to take another hard look at what you have and decide what would be the next useful steps.
You should probably move some of the code from dbsetup.pl into RecipeDb.pm,
and leave dbsetup.pl as a command-line interface to creating the database.
If some day you decide to provide a graphics interface for this activity, you'll be ready.
Next, turn those recipe hashes into packages, perhaps?
You can turn the test program into a regression test by hardcoding the expected results
and comparing with what you get from the database.
Oh, I almost forgot the most important advice: enjoy!
Rudif
|