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 perl. Show all posts
Showing posts with label perl. Show all posts

Quick reference

.

Mac: \r
Unix: \n
Windows: \r\n
vi s/,/,\r/
$CRLF = "\015\012";
perl -le'$q = "\047"; print $q' # single quote

unset PERL5LIB; unset PERL_LOCAL_LIB_ROOT; unset PERL_MB_OPT; unset PERL_MM_OPT; eval $(perl -Mlocal::lib=./local)

perl -MDevel::Cover=+ignore,.*,-select,^lib,-select,^t,-silent,on t/path/to/test.t

python -m SimpleHTTPServer 8080
python3 -m http.server 8080

warn "mojo response = ".$t->tx->res->to_string;
...->or(sub { diag("Result = ".$t->tx->res->to_string) });

use Data::Printer { class => { internals => 0, inherited => 'public' } };

my $r=\@_; $l->debug("entering ".( caller(0) )[3])." with ". sub { $l->dump(args => $r) }); # log calls to subroutines

patch -p0 < file.patch

DBIC_TRACE_PROFILE=console DBIC_TRACE=1
TEST_METHOD=foo

$Data::Dumper::Maxdepth = 1;

$DB::single = 1;

echo -ne "\033]0;"some title"\007" # set putty title

shopt -s checkwinsize; reset # fix terminal display issue

# bash strict mode
set -euo pipefail
IFS=$'\n\t'
# debug mode
set -vx

(s)printf:
printf '<%+d>', 12; # prints "<+12>"
printf '<%6s>', 12; # prints "< 12>"
printf '<%-6s>', 12; # prints "<12 >"

eval $(dircolors|sed 's/di=01;34/di=01;36/'); # light blue directories

if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root"
exit 1
fi

| python -m json.tool # sorts keys
| json_pp # doesn't sort keys (perl JSON module)

Search and replace over two lines:
sed ':a;N;$!ba;s/\n second line: / second line: /g'


Bash quotes: '\'' & '"'"'

print "debug = ".Dumper({%{{$_->get_columns}}{qw/id shipment_id/}}) foreach $shipment_rs->items; # DBIC quick peek

print $result->{_column_data} # DBIC quicker peek

require Carp; Carp::cluck "got here";

telnet host port

openssl s_client -debug -connect host:port

www.tablesgenerator.com

New software cheat sheet

 

## Languages

- Perl: best for fast prototyping
- Ruby: best for having fun
- Node: best for public projects
- Python: best for experiments

## Frameworks

### Perl

- DBIx::Class 💯
- Mojolicious 💯

### Node

- Express (popular)
- React?
- Koa?
- NestJS?
-....? for testing: Qunit?
-....? for web framework

### Python

- Django? (this one)
- Flask?

### Ruby

- Rails?
- Active Record?

## Libraries

### Perl

- just everything

### Node

- minimist reads command line arguments
- cheerio parses HTML
- daysjs manages dates/times
  - customParseFormat plugin parses dates
- knex does CRUD on databases
- fs perfoms operations on the file system
- import process from 'node:process'; // process.exit(1);

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

Pinto commands, working with pinto and cpm

# Check what's in Pinto CPAN mirror:

pinto list --root $PINTO_MIRROR | grep Your::Module | head -1

# ...or do the same locally (note the space after the module name)

grep 'Smurf::Foo ' ~/.perl-cpm/sources/$DARKPAN/02packages.details.txt

# Downgrade a module using cpm

cpm install --reinstall --no-prebuilt --resolver metadb --resolver 02packages,$DARKPAN_NAME $DARKPAN_FQDN_WITH_BASIC_AUTH/authors/id/U/UB/UBUNTU/Smurf-Foo-1.23.tar.gz


What "Wide character in print" means in Perl (hint: UTF8)

 It means there is a glitch in the matrix - agents are coming!

(further reading)

Improving Perl's Test2 documentation and using the metacpan docker image

#fixallthethings #tooling #fail on Mac OSX 13.6 High Sierra

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.

Mojolicious version 9 cheat sheet

Mojo 9 changes:

s/over/requires/

s/route/any/

s/via/methods/


Parse a Perl stack trace for ease of understanding

Problem:

A Perl stack track is difficult to parse with my inferior human brain; I want to align each line horizontally so that discrepancies jump out at me.

Solution:

This isn't the whole solution, but it goes some way towards it.

perl script.pl | grep -v ^eval | perl -plne'$len=300-length($_); $space=" "x$len; s/called at /${space}called at /'


Perl one-liner to decode JSON

 cat file.json | sed 's/\/\/.\+//' | perl -MData::Dumper::Concise -MJSON -n0777 -E '$r = decode_json($_); say Dumper($r)'

Debugging Perl data structures

Use Data::Tersify like this:

    print Dumper( tersify($complicated_data_structure) );


Quick guide: How to set up MySQL and PostgreSQL databases for Perl development

# The following means mysql is not running:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)


MySQL

INSTALL

sudo apt install -y libmysqlclient-dev mysql-client mysql-server

START

$ sudo service mysql start

SETUP

CREATE USER zaphod;

ALTER USER 'zaphod'@'%' IDENTIFIED BY 'some_pass';

GRANT ALL PRIVILEGES ON *.* TO 'zaphod'@'%'; -- makes zaphod an admin

FLUSH PRIVILEGES;

ACCESS

$ mysql -u zaphod -D some_db -p

ADMIN ACCESS

$ sudo mysql


PostgreSQL

INSTALL

sudo apt install -y postgresql libpq-dev

START

$ sudo service postgresql start

SETUP

create user zaphod;

\password zaphod

create database some_db;

grant all privileges on database some_db to zaphod;

ACCESS

$ psql -U zaphod -h localhost -d some_db

# specifying the host forces md5 (password) authentication. Otherwise default is "peer"

ADMIN ACCESS

$ sudo su postgres

$ psql


POD servers for Perl

You want to browse Perl embedded documentation (POD)
You have some software that was designed for browsing information: a web browser
You need a server to turn the POD into web pages and serve it to the browser.

You try one of these modules:
  • https://metacpan.org/pod/Pod::Browser
    • Uses Catalyst
  • https://metacpan.org/pod/Pod::Server
    • ?
  • https://metacpan.org/pod/Pod::Webserver
    • Very basic
    • Parsing much better than Pod::POM::Web, but still fails in places.
    • Contains all the Perl built-in modules, which I don't want to see.
    • How to run: podwebserver
  • https://metacpan.org/pod/Pod::POM::Web
    • Advanced design
    • Fails to parse nested tags
    • Contains all the Perl built-in modules, which I don't want to see.
    • How to run: perl -I $DOC_PATH -I $POD_POM_WEB_PATH -MPod::POM::Web -e server

Questions:
  • What is the reference implementation of a POD interpreter? `perldoc` just removes links and it is plain text only. So in what viewer do the links actually link to something?

Mojo::UserAgent request format

The get(), post(), etc. methods are both too magic, and not magic enough.

They do what I mean, but only if I remember the order or parameters. Luckily Perl has an easy solution to this problem: Named parameters! AKA Passing a hash, like a normal person.


Perl Postgres test fixtures

Test::PostgreSQL approach:


Test::DBIx::Class approach:


Sed example - removing lines

for file in `grep -r mysqld t|cut -d: -f1|uniq`; do sed -i -e '/use Test::mysqld/d; /Test::mysqld->new/N; /Test::mysqld->new/N; /Test::mysqld->new/N; /Test::mysqld->new/N; /Test::mysqld->new/N; /Test::mysqld->new/d; /traits/d' $file; done; find t -name '*-e' -delete


Result:


Devel::Cover patterns for Perl

One:
cover -delete PERL5OPT=-MDevel::Cover=-ignore,^local/ prove -r t cover -report html_basic

Another:
perl -MDevel::Cover=+ignore,.*,-select,^lib/,-select,^t/,-silent,on t/path/to/test.t cover

Or:

for file in `find t -name '*.t`; do perl -MDevel::Cover=+ignore,.*,-select,^lib/,-select,^t/,-silent,on $file; done

In full:

unset PERL5LIB; unset PERL_LOCAL_LIB_ROOT; eval $(perl -Mlocal::lib=./local)

export PERL5LIB="/home/will/alt/cpan/devel-cover/local/lib/perl5:$PERL5LIB"

PERL5OPT=-MDevel::Cover=-ignore,^local/ prove -I t/lib -lr t

perl -I /home/will/alt/cpan/devel-cover/local/lib/perl5 /home/will/alt/cpan/devel-cover/local/bin/cover