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"); }
}
}
A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.
Jump to
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
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:
See http://perldoc.perl.org/perlsyn.html#Switch-statements
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
Step 2: create a file named git_diff_wrapper, put it somewhere in your $PATH
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:
Source: http://technotales.wordpress.com/2009/05/17/git-diff-with-vimdiff/
[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/
Labels:
diff,
git,
productivity,
vi
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
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
Labels:
basics,
commands,
config,
git,
versioning
Redirects behave weirdly in Chrome
Chrome (un)helpfully caches redirects sometimes.
Try using an incognito window and the behaviour should make more sense.
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.
Debugging websites
CSS:
element {
outline: red solid thick;
background: green;
};
PHP:
<?php $debug = $_GET['debug'] ?>
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
Diff two files side-by-side using vi
(use Ctrl-W+W to switch sides; may need :syntax off to prevent colours clashing)
Subversion diff using vi
Step 1. Create a diff command script for svn (and set the execute bit):
Step 2. Create a diff script for you to use:
Step 3. Run the diff script
(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]
Labels:
diff,
productivity,
svn,
vi
Music players on Ubuntu
I haven't yet found software for Linux that equals Winamp on Windows, for ease of playlist manipulation.
thanks
- 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 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).
Labels:
commands,
productivity,
vi
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.
Labels:
macro,
productivity,
record,
windows
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
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.
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";
Labels:
namespaces,
php,
url,
xml
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
Have Perl debugger break on a sub in any module
b Name::Of::Module::name_of_sub
Labels:
break,
debugging,
perl,
subroutines
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)
Labels:
alert,
calendar,
email,
linux,
notification,
plugin,
pop-up,
productivity
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.
But none of them force the window to always appear over other windows.
Labels:
alert,
email,
linux,
message,
notification,
pop-up,
productivity
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.
> @DB::typeahead=('v')
or
{{v
See also these questions and perldebug.
Labels:
code,
debugging,
IDE,
perl,
productivity
Delete a file starting with a dash
You accidentally created a file called "-.log"
To delete it, instead of
rm -.log
try
rm ./-.log
To delete it, instead of
rm -.log
try
rm ./-.log
Labels:
bash,
characters,
delete,
files
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
Labels:
idea,
subroutines,
testing
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.
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.
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.
Labels:
data,
duplicates,
sort,
unique,
vi
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
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.
Labels:
apache,
directories,
password,
webserver
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"
));
$template->assign_block_vars('navlinks', array(
'FORUM_NAME' => "link display text",
'U_VIEW_FORUM' => "http://url-of-page"
));
Labels:
breadcrumb,
links,
navigation,
phpbb,
template,
ux
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;
Thanks
@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.
Labels:
admin,
forum,
moderation,
phpbb,
post
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++;
$year += 1900;
$month++;
Prevent spammers from harvesting your email address
When you write your email address on a web page, use @ instead of @, and . 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
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
Labels:
ascii,
characters,
dodgy,
encoding,
non-printable,
one-liner,
perl,
utf8
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 [[ ]]
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 [[ ]]
Labels:
bash,
if,
parameters,
variables
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:
- Go to ACP | General | Security settings, and set "Allow php in templates" to "Yes".
- Follow the tutorial at: http://wiki.phpbb.com/Practical.Add_custom_page
- 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;
}
}
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;
}
}
Labels:
databases,
mysql,
oo,
perl,
subroutines
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)
Labels:
colour,
eclipse,
perl,
syntax,
text editor
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.
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.
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
Labels:
graphics
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 also, and
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
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
See: http://perldoc.perl.org/5.8.8/functions/-X.html
and http://perldoc.perl.org/5.8.8/functions/stat.html
Labels:
files,
perl,
syntax,
system,
underscore
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 );
...
__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
}
# 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
- The syntax is more terse
- That's all. Test::MockModule also allows wrapping (i.e. calling the original module)
- The syntax is more terse
- That's all. Test::MockModule also allows wrapping (i.e. calling the original module)
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:
*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
- 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()
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::Trace, Debug::LTrace, Devel::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) {
} 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".
Debug::Trace, Debug::LTrace, Devel::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".
Labels:
debugging,
moose,
perl,
subroutines,
trace
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
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
- Find out which linux distro your web host is running
- Download a set of subversion binaries for that linux distro
- or install that linux distro on a VM and compile into a PREFIX directory
- Copy bin/svn and require libs onto your web host (see list below for svn 1.6.16)
- 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
Labels:
hosting,
svn,
versioning,
webserver
You can do 'OR' searches in FogBugz
See instructions here:
https://fogbugz.lovefilm.com/help/topics/basics/Searchingforcases.html
https://fogbugz.lovefilm.com/help/topics/basics/Searchingforcases.html
Labels:
fogbugz,
issue tracking
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);
?>
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);
?>
Pattern specification for Log4perl log messages
Pattern specification for Log4perl log messages:
http://search.cpan.org/~mschilli/Log-Log4perl-1.32/lib/Log/Log4perl/Layout/PatternLayout.pm
Vim features
- Line numbering: set number
- Text completion: Ctrl-n or Ctrl-P (while in insert mode)
- Marks: mc (to set mark c) 'c (to go to mark c)
- Perl syntax compiler
- Tag explorer
- Block commenting
- Colour schemes
- Visible tabs: :set listchars=tab:\|\
- last character is a space
- Perldoc integration
- Text folding: set foldmethod=marker and set foldmarker="{{{,}}}"work)
- see other fold methods including perl_fold
- Map keys to other keys:
- " e.g. map Ctrl-E to end-of-line (in insert mode)
- imap
$i
- Auto-complete (for Perl files): start typing, then press Ctrl-Shift-P
Labels:
comments,
docs,
perl,
productivity,
syntax,
text editor,
vi
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]
#!/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!
Labels:
basics,
shortcut keys,
text editor,
vi
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
" 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
Labels:
files,
perl,
status,
subroutines,
text editor,
vi
Subscribe to:
Posts (Atom)