A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label module. Show all posts
Showing posts with label module. Show all posts

How to use DBIx::Class::Migration

There is a tutorial (note: links are broken), but this is a cheat sheet:

Use case A: Developing - initial setup

Step 0: Set up a database instance

Use dbdeployer, it's great.

Step 1: Generate the DBIx::Class Result classes

  • dbicdump
    • dbicdump -o dump_directory=lib -o components='["InflateColumn::DateTime"]' Smurf::Foo::DB 'dbi:mysql:database=foo;host=127.0.0.1;port=8022;user=msandbox;password=msandbox'
    • ...this will create:
      • lib/Smurf/Foo/DB.pm
        • Manually add: our $VERSION = 1; to this at the end.
      • lib/Smurf/Foo/DB/Result/Table1.pm, etc.

Step 2: Generate the DBIx::Class::Migration files

  • dbic-migration prepare
    • dbic-migration -I lib prepare --schema_class Smurf::Foo::DB --target_dir=share --dsn='dbi:mysql:database=foo;...etc'
    • ...this will create:
      • share/migrations/_source/deploy/1/001-auto.yml
      • share/migrations/_source/deploy/1/001-auto-__VERSION.yml
      • share/migrations/MySQL/deploy/1/001-auto-__VERSION.sql
      • share/migrations/MySQL/deploy/1/001-auto.sql
      • share/fixtures/1/conf/all_tables.json

Notes and gotchas

  • If you see a definition for dbix_class_deploymenthandler_versions anywhere, i.e. in lib/Smurf/Foo/DB/Result/DbixClassDeploymenthandlerVersion.pm then you're gonna have a bad time. This could mean you accidentally ran dbicdump after dbic-migration prepare. It will cause migrations to fail when they try to create the dbix_class_deploymenthandler_versions table from both 001-auto-__VERSION.sql and 001-auto.sql

Use case B: Making changes to the database

Step 3: Make changes and update files

  • Do not write any SQL
  • Make changes to the DBIC classes under `lib/Smurf/Foo/DB/Result`, but DO NOT MODIFY THE FIRST PART OF THE FILE (see DBIx::Class::Schema::Loader comments in those files)
  • Bump the version in `lib/Smurf/Foo/DB.pm` (or add it - at the bottom outside the auto-generated section: `our $VERSION = 2;`
  • Run `dbic-migration prepare --schema_class Smurf::Foo::DB --target_dir=share --dsn='dbi:mysql:database=foo;...etc'` to create a new migration in the `share` directory
  • Run `dbicdump -o dump_directory=lib -o components='["InflateColumn::DateTime"]' Smurf::Foo::DB 'dbi:mysql:database=foo;...etc'` to see if it makes any updates to the first part of the DBIC classes under `lib/Smurf/Foo/DB/Result`

Use case C: Not making changes to the database

Step 4: Install and upgrade as needed

  • Run dbic-migration install --schema_class Smurf::Foo::DB --target_dir=share --dsn='dbi:mysql:database=foo;...etc'
  • Run dbic-migration upgrade ...etc

How to install libxmlsec1 via Alien::LibXMLSec on Mac OSX

  1. Make sure openssl is installed
  2. Download Alien::LibXMLSec (it's not on CPAN)
  3. Unzip it & change to dir
  4. perl Makefile.PL
  5. PKG_CONFIG_PATH=/usr/local/Cellar/openssl@1.1/1.1.1k/lib/pkgconfig make
  6. make
  7. make install
Note: To get the Makefile.PL to run (i.e. step 3½), you may also need to:
  • git clone Alien::Build from its git repo
  • do a `dzil build` on that
  • then set the PERL5LIB to point to the built instance of Alien::Build
  • ...and also make sure its deps are in PERL5LIB.

How to install DBD::Pg Perl module on Mac OSX

Make sure `pg_config` is in your path, and that's it! DBD::Pg will build normally.

Debugging Perl data structures

Use Data::Tersify like this:

    print Dumper( tersify($complicated_data_structure) );


How to specify a library path when installing perl modules

Examples:

brew install openssl
export LDFLAGS=-L/usr/local/opt/openssl/lib
export CPPFLAGS=-I/usr/local/opt/openssl/include
export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
cpanm IO::Socket::SSL
Or:
cpanm --look Crypt::OpenSSL::X509
vim Makefile.PL
 + inc '-I/usr/local/opt/openssl/include -I/usr/include/openssl -I/usr/local/include/ssl -I/usr/local/ssl/include';
 + libs '-L/usr/local/opt/openssl/lib -L/usr/lib -L/usr/local/lib -L/usr/local/ssl/lib -lcrypto';
perl Makefile.PL
make
make test
make install

(source)



How to build a CPAN module

Not really, this is just a few rough notes.

https://metacpan.org/pod/Dist::Zilla::Tutorial - shows the format of dist.ini

http://dzil.org/tutorial/start.html

Still use a cpanfile, and also Dist::Zilla::Plugin::Prereqs::FromCPANfile

With dzil you can choose whether you want to generate a Makefile.PL or Build.PL

Changes:

Thanks to Nelo & the team.

Test Kerberos authentication

vi /etc/krb5.conf
/opt/mitk5/bin/kinit [username]

Perl: Try::Tiny vs TryCatch vs Syntax::Feature::Try

From NAP::Policy (thanks dakkar):

       Using TryCatch you’d write:

         try { ... }
         catch (SomeClass $e) { use($e) }
         catch (SomethingElse $e) { use($e) }
         catch ($e) { use($e) }

       Using Try::Tiny you’d write:

         try { ... }
         catch {
          # here you get the exception in $_
          when (match_instance_of('SomeClass')) { use($_) }
          when (match_instance_of('SomethingElse')) { use($_) }
          default { use($_) }
         }; # note the semi-colon

       On the other hand, if your TryCatch use did not have a unqualified "catch ($e)", you need to write "default { die $_ }" to re-throw the unhandled exception (yes, you really have to write "die
       $_", read the documentation of die to learn the ugly details; "die" without arguments won’t do anything useful there).

       Also, keep in mind that the blocks used by Try::Tiny are actually anonymous subroutines, so they get their own @_ (nothing in the case of the "try" block, the exception in the case of the
       "catch" block), and "return" will return from the block, not the containing subroutine.


      Devel::Declare (via TryCatch) is deep scary voodoo.


From #backend:

  • Try::Tiny is the less magical and scary (and fragile) version of TryCatch
  • Syntax::Feature::Try is currently the least offensive of the alternatives, but it has quite a way to go
    • it does nasty things with the call stack
    • preferrably it would splice the optree, like a compiler macro
  • How does return work? TryCatch returns from the surrounding sub, Try::Tiny returns form the try {} block

How are my Perl modules being loaded?

Large legacy system?
Confused about how your modules are being loaded?
Getting errors because they are loaded in the wrong order?

Try Devel::TraceUse

HTML::FormHandler example

package My::Form;

extends 'HTML::FormHandler';

has_field "age" (
    label => "Type",
    required => 0,
    type => 'Integer',
);

____________________________________________________________

package My::Handler;

my $form = My::Form->new;

if ($form->validated) {

    # validate form
    $form->process( params => $c->req->query_params );
    my @errors = $form->errors;
    alert("Error: $_") foreach @errors;

    my $age = $form->field('age')->value;
    $logger->info("User entered age $age");

    # build page
    $c->stash->{age} = $age;
}

Making a Perl module

Object oriented convention in Perl:

sub new
{  
    my ($class, %params) = @_;
    my $self = \%params;
    bless $self => $class;
    return $self;
}

XML::Validator::Schema

#!/usr/bin/perl

use XML::SAX::ParserFactory;
use XML::Validator::Schema;
# create a new validator object, using foo.xsd
$validator = XML::Validator::Schema->new(file => 'foo.xsd');
# create a SAX parser and assign the validator as a Handler
$parser = XML::SAX::ParserFactory->parser(Handler => $validator);
# validate foo.xml against foo.xsd
eval { $parser->parse_uri('foo.xml') };
die "File failed validation: $@" if $@;

The problem is:

Perl test template

Comments: Logging may be mostly useful for debugging -- the log level can be raised for release.

#!/usr/bin/perl

#################################################################################
# Description of tests
#################################################################################

use strict;
use warnings;

use Test::More qw(no_plan);
use Test::Differences; # eq_or_diff()
use Test::Lazy qw/try check/; # check() displays the expected & actual upon failure, even for scalars
use Log::Log4perl;
use XML::Simple qw(:strict);

Log::Log4perl::init('conf/log4perl-test.conf');
my $LOG = Log::Log4perl->get_logger('log4perl.appender.LOGFILE');

$| = 1; select STDERR;
$| = 1; select STDOUT;

$LOG->info("Started tests");

use_ok('MyNamespace::MyModule');

dies_ok { MyNamespace::MyModule->new } 'fail to instantiate without parameters';

my $m = MyNamespace::MyModule->new( url => "foo", name => 'bar');
isa_ok($m, 'MyNamespace::MyModule');

Create a Perl module structure

h2xs -cn MyModule

Read an internal Apache variable

...such as %{MY_MOD_OUTPUT_NOTE}n -- that would be available for logging, but not visible by mod_include.

RewriteEngine On
RewriteRule ^(.*)$ $1 [E=MY_MOD_ENV_VAR:%{ENV:MY_MOD_OUTPUT_NOTE}]

Scanning HTML

Screen scraping with HTML::TreeBuilder:

my $real_h1 = $tree->look_down(
    '_tag', 'h1',
    sub {
        my $link = $_[0]->look_down('_tag','a');
        return 1 unless $link; # no link means it's fine
        return 0 if $link->attr('href') =~ m{/dyna/}; # a link to there is bad
        return 1; # otherwise okay
    }
);