ACME-QuoteDB

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


0.1.2   Wed Sep 30 23:26:11 PDT 2009
  bug fixes:
  * Build.PL install changes - SQLite3 could not actually write to the database,
    even though, the db file was world writeable. The container dir 
    also needs to be writable, now it is.
  * ensure the database is 0666 for tests as well

0.1.1   Fri Sep 18 02:11:02 PDT 2009
  bug fixes:
  * default constructor values were not getting set on the object as they should
  * loosen untaint filepath - for the dist test failures

0.1.0   Wed Sep  9 23:43:56 PDT 2009
        Initial public pre-release (minor version)


lib/ACME/QuoteDB.pm  view on Meta::CPAN

#$Id: QuoteDB.pm,v 1.36 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB;

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#major-version.minor-revision.bugfix
use version; our $VERSION = qv('0.1.2');

lib/ACME/QuoteDB.pm  view on Meta::CPAN


sub add_quote {
    my ( $self, $arg_ref ) = @_;

    _args_are_valid($arg_ref, [qw/Quote AttrName Source Rating Category/]);

    my $load_db = ACME::QuoteDB::LoadDB->new({
                                #verbose => 1,
                  });

    $load_db->set_record(quote  => $arg_ref->{Quote});
    $load_db->set_record(name   => $arg_ref->{AttrName});
    $load_db->set_record(source => $arg_ref->{Source});
    $load_db->set_record(catg   => $arg_ref->{Category});
    $load_db->set_record(rating => $arg_ref->{Rating});

    if ($load_db->get_record('quote') and $load_db->get_record('name')) {
        return $load_db->write_record;
    }
    else {
        croak 'quote and attribution name are mandatory parameters';
    }

    return;
}

lib/ACME/QuoteDB.pm  view on Meta::CPAN

    foreach my $q ( @{$sq->get_quotes({Limit => 6})} ) {
        print "$q\n";
    }


    # get list of available attributions (that have quotes provided by this module)
    print $sq->list_attr_names;

    # any unique part of name will work
    # i.e these will all return the same results (because of our limited
    # quotes db data set)
    print $sq->get_quotes({AttrName => 'comic book guy'});
    print $sq->get_quotes({AttrName => 'comic book'});
    print $sq->get_quotes({AttrName => 'comic'});
    print $sq->get_quotes({AttrName => 'book'});
    print $sq->get_quotes({AttrName => 'book guy'});
    print $sq->get_quotes({AttrName => 'guy'});

   # get all quotes, only using these categories (you have defined)
   print @{$sq->get_quotes({ Category => [qw(Humor ROTFLMAO)] })};

lib/ACME/QuoteDB.pm  view on Meta::CPAN

  "I hope this has taught you kids a lesson: kids never learn.","Chief Wiggum","The Simpsons","Humor",9
  "Sideshow Bob has no decency. He called me Chief Piggum. (laughs) Oh wait, I get it, he's all right.","Chief Wiggum","The Simpsons","Humor",8

=item 1 if these dont suit your needs, ACME::QuoteDB::LoadDB is sub-classable, 

  so one can extract data anyway they like and populate the db themselves. 
  (there is a test that illustrates overriding the stub method, 'dbload')

   you need to populate a record data structure:

    $self->set_record(quote  => q{}); # mandatory
    $self->set_record(name   => q{}); # mandatory
    $self->set_record(source => q{}); # optional but useful
    $self->set_record(catg   => q{}); # optional but useful
    $self->set_record(rating => q{}); # optional but useful

   # then to write the record you call
   $self->write_record;

   NOTE: this is a record-by-record operation, so one would perform this within a
   loop. there is no bulk (memory dump) write operation currently.


=back

lib/ACME/QuoteDB.pm  view on Meta::CPAN

install cpan modules, you should have no problem installing this module
(utf-8 support in DBD::SQLite not avaible until 5.8 - we don't support 'non
utf-8 mode)

=over 1

=item * By default, the quotes database used by this module installs in the 
system path, 'lib', (See L<Module::Build/"INSTALL PATHS">)
as world writable - i.e. 0666 (and probably owned by root)
If you don't like this, you can modify Build.PL to not chmod the file and it
will install as 444/readonly, you can also set a chown in there for whoever
you want to have RW access to the quotes db.

Alternativly, one can specify a location to a quotes database (file) to use.
(Since the local mode is sqlite3, the file doesn't even need to exist, just
needs read/write access to the path on the filesystem)

Set the environmental variable:

$ENV{ACME_QUOTEDB_PATH} (untested on windows)

(this has to be set before trying a database load and also (everytime before 
using this module, obviouly)

Something such as:

BEGIN { 
    # give alternate path to the DB
    # doesn't need to exist, will create
    $ENV{ACME_QUOTEDB_PATH} = '/home/me/my_stuff/my_quote_db'
}

* (NOTE: be sure this (BEGIN) exists *before* the 'use ACME::QuoteDB' lines)

The default is to use sqlite3.

In order to connect to a mysql database, several environmental variables
are required.

BEGIN {
    # have to set this to use remote database
    $ENV{ACME_QUOTEDB_REMOTE} =  'mysql';
    $ENV{ACME_QUOTEDB_DB}     =  'acme_quotedb';
    $ENV{ACME_QUOTEDB_HOST}   =  'localhost';
    $ENV{ACME_QUOTEDB_USER}   =  'acme_user';
    $ENV{ACME_QUOTEDB_PASS}   =  'acme';
}

Set the above in a begin block.

The database connection is transparent. 

lib/ACME/QuoteDB.pm  view on Meta::CPAN

XXX - look at search_like, instead of what you are doing now

=end comment

currently, I am not encapsulating the record data structure used 
by LoadDB->write. (i.e. it's a typical perl5 ojbect, the blessed hash)

I will for sure be encapsulating all data in a future version.
(so, don't have code that does $self->{record}->{name} = 'value', or you won't
be happy down the road). Instead use $self->get_record('name') (getter) or
$self->set_record(name => 'my attrib') (setter)


When we are using a SQLite database backend ('regular' local usage), we 
should probably be using, ORLite instead of Class::DBI 
(although we have not seen any issues yet).

Please report any bugs or feature requests to C<bug-acme-quotedb at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=ACME-QuoteDB>.  
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

lib/ACME/QuoteDB/DB/Attribution.pm  view on Meta::CPAN

#$Id: Attribution.pm,v 1.12 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::DB::Attribution;
use base 'ACME::QuoteDB::DB::DBI';

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

lib/ACME/QuoteDB/DB/Category.pm  view on Meta::CPAN

#$Id: Category.pm,v 1.7 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::DB::Category;
use base 'ACME::QuoteDB::DB::DBI';

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

lib/ACME/QuoteDB/DB/DBI.pm  view on Meta::CPAN

#$Id: DBI.pm,v 1.19 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::DB::DBI;
use base 'Class::DBI';

use 5.008005;        # require perl 5.8.5
                     # DBD::SQLite Unicode is not supported before 5.8.5
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

lib/ACME/QuoteDB/DB/DBI.pm  view on Meta::CPAN

use File::Basename qw/dirname/;
use Carp qw/croak/;
use Cwd 'abs_path';
use File::Spec;

Readonly my $QUOTES_DATABASE => $ENV{ACME_QUOTEDB_PATH}
                                  || File::Spec->catfile(_untaint_db_path(),
                                                   q(quotedb), q(quotes.db)
                                     );

# set this to use a remote database
# i.e. mysql
Readonly my $REMOTE => $ENV{ACME_QUOTEDB_REMOTE};

# be more specific (or more general) this is mysql
# and 'remote' can be localhost
if ($REMOTE && $REMOTE ne 'mysql') {
      croak "mysql is the only remote database supported"
               ." set ENV{ACME_QUOTEDB_REMOTE} = 'mysql'";
}
elsif ($REMOTE && $REMOTE eq 'mysql') {

    my $database = $ENV{ACME_QUOTEDB_DB};
    my $host     = $ENV{ACME_QUOTEDB_HOST};
    my $user     = $ENV{ACME_QUOTEDB_USER};
    my $pass     = $ENV{ACME_QUOTEDB_PASS};

    ACME::QuoteDB::DB::DBI->connection(
           "DBI:mysql:database=$database;host=$host",$user,$pass,

lib/ACME/QuoteDB/DB/DBI.pm  view on Meta::CPAN

                   # func/pragma's may not work here,..(probably isnt' smart anyway)
                   #count_changes  => 0,
                   #temp_store     => 2,
                   #synchronous    => 'OFF',
                   #busy_timeout => 3600000
               }
           )
      || croak "$QUOTES_DATABASE does not exist, or cant be created $!";

      # how to enable this function?
      #ACME::QuoteDB::DB::DBI->set_sql(func( 3600000, 'busy_timeout' ); 
}


sub get_current_db_path {
    return $QUOTES_DATABASE;
}

sub _untaint_db_path {
    my $sane_path = abs_path(dirname(__FILE__));
    # appease taint mode, what a dir path looks like,... (probably not)

lib/ACME/QuoteDB/DB/DBI.pm  view on Meta::CPAN


By default, the quotes database used by this module installs in a system path,
which means you'll need to be root (sudo :) to load and modify it.

Alternativly, one can specify a location to a quotes database (file) to use.

Set the environmental variable:

$ENV{ACME_QUOTEDB_PATH} (untested on windows)

(this has to be set before trying a database load and also (everytime) before 
using this module, obviouly)

see L<ACME::QuoteDB>

and

see L<ACME::QuoteDB::LoadDB>


=head1 DEPENDENCIES

lib/ACME/QuoteDB/DB/Quote.pm  view on Meta::CPAN

#$Id: Quote.pm,v 1.12 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::DB::Quote;
use base 'ACME::QuoteDB::DB::DBI';

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

lib/ACME/QuoteDB/DB/QuoteCatg.pm  view on Meta::CPAN

#$Id: QuoteCatg.pm,v 1.4 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::DB::QuoteCatg;
use base 'ACME::QuoteDB::DB::DBI';

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

#$Id: LoadDB.pm,v 1.30 2009/09/30 07:37:09 dinosau2 Exp $
# /* vim:et: set ts=4 sw=4 sts=4 tw=78: */

package ACME::QuoteDB::LoadDB;

use 5.008005;        # require perl 5.8.5, re: DBD::SQLite Unicode
use warnings;
use strict;

#use criticism 'brutal'; # use critic with a ~/.perlcriticrc

use version; our $VERSION = qv('0.1.1');

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

    $self->{file_format} = $args->{file_format};
    $FILE_ENCODING       = $args->{file_encoding} || $FILE_ENCODING;
    $self->{delim}       = $args->{delimiter};
    $self->{verbose}     = $args->{verbose};
    $self->{category}    = $args->{category};
    $self->{rating}      = $args->{rating};
    $self->{attr_source} = $args->{attr_source};
    $self->{orig_args}   = $args;
    $self->{success}     = undef;

    # start with if set
    $self->{record}->{rating} = $self->{rating};
    $self->{record}->{name}   = $self->{attr_source};
    $self->{record}->{source} = $self->{attr_source};
    if (ref $self->{category} eq 'ARRAY') {
       $self->{record}->{catg} = ();
       foreach my $c (@{$self->{category}}){
         push @{$self->{record}->{catg}}, $c;
       }
    }
    else {

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

        $self->{pass} = $ENV{ACME_QUOTEDB_PASS};
    }

    if (!$args->{dry_run}){$self->{write_db} = 1};
    #if ($args->{create_db}) {$self->create_db};
    if ($args->{create_db}) {$self->create_db_tables};

    return $self;
}

sub set_record {
  my ($self, $field, $value) = @_;

  # TODO support mult-field simultanous loading

  if ($value) {
      $self->{record}->{$field} = $value;
  }

  return $self;
}

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN


      if ($self->{verbose}){
          print "\n",
                'Quote:   ', $hr->{quote},"\n",
                'Name:    ', $hr->{name},"\n",
                'Source:  ', $hr->{source},"\n",
                'Category:', $hr->{catg},"\n",
                'Rating:  ', $hr->{rating},"\n\n";
      };

      $self->set_record(quote  => $hr->{quote});
      $self->set_record(name   => $hr->{name});
      $self->set_record(source => ($self->{attr_source} || $hr->{source}));
      # take user defined first
      # TODO support multi categories
      $self->set_record(catg   => ($self->{category} || $hr->{catg}));
      $self->set_record(rating => ($self->{rating} || $hr->{rating}));
      $self->write_record;
  }
  close $source or carp $!;

  return $self;
}

# sub class this - i.e. provide this method in your code (see test
# 01-load_quotes.t)
sub dbload {

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

                 quot_id  => $qid,
                 catg_id  => $cid,
            }) or croak $!;
         }
       }
    }
    # confirmation?
    # TODO add a test for failure
    if ($self->{write_db} and not $attr_id) {croak 'db write not successful'}

    #$self->set_record(undef);
    $self->{record} = {};
    $self->_reset_orig_args;

    if ($self->{write_db}) {
        $self->success(1);
    }

    return $self->success;
}

sub _reset_orig_args {
  my ($self) = @_;

  $self->{record}->{rating} = $self->{orig_args}->{rating};
  $self->{record}->{name}   = $self->{orig_args}->{attr_source};
  $self->{record}->{source} = $self->{orig_args}->{attr_source};
  if (ref $self->{orig_args}->{category} eq 'ARRAY') {
     foreach my $c (@{$self->{orig_args}->{category}}){
       push @{$self->{record}->{catg}}, $c;
     }
  } 

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN



=head3 load from any source

If those dont catch your interest, ACME::QuoteDB::LoadDB is sub-classable, 
so one can extract data anyway they like and populate the db themselves. 
(there is a test that illustrates overriding the stub method, 'dbload')

you need to populate a record data structure:

    $self->set_record(quote  => q{}); # mandatory
    $self->set_record(name   => q{}); # mandatory
    $self->set_record(source => q{}); # optional but useful
    $self->set_record(catg   => q{}); # optional but useful
    $self->set_record(rating => q{}); # optional but useful

    # then to write the record you call
    $self->write_record;

NOTE: this is a one record at a time operation, so one would perform 
this within a loop. there is no bulk write operation currently.


=head1 OVERVIEW

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

=item  attr_source - extracted from data if exists, otherwise will use what you
specify

example:

{attr_source => 'The Simpsons'}

=item  file_encoding - optional

Files being loaded are assumed to be utf8 encoded. if utf8 flag is not detected,
falls back to latin1 (iso-8859-1). If neither of these is correct, set this
option to the encoding your file is in.

=back

=head4 Operation Related Parameters

=over 4

=item  dry_run - optional

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

example:

{verbose => 1}

=item  create_db  - optional (boolean)

L<ACME::QuoteDB::LoadDB> default behaviour is to always assume there is a
database and append new data to that. (It is usually only needed the first 
time one load's data)

setting this parameter to a true value will create a new database.
(so while this is an optional param, it is required at least once ;)

B<NOTE: it is not intelligent, if you hand it a populated database,
it will happily overwrite all data>

B<AGAIN: setting this param will destroy the current database, creating a new
empty one>

example:

{create_db => 1}


=back 

=head2 data_to_db

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN


takes a csv file (in our defined format) as an argument, parses it and writes
the data to the database. (uses L<Text::CSV> with pure perl parser)
utf-8 safe. (opens file as utf8)

will croak with message if not successful


=head2 dbload

if your file format is set to 'html' or 'custom' you must 
define this method to do your parsing in a sub class.

Load from html is not supported because there are too many 
ways to represt the data. (same with 'custom')
(see tests for examples - there is a test for loading a 'fortune' file format)

One can subclass ACME::QuoteDB::LoadDB and override dbload,
to do our html parsing

=head2 debug_record

dump record (show what is set on the internal data structure) 

e.g. Data::Dumper

=head2 set_record

only needed it one plans to sub-class this module.
otherwise, is transparent in usage.

if you are sub-classing this module, you would have to populate 
this record. (L</write_record> knows about/uses this data structure)

possible fields consist of:

$self->set_record(quote  => q{});
$self->set_record(rating => q{});
$self->set_record(name   => q{});
$self->set_record(source => q{});
$self->set_record(catg   => q{});

currently can only set one attribute at a time.

ie. you cant do this:

 $self->set_record(
            name   => $name,
            source => $source
 );

 # or this even
 $self->set_record({
            name   => $name,
            source => $source
 });

=head2 get_record

only useful it one plans to sub-class this module.
otherwise, is transparent in usage.

if you are sub-classing this module, you would have to populate 
this record. [see L</set_record>] 

(L</write_record> knows about/uses this data structure)

possible fields consist of:

$self->get_record('quote');
$self->get_record('rating');
$self->get_record('name');
$self->get_record('source');
$self->get_record('catg');

lib/ACME/QuoteDB/LoadDB.pm  view on Meta::CPAN

install cpan modules, you should have no problem installing this module
(utf-8 support in Text::CSV not avaible until 5.8 - we don't support 'non
utf-8 mode)

=over 1

=item * By default, the quotes database used by this module installs in the 
system path, 'lib', (See L<Module::Build/"INSTALL PATHS">)
as world writable - i.e. 0666 (and probably owned by root)
If you don't like this, you can modify Build.PL to not chmod the file and it
will install as 444/readonly, you can also set a chown in there for whoever
you want to have RW access to the quotes db.

Alternativly, one can specify a location to a quotes database (file) to use.
(Since the local mode is sqlite3, the file doesn't even need to exist, just
needs read/write access to the path)

Set the environmental variable:

$ENV{ACME_QUOTEDB_PATH} (untested on windows)

(this has to be set before trying a database load and also (everytime) before 
using this module, obviouly)

Something such as:

BEGIN {
    # give alternate path to the DB
    # doesn't need to exist, will create
    $ENV{ACME_QUOTEDB_PATH} = '/home/me/my_stuff/my_quote_db'
}

* (NOTE: be sure this (BEGIN) exists *before* the 'use ACME::QuoteDB' lines)

The default is to use sqlite3.

In order to connect to a mysql database, several environmental variables
are required.

BEGIN {
    # have to set this to use remote database
    $ENV{ACME_QUOTEDB_REMOTE} =  'mysql';
    $ENV{ACME_QUOTEDB_DB}     =  'acme_quotedb';
    $ENV{ACME_QUOTEDB_HOST}   =  'localhost';
    $ENV{ACME_QUOTEDB_USER}   =  'acme_user';
    $ENV{ACME_QUOTEDB_PASS}   =  'acme';
}

Set the above in a begin block and all operations are the same but now
you will be writing to the remote mysql database specified.

t/01-load_quotes.t  view on Meta::CPAN

                              # provide a attr_source for all (if not in data)
                              attr_source => 'The Simpsons',
                              dry_run     => 1, # don't write to the database
                              #verbose    => 1, # show what is being done
                              create_db   => 1, # need to create the database
                          });
  isa_ok $load_db, 'ACME::QuoteDB::LoadDB';

  $load_db->data_to_db;

  #flag not set on dry_run
  is $load_db->success, undef; # success only after a database write, 
  
  my $sq = ACME::QuoteDB->new;
  isa_ok $sq, 'ACME::QuoteDB';
  ok ! $sq->list_attr_names;
}

{
  my $load_db = ACME::QuoteDB::LoadDB->new({
                              file =>

t/01-load_quotes.t  view on Meta::CPAN

  use HTML::TokeParser;

    sub dbload {
      my ($self, $file) = @_;

      my $p = HTML::TokeParser->new($file) || croak $!;
    
      while (my $token = $p->get_tag("p")) {
          my $idn = $token->[1]{class} || q{};
          my $id = $token->[1]{id} || q{}; # if a quotation is continued (id
          #is not set)
          next unless $idn and ( $idn eq 'quotation' || $idn eq 'source');
          #my $data = $p->get_trimmed_text("/p");
          my $data = $p->get_text('p', 'cite');
          #warn Dumper $data;
          # XXX see $self->set_record in ACME::QuoteDB::LoadDB for fields
          # to populate
          if ($idn eq 'quotation' and $id) {
              $self->set_record(quote => $data);
          }
          elsif ($idn eq 'quotation' and not $id) {
              my $d = $self->get_record('quote') || q{};
              $self->set_record(quote => qq{$d $data});
          }
          elsif ($idn eq 'source'){
              my ($name, $source) = split /,/, $data;
              if ($name) {
                chomp $name;
                $name =~ s/\A\s+//xms;
                $name =~ s/\s+\z//xms;
              }
              $self->set_record(name   => $name);
              $self->set_record(source => $source);

              # TODO
              #$self->set_record({
              #           name   => $name,
              #           source => $source
              #});
          }
    
          if ($self->get_record('quote') and $self->get_record('name')) {
              # we provided a category and rating, otherwise would have to
              # parse from data too
              $self->set_record(catg => $self->{category});
              $self->set_record(rating => $self->{rating});

              # TODO
              #$self->set_record({
              #           catg => $self->{category},
              #           rating => $self->{rating}
              #});

              #$self->debug_record;
              $self->write_record;
          }
      }
    }

t/01-load_quotes.t  view on Meta::CPAN


    while (my $line = <$source>){

      #$self->debug_record;

      $q .= $line;
      $q =~ s{\A\s+}{}xsmg;
      $q =~ s{\s+\z}{}xsmg;
      $q =~ s/\s+$self->{delim}//g;

      $self->set_record(quote => $q);

      my $name = $self->get_record('quote');
      $name =~ s{\A(.*?):.*}{$1}xmsg; # not accurate,

      $self->set_record(name   => $name);
      $self->set_record(source => $self->{attr_source});
      $self->set_record(catg   => $self->{category} || q{});
      $self->set_record(rating => $self->{rating} || q{});

      $self->write_record;
      $q = q{};
    }
    close $source || croak $!;
  }

  package main;
  use File::Basename qw/dirname/;
  use File::Spec;

t/01-load_quotes.t  view on Meta::CPAN

  my $sq = ACME::QuoteDB->new;
  isa_ok $sq, 'ACME::QuoteDB';
  is( $sq->list_attr_sources, 'Futurama');
  is( $sq->list_categories, 'Humor');

  is scalar @{$sq->get_quotes({AttrName => 'Leela'})}, 2;
  is scalar @{$sq->get_quotes({AttrName => 'Professor'})}, 2;
  is scalar @{$sq->get_quotes({AttrName => 'Fry'})}, 4;
  is scalar @{$sq->get_quotes({AttrName => 'Bender'})}, 1;
  is scalar @{$sq->get_quotes({AttrName => 'Zapp'})}, 1;
  # set_quote? update  futurama to be in humor and cartoon
}

t/04-load_get_quote_utf8.t  view on Meta::CPAN

#!perl -T
# /* vim:et: set ts=4 sw=4 sts=4 tw=78 encoding=utf-8: */

use 5.008005;        # require perl 5.8.5
                     # DBD::SQLite Unicode is not supported before 5.8.5
use strict;
use warnings;
use utf8; # yes this source code does contain utf8 characters

use ACME::QuoteDB;
use ACME::QuoteDB::LoadDB;

t/05-load_quotes_remote.t  view on Meta::CPAN

#use Test::More qw/no_plan/;
use File::Basename qw/dirname/;
use DBI;
use File::Temp;
use File::Spec;

BEGIN {
    eval "use DBI";
    $@ and plan skip_all => 'DBI/mysql is required for this test';

    # have to set this to use remote database
    $ENV{ACME_QUOTEDB_REMOTE} =  'mysql';
    $ENV{ACME_QUOTEDB_DB}     =  'acme_quotedb';
    $ENV{ACME_QUOTEDB_HOST}   =  'localhost';
    $ENV{ACME_QUOTEDB_USER}   =  'acme_user';
    $ENV{ACME_QUOTEDB_PASS}   =  'acme';
}
my $database = $ENV{ACME_QUOTEDB_DB};
my $host     = $ENV{ACME_QUOTEDB_HOST};
my $user     = $ENV{ACME_QUOTEDB_USER};
my $pass     = $ENV{ACME_QUOTEDB_PASS};

t/data/python_quotes.txt  view on Meta::CPAN


Two things I learned for sure during a particularly intense acid trip in my own
lost youth: (1) everything is a trivial special case of something else; and,
(2) death is a bunch of blue spheres.
      -- Tim Peters, 1 May 1998

Well, they will be: "<" will mean what everyone thinks it means when applied to
builtin types, and will mean whatever __lt__ makes it mean otherwise, except
when __lt__ isn't defined but __cmp__ is in which case it will mean whatever
__cmp__ makes it mean, except when neither __lt__ or __cmp__ are defined in
which case it's still unsettled. I think. Or isn't that what you meant by
"clearly defined"?
      -- Tim Peters, 6 May 1998

You write a great program, regardless of language, by redoing it over & over &
over & over, until your fingers bleed and your soul is drained. But if you tell
newbies *that*, they might decide to go off and do something sensible, like
bomb defusing<wink>.
      -- Tim Peters, 5 Jun 1998

OO styles help in part because they make it easier to redo large parts over,

t/data/python_quotes.txt  view on Meta::CPAN

    mind-if-i-use-that-as-my-epitaph<wink>?-ly y'rs - tim
      -- Timothy J. Grant and Tim Peters, 22 Jun 1998

    > Just for the record, on AIX, the following C program:
    Oh no you don't! I followed AIX threads for the first year it came out, but
eventually decided there was no future in investing time in baffling
discussions that usually ended with "oh, never mind -- turns out it's a bug"
<0.9 wink>.
      -- Vladimir Marangozov and Tim Peters, 23 Jun 1998

Python - why settle for snake oil when you can have the *whole* snake?
      -- Mark Jackson, 26 Jun 1998

The problem I have with "SETL sets" in Python is the same I have with every
other language's "killer core" in Python: SETL is much more than just "a set
type", Eiffel is much more than just fancy pre- and post- conditions, Perl's
approach to regexps is much more than just its isolated regexp syntax, Scheme
is much more than just first-class functions & lexical closures, and so on.
Good languages aren't random collections of interchangeable features: they have
a philosophy and internal coherence that's never profitably confused with their
surface features.
      -- Tim Peters, 10 Jul 1998

    "Since I'm so close to the pickle module, I just look at the pickles
directly, as I'm pretty good at reading pickles."

t/data/python_quotes.txt  view on Meta::CPAN

facilitator of/participant in online communities, better and more easily than I
otherwise could do.
      -- Ken Manheimer, 24 Jan 1999

    Every standard applies to a certain problem domain and a certain level. A
standard can work perfectly and save the world economy billions of dollars and
there will still be software and hardware compatibility problems. In fact,
solving one level of compatibility just gives rise to the next level of
incompatibility. For example, connecting computers together through standard
protocols gives rise to the problem of byte endianness issues. Solving byte
endianness gives rise to the problem of character sets. Solving character sets
gives rise to the problem of end-of-line and end-of-file conventions. Solving
that gets us to the problem of interpreting the low-level syntax (thus XML).
Then we need to interpet that syntax in terms of objects and properties (thus
RDF, WDDX, etc.). And so forth.
    We could judge a standard's success by its ability to reveal another level
of standardization that is necessary.
      -- Paul Prescod, 24 Jan 1999

I just want to go on the record as being completely opposed to computer
languages. Let them have their own language and soon they'll be off in the

t/data/python_quotes.txt  view on Meta::CPAN

"XML applications" and "XML parsers" which handle this gang- of-four concepts.
... Now we can peer over the parapet and shout "your parser smells of
elderberries" or "I wave my mixed content at your ankles", as long as we like
but the simple gang-of-four base apps will not go away.
      -- Sean McGrath, 19 Dec 1999

Abstraction is one of those notions that Python tosses out the window, yet
expresses very well.
      -- Gordon McMillan, 6 Jan 2000

The set of naming conventions has a cardinality equal to the number of Python
users.
      -- Gordon McMillan, 6 Jan 2000

The way to build large Python applications is to componentize and
loosely-couple the hell out of everything.
      -- Aahz Maruch, 6 Jan 2000

It's not the mail volume that bothers me -- I can ignore 100s of messages a day
very quickly. It's the time it takes to respond to all of them.
      -- Guido van Rossum, 20 Jan 2000

t/data/www.amk.ca/quotations/python-quotes/page-3.html  view on Meta::CPAN

<p class='quotation' id='q66'>Two things I learned for sure during
a particularly intense acid trip in my own lost youth: (1)
everything is a trivial special case of something else; and, (2)
death is a bunch of blue spheres.</p>
<p class='source'>Tim Peters, 1 May 1998</p>
<p class='quotation' id='q67'>Well, they will be: "&lt;" will mean
what everyone thinks it means when applied to builtin types, and
will mean whatever __lt__ makes it mean otherwise, except when
__lt__ isn't defined but __cmp__ is in which case it will mean
whatever __cmp__ makes it mean, except when neither __lt__ or
__cmp__ are defined in which case it's still unsettled. I think. Or
isn't that what you meant by "clearly defined"?</p>
<p class='source'>Tim Peters, 6 May 1998</p>
<p class='quotation' id='q68'>You write a great program, regardless
of language, by redoing it over &amp; over &amp; over &amp; over,
until your fingers bleed and your soul is drained. But if you tell
newbies <em>that</em>, they might decide to go off and do something
sensible, like bomb defusing&lt;wink&gt;.</p>
<p class='source'>Tim Peters, 5 Jun 1998</p>
<p class='quotation' id='q69'>OO styles help in part because they
make it easier to redo large parts over, or, when the moon is

t/data/www.amk.ca/quotations/python-quotes/page-3.html  view on Meta::CPAN

mind-if-i-use-that-as-my-epitaph&lt;wink&gt;?-ly y'rs - tim</p>
<p class='source'>Timothy J. Grant and Tim Peters, 22 Jun 1998</p>
<p class='quotation' id='q77'>&gt; Just for the record, on AIX, the
following C program:
Oh no you don't! I followed AIX threads for
the first year it came out, but eventually decided there was no
future in investing time in baffling discussions that usually ended
with "oh, never mind -- turns out it's a bug" &lt;0.9 wink&gt;.</p>
<p class='source'>Vladimir Marangozov and Tim Peters, 23 Jun
1998</p>
<p class='quotation' id='q78'>Python - why settle for snake oil
when you can have the <em>whole</em> snake?</p>
<p class='source'>Mark Jackson, 26 Jun 1998</p>
<p class='quotation' id='q79'>The problem I have with "SETL sets"
in Python is the same I have with every other language's "killer
core" in Python: SETL is much more than just "a set type", Eiffel
is much more than just fancy pre- and post- conditions, Perl's
approach to regexps is much more than just its isolated regexp
syntax, Scheme is much more than just first-class functions &amp;
lexical closures, and so on. Good languages aren't random
collections of interchangeable features: they have a philosophy and
internal coherence that's never profitably confused with their
surface features.</p>
<p class='source'>Tim Peters, 10 Jul 1998</p>
<p class='quotation' id='q80'>"Since I'm so close to the pickle
module, I just look at the pickles directly, as I'm pretty good at



( run in 1.625 second using v1.01-cache-2.11-cpan-49f99fa48dc )