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

Perl: Debugging DBIx::Class with DBI

If your code uses DBIx::Class, but you want to debug using DBI:

     while (my ($name, $s) = each %{{
         'MySQL' => ...->get_schema(),
         'SQLite' => ...->get_schema(),
     }}) {
         diag("\n\n>> $name schema\n\n");
         foreach my $table qw(a b c) {
             my $r;
             eval { $r = $s->storage->dbh->selectall_arrayref("SELECT * FROM $table"); };
             if ($@) { note("No table $table"); }
             else { note(scalar(@$r)." rows in $table"); }
         }
     }

My .bashrc config

# general:
export PATH="~/scripts:$PATH"

alias ls="ls -F --color"
alias grep="grep --color=auto"

# git aliases
function gitdiff() {    git diff --no-ext-diff -w "$@" | vim -R -
}

function gitlog() {
    git log --name-only "$@"
}

function gitcommit() {
    git --no-pager diff --no-ext-diff
    echo
    read -p "Are you sure you want to commit these changes? " yn
    case $yn in
        [Yy]* ) git commit "$@"; break;;
    esac
}

# git prompt
host_colour="01;34"
export PS1="\[\033[${host_colour}m\]\h\[\033[00m\]/\u \t \w \$ "

function __git_commits_behind {
    if [ -d .git ]
    then
        git st | perl -ne'm{Your branch is behind.+by (\d+) commit} && print "behind $1< "'
    fi
}

function __git_commits_ahead {
    if [ -d .git ]
    then
        git st | perl -ne'm{Your branch is ahead of.+ by (\d+) commit} && print "ahead $1> "'
    fi
}

function update_prompt {
    local branch=$(git branch --no-color 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /')
    export PS1="\[\033[${host_colour}m\]\h\[\033[00m\]/\u \[\033[${branch_colour}m\]${branch}$(__git_commits_behind)$(__git_commits_ahead)\[\033[00m\]\t \w \$ "
}
export PROMPT_COMMAND=update_prompt

Switch for Perl done right

Instead of the horribly flaky 'Switch' module, from Perl 5.10 you can now do:

use feature "switch";

given($_) {
    when (/^abc/) { $abc = 1; }
    default { $nothing = 1; }
}
 
See http://perldoc.perl.org/perlsyn.html#Switch-statements

vimdiff fun with git

Step 1: add this to your .gitconfig
[diff]
  external = git_diff_wrapper
[pager]
  diff =


Step 2: create a file named git_diff_wrapper, put it somewhere in your $PATH
#!/bin/sh
vimdiff "$2" "$5"


Still have access to the default git diff behavior with the --no-ext-diff flag. Here’s a function to put in your bash configuration files:
function git_diff() {
  git diff --no-ext-diff -w "$@" | vim -R -
}


Source: http://technotales.wordpress.com/2009/05/17/git-diff-with-vimdiff/

Git setup

git config --global user.name "Your Name Comes Here"
git config --global user.email you@yourdomain.example.com

git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto

git config --global core.editor vim

Redirects behave weirdly in Chrome

Chrome (un)helpfully caches redirects sometimes.
Try using an incognito window and the behaviour should make more sense.

Moving a wordpress e-commerce site

  • UPDATE wp_options SET option_value="http://newsite/new_dir" WHERE option_value="http://oldsite/old_dir"; -- this fixes most of the site
  • UPDATE wp_options SET option_value="http://newsite/new_dir" WHERE option_value="http://oldsite/old_dir"; -- this fixes the pagination for the e-commerce plugin.
  • In .htaccess:

    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-f [NC]
    RewriteCond %{REQUEST_FILENAME} !-d [NC,OR]
    RewriteCond %{REQUEST_URI} / [NC]
    RewriteRule ^(.*)$ /new/$1 [L,QSA]

Importing with Wordpress

If you get a 500 Internal Server Error while importing a large file in Wordpress:

  • Just keep refreshing the page and re-submitting the data.
  • Items will continue to be added (and downloaded) a few at a time, and no item will be added twice.
Eventually all the data will be imported correctly.

Move directory on FTP server

without downloading and re-uploading:

rnfr source_dir
rnto target_dir

Debugging websites

CSS:
element {
    outline: red solid thick;
    background: green;
};

PHP:
<?php $debug = $_GET['debug'] ?>

Email clients on Ubuntu

Linux email clients for Microsoft Exchange:
  • Evolution: Ugh. Clunky. Hangs.
    • "Microsoft Exchange" server type screen scrapes webmail
    • MAPI needs the 'evolution-mapi' package from Ubuntu software centre
    • Otherwise IMAP
  • Thunderbird: Pfft. Also clunky. Hangs slightly less than Evolution, sometimes.

Diff fun with vi and svn

Diff two files side-by-side
(search for this to highlight differences only -- replace ^I with actual tabs -- / <^I| <$| >^I| >$| \|^I )
diff --side-by-side [a] [b] | less

Diff two files side-by-side using vi
(use Ctrl-W+W to switch sides; may need :syntax off to prevent colours clashing)
vimdiff [a] [b]

Subversion diff using vi
Step 1. Create a diff command script for svn (and set the execute bit):
#!/bin/sh
# Subversion provides the paths we need as the sixth and seventh parameters.
LEFT=${6}
RIGHT=${5%    (working copy)}
[ "$RIGHT" == "$5" ] && RIGHT=$7
# Call the diff command (change the following line to make sense for your merge program).
# diffopt+=iwhite ignores whitespace differences
# \<c-w>\<c-w> switches to the right-hand pane
vimdiff "+set diffopt+=iwhite" '+execute "normal \<c-w>\<c-w>"' $LEFT $RIGHT


Step 2. Create a diff script for you to use:
#!/bin/bash
# Call the diff command (change the following line to make sense for your merge program).
# "-x -w" ignores all whitespace
svn diff -x -w --diff-cmd /path/to/diff/command/script/above $1


Step 3. Run the diff script
name_of_your_script [file in workspace]

Good FTP clients

  • WinSCP (Windows)
  • WS FTP LE (Windows)
  • FileZilla (Windows, Linux)
  • FireFTP (Windows, Linux)

Music players on Ubuntu

I haven't yet found software for Linux that equals Winamp on Windows, for ease of playlist manipulation.

  • Movie player - ugh
  • Banshee - Can't easily work with albums. Play Queue is too fiddly. Can't copy music between Play Queue, File System Queue and Playlists.
  • Amarok - Better than Banshee. Actually lets me see my directories on disk! Easy to make playlists.
  • Clementine - Works. Easy to browse files, easy to make playlists.
  • XMMS - ?
  • Audacious - ?
  • Rhythm box - ?
  • Songbird - ?


thanks

Know if output is being captured in Perl

if (-t STDERR) {
    print "standard error is not being captured (it's going to the terminal)\n";
    # email the error
}
else {

    print "standard error IS being captured\n";
    # just print the error
}

Developing over FTP

Using Eclipse and RSE plugin:
  • Logs in okay
  • But seems to always be closing directory sub-trees I've opened in 'Remote Systems' panel
  • It wants to do an 'ls' on every parent directory in the hierarchy, every time I change files. Very slow.
Using CurlFtpFS:
  • Install in Ubuntu from the software centre
    • to mount: curlftpfs -v username:password@server.example.com local_dir/
    • to unmount: fusermount -u local_dir/
  • Performance is unusably slow... Eclipse wants to know about every single file on the remote server, not just the ones I'm editing.
  • Saving the file through Eclipse using CurlFtpFS takes even longer than it would to upload it separately.
Using FileZilla and gedit:
  • Browsing is fast
  • Editing is fast
  • But you have to navigate to every file manually each session, it doesn't remember what you had open
  • The system of holding temp files locally is not ideal, but FileZilla detects changes in them very nicely
  • You still can't grep over the files as they're all held remotely, and it's a bit fiddly to navigate to a specific file
    Editing locally with Eclipse, and uploading after changes are made:
    • Write an Ant script to upload any modified files?
    • ...to investigate

    Using vim's viewports

    • :sp [filename] will split the Vim window horizontally
      • Can be written out entirely as :split
      • [filename] is optional, if it's omitted then the current file is loaded in the new viewport
    • :vsp [filename] will split the Vim window vertically
      • Can be written out as :vsplit
    • Ctrl-e [filename] loads a new file into the current viewport
    • Ctrl-w Ctrl-w moves between Vim viewports.
    • Ctrl-w j moves one viewport down.
    • Ctrl-w k moves one viewport up.
    • Ctrl-w h moves one viewport to the left.
    • Ctrl-w l moves one viewport to the right.
      • Can also use the arrow keys instead of h/j/k/l
    • Ctrl-w = tells Vim to resize viewports to be of equal size.
    • Ctrl-w - reduce active viewport by one line.
    • Ctrl-w 10- reduce active viewport by ten lines.
    • Ctrl-w + increase active viewport by one line.
    • Ctrl-w 10+ increase active viewport by ten lines.
    • Ctrl-w q will close the active window.
    • Ctrl-w r will rotate windows to the right.
    • Ctrl-w R will rotate windows to the left.


    Full article

    Run bash in a viewport, with this plugin (easy installation).

    Macro recorders for Windows 7

    Testing on Windows 7 Pro (SP1), in a Virtual Box (VM) window, running under Ubuntu 11.04.
    • AutoHotKey - scripting only, but users have built a recorder too.
      • Overall good. Free.
      • Steep learning curve, but users on IRC channel are very helpful
      • Note: Trying running program in "Administrator mode" if it doesn't seem to work.
      • How to develop scripts:
        • Use Recorder to get basic outline
        • Use included Window Spy to get precise coords (set "CoordMode, Mouse, Screen")
        • May need to fiddle with WinActivate parameters
        • Put sections of functionality into subroutines and test them individually
        • Use TrayTips as debug output
        • Make sure you make the script Sleep for at least 300ms between each action
    • Quick Macro - Couldn't get it to work. Shareware.
    • Auto Macro Recorder - Couldn't get it to work, either. Shareware.
    • PC Anywhere - Couldn't even download it.

    How to checkout hosted subversion project

    Google code:

    svn checkout https://example.googlecode.com/svn/trunk/ example_directory --username example@gmail.com

    Assembla:

    svn checkout https://subversion.assembla.com/svn/example/ example_directory --username your_username


    Timing out a call to a remote service in Perl

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    select STDERR; $| = 1;
    select STDOUT; $| = 1;
    
    my $server = 'remote server';
    
    my $timeout = 3;
    my $retries = 3;
    my $retry = 1;
    my $con = 0; # connection object
    my $err; # error message
    while (not $con and not $err and $retry <= $retries) {
        print "starting block...\n";
    
        eval {
            print "eval'ing\n";
            local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
            alarm $timeout;
            # make connection to server
            sleep $timeout + 1; # fake
            # if we reached here, the connection was successful
            alarm 0;
        };
        if ($@) {
            if ($@ eq "alarm\n") {
                # timed out
                print "Timed out $retry time(s) connecting to $server\n";
            }
            else {
                print "died unexpectedly\n";
                $err = $@;
                $err =~ s' at /[\w\./]+\.pm line \d+$'' if $err;
            }
        }
        else {
            print "No problem!!!\n";
            $con = 1;
        }
        $retry++;
    }
    
    
    print "ERROR: $err\n" if $err;
    
    print "finished. connection = '$con'\n";
    

    Parse XML in PHP

    http://php.net/manual/en/function.file-get-contents.php - fetch URL
    http://php.net/manual/en/simplexmlelement.xpath.php - parse XML
    http://www.php.net/manual/en/simplexml.examples-basic.php - register namespaces, etc.

    Example for Google calendar. Most important parts are the namespaces and (string) casting.

        $contents = file_get_contents($calendar_url); // should end with 'full', not 'basic'
        $xml = new SimpleXMLElement($contents);
    
        $namespaces = $xml->getDocNamespaces();
        $xml->registerXPathNamespace('__empty_ns', $namespaces['']);
        $xml->registerXPathNamespace('gd', 'http://schemas.google.com/g/2005'); # xmlns:gd='http://schemas.google.com/g/2005'
    
        $entries = $xml->xpath("//__empty_ns:entry");
        while(list( , $node) = each($entries)) {
            $time_nodes = $node->xpath("gd:when/@startTime");
            while ($time_node = each($time_nodes)) {
                # <gd:when endTime="2011-08-19T17:00:00.000+01:00" startTime="2011-08-19T14:00:00.000+01:00"></gd:when>
    
                $time_text = (string)$time_node[1]->startTime;
    
                die "time = $time_text\n";

    Parse HTML with Ruby and Nokogiri


    doc = Nokogiri::HTML(open(filename, 'r'))
    puts doc.xpath('//title')[0].inner_html
    puts doc.xpath('//h2')

    Ruby: Read+write to database


    require 'sqlite3'

    db = SQLite3::Database.new( "db1" )
    db.execute('INSERT INTO table_name (id, text) VALUES (1, "hello")')
    db.execute( "SELECT* FROM table_name" ) do |row|
        puts row.inspect
    end

    Add-ons for Thunderbird

    • Lightning = a calendar
    • Mailbox Alert = pop up a message for important emails (first set a rule to copy them to a folder, then right click on the folder to set the Mailbox Alert)

    Pop up a message box in Ubuntu

    Try gmessage, xmessage or zenity (in that order)
    But none of them force the window to always appear over other windows.

    Display upcoming code in Perl debugger

    Type this after the debug session has started:
    > @DB::typeahead=('v')
    or
    {{v

    See also these questions and perldebug.

    How to install perl modules into a local directory

    instead of:
    perl Makefile.PL
    try:
    perl Makefile.PL PREFIX=/path/to/your/directory/perllibs
    or:
    perl Build.PL PREFIX=/path/to/your/directory/perllibs

    Delete a file starting with a dash

    You accidentally created a file called "-.log"

    To delete it, instead of
    rm -.log
    try
    rm ./-.log

    Reasons to split up a very long subroutine into several more subroutines

    • Repetition
      • If the same or very similar code is being called several times, it should be put into a subroutine to avoid code duplication.
      • This is the most obvious reason.
    • Clarity
      • You should be able to read the code like English
      • Reading the code in a top level subroutine or script should give an overview of what it does, without going into detail
      • Each subroutine should be able to be easily described in one or two sentences
      • Comments are not sufficient for this, as you would still have to scan through many pages to gain an understanding. 
      • This reason is controversial; Some people say repetition is the only valid reason (see 'dangers' below)
    • Testing
      • You should be able to test each conceptual part of the system separately.
      • It should be obvious to which part of the system a unit test applies.


    Dangers of the second two reasons:
    - Too much abstraction, difficult to understand and follow code flow
    - Code is slow because of overhead of creating and managing subroutines

    Allow your customers to contact you easily

    Live chat
    olark is designed to let your customers chat to you. It works great on spoofcard.com.
    It's also possible to use adium or pidgin in this manner.

    Feedback
    getsatisfaction is free, uservoice isn't. Maybe there are other services, too.

    Web scraping with Ruby

    In order of goodness:

    • Nokogiri
    • Hpricot
    • Scrapi

    Dedupe lines in place

    in vim, select a list of values with shift-V (visual mode), and then type :sort u to sort them and remove duplicates.

    Password protect a directory in Apache

    Put a .htaccess file in the directory you want to protect, containing:

    AuthUserFile /full/path/to/your/htpasswd_file
    AuthGroupFile /dev/null
    AuthName "Password Protected Area"
    AuthType Basic



    require valid-user


    Then use an online htpasswd generator to create the htpasswd_file at the location you specified for AuthUserFile above. Make sure this is outside your public webspace.

    Add to breadcrumb trail in phpBB

    Do this before loading the template:

    $template->assign_block_vars('navlinks', array(
        'FORUM_NAME'    => "link display text",
        'U_VIEW_FORUM'  => "http://url-of-page"
    ));

    Sorting in Perl

    Custom sorting method:

    @sorted = sort { 
      if ($a eq 'aardvark') { return 1; }
      elsif ($b eq 'aardvark') { return -1; }
      else { return $a cmp $b; } 
    } @words;

    Remember to test for the special case for both $a and $b.


    Thanks

    Common admin tasks in phpBB 3

    Change the author of a post:

    • Click on the post
    • Click on the "Moderator Control Panel" link in the top left
    • Click on the "Post details" link on the right-hand side (note: It might look like a triangle with a question mark in it)
    • Scroll down to the bottom of the post, and you will see a drop-down menu to change the poster.

    Easiest way to find yesterday's date in Perl

    my ($year, $month, $day) = (localtime(time + 7 * 24 * 60 * 60))[5,4,3];
    $year += 1900;
    $month++;

    svn: Files skipped

    Is subversion displaying a message that some files/directories were "skipped" ?
    If you are using symlinks, try cd'ing into the directory, or using the full path instead.

    Prevent spammers from harvesting your email address

    When you write your email address on a web page, use &#64; instead of @, and &#46; instead of the dot.
    That way, most email harvesting programs won't recognise it.

    Here's a method using Javascript that should stop 100% of email harvesting programs.

    However, just using a web contact form would work best.

    Find dodgy characters in a file

    This will print any characters with values higher than 127, i.e. non-ascii characters that might look like ascii, but really be breaking your processor.

    perl -lne'while (my ($c) = $_ =~ m{^(.)}) { print "$c = ".ord($c) if ord($c) > 127; $_ =~ s/^.// }' file_to_check.something


    A quick, manual way to confirm some characters really are what you think they are:

    cat file_to_check.something | od -bc

    Require a parameter/variable in bash

    FILE=$1
    if [[ -z "$FILE" ]]; then echo "usage: script_name.sh [filename]"; exit 1; fi

    # don't forget the quotes around "$FILE", they will be required if $FILE has a space in it, and always use double [[ ]]

    Add a pause to a bash script

    read -p "Press any key to start backup..."
    thanks

    How to add a custom PHP page to phpBB3

    There is a tutorial explaining how to add a static HTML page, with phpBB header and footer.
    This is how to add a dynamic PHP page in a similar way:
    1. Go to ACP | General | Security settings, and set "Allow php in templates" to "Yes".
    2. Follow the tutorial at: http://wiki.phpbb.com/Practical.Add_custom_page
    3. In the template (e.g. about_us.html), replace where it says "Content in here" with <!-- INCLUDEPHP relative/path/to/your/php/page.php -->

    Perl: Fix DBI::db->disconnect invalidates 1 active statement handle

    Add this subroutine to the module:

    sub DESTROY {
        my ($self) = @_;
        # Finish off our statement handle, so we don't get warnings like:
        # DBI::db->disconnect invalidates 1 active statement handle
        my $sth = $self->{data_handle};
        if (blessed($sth) && $sth->can('finish')) {
            $sth->finish;
        }
    }

    Things lacking in Eclipse for Perl

    Using EPIC
    • You can't fold code on 'if' blocks, or any arbitrary block (only on subs and perldocs).
    • Word wrap causes the line numbers to be wrong (a single wrapped line has more than one line number)
    • Syntax highlighting is not a perfect fit (perhaps this or these might help):
      • POD and heredoc are both marked as 'Comment2' and so can't be different colours
      • Even though there is a 'Markup' entry, it doesn't seem to be used for POD
      • The colour of dollar signs can't be changed (it's the same as the variable name in vim)
      • Neither variables nor special characters change colour within interpolated strings (as in vim)

    How to change a shape type in Visio

    Install the "Super Utilities and Tools" add-in from Paul Herber's Sandrila Ltd.

    Use the 'Shape | Substitute' command.

    Create Eclipse project with existing files

    • Have your workspace as the directory above the directory containing your files.
    • Create the project with a name that is the same as your files directory.
    The problem is, if there are lots of (unrelated) files, Eclipse will take a long time to load up.

    There are other options, i.e.:

    • Create a new folder
    • Click the 'Advanced' button
    • Link to an external folder

    sshfs on linux

    • sshfs -o uid=1000 -o gid=1000 example.com:/workplace /workplace
    Where 1000 is your user and group ID from /etc/passwd

    That's it!

    Make a layer transparent in GIMP

    • Create a blank layer, filled with white
    • Right-click on the layer and choose 'Add Layer Mask'
    • Select 'Grayscale copy of layer'
    • Fill or draw on the layer with any colour (e.g. shades of gray)
      • the darker black you go, the more transparent the layer will become

    Example ssh config

    Host [alias]
        HostName [remote hostname]
        User [remote username]
        IdentityFile [file]

    [alias] is what you type to select the connection, e.g. ssh [alias]
    [file] is your DSA or RSA private key file

    Toggle comments in vi

    Add a comment for one line only:
    &

    A unary-plus sign before a package name in Perl

    ok +Some::Package::Foo->a_method_call($var), 'test succeeded';

    This is to get around Perl's 'indirect object syntax'.
    Otherwise
    ok Mock::Basic->update(...);
    looks like
    Mock::Basic->ok->update(...);
    which is probably not what is intended.
    ok(Mock::Basic->update(...)); works as well.

    It tells the parser "Hi. Since I have a leading (unary) plus sign, I'm now a scalar expression, so I qualify to match the first item in ok()'s prototype; please do not get confused and interpret me as a class name you should call an ok() method on."

    Demonstration:
    perl -MCGI -MTest::More -e'ok 1, "ok"; ok +CGI->new, +CGI->new; ok scalar CGI->new, "scalar"; ok( CGI->new, "brackets" ); ok CGI->new, "no plus";'
    ok 1 - ok
    ok 2 - CGI=HASH(0x8b68c0)
    ok 3 - scalar
    ok 4 - brackets
    Undefined subroutine CGI::ok
     at -e line 1

    See alsoand

    What a solitary underscore in Perl means

    It represents the previous 'stat' structure, saving a system call.
    See: http://perldoc.perl.org/5.8.8/functions/-X.html
    and http://perldoc.perl.org/5.8.8/functions/stat.html

    Get a full backtrace upon Perl error

    $SIG{__DIE__} = \&confess;

    How to tell if a perl script is only being syntax checked

    The special variable $^C will be true if the script is only being compiled with: perl -c script.pl

    Different ways to set up a database test in Perl

    • Use a DBI wrapper subroutine to code up each SQL statement:
      • pros: all the data is kept inside each test, and you can put Perl comments next to the SQL statements
      • cons: you have to translate the SQL statements into Perl and back for testing/debugging
    subtest 'a' {
        clear_db;
        db_wrapper( db => 'db1' sql =>'INSERT INTO table_a SET x = ?, y = ?', bind_values => [1, 2]);
        # do something
    }
    subtest 'b' {
        clear_db;
        db_wrapper( db => 'db1' sql =>'INSERT INTO table_a SET x = ?, y = ?', bind_values => [1, 3]);

        # do something
    }
    • Put all the statements inline, in the DATA section, and use a special subroutine to read them all:
      • pros: the database statements stay in SQL format
      • cons: you have to use different ID numbers for each test, 
    setup_db_once( data => \*DATA );
    ...
    subtest 'a' { # do something with first row }
    subtest 'b' { # do something with second row }
    ...
    __DATA__

    INSERT INTO table_a SET x = 1, y = 2
    INSERT INTO table_a SET x = 5, y = 6
    • Use a DBI wrapper subroutine to read SQL statements from an inline heredoc:
      • all the pros and none of the cons
    subtest 'a' {
        clear_db;
        setup_db_per_test( data => <<EOM
    INSERT INTO table_a SET x = 1, y = 2
    EOM;
        # do something
    }


    subtest 'b' {

        clear_db;
        setup_db_per_test( data => <<EOM
    INSERT INTO table_a SET x = 1, y = 3

    EOM;
        # do something
    }

    Mock modules & Rules of mocking for Perl tests

    Mock modules

    • Test2::V0 - I really must start using this soon. See Test2::Mock and possibly Test2::Tools::Mock
    • Test::MockObject - Works. Has set_isa() to pass Moose constraints. Start with an empty object and add methods as needed. This one.
      • see also Test::MockObject::Extends 
    • Test::MockModule - "Override subroutines in a module for unit testing".
      • Does not fool Moose (modules appear as Test::MockModule instead of what they are).
      • Only overrides the methods you say.
      • Has strict mode (can't accidentally mock non-existent methods)
      • Has an 'original()' function for wrapping methods (source):
        • my $mock = Test::MockModule->new("MyModule");
          $mock->redefine("something", sub { my ($self, $args) = @_; push @record_for_testing_later, $args;
                  return $mock->original(@_);
          });
    • DBD::Mock - don't use this, use Test::DBIx::Class (with DBIx::Class::Fixtures) or a real test database.
    • Test::Mock::Class - looks clunky
    • Mock::Quick - another one, syntax may be better. "less side effects", doesn't reload modules.
      • To call original un-mocked method, use (source):
      • my $mock = qtakeover 'Some::Module' => (
            id => sub {
                my ( $mock_self, @args ) = @_;
                $counter->{id}++ if scalar @args;
                return $mock_self->MQ_CONTROL->original('id')->( $mock_self, @args );
            },
        );

    Reasons to use Mock::Quick

    Monkey patching modules

    • Manually overriding subroutines AKA monkey patching - risky. What if you miss a method? Same as what Test::MockModule does.
      • example: { package X; *method_name = sub { return 'foo'; } }
    • Class::Monkey
    • Monkey::Patch
    • Mojo::Util::monkey_patch
    • Sub::Override
    • Mock::Sub - another one
    • Mock::MonkeyPatch
      • Can easily call original sub with Mock::MonkeyPatch::ORIGINAL

    Rules of mocking

    Don't monkey patch. Don't modify the symbol table directly like this:
    *Acme::Foo::method = sub { return "mock you"; }

    Instead use Test::MockModule or Sub::Override or similar. Reasons:
    • If you type the method name wrong, or if it gets moved, it becomes so obvious that it can't be missed
    • You won't continue to test code that doesn't exist anymore
    The first rule of mocking is: Don't mock.

    Instead use dependency injection. If you think you want to use a mock:
    • instead expose the object as an attribute,
    • and pass in one mock object once
    • this is easier to develop & maintain than mocking different things in every test
    • and less prone to leakage between tests
    Or if you need a mock method to be in place when an app is instantiated, add logic in the attribute to load a custom object from config, or default to the real object if nothing found in config:
    • create a test class like Foo::Test that inherits from Foo
    • override the dangerous methods
    • add test code: my $test_foo = Foo::Test->(@test_args)
    • and then: $t = Test::Mojo->new("App", { foo => $test_foo });
    • instantiate like this: $class = $config->foo || Foo->new(@args)
    • if necessary, the main library and test library should share an abstract interface (implemented via a role)
    Only if all the above fail, use MockModule. Note that scope can matter when using set_isa()

    Patch

    patch -p0 < patch.file

    Trace the execution of subroutines under mod_perl

    1) First try one of these to trace every line (doesn't actually capture subroutine names):

    Debug::TraceDebug::LTraceDevel::Trace, or others.

    2) Then if you want to filter the list, try:

    perl PERL5DB='sub DB::DB {my @c=caller;return if $c[1] =~ m|/opt/foo/bar| || $c[1] =~ m|/qux/| || $c[1] =~ m|Useless|; print STDERR qq|@c[1,2] ${"::_<$c[1]"}[$c[2]]|}' perl -d path/to/test/file.t

    (thanks Brian)

    3) Here's one I came up with using Moose:

    use Moose;
    use Scalar::Util;
    use Data::Dumper;
    for my $func qw(list all the subroutine names here) {
        around $func => sub {
            my $orig = shift;
            my $self = shift;
            warn "Running __PACKAGE__::${func} with:\n";
            my $i = 0;
            foreach my $param (@_) {
                $i++;
                # don't display class it$self
                next if blessed $param and $param->isa(__PACKAGE__);
                if (blessed $param) {
                    # try not to dump out huge objects
                    warn "\t$i = $param\n";
                } else {
                    warn "\t$i = ".Dumper($param);
                }
            }
            # call the original sub
            $self->$orig(@_);
        }
    }

    4) Simple way to log all parameters:

    my $r=\@_; $logger->debug('entering ', sub { $logger->dump(args => $r) });

    5) Simple way to log method name only, without potentially verbose parameters:

    $logger->info("entering ".( caller(0) )[3]);

    6) Log4perl configuration

    Use %M to log the method name, then just log anything, e.g. "entering".



    Open files from the command line in Ubuntu

    Either:
    evince [filename] (for document viewer, e.g. pdfs)
    or:
    gnome-open [filename] (for any file)

    http://ubuntuforums.org/showthread.php?t=446766

    How to install subversion on your linux shared hosting account

    1. Find out which linux distro your web host is running
    2. Download a set of subversion binaries for that linux distro
      1. or install that linux distro on a VM and compile into a PREFIX directory
    3. Copy bin/svn and require libs onto your web host (see list below for svn 1.6.16)
    4. Voila!


    List of libs required for svn client:
    svntest/lib/libsvn_ra-1.so.0
    svntest/lib/libssl.so.0.9.8
    svntest/lib/libsvn_diff-1.so.0
    svntest/lib/libneon.so.27
    svntest/lib/libsvn_ra_neon-1.so.0
    svntest/lib/libsvn_subr-1.so.0
    svntest/lib/libsvn_ra_local-1.so.0
    svntest/lib/libsvn_wc-1.so.0
    svntest/lib/libsvn_ra_svn-1.so.0
    svntest/lib/liblber-2.4.so.2
    svntest/lib/libsvn_fs_util-1.so.0
    svntest/lib/libsvn_delta-1.so.0
    svntest/lib/libldap-2.4.so.2
    svntest/lib/libcrypto.so.0.9.8
    svntest/lib/libsvn_fs_fs-1.so.0
    svntest/lib/libsvn_fs-1.so.0
    svntest/lib/libapr-1.so.0
    svntest/lib/libserf-0.so.0
    svntest/lib/libaprutil-1.so.0
    svntest/lib/libgdbm.so.3
    svntest/lib/libsvn_ra_serf-1.so.0
    svntest/lib/libsvn_client-1.so.0
    svntest/lib/libsvn_repos-1.so.0

    You can do 'OR' searches in FogBugz

    See instructions here:
    https://fogbugz.lovefilm.com/help/topics/basics/Searchingforcases.html

    Real IE6 on Ubuntu

    • Download the Internet Explorer Application Compatibility VPC Image from Microsoft
    • It is an .exe file. In Windows, run it to extract the files. You will get IE6Compat.vhd and some text files.
    • In Ubuntu, install VirtualBox 1.4.x
    • Type: vboxmanage clonehd IE6Compat.vhd WindowsXP_IE6_VirutalBox.vdi --format vdi
    • Create a new VirtualBox VM and load WindowsXP_IE6_VirutalBox.vdi into it
    • It will not log in because it says it's not registered.

    Log and email your Apache errors

    In the .htaccess at the root of the site:
    ErrorDocument 404 http://www.example.com/error_page.php?err=404
    ErrorDocument 503 http://www.example.com/error_page.php?err=503
    etc.

    In error_page.php:


    $myemail = "someone@example.com";
    $subject = "example.com: $errorNum error";
    $message = "$errorNum Error Report:\n";
    $message .= "\nHTTP_REFERRER: ".$_SERVER['HTTP_REFERER'];
    $message .= "\nREQUEST_URI: ".$_SERVER['REQUEST_URI'];
    $message .= "\nHTTP_USER_AGENT: ".$_SERVER['HTTP_USER_AGENT'];
    $message .= "\nQUERY_STRING: ".$_SERVER['QUERY_STRING'];
    $message .= "\nREMOTE_ADDRESS: ".$_SERVER['REMOTE_ADDR'];


    ob_start();
    print "\n\nSERVER = "; print_r( $_SERVER );
    print "\nGET = "; print_r( $_GET );
    print "\nPOST = "; print_r( $_POST );
    print "\nFILES = "; print_r( $_FILES );
    print "\nREQUEST = "; print_r( $_REQUEST );
    print "\nSESSION = "; print_r( $_SESSION );
    print "\nENV = "; print_r( $_ENV );
    print "\nCOOKIE = "; print_r( $_COOKIE );
    print "\nprevious php_errormsg = "; print_r( $php_errormsg );
    print "\nargv = "; print_r( $argv );
    $output = ob_get_clean();
    $message .= "\n\n$output\n";


    # email the error
    mail($myemail,$subject,$message,"From: support@example.com");


    # log the error
    $myFile = "logs/error.".date('Y_m_d-H.i.s').".log";
    $fh = fopen($myFile, 'w');
    $stringData = $message;
    fwrite($fh, $stringData);
    fclose($fh);
    ?>

    Vim features


    • Auto-complete (for Perl files): start typing, then press Ctrl-Shift-P

    Automate an FTP script

    in the ftp script put.pl:
    #!/bin/bash
    HOST="example.com"
    HOMEDIR="/"
    ftp -i $HOST <<-EOF
    passive
    cd $HOMEDIR
    put $1
    quit
    EOF
    echo "I put the file "$1

    in ~/.netrc:

    machine example.com
        login [username]
        password [password]

    to run:
    put.pl [filename]

    Vim navigation

    1. Vim Line Navigation
    Following are the four navigation that can be done line by line.
    • k – navigate upwards
    • j – navigate downwards
    • l – navigate right side
    • h – navigate left side
    By using the repeat factor in VIM we can do this operation for N times. For example, when you want to
    go down by 10 lines, then type “10j”.

    Within a line if you want to navigate to different position, you have 4 other options.
    • 0 – go to the starting of the current line.
    • ^ – go to the first non blank character of the line.
    • $ – go to the end of the current line.
    • g_ – go to the last non blank character of the line.

    2. Vim Screen Navigation

    Following are the three navigation which can be done in relation to text shown in the screen.
    • H – Go to the first line of current screen.
    • M – Go to the middle line of current screen.
    • L – Go to the last line of current screen.
    • ctrl+f – Jump forward one full screen.
    • ctrl+b – Jump backwards one full screen
    • ctrl+d – Jump forward (down) a half screen
    • ctrl+u – Jump back (up) one half screen

    3. Vim Special Navigation

    You may want to do some special navigation inside a file, which are:
    • N% – Go to the Nth percentage line of the file.
    • NG – Go to the Nth line of the file.
    • G – Go to the end of the file.
    • `” – Go to the position where you were in NORMAL MODE while last closing the file.
    • `^ – Go to the position where you were in INSERT MODE while last closing the file.
    • gg – Go to the beginning of the file.

    4. Vim Word Navigation

    You may want to do several navigation in relation to the words, such as:
    • e – go to the end of the current word.
    • E – go to the end of the current WORD.
    • b – go to the previous (before) word.
    • B – go to the previous (before) WORD.
    • w – go to the next word.
    • W – go to the next WORD.

    5. Vim Paragraph Navigation

    • { – Go to the beginning of the current paragraph. By pressing { again and again move to the previous paragraph beginnings.
    • } – Go to the end of the current paragraph. By pressing } again and again move to the next paragraph end, and again.

    6. Vim Search Navigation

    • /i – Search for a pattern which will you take you to the next occurrence of it.
    • ?i – Search for a pattern which will you take you to the previous occurrence of it.
    • - Go to the next occurrence of the current word under the cursor.
    • - Go to the previous occurrence of the current word under the cursor.

    7. Vim Code Navigation

    % – Go to the matching braces, or parenthesis inside code.

    8. Vim Navigation from Command Line

    Vim +N filename: Go to the Nth line of the file after opening it.
    vim +10 /etc/passwd

    An easy way to browse the file system is the command:
    :Sex
    Really!

    Perl sub name in vi status line

    " Thanks Ovid!
    " http://blogs.perl.org/users/ovid/2011/01/show-perl-subname-in-vim-statusline.html


    :set laststatus=2


    if ! exists("g:did_perl_statusline")
        setlocal statusline+=%(\ %{StatusLineIndexLine()}%)
        setlocal statusline+=%=
        setlocal statusline+=%f\ 
        setlocal statusline+=%P
        let g:did_perl_statusline = 1
    endif


    if has( 'perl' )
    perl << EOP
        use strict;
        sub current_sub {

            my $curwin = $main::curwin;
            my $curbuf = $main::curbuf;


            my @document = map { $curbuf->Get($_) } 0 .. $curbuf->Count;
            my ( $line_number, $column  ) = $curwin->Cursor;


            my $sub_name;
            # for modules, display the current sub name
            for my $i ( reverse ( 1 .. $line_number  -1 ) ) {
                my $line = $document[$i];
                if ( $line =~ /^\s*sub\s+(\w+)\b/ ) {
                    $sub_name = $1;
                    last;
                }
            }
            # for templates, display the current block starting line
            if (not $sub_name) {
                for my $i ( reverse ( 1 .. $line_number  -1 ) ) {
                    my $line = $document[$i];
                    # if ($input_state eq 'next_disc_at_station') {
                    if ( $line =~ /^}/ ) {
                        # we're below a block
                        last;
                    }
                    elsif ( $line =~ /^(\S.+{)\s*$/ ) {
                        $sub_name = $1;
                        $sub_name =~ s/'/''/g; #' # escape single quotes for vim function
                        last;
                    }
                }
            }
            # TODO:
            # * Reset sub name if we're out of the sub (check for closing bracket: })
            # * Search upwards vertically in the same column for nested blocks
            $sub_name ||= '..';
            VIM::DoCommand "let subName='$line_number: $sub_name'";
        }
    EOP


    function! StatusLineIndexLine()
      perl current_sub()
      return subName
    endfunction
    endif