ACME-QuoteDB

 view release on metacpan or  search on metacpan

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');

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

use Exporter 'import';
our @EXPORT = qw/quote/; # support one liner

use Carp qw/croak/;
use Data::Dumper qw/Dumper/;
use ACME::QuoteDB::LoadDB;
use aliased 'ACME::QuoteDB::DB::Attribution' => 'Attr';
use aliased 'ACME::QuoteDB::DB::QuoteCatg'  => 'QuoteCatg';
use aliased 'ACME::QuoteDB::DB::Category'  => 'Catg';
use aliased 'ACME::QuoteDB::DB::Quote'    => 'Quote';

binmode STDOUT, ':encoding(utf8)';
binmode STDERR, ':encoding(utf8)';

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    return $self;
}

# provide 1 non OO method for one liners
sub quote {
    my ($arg_ref) = @_;
    return get_quote(q{}, $arg_ref);
}

# list of quote attributions (names) (makes searching easier)
sub list_attr_names {
   return _get_field_all_from('name', Attr->retrieve_all);
}

# list of quote categories
sub list_categories {
   return _get_field_all_from('catg', Catg->retrieve_all);
}

## list of quote sources
sub list_attr_sources {
   return _get_field_all_from('source', Quote->retrieve_all);
}

sub _get_field_all_from {
   my ($field, @all_stored) = @_;

    my $arr_ref = [];
    RECORDS:
    foreach my $f_obj (@all_stored){
        my $s = $f_obj->$field;
        # if doesn't exist and not a dup
        if (! $f_obj->$field || scalar grep {/$s/sm} @{$arr_ref}){
            next RECORDS;
        }
        push @{ $arr_ref }, $f_obj->$field;
    }
    return join "\n", sort @{$arr_ref};
}

sub _get_attribution_ids_from_name {
    my ($attr_name) = @_;

    my $c_ids = [];
    # a bug: what if string starts with what we specify
    #i.e. => %Griffin% doesn' match 'Griffin' (no quotes)
    RESULTS:
    foreach my $c_obj (Attr->search_like(name => "%$attr_name%")){
       next RESULTS unless $c_obj->attr_id;
       push @{ $c_ids }, $c_obj->attr_id;
    }

    if (not scalar @{$c_ids}) {
        croak 'attribution not found';
    }

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


    # category/quote is a many to many relationship: 
    # 1 quote can be in many categories. (and of course 1 category can have many quotes)


=head4 Example of L<Delete|/Delete>

    # delete a quote from the database
    $sq->delete_quote({QuoteId => $quote_id});
    

=over 2

=item record format

One full quote database record currently consits of 5 fields:

Quote, AttrName, Source, Rating, Category

    Quote     => 'the quote desired' # mandatory
    AttrName  => 'who said it'       # mandatory
    Source    => 'where was it said'
    Rating    => 'how you rate the quote/if at all',
    Category  => 'what category is the quote in',

For example:

    Quote     => 'Hi, I'm Peter,...",
    AttrName  => 'Peter Griffin',
    Source    => 'Family Guy',
    Rating    => '8.6',
    Category  => 'TV Humor',

=item * NOTE: In order for this module to be useful one has to load some quotes
 to the database.  Hey, just once though :) (see below - L<Loading Quotes|/"LOADING QUOTES">)

=back

=head1 OVERVIEW

Easy, quick auto-CRUD access to a collection of quotes. (which you provide)

Some ideal uses for this module could be:

=over 4

=item 1 

Quotes Website (quotes/movie/lyrics/limerick/proverbs/jokes/etc)

=item 2 

perl replacement for 'fortune'

=item 3 

Dynamic signature generation

=item 4 

international languages (has utf8 support)

=item 5 

convenient storing/sharing collections of quotes

=item 6 

for me to finally have a place to store (and manage) quotes (that can
be easily backed up or even to a remote db if desired)

=item 7 

anywhere perl is supported and 'quotes' are desired.

=item 8

others? (let me know what you do, if you want, if you do)

=back

See L</DESCRIPTION> above

Also see L<ACME::QuoteDB::LoadDB>


=head1 USAGE

    use ACME::QuoteDB;

    my $sq = ACME::QuoteDB->new;

    print $sq->get_quote;

    # examples are based on quotes data in the test database. 
    # (see tests t/data/)

    # get specific quote based on basic text search.
    # search all 'ralph' quotes for string 'wookie'
    print $sq->get_quotes_contain({
                  Contain   => 'wookie', 
                  AttrName => 'ralph',
                  Limit     => 1          # only return 1 quote (if any)
           });
    # output:
    I bent my wookie.
    -- Ralph Wiggums

    # returns all quotes attributed to 'ralph', with a rating between 
    # (and including) 7 to 9
    print join "\n",  @{$sq->get_quotes({
                                          AttrName => 'ralph', 
                                          Rating    => '7-9'
                                        })
                       };
    
    # same thing but limit to 2 results returned
    # (and including) 7 to 9
    print join "\n",  @{$sq->get_quotes({
                                          AttrName => 'ralph', 
                                          Rating    => '7-9',

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

   $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


For more see L<ACME::QuoteDB::LoadDB>


=begin comment
 
    keep pod coverage happy.

    # Coverage for ACME::QuoteDB is 71.4%, with 3 naked subroutines:
    # Attr
    # Quote
    # Catg
    # QuoteCatg

    pod tests incorrectly state, Attr, Quote and Catg are subroutines, well they
    are,... (as aliases) but act on a different object. 
    
    TODO: explore the above (is this a bug, if so, who's?, version effected, 
    create use case, etc) 
    
=head2 Attr

=head2 Quote

=head2 Catg

=head2 QuoteCatg

=end comment

=head1 DIAGNOSTICS

An error such as:

C<DBD::SQLite::db prepare_cached failed: no such table: ,...>

probably means that you do not have a database created in the correct format.

basically, you need to create the database, usually, on a first run

you need to add the flag (to the loader):

create_db => 1, # first run, create the db

appending to an existing database is the default behaviour

see L<ACME::QuoteDB::LoadDB/create_db_tables>

=head1 CONFIGURATION AND ENVIRONMENT

if you are running perl > 5.8.5 and have access to
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. 

Module usage wise, all operations are the same but now
you will be writing to the remote mysql database specified.

(The user will need read/write permissions to the db/tables)
(mysql admin duties are beyond the scope of this module)

The only supported databases at this time are sqlite and mysql.

It is trivial to add support for others

=back



( run in 0.224 second using v1.01-cache-2.11-cpan-fd5d4e115d8 )