If you've discovered something amazing about Perl that you just need to share with everyone, this is the right place.

This section is also used for non-question discussions about Perl, and for any discussions that are not specifically programming related. For example, if you want to share or discuss opinions on hacker culture, the job market, or Perl 6 development, this is the place. (Note, however, that discussions about the PerlMonks web site belong in PerlMonks Discussion.)

Meditations is sometimes used as a sounding-board — a place to post initial drafts of perl tutorials, code modules, book reviews, articles, quizzes, etc. — so that the author can benefit from the collective insight of the monks before publishing the finished item to its proper place (be it Tutorials, Cool Uses for Perl, Reviews, or whatever). If you do this, it is generally considered appropriate to prefix your node title with "RFC:" (for "request for comments").

User Meditations
Perl 5 Optimizing Compiler, Part 16: RPerl v1.2 Kickstarter Challenge
4 direct replies — Read more / Contribute
by Will_the_Chill
on Sep 25, 2015 at 08:20
Perl 5 Optimizing Compiler, Part 15: RPerl v1.2 Kickstarter Now Live
4 direct replies — Read more / Contribute
by Will_the_Chill
on Sep 22, 2015 at 05:15
    Greetings, Monks!

    I am proud to announce the launch of our next Kickstarter campaign.

    We immediately reached our minimum of $1,701; now our goal is to reach $20K in the next 9 days. We can do it... WITH YOUR HELP!

    STEP 1: Make a generous pledge.
    STEP 2: Get your friends to match your pledge.
    STEP 3: Get your boss to double your pledge.
    STEP 4: Go back and increase your pledge.

    Thanks so much for your continued support of RPerl!

    ~ Will the Chill
Most well-known Perl-powered product?
7 direct replies — Read more / Contribute
by u65
on Sep 21, 2015 at 21:54

    I had the pleasure this afternoon of being interviewed by a local, online publication about our new Perl Mongers group (http://niceville.pm.org). Among other things, the interviewer asked me to name a Perl-powered product that would be known by many lay persons. I have found one list here, but I'm afraid most non-programmers I know would not recognize most, if not all, of those. Realizing that the interviewer's audience are local non-techies, how would you respond?

    My off-the-cuff response was big, open-source projects like Linux, Git, and Subversion use Perl behind the scenes, but she has given me a chance to come up with something perhaps more well-known to the average iPad user. So any better suggestions are welcome and will help in a small way to spread the word about Perl.

    Thanks for any input.

SSH to Java based SSH server
No replies — Read more | Post response
by Beatnik
on Sep 16, 2015 at 16:22
    First post in over 10 years. Ugh!
    Recently, I had to work with a Java based SSH server (based on SSHTools, sometimes forked as J2SSH). I tried different options (ignoring the fact that some SSH modules are an absolute pain to install). There were different reasons why one or the other solution didn't work. Public key authentication was not support (don't ask), Expect was at the top of my list either. In the end, I made it work with Net::OpenSSH and the pty mapping to Net::Telnet. From POD:
    my ($pty, $pid) = $ssh->open2pty({stderr_to_stdout => 1}) or die "unable to start remote shell: " . $ssh->error; my $telnet = Net::Telnet->new(-fhopen => $pty, -prompt => '/.*\$ $/', -telnetmode => 0, -cmd_remove_mode => 1, -output_record_separator => "\r"); $telnet->waitfor(-match => $telnet->prompt, -errmode => "return") or die "login failed: " . $telnet->lastline; my @lines = $telnet->cmd("who"); ... $telnet->close; waitpid($pid, 0);
    The Prompt needed to be adjusted as the COTS had its own customized prompt.
    ... I'm belgian but I don't play one on TV.
Should I come back to Perl?
7 direct replies — Read more / Contribute
by jekyll
on Sep 11, 2015 at 07:16


    maybe this is not a good forum to ask this, but on reddit they were rather quiet ... :-)

    I exclusively used Perl 5 and a bit of JavaScript and PHP for my first job, then I somehow focused on PHP completely and started to make money with it. Writing scripts in other languages was never a job choice for me, I just like to learn new things. (Although I guess that knowing more languages will highly increase my job chances anyway.) The occasional Perl here and there (a fun IRC bot in my spare time, a text parser for some of my colleagues at work) was never gone but I didn't invest much time into it.

    Some day I needed a website parser for the PHP tool I had been hired to develop. As I had read about Python's urllib just a short time before, I decided to implement that script in Python, not being aware of the actual difference between Python 2 and Python 3. Another hobby, I thought. When the script was nearly complete, I learned that Python 2 is about to be phased out slooooowly and Python 3 lacks a comparable community yet. I assume Python 4 will cause even more trouble, and it's not really worth all that.

    I have a couple of other projects in my "To do when there's some more spare time left" list, including a rework of the particular Python script and some web development things. I guess some will be in Common Lisp (learning languages by implementing things in them has always worked out for me), but I also will revive my Perl knowledge. I just don't want to switch to Perl just to see it suffering from the same problem too, Perl 5 being slowly phased out and Perl 6 being not widely accepted. If Perl 5 won't have the same "future" as Python 2, I'm happy to join the old Perl club again; otherwise, I (again) don't really know what to do.

    I don't want to rewrite my code every few years just because someone decides that the language I wrote it in is deprecated for no good reason now. Does anyone of you have a deeper, reasonable clue about what will happen with Perl 5 when Perl 6 has gained enough attraction?

    Regards and all that, jkl
RFC: Emulating the monastery voting system
2 direct replies — Read more / Contribute
by biohisham
on Sep 10, 2015 at 08:27

    Out of admiration for the PM voting and ranking system described in votes; I am inspired to suggest an implementation along its lines on a website being developed with a team of my friends. So as a proof of concept I wrote this interactive code that accepts: a member's reputation, (u)pvotes & (d)ownvotes, average likes per week as well as age of the node; then decides whether the number of u's or d's would result in reputation gain or loss relative to the current reputation.

    As it is the code tests fine but I feel it could still use comments and anecdotal wisdom from the monks here, hence I posted it in Meditations.

    use strict; use warnings; use Readonly; use Getopt::Long; use Scalar::Util::Numeric qw(isint); #age and avg_xp are calculated at the start of everyday. #The avg_xp=sum(XP)/#nodes in the past 7 days. #The program takes these two values in addition to #likes and #unlikes + to dynamically compute reputation gains and losses. #Input for current reputation is prompted when it is time to update th +e reputation. my ($age, $avg_xp,$gained_rep, $lost_rep); my ($upvotes, $downvotes, $total_rep); my $current_rep; #variable to hold the current user reputation from th +e user page. my $vote; #a listener:either (u)pvote or (d)ownvote. Readonly::Scalar my $args =>4; #program accepts two args & two vals if(@ARGV != $args){die "syntax error: perl calculate_rep.pl --age n -- +avg_xp n\n";} GetOptions( "age=i"=>\$age, "avg_xp=i"=>\$avg_xp, )or die "syntax error: perl calculate_rep.pl --age n --avg_xp n\n" +; print "enter u for upvote or d for downvote\n"; while($vote=<>){ chomp $vote; if($vote =~/^u$/i){ $upvotes++; analyze_upvotes($age, $upvotes); }elsif($vote=~/^d$/i){ $downvotes++; analyze_downvotes($age,$downvotes); }else{ print "ERROR: enter u for upvote or d for downvote\n"; } } sub analyze_upvotes{ my $node_age=shift; my $like_counter=shift; printf "you have %d likes\n",$like_counter; if($like_counter==1){#reward the first upvote $gained_rep=1; rep_update($gained_rep,"gain", $like_counter); $gained_rep=0; } if($age>2 && $like_counter>1){ #nodes older than two weeks get 1/5 + rep increase $gained_rep+=1/5; if(isint $gained_rep){ #reputation is reported when gained +reputation sums to a whole number rep_update($gained_rep,"gain", $like_counter); $gained_rep=0; } }elsif($age<=2 && $like_counter>1){ #rep for nodes < 2 weeks o +ld is calculated with avg_xp perspective if($like_counter<=$avg_xp){ $gained_rep+=1/3; } elsif($like_counter>$avg_xp && $like_counter<=2*$avg_x +p){ $gained_rep+=1/2; } elsif($like_counter>2*$avg_xp && $like_counter<=3*$avg +_xp){ $gained_rep+=2/3; } elsif($like_counter>3*$avg_xp && $like_counter<=4*$avg +_xp){ $gained_rep+=3/4; } elsif($like_counter>4*$avg_xp){$gained_rep+=1; $gained +_rep=int $gained_rep; } if(isint $gained_rep){ if($current_rep-$gained_rep==0){ #for when cur_rep +=1 and gained_rep=1; rep_update(1,"gain", $like_counter); }else{ rep_update($gained_rep, "gain", $like_coun +ter); } $gained_rep=0; } } } sub analyze_downvotes{ my $node_age=shift; my $unlike_counter=shift; printf "you have %d unlikes\n", $unlike_counter; if($age<=2){ if($unlike_counter<= 3*$avg_xp){ $lost_rep+=1/3; } elsif($unlike_counter > 3*$avg_xp && $unlike_counter <= 4* +$avg_xp){ $lost_rep+=1/4; } elsif($unlike_counter > 4*$avg_xp){ $lost_rep+=0; } if(isint $lost_rep){ rep_update($lost_rep, "loss", $unlike_counter); $lost_rep=0; } }elsif($age>2){ $lost_rep+=0;} } sub rep_update{ my $rep_gain_loss=shift; my $status=shift; my $like_unlike_counter=shift; print "what is the current user reputation?\n"; $current_rep=<>; chomp $current_rep; if($status eq "gain"){ my $total_gain=$current_rep + $rep_gain_loss; printf "you gained %d points\nyour reputation is %d\n", $rep_g +ain_loss, $total_gain; }elsif($status eq "loss"){ my $total_loss=$current_rep-$rep_gain_loss; printf "you lost %d reputation points\nyour reputation is +%d\n", $rep_gain_loss,$total_loss; } }

    I am also thinking about changing the way loss of reputation is done by basing it on a variable (say avg_unlike_xp) similar to the avg_xp that I currently use for calculating gain/loss or reputation. If I did this I won't be that benevolent of a dictator any more though as I could risk over-penalizing members.

    Something or the other, a monk since 2009
Mojolicious and MongoDB
1 direct reply — Read more / Contribute
by rahuldhodapkar
on Sep 09, 2015 at 19:54
    Hey Monks!

    I haven't been around the perl community for a while, but have had a lot of fun getting familiar with the language again. Perl was my first language, but it seems to me that a lot of new programmers choose other languages like Python or Javascript to get themselves started.

    I set out to make a simple, but robust starter framework using Mojolicious and MongoDB so that new programmers (especially those at hackathons) would be able to use Perl for fun and diverse projects.


    I wanted to put the current project out there, and would appreciate help (or even pull requests maybe ^_^) and feedback. Hope everyone is doing well

Dup: Perl 5 Optimizing Compiler, Part 14: RPerl v1.1 Release, Codename Jupiter, Now Supporting N-Body Benchmark
1 direct reply — Read more / Contribute
by Will_the_Chill
on Sep 05, 2015 at 19:37
    Howdy Monks,

    RPerl v1.1, codename 'Jupiter', has been released to CPAN!

    Jupiter supports fully-automated compiling of the long-awaited N-body application software, which is a solar system simulator used by the Alioth Benchmark Game to rank programming languages by speed.

    RPerl and the new PhysicsPerl software suite enable the N-body app to run at the speed of C++, dropping from over 19 minutes runtime to barely 13 seconds!

    For now, see the INSTALL notes file for instructions on running N-body using RPerl & PhysicsPerl.

    Also, take a look at the pre-release user documentation, Learning RPerl!

    Please visit us on IRC for real-time tech support:


    ~ Will the Chill, rperl.org & austin.pm
Notepad++ Perl Function List with "Classes"
No replies — Read more | Post response
by VinsWorldcom
on Aug 24, 2015 at 12:50

    Windows Monks,

    As follow-on to my previous meditation regarding Notepad++ Integrated Perl Debugging, I've been doing other things with Notepad++ to make it more friendly when I write Perl (of which I've been doing more than usual lately).

    One thing I did was to get Python debugging working the same way as with Perl. In case you're interested, see here: http://vinsworldcom.blogspot.com/2015/08/notepad-dbgp-and-python.html.

    This got me thinking as I looked in the "Function List" window at Python code:

    file.py +[Class]h_main __init__ +[Class]h_base toXML convert main

    Why does the "Function List" window show Python classes, but not Perl by default? Of course by Perl class, I mean 'package <name>'. All I would see was a list of subs. Take the following example program:

    #!perl use strict; use warnings; package MyPkg; sub one { 1; } sub two { 1; } 1; package main; my $p = pre(); print $p . MyPkg->one; sub pre { return "ONE = "; }

    The Notepad++ Function List is:

    file.pl one two pre

    But there are clearly "classes" (read: packages) under which I'd like my subs grouped. Thankfully, Notepad++ allows customization of a file in the Notepad++ top level directory called 'functionList.xml' (documentation: https://notepad-plus-plus.org/features/function-list.html). A quick web search turned up a partial solution and with some more tweaking I finally got it to display:

    file.pl +[Class]MyPkg one two +[Class]main pre

    If there are no "packages", then the original display of just filename with the subs is what is displayed. I even tweaked it a bit to ignore stuff after __END__, so any "sub name" that appears in POD won't be mistakenly added to the Function List. I've tested it by viewing a few of my scripts, some modules and a few "custom" codes to demonstrate different use cases. So far, so good.

    The solution; save a copy of your existing 'functionList.xml' to something like 'functionList.xml.ORIG' (just in case you want to revert back), open the existing 'functionList.xml' file, find the Perl parser lines:

    <parser id="perl_function" displayName="Perl" ... ... </parser>

    and replace the whole lot with:

    <parser id="perl_function" displayName="Perl" commentExpr="(#.*?$|(__E +ND__.*\Z))"> <classRange mainExpr="(?&lt;=^package).*?(?=\npackage|\Z)"> <className> <nameExpr expr="\s\K[^;]+"/> </className> <function mainExpr="^[\s]*(?&lt;!#)[\s]*sub[\s]+[\w]+[\s]*\(?[^\)\ +(]*?\)?[\n\s]*\{"> <functionName> <funcNameExpr expr="(sub[\s]+)?\K[\w]+"/> </functionName> </function> </classRange> <function mainExpr="^[\s]*(?&lt;!#)[\s]*sub[\s]+[\w]+[\s]*\(?[^\)\(] +*?\)?[\n\s]*\{"> <functionName> <nameExpr expr="(?:sub[\s]+)?\K[\w]+"/> </functionName> </function> </parser>
MCE::OrdHash naming Push and Unshift methods supporting merging and reordering
1 direct reply — Read more / Contribute
by marioroy
on Aug 18, 2015 at 12:49

    Greetings all,

    I have been working on MCE::OrdHash, a sharable ordered hash module for use with MCE::Shared. These things will be included with MCE 1.7 when released. MCE::OrdHash is 100% compatible with Tie::IxHash. It overlays a modified tombstone deletion seen in Hash::Ordered. It supports both OO and Tie. The OO interface is faster, but provides auto-tie on-demand when hash-like dereferencing is requested. This is done via an autoload directive.

    The Push and Unshift methods in MCE::OrdHash merges for existing keys to remain compatible with Tie::IxHash. It adds two methods when reorder is desired. The method names are PushRo and UnshiftRo. Reorder means having to delete an existing key prior to inserting.

    I seek for the opinion of other monks on the naming of PushRo and UnshiftRo. Should I name these something else?

    Thank you, Mario

    If interested, I benchmarked against Hash::Ordered and Tie::IxHash. I have dropped MCE::Hash::Indexed (OI) and keeping MCE::Hash::Ordered (OT) which is now MCE::OrdHash.

OT: Sigh ... Windows 10
9 direct replies — Read more / Contribute
by roboticus
on Aug 14, 2015 at 19:27

    Annoying OT rant. You'll probably want to skip reading this altogether.

    I built myself a rather nice Gaming system a while back, and for the most part, I'm pretty happy with it. The big pain in the ass, though, was that I installed Windows 8.1 on it, rather than finding a copy of Windows 7. I've used Windows 7 for a couple years at work, and am pretty happy with it.

    However, Windows 8.1 was a nasty kick in the teeth. I'm still fighting with it, and hating it. So when the new and improved Windows 10 was announced, I thought I'd go and install it.

    Though, this time, I thought I'd learn a little about it first, so as not to install something even worse than Windows 8.1 (which sucks horribly, by the way). (Note: It's pretty much just the UI part that seems to suck. Performance is good. It's just that the UI went to hell for no good reason. When you mention it on a mailing list, you get the old "Oh, you old farts are afraid of change". Bullhocky! I'm not a *bit* afraid of change. I just hate things that suck!)

    Anyway, reading the reviews, it seems that Windows 10 might be a significant improvement over Windows 8.1. Not that I'll be finding out, though. Luckily, before I allowed my box to upgrade to Windows 10, I stumbled across something: Apparently Windows 10 is going to *force* autoupdates--no compromises.

    Sorry, Microsoft, but you've lost *far* too much trust for me to allow you to decide when to upgrade my operating system. So I'll be sticking with Windows 8.1 until someone either gives me a (legal) copy of Windows 7 (I'm not interested in pirating it, *nor* am I planning on giving Microsoft another dime to fix their mistake.)

    Sorry for the off-topic rant, but I'm in a ranting mood.

    (For those advising that I should use Linux, I'll let you know that I have more Linux boxes (5) at home than Windows boxes (2). I put this box together for gaming, but I run it most of the time because it has the good monitors on it, the big honkin' CPU and the excessive RAM. The instant that game stops being fun, this box'll be getting upgraded to Debian, and there'll only be my son's Windows box left in the place.)


    When your only tool is a hammer, all problems look like your thumb.

RFC: Improving the quality of your module
1 direct reply — Read more / Contribute
on Aug 14, 2015 at 15:24

    I have been looking for a list of tools that I can use to improve the quality of my modules, and I haven't been able to find one elsewhere, so I posted a question to Seekers and summarized the tools below. I propose adding the following to be added to the tutorials list (under Modules: How to Create, Install, and Use -> Creating and Distributing Modules).

    Improving the quality of a perl module

    There are a large number of tools available which can be used to improve the quality of a perl module. This might mean decreasing the number of bugs in it, improving it's performance, improving it's ability to interact with various other perl tools, or making it more usable to others.

    Below is a list of tools that are available which may help improve various aspects of your module. Not all will be useful in all situations, but it should still be a useful starting point.

    Change Kwalitee
    Every module should come with a description of the changes made at each version. There is a standard format that can be used. This site can be used to determine if your changes file meets the standard.
    CPAN Testers
    Once a module is released to CPAN, it is automatically tested by a set of volunteer testers on various platforms with different versions of perl. This site lists the platforms used to test the module as well as which ones succeed and which fail.
    CPANTS Kwalitee
    There are a number of best practices when creating a module. This site lists many of the most common ones and reports on which ones a module passes and which ones it fails.
    Devel::Cover, cpancover.com
    These can be used to make sure that every line in your module is covered by at least one test in the test suite.
    This is THE tool for profiling a module to see where the time is being spent in order to speed things up.
    This can be used to check perl code to see whether it uses the best practices described in Damian Conway's Perl Best Practices book.
    This can be used to fix indentation and enforce a few other coding style practices.
    A spell checker for Pod files.
    A check list of things to look at when releasing a new module.
    A list of recommended perl modules. Especially useful are Task::Kensho::ModuleDev and Task::Kensho::Testing which contain modules recommended for development and testing.
    Test::Pod, Test::Pod::Coverage
    These are used to make sure that no pod files are missing and that they cover all of the functions in a module.
    Travis CI
    This tool can be used for modules stored on GitHUB. Every time a set of changes is checked in, the module will be automatically tested using a number of different perl versions to make sure that all tests pass.
Ternary vs. Sort vs. Max
8 direct replies — Read more / Contribute
by QM
on Aug 10, 2015 at 05:23
    A line in BrowserUK's post reminded me of one of my cobwebs that I'm always chasing, namely, whether the Conditional Operator, ?:, is preferable over sort. In the end I should import a max function when possible, but I don't always do so.

    Conditional operator:

    my $n = $x > $y ? $x : $y;

    I find this awkward to read, and it also duplicates the variable names.


    my $n = (sort {$a <=> $b} $x, $y)[-1];

    But because sort needs a numeric sort function, that's a bit long winded.

    And the max function:

    use List::Util qw(max); my $n = max($x, $y);

    Which seems to be the laziest and preferred way.

    Quantum Mechanics: The dreams stuff is made of

RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
5 direct replies — Read more / Contribute
by u65
on Aug 05, 2015 at 20:56

    I have posted a draft tutorial in my scratchpad here below (per Arunbear's suggestion) and am looking for constructive criticism. Thanks.

    UPDATE 1: Added three subheadings including an informal list of Perl 6's desirable features.

    UPDATE 2: Added link to rosettacode in the "Some Longer Comments" section below.

    UPDATE 3: After some rework (perltidy, perlcritic) in the Perl 5 code, modified the Perl 6 code accordingly, then made additional improvements to the Perl 6 code to be more Perl6ish.

    === BEGIN TUTORIAL ===


    Perl 6 is almost upon us, and it promises to cure many of the shortcomings of Perl 5. For all the official information, check out its web site at <http://perl6.org>. I use the instructions here <http://rakudo.org/how-to-get-rakudo/> for a Linux source installation with the rakudobrew script.

    I asked for users opinions of Perl 6's "killer" features on the Perl 6 users list and following are some of the responses:

    • variables must be declared
    • strong typing available
    • built-in command line processing
    • built-in multiple dispatch
    • the where clause
    • built-in sets and bags
    • built-in pick and roll
    • built-in better arithmetic (Rat number type)
    • improved regex
    • no parens required for if statements
    • built-in facilities for the language to parse, transform and extend itself (std grammar, macros)
    • awesome error messages
    • hyphens allowed in names
    • grammars
    • easy interface with C
    • named subroutine arguments
    • better classes and namespaces
    • built-in object methods
    • see rosettacode for good examples

    Some longer comments:

    • Just make them look at Perl6 source code, e.g., on rosettacode. Someone who doesn't see how wonderful Perl6 is, is a lost soul anyway.
    • Less cumbersome to write and easier to read.
    • Grammars: Perl 6 is most attractive to me as a framework development tool. It lets you be really creative in how you let users describe their problem to your framework, whether that be webserver, parser, etc.
    • One thing that was not mentioned already is using Rat instead of standard floating point number. It prevents many silly mistakes, especially when counting money.


    This tutorial aims to show how my typical modest Perl 5 scripts translate into Perl 6. As the current Perl 6 documentation is not yet complete, my beginning Perl 6 efforts have resulted in putting together a simple model for a typical task for me. It was completed somewhat by trial and error along with much help from the Perl 6 mailing list.

    The Code

    A typical script of mine does something like the following:

    • Provides a simple usage statement when executed without any arguments.
    • Provides detailed help when the '--help' or '-h' or '?' options are provided.
    • Opens and parses some kind of data file (often in a special key-value format).
    • Takes some kind of action with the input data.
    • Writes data to STDOUT or a specific file.
    • Provides a friendly results message upon successful completion.

    The following table is a side-by-side comparison of the two example programs (both of which work for me; please report any errors you may find). There are some comments to indicate differences in Perl 5 versus Perl 6, but many are not documented explicitly. In many cases of my Perl 6 usage, as in Perl 5, TIMTOWTDI, so I'm sure both programs can be improved.

    Below the programs is the input data file used by each program. Run each program like this to compare results (assuming you have done chmod +x filename for each file):

    $ ./tutorial-p5.pl -g -d >& p5.txt $ ./tutorial-p6.pl -g -d .& p6.txt
    Perl 5Perl 6
    #!/usr/bin/env perl # file: tutorial-p5.pl # PRELIMS ======================== use v5.10; # features 'say' and 'state' use strict; use warnings; use File::Basename; # p6: no such module yet use Data::Dumper; my $default_infile = 'tutorial-data.txt'; my $prog = basename $0; my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage .= ' | --help | ? [--debug[=N]]'; # ARG/OPTION HANDLING ======================== if (!@ARGV) { say $usage . "\n"; exit; } foreach my $arg (@ARGV) { my $oarg = $arg; # save original for error handling my $val = undef; my $idx = index $arg, q{=}; if ($idx >= 0) { $val = substr $arg, $idx+1; $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if (! -e $infile); my %user; my @keywords = qw(last first job); my %keywords; @keywords{@keywords} = (); parse_data_file($infile, \%user, $debug); if ($debug) { say 'DEBUG: Dumping user hash after loading:'; print Dumper(\%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file { my $fname = shift @_; my $href = shift @_; my $debug = shift @_ || 0; say "Parsing input file '$fname'..."; open my $fp, '<', $fname or die "$fname: $!"; my $uid = undef; my $linenum = 0; while (defined(my $line = <$fp>)) { ++$linenum; my $err = 0; # remove comments my $idx = index $line, q{#}; if ($idx >= 0) { $line = substr $line, 0, $idx; } # skip blank lines next if $line !~ /\S/xms; # every valid line must have a colon (':') # following a key word $idx = index $line, q{:}; if ($idx >= 0) { # ensure the key is lower case my $k = lc substr $line, 0, $idx; # trim ws on both ends $k =~ s{\A \s* | \s* \z}{}gxms; my $val = substr $line, $idx+1; # also needs trimming $val =~ s{\A \s* | \s* \z}{}gxms; # User attributes if ($k eq 'user') { $uid = $val; die 'FATAL: $uid not defined.' if !defined $uid; if ($uid =~ /\D/xms) { say 'ERROR: User ID not an integer.'; ++$err; } elsif ($uid <= 0) { say 'ERROR: User ID not an integer > 0.'; ++$err; } elsif (exists $href->{$uid}) { say 'ERROR: User ID is not unique.'; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if (!defined $uid) { say 'ERROR: User ID is not defined for this user.'; ++$err; } elsif ($k eq 'hobbies') { $href->{$uid}{hobbies} = []; my @h = split q{,}, $val; foreach my $h (@h) { # trim ws on both ends $h =~ s{\A \s* | \s* \z}{}gxms; push @{$href->{$uid}{hobbies}}, $h; } } elsif (exists $keywords{$k}) { $href->{$uid}{$k} = $val; } else { chomp $line; say 'ERROR: Unknown line format:'; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format.'; ++$err; } if ($debug) { chomp $line; say STDERR "DEBUG: line = '$line'"; } if ($err) { chomp $line; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { say <<"HERE"; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help # EOF ========================
    #!/usr/bin/env perl6 # file: tutorial-p6.pl # PRELIMS ======================== use v6.0; # not required, but good practice for # maintenance # 'strict' and 'warnings' are the default # Note: Using perl6 -v => # '2015.07.1-66-g0dcbba7 built on MoarVM version 2015.07-8-gb8fdeae' use Data::Dump; my $default_infile = 'tutorial-data.txt'; my $prog = basename($*PROGRAM); my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage ~= ' | --help | ? [--debug[=N]]'; # '~=' instead of '.=' # ARG/OPTION HANDLING ======================== # See [http://design.perl6.org/S06.html] # for built-in methods similar to Getopts::Long if !@*ARGS.elems { say $usage ~ "\n"; # '~' instead of '.' exit; } for @*ARGS -> $arg is copy { # 'is copy' allows modifying locally my $oarg = $arg; # save original for error handling my $val = Any; # 'Any' instead of 'undef' my $idx = index $arg, '='; if $idx.defined { # index is defined if an index is found $val = substr $arg, $idx+1; # use substr function $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if $infile.IO !~~ :f; my %user; my @keywords = <last first job>; my %keywords; %keywords{@keywords} = (); parse_data_file($infile, %user, $debug); if $debug { say "DEBUG: Dumping user hash after loading:"; say Dump(%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file(Str $fname, # declare args #Any $href, %href, Int $debug = 0) { say "Parsing input file '$fname'..."; my $uid = Any; # p6 doesn't use 'undef' my $linenum = 0; for $fname.IO.lines -> $line is copy { ++$linenum; my $err = 0; # remove comments my $idx = index $line, '#', 0; if defined $idx { $line = $line.substr(0, $idx); } # skip blank lines next if $line !~~ /\S/; # '~~' and '!~~' for matching # every valid line must have a colon (':') # following a key word $idx = $line.index(':'); if $idx.defined { # ensure the key is lower case my $k = $line.substr(0, $idx).lc; # trim ws on both ends $k = $k.trim; # string object method my $val = $line.substr($idx+1); # use object method # also needs trimming $val = $val.trim; # User attributes if $k eq 'user' { $uid = $val; die "FATAL: \$uid not defined." if !$uid.defined; if $uid ~~ /\D/ { say "ERROR: User ID not an integer."; ++$err; } elsif $uid <= 0 { say "ERROR: User ID not an integer > 0."; ++$err; } elsif %href{$uid}:exists { # 'exists' adverb say "ERROR: User ID is not unique."; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if !$uid.defined { say "ERROR: User ID is not defined for this user."; ++$err; } elsif $k eq 'hobbies' { # literal string keys must be quoted %href{$uid}<<hobbies>> = []; my @h = split ',', $val; for @h -> $h is rw { # trim ws on both ends $h .= trim; # literal string keys must be quoted # use '@()' instead of '@{} push @(%href{$uid}<hobbies>), $h; } } elsif %keywords{$k}:exists { %href{$uid}{$k} = $val; } else { $line .= chomp; say "ERROR: Unknown line format, \$k = '$k'."; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format (no key).'; ++$err; } if $debug { $line .= chomp; say "DEBUG: line = '$line'"; } if $err { $line .= chomp; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { # note indent is taken from position of ending token say qq:to/HERE/; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help sub basename(IO::Path $fname) { # no File::Basename module in p6 yet my $idx = rindex $fname, '/'; if $idx { return $fname.substr($idx+1); # use substr method } return $fname; } # basename # EOF ========================

    Following is the input data file used in the programs above:

    # file: tutorial-data.txt # a data file of users and their attributes # note all valid lines are in format "key: value..." user: 1234 # unique ID (an integer > zero) last: Brown first: Sam job: gunsmith # hobbies may be a comma-separated list hobbies: hunting, Perl Monging user: 2316 last: Doe first: Jane job: financial analyst hobbies: Python open source, bowling
Notepad++ Integrated Perl Debugging
2 direct replies — Read more / Contribute
by VinsWorldcom
on Aug 05, 2015 at 06:28

    Windows Monks,

    Do you use Notepad++ as your preferred editor? Have you done some things with NppExec to move towards an IDE? Do you want integrated debugger support?

    I was out of luck on the last one and a myriad of Google-ing didn't help. There was a debugger plugin for Notepad++ (DBGp - http://sourceforge.net/projects/npp-plugins/files/DBGP%20Plugin/) but it was for PHP debugging with XDebug ... originally. I set out to get Perl working with it and lo and behold - I did it!

    UPDATE: I'm on Windows 7 x64 and using Strawberry Perl 5.18.1 MSWin32-x64-multi-thread.

    The gory details can be found here:


    Essentially, you need:

    DBGp plugin

    Get it from the SourceForge page at http://sourceforge.net/projects/npp-plugins/files/DBGP%20Plugin/. Get the latest (0.13 beta as of this writing) and you'll only need the DLL. Current file name is: DBGpPlugin_0_13b_dll.zip. Unzip the DLL to your Notepad++\plugins directory.

    Perl Debugger for Komodo IDE

    We only need this since there isn't a "Perl Debugger for Notepad++ IDE". It essentially supplies the interface via "perl5db.pl" and subdirectory "DB" of various supporting modules. You get it here: http://downloads.activestate.com/Komodo/releases/archive/4.x/4.4.1/remotedebugging/ and you'll want the Komodo-PerlRemoteDebugging-4.4.1-20896-win32-x86.zip file. NOTE: I tried newer releases, but found other issues cropped up in addition to the ones I show you how to fix below, so use this version, or the rest of this won't make much sense.

    I created a directory in my Notepad++\plugins directory called "PerlDebug"; so, ...Notepad++\plugins\PerlDebug. I unzipped only the "perl5db.pl" file and the entire "DB" directory and its sub directories into that PerlDebug directory.

    Getting it to Work

    You need to make some edits to the Perl Debugger scripts from the Komodo IDE as well as set some environment variables. First, the edits.

    Edit DB\DBgrProperties.pm

    Open the Notepad++\plugins\PerlDebug\DB\DBgrProperties.pm file. Line 657-659 is something like:

    $res .= sprintf(qq(<value%s><![CDATA[%s]]></value>\n), $encoding ? qq( encoding="$encoding") : "", $encVal);

    Change that to:

    $res .= sprintf(qq(<![CDATA[%s]]>\n), $encVal);

    Also, further up on line 131, you'll see:


    Change that to:

    Edit perl5db.pl

    Open the Notepad++\plugins\PerlDebug\perl5db.pl file. On line 1525:

    $res .= sprintf(' line="%s"',

    change to:

    $res .= sprintf(' lineno="%s"',

    And, after line 2898, which should read:

    my $bpInfo = getBreakpointInfoString($bkptID, function => $bFuncti +on);

    add the following three lines:

    if ($bpInfo) { $res .= $bpInfo; }
    Environment Variables

    You'll need some environment variables to get this to work. I wanted them to be volatile so as not to upset normal operations. This where I used NppExec. I'll assume you have it installed as it's an awesome plugin that you should have installed. If not, get if from the Plugin Manager.

    The only essential environment variables to set are:

    set PERL5LIB=C:\path\to\Notepad++\plugins\PerlDebug set PERLDB_OPTS=RemotePort=

    where "\path\to\Notepad++" is your directory path to Notepad++. I have mine at "C:\usr\bin\npp\plugins\PerlDebug". Yours may be "C:\Program Files\Notepad++\plugins\PerlDebug". Note if your path has a space (like between "Program" and "Files" in the example, you'll probably need to double-quote the entire path assigned to PERL5LIB like: set PERL5LIB="C:\Program Files\Notepad++\plugins\PerlDebug".

    I set my variables with an NppExec script:

    NPP_SAVE cd "$(CURRENT_DIRECTORY)" NPP_MENUCOMMAND Plugins\DBGp\Debugger ENV_SET PERLDB_OPTS=RemotePort= ENV_SET PERL5LIB=$(SYS.PERL5LIB);$(NPP_DIRECTORY)\plugins\PerlDebug INPUTBOX "Command Line Arguments: " cmd /c start "Perl Debug" cmd /c perl.exe -d "$(FILE_NAME)" $(INPUT)

    I saved it as "Perl - Debug" and used NppExec to add it to my "Macro" menu in Notepad++. It saves the current file, changes to the working directory, enables the DBGp plugin, sets the environment variables (only temporarily within the Notepad++ context, and careful not to step on a current value that may be in PERL5LIB), prompts for any command-line input to pass to your script to get it to run and finally starts the Perl debugging session - integrated in Notepad++!

    Some options I used to tune the DBGp plugin; from the Notepad++ "Plugins" menu, select "DBGp" and then "Config...".

    • Ensure the top checkbox "Bypass all mapping (local windows setup) is checked
    • No configuration in the "Remote Server IP", "IDE KEY" ... window
    • Under the "Misc" section, check:
      • "Break at first line when debugging starts"
      • "Refresh local context on every step"
      • "Refresh global context on every step"

    Hope it works for you - happy debugging!

Add your Meditation
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.