<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3035323255246508397</id><updated>2011-12-14T22:56:34.388-08:00</updated><category term='lang=id'/><category term='javascript'/><category term='mysql'/><category term='php'/><category term='zak'/><category term='cpan'/><category term='steven'/><category term='perl'/><title type='text'>Perl Indonesia</title><subtitle type='html'>Indonesian Perl mongers, blogging about Perl and related stuffs in Bahasa Indonesia and English. Come join us if you are a fellow Indonesian monger!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Perl Indonesia</name><uri>http://www.blogger.com/profile/09083793321887864209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>88</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5392779601438985177</id><published>2011-10-19T00:08:00.001-07:00</published><updated>2011-10-19T00:26:34.824-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Menginstal Finance::Bank::ID::Mandiri untuk mengunduh transaksi Mandiri</title><content type='html'>Atas permintaan user, berikut ini panduan cara menggunakan modul Perl &lt;a href=http://search.cpan.org/dist/Finance-Bank-ID-Mandiri&gt;Finance::Bank::ID::Mandiri&lt;/a&gt; untuk mengunduh transaksi rekening bank Mandiri Anda. Panduan ini berasumsi Anda menggunakan Linux (Debian atau Ubuntu) dengan Perl 5.10 ke atas. Jika Anda menggunakan Windows, atau Linux dengan Perl di bawah 5.10 (mis: CentOS 5.x) harap menyesuaikan sendiri (atau, jika ada yang mau membuatkan tutorialnya, silakan hubungi saya).&lt;br /&gt;&lt;br /&gt;Modul serupa untuk BCA &lt;a href=http://search.cpan.org/dist/Finance-Bank-ID-BCA&gt;Finance::Bank::ID::BCA&lt;/a&gt; juga tersedia, cara menggunakannya mirip.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Prasyarat:&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Komputer dengan koneksi Internet bersistem operasi Linux (Debian/Ubuntu) dan Perl 5.10 ke atas&lt;br /&gt;&lt;li&gt;Program curl (untuk mendownload cpanminus)&lt;br /&gt;&lt;li&gt;Akses root (aplikasi bisa juga diinstal tanpa akses root, tapi agar mudahnya kita pakai root)&lt;br /&gt;&lt;li&gt;Rekening bank Mandiri dengan akses internet banking aktif (ada username dan password).&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Langkah-langkah:&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Instal modul-modul Perl yang dibutuhkan.&lt;/b&gt; Agar mudahnya, kita menggunakan &lt;a href=http://search.cpan.org/dist/App-cpanminus&gt;cpanminus&lt;/a&gt; untuk menginstal modul-modul Perl. Jika Anda belum menginstal cpanminus, silakan instal dulu sbb:&lt;br /&gt;&lt;br /&gt;Buka konsol, lalu ketik:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ curl -L http://cpanmin.us | perl - --sudo App::cpanminus&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Setelah itu, kita menginstal modul Mandiri dengan cpanminus:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ sudo cpanm -n Finance::Bank::ID::Mandiri&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Mengkonfigurasi program&lt;/b&gt;. Setelah selesai, Anda akan mendapatkan perintah &lt;b&gt;download-mandiri&lt;/b&gt;. Konfigurasi perintah ini dengan membuat file konfigurasi:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ mkdir ~/.app&lt;br /&gt;$ (buat/edit file download-mandiri.conf)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Isi file konfigurasi adalah sbb:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;[ALL]&lt;br /&gt;username = (username akun Mandiri Anda)&lt;br /&gt;password = (password akun Mandiri Anda)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Setelah itu tinggal jalankan perintah download-mandiri dari konsol. Defaultnya program akan mengunduh transaksi dalam format YAML selama sebulan terakhir. Bisa juga dioutput format JSON dan kustomisasi tanggal. Tambahkan opsi --debug jika ingin melihat pesan debugging. Anda juga bisa menjalankan skrip ini lewat cron agar berjalan otomatis secara periodik (mis: seminggu sekali atau sehari sekali).&lt;br /&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Jika mengalami masalah, silakan reply posting blog ini.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5392779601438985177?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5392779601438985177/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/10/menginstal.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5392779601438985177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5392779601438985177'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/10/menginstal.html' title='Menginstal Finance::Bank::ID::Mandiri untuk mengunduh transaksi Mandiri'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3798286174394183981</id><published>2011-07-27T20:37:00.001-07:00</published><updated>2011-07-27T20:41:39.491-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>App::UniqFiles (a case for building app with Dist::Zilla and Sub::Spec)</title><content type='html'>When watching videos at &lt;a href="http://tudou.com"&gt;Tudou&lt;/a&gt; or &lt;a href="http://youku.com"&gt;Youku&lt;/a&gt;, both Chinese YouTube-like video sites, you'll often get one/two 15- or 30-second video ads at the beginning. Since I download lots of videos recently, my Opera browser cache contains a bunch of these video ads files, each usually ranging from around 500k to a little over 1MB. But there are also duplicates.&lt;br /&gt;&lt;br /&gt;I thought I'd collect these ads, for learning Chinese, but I don't want the duplicates, only one file per different ad. The result: &lt;a href="http://search.cpan.org/dist/App-UniqFiles"&gt;App::UniqFiles&lt;/a&gt;, which contains a command-line script called &lt;b&gt;uniq-files&lt;/b&gt;. Now all I need to do is just type &lt;code&gt;mkdir .save; mv `uniq-files *` .save/&lt;/code&gt; and delete the duplicate videos, which are files not moved to &lt;code&gt;.save/&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;With the help of &lt;a href="http://search.cpan.org/dist/Dist-Zilla"&gt;Dist::Zilla&lt;/a&gt;, &lt;a href="http://search.cpan.org/dist/Sub-Spec-CmdLine"&gt;Sub::Spec::CmdLine&lt;/a&gt;, &lt;a href="http://search.cpan.org/dist/Pod-Weaver-Plugin-SubSpec"&gt;Pod::Weaver::Plugin::SubSpec&lt;/a&gt;, and &lt;a href="http://search.cpan.org/dist/Log-Any-App"&gt;Log::Any::App&lt;/a&gt;, I managed to finish App::UniqFiles, from scribbling down the concept to uploading the first release to CPAN and github, in just about under an hour (00:54 to be exact). Not super-speedy for a small script (I can probably write a one-off script version in 15-30 minutes), but for an extra 30 minutes, I get:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;a proper Perl distribution, with tests and POD and all;&lt;br /&gt;&lt;li&gt;all the core functionality contained in subroutines (which is much more reusable than a script);&lt;br /&gt;&lt;li&gt;a POD API documentation for the subroutines;&lt;br /&gt;&lt;li&gt;a command-line application with --help message, argument parsing, configurable log levels, even bash completion with just 3 lines of code.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I think developing with Dist::Zilla and Sub::Spec is great, mainly because they realize the DRY ("Don't Repeat Yourself") principle and free you from mundane tasks. Having to repeat the same stuffs or do mindless/tedious tasks is indeed a significant source of frustation for programmers. It deflects us from the real, important task: writing the code to actually solve our problems.&lt;br /&gt;&lt;br /&gt;Dist::Zilla allows you to generate dist's README from the main module's POD instead of you having to create this file manually. It inserts LICENSE, AUTHORS, VERSION sections to your POD instead of you having to insert and update them manually. It frees you from the mundane tasks like creating dist tarballs, checking ChangeLog, incrementing version numbers, uploading to CPAN, etc. Really, I wouldn't want to build dists manually ever again without tools like Dist::Zilla.&lt;br /&gt;&lt;br /&gt;Sub::Spec allows you to specify rich metadata for your sub in one place, from which you can generate Getopt::Long options, POD documentation, command-line --help message, etc from it, instead of you having to maintain each of them manually. Module like Sub::Spec::CmdLine also frees you from many mundane UI issues (which, coincidentally, I hate) like parsing arguments and formatting output data to screen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3798286174394183981?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3798286174394183981/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/07/appuniqfiles-case-for-building-app-with.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3798286174394183981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3798286174394183981'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/07/appuniqfiles-case-for-building-app-with.html' title='App::UniqFiles (a case for building app with Dist::Zilla and Sub::Spec)'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4335477473027068825</id><published>2011-07-25T21:43:00.000-07:00</published><updated>2011-07-25T22:11:03.857-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Undocumented Getopt::Long::Configure feature</title><content type='html'>&lt;a href="http://search.cpan.org/dist/Getopt-Long"&gt;Getopt::Long&lt;/a&gt; has a Configure() function to let you customize its parsing behaviour, e.g. whether or not to be case-sensitive, whether or not unknown options are passed unmodified or generate an error, etc. However, this customization is global: it affects every piece of code using Getopt::Long.&lt;br /&gt;&lt;br /&gt;Since I use Getopt::Long in a utility module, which might conflict with the module user using Getopt::Long along with my module, I need to localize my Configure() effect. I was about to submit an RT wishlist ticket pertaining to this, but some quick checking revealed that Configure() already has this feature.&lt;br /&gt;&lt;br /&gt;Configure() returns an arrayref containing all the current options. If you pass this arrayref to it, it will set all the options. This way, you can save and restore options.&lt;br /&gt;&lt;br /&gt;Thanks to the Getopt::Long author, &lt;a href="http://search.cpan.org/~jv/"&gt;Johan Vromans&lt;/a&gt;, who apparently has maintained this module since 1990!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4335477473027068825?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4335477473027068825/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/07/undocumented-getoptlongconfigure.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4335477473027068825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4335477473027068825'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/07/undocumented-getoptlongconfigure.html' title='Undocumented Getopt::Long::Configure feature'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4901168652845315288</id><published>2011-06-16T20:54:00.000-07:00</published><updated>2011-06-16T20:59:53.747-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Using Org format to document code</title><content type='html'>My most recent hacktivity includes preparing Org::Export::Pod and Org::Export::Text (both not yet ready) following &lt;a href="http://search.cpan.org/dist/Org-Export-HTML"&gt;Org::Export::HTML&lt;/a&gt;. I am planning to document source code (currently just for &lt;a href="https://github.com/sharyanto/perl-Sub-Spec-Gen-ReadTable/blob/master/lib/Sub/Spec/Gen/ReadTable.pm#L565"&gt;functions&lt;/a&gt;) using &lt;a href="http://orgmode.org/manual/index.html"&gt;Org&lt;/a&gt; as the master format instead of POD. From Org, I'll be exporting to various target formats, including POD itself, inserted to modules' source code in the build process using a simple Dist::Zilla plugin.&lt;br /&gt;&lt;br /&gt;Now why Org? First and foremost, obviously because I use Emacs, and the last few months I've migrated practically all of my notes/todolists/addressbooks to this format. Also, it's visually nicer to look at than POD when it comes to things like headings and lists. Org also supports tables (I understand that there's an extension to POD that supports tables too, but I imagine it will not be as easy to write?). BTW, among other lightweight markup languages, Markdown Extra also supports tables with an equally nice syntax.&lt;br /&gt;&lt;br /&gt;A couple of concerns for Org. First, writing literal examples is a bit more cumbersome. Where in Pod or Markdown or most Wiki format you only need to indent to go verbatim, in Org you need to enclose with #+BEGIN_SRC ... #+END_SRC or prepend each line with ": ". But I've come to accept it.&lt;br /&gt;&lt;br /&gt;Second is parser support in other languages. Since I envision ultimately my &lt;a href="http://search.cpan.org/dist/Sub-Spec"&gt;function specs&lt;/a&gt; is to be processed by other languages too, it would be nice if there are support for the document parser in these languages, including for Javascript and PHP. In this regard, Markdown seems to be a win.&lt;br /&gt;&lt;br /&gt;But hey, Org is still readable as-is, and currently nothing beats Org-mode for writing notes. So Org FTW!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4901168652845315288?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4901168652845315288/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/06/using-org-format-to-document-code.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4901168652845315288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4901168652845315288'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/06/using-org-format-to-document-code.html' title='Using Org format to document code'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6220248588989461724</id><published>2011-03-30T00:29:00.000-07:00</published><updated>2011-03-30T19:39:27.243-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Bench: a simpler benchmark module</title><content type='html'>There was a post in &lt;a href=http://blogs.perl.org&gt;blogs.perl.org&lt;/a&gt; or &lt;a href=http://ironman.enlightenedperl.org/&gt;Planet Perl Iron Man&lt;/a&gt; (sorry, forgot the exact article) that said something along the line of: "Benchmark is a fine module, but for simplicity I'll use the time command". Which immediately hit home with me, because I too very seldomly use Benchmark. I guess the problem is I almost always have to perldoc it before using it, and there are quite some extra characters to type.&lt;br /&gt;&lt;br /&gt;So last weekend I wrote &lt;a href=http://search.cpan.org/dist/Bench&gt;Bench&lt;/a&gt; (&lt;a href=https://github.com/sharyanto/perl-Bench&gt;repo&lt;/a&gt;) that's hopefully simpler enough to get used more.&lt;br /&gt;&lt;br /&gt;To benchmark your program, just type: &lt;code&gt;perl -MBench yourscript.pl&lt;/code&gt;. Sample output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ perl -Ilib -MBench -MMoose -e1&lt;br /&gt;0.229s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Bench exports a single function, bench(), by default. To time a single sub, use: &lt;code&gt;perl -MBench -e'bench sub { ... }'&lt;/code&gt;. By default it will call your sub at most 100 times or 1 second. Here's a sample output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;100 calls (12120/s), 0.0083s (0.0825ms/call)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To benchmark several subs: &lt;code&gt;perl -MBench -e'bench {a=&gt;sub{...}, b=&gt;sub{...}}'&lt;/code&gt; or &lt;code&gt;perl -MBench -e'bench [sub{...}, sub{...}]'&lt;/code&gt;. Sample output:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;a: 100 calls (12120/s), 0.0083s (0.0825ms/call)&lt;br /&gt;b: 100 calls (5357/s), 0.0187s (0.187ms/call)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Bench will automatically use &lt;a href=http://search.cpan.org/dist/Dumbbench&gt;Dumbbench&lt;/a&gt; if it's already loaded, e.g.: &lt;code&gt;perl -MDumbbench -MBench -e'...'&lt;/code&gt;. Or you can force Bench to use Dumbbench: &lt;code&gt;perl -MBench -e'bench sub { ... }, {dumbbench=&gt;1}'&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;That's about it currently.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6220248588989461724?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6220248588989461724/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/03/bench-simpler-benchmark-module.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6220248588989461724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6220248588989461724'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/03/bench-simpler-benchmark-module.html' title='Bench: a simpler benchmark module'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1392467377108769687</id><published>2011-03-17T07:02:00.001-07:00</published><updated>2011-03-17T07:02:46.929-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Org::Parser</title><content type='html'>If you're like me, over the years you'll have had your todo lists scattered over multiple programs and places. First a simple text file with homebrewn format, then various Windows programs, then various Linux GUI programs, then back to Notepad and joe/gedit/kate, then various apps on cellphones, then pencil &amp; paper (due to cellphones keep getting lost/stolen), then some cloud apps, then &lt;a href=http://todotxt.com&gt;todo.txt&lt;/a&gt;, then finally &lt;a href=http://orgmode.org&gt;org-mode&lt;/a&gt;. And if you're anything like me or many others, you'll find that org-mode is *it*.&lt;br /&gt;&lt;br /&gt;I'm now in the (long, boring) process of consolidating everything in Org. For todo lists, contact lists, and even long documents and all journals/diaries. I've written a preliminary version of &lt;a href=http://search.cpan.org/dist/Org-Parser/&gt;Org::Parser&lt;/a&gt; to help automate stuffs via the command line. It only supports the basic stuffs at the moment but has been able to parse all my *.org files.&lt;br /&gt;&lt;br /&gt;The code is available &lt;a href=https://github.com/sharyanto/perl-Org-Parser&gt;on GitHub&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1392467377108769687?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1392467377108769687/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/03/orgparser.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1392467377108769687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1392467377108769687'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/03/orgparser.html' title='Org::Parser'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3100616488097858645</id><published>2011-02-14T23:27:00.000-08:00</published><updated>2011-02-14T23:36:39.571-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Backup data dengan dengan Perl, rsync, dan git</title><content type='html'>Saat ini, saya menyimpan data pribadi di 2 direktori utama: ~/repos dan ~/media. Semua file-file teks (termasuk source code, website, catatan/tulisan, konfigurasi, agenda .org Emacs) ditaruh di bawah ~/repos di dalam repo-repo git, per proyek (Contoh: ada ~/repos/settings, ~/repos/writings, ~/repos/perl-Git-Bunch, dsb). Semua file lain yang berupa file media besar-besar ditaruh di ~/media.&lt;br /&gt;&lt;br /&gt;Untuk membackup data di ~/media, saya menggunakan &lt;a href="http://search.cpan.org/dist/File-RsyBak"&gt;File::RsyBak&lt;/a&gt;, yang menyediakan skrip command-line &lt;b&gt;rsybak&lt;/b&gt;. Skrip ini pada dasarnya hanyalah wrapper untuk perintah rsync dan membuat snapshot-snapshot backup sesuai jangka waktu histori yang diinginkan (defaultnya: 7 harian + 4 mingguan + 3 bulanan). Skrip ini dijalankan tiap hari lewat cron dan backupnya disimpan di harddisk terpisah /backup.&lt;br /&gt;&lt;br /&gt;Untuk membackup data di ~/repos, saya menggunakan &lt;a href="http://search.cpan.org/dist/Git-Bunch"&gt;Git::Bunch&lt;/a&gt;, yang menyediakan skrip command-line &lt;b&gt;gitbunch&lt;/b&gt;. Pada dasarnya, gitbunch membackup menggunakan rsync juga, tapi tanpa histori (karena git sudah menyimpan sejarah perubahan). Selain itu, yang dibackup juga hanya subdirektori .git/ dari tiap repo. Ini mengirit ruang disk, karena ~/repos masih sering saya kopi ke flashdisk yang kapasitasnya terbatas. Untuk merestore dari backup, kita tinggal melakukan "git checkout" dari hasil backup .git/ tiap repo ini.&lt;br /&gt;&lt;br /&gt;Skrip gitbunch juga dapat melakukan sinkronisasi dari satu direktori ~/repos ke direktori ~/repos lainnya. Pada intinya, "gitbunch sync" hanyalah wrapper untuk "git pull". Dengan cara ini, saya bisa mensinkronkan pekerjaan PC ke netbook atau sebaliknya dengan mudah.&lt;br /&gt;&lt;br /&gt;Artikel yang lebih mendetil, pernah ditulis untuk majalah InfoLINUX: &lt;a href="http://kb.masterweb.net/beta/index.cgi/read/Artikel:Manajemen_data_pribadi_dengan_git"&gt;Manajemen data pribadi dengan git&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Bagaimana strategi backup Anda?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3100616488097858645?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3100616488097858645/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/02/backup-data-dengan-git.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3100616488097858645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3100616488097858645'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/02/backup-data-dengan-git.html' title='Backup data dengan dengan Perl, rsync, dan git'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-189465503489634209</id><published>2011-02-07T08:06:00.001-08:00</published><updated>2011-02-07T08:07:46.997-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The coming bloated Perl apps?</title><content type='html'>A few weeks ago, I got annoyed by the fact that one of our command line applications was getting slower and slower to start up (the delay was getting more and more noticable), so I thought I'd do some refactoring, e.g. split large files into smaller ones and delay loading modules until necessary.&lt;br /&gt;&lt;br /&gt;Sure enough, one of the main causes of the slow start up was preloading too many modules. Over the years I had been blindly sticking 'use' statements into our kitchen sink $Proj::Utils module, which was used by almost all scripts in the project. Loading $Proj::Utils alone pulled in over 60k lines from around 150 files!&lt;br /&gt;&lt;br /&gt;After I split things up, it became clearer which modules are particularly heavy. This one stood out:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% time perl -MFile::ChangeNotify -e1&lt;br /&gt;real   0m0.972s&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% perl -MDevel::EndStats -e1&lt;br /&gt;# Total number of module files loaded: 129&lt;br /&gt;# Total number of modules lines loaded: 46385&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So almost 130 files and a total of 45k+ lines just from loading File::ChangeNotify alone. 130 files just for a filesystem monitoring routine! Who would've thought that a filesystem monitor needs so many lines of program? Compare with, say, a recent HTTP client:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% perl -MHTTP::Tiny -e1&lt;br /&gt;# Total number of module files loaded: 18&lt;br /&gt;# Total number of modules lines loaded: 6089&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I quickly switched to Linux::Inotify2 and things are much better now (but I might have to revisit this since we want to give the new Debian/kFreeBSD a Squeeze).&lt;br /&gt;&lt;br /&gt;As I suspected (since the module is written by Dave Rolsky also), File::ChangeNotify utilizes Moose, which is not particularly lightweight either:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% time perl -MMoose -e1&lt;br /&gt;real    0m0.712s&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% perl -MDevel::EndStats -MMoose -e1&lt;br /&gt;# Total number of module files loaded: 100&lt;br /&gt;# Total number of modules lines loaded: 35760&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Compare with:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% time perl -MMouse -e1&lt;br /&gt;real    0m0.089s&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;% perl -MDevel::EndStats -MMouse -e1&lt;br /&gt;# Total number of module files loaded: 20&lt;br /&gt;# Total number of modules lines loaded: 6675&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Come to think of it, running Dist::Zilla is also quite painfully slow these days. Just running "dzil foo" pulled in around 60k lines and took 1.7s! Of course, dzil is Moose-based.&lt;br /&gt;&lt;br /&gt;While it is a good thing that Moose is getting more popular, it's a bit shameful to see that Ruby and Python scripts "get OO for free" while Moose scripts have to endure a 0.7s startup penalty. Mouse, Moo, Role::Basic come to the rescue but I wonder what would Ruby/Python programmers think (you have how many object systems?? Why do you people can never agree on one thing and TIMTOWTDI everything?)&lt;br /&gt;&lt;br /&gt;Disclaimer: Number of lines includes all blanks/comment/POD/DATA/etc from all files loaded in %INC, actual SLOC is probably significantly less. Timing is done on a puny HP Mininote netbook (Atom N450 1.66GHz) which I'm currently stuck with in the past few weeks. With all due respects to all authors of modules mentioned. They all write fantastic, working code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-189465503489634209?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/189465503489634209/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2011/02/few-weeks-ago-i-got-annoyed-by-fact.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/189465503489634209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/189465503489634209'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2011/02/few-weeks-ago-i-got-annoyed-by-fact.html' title='The coming bloated Perl apps?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5697325571380941176</id><published>2010-11-19T04:07:00.000-08:00</published><updated>2010-11-19T04:08:10.122-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Outputting pretty data structure on console programs</title><content type='html'>&lt;p&gt;Our application has a command-line API interface for convenient access via shell/console. It used to output API result data in YAML:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# /c/sbin/spanel api --yaml File list --account steven --volume data --dir /public&lt;br /&gt;--- &lt;br /&gt;dir: &lt;br /&gt;  atime: '1270675429'&lt;br /&gt;  ctime: '1285916065'&lt;br /&gt;  gid: 1023&lt;br /&gt;  group: steven&lt;br /&gt;  is_dir: 1&lt;br /&gt;  mtime: '1285916065'&lt;br /&gt;  perms: 493&lt;br /&gt;  uid: 1012&lt;br /&gt;  url: ~&lt;br /&gt;  user: steven&lt;br /&gt;entries: &lt;br /&gt;  - &lt;br /&gt;    atime: '1284665000'&lt;br /&gt;    ctime: '1289609859'&lt;br /&gt;    dir: /public&lt;br /&gt;    gid: 1023&lt;br /&gt;    group: steven&lt;br /&gt;    icon_file: folder.gif&lt;br /&gt;    inode: 1984908&lt;br /&gt;    is_dir: 1&lt;br /&gt;    is_link: 0&lt;br /&gt;    mtime: '1289609859'&lt;br /&gt;    name: git&lt;br /&gt;    perms: 493&lt;br /&gt;    reldir: ''&lt;br /&gt;    size: 4096&lt;br /&gt;    uid: 1012&lt;br /&gt;    url: ~&lt;br /&gt;    user: steven&lt;br /&gt;  - &lt;br /&gt;    atime: '1270675424'&lt;br /&gt;    ctime: '1285130140'&lt;br /&gt;    dir: /public&lt;br /&gt;    gid: 1023&lt;br /&gt;    group: steven&lt;br /&gt;    icon_file: text.gif&lt;br /&gt;    inode: 1976727&lt;br /&gt;    is_dir: 0&lt;br /&gt;    is_link: 0&lt;br /&gt;    mtime: '1155368486'&lt;br /&gt;    name: .htaccess&lt;br /&gt;    perms: 436&lt;br /&gt;    reldir: ''&lt;br /&gt;    size: 48&lt;br /&gt;    uid: 1012&lt;br /&gt;    url: ~&lt;br /&gt;    user: steven&lt;br /&gt;  - &lt;br /&gt;    atime: '1270675424'&lt;br /&gt;    ctime: '1285130140'&lt;br /&gt;    dir: /public&lt;br /&gt;    gid: 1023&lt;br /&gt;    group: steven&lt;br /&gt;    icon_file: unknown.gif&lt;br /&gt;    inode: 1976725&lt;br /&gt;    is_dir: 0&lt;br /&gt;    is_link: 0&lt;br /&gt;    mtime: '1155368397'&lt;br /&gt;    name: .htaccess~&lt;br /&gt;    perms: 436&lt;br /&gt;    reldir: ''&lt;br /&gt;    size: 63&lt;br /&gt;    uid: 1012&lt;br /&gt;    url: ~&lt;br /&gt;    user: steven&lt;br /&gt;total_num_entries: 3&lt;br /&gt;url: ~&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;YAML is relatively readable if you compare to JSON or (shudder) XML, but I soon grew tired of reading YAML for data that should be tabulated and better formatted for human consumption.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Thus, &lt;a href="http://search.cpan.org/dist/Data-Format-Pretty-Console"&gt;Data::Format::Pretty::Console&lt;/a&gt;. The idea is for me, a lazy programmer, to throw it data structure of various kind and it will display it nicely suitable for console viewing. The command line API interface now by default shows nicely formatted text for API result data (but still provides --yaml and --json option). Please bear with this blog post's misformatting and assume it's all pretty:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;dir:&lt;br /&gt;.---------------------.&lt;br /&gt;| key    | value      |&lt;br /&gt;+--------+------------+&lt;br /&gt;| atime  | 1270675429 |&lt;br /&gt;| ctime  | 1285916065 |&lt;br /&gt;| gid    |       1023 |&lt;br /&gt;| group  | steven     |&lt;br /&gt;| is_dir |          1 |&lt;br /&gt;| mtime  | 1285916065 |&lt;br /&gt;| perms  |        493 |&lt;br /&gt;| uid    |       1012 |&lt;br /&gt;| url    |            |&lt;br /&gt;| user   | steven     |&lt;br /&gt;'--------+------------'&lt;br /&gt;&lt;br /&gt;entries:&lt;br /&gt;.----------------------------------------------------------------------------------------------------------------------------------------------------------------------.&lt;br /&gt;| atime      | ctime      | dir     | gid  | group  | icon_file   | inode   | is_dir | is_link | mtime      | name       | perms | reldir | size | uid  | url | user   |&lt;br /&gt;+------------+------------+---------+------+--------+-------------+---------+--------+---------+------------+------------+-------+--------+------+------+-----+--------+&lt;br /&gt;| 1284665000 | 1289609859 | /public | 1023 | steven | folder.gif  | 1984908 |      1 |       0 | 1289609859 | git        |   493 |        | 4096 | 1012 |     | steven |&lt;br /&gt;| 1270675424 | 1285130140 | /public | 1023 | steven | text.gif    | 1976727 |      0 |       0 | 1155368486 | .htaccess  |   436 |        |   48 | 1012 |     | steven |&lt;br /&gt;| 1270675424 | 1285130140 | /public | 1023 | steven | unknown.gif | 1976725 |      0 |       0 | 1155368397 | .htaccess~ |   436 |        |   63 | 1012 |     | steven |&lt;br /&gt;'------------+------------+---------+------+--------+-------------+---------+--------+---------+------------+------------+-------+--------+------+------+-----+--------'&lt;br /&gt;&lt;br /&gt;total_num_entries:&lt;br /&gt;3&lt;br /&gt;&lt;br /&gt;url:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5697325571380941176?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5697325571380941176/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/11/outputting-pretty-data-structure-on.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5697325571380941176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5697325571380941176'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/11/outputting-pretty-data-structure-on.html' title='Outputting pretty data structure on console programs'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2174212733335842564</id><published>2010-11-17T20:53:00.003-08:00</published><updated>2010-11-17T20:53:35.622-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Comparison of INI-format modules on CPAN</title><content type='html'>I'm not terribly happy with the state of Perl/CPAN support for the INI file format.&lt;br /&gt;&lt;br /&gt;I have this requirement of modifying php.ini files programmatically from Perl like: set register_globals to On/Off, add/remove some extension (via the extension=foo lines), adding/removing some functions from the disabled_functions list, etc. So I would like to find a CPAN module that can just set/unset a parameter and leave formatting/comments alone as much as possible.&lt;br /&gt;&lt;br /&gt;Turns out that among a dozen or so of INI modules on CPAN, a few of them do not do writes at all (e.g. &lt;a href="http://search.cpan.org/dist/Config-INI-Access"&gt;Config::INI::Access&lt;/a&gt; or &lt;a href="http://search.cpan.org/dist/Config-Format-INI"&gt;Config::Format::INI&lt;/a&gt;). And a few that do, write a la dump. That is, they just rewrite the whole INI file with the in-memory structure. All comments and formatting (even ordering, in some cases) are lost. Example: &lt;a href="http://search.cpan.org/dist/Config-INI-Writer"&gt;Config::INI::Writer&lt;/a&gt; and &lt;a href="http://search.cpan.org/dist/Tie-Cfg"&gt;Tie::Cfg&lt;/a&gt;. And, last time I tried, I couldn't even install Config::IniHash from the CPAN client. Not good.&lt;br /&gt;&lt;br /&gt;So I ended up with &lt;a href="http://search.cpan.org/dist/Config-IniFiles"&gt;Config::IniFiles&lt;/a&gt;. And I needed to patch two features in before I could even read php.ini and write to it properly. This is an old module, which although still maintained, probably needs a rewrite or modernization. One reviewer in CPAN Ratings also wrote that this module fails in edge cases and the test suite is incomplete.&lt;br /&gt;&lt;br /&gt;But, at least this module gets the work done. It tries to maintain comments, and even has a host of other features like delta, multiline, default section, etc. Most features seem to be rather exotic to me personally, but then none of the other INI modules on CPAN has the basic features that I needed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2174212733335842564?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2174212733335842564/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/11/comparison-of-ini-format-modules-on.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2174212733335842564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2174212733335842564'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/11/comparison-of-ini-format-modules-on.html' title='Comparison of INI-format modules on CPAN'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-290597848745219587</id><published>2010-11-17T20:53:00.001-08:00</published><updated>2010-11-17T20:53:22.631-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>(Short, grossly incomplete) comparison of Perl logging frameworks</title><content type='html'>After doing &lt;a href="http://blogs.perl.org/users/steven_haryanto/2010/09/comparison-of-perl-serialization-modules.html"&gt;this post on comparison of Perl serialization modules&lt;/a&gt;, I intended to continue with other comparisons, and even thought on setting up a wiki or creating/maintaining a section on the &lt;a href="https://www.socialtext.net/perl5/index.cgi"&gt;Official Perl 5 Wiki&lt;/a&gt;, which already has a Recommended Modules section, although there is not much comparison being written for each recommendation. (Btw, I just noticed a change of domain for the Wiki, from perlfoundation.org to socialtext.net).&lt;br /&gt;&lt;br /&gt;But of course other tasks soon took precedence, so until the Wiki idea is realized, I thought I'll just continue posting on the blog as usual.&lt;br /&gt;&lt;br /&gt;There are **seriously** too many Perl logging frameworks out there. As the Log4perl FAQ mentions, "Writing a logging module is like a rite of passage for every Perl programmer, just like writing your own templating system."&lt;br /&gt;&lt;br /&gt;So I'm not going to pretend like I've evaluated even half of logging modules that are on CPAN. Instead I'm just going to include a few worth mentioning.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Log::Dispatch and Log::Log4perl. &lt;/strong&gt;Two of the arguably most popular Perl logging frameworks are &lt;a href="http://search.cpan.org/dist/Log-Dispatch"&gt;Log::Dispatch&lt;/a&gt; and &lt;a href="http://search.cpan.org/dist/Log-Log4perl"&gt;Log::Log4perl&lt;/a&gt;. They are like the Moose of logging frameworks: mature, feature rich, flexible, has a lot of support/extra/3rd party modules, but... "slow". I quote the slow part because first of all, speed is not an issue for the majority of applications. And second of all, they are not relatively slow at all compared to other modules until they actually log stuff to output. For example, doing debug() on a warn level is around 1,5mils/sec with with Log4perl, and 3mils/sec with Log::Fast. But for actual logging, Log::Fast can be 10-45 times faster than these two.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Log::Any&lt;/strong&gt;. For most people, Log::Dispatch and Log4perl should suffice. I personally haven't been unable to produce a case where I can't customize Log4perl they way I want. This shows the flexibility of the module. So the only thing left for flexibility is a thin wrapper where you might want to switch logging framework (kind of like Any::Moose for logging). There are a few of these on CPAN, but I prefer &lt;a href="http://search.cpan.org/dist/Log-Any"&gt;Log::Any&lt;/a&gt; (and I've also made a thin wrapper for *that*, &lt;a href="http://search.cpan.org/dist/Log-Any-App"&gt;Log::Any::App&lt;/a&gt;). RJBS also made one: &lt;b&gt;&lt;a href="http://search.cpan.org/dist/Log-Dispatchoulli"&gt;Log::Dispatchoulli&lt;/a&gt;&lt;/b&gt;. You might be interested in using it if you are interested in using &lt;a href="http://search.cpan.org/dist/String-Flogger"&gt;String::Flogger&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Performance-wise, as with Moose, there are other alternatives: &lt;a href="http://search.cpan.org/dist/Log-Fast"&gt;Log::Fast&lt;/a&gt;, for one. There are also a few other minimalistic frameworks, but I do not recommend using them as many of them are not flexible at all. Unless your application is really performance-critical.&lt;br /&gt;&lt;br /&gt;I've most probably left out a lot of possibly interesting alternatives.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-290597848745219587?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/290597848745219587/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/11/short-grossly-incomplete-comparison-of.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/290597848745219587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/290597848745219587'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/11/short-grossly-incomplete-comparison-of.html' title='(Short, grossly incomplete) comparison of Perl logging frameworks'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-9181947985911027555</id><published>2010-10-01T08:39:00.001-07:00</published><updated>2010-10-01T08:39:11.394-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Sometimes you *don't* want circular checking</title><content type='html'>I use the nifty &lt;a href="http://search.cpan.org/dist/Data-Rmap"&gt;Data::Rmap&lt;/a&gt; to "flatten" DateTime objects into strings so they can be exported to JSON and handled outside Perl. But due to circular checking in Data::Rmap, this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -MData::Rmap=:all -MData::Dump \&lt;br /&gt;-e'$d = DateTime-&gt;now; $doc = [$d, $d]; &lt;br /&gt;rmap_ref { $_ = $_-&gt;ymd if UNIVERSAL::isa($_, "DateTime") } $doc; &lt;br /&gt;dd $doc'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;produces something like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;["2010-10-01", ...unconverted DateTime object...]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;For now I work around this by defeating Data::Rmap's circular checking, though I wonder if there's a better way.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -MData::Rmap=:all -MData::Dump \ &lt;br /&gt;-e'$d = DateTime-&gt;now; $doc = [$d, $d]; &lt;br /&gt;rmap_ref { $_[0]{seen} = {}; $_ = $_-&gt;ymd if UNIVERSAL::isa($_, "DateTime") } $doc; &lt;br /&gt;dd $doc'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;will correctly produce:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;["2010-10-01", "2010-10-01"]&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-9181947985911027555?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/9181947985911027555/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/10/sometimes-you-dont-want-circular.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/9181947985911027555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/9181947985911027555'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/10/sometimes-you-dont-want-circular.html' title='Sometimes you *don&apos;t* want circular checking'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7916869135865519411</id><published>2010-09-30T17:56:00.000-07:00</published><updated>2010-10-01T01:27:11.929-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Yet another stupid mistake #1</title><content type='html'>During a refactor of a data from array @foo to hash %foo, I used 'each' to iterate over the hash, but forgot to change the 'for' statement with 'while'. So I ended up with something like:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -MData::Dump -E'%a=(a=&gt;1, b=&gt;2);&lt;br /&gt;for (my ($k, $v) = each %a) { $_ = "$k x"; dd {k=&gt;$k, v=&gt;$v, "\$_"=&gt;$_} }'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And this is nasty because for(@ary) aliases $_ to each element in @ary, and in this case it modifies $k (quiz #1: and $v too, do you know why?) right under your nose! Thus the result are really messed up:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;{ "\$_" =&gt; "a x", "k" =&gt; "a x", "v" =&gt; 1 }&lt;br /&gt;{ "\$_" =&gt; "a x x", "k" =&gt; "a x", "v" =&gt; "a x x" }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Not to mention the loop stops after processing two items (quiz #2: do you know why?) But you might not realize that after you add some pairs to %a and wondering why they don't get processed.&lt;br /&gt;&lt;br /&gt;The error message Perl gives is not really helpful, to say the least :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7916869135865519411?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7916869135865519411/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/09/yet-another-stupid-mistake-1.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7916869135865519411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7916869135865519411'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/09/yet-another-stupid-mistake-1.html' title='Yet another stupid mistake #1'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3369353113695305304</id><published>2010-09-23T03:28:00.002-07:00</published><updated>2010-09-23T04:02:29.140-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Comparison of Perl serialization modules</title><content type='html'>A while ago I needed a Perl data serializer with some requirements (supports circular references and Regexp objects out of the box, consistent/canonical output due output will be hashed). Here's my rundown of currently available data serialization Perl modules. A few notes: the labels fast/slow is relative to each other and are not the result of extensive benchmarking.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Data::Dumper&lt;/b&gt;. The grand-daddy of Perl serialization module. Produces Perl code with adjustable indentation level (default is lots of indentation, so output is verbose). Slow. Available in core since the early days of Perl 5 (5.005 to be exact). To unserialize, we need to do eval(), which might not be good for security. Usually the first choice for many Perl programmers when it comes to serialization and arguably the most popular module for that purpose.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Storable&lt;/b&gt;. Fast. Produces compact, portable binary output. Also available in core distribution. Does not support Regexp objects out of the box (though adding support for that requires only a few lines). Binary format used to change several times in the past without backward compatibility in the newer version of the module, giving people major PITA. Supposedly stabilized now.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;YAML::XS&lt;/b&gt;. Fast. Verbose YAML output (currently doesn't seem to have option to output inline YAML). My personal experience in the past is sometimes this module behaved weirdly and died with a cryptic error, but I guess currently it's pretty stable.&lt;br /&gt;&lt;br /&gt;There are other YAML implementations like YAML::Syck (also pretty speedy) and the old Pure-Perl YAML.pm and partial implementation YAML::Tiny. The last two might not be a good choice for general serialization needs.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Data::Dump&lt;/b&gt;. Very slow. Produces nicely indented Perl output. The strength of this module is in pretty output and flexibility in customizing the formatting process. Based on Data::Dump I've hacked two other specialized modules: &lt;a href="http://search.cpan.org/dist/Data-Dump-PHP"&gt;Data::Dump::PHP&lt;/a&gt; for producing PHP code, and &lt;a href="http://search.cpan.org/dist/Data-Dump-Partial"&gt;Data::Dump::Partial&lt;/a&gt; to produce compact and partial Perl output for logging.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;XML::Dumper&lt;/b&gt;. Produces *very* verbose (as is the case with all XML) XML output. Slow. Aside from the XML format, I don't think there's a reason why you should choose this over the others.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JSON::XS&lt;/b&gt;. Fast, outputs pretty compact but still readable code, but does not support circular references or Regexp objects.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JSYNC&lt;/b&gt;. Slow, outputs JSON and in addition supports circular references but not yet Regexp objects.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;FreezeThaw&lt;/b&gt;. Slow, produces compact output but not as compact as Storable. Does not support Regexp objects out of the box.&lt;br /&gt;&lt;br /&gt;Apart from these there are many other choices too, but I personally don't think any of them is interesting enough to be a favorite. For example, last time I checked &lt;b&gt;PHP::Serialization&lt;/b&gt; (and all the other PHP-related modules) does not support circular references. There's also, for example, &lt;b&gt;Data::Pond&lt;/b&gt;: cute concept but of little practical use as it is even more limited than JSON format.&lt;br /&gt;&lt;br /&gt;There are also numerous alternatives to Data::Dumper/Data::Dump, producing Perl or Perl-like code or indented formatted output, but they are either: not unserializable back to data structures (so, they are more of a formatting module instead of serialization module) or focus on pretty printing instead of speed. In general I think most Data::Dumper-like modules are slow when it comes to serializing data.&lt;br /&gt;&lt;br /&gt;In conclusion, choice is good but I have not found my perfect general serialization module yet. My two favorites are Storable and YAML::XS. If JSYNC is faster and supports Regexp, or if YAML::XS or YAML::Syck can output inline/compact YAML, that would be as near to perfect as I would like it.&lt;br /&gt;&lt;br /&gt;Hope this comparison is useful. Corrections and additions welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3369353113695305304?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3369353113695305304/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/09/comparison-of-perl-serialization.html#comment-form' title='5 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3369353113695305304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3369353113695305304'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/09/comparison-of-perl-serialization.html' title='Comparison of Perl serialization modules'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3568689835935571106</id><published>2010-09-23T03:28:00.001-07:00</published><updated>2010-09-23T03:28:41.190-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl vs PHP (a bit of credit to PHP)</title><content type='html'>Just read &lt;a href="http://podcats.in/general/perl-vs-php-1"&gt;this blog post&lt;/a&gt;. Comments are disabled, so I thought I'd add a blog post.&lt;br /&gt;&lt;br /&gt;There are endless ways we can sneer at PHP's deficiencies, but since 5.3 PHP already supports anonymous subroutines, via the &lt;b&gt;function (args) { ... }&lt;/b&gt; syntax. So:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$longestLine = max(&lt;br /&gt;    array_map(&lt;br /&gt;        create_function('$a', 'return strlen($a);'), &lt;br /&gt;        explode("\n", $str)&lt;br /&gt;    )&lt;br /&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;can be rewritten as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$longestLine = max(&lt;br /&gt;    array_map(&lt;br /&gt;        function($a) { return strlen($a); }, &lt;br /&gt;        explode("\n", $str)&lt;br /&gt;    )&lt;br /&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;though the example is not a good one since it might as well be:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$longestLine = max(&lt;br /&gt;    array_map(&lt;br /&gt;        'strlen',&lt;br /&gt;        explode("\n", $str)&lt;br /&gt;    )&lt;br /&gt;);&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3568689835935571106?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3568689835935571106/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/09/perl-vs-php-bit-of-credit-to-php.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3568689835935571106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3568689835935571106'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/09/perl-vs-php-bit-of-credit-to-php.html' title='Perl vs PHP (a bit of credit to PHP)'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5253377113659587090</id><published>2010-09-01T21:03:00.000-07:00</published><updated>2010-09-02T07:19:17.803-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Book review: Catalyst 5.8 The Perl MVC Framework</title><content type='html'>&lt;strong&gt;Book information&lt;/strong&gt;&lt;br /&gt;Title: Catalyst 5.8 The Perl MVC Framework.&lt;br /&gt;Subtitle: Build Scalable and extendable web applications using the Agile MVC framework.&lt;br /&gt;Author: Antano Solar John.&lt;br /&gt;Publisher: Packt Publishing.&lt;br /&gt;Country: UK/India.&lt;br /&gt;Year: 2010.&lt;br /&gt;&lt;br /&gt;This book is a follow up to the 2007 Catalyst book by Jonathan Rockway (member of Catalyst core developer team). I have no idea how much of the content is changed between the two.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;About the review(er)&lt;/strong&gt;&lt;br /&gt;This is a review on the electronic (PDF) edition of the book. I am a Perl developer and a CPAN author, but have not used Catalyst (or most other recent web frameworks, for that matter) before.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;About Catalyst&lt;/strong&gt;&lt;br /&gt;So far I've managed to avoid learning about web frameworks and continue to create web applications the old way (CGI/CGI::Fast, direct DBI/SQL, a homemade simple templating language, and recently lots of jQuery and CSS play). Part of this is due to laziness, and part due to lack of need. I've never needed to create complex web applications in Perl. And the apparently heavy learning curve and complexities of Catalyst, Mojo, Dancer, etc just make me say don't bother.&lt;br /&gt;&lt;br /&gt;But, thanks to this book, I find out that Catalyst project is not unlike a Perl CPAN module, with files/subdirectories like Makefile.PL, Changes, README, lib/, t/, etc. You can now even manage your project with Dist::Zilla (not mentioned in the book though as the plugin for this is new).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The good&lt;/strong&gt;&lt;br /&gt;This book is only about 200 (instead of 500+) pages long, which I appreciate. The preface is concise, and the explanation in the chapters are straightforward enough. The author uses clear and simple English sentences instead of long complex ones. The organization of topics into chapters is quite appropriate.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Missing topics&lt;/strong&gt;&lt;br /&gt;I didn't find any mention of Strawberry Perl, only ActivePerl. The examples are all using SQLite and no other databases. I wish AJAX and integration with one/more JavaScript frameworks like jQuery (and thus, CSS) is discussed more, as this is now very popular and common. But that will add significantly to the length of the book.&lt;br /&gt;&lt;br /&gt;The first chapter on MVC also deserves some more extension.&lt;br /&gt;&lt;br /&gt;There is no comparison whatsoever with any other Perl web frameworks or other non-Perl frameworks like Django and Rails.&lt;br /&gt;&lt;br /&gt;I would've liked a chapter/subchapter on performance tuning and benchmarking (there is a 'Performance considerations' section in the Deployment chapter but that only covers the choice of webserver).&lt;br /&gt;&lt;br /&gt;Plack/PSGI is not yet covered on this edition, which is a pity.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The rather bad&lt;/strong&gt;&lt;br /&gt;The author gives CPAN links to pages of specific release versions, e.g. http://search.cpan.org/~ash/DBIx-Class-0.08013/lib/DBIx/Class/Schema/&lt;br /&gt;Versioned.pm which tends to break as new releases added and old releases removed from CPAN. &lt;strike&gt;But this is understandable because currently CPAN only provides http://search.cpan.org/dist/DBIx-Class/ and not something like http://search.cpan.org/dist/DBIx-Class/current/pod/Foo/Bar.pm.&lt;/strike&gt; search.cpan.org does provide a more stable URL: http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class/Manual/FAQ.pod&lt;br /&gt;&lt;br /&gt;The author also uses 2-space indent instead of 4, which I suspect is because he also uses Ruby/Rails.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The really ugly&lt;/strong&gt;&lt;br /&gt;The general editing of the book, and especially the code/output formatting, is the deal breaker here. I have not found another book that fares equally poorly in this regard.&lt;br /&gt;&lt;br /&gt;The first paragraph of the preface already contains two very off-putting typos: "Frednic Brooks" (of Mythical Man-Month fame) and "MOOSE". Boxes drawn with ASCII characters which should align become wrapped and misaligned. When the long lines of code/output are wrapped, it is not clear which lines are wrapped and which are just new lines (some visual indicator should've added like a + or \ sign, line number, or striped background/lines).&lt;br /&gt;&lt;br /&gt;There is a plain error in YAML syntax in p67, plain wrong MySQL configuration in p69.&lt;br /&gt;&lt;br /&gt;Code formatting/editing is atrocious, with __PACKAGE__ sometimes becomes PACKAGE, or __Package__. Blank lines (which are significant for POD) are removed. And there is some garbage/random characters added in a few places. Totally unacceptable.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Verdict&lt;/strong&gt;&lt;br /&gt;Unfortunately I cannot recommend this book due to the utterly poor code formatting. I have no major problem with the content though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5253377113659587090?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5253377113659587090/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/09/book-review-catalyst-58-perl-mvc.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5253377113659587090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5253377113659587090'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/09/book-review-catalyst-58-perl-mvc.html' title='Book review: Catalyst 5.8 The Perl MVC Framework'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3300923103061644400</id><published>2010-09-01T19:18:00.000-07:00</published><updated>2010-09-01T21:03:31.753-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Coding Style As A Failure Of Language Design?</title><content type='html'>Read &lt;a href="http://weblogs.mozillazine.org/roc/archives/2010/07/coding_style_as.html"&gt;this older blog post&lt;/a&gt; the other day. Hilarious at best, creepy at worst.&lt;br /&gt;&lt;br /&gt;Arbitrary limitations should not be added to a general-purpose programming language unless for a really good reason. Do you really want to code in a language that forces you to indent with 2 spaces, never cross 80-column line, or require/forbid whitespace here and there? And besides, is there any language (no matter how strict the syntax of which is) which do not have some sort of coding style?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3300923103061644400?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3300923103061644400/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/09/coding-style-as-failure-of-language.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3300923103061644400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3300923103061644400'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/09/coding-style-as-failure-of-language.html' title='Coding Style As A Failure Of Language Design?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7554476321451564291</id><published>2010-08-27T18:23:00.001-07:00</published><updated>2010-08-27T18:23:31.793-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Wishlist for a service framework and/or manager</title><content type='html'>I maintain code for a few daemons/services written in Perl (most of them serve requests by forking/preforking). Reading &lt;a href="http://blogs.perl.org/users/vyacheslav_matjukhin/2010/08/ubic---how-to-implement-your-first-service.html"&gt;post on Ubic&lt;/a&gt;, I started to feel that I am reinventing a lot of wheels. Currently I am doing these by writing my own code, as much as which I hope can be offloaded to CPAN in the future:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Autorestart when process size is becoming too big&lt;/b&gt;. We need to do this gracefully, meaning wait until there is no more clients being serviced, unless process size really gets too big in which case we need to restart immediately. Checking period can be configured.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Autorestart if script or modules change on disk&lt;/b&gt;. Also needs to be done gracefully. This is usually being recommended to be used only on development environment, but I use this too in production, for ease of deployment. But we need to check first (e.g. via "perl -c" or "eval + require" whether the new code from disk is okay.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Avoid duplicate instance&lt;/b&gt; (currently always using &lt;a href="http://search.cpan.org/dist/Proc-PID-File/"&gt;Proc::PID::File&lt;/a&gt;, but I'm open to better mechanism).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Limit clients concurrency&lt;/b&gt;. Sometimes this is simple (a single limit for all clients) and sometimes not so much (different limits for different IP/IP blocks/authenticated users/groups/etc).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Reap dead child processes and maintain a count of child processes&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Handle timed out clients&lt;/b&gt;. This is rather cumbersome with blocking I/O.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Write init script&lt;/b&gt;. This is the part I dislike the most, since there are tons of different OS flavors out there, and with more recent efforts like upstart, launchd, systemd, sooner or later I will certainly have to write different init scripts. I wish there is something equivalent to PSGI/Plack for general services, which can plug my code to whatever service manager might be out there.&lt;br /&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7554476321451564291?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7554476321451564291/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/08/wishlist-for-service-framework-andor.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7554476321451564291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7554476321451564291'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/08/wishlist-for-service-framework-andor.html' title='Wishlist for a service framework and/or manager'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-9117227377526960330</id><published>2010-08-25T11:58:00.001-07:00</published><updated>2010-08-25T11:58:49.616-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Random Perl wishlists #1: uncapture modifier, require+import, backtick function</title><content type='html'>&lt;strong&gt;Uncapture modifier&lt;/strong&gt;.  The new /r regexp substitution modifier in Perl 5.13.2 indicates that there might be hope for even more modifiers in the future. A possible modifier might be one that ignores all capture groups, which can solve &lt;a href="http://stackoverflow.com/questions/3552850/how-do-i-make-an-arbitrary-perl-regex-wholly-non-capturing-answer-you-cant"&gt;this guy's problem&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;require that can also import&lt;/strong&gt;. I wonder why "require" doesn't also support importing like "use" does: use MODULE_NAME LIST... since it already support "require MODULE_NAME". This way, whenever I want to defer loading some modules, I can just replace "use" with "require" and put the statement under some "if" statement.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;the backtick function.&lt;/strong&gt;. Do you find yourself often having to do use a temporary variable like this, $cmd = "some longish and ".quote("complexly formed")."command"; before doing backtick `$cmd`? This is because unlike in PHP, we have system() but no backtick(). Most probably remnants from shell. There is Capture::Tiny for more general solution but of course it's a bit more cumbersome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-9117227377526960330?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/9117227377526960330/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/08/random-perl-wishlists-1-uncapture.html#comment-form' title='5 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/9117227377526960330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/9117227377526960330'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/08/random-perl-wishlists-1-uncapture.html' title='Random Perl wishlists #1: uncapture modifier, require+import, backtick function'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2467132206923745640</id><published>2010-07-28T17:19:00.000-07:00</published><updated>2010-07-28T17:22:58.362-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Startup overhead still matters</title><content type='html'>We all love Moose, and the subject of this &lt;a href="http://stackoverflow.com/questions/3162390/is-moose-really-this-slow"&gt;question&lt;/a&gt; could have been rephrased better, but why do I get the feeling that not many people write pure CGI or command-line scripts in Perl (that got executed many times) anymore? After all, didn't Perl begin as a tool for sysadmin and only in the mid 1990's got picked up as the darling of CGI/web programming?&lt;br /&gt;&lt;br /&gt;There are still many cases where/reasons why Perl scripts need to be run many times (instead of persistently long running).&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's much more stable (I've often need to kill or ulimit or periodically restart a Perl process because after days it grows to 500+ MB). &lt;br /&gt;&lt;br /&gt;&lt;li&gt;Sometimes CGI is all you get (especially in shared hosting environment, which is related to point 1).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Sometimes you need to run the scripts for many users, and it's not feasible (e.g. memory-wise) to let them all run persistently.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Many old scripts are designed that way.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Some environments require them that way (e.g. scripts run in .qmail are run for every incoming mail, scripts run by tcpserver are started for every incoming connection, etc).&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;There used to be projects like PersistentPerl or SpeedyPerl to let us easily make a Perl script persistent by just changing the shebang line (e.g. from #!perl to #!pperl), but these projects are currently not actively developed, probably due to lack of demand (?), or becase this kind of deployment tends to cause subtle bugs (I did get bitten by this a couple of times in the past). You can't just convert a script that is designed/written to be a one-off run into a long-running one without expecting some bugs, anyway.&lt;br /&gt;&lt;br /&gt;And the Perl compiler (B::*, *.pmc) is also now deprecated, probably because it does not give that many startup cost saving after all (the fact that Perl has phasers like BEGIN/CHECK blocks means it has to execute code as it compiles them anyway).&lt;br /&gt;&lt;br /&gt;And thus we're stuck with having to accept the startup cost of parsing &amp; compiling for every script run. That's why startup cost matters. On our servers awstats runs many thousand of times everyday (2000-5000 sites x 10+ HTML pages), and since it's a giant script (10k-ish line) it has a startup overhead of almost 1s. I really would like to shave this startup overhead as it is a significant part of server load.&lt;br /&gt;&lt;br /&gt;Until today many of my scripts/programs are still deployed as one-off command line scripts. And that's why instead of Moose I use Mouse (or Any::Moose, to be exact) whenever I can. And so far I can.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2467132206923745640?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2467132206923745640/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/07/startup-overhead-still-matters.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2467132206923745640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2467132206923745640'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/07/startup-overhead-still-matters.html' title='Startup overhead still matters'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-8742979512123832912</id><published>2010-07-05T21:24:00.000-07:00</published><updated>2010-07-05T21:25:14.264-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Spot the error</title><content type='html'>&lt;code&gt;use Data::Rmap qw(:all);&lt;br /&gt;use JSON;&lt;br /&gt;use Data::Dump;&lt;br /&gt;use Clone;&lt;br /&gt;use boolean;&lt;br /&gt;&lt;br /&gt;my $arg = from_json(q{{"1":true,"2":false}});&lt;br /&gt;# convert JSON booleans to boolean's booleans&lt;br /&gt;rmap_all { bless $_,"boolean" if ref($_) =~ /^JSON::(XS|PP)::Boolean$/ }, $arg;&lt;br /&gt;dd $arg;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Hint: it's one character long.&lt;br /&gt;&lt;br /&gt;In fact, this piece of code is full of Perl's traps (from Perl's lack of booleans obviously, to less obviously having to clone and rmap not working), it disgusts me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-8742979512123832912?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/8742979512123832912/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/07/use-datarmap-qwall-use-json-use.html#comment-form' title='9 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8742979512123832912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8742979512123832912'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/07/use-datarmap-qwall-use-json-use.html' title='Spot the error'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3512176289832607838</id><published>2010-06-29T20:34:00.001-07:00</published><updated>2010-06-29T20:34:52.512-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Reduce in Perl</title><content type='html'>Perl has &lt;b&gt;grep/map/sort&lt;/b&gt; since probably forever (actually, sort() starts appearing since Perl 2.0). But even now, &lt;b&gt;reduce&lt;/b&gt; is still not a builtin in Perl 5 (though available via List::Util), so doing reduce is probably not something that comes as naturally to Perl programmers. Meanwhile Ruby, JavaScript, and even PHP have their reduce operation builtin.&lt;br /&gt;&lt;br /&gt;But then, reduce is "not really that useful" (you can just replace it with a simple for loop). So much that Python 3.0 now removes the function from the global namespace and reduces it (pun intended) to a mere member of functools. I guess reduce is really handy only if you are in a heavily functional language that lacks procedural basics.&lt;br /&gt;&lt;br /&gt;This can be thought of as a testament to the level of language design skill that Larry has.&lt;br /&gt;&lt;br /&gt;The rather funny thing is, in Perl 6, in addition to the reduce() List method there is also the reduce ([]) metaoperator as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3512176289832607838?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3512176289832607838/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/06/reduce-in-perl.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3512176289832607838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3512176289832607838'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/06/reduce-in-perl.html' title='Reduce in Perl'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6645955498260770656</id><published>2010-06-23T03:39:00.001-07:00</published><updated>2010-06-23T03:39:35.919-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl vs JavaScript</title><content type='html'>Here are some notes I made while hacking on &lt;a href="http://search.cpan.org/dist/Language-Expr"&gt;Language::Expr::Compiler::JS&lt;/a&gt;. Of course, there are a million differences between the two, but these focus mostly on operators and types. Hope it can be useful.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Double vs single quotes&lt;/b&gt;. There are practically no functional differences between double-quoted string and single-quoted one in JavaScript. In Perl, single quotes do not interpret escape sequences other than \\ and \', but in JavaScript both single- and double-quoted strings interpret the same set of escape sequences.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;String escape sequences&lt;/b&gt;. Perl does not support JavaScript's \v (vertical tab), while JavaScript does not support \N{NAME} (named Unicode character), \e and \c[ (escape/control), \a (alarm bell).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Two undefs&lt;/b&gt;. JavaScript has two special nothingness/undefinedness: null and undefined. Strangely, null == undefined and they are equal to themselves, but they are not equal to any other values (including 0, '', false). The difference between the two is just this: undefined is not a keyword but a global variable (you can assign to it, but of course you shouldn't). If you want less confusion, just use null.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Behaviour of "+"&lt;/b&gt;. Since JavaScript only has "+" (while Perl has "+" and "."), you should be aware that "+" in JavaScript coerces to strings when one of the operands is a string (e.g. 1 + "2" becomes "12"). In Perl, "+" coerces to numbers. So be careful when mixing numbers and strings.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;You need to explicitly "return" value from a function. But there's a cute shortcut for one statement functions introduced in JavaScript 1.8: 'function (x) x*3' which is equivalent to 'function (x) { return x*3 }' so in this case you don't need the "return".&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Boolean&lt;/b&gt;. JavaScript has real boolean. In Perl you can use 'boolean' from CPAN which gives you practically the same stuff.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;JavaScript lacks a lot of Perl convenience operators, including &amp;lt;=&amp;gt; cmp, low-precedenced and/or/not, //, =~, ~~, qq(), qx(), qw(), m//, s///, **, etc.&lt;br /&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;All in all, I think JavaScript is quite nice and simple language with familiar syntax (at least compared to PHP). It also has lexical variables, anonymous functions, OO, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6645955498260770656?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6645955498260770656/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/06/perl-vs-javascript.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6645955498260770656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6645955498260770656'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/06/perl-vs-javascript.html' title='Perl vs JavaScript'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4910299172052304529</id><published>2010-06-22T09:00:00.000-07:00</published><updated>2010-06-22T09:08:54.880-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>JSYNC is brilliant!</title><content type='html'>It's a brilliant idea: bank on JSON's popularity and more widespread implementations, add some of the important YAML features not present in JSON on top of it. The result is &lt;a href="http://www.jsync.org/"&gt;JSYNC&lt;/a&gt;, along with its &lt;a href="http://search.cpan.org/dist/JSYNC/"&gt;preliminary CPAN module&lt;/a&gt;. (I'd probably picked a different name and choose something like "\" for prefix instead of ".", but hey, it's not my project :-)&lt;br /&gt;&lt;br /&gt;A few months ago I was really desperate with the YAML situation in Perl. We have the largest number of YAML implementations, but none of them are good enough compared to Ruby's libsyck. I even contemplated converting all my YAML documents to JSON, but of course that plan was cancelled because JSON doesn't even support references nor objects.&lt;br /&gt;&lt;br /&gt;Here's to hoping JSYNC will rocket to popularity soon enough. Ingy++.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4910299172052304529?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4910299172052304529/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/06/jsync-is-brilliant.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4910299172052304529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4910299172052304529'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/06/jsync-is-brilliant.html' title='JSYNC is brilliant!'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7611078558156520844</id><published>2010-06-09T05:10:00.000-07:00</published><updated>2010-06-09T05:31:53.293-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Custom dumping *in* Data::Dump</title><content type='html'>After &lt;a href=http://blogs.perl.org/users/steven_haryanto/2010/05/class-custom-dumping-for-datadump.html&gt;blogging&lt;/a&gt; about my small patch to Data::Dump, I contacted Gisle Aas. He is quite responsive and finally comes up with a new release (1.16) of Data::Dump containing the cool new filter feature. My previous example after converted to use the new feature becomes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ perl -MData::Dump=dumpf -MDateTime -e'dumpf(DateTime-&gt;now, sub { my ($ctx, $oref) = @_; return unless $ctx-&gt;class eq "DateTime"; {dump=&gt;qq([$oref])} })'&lt;br /&gt;[2010-06-09T12:22:58]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This filter mechanism is quite generic and allows you to do some other tricks like switching classes, adding comments, and ignore/hide hash keys. The interface is also pleasant to work with, although starting with this release the "no OO interface" motto should perhaps be changed to "just a little bit of OO interface" :-)&lt;br /&gt;&lt;br /&gt;Aren't we glad that stable and established modules like this are still actively maintained and getting new features.&lt;br /&gt;&lt;br /&gt;Thanks, Gisle!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7611078558156520844?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7611078558156520844/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/06/custom-dumping-in-datadump.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7611078558156520844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7611078558156520844'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/06/custom-dumping-in-datadump.html' title='Custom dumping *in* Data::Dump'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4809542456454751662</id><published>2010-06-02T09:12:00.000-07:00</published><updated>2010-06-02T09:21:12.461-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Menunggu statistik-statistik menarik dari sensus 2010</title><content type='html'>Koran PR beberapa minggu lalu menulis, Sensus Penduduk 2010 selain bertujuan mencacah jiwa, juga ingin "mencari fakta-fakta unik." Salah satu (dan satu-satunya) contoh: mencari orang tertua. Dan benar memang, selama beberapa minggu ini sudah ada beberapa artikel yang meliput tentang nenek di kampung anu yang berumur 115th, lalu rekornya dipecahkan oleh yang berumur 120th, lalu 125th, dst. Terakhir kalau tidak salah ada yang lebih dari 140th (walaupun semua klaim usia ini berdasarkan ucapan semata, bahkan tidak ada akte lahir atau bukti tertulis lainnya).&lt;br /&gt;&lt;br /&gt;Tentu saja, selain hanya mencari orang tertua, masih ada banyak sekali hal menarik yang bisa diekstrak dari data sensus ini. Misalnya, saya harapkan, BPS dapat menerbitkan adalah daftar nama depan dan nama belakang yang paling lazim, seperti &lt;a href="http://www.census.gov/genealogy/names/"&gt;yang dilakukan&lt;/a&gt; oleh badan sensus Amrik.&lt;br /&gt;&lt;br /&gt;Saat menyusun versi awal modul Perl &lt;a href="http://search.cpan.org/dist/Locale-ID-GuessGender-FromFirstName"&gt;Locale::ID::GuessGender::FromFirstName&lt;/a&gt;, saya kesulitan mencari basis data nama yang bisa dipakai, karenanya saya mengambil 1000 nama depan terlazim dari database pelanggan kantor. Tentu saja, andaikan ada data yang lebih representatif, seperti dari sensus penduduk, tentu jauh lebih baik.&lt;br /&gt;&lt;br /&gt;Seandainya diberi kesempatan, saya bersedia mengolah data mentahnya ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4809542456454751662?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4809542456454751662/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/06/menunggu-statistik-statistik-menarik.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4809542456454751662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4809542456454751662'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/06/menunggu-statistik-statistik-menarik.html' title='Menunggu statistik-statistik menarik dari sensus 2010'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2409300359104677665</id><published>2010-05-27T06:28:00.000-07:00</published><updated>2010-05-27T06:44:33.403-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Optimizing for $money?</title><content type='html'>While some sites optimize for speed and bandwidth usage, others do the opposite. About a decade ago when Internet connection at the office (then at pathetic speed of 128-256kbps) was experiencing serious slowdown, I noticed that images and even flag icons from the Summer Olympic website are deliberately made totally uncacheable, by setting Expires header value to a past date. Apparently IBM is still doing the same trick for the Grand Slams sites.&lt;br /&gt;&lt;br /&gt;$ cctrl() { perl -MLWP::UserAgent -E'$ua=LWP::UserAgent-&gt;new; $res=$ua-&gt;get($ARGV[0]); say $res-&gt;header("cache-control")' $1; }&lt;br /&gt;&lt;br /&gt;RSS icon, only cacheable for several hours:&lt;br /&gt;&lt;br /&gt;$ cctrl http://www.rolandgarros.com/images/nav/rgr_nv_00000g3.gif&lt;br /&gt;max-age=15000&lt;br /&gt;&lt;br /&gt;In fact all content photos are also cacheable for several hours only, despite already having unique URLs.&lt;br /&gt;&lt;br /&gt;Yellow button, which surely won't change a lot (and has a fairly unique URL anyway), cacheable only to a little over 11 minutes!&lt;br /&gt;&lt;br /&gt;$ cctrl http://www.rolandgarros.com/images/misc/rgr_ms_00000g2.gif&lt;br /&gt;max-age=700&lt;br /&gt;&lt;br /&gt;Compare to:&lt;br /&gt;&lt;br /&gt;$ cctrl http://www.facebook.com/images/app_icons/newsfeed.gif&lt;br /&gt;max-age=2592000&lt;br /&gt;&lt;br /&gt;or even:&lt;br /&gt;&lt;br /&gt;$ cctrl http://www.ibm.com/i/v16/t/ibm-logo.gif&lt;br /&gt;max-age=2592000&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2409300359104677665?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2409300359104677665/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/optimizing-for-money.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2409300359104677665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2409300359104677665'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/optimizing-for-money.html' title='Optimizing for $money?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6077048807895328972</id><published>2010-05-21T01:59:00.000-07:00</published><updated>2010-05-21T05:32:03.831-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Custom class dumping for Data::Dump</title><content type='html'>I'm using DateTime objects a lot these days: anytime I get some date/time data from outside of Perl, the first thing I do is convert them to DateTime object, to avoid calculation/formatting hassle ahead.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;However, the dumps are not pretty.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;% perl -MDateTime -MData::Dump -e'dd [DateTime-&gt;now]'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[                                                                                                                                     &lt;br /&gt;&lt;br /&gt;  bless({                                                                                                                             &lt;br /&gt;&lt;br /&gt;    formatter       =&gt; undef,                                                                                                         &lt;br /&gt;&lt;br /&gt;    local_c         =&gt; {&lt;br /&gt;&lt;br /&gt;                         day =&gt; 21,&lt;br /&gt;&lt;br /&gt;                         day_of_quarter =&gt; 51,&lt;br /&gt;&lt;br /&gt;                         day_of_week =&gt; 5,&lt;br /&gt;&lt;br /&gt;                         day_of_year =&gt; 141,&lt;br /&gt;&lt;br /&gt;                         hour =&gt; 8,&lt;br /&gt;&lt;br /&gt;                         minute =&gt; 55,&lt;br /&gt;&lt;br /&gt;                         month =&gt; 5,&lt;br /&gt;&lt;br /&gt;                         quarter =&gt; 2,&lt;br /&gt;&lt;br /&gt;                         second =&gt; 36,&lt;br /&gt;&lt;br /&gt;                         year =&gt; 2010,&lt;br /&gt;&lt;br /&gt;                       },&lt;br /&gt;&lt;br /&gt;    local_rd_days   =&gt; 733913,&lt;br /&gt;&lt;br /&gt;    local_rd_secs   =&gt; 32136,&lt;br /&gt;&lt;br /&gt;    locale          =&gt; bless({&lt;br /&gt;&lt;br /&gt;                         "default_date_format_length" =&gt; "medium",&lt;br /&gt;&lt;br /&gt;                         "default_time_format_length" =&gt; "medium",&lt;br /&gt;&lt;br /&gt;                         en_complete_name =&gt; "English United States",&lt;br /&gt;&lt;br /&gt;                         en_language =&gt; "English",&lt;br /&gt;&lt;br /&gt;                         en_territory =&gt; "United States",&lt;br /&gt;&lt;br /&gt;                         id =&gt; "en_US",&lt;br /&gt;&lt;br /&gt;                         native_complete_name =&gt; "English United States",&lt;br /&gt;&lt;br /&gt;                         native_language =&gt; "English",&lt;br /&gt;&lt;br /&gt;                         native_territory =&gt; "United States",&lt;br /&gt;&lt;br /&gt;                       }, "DateTime::Locale::en_US"),&lt;br /&gt;&lt;br /&gt;    offset_modifier =&gt; 0,&lt;br /&gt;&lt;br /&gt;    rd_nanosecs     =&gt; 0,&lt;br /&gt;&lt;br /&gt;    tz              =&gt; bless({ name =&gt; "UTC" }, "DateTime::TimeZone::UTC"),&lt;br /&gt;&lt;br /&gt;    utc_rd_days     =&gt; 733913,&lt;br /&gt;&lt;br /&gt;    utc_rd_secs     =&gt; 32136,&lt;br /&gt;&lt;br /&gt;    utc_year        =&gt; 2011,&lt;br /&gt;&lt;br /&gt;  }, "DateTime"),&lt;br /&gt;&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It gets worse when you have some records each with DateTime object in it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That's why I added a couple of mechanisms to allow us to custom a class' dump.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;$ perl -Ilib -MDateTime -MData::Dump -e'$Data::Dump::CUSTOM_CLASS_DUMPERS{"DateTime"} = sub { "$_[0]" }; dd [DateTime-&gt;now]'&lt;br /&gt;&lt;br /&gt;[2010-05-21T08:57:45]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;or:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;$ perl -Ilib -MDateTime -MData::Dump -e'package DateTime; sub dump { "$_[0]" }; package main; dd [DateTime-&gt;now]'&lt;br /&gt;&lt;br /&gt;[2010-05-21T08:58:09]&lt;br /&gt;&lt;br /&gt;I know some other dumper in CPAN probably has this ability, but I like Data::Dump's output.&lt;br /&gt;&lt;br /&gt;If you want to take a look at a couple of small patches to Data::Dump: http://github.com/sharyanto/data-dump&lt;br /&gt;&lt;br /&gt;I've also contacted Gisle Aas to ask what he thinks of it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6077048807895328972?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6077048807895328972/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/custom-class-dumping-for-datadump.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6077048807895328972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6077048807895328972'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/custom-class-dumping-for-datadump.html' title='Custom class dumping for Data::Dump'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-930782859518780418</id><published>2010-05-13T03:49:00.001-07:00</published><updated>2010-05-13T16:26:05.362-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>On RJBS's automatic version numbering scheme</title><content type='html'>Everytime I browse through &lt;a href="http://search.cpan.org/recent"&gt;CPAN recent uploads&lt;/a&gt;, and see versions of modules with RJBS's automatic numbering scheme, like 2.100920 or 1.091200 I tend to read it as 2.(noise) and 1.(more noise).&lt;br /&gt;&lt;br /&gt;The problem is that it &lt;strong&gt;doesn't look like a date at all&lt;/strong&gt; (is there any country or region using day of year in their date??). I've never been bothered enough with this though, as I don't use this scheme myself, but have always had a suspicion that this obfuscation is deliberate for some deep reason.&lt;br /&gt;&lt;br /&gt;Turns out that it's &lt;a href="http://rjbs.manxome.org/rubric/entry/1749"&gt;just a matter of space saving and floating point issue&lt;/a&gt;. I'm not convinced though, is x.100513n (YYMMDD, 6 digits + 1 digit serial = 7 digits) really that much longer than x.10133n (YYDDD, 5 digits + 1 digit serial = 6 digits)? Is there a modern platform where Perl's numbers are represented with 32-bit single precision floating point (only 7 decimal digit precision) where it will present a problem when n becomes 2 digit using YYMMDD scheme?&lt;br /&gt;&lt;br /&gt;Based on past experiences, since it is unlikely that I will do more than 20 releases in one month (usually even only once or twice a month or less frequently), if I were to adopt a date-based automatic versioning policy, perhaps I'll pick x.YYMMn where n is omitted for the first release, and then 1..9, and then 91..99 (and then 991..999 and so on). This way, most releases have the shortest number of digits. I don't "incur cost" for the first few releases (which anyway will be all there is, most of the time).&lt;br /&gt;&lt;br /&gt;&lt;code&gt;1.1005&lt;br /&gt;1.10051&lt;br /&gt;1.10052&lt;br /&gt;...&lt;br /&gt;1.10059&lt;br /&gt;1.100591&lt;br /&gt;1.100592&lt;br /&gt;...&lt;br /&gt;1.100599&lt;br /&gt;1.1005991&lt;br /&gt;...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In fact, I bet most modules have only a few releases &lt;strong&gt;per year&lt;/strong&gt;. So how about this scheme, x.YYn:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;1.10 - first release of the year&lt;br /&gt;1.101 - second&lt;br /&gt;1.102 - third&lt;br /&gt;...&lt;br /&gt;1.109 - tenth&lt;br /&gt;1.1091 - eleventh&lt;br /&gt;1.1092 - 12th&lt;br /&gt;...&lt;br /&gt;1.1099 - 19th&lt;br /&gt;1.10991 - 20th&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Or how about x.Dn (releases per decade) or even x.Cn (releases per century)? :-)&lt;br /&gt;&lt;br /&gt;My brain prefers that I don't use long version numbers. Except when the version number is long because of some date (e.g. to indicate freshness of release). But why torture ourselves with a date that we need several seconds to parse in our head?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So I'll stick with 0.01, 0.02, 0.03, ... for now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-930782859518780418?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/930782859518780418/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/on-rjbss-automatic-version-numbering.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/930782859518780418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/930782859518780418'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/on-rjbss-automatic-version-numbering.html' title='On RJBS&apos;s automatic version numbering scheme'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3539269928856200336</id><published>2010-05-13T02:57:00.000-07:00</published><updated>2010-05-13T03:04:16.583-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Menebak gender orang Indonesia berdasarkan nama depan</title><content type='html'>Sesuai &lt;a href="http://steven.blogs.masterweb.net/2009/12/10/arti-sebuah-nama/"&gt;janji di posting blog beberapa bulan lalu&lt;/a&gt;, hari ini saya merilis &lt;a href="http://search.cpan.org/dist/Locale-ID-GuessGender-FromFirstName"&gt;Locale-ID-GuessGender-FromFirstName&lt;/a&gt;. Nama modulnya jadi panjang ya? :-p&lt;br /&gt;&lt;br /&gt;Sebab ke depannya, seiring dengan modul pelengkap yang direncanakan, Locale-ID-ParseName-Person, kita juga bisa menebak gender seseorang dari atribut nama lainnya, misalnya dari sapaan (Bapak/Ibu/Bung/Mbak), dari gelar keagamaan (H/Hj), dari pola nama kedaerahan (mis: I Ketut/Ni Ayu), dll.&lt;br /&gt;&lt;br /&gt;Rilis pertama ini akurasi dan kelengkapannya belum bisa diandalkan, tapi sudah bisa dicoba-coba. Saya sudah menambahkan sekitar 1000 nama-nama umum dari database klien kantor (soalnya kesulitan mencari database yang lebih bagus, tidak seperti di Amrik yang bisa mengambil data dari biro sensus di sana). Algoritma heuristik (sangat) sederhana juga sudah ditambahkan, beserta dengan algoritma untuk mencari dari Google.&lt;br /&gt;&lt;br /&gt;Ada yang punya waktu luang membuat skrip CGI sederhana, atau aplikasi Facebook, untuk interface web modul ini? Sekalian mengumpulkan lebih banyak data dan koreksi. Saya sih pengen aja, cuma males :p&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3539269928856200336?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3539269928856200336/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/menebak-gender-orang-indonesia.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3539269928856200336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3539269928856200336'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/menebak-gender-orang-indonesia.html' title='Menebak gender orang Indonesia berdasarkan nama depan'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5922918252931562994</id><published>2010-05-12T11:18:00.000-07:00</published><updated>2010-05-12T11:35:13.691-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>perlmv: Renaming files with Perl code</title><content type='html'>&lt;a href=http://search.cpan.org/dist/App-perlmv&gt;perlmv&lt;/a&gt; is a script which I have personally been using all the time for years, but has only been uploaded to CPAN today. The concept is very simple, to rename files by manipulating $_ in specified Perl code. For example, to rename all .avi files to lowercase, &lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perlmv -de '$_=lc' *.avi&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;-d&lt;/b&gt; option is for dry-run, so that we can test our code before actually renaming the files. If you are sure that the code is correct, remove the -d (or replace it with &lt;b&gt;-v&lt;/b&gt;, for verbose).&lt;br /&gt;&lt;br /&gt;perlmv can also save your code into scriptlets (files in ~/.perlmv/scriptlets/), so if you do:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perlmv -e 's/\.(jpe?g|jpe)$/.jpg/i' -W normalize-jpeg&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can later do this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perlmv -v normalize-jpeg *.JPG *.jpeg&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In fact, perlmv comes with several scriptlets you can use (more useful scriptlets will be added in the future):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perlmv -L&lt;br /&gt;lc&lt;br /&gt;pinyin&lt;br /&gt;remove-common-prefix&lt;br /&gt;remove-common-suffix&lt;br /&gt;uc&lt;br /&gt;with-numbers&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Let me know if you have tried out the script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5922918252931562994?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5922918252931562994/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/perlmv-renaming-files-with-perl-code.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5922918252931562994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5922918252931562994'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/perlmv-renaming-files-with-perl-code.html' title='perlmv: Renaming files with Perl code'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-8435404160737522649</id><published>2010-05-05T13:00:00.000-07:00</published><updated>2010-05-05T13:14:11.961-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>So is wantarray() bad or not?</title><content type='html'>The style of returning different things in list vs scalar context has been debated for a long time (for a particular example, &lt;a href="http://perlmonks.org/index.pl?node_id=729965"&gt;this thread&lt;/a&gt; in &lt;a href="http://perlmonks.org"&gt;Perlmonks&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;A few months ago I made a decision that all API functions in one of my projects should return this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;return wantarray ? ($status, $errmsg, $result) : $result;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That is, we can skip error checking when we don't want to do it.&lt;br /&gt;&lt;br /&gt;Now, in the spirit of Fatal and autodie, I am changing the above to:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;return wantarray ? ($status, $errmsg, $result) : &lt;br /&gt;    do { die "$status - $errmsg" unless $status == SUCCESS; $result };&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But somehow I can still see myself and others tripping over this in the future, as I have, several times so far. It's bad enough that for each API function one already has to remember the arguments and their types, and one kind of return and its type.&lt;br /&gt;&lt;br /&gt;Maybe I should just bite the bullet and admit the misadventure into wantarray(), and that context-sensitive return should be left to @foo, localtime(), and a few other classical Perl 5 builtins that have been ingrained in every Perl programmer's mind.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-8435404160737522649?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/8435404160737522649/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/05/so-is-wantarray-bad-or-not.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8435404160737522649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8435404160737522649'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/05/so-is-wantarray-bad-or-not.html' title='So is wantarray() bad or not?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6103435122456443739</id><published>2010-04-28T10:43:00.000-07:00</published><updated>2010-04-28T10:52:23.052-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Module Wishlist: magical loading of module</title><content type='html'>This Module Wishlist series is meant to surprise me with the power of CPAN. I wish about or dream up some module without first checking on CPAN, and hopefully can be delighted when what I want is already there.&lt;br /&gt;&lt;br /&gt;Don't you hate it when you have to do:&lt;br /&gt;&lt;br /&gt; $ perl -MSome::Really::Long::Module -e'print Some::Really::Long::Module-&gt;foo'&lt;br /&gt; &lt;br /&gt;The goal is to be able to say something very close to:&lt;br /&gt;&lt;br /&gt; $ perl -e'print Some::Really::Long::Module-&gt;foo'&lt;br /&gt;&lt;br /&gt;and my module is loaded automaticaly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6103435122456443739?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6103435122456443739/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/module-wishlist-magical-loading.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6103435122456443739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6103435122456443739'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/module-wishlist-magical-loading.html' title='Module Wishlist: magical loading of module'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-774609042074386310</id><published>2010-04-28T10:21:00.000-07:00</published><updated>2010-04-28T10:39:59.688-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>To die or to croak, that is the question</title><content type='html'>Lately I've been tempted to use croak() instead of die(). Somehow it seems more considerate to users. But finally in the end I'm sticking with die(). In fact, I think the Carp module should be, well, croaked.&lt;br /&gt;&lt;br /&gt;The reasons:&lt;br /&gt;&lt;br /&gt;1. Even though Carp has been included in Perl 5 since forever (Module::CoreList tells me: "5"), carp(), croak(), cluck(), and confess() are still not builtins, which means I still need an extra "use Carp".&lt;br /&gt;&lt;br /&gt;2. Too many keywords! Most other languages only have "throw" or "raise".&lt;br /&gt;&lt;br /&gt;3. Names are too weird! I understand the difficulty of coming up with a concise set of names that are similar but slightly different. But requiring these weird names might also indicate that there is something fishy about the concept itself.&lt;br /&gt;&lt;br /&gt;4. The choice of showing a stack trace or not should not be in the individual functions. That burdens the programmer with too much thinking.&lt;br /&gt;&lt;br /&gt;5. Even with Carp qw(verbose), what's to be done with codes that still die() and warn()? (But luckily there's Carp::Always.)&lt;br /&gt;&lt;br /&gt;6. Showing stack trace should not be this difficult. I still think there should be a command-line switch for Carp::Always (or alias it to 'oan' :-)&lt;br /&gt;&lt;br /&gt;7. Programmers (module writers) make mistake. They should not skip a call frame.&lt;br /&gt;&lt;br /&gt;In short, I think Carp makes things a little bit too complicated. But what's Perl without complication? :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-774609042074386310?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/774609042074386310/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/to-die-or-to-croak-that-is-question.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/774609042074386310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/774609042074386310'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/to-die-or-to-croak-that-is-question.html' title='To die or to croak, that is the question'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5475995383280863685</id><published>2010-04-28T09:26:00.000-07:00</published><updated>2010-04-28T10:08:32.809-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>You know you're a Perl programmer when...</title><content type='html'>You know you're a Perl programmer (or a CPAN author) when...&lt;br /&gt;&lt;br /&gt;When you're thinking of packaging every piece of code as a CPAN module.&lt;br /&gt;&lt;br /&gt;A couple of days ago I need a subroutine that takes a nested data structure (e.g. {vol1 =&gt; {a=&gt;{b=&gt;{c=&gt;10}}}, vol2 =&gt; {a2=&gt;{b2=&gt;{c2=&gt;20}}}}), a Unix-like path string (e.g. "vol1:/a/b/c") and return the branch/leaf node of the data structure according to the specified path (in this example, 10).&lt;br /&gt;&lt;br /&gt;After browsing CPAN and a few minutes of reading the POD of some modules and not finding exactly what I wanted [*], that subroutine idea quickly transformed into an idea of a full-fledged CPAN module. The next day I uploaded &lt;a href="http://search.cpan.org/dist/Data-Filesystem/"&gt;Data::Filesystem&lt;/a&gt; to CPAN, which is actually yet another Data::Walker- / Data::Path- / Data::DPath-like module.&lt;br /&gt;&lt;br /&gt;Turns out that I really don't need that module (yet, maybe someday). What I needed is just a simple Perl subroutine, and nothing more, because I will need to create a Javascript and PHP equivalent for it. Porting a whole module is not something I even want to do.&lt;br /&gt;&lt;br /&gt;I wonder just how many CPAN authors that (do not) start their modules this way: overengineering of a small problem after not finding exactly what they want in CPAN. &lt;br /&gt;&lt;br /&gt;[*] Btw, not finding what you want in one of the millions of CPAN modules has got to be one of the saddest thing in the universe. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5475995383280863685?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5475995383280863685/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/you-know-youre-perl-programmer-when.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5475995383280863685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5475995383280863685'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/you-know-youre-perl-programmer-when.html' title='You know you&apos;re a Perl programmer when...'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3092019228065219011</id><published>2010-04-18T09:08:00.000-07:00</published><updated>2010-04-18T09:12:44.558-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='zak'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Yada Yada, Buat apa ?</title><content type='html'>Perl 5.12.0 baru saja keluar dan salah satu yang baru yaitu &lt;a href="http://search.cpan.org/~jesse/perl-5.12.0/pod/perlop.pod#Yada_Yada_Operator___"&gt;Yada Yada Operator&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Saya hanya bingung kapan atau situasi seperti apa yang membuat yada yada operator bisa (dan bagus) untuk digunakan ?,&lt;br /&gt;Selintas saya teringat seperti &lt;code&gt;pending&lt;/code&gt; nya &lt;i&gt;RSpec.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3092019228065219011?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3092019228065219011/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/yada-yada-buat-apa.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3092019228065219011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3092019228065219011'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/yada-yada-buat-apa.html' title='Yada Yada, Buat apa ?'/><author><name>zak</name><uri>http://www.blogger.com/profile/01139402800607788017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7782866120164654453</id><published>2010-04-15T19:28:00.000-07:00</published><updated>2010-04-15T19:42:02.614-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Tip sprintf()</title><content type='html'>Salah satu fitur sprintf() (dan printf()) yang agak jarang diketahui/dipakai orang adalah bahwa sprintf() mendukung spesifikasi posisi argumen di dalam string formatnya, menggunakan prefiks NOMOR + "$":&lt;br /&gt;&lt;br /&gt;% perl -E'say sprintf(q[%d %d %d], 1, 2, 3)' &lt;br /&gt;1 2 3&lt;br /&gt;&lt;br /&gt;% perl -E'say sprintf(q[%2$d %3$d %1$d], 1, 2, 3)'&lt;br /&gt;2 3 1&lt;br /&gt;&lt;br /&gt;Sayangnya, sprintf() tidak mendukung binding berdasarkan nama, seperti di Python:&lt;br /&gt;&lt;br /&gt;print 'This {food} is {adjective}.'.format(adjective='absolutely horrible', food='spam')&lt;br /&gt;This spam is absolutely horrible.&lt;br /&gt;&lt;br /&gt;Kadang-kadang binding berdasarkan nama lebih nyaman, karena jika terjadi penambahan/pengurangan argumen, kita tidak harus menggeser-geser posisi lagi. Beberapa aplikasi tertentu seperti translasi juga kadang bisa dibuat lebih enak interfacenya seandainya menggunakan binding berbasis nama.&lt;br /&gt;&lt;br /&gt;Jadi, bagaimana solusinya di Perl? Bisa dengan modul seperti &lt;a href="http://search.cpan.org/dist/String-Formatter/"&gt;String::Formatter&lt;/a&gt;, atau membuat sendiri :-) (seperti yang saya lakukan baru-baru ini di &lt;a href="http://search.cpan.org/dist/Data-Schema/"&gt;Data::Schema&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;# $extra = {mverb =&gt; "harus"}; # mverb juga bisa 'sebaiknya'&lt;br /&gt;# $args = [1, 10];&lt;br /&gt;print stringf("Data %(mverb)s di antara %(0)d sampai %(1)d", $args, $extra);&lt;br /&gt;Data harus lebih kecil di antara 1 sampai 10.&lt;br /&gt;&lt;br /&gt;Fungsi stringf() mencoba mencari nilai binding di argumen kedua dst. Argumen dapat berupa hashref maupun arrayref, jadi saya bisa menggunakan binding berdasarkan posisi maupun nama. Nyaman :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7782866120164654453?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7782866120164654453/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/tip-sprintf.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7782866120164654453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7782866120164654453'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/tip-sprintf.html' title='Tip sprintf()'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7720470233127373421</id><published>2010-04-14T11:26:00.000-07:00</published><updated>2010-04-14T11:42:32.403-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Data::Dumper (Unfortunately, Part 2)</title><content type='html'>One of the first things a Perl programmer will notice when learning about Data::Dumper is: how weird and "inside out" the OO interface is. This is, I think, another unfortunate accident in the Perl history, as Data::Dumper, being the first of such modules, gets into the core in early Perl 5 and remains popular up until this day. But the interface and default settings apparently annoy a lot of people so much that alternatives and wrappers like Data::Dump, Data::Dumper::Again, Data::Dumper::Concise, among others, sprung up to life.&lt;br /&gt;&lt;br /&gt;A loose analogy would be CVS which was popular for (too long) a time, and following it the explosion of alternative version control systems. Eventually after this phase a winner will emerge or dominate. In the version control system case it appears to be git. And in the Perl case I think it will be a builtin perl() method/function, like in Perl 6. Probably in 5.14? 5.16? 5.18? Don't you think it's about time Perl can "natively" dump its own structures in Perl, just like Python, Ruby, PHP, etc have been able to for a long time?&lt;br /&gt;&lt;br /&gt;(Btw, lest anyone thinks otherwise: I do love DD. It has lots of options and has served its purpose well over the years.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7720470233127373421?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7720470233127373421/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/datadumper-unfortunately-part-2.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7720470233127373421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7720470233127373421'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/datadumper-unfortunately-part-2.html' title='Data::Dumper (Unfortunately, Part 2)'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2098825367047197108</id><published>2010-04-14T10:52:00.000-07:00</published><updated>2010-04-14T11:26:15.415-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>List::Util, List::MoreUtils, Util::Any (Unfortunately, Part 1)</title><content type='html'>The dichotomy of List::Util and List::MoreUtils is one of the unfortunate annoyances in Perl. One is without s, one is with s. Which function belongs to which? And no, you can't simply say, "f*ck it, just import everything!" as List::Util doesn't provide the usual ":all" import tag (&lt;a href="https://rt.cpan.org/Ticket/Display.html?id=56591"&gt;RT&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Some thoughts (from someone who is largely ignorant on the history of both modules), all IMO:&lt;br /&gt;&lt;br /&gt;1. Since List::Util is basically a convenient library, convenience should've been its main design goal. It should've been inclusive enough. The decision to deny the inclusion of any(), all(), none() just because they are too "trivial" to implement in one line of Perl was a bit strange, since max(), min(), etc are also trivial to implement in Perl.&lt;br /&gt;&lt;br /&gt;2. List::MoreUtils should've included all the functionalities of List::Util, so one can use it *instead of* List::Util.&lt;br /&gt;&lt;br /&gt;But hey, what happened happened.&lt;br /&gt;&lt;br /&gt;Btw, we also have Perl 6's junction taking the "all", "any", "none" keyword.&lt;br /&gt;&lt;br /&gt;And we'll see whether solutions like Util::Any will catch on, as it's another syntax to learn, another module to download and install. As with many annoyances, they are actually not that big of a deal. One can just spend a few seconds looking up the documentation to find the functions he/she wants, and after about tens of uses should remember which ones are in which.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2098825367047197108?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2098825367047197108/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/listutil-listmoreutils-utilany.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2098825367047197108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2098825367047197108'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/listutil-listmoreutils-utilany.html' title='List::Util, List::MoreUtils, Util::Any (Unfortunately, Part 1)'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7644923651795267353</id><published>2010-04-14T09:27:00.000-07:00</published><updated>2010-04-14T09:50:08.247-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Just when I'm warming to 5.10, comes 5.12!</title><content type='html'>Perl is far from dead/dying nowadays, with 5.12 being released recently, and the yearly timed-based release plan and all. In fact, just after I start to be comfortable using some of the 5.10 niceties, here comes a whole new version with even more niceties waiting to be explored!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Features in 5.10 I'm using regularly.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Defined-or (if there's only one feature I can have in 5.10, I pick this one).&lt;br /&gt;&lt;br /&gt;State variables (love it!).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Features in 5.10 I'm starting to use.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;-E switch (but my reflex still says -e all the time).&lt;br /&gt;&lt;br /&gt;Recursive pattern in regex (e.g., via Regexp::Grammars).&lt;br /&gt;&lt;br /&gt;say() (maybe if I say it often enough I'll start to say say more).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Features in 5.10 I rarely/ever touch.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Smart match (I know it's a godsend, but strangely I never feel the need for it so far).&lt;br /&gt;&lt;br /&gt;given/when (I'm sticking with if/elsif/else, especially since given/when cannot be used as an expression yet).&lt;br /&gt;&lt;br /&gt;Named capture in regex (yeah, old habits die hard).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5.10 and 5.12.&lt;/b&gt; IMO, 5.10 contains more "significant" visible new features for end users (i.e. Perl programmers), especially in the area of new syntax addition. It's 5 years in the making and delivers many features borrowed from Perl 6. But that is not meant to belittle 5.12 which also packs some major goodies, especially &lt;b&gt;pluggable keywords&lt;/b&gt;. This one promises to usher us into a world of new syntaxes and mini languages, though it also confirms Perl as being a language that is "impossible to parse" and it surely will pose a challenge/headache for PPI and syntax highlight/Intellisense writers. I look forward to something like a better embedded SQL and templates (using pluggable keywords instead of treating everything as strings all the time).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7644923651795267353?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7644923651795267353/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/just-when-im-warming-to-510-comes-512.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7644923651795267353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7644923651795267353'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/just-when-im-warming-to-510-comes-512.html' title='Just when I&apos;m warming to 5.10, comes 5.12!'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4499298865933472640</id><published>2010-04-07T03:50:00.000-07:00</published><updated>2010-04-14T08:10:53.686-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Data::Dump::PHP</title><content type='html'>I actually don't believe there isn't something like this in CPAN yet. Well, actually there is &lt;a href="http://search.cpan.org/dist/PHP-Var/"&gt;PHP::Var&lt;/a&gt;, but it has bugs, doesn't handle scalars, and doesn't do recursive structure. But then I am equally surprised to be able to hack &lt;a href="http://search.cpan.org/dist/Data-Dump-PHP"&gt;Data::Dump::PHP&lt;/a&gt; in just a couple of hours, by blatanly copying from Gisle Aas' &lt;a href="http://search.cpan.org/dist/Data-Dump"&gt;Data::Dump&lt;/a&gt; and just modifying only what's necessary.&lt;br /&gt;&lt;br /&gt;And another note, PHP's var_export() currently can't dump recursive structures, which Data::Dump::PHP can.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4499298865933472640?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4499298865933472640/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/datadumpphp.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4499298865933472640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4499298865933472640'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/datadumpphp.html' title='Data::Dump::PHP'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5059622369207667359</id><published>2010-04-01T12:01:00.000-07:00</published><updated>2010-04-01T12:42:08.222-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Bahasa yang buruk vs programer yang buruk</title><content type='html'>Apakah kita seharusnya menangisi kenyataan bahwa Perl tidak lagi menjadi bahasa primadona untuk Web? Rasanya sulit bisa mengejar popularitas PHP, atau Ruby dan Python saat ini di domain pemrograman Web. Dulu pertengahan 1990-an Perl dipilih karena belum banyak bahasa lain yang tersedia default di server-server Unix. Alternatifnya saat itu hanyalah C, shell, atau Tcl. Kini persaingan amat ketat/banyak. Perl termasuk salah satu yang lebih sulit/lama dipelajari dan selain itu memiliki imej "tua" (padahal umurnya gak beda jauh dengan rekan2nya, hanya sekitar 1-2 tahun dengan Python dan hanya 5 tahunan lebih dengan Ruby; semua bahasa2x ini sudah hampir atau lebih tua dari 20 tahun).&lt;br /&gt;&lt;br /&gt;Di satu sisi kehilangan pamor/momentum/posisi jawara/apalah tentu gak mengenakkan. Tapi di sisi lain, ada manfaatnya. Para "programer" web yang cenderung lebih banyak menghasilkan kode-kode yang buruk jadi meninggalkan Perl. Saya ingat dulu saat Perl popular, betapa komunitas Perl dianggap elitist, eksklusivist, sombong, angkuh, tidak ramah terhadap pemula. Dan bahasa-bahasa lain mulai mendapat tempat di hati khalayak ramai karena menawarkan komunitas yang lebih ramah pemula. (Belakangan, komunitas Perl pun mulai melunak dan menginisiasi effort2x untuk lebih merangkul pemula, seperti membuat milis beginners@, dsb. Tapi mungkin sudah terlambat).&lt;br /&gt;&lt;br /&gt;Salah satu alasan mengapa komunitas Perl "benci" pemula adalah: karena begitu banyak niubi yang jadi programer karbitan/jadi2xan berbondong2x mempelajari Perl, kadang setengah2x (atau seperempat2x!), dan selalu mencampurkan konsep Perl dan CGI. Selalu menulis Perl dengan PERL. Selalu mendecode parameter CGI sendiri (karena mengikuti instruksi buku2x Perl tak bermutu), padahal di Perl 4 pun sudah ada cgi-lib.pl. Selalu menanyakan persoalan sepele yang sudah sejak lama ada di FAQ. Selalu mengkopi paste kode dan menulis skrip yang begitu hancur2xan jeleknya.&lt;br /&gt;&lt;br /&gt;Sekarang rupanya mayoritas dari mereka sudah berpindah ke PHP. Sebagai pengurus server hosting Linux, sudah sering saya harus mengecek aplikasi PHP milik klien hosting yang bermasalah. Dan tiap kali saya mengintip kode sumbernya, kadang saya tersenyum pahit, kadang mengelus dada, kadang geleng2x kepala. Program2x jelek dan berantakan ternyata tidak pernah punah. Dulu di Perl, sekarang di PHP. Kalau dulu Matt's Script Archive jadi biang hole, kini ada phpBB, WordPress, Joomla sebagai penerusnya.&lt;br /&gt;&lt;br /&gt;Apakah Rails atau Django akan kebal dari para programer buruk? Don't underestimate the power of stupid people :)&lt;br /&gt;&lt;br /&gt;Maaf, saya tidak bermaksud berarogan ria di sini. Ada berbagai macam alasan mengapa seseorang bisa disebut programer buruk, seringkali itu bukan karena dia bodoh. Deadline yang terlalu singkat menyebabkan harus kopi paste kode. Pengetahuan yang minim karena pengalaman kurang menyebabkan desain yang naif. Peran bahasa untuk melakukan "nudging" dan manajemen insentif untuk memperbaiki kebiasaan-kebiasaan yang salah memang berpengaruh, tapi selalu ada ruang untuk beginner's mistakes. Dan selalu harus ada refactoring. Programer yang buruk tidak pernah melakukan refactoring.&lt;br /&gt;&lt;br /&gt;Jadi, bersyukurlah karena nanti 10 tahun lagi para generasi programer baru tidak lagi banyak mengutuk Perl karena harus memaintain kode lama CGI yang sudah membusuk. Melainkan mengutuk PHP karena diwarisi segunung kode spageti busuk bercampur HTML. Atau mengutuk Ruby karena peninggalan kode-kode busuk Rails dengan desain objek yang terbalik-balik dan pattern-pattern salah kaprah.&lt;br /&gt;&lt;br /&gt;Programer yang buruk selalu ada sepanjang masa. Bahasa yang saat itu banyak dipakai yang akan jadi kambing hitamnya. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5059622369207667359?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5059622369207667359/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/04/bahasa-yang-buruk-vs-programer-yang.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5059622369207667359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5059622369207667359'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/04/bahasa-yang-buruk-vs-programer-yang.html' title='Bahasa yang buruk vs programer yang buruk'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4280422352902460939</id><published>2010-03-31T10:47:00.000-07:00</published><updated>2010-04-01T11:56:05.803-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Kompetisi, kompetisi</title><content type='html'>(Berhubung lagi gak mut dan ada kerjaan2x lain, kelewat seminggu deh posting Iron Man. &lt;strike&gt;Menurut aturan, seharusnya status ane jadi kertas lagi :-(&lt;/strike&gt; Ternyata tidak, karena ada &lt;a href="http://id-perl.blogspot.com/2010/03/autovivication.html"&gt;posting dari zak&lt;/a&gt;. Thanks zak :) )&lt;br /&gt;&lt;br /&gt;Tadi barusan baca &lt;a href="http://blogs.perl.org/users/sawyer_x/2010/03/stepping-up-to-the-plate.html"&gt;postingan Sawyer X&lt;/a&gt; tentang &lt;a href="http://use.perl.org/~Alias/journal/40270"&gt;postingan Adam Kennedy&lt;/a&gt; yang berencana mengadu &lt;a href="http://perldancer.org/"&gt;Dancer&lt;/a&gt; dan &lt;a href="http://mojolicious.org/"&gt;Mojolicious&lt;/a&gt;. Exciting banget!&lt;br /&gt;&lt;br /&gt;IMO, dari dulu seharusnya komunitas Perl menggelar inisiatif2x kompetisi seperti ini.&lt;br /&gt;&lt;br /&gt;Biasanya yang sering terjadi di CPAN adalah kelahiran modul demi modul baru yang merupakan eksperimen atau proyek pribadi milik orang2x berbeda. Kurang suka dengan sebuah modul? Buat saja tandingannya,  alternatifnya, versi Anda sendiri. Lihat ada berapa belas framework web di Perl sejak Catalyst, ada berapa puluh modul untuk validasi data (ane juga &lt;a href="http://search.cpan.org/dist/Data-Schema/"&gt;nyumbang satu&lt;/a&gt; nih hehe), dan mungkin seratusan modul konfigurasi.&lt;br /&gt;&lt;br /&gt;Tapi yang membuat pengguna bingung, bagaimana memilih modul terbaik? Terpopular? Tercepat? Dsb. Kurang ada perbandingan2x atau benchmark2x atau kontes. Komunitas Perl seolah gak suka dengan kompetisi. Bahkan counter download aja dari dulu gak jadi dibuat2x.&lt;br /&gt;&lt;br /&gt;Kita perlu ingat bahwa kompetisi mendorong inovasi. Kurang inovasi berarti mati.&lt;br /&gt;&lt;br /&gt;Ayo kita berkompetisi, ayo kita saling beradu secara positif.&lt;br /&gt;&lt;br /&gt;-- sh (Yang sedang menggodok versi Data::Schema berikutnya untuk menjadi DFV-killer :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4280422352902460939?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4280422352902460939/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/kompetisi-kompetisi.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4280422352902460939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4280422352902460939'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/kompetisi-kompetisi.html' title='Kompetisi, kompetisi'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5159637221605279369</id><published>2010-03-26T20:12:00.000-07:00</published><updated>2010-04-02T10:01:50.574-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='zak'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Autovivification</title><content type='html'>Berdasarkan pertanyaan dari beberapa orang yang agak kebingungan dengan istilah &lt;span style="font-style:italic;"&gt;&lt;strike&gt;autovivication&lt;/strike&gt;&lt;/span&gt;&lt;i&gt;autovivification&lt;/i&gt;, mungkin secara singkat saya akan langsung memberikan contoh tentang apa itu yang disebut dengan &lt;span style="font-style:italic;"&gt;&lt;strike&gt;autovivication&lt;/strike&gt;&lt;/span&gt;.&lt;i&gt;autovivification&lt;/i&gt;&lt;br /&gt;Ini dia &lt;span style="font-style:italic;"&gt;&lt;strike&gt;autovivication&lt;/strike&gt;&lt;/span&gt; &lt;i&gt;autovivification&lt;/i&gt;:&lt;br /&gt;&lt;pre&gt;my $hash;&lt;br /&gt;$hash-&gt;{aaa}{bbb}{ccc} = 'sebuah nilai';&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ketika dideklarasikan, &lt;code&gt;$hash&lt;/code&gt; tidak mempunyai key dan value, tetapi kemudian kita memberikan suatu value pada key yang 'undefined'.&lt;br /&gt;&lt;br /&gt;Ya sesingkat itulah definisi dari &lt;span style="font-style:italic;"&gt;&lt;strike&gt;autovivication&lt;/strike&gt;&lt;/span&gt;.&lt;i&gt;autovivification&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5159637221605279369?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5159637221605279369/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/autovivication.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5159637221605279369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5159637221605279369'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/autovivication.html' title='Autovivification'/><author><name>zak</name><uri>http://www.blogger.com/profile/01139402800607788017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7696566601557257270</id><published>2010-03-17T08:00:00.001-07:00</published><updated>2010-03-17T08:11:33.931-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Modules *AND* applications</title><content type='html'>"Why choose?" -- Fatima Dinssa&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://blogs.perl.org/users/sawyer_x/2010/03/modules-vs-applications.html"&gt;Modules vs Applications&lt;/a&gt;, Sawyer X noted that one of the "issues" (emphasis mine) of Perl people is the tendency to write modules instead of applications. That CPAN is great but due to the lack of end user programs there is no WOW factor. He suggested that we write programs/applications that everyone can use to attract more people to Perl.&lt;br /&gt;&lt;br /&gt;While I agree with the last suggestion, I don't agree with the preference to modularize everything as an issue. As someone who wrote a program years ago that is comprised of many separate scripts and duplicated code (even in different languages, just for the fun of it) and still have to maintain it today, I'd say that not putting as much code as possible into reusable modules is a mistake.&lt;br /&gt;&lt;br /&gt;I'd instead suggest that we still write modules (which is what made CPAN great anyway), but try to *also* accompany each distribution with a demo app (preferably in the App:: namespace).&lt;br /&gt;&lt;br /&gt;I myself will try to do that from now on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7696566601557257270?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7696566601557257270/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/modules-and-applications.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7696566601557257270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7696566601557257270'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/modules-and-applications.html' title='Modules *AND* applications'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3560276943518092598</id><published>2010-03-17T07:15:00.000-07:00</published><updated>2010-03-17T07:48:35.297-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Log::Any::App (2)</title><content type='html'>Following up on &lt;a href="http://id-perl.blogspot.com/2010/02/loganyscript.html"&gt;my previous post&lt;/a&gt;, I've just uploaded &lt;a href="http://search.cpan.org/dist/Log-Any-App/"&gt;Log::Any::App&lt;/a&gt; to CPAN.&lt;br /&gt;&lt;br /&gt;Do you write or use modules that use &lt;a href="http://search.cpan.org/dist/Log-Any/"&gt;Log::Any&lt;/a&gt;? Or, do you want to use Log::Any conveniently in an application? Now you can just do this:&lt;br /&gt;&lt;br /&gt;% perl -MLog::Any::App -MOtherModuleThatUsesLogAny -e ...&lt;br /&gt;&lt;br /&gt;and the logs will be displayed to screen. The default level is WARN, but if you want to debug things:&lt;br /&gt;&lt;br /&gt;% DEBUG=1 perl -MLog::Any::App ...&lt;br /&gt;&lt;br /&gt;or if you want to quiet things down:&lt;br /&gt;&lt;br /&gt;% LOGLEVEL=error perl -MLog::Any::App ...&lt;br /&gt;&lt;br /&gt;If you put 'use Log::Any::App' in your script, when run it will by default log to file too (~/prog.log or /var/log/prog.log). It can even automatically log to syslog.&lt;br /&gt;&lt;br /&gt;Zero-conf. No more long incantation.&lt;br /&gt;&lt;br /&gt;Please tell me what you think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3560276943518092598?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3560276943518092598/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/loganyapp-2.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3560276943518092598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3560276943518092598'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/loganyapp-2.html' title='Log::Any::App (2)'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5553137168208404210</id><published>2010-03-11T23:02:00.000-08:00</published><updated>2010-03-11T23:08:27.208-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Choosing test names</title><content type='html'>Which test names do you prefer?&lt;br /&gt;&lt;br /&gt;"tong() method can connect to database"&lt;br /&gt;"tong() method can disconnect from database"&lt;br /&gt;"sha() method can delete an existing file"&lt;br /&gt;"sha() method fails when deleting a non-existing file"&lt;br /&gt;&lt;br /&gt;or:&lt;br /&gt;&lt;br /&gt;"tong 1"&lt;br /&gt;"tong 2"&lt;br /&gt;"sha 1"&lt;br /&gt;"sha 2"&lt;br /&gt;&lt;br /&gt;They are both rather extreme, but if I had to choose, I would still rather go with the shorter ones. I tend to treat test names more like unique IDs, and when things go wrong I just look up the actual test code.&lt;br /&gt;&lt;br /&gt;I wouldn't mind verbose test names though if they can somehow be automatically generated (a future Google Translate project, perhaps?) from code, because they are just repeating what the code says.&lt;br /&gt;&lt;br /&gt;To repeat myself, it's the DRY principle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5553137168208404210?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5553137168208404210/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/choosing-test-names.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5553137168208404210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5553137168208404210'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/choosing-test-names.html' title='Choosing test names'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-523411473437743080</id><published>2010-03-03T04:26:00.000-08:00</published><updated>2010-03-03T04:59:50.915-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>On reading code</title><content type='html'>Last week I started using github, forked a project, and read some of &lt;a href="http://github.com/miyagawa/"&gt;miyagawa&lt;/a&gt;'s beautiful code. Later on the weekend, I imitated a particular style I found from his code to improve my own code.&lt;br /&gt;&lt;br /&gt;And then I realized: during the course of many years as a programmer, I really really seldom read other people's code, especially real-world code. Sure, I do whenever I have to patch something. But other than that, practically never.&lt;br /&gt;&lt;br /&gt;Other than code, I do read an awful lot: books, magazines, mailing lists, forums, blogs, web pages. I have never doubted the benefits of reading for improving knowledge and understanding, so why haven't I read more code? A couple of reasons I can think of:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. We programmers are not paid to read code.&lt;/b&gt; We are paid to write programs, to churn out lines upon lines of code. Heck, we're not even paid to write good code, we're paid to get the job done.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Reading code is hard.&lt;/b&gt; It can really drain your brain. Imagine a recipe book where the flow of instructions is not linear (jump to line X, jump to page Y and then return here), where a misplaced character can destroy the whole recipe, and where everything is so interdependent and interlinked that you need to read everything twice first before you can begin to understand it. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Reading code is boring.&lt;/b&gt; Can you really curl up with a good program the way you can with an exciting novel?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Reading code is not necessary.&lt;/b&gt; A good reusable piece of code need not be read anyway, all you need is its API documentation. Programmers are hired regardless of their ability to read real-world code, there are no interview tests in reading code other than a few or at most a dozen lines of it. Heck, programmers are even hired &lt;a href="http://www.codinghorror.com/blog/2007/02/why-cant-programmers-program.html"&gt;despite their inability to write any code at all&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After experiencing that one session of code reading can do some wonders, I'll make it a program to read more (good) other people's code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-523411473437743080?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/523411473437743080/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/03/on-reading-code.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/523411473437743080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/523411473437743080'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/03/on-reading-code.html' title='On reading code'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2342788216439176970</id><published>2010-02-26T19:56:00.000-08:00</published><updated>2010-02-26T20:32:24.554-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>{Logging, Messaging, Notification, Auditing, ...} frameworks</title><content type='html'>They're all the same, in many respects.&lt;br /&gt;&lt;br /&gt;In my module code, I want to be as flexible as possible. I want to be as detached from implementation details as possible.&lt;br /&gt;&lt;br /&gt;I just want to generate a log message (or a notification, or an audit entry). I don't want to care where it ends up, how it is sent, how it is filtered/categorized, who the recipient(s) is/are, what medium(s) is/are used, etc. Let whoever uses the module configure it all.&lt;br /&gt;&lt;br /&gt;And I don't want to reinvent the wheel, I want to use an existing framework. A logging framework seems to be a sensible choice. Let's use &lt;a href="http://search.cpan.org/dist/Log-Any/"&gt;Log::Any&lt;/a&gt; for example. This is a snippet from a module for a file-manager-type web app:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;my (@success, @failed);&lt;br /&gt;for (@files) {&lt;br /&gt;    unlink $_;&lt;br /&gt;    if ($!) { push @failed, $_ } else { push @success, $_ }&lt;br /&gt;}&lt;br /&gt;$log-&gt;info("Done deleting files. Files deleted: %s. Files not deleted: %s", \@success, @failed);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The message can end up:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;in a system-wide log-file;&lt;br /&gt;&lt;li&gt;discarded (if configured level of output is less than INFO);&lt;br /&gt;&lt;li&gt;in a per-user log file;&lt;br /&gt;&lt;li&gt;in a notification email to user (should the user configure it);&lt;br /&gt;&lt;li&gt;in a notification email to sysadmin (should the admin configure it);&lt;br /&gt;&lt;li&gt;into audit table in database (if the application is using a database);&lt;br /&gt;&lt;li&gt;in the console (if this module is also used in a command-line based app);&lt;br /&gt;&lt;li&gt;as a desktop notification (if this module is also used in a desktop app);&lt;br /&gt;&lt;li&gt;in an internal web-based forum;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;However, some of those outputs usually need some additional metadata. In email and desktop notification we usually need separate subject and body. In the audit table in database we need to fill in who (the logged in user). In web applications we usually need to log the remote IP address (or even User-Agent string). In desktop notification or forum sometimes we would like to be able to update the message instead of creating a new one.&lt;br /&gt;&lt;br /&gt;Instead of in the logging output module (the appender and formatter, in Log4perl-speak), sometimes I *do* care and need to specify this in my module.&lt;br /&gt;&lt;br /&gt;Logging APIs usually do not allow us to do so. Output/appender modules are only given the message as a string.&lt;br /&gt;&lt;br /&gt;So I intend to cheat by embedding a JSON-/YAML-encoded metadata in front of the message, e.g.:&lt;br /&gt;&lt;pre&gt;$log-&gt;info("\x00{subject: 'Progress of copying $foo to $bar', id: xasd8f7d}\x00Copying $foo to $bar. 0%");&lt;br /&gt;for (1..100) {&lt;br /&gt;    $log-&gt;info("\x00{id: xasd8f7d}\x00$_%");&lt;br /&gt;    sleep 1;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The presence of \x00 signify that until the next \x00 there will be additional metadata in the form of YAML (or JSON). This way, my desktop notification and web-based forum output module knows that the 2nd-101st message is an update and thus can adjust accordingly. &lt;br /&gt;&lt;br /&gt;It should, and I don't have to reinvent any framework or wrapper. But it feels so hackish and ugly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2342788216439176970?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2342788216439176970/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/logging-messaging-notification-auditing.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2342788216439176970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2342788216439176970'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/logging-messaging-notification-auditing.html' title='{Logging, Messaging, Notification, Auditing, ...} frameworks'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4092299359110278189</id><published>2010-02-25T23:13:00.000-08:00</published><updated>2010-02-25T23:31:55.073-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The problems with the older CPAN clients</title><content type='html'>Thank God for &lt;a href="http://search.cpan.org/dist/App-cpanminus/"&gt;cpanminus&lt;/a&gt;. Now that I'm free from having to use them, allow me to rant, no, bitch about them.&lt;br /&gt;&lt;br /&gt;1. Bad defaults. Some default values might make sense 10-15 years ago, but not so much nowadays. For example, I'd argue that "follow" should now be default. See #2.&lt;br /&gt;&lt;br /&gt;2. Too developer-oriented. For example, I believe "notest" should be on by default. This is compounded by the fact that installing Perl modules is so damn-slow already. See #3.&lt;br /&gt;&lt;br /&gt;3. Too slow. Startup takes around 10-30 seconds or more. Installing Moose usually takes minutes (but with cpanminus, it only takes about 1 minute with --notest on my PC). Autocomplete takes one to a couple of seconds.&lt;br /&gt;&lt;br /&gt;4. Too interactive, too verbose. The older clients are getting better but not quiet enough, cpanminus is such a breathe of fresh air.&lt;br /&gt;&lt;br /&gt;5. Too bloated (which is the reason why cpanminus was developed in the first place).&lt;br /&gt;&lt;br /&gt;The older CPAN clients are an embarassment if we compare it to "apt-get", "yum", "urpmi", which are way faster, way quieter, way less interactive. There's no reason why a CPAN client cannot be like those. And fortunately cpanminus proves it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4092299359110278189?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4092299359110278189/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/problems-with-older-cpan-clients.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4092299359110278189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4092299359110278189'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/problems-with-older-cpan-clients.html' title='The problems with the older CPAN clients'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1879540137900214729</id><published>2010-02-25T21:14:00.000-08:00</published><updated>2010-02-25T23:09:23.692-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The shorter path to deployment heaven</title><content type='html'>Now that there is &lt;a href=http://search.cpan.org/dist/App-cpanminus/&gt;cpanminus&lt;/a&gt;, I've &lt;a href="http://github.com/sharyanto/cpan_autoinc"&gt;modified&lt;/a&gt; the handy little module &lt;a href="http://search.cpan.org/dist/CPAN-AutoINC/"&gt;CPAN::AutoINC&lt;/a&gt; to prefer cpanminus over CPAN.&lt;br /&gt;&lt;br /&gt;So now when users download and run my programs/scripts for the first time, instead of failing with the dreaded message:&lt;br /&gt;&lt;pre&gt;Can't locate Foo/Bar.pm in @INC (@INC contains: [a dozen or more of paths....]).&lt;br /&gt;BEGIN failed--compilation aborted at /some/path line 123&lt;/pre&gt;&lt;br /&gt;which users or even Perl novices have no clue on how to fix, the program will instead automatically download every necessary CPAN modules into the user's home directory and runs out-of-the-box on the first try!&lt;br /&gt;&lt;pre&gt;$ download-bca&lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/A/AD/ADAMK/File-HomeDir-0.89.tar.gz&lt;br /&gt;Building File-HomeDir-0.89 for File::HomeDir...                                    &lt;br /&gt;File::HomeDir installed successfully.                                              &lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/D/DR/DROLSKY/File-Slurp-9999.13.tar.gz&lt;br /&gt;Building File-Slurp-9999.13 for File::Slurp...                                        &lt;br /&gt;File::Slurp installed successfully.                                                   &lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/S/SH/SHARYANTO/Finance-Bank-ID-BCA-0.07.tar.gz&lt;br /&gt;==&gt; Found dependencies: Pod::Coverage, DateTime, Test::Pod::Coverage, Log::Any, Any::Moose, Mouse&lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/R/RC/RCLAMP/Pod-Coverage-0.20.tar.gz             &lt;br /&gt;==&gt; Found dependencies: Devel::Symdump                                                           &lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/A/AN/ANDK/Devel-Symdump-2.08.tar.gz              &lt;br /&gt;Building Devel-Symdump-2.08 for Devel::Symdump...                                                &lt;br /&gt;Devel::Symdump installed successfully.                                                           &lt;br /&gt;Building Pod-Coverage-0.20 for Pod::Coverage...                                                  &lt;br /&gt;Pod::Coverage installed successfully.                                                            &lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;Fetching http://search.cpan.org/CPAN/authors/id/S/SP/SPADKINS/App-Options-1.07.tar.gz&lt;br /&gt;Building App-Options-1.07 for App::Options...&lt;br /&gt;App::Options installed successfully.&lt;br /&gt;...&lt;br /&gt;(the program finally runs)&lt;/pre&gt;&lt;br /&gt;As the developer, you only need to put "use CPAN::AutoINC" at the top of your main script. How's that for deployment heaven? Zero installation, zero configuration (thanks to cpanminus), zero dependency outside of Perl core modules.&lt;br /&gt;&lt;br /&gt;But there's a catch. The user (or the user's sysadmin) still needs to install CPAN::AutoINC and needs to install and bootstrap local::lib first. So it's not really an out-of-the-box experience yet.&lt;br /&gt;&lt;br /&gt;miyagawa++ is already planning to automatically bootstrap local::lib from cpanminus, and the logic behind CPAN::AutoINC is just a couple of dozen lines that can be embedded easily into the script (this process can be made automatic with distribution building tools like &lt;a href="http://search.cpan.org/dist/Dist-Zilla"&gt;Dist::Zilla&lt;/a&gt; plugin).&lt;br /&gt;&lt;br /&gt;Since cpanminus has zero dependencies, we can simply include it too in our application.&lt;br /&gt;&lt;br /&gt;And maybe in the future there can be GUI interfaces for cpanm, so it can display a nice dialog to ask confirmation via the desktop.&lt;br /&gt;&lt;br /&gt;Be prepared to be able to provide a much nicer experience for your users.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1879540137900214729?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1879540137900214729/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/shorter-path-to-deployment-heaven.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1879540137900214729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1879540137900214729'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/shorter-path-to-deployment-heaven.html' title='The shorter path to deployment heaven'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7956192491069555655</id><published>2010-02-24T06:33:00.000-08:00</published><updated>2010-02-24T07:06:50.006-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Log::Any::App</title><content type='html'>This is a draft/RFC document.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/dist/Log-Any/"&gt;Log::Any&lt;/a&gt; is &lt;a href="http://id-perl.blogspot.com/2010/01/logany.html"&gt;great if you're writing modules&lt;/a&gt;. You only need to say:&lt;br /&gt;&lt;pre&gt;use Log::Any qw($log);&lt;/pre&gt;&lt;br /&gt;and then you're off producing logs with:&lt;br /&gt;&lt;pre&gt;$log-&gt;debug(...);&lt;br /&gt;$log-&gt;warn(...);&lt;br /&gt;# etc&lt;/pre&gt;&lt;br /&gt;But if you're writing scripts/applications (and thus need to "consume" or display the logs as well), it becomes a bit of a hassle. For example, if you want to display logs to the screen with &lt;a href="http://search.cpan.org/dist/Log-Dispatch/"&gt;Log::Dispatch&lt;/a&gt;, this is the incantation you need:&lt;br /&gt;&lt;pre&gt;use Log::Any qw($log);&lt;br /&gt;use Log::Any::Adapter;&lt;br /&gt;use Log::Dispatch;&lt;br /&gt;Log::Any::Adapter-&gt;set('Dispatch');&lt;br /&gt;my $disp = Log::Dispatch-&gt;new(outputs =&gt; ["Screen", min_level=&gt;"debug", newline=&gt;1]);&lt;br /&gt;Log::Any::Adapter-&gt;set("Dispatch", dispatcher=&gt;$disp);&lt;br /&gt;...&lt;br /&gt;$log-&gt;warn(...);&lt;/pre&gt;&lt;br /&gt;which I'm sure I'll never ever remember and will just copy paste everytime.&lt;br /&gt;&lt;br /&gt;The goal is to be able to write only this in your scripts:&lt;br /&gt;&lt;pre&gt;use Log::Any::App qw($log);&lt;/pre&gt;&lt;br /&gt;and Log::Any::App (which currently does not exist) will take care of all the rest:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Choose the best available adapter(s);&lt;br /&gt;&lt;li&gt;Configure the adapter(s) with the best defaults, e.g. to screen, as well as to file /var/log/SCRIPTNAME.log (if running as root) or ~/SCRIPTNAME.log (if running as user). The defaults can of course be changed via configuration;&lt;br /&gt;&lt;li&gt;Pick configuration from various sources, like environment variables (e.g. turning level to debug if DEBUG is set to true), command line options (e.g. log level from --log_level/--log-level/--debug/--verbose/etc, as well as detecting result from Getopt::Long or App::Options so we can avoid parsing by ourselves)&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I think the main challenge is arranging a set of defaults that are acceptable and comfortable for a lot of people, and working together nicely with available modules like adapter modules (Log::Any::Adapter::Dispatch, Log::Any::Adapter::Log4perl), command line parsing modules, configuration modules, etc.&lt;br /&gt;&lt;br /&gt;And later should you refactor your script into modules, the logging part can be left untouched as they already use the Log::Any framework.&lt;br /&gt;&lt;br /&gt;Modules to look at: &lt;a href="http://search.cpan.org/dist/Log-Dispatchouli/"&gt;Log::Dispatchouli&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7956192491069555655?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7956192491069555655/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/loganyscript.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7956192491069555655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7956192491069555655'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/loganyscript.html' title='Log::Any::App'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2900481484669947842</id><published>2010-02-17T01:59:00.000-08:00</published><updated>2010-02-17T02:09:07.146-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>A small plea to non-English bloggers</title><content type='html'>I absolutely welcome and cheer the non-English posts in the Iron Man feed (as they are also welcome by &lt;a href="http://www.enlightenedperl.org/ironman.html"&gt;the rules&lt;/a&gt;). I even try to read one or two whenever I can.&lt;br /&gt;&lt;br /&gt;But, at the risk of sounding like a party pooper, guys, could you please not give your post an English title/subject when the content is not in English? I'm sure other people will appreciate it as it saves them time when they can't read your language anyway.&lt;br /&gt;&lt;br /&gt;Thank you very very much, and keep blogging!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2900481484669947842?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2900481484669947842/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/small-plea-to-non-english-bloggers.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2900481484669947842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2900481484669947842'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/small-plea-to-non-english-bloggers.html' title='A small plea to non-English bloggers'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4499937791049291290</id><published>2010-02-10T18:10:00.000-08:00</published><updated>2010-02-10T18:10:00.450-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The (lack of) readability of Perl</title><content type='html'>Can't believe it's almost 8 years since I wrote this &lt;a href="http://www.master.web.id/scriptingworld/03-8_perl_unreadable/03-8_perl_unreadable.html"&gt;Indonesian article&lt;/a&gt; about "8 things that make Perl relatively unreadable".&lt;br /&gt;&lt;br /&gt;To summarize, I think the readability issue in Perl largely boils down to the high usage of symbols/non-alphanumeric characters (e.g. regex and special variables). This admittedly won't change for years to come, as Perl 6 also offers us lots of new operators, even allows us to define new ones, using the full range of the Unicode charset! So we will almost certainly be hearing and need to be fighting against this meme for a long long time.&lt;br /&gt;&lt;br /&gt;I also believe that most of the complaints about Perl being unreadable come from non-Perl users. When they read some code, they expect it to be able to read/guess it based on the prior knowledge of some other programming language. For example, even before I started learning French or German, I could guess the general meaning of some French and German (or some other European language) phrases based solely on my knowledge of English. This does not happen with, say, Chinese or Math or regular expression, as the symbols are just gibberish to the non-initiated.&lt;br /&gt;&lt;br /&gt;Perhaps marketing that Perl is one of the hardest languages to master will attract more people to learning it, as that's &lt;a href="http://www.youtube.com/watch?v=yFaCDyPPk7s"&gt;what's happening&lt;/a&gt; with Cantonese and some westerners.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4499937791049291290?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4499937791049291290/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/lack-of-readability-of-perl.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4499937791049291290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4499937791049291290'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/lack-of-readability-of-perl.html' title='The (lack of) readability of Perl'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4051500025700684260</id><published>2010-02-10T17:49:00.000-08:00</published><updated>2010-02-10T17:49:00.177-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Setelah 7 tahun...</title><content type='html'>Tahun 2003 saya menulis artikel ini: &lt;a href="http://master.web.id/scriptingworld/03-8_perl_unreadable/03-8_perl_unreadable.html"&gt;8 Hal Yang Membuat Perl Relatif Unreadable&lt;/a&gt;. Wah, 1 tahun lagi sudah 8 tahun deh, secepat itukah waktu berlalu?&lt;br /&gt;&lt;br /&gt;Eniwei, setelah lewat 7 tahun, tentu saja ada beberapa hal/poin di artikel tersebut yang sudah tidak berlaku lagi. Bukti bahwa Perl tetap hidup karena tetap berubah dan berevolusi.&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;Moose dan sistem OO di Perl6.&lt;/b&gt; Kini pengguna Perl tidak perlu minder lagi, karena Perl kini sudah punya sistem objek yang modern dan "tidak mengerikan lagi", bahkan berani deh beradu superior dengan Ruby, Python, Javascript, dll.&lt;br /&gt;&lt;br /&gt;2. Beberapa perbaikan readability dapat kita jumpai di Perl 6, antara lain penggunaan prefiks variabel yang lebih konsisten, Untuk mengakses elemen array dan hash kini menggunakan @array[n] dan %array{s}, tidak lagi $array[n] dan $array{s}, bahkan sebetulnya Anda bisa "hidup" hanya dengan mengenal satu prefiks saja, $, karena array dan hash dan struktur kompleks semuanya dapat ditampung oleh $.&lt;br /&gt;&lt;br /&gt;Terdapat pula grammar untuk mengizinkan kita memodularkan pola regex yang kompleks sehingga menjadi jauh lebih readable.&lt;br /&gt;&lt;br /&gt;Tapi... bukan Perl namanya kalau tidak mengizinkan kita meringkas-ringkas program menggunakan banyak simbol. Tak kurang dari puluhan operator baru, belum lagi metaoperator, dan juga berbagai idiom baru, hadir di Perl 6. Bahkan seluruh karakter Unicode dapat dipakai!&lt;br /&gt;&lt;br /&gt;Apakah ini membuat Perl tetap/makin unreadable? Mengulangi kata-kata di artikel 2003 saya, readability sesuatu yang subjektif. Apakah matematik yang penuh simbol juga unreadable? Tentu saja iya, bagi mereka yang buta/awam matematik, tapi tentu tidak bagi matematikawan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4051500025700684260?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4051500025700684260/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/setelah-7-tahun.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4051500025700684260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4051500025700684260'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/setelah-7-tahun.html' title='Setelah 7 tahun...'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7865629953843285091</id><published>2010-02-03T16:07:00.000-08:00</published><updated>2010-02-03T16:07:00.629-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>App::Options</title><content type='html'>Over the course of many years, I have written lots of lots of short command-line scripts in Perl (Perl's great for that, you know). Most of these scripts are small utilities, or replacement for shell scripts, or automation tools.&lt;br /&gt;&lt;br /&gt;All of these scripts invariably need some ability to take command-line options. Of course, back in the days, I used Getopt::Std and Getopt::Long. They both did their task well, but also invariably I will need to provide -h or --help for usage information. I always hate having to write this usage text manually.&lt;br /&gt;&lt;br /&gt;Also, if you use your scripts often enough, you will end up with the same incantation for some, that you will want to put the command line options to a config file to avoid repeating yourself. Passwords are also not appropriate in command-line options due to security issues.&lt;br /&gt;&lt;br /&gt;So I now use &lt;a href="http://search.cpan.org/dist/App-Options/"&gt;App::Options&lt;/a&gt; and have never looked back. You can look at it as a pretty straightforward replacement for Getopt::Long, but it gives you automatic --help and --version (--program_version actually, but --version also does something else wonderful). And it &lt;b&gt;automatically&lt;/b&gt; enables you to read config files. I emphasize "automatically" because you absolutely do not have to do a single thing, as App::Options gives you some nice defaults on where to find the config files.&lt;br /&gt;&lt;br /&gt;How great is that? Just write your code as if you're using Getopt::Long, but gain all these extra abilities for free!&lt;br /&gt;&lt;br /&gt;There are other solutions for command-line scripts, like &lt;a href="http://search.cpan.org/dist/App-Cmd/"&gt;App::Cmd&lt;/a&gt;, but really App::Options is the easiest way especially for old-timers like me who do not want to change their Getopt::Long-style habit.&lt;br /&gt;&lt;br /&gt;App::Options is not perfect though. There are a couple of small annoyances I have about it, but I'm not hung up on them. The first is that "=" in command-line option is required, i.e. you have to write "--opt=args" instead of "--opt args". Second is, --version defaults to displaying Perl modules version instead of your program's version.&lt;br /&gt;&lt;br /&gt;For larger apps, I also sometimes need hierarchical/multilevel configuration. It'd also be nice to have YAML support. These are something I hope to accomplish with &lt;a href="http://search.cpan.org/dist/Config-Tree/"&gt;Config::Tree&lt;/a&gt;, but I guess I still need to work on it quite a bit before I can replace my usage of App::Options with it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7865629953843285091?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7865629953843285091/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/02/appoptions.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7865629953843285091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7865629953843285091'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/02/appoptions.html' title='App::Options'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5866289967059518186</id><published>2010-01-27T15:42:00.000-08:00</published><updated>2010-01-27T15:42:00.221-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Four months after...</title><content type='html'>Four months ago I joined the &lt;a href="http://www.enlightenedperl.org/ironman.html"&gt;Iron Man challenge&lt;/a&gt;. So what have I done and what did I get out of this?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What I have done:&lt;/b&gt; wrote &lt;a href="http://search.cpan.org/~sharyanto/"&gt;several new Perl modules&lt;/a&gt;. I didn't feel like I have enough things to say (that's why I set up the blog as "Perl Indonesia" and invited others to join instead of "Steven Haryanto's Perl Adventure"), and I still don't, really. So I write more code instead, and post about them.&lt;br /&gt;&lt;br /&gt;The modules are typically small, ones which I can finish in one or two sittings. The ideas for these modules usually have been floating in my head for some time, but since they are trivial enough I have never gotten around to write them. The blogging challenge changed that.&lt;br /&gt;&lt;br /&gt;Some of the other modules actually come from code I have written, in one form or another, but have not been properly packaged. &lt;a href="http://search.cpan.org/dist/dist-zilla/"&gt;Dist::Zilla&lt;/a&gt; changed that, as it lowers the cost of maintaining and releasing Perl distributions. Thanks, RJBS!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What I get:&lt;/b&gt; joy and satisfaction that I am actively doing something for Perl.&lt;br /&gt;&lt;br /&gt;All in all, Ironman is a great idea and a good cause. I encourage everybody to keep blogging and writing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5866289967059518186?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5866289967059518186/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/01/four-months-after.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5866289967059518186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5866289967059518186'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/01/four-months-after.html' title='Four months after...'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6623223755068529222</id><published>2010-01-20T04:00:00.000-08:00</published><updated>2010-01-20T04:59:59.887-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Lingua::ZH::PinyinConvert::ID</title><content type='html'>Today I released &lt;a href="http://search.cpan.org/dist/Lingua-ZH-PinyinConvert-ID"&gt;Lingua::ZH::PinyinConvert::ID&lt;/a&gt;. This release is dedicated to the recently deceased former President of Indonesia, &lt;a href="http://en.wikipedia.org/wiki/Abdurrahman_Wahid"&gt;Abdurrahman Wahid&lt;/a&gt;, which in 2001 declared Chinese new year as national holiday as well as re-allowed the use of Chinese characters and the expression of Chinese culture in daily life, thus ending the 30 years of anti-Chinese laws during the Suharto regime.&lt;br /&gt;&lt;br /&gt;Sadly, a generation of &lt;a href="http://en.wikipedia.org/wiki/Chinese_Indonesian"&gt;Indonesian Chinese&lt;/a&gt; people grew up while being cut off from their heritage, not learning Chinese languages nor a lot of the Chinese culture. This will probably be fixed in the next couple of generations as many elementary schools now start to include Mandarin in their curriculum.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6623223755068529222?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6623223755068529222/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/01/linguazhpinyinconvertid.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6623223755068529222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6623223755068529222'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/01/linguazhpinyinconvertid.html' title='Lingua::ZH::PinyinConvert::ID'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-935031877483813798</id><published>2010-01-12T18:21:00.000-08:00</published><updated>2010-01-14T07:10:14.911-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Log::Any</title><content type='html'>A few weeks ago I found about &lt;a href="http://search.cpan.org/dist/Log-Any/"&gt;Log::Any&lt;/a&gt;, and have since migrated many of modules to it (usually from &lt;a href="http://search.cpan.org/dist/Log-Log4perl/"&gt;Log::Log4perl&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The two main advantages of Log::Any for me:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;your users don't need to configure anything if they don't want logging.&lt;/b&gt; When my module, say Foo, uses Log4perl to produce logs, then when you use Foo, Log4perl will emit a warning: &lt;code&gt;Log4perl: Seems like no initialization happened. Forgot to call init()?&lt;/code&gt;. To remove this warning you need to initialize Log4perl, e.g. using &lt;code&gt;use Log::Log4perl qw(:easy); Log::Log4perl-&gt;easy_init($FATAL);&lt;/code&gt; This is annoying if you happen to not care about logging.&lt;br /&gt;&lt;br /&gt;With Log::Any, the default is null logging.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;printf-style logging.&lt;/b&gt; For example, &lt;code&gt;$log-&gt;debugf("data = %s", $data);&lt;/code&gt; It can also handle references/nested data structures, so you don't have to resort to something like &lt;code&gt;$log-&gt;debug(sub { "data = " . Dumper($big_data) });&lt;/code&gt;. In fact, 99% of the time I use sub{} is precisely because I want to avoid the cost of dumping.&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Of course, there are some features in Log4perl that is missing in Log::Any, like logdie() and the TRACE level. But it is a small price to pay. You gain other benefits, the most important of which is compatibility with other logging frameworks. I'm sure some people prefer something else to  Log4perl. Log::Any currently supports Log4perl as well as &lt;a href="http://search.cpan.org/dist/Log-Dispatch/"&gt;Log::Dispatch&lt;/a&gt;, and possibly others too in the future.&lt;br /&gt;&lt;br /&gt;Thanks Jonathan for Log::Any!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-935031877483813798?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/935031877483813798/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/01/logany.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/935031877483813798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/935031877483813798'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/01/logany.html' title='Log::Any'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7523906779690251935</id><published>2010-01-05T16:09:00.000-08:00</published><updated>2010-01-05T17:26:46.364-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The Help MySQL petition</title><content type='html'>As much as I love(d) MySQL and am still using it a lot (mostly for PHP web applications that are married to it), there seems to be too much politics surrounding it these days.&lt;br /&gt;&lt;br /&gt;From &lt;a href="http://helpmysql.org/en/theissue/customerspaythebill"&gt;helpmysql.org&lt;/a&gt; (emphasis mine):&lt;br /&gt;&lt;blockquote&gt;If those IPRs fall into the hands of MySQL's &lt;b&gt;primary competitor&lt;/b&gt;, then MySQL immediately ceases to be an alternative to Oracle's own high-priced products. So far, customers had the choice to use MySQL in new projects instead of Oracle's products. Some large companies even migrated (switched) from Oracle to MySQL for existing software solutions. And every one could credibly threaten Oracle's salespeople with using MySQL unless a major discount was granted. &lt;b&gt;If Oracle owns MySQL, it will only laugh when customers try this.&lt;/b&gt; Getting rid of this problem is easily worth one billion dollars a year to Oracle, if not more.&lt;/blockquote&gt;&lt;br /&gt;Is Oracle really MySQL's primary competitor? I thought they represent two very distinct segments?&lt;br /&gt;&lt;br /&gt;Also, if Oracle owns MySQL, why can't I still threaten Oracle sales reps to use MySQL to get a deep discount on Oracle DB? Because Oracle will threaten to kill MySQL, or sue every other company that provides paid support for MySQL, or deliberately delay fixing critical bugs in MySQL? I'm really not convinced with this argument. In any case MySQL would still be a cheaper substitute for Oracle. And I were an Oracle client wanting to get a discount (and not laughs), I think I would rather threaten to switch to SQL Server or Postgres instead.&lt;br /&gt;&lt;br /&gt;Also, online petition immediately conjures up the image of a teenager trying to save his/her favorite cartoon TV show that is being cancelled.&lt;br /&gt;&lt;br /&gt;Also, let's never forget the bigger "politics" before this, regarding the position of MySQL AB on the usefulness of things like transactions or foreign key constraints, depending on whether its product has support for them.&lt;br /&gt;&lt;br /&gt;Let's take one particular example with foreign key constraints. It shows that you really can't trust the opinion of people with ulterior motives. Here's a snippet from the old MySQL 3.23.x manual, when MySQL has no support for foreign key checking (emphasis mine):&lt;br /&gt;&lt;blockquote&gt;&lt;big&gt;5.4.5.1 Reasons NOT to Use Foreign Keys constraints&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;There are &lt;b&gt;so many problems&lt;/b&gt; with foreign key constraints that we don't know where to start:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Foreign key constraints make life &lt;b&gt;very complicated&lt;/b&gt;, because the foreign key definitions must be stored in a database and implementing them would destroy the whole ``nice approach'' of using files that can be moved, copied, and removed.&lt;br /&gt;&lt;li&gt;The &lt;b&gt;speed impact is terrible&lt;/b&gt; for INSERT and UPDATE statements, and in this case almost all FOREIGN KEY constraint checks are useless because you usually insert records in the right tables in the right order, anyway.&lt;br /&gt;&lt;li&gt;There is also a need to hold locks on many more tables when updating one table, because the side effects can cascade through the entire database. It's MUCH faster to delete records from one table first and subsequently delete them from the other tables.&lt;br /&gt;&lt;li&gt;You can no longer restore a table by doing a full delete from the table and then restoring all records (from a new source or from a backup).&lt;br /&gt;&lt;li&gt;If you use foreign key constraints you can't dump and restore tables unless you do so in a very specific order.&lt;br /&gt;&lt;li&gt;It's very easy to do ``allowed'' circular definitions that make the tables impossible to re-create each table with a single create statement, even if the definition works and is usable.&lt;br /&gt;&lt;li&gt;It's very easy to overlook FOREIGN KEY ... ON DELETE rules when one codes an application. It's not unusual that one loses a lot of important information just because a wrong or misused ON DELETE rule. &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;The &lt;b&gt;only&lt;/b&gt; nice aspect of FOREIGN KEY is that it gives ODBC and some other client programs the ability to see how a table is connected and to use this to show connection diagrams and to help in building applicatons.&lt;/blockquote&gt;&lt;br /&gt;And here's a snippet from MySQL 5.1 manual, when, through InnoDB, MySQL now has support for foreign keys. Notice the complete change of heart (emphasis mine):&lt;br /&gt;&lt;blockquote&gt;&lt;big&gt;1.8.5.4. Foreign Keys&lt;/big&gt;&lt;br /&gt;&lt;br /&gt;The InnoDB storage engine supports checking of foreign key constraints, including CASCADE, ON DELETE, and ON UPDATE. See Section 13.6.4.4, “FOREIGN KEY Constraints”.&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;Foreign key enforcement offers &lt;b&gt;several&lt;/b&gt; benefits to database developers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Assuming proper design of the relationships, foreign key constraints make it more difficult for a programmer to introduce an inconsistency into the database.&lt;br /&gt;&lt;li&gt;Centralized checking of constraints by the database server makes it unnecessary to perform these checks on the application side. This eliminates the possibility that different applications may not all check the constraints in the same way.&lt;br /&gt;&lt;li&gt;Using cascading updates and deletes can &lt;b&gt;simplify&lt;/b&gt; the application code.&lt;br /&gt;&lt;li&gt;Properly designed foreign key rules aid in documenting relationships between tables.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Do keep in mind that these benefits come at the cost of additional overhead for the database server to perform the necessary checks. Additional checking by the server affects performance, which &lt;b&gt;for some applications&lt;/b&gt; may be sufficiently undesirable as to be avoided if possible. (Some major commercial applications have coded the foreign key logic at the application level for this reason.)&lt;br /&gt;&lt;br /&gt;[...]&lt;br /&gt;&lt;br /&gt;Be aware that the use of foreign keys can &lt;b&gt;sometimes&lt;/b&gt; lead to problems:&lt;br /&gt;&lt;br /&gt;[...]&lt;/blockquote&gt;&lt;br /&gt;This either means MySQL AB deliberately added misleading opinion about foreign key constraints, or MySQL AB grew up and saw the benefits of foreign key constraints during the later days of 3.23/4.x. Either way doesn't bode well on MySQL.&lt;br /&gt;&lt;br /&gt;But anyway, I guess all of these so-called "politics" exist in any product advocacy. No product can support all possible features, so unsupported features sometimes get downplayed, either deliberately or innocently. Since Perl subscribes to the multiparadigm and TIMTOWTDI thinking, we suffer less from these. But haven't we all heard more than a handful of otherwise brilliant Perl programmers casting aside things like block indentation or even OOP as overrated, just because other languages support these features (better) than us?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7523906779690251935?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7523906779690251935/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/01/help-mysql-petition.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7523906779690251935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7523906779690251935'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/01/help-mysql-petition.html' title='The Help MySQL petition'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7152242587690265236</id><published>2010-01-05T08:56:00.000-08:00</published><updated>2010-01-05T09:38:50.095-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Parsing with Perl</title><content type='html'>When it comes to text processing and manipulation, I suspect that the majority of Perl programmers depend on their regex skill to do the job. So much that it becomes their hammer. At least it is mine, because I whip up regexes for almost anything, from web scraping to &lt;a href="http://steven.blogs.masterweb.net/2009/05/21/kbbi-versi-stardict/"&gt;converting dictionaries&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Which is a pity because there are other useful techniques, like parsing.&lt;br /&gt;&lt;br /&gt;Admittedly, parsing is a bit harder (to do correctly), and libraries for parsing most formats out there, from XML to YAML, from CSV to PPI, already exist anyway. So ironically it's even harder to find useful, practical applications for parsing that are easy to implement. Most parser tools seem to invariably give the tired, if not overused, calculator example (i.e., parsing simple mathematical expression like '3 * (2 + 4)').&lt;br /&gt;&lt;br /&gt;In the recent years, I've also have only encountered one instance where I want to do some parsing. Two weeks ago I thought it would be nice for my &lt;a href="http://search.cpan.org/dist/Data-Schema/"&gt;Data::Schema&lt;/a&gt; module to provide some shortcuts.&lt;br /&gt;&lt;br /&gt;'int*' would be translated to [int =&gt; {set=&gt;1}]&lt;br /&gt;&lt;br /&gt;'int[]' to [array =&gt; {of =&gt; "int"}], &lt;br /&gt;&lt;br /&gt;'(int*)[]' to [array =&gt; {of =&gt; [int =&gt; {set=&gt;1}]}]&lt;br /&gt;&lt;br /&gt;'(int[])*' to [array =&gt; {set =&gt; 1, of =&gt; "int"}]&lt;br /&gt;&lt;br /&gt;'(int|int[])[]' to [array =&gt; {of =&gt; {either =&gt; {of =&gt; ["int", [array =&gt; {of =&gt; "int"}]]}}}]&lt;br /&gt;&lt;br /&gt;and so on. (These shortcuts, along with some other goodies, will be in the next release of Data::Schema.)&lt;br /&gt;&lt;br /&gt;I ended up using &lt;a href="http://search.cpan.org/dist/Regexp-Grammars/"&gt;Regexp::Grammars&lt;/a&gt; for this, since I'm already on Perl 5.10. Regexp::Grammars is basically just a syntactic sugar and helper on top of Perl 5.10's regex which is already capable of doing recursive matching. &lt;a href="http://search.cpan.org/dist/Parse-RecDescent/"&gt;Parse::RecDescent&lt;/a&gt; is also equally easy to use, but I prefer the simpler interface of Regexp::Grammars. I quickly gave up on &lt;a href="http://search.cpan.org/dist/Parse-Yapp/"&gt;Parse::Yapp&lt;/a&gt; and &lt;a href="http://search.cpan.org/dist/Parse-Eyapp/"&gt;Parse::Eyapp&lt;/a&gt; though. Not that they're no good, it's just that they are too much trouble for my particularly simple need.&lt;br /&gt;&lt;br /&gt;Anyway, parsing is fun, as long as--like anything else in life--it doesn't get too complicated :-) I just need to find other small use cases where I can do some more parsing...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7152242587690265236?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7152242587690265236/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2010/01/parsing-with-perl.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7152242587690265236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7152242587690265236'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2010/01/parsing-with-perl.html' title='Parsing with Perl'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7676070502161777745</id><published>2009-12-30T16:26:00.000-08:00</published><updated>2009-12-30T19:50:58.619-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>CPAN CPAN on the disk, ...</title><content type='html'>Interestingly, there are some ID's up there that I've never ever heard of, ever. Either I'm the hobbit, or this list is not representative at all, or both. Maybe we should rank on total number of prereq'ed modules...&lt;br /&gt;&lt;pre&gt;$ cd /minicpan &amp;&amp; ( for dir in */*/*; do &lt;br /&gt;echo -e `ls $dir/*.tar.gz 2&gt;/dev/null | perl -ne's/-[^A-Za-z_].+//; &lt;br /&gt;$m{$_}++; END{print 0+keys %m}'`\\t${dir#*/*/}; done ) | sort -rn | head -10&lt;br /&gt;213     ADAMK&lt;br /&gt;212     ZOFFIX&lt;br /&gt;206     RJBS&lt;br /&gt;169     MIYAGAWA&lt;br /&gt;124     SMUELLER&lt;br /&gt;122     NUFFIN&lt;br /&gt;117     BINGOS&lt;br /&gt;111     GUGOD&lt;br /&gt;109     MARCEL&lt;br /&gt;100     TOKUHIROM&lt;/pre&gt;&lt;br /&gt;Keywords: CPAN authors with the most modules, most distributions&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7676070502161777745?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7676070502161777745/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/cpan-cpan-on-my-disk.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7676070502161777745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7676070502161777745'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/cpan-cpan-on-my-disk.html' title='CPAN CPAN on the disk, ...'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1592341674024609833</id><published>2009-12-28T06:30:00.000-08:00</published><updated>2009-12-28T08:17:03.903-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Given/when expression</title><content type='html'>Given/when in Perl 5.10 is great (and will be even greater in Perl 6, for example we can remove many of the now-required parentheses). But it is very statement-oriented. Sometimes I miss CASE expressions a la SQL:&lt;br /&gt;&lt;pre&gt;SELECT store_name, CASE store_name&lt;br /&gt;  WHEN 'Los Angeles' THEN sales*2&lt;br /&gt;  WHEN 'San Diego' THEN sales*1.5&lt;br /&gt;  ELSE sales&lt;br /&gt;  END AS new_sales&lt;br /&gt;FROM store;&lt;/pre&gt;&lt;br /&gt;So, how do you do given/when expressions in Perl? I can think of a couple alternatives, but none is very appealing. Do you a have better one?&lt;br /&gt;&lt;pre&gt;my @store = (&lt;br /&gt;    {store_name=&gt;'Los Angeles', sales=&gt;100_000},&lt;br /&gt;    {store_name=&gt;'San Diego', sales=&gt;100_000},&lt;br /&gt;    {store_name=&gt;'Anaheim', sales=&gt;100_000}&lt;br /&gt;);&lt;/pre&gt;&lt;br /&gt;1. do {} + if/elsif (con: needs do{}, needs explicit assignment to $_, no implicit smart matching)&lt;br /&gt;&lt;pre&gt;for my $s (@store) {&lt;br /&gt;    printf "%s %d %d\n", $s-&gt;{store_name}, $s-&gt;{sales}, do {&lt;br /&gt;        local $_ = $s-&gt;{store_name};&lt;br /&gt;        if (/Angel/) { $s-&gt;{sales}*2 }&lt;br /&gt;        elsif ($_ eq 'San Diego') { $s-&gt;{sales}*1.5 }&lt;br /&gt;        else { $s-&gt;{sales} }&lt;br /&gt;    };&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;2. do {} + given/when (con: needs do{}, needs $tmp assignments)&lt;br /&gt;&lt;pre&gt;for my $s (@store) {&lt;br /&gt;    printf "%s %d %d\n", $s-&gt;{store_name}, $s-&gt;{sales}, do {&lt;br /&gt;        my $tmp;&lt;br /&gt;        given($s-&gt;{store_name}) {&lt;br /&gt;            when (/Angel/) { $tmp = $s-&gt;{sales}*2 }&lt;br /&gt;            when ('San Diego') { $tmp = $s-&gt;{sales}*1.5 }&lt;br /&gt;            default { $tmp = $s-&gt;{sales} }&lt;br /&gt;        }&lt;br /&gt;        $tmp&lt;br /&gt;    };&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;3. sub {} + given/when (con: needs sub{}, slower perhaps?, needs explicit return's)&lt;br /&gt;&lt;pre&gt;for my $s (@store) {&lt;br /&gt;    printf "%s %d %d\n", $s-&gt;{store_name}, $s-&gt;{sales}, sub {&lt;br /&gt;        given ($s-&gt;{store_name}) {&lt;br /&gt;            when (/Angel/) { return $s-&gt;{sales}*2 }&lt;br /&gt;            when ('San Diego') { return $s-&gt;{sales}*1.5 }&lt;br /&gt;            default { return $s-&gt;{sales} }&lt;br /&gt;        }&lt;br /&gt;    }-&gt;();&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1592341674024609833?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1592341674024609833/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/givenwhen-expression.html#comment-form' title='7 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1592341674024609833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1592341674024609833'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/givenwhen-expression.html' title='Given/when expression'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5586533081066275976</id><published>2009-12-20T21:27:00.000-08:00</published><updated>2009-12-21T02:04:11.484-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Kalender adven Perl 6, RSS di HP</title><content type='html'>Blog apa yang paling menarik dibaca tahun 2009 ini? Tak diragukan lagi, Perl 6 Advent Calendar, http://perl6advent.wordpress.com/ . Selama sebulan menjelang Natal, Anda akan disuguhi artikel-artikel menarik bergaya bahasa santai yang masing-masing mengulas satu fitur baru/keren dari Perl 6. Saat ini sudah ada 20-an artikel yang diterbitkan. Masih ada beberapa hari lagi tersisa, jangan lewatkan!&lt;br /&gt;&lt;br /&gt;Betewe, sejak taun ini ikut-ikutan beli hape kuerti yang bisa internetan, walau gak ikut-ikutan fesbukan, saya menemukan kegiatan yang mengasyikkan: membaca RSS di hape dengan Google Reader. Terasa sekali, perusahaan yang paling gets it, paling memperhatikan usability mobile browsing tak lain tak bukan adalah Google. Dan juga Facebook mungkin (tapi saya jarang pakai). Karena itu gak sabar rasanya menanti ponsel dan netbuk besutan Google tahun depan.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5586533081066275976?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5586533081066275976/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/kalender-adven-perl-6-rss-di-hp.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5586533081066275976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5586533081066275976'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/kalender-adven-perl-6-rss-di-hp.html' title='Kalender adven Perl 6, RSS di HP'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5506427486160591092</id><published>2009-12-16T08:34:00.000-08:00</published><updated>2009-12-16T09:24:01.636-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Storable, Regexp, bugs, bugs, bugs</title><content type='html'>A few hours spent yesterday trying to find out why some of my tests keep failing under certain conditions. Turns out I did a Storable::dclone() on an object, and that object contains a regular&lt;br /&gt;expression. And Storable Don't Do No Regex. Worse is, Storable doesn't complain but will just freeze/thaw the regexes into garbage.&lt;br /&gt;&lt;pre&gt;$ perl -MStorable=dclone -MData::Dumper -e'&lt;br /&gt;    print "Storable version = $Storable::VERSION\n";&lt;br /&gt;    $re = qr/abc/;&lt;br /&gt;    print Dumper $re;&lt;br /&gt;    print Dumper dclone $re;'&lt;br /&gt;Storable version = 2.21&lt;br /&gt;$VAR1 = qr/(?-xism:abc)/;&lt;br /&gt;$VAR1 = bless( do{\(my $o = undef)}, 'Regexp' );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This means:&lt;br /&gt;&lt;pre&gt;$ perl -MStorable=freeze -E'say "yikes" if freeze(qr/a/) eq freeze(qr/b/)'&lt;br /&gt;yikes&lt;/pre&gt;&lt;br /&gt;Since regexes are so common in Perl, maybe some warnings in Storable documentation should be in order? I'm sure many more bums are in line waiting to be bitten by this. (Bug report &lt;a href="https://rt.cpan.org/Ticket/Display.html?id=52835"&gt;filed&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;There is &lt;a href="http://search.cpan.org/dist/Regexp-Copy/"&gt;Regexp::Copy&lt;/a&gt; which contains Regexp::Storable, which is supposed to add regexp (de)serialization to Storable, but turns out that it still has bugs. Even this very simple case will yield a wrong answer:&lt;br /&gt;&lt;pre&gt;$ perl -MData::Dumper -MStorable=dclone -MRegexp::Copy -E'say "Regexp::Copy version = $Regexp::Copy::VERSION"; say Dumper dclone([qr/a/, qr/b/])'&lt;br /&gt;Regexp::Copy version = 0.06&lt;br /&gt;$VAR1 = [&lt;br /&gt;          qr/(?-xism:b)/,&lt;br /&gt;          qr/(?-xism:b)/&lt;br /&gt;        ];&lt;/pre&gt;&lt;br /&gt;(Btw, if you "use Regexp::Copy" before/without "use Storable", it will also result in an error. So that's couple of bug reports &lt;a href="https://rt.cpan.org/Ticket/Display.html?id=52833"&gt;filed&lt;/a&gt; &lt;a href="https://rt.cpan.org/Ticket/Display.html?id=52834"&gt;in&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Sadly it's unclear whether these will be fixed soon. The bug queues for Storable and Regexp::Copy contains unresolved entries several years old.&lt;br /&gt;&lt;br /&gt;I first tried to switch to &lt;a href="http://search.cpan.org/dist/Data-Compare/"&gt;Data::Compare&lt;/a&gt; (as actually I was just comparing data structure freeze()'s for comparison, as well as some cloning). But turns out that Data::Compare doesn't deal with recursive/circular structure yet (&lt;a href="https://rt.cpan.org/Ticket/Display.html?id=52836"&gt;bug filed&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Finally I resorted to using the good ol' &lt;a href="http://search.cpan.org/dist/Data-Dumper/"&gt;Data::Dumper&lt;/a&gt; for serializing/comparison part, and &lt;a href="http://search.cpan.org/dist/Clone/"&gt;Clone&lt;/a&gt; for the cloning part.&lt;br /&gt;&lt;br /&gt;Is it just me (I hope it's just me) or do other people find serializing/deserializing modules in CPAN tend to be more buggy than, say, Ruby ones? I've never *once* encountered a problem with Ruby's yaml module, yet aside from Storable and Regexp case above, I have also been bitten several times by bugs in YAML.pm, YAML::Syck, and YAML::XS. The last one is &lt;a href="https://rt.cpan.org/Ticket/Display.html?id=52837"&gt;this&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And with a couple of bugs in my own code unrelated to all the above, that makes the most number of bugs found/reported between yesterday and today. Not bad after all, but still I'm worried.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5506427486160591092?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5506427486160591092/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/storable-regexp-bugs-bugs-bugs.html#comment-form' title='5 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5506427486160591092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5506427486160591092'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/storable-regexp-bugs-bugs-bugs.html' title='Storable, Regexp, bugs, bugs, bugs'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-6116472486725146528</id><published>2009-12-16T03:31:00.000-08:00</published><updated>2009-12-16T03:32:36.276-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Arti sebuah nama</title><content type='html'>“What’s in a name?” Apalah arti sebuah nama, begitu tulis Shakespeare. “That which we call a rose. By any other name would smell as sweet.” Atau diterjemahkan, terasi dibilang mawar pun tetap bau.&lt;br /&gt;&lt;br /&gt;Tentu saja, dalam kenyataan, sebuah nama biasanya mengandung banyak arti, karena kita memberi nama tidak secara acak melainkan disertai asosiasi, maksud, ekspresi, atau harapan tertentu. Saya ingat saat sebuah serial drama Jepang 1980-an beken di Indonesia, dari anak kenalan sampai anjing tetangga diberi nama Oshin. Jiwa setiap zaman dan budaya terjejak dalam nama-nama yang diberikan pada era/kultur tersebut. Masa revolusi dan perjuangan China dulu banyak bayi lelaki diberi nama Jian Guo (bangun negara) atau Guo Qing (hari kemerdekaan). Di Internet, muncul situs-situs bernama aneh seperti digg, reddit, twitter, semuanya karena ingin nama yang pendek di tengah kelangkaan domain .com.&lt;br /&gt;&lt;br /&gt;Baru-baru ini saya menulis 2 buah modul kecil dalam bahasa pemrograman Perl, yang satu untuk menebak gender nama orang berdasarkan nama depan (menurut statistik dan sejumlah aturan heuristik), dan yang satu lagi untuk mengurai sebuah nama menjadi komponen-komponennya. Pada waktu Anda membaca tulisan ini, kemungkinan kedua modul tersebut sudah bertengger di situs repositori Perl CPAN.&lt;br /&gt;&lt;br /&gt;Berbeda dengan beberapa modul serupa yang sudah ditulis untuk bahasa lain seperti Inggris yang hanya berkutat soal penebakan gender, modul pengurai nama Indonesia ini saya lengkapi dengan rutin untuk mengekstrak segala macam aspek yang memang terindikasi dalam nama. Termasuk agama (dari keberadaan titel seperti Haji/Hj, nama depan seperti Muhammad/Muh, atau singkatan nama baptis seperti FX), suku/etnik (dari pola penamaan tertentu misalnya di Bali dengan nama-nama seperti I Gusti Agung atau Ni Made, di Jawa dengan Raden, atau dari nama depan/marga yang amat khas seperti Liem untuk etnik China, Siregar untuk Batak, dll), hingga profesi/tingkat pendidikan (dari titel akademik). Sudah sangat “SARA” bukan? Tapi apa yang sebetulnya dimaksud dengan isu SARA?&lt;br /&gt;&lt;br /&gt;Modul penebak gender biasanya digunakan untuk memberi kata sapaan yang cocok (bisa Bapak atau Ibu) saat menulis surat/email, karena ada studi yang mengatakan bahwa penyebutan kata sapaan yang salah dapat mengurangi efektivitas/tingkat respon/dsb (selain tentunya menyinggung perasaan!). Namun modul pengurai nama saya ini, termasuk alat bantu lain seperti perangkat lunak pendeteksi ras dalam foto wajah, dapat membantu proses diskriminasi lebih lanjut. Bayangkan proses penyaringan mahasiswa/karyawan/pejabat yang kini dapat lebih praktis dalam membuang calon tak diinginkan dari ras, suku, agama/keyakinan tertentu.&lt;br /&gt;&lt;br /&gt;Saya sempat ragu sesaat untuk tidak jadi merilis modul ini, namun berdasarkan pertimbangan-pertimbangan di bawah, akhirnya saya berkeputusan untuk tetap merilisnya.&lt;br /&gt;&lt;br /&gt;Pertama, perangkat lunak semacam ini tidak membuat jadi mungkin diskriminasi yang sebelumnya tidak dimungkinkan. Maksudnya adalah, semua informasi untuk diskriminasi seperti agama, suku, gender, dsb tersebut sebetulnya sudah terkandung di dalam nama itu sendiri. Perangkat lunak hanya merupakan enkoding informasi ini dalam bentuk instruksi komputer. Entah karena kebanggaan, kebiasaan, atau untuk meneruskan garis keturunan, orang tetap mencantumkan berbagai elemen indikator ke dalam nama mereka, walaupun konsekuensinya mempermudah dirinya didiskriminasi berdasarkan nama.&lt;br /&gt;&lt;br /&gt;Kedua, argumen “pedang bermata dua”. Sama seperti senjata pisau atau senapan yang bisa digunakan untuk membunuh maupun menyelamatkan, memulai atau menghentikan perang, demikian juga perangkat lunak dapat dipakai oleh polisi untuk melakukan racial profiling ataupun bagi para organisasi untuk melaksanakan affirmative action. Keberadaan perangkat lunak itu sendiri tidak mengubah kecenderungan ke arah salah satu.&lt;br /&gt;&lt;br /&gt;Ketiga, dalam kaitannya dengan SARA, UU ITE di Bab tentang perbuatan yang dilarang menyebutkan bahwa hanya informasi yang ditujukan untuk menimbulkan kebencian atau permusuhan antarindividu/antargolonganlah yang termasuk dilarang disebarkan. Perangkat lunak pengurai (parser) sama sekali tidak dibibiti informasi kebencian/permusuhan.&lt;br /&gt;&lt;br /&gt;Bagaimana menurut pandangan para pembaca? Saya menanti masukan dari Anda semua. Apakah merilis perangkat lunak untuk menguraikan (parsing) nama orang dengan tujuan mengetahui gender, agama, suku, golongan, termasuk ke dalam tindakan terlarang? (PCMedia Edisi Jan 2010)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-6116472486725146528?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/6116472486725146528/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/arti-sebuah-nama.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6116472486725146528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/6116472486725146528'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/arti-sebuah-nama.html' title='Arti sebuah nama'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3624064545743250851</id><published>2009-12-07T21:10:00.000-08:00</published><updated>2009-12-08T03:43:30.699-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Variabel state di Perl 5.10</title><content type='html'>Bahasa Perl termasuk memberi banyak pilihan skop variabel bagi programer. Pertama, ada variabel global (tepatnya variabel package, karena sebetulnya tidak ada variabel global di Perl; ck ck ck di awal artikel sudah berbohong? :-)&lt;br /&gt;&lt;br /&gt;Kedua, yang mungkin paling sering kita pakai, variabel leksikal alias variabel privat yang dideklarasikan dengan my() yang hanya bisa dilihat/diakses oleh blok atau file atau eval tempat si variabel dideklarasi.&lt;br /&gt;&lt;br /&gt;Ketiga, variabel lokal untuk dynamic scoping, menggunakan kata kunci local(), biasanya kita pakai untuk menyimpan/mem-backup sebuah variabel, lalu mengubahnya di dalam sebuah blok, dan nanti otomatis saat kita keluar dari blok tersebut nilai si variabel akan terpulihkan kembali. Kita bisa melokalkan variabel package, filehandle, glob, dsb. Bahkan kita bisa melakukan hal seperti ini:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$config = { foo=&gt;'ujan', bar=&gt;'kemarau' };&lt;br /&gt;...&lt;br /&gt;{&lt;br /&gt;    local $config-&gt;{foo} = 'blah';&lt;br /&gt;    sini();&lt;br /&gt;    sana();&lt;br /&gt;}&lt;br /&gt;print $config-&gt;{foo}; # 'ujan' lagi&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Pada contoh di atas, kita melokalkan satu pair dari hash saja. Saat masuk ke sini() dan sana(), nilai lokal $config-&gt;{foo} akan &lt;i&gt;terus dipertahankan&lt;/i&gt;. Inilah yang dimaksud dynamic scoping, jadi tidak berbasis pada source code melainkan pada alur running program. Setelah blok selesai, barulah nilai lama $config-&gt;{foo} pulih. Asyik kan?&lt;br /&gt;&lt;br /&gt;Keempat, ada lagi yang namanya our(), mulai diperkenalkan sejak Perl 5.6. Ini pada dasarnya adalah pengganti untuk "use vars qw($foo)". our() membuat alias leksikal untuk sebuah variabel global, eh, variabel package. Tentu saja variabel tersebut nanti bisa diakses dari package lain.&lt;br /&gt;&lt;br /&gt;Kelima, yang menjadi topik posting blog ini, yaitu variabel state. Variabel ini diperkenalkan sejak Perl 5.9.sekian dan resmi menjadi bagian fitur baru dari 5.10. Untuk menggunakannya, di awal skrip kita harus melakukan:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;use feature 'state';&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;atau:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;use feature ':5.10'; # jangan lupa kutipnya ya...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Kegunaan variabel state adalah untuk membuat variabel leksikal yang persisten. Sebelumnya hal ini memang bisa dilakukan menggunakan closure, tapi terus terang saya malas menghafalnya. Setelah ada state(), barulah jadi lebih termotivasi untuk menggunakan leksikal persisten.&lt;br /&gt;&lt;br /&gt;Akhir-akhir ini saya sering membuat metode yang mengembalikan nilai konstan/statik, contohnya:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sub config_vars {&lt;br /&gt;    [qw/&lt;br /&gt;     recurse_hash&lt;br /&gt;     recurse_array&lt;br /&gt;     parse_prefix&lt;br /&gt;     ...&lt;br /&gt;    /]&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Kenapa tidak pakai variabel biasa saja (mis menggunakan our())? Tujuannya sih agar bisa memanfaatkan inheritance.&lt;br /&gt;&lt;br /&gt;Tapi, tahukah Anda, bahwa setiap kali dipanggil, si metode tersebut akan membuat arrayref baru? Buktinya:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -le'sub f { [1,2,3,4,5,6,7,8,9,10] } print f for 1..5'&lt;br /&gt;ARRAY(0x9d1c40)&lt;br /&gt;ARRAY(0xa083c8)&lt;br /&gt;ARRAY(0xa083b0)&lt;br /&gt;ARRAY(0xa08398)&lt;br /&gt;ARRAY(0xa08380)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Pemborosan bukan? Nah, solusinya kita bisa menggunakan variabel state:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;sub config_vars {&lt;br /&gt;    state $a = [qw/&lt;br /&gt;     recurse_hash&lt;br /&gt;     recurse_array&lt;br /&gt;     parse_prefix&lt;br /&gt;     ...&lt;br /&gt;    /];&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Variabel $a ini akan hidup terus walaupun sudah keluar dari skop (tentu saja, pada ujungnya nanti akan di-garbage collect kalau memang tidak ada yang memakai lagi).&lt;br /&gt;&lt;br /&gt;Kini:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -lE'sub f { state $f = [1,2,3,4,5,6,7,8,9,10] } print f for 1..5'&lt;br /&gt;ARRAY(0x12ffc40)&lt;br /&gt;ARRAY(0x12ffc40)&lt;br /&gt;ARRAY(0x12ffc40)&lt;br /&gt;ARRAY(0x12ffc40)&lt;br /&gt;ARRAY(0x12ffc40)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Oya, -E sama seperti -e tapi menghidupkan semua fitur Perl terbaru (dalam kasus ini, ekivalen dengan "use feature ':5.10'").&lt;br /&gt;&lt;br /&gt;Selamat bermain dengan variabel di Perl!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3624064545743250851?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3624064545743250851/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/variabel-state.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3624064545743250851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3624064545743250851'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/variabel-state.html' title='Variabel state di Perl 5.10'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2712524899495690094</id><published>2009-12-02T19:44:00.000-08:00</published><updated>2009-12-02T20:15:51.855-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Requiring 5.10</title><content type='html'>So I decided to add "perl = 5.010000" in some of my dist.ini's. This is just because of one particular habit I recently acquired: writing "$a //= 1" and "$b = $a // 2". (Well actually I've rejoiced since defined-or is announced for 5.10, but for some reason have only begun to really use it in the past weeks.)&lt;br /&gt;&lt;br /&gt;So much nicer than writing "$a = 1 unless defined($a)" and "$b = defined($a) ? $a : $2". It's the having to repeat myself aspect which I find disgusting, especially if $a is an expression. Which is one of the reason I always hate coding in PHP because in PHP you can't even say "$b = $a || 2".&lt;br /&gt;&lt;br /&gt;I'm not switching, state-ing, say-ing, doing recursive patterns, or any of the other cool stuffs in 5.10. So am I so selfish for forcing 5.10 down the throats of other people just for such a minor convenience? The word externality comes to mind (having completed reading &lt;a href="http://www.google.co.id/search?q=superfreakonomics"&gt;Superfreakonomics&lt;/a&gt; 2 days ago). &lt;br /&gt;&lt;br /&gt;But it's a &lt;span style="font-style:italic;"&gt;positive&lt;/span&gt; externality, really. ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2712524899495690094?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2712524899495690094/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/requiring-510.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2712524899495690094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2712524899495690094'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/requiring-510.html' title='Requiring 5.10'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7398636176031035839</id><published>2009-12-01T04:15:00.000-08:00</published><updated>2009-12-01T04:31:41.628-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>minicpan</title><content type='html'>Last weekend I got a new toy: Asus EEE PC S101. This is actually my second netbook (and fourth laptop overall). I sort of dumped my first netbook only after a month of use because I now totally hate hard drives on netbooks: they're hot, they're loud, they're a power drain.&lt;br /&gt;&lt;br /&gt;The EEE has a SSD drive, but at only 32GB, putting the whole CPAN (currently at 6.9GB) on it is a bit taxing. With the help of &lt;a href="http://search.cpan.org/dist/CPAN-Mini/"&gt;minicpan&lt;/a&gt;, I got it down to only 1.2GB. So thanks again Ricardo!&lt;br /&gt;&lt;br /&gt;Then I immediately wondered how big &lt;a href="http://backpan.perl.org"&gt;BackPAN&lt;/a&gt; is, guessing it might be between 30-100GB (with 14 years of CPAN's history and all). But then:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ perl -MParse::BACKPAN::Packages -e'$p = Parse::BACKPAN::Packages-&gt;new(); printf "BACKPAN is %.1fGB\n", $p-&gt;size/1024/1024/1024'&lt;br /&gt;BACKPAN is 12.4GB&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Much smaller than I had thought. It's just about twice the current size of CPAN. Which probably means that a lot of CPAN authors still leave much of their stuffs around and not delete them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7398636176031035839?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7398636176031035839/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/12/minicpan.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7398636176031035839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7398636176031035839'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/12/minicpan.html' title='minicpan'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-900136931540026685</id><published>2009-11-26T23:07:00.000-08:00</published><updated>2009-11-27T04:26:13.260-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>More flexible configuration merging with Data::PrefixMerge</title><content type='html'>(I'm planning a refactoring for &lt;a href=http://search.cpan.org/dist/Data-PrefixMerge/&gt;Data::PrefixMerge&lt;/a&gt; and will be renaming it to Data::ModeMerge. Thought I'd post something on the blog.)&lt;br /&gt;&lt;br /&gt;In a typical Unix program, there are three levels of configuration: system-wide config file (/etc/myapp.conf), per-user config file (~/.myapprc), and command-line options. It's convenient programatically to load each of those in a hash and then merge (e.g. using &lt;a href=http://search.cpan.org/dist/Data-Utilities/&gt;Data::Merger&lt;/a&gt; or &lt;a href=http://search.cpan.org/dist/Hash-Merge/&gt;Hash::Merge&lt;/a&gt;) system-wide hash with the per-user hash, and then merge again the result with the command-line hash to get the a single hash as the final configuration. Your program can from there on deal with this just one hash instead of three.&lt;br /&gt;&lt;br /&gt;In a typical merging process between two hashes (left-side and right-side), when there is a conflicting key, then the right-side key will override the left-side. This is usually the desired behaviour in our said program as the system-wide config is there to provide defaults, and the per-user config (and the command-line arguments) allow a user to override those defaults.&lt;br /&gt;&lt;br /&gt;But suppose that the user wants to &lt;i&gt;unset&lt;/i&gt; a certain configuration setting that is defined by the system-wide config? She can't do that unless she edits the system-wide config (in which she might need admin rights), or the program allows the user to disregard the system-wide config. The latter is usually what's implemented by many Unix programs, e.g. the &lt;code&gt;-noconfig&lt;/code&gt; command-line option in &lt;code&gt;mplayer&lt;/code&gt;. But this has two drawbacks:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;a slightly added complexity in the program. The program needs to provide a special, extra comand-line option.&lt;br /&gt;&lt;li&gt;the user loses all the default settings in the system-wide config. What she needed in the first place was to just unset &lt;i&gt;a single setting&lt;/i&gt; (a single key-value pair of the hash).&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Here's where Data::PrefixMerge comes in. It provides a so-called &lt;b&gt;DELETE mode&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;prefix_merge({foo=&gt;1, bar=&gt;2}, {"!foo"=&gt;undef, bar=&gt;3, baz=&gt;1});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;will result ini:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;{bar=&gt;3, baz=&gt;1}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;!&lt;/code&gt; prefix tells Data::ModeMerge to do a DELETE mode merging. So the final result will lack the &lt;code&gt;foo&lt;/code&gt; key.&lt;br /&gt;&lt;br /&gt;On the other hand, what if the system admin wants to &lt;i&gt;protect&lt;/i&gt; a certain configuration setting from being overriden by the user or the command-line? This is useful in a hosting or other retrictive environment where we want to limit users' freedom to some degree. This is possible via the &lt;b&gt;KEEP mode&lt;/b&gt; (prefix &lt;code&gt;^&lt;/code&gt;):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;prefix_merge({"^bar"=&gt;2, "^baz"=&gt;1}, {bar=&gt;3, "!baz"=&gt;0, quux=&gt;7});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;will result in:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;{bar=&gt;2, baz=&gt;1, quux=&gt;7}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;effectively protecting &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; from being overriden/deleted/etc.&lt;br /&gt;&lt;br /&gt;Aside from the two mentioned modes, there are also a few others available by default: ADD (prefix &lt;code&gt;+&lt;/code&gt;), CONCAT (prefix &lt;code&gt;.&lt;/code&gt;), SUBTRACT (prefix &lt;code&gt;-&lt;/code&gt;), as well as the plain ol' NORMAL/override (optional prefix &lt;code&gt;*&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;You can add other modes by writing a mode handler module. (planned in upcoming Data::ModeMerge release)&lt;br /&gt;&lt;br /&gt;You can change the default prefixes for each mode if you want. You can disable each mode individually. (planned in upcoming Data::ModeMerge release)&lt;br /&gt;&lt;br /&gt;You can default to always using a certain mode, like the NORMAL mode, and ignore all the prefixes, in which case Data::ModeMerge will behave like most other merge modules.&lt;br /&gt;&lt;br /&gt;You can change default mode, prefixes, disabling/enabling mode, etc on a per-hash basis using the so-called &lt;b&gt;options key&lt;/b&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-900136931540026685?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/900136931540026685/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/more-flexible-configuration-merging.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/900136931540026685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/900136931540026685'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/more-flexible-configuration-merging.html' title='More flexible configuration merging with Data::PrefixMerge'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7511785430379354030</id><published>2009-11-24T07:39:00.001-08:00</published><updated>2009-11-24T08:05:49.837-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>WEHT Emperl?</title><content type='html'>Speaking of templating systems in the previous post, I also got reminded of &lt;a href="http://search.cpan.org/dist/Embperl/"&gt;Embperl&lt;/a&gt;, and wondered why it didn't get more popular. I remember back in 1998-1999 enjoying working with Embperl before moving on to Mason. It has a nice syntax, and one very nice feature: (HTML- and/or URL-)escaping output &lt;i&gt;by default&lt;/i&gt;. Say you have in $foo "&amp;lt;script&amp;gt;evil()&amp;lt;/script&amp;gt;" then this template:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;[+ $foo +]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;will output "&amp;amp;lt;script&amp;amp;gt;evil()&amp;amp;lt;/script&amp;amp;gt;". You are protected from XSS by default. And if you want to turn off this escaping, you can set EMBPERL_ESCMODE to 0, or, do this:&lt;br /&gt;&lt;br /&gt; &lt;code&gt;[+ do { local $escmode = 0; $foo } +]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But then maybe this is akin to what earlier versions of PHP attempted to do with default magic_quotes_gpc and magic_quotes_runtime set to on. These two default configuration have helped spread the backslashitis/toothpick syndrome all over the web and are currently deprecated (and will be removed in PHP 6.0). A majority of PHP programmers apparently never understood the need of these escaping, and got confused/mad by the insistence of PHP to add those pestering backslashes. And most would turn off the configuration, or add a routine to reverse the escaping at the beginning of their programs.&lt;br /&gt;&lt;br /&gt;So is the moral of the story: do not overprotect programmers (especially ignorant ones)? Or don't try to fix the problem the wrong way? Or both?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7511785430379354030?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7511785430379354030/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/weht-emperl.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7511785430379354030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7511785430379354030'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/weht-emperl.html' title='WEHT Emperl?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5189826719844655971</id><published>2009-11-24T06:12:00.000-08:00</published><updated>2009-11-24T08:07:55.201-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl program that generates... Perl programs</title><content type='html'>&lt;a href="http://search.cpan.org/dist/Data-Schema/"&gt;Data::Schema&lt;/a&gt; is a module that I wrote to do data structure validation (using another data structure acting as a schema). I had not been terribly happy with the validation speed, ranging in about 100 validations/sec for schemas that are only barely complex. This is not bad, actually, because &lt;a href="http://search.cpan.org/dist/Data-FormValidator/"&gt;Data::FormValidator&lt;/a&gt; also performs more or less the same. But that was below expectation.&lt;br /&gt;&lt;br /&gt;Last week I suddenly realized, writing data validator or a templating system is essentially writing a [mini] language, with our schema/template as the miniprogram and our [Perl] program as the &lt;span style="font-style:italic;"&gt;interpreter&lt;/span&gt;. To make our miniprogram faster, we can &lt;span style="font-style:italic;"&gt;compile&lt;/span&gt; it into Perl.&lt;br /&gt;&lt;br /&gt;FastTemplate from PHP quickly comes to mind. I remember that it was advertised as being fast because it converts the template into PHP code (e.g. into a bunch of echo's, if/else's, and for loops). And I think there must be at least half a dozen Perl-based template languages on CPAN doing the same. Although I'm not sure about how common data validators compile schemas into Perl code.&lt;br /&gt;&lt;br /&gt;So anyway, starting from 0.12, Data::Schema can convert schema into Perl subroutines and use it to validate data structures. Validation speed jumps about one order of magnitude faster, and I'm a happy guy again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5189826719844655971?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5189826719844655971/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/perl-program-that-generates-perl.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5189826719844655971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5189826719844655971'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/perl-program-that-generates-perl.html' title='Perl program that generates... Perl programs'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1109396529198477801</id><published>2009-11-17T18:16:00.000-08:00</published><updated>2009-11-17T18:43:09.714-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Who's using your module?</title><content type='html'>To see who on CPAN are using your module (distribution), go to this page: &lt;code&gt;http://cpants.perl.org/dist/used_by/&lt;i&gt;Your-DistName&lt;/i&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So I casually entered my distributions, being happily surprised that there &lt;i&gt;are&lt;/i&gt; people using them.&lt;br /&gt;&lt;br /&gt;If you're like me, and I'm sure thousands of other CPAN authors, you're putting stuffs on CPAN either for fun, or for your own use. Knowing other people are using your module gives you some perspective. I was happily breaking/removing/refactoring stuffs as I please, but now I'll need to think twice everytime.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1109396529198477801?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1109396529198477801/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/whos-using-your-module.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1109396529198477801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1109396529198477801'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/whos-using-your-module.html' title='Who&apos;s using your module?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1001950722580500441</id><published>2009-11-17T02:59:00.000-08:00</published><updated>2009-11-17T03:06:11.376-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Merge key support in YAML</title><content type='html'>None of the many Perl YAML modules support &lt;a href="http://yaml.org/type/merge.html"&gt;merge key&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ cat merge.yaml&lt;br /&gt;foo: 1&lt;br /&gt;bar: 2        &lt;br /&gt;&lt;&lt;:&lt;br /&gt;  baz: 3      &lt;br /&gt;&lt;br /&gt;$ perl -MYAML::Tiny -MFile::Slurp -e'print Dump Load(scalar read_file "merge.yaml")'&lt;br /&gt;---                                                                                               &lt;br /&gt;&lt;&lt;:             &lt;br /&gt;  baz: 3      &lt;br /&gt;bar: 2        &lt;br /&gt;foo: 1&lt;br /&gt;&lt;br /&gt;$ perl -MYAML -MFile::Slurp -e'print Dump Load(scalar read_file "merge.yaml")'&lt;br /&gt;---&lt;br /&gt;&lt;&lt;:&lt;br /&gt;  baz: 3&lt;br /&gt;bar: 2&lt;br /&gt;foo: 1&lt;br /&gt;&lt;br /&gt;$ perl -MYAML::Syck -MFile::Slurp -e'print Dump Load(scalar read_file "merge.yaml")'&lt;br /&gt;---&lt;br /&gt;&lt;&lt;:&lt;br /&gt;  baz: 3&lt;br /&gt;bar: 2&lt;br /&gt;foo: 1&lt;br /&gt;&lt;br /&gt;$ perl -MYAML::XS -MFile::Slurp -e'print Dump Load(scalar read_file "merge.yaml")'&lt;br /&gt;---&lt;br /&gt;&lt;&lt;:&lt;br /&gt;  baz: 3&lt;br /&gt;bar: 2&lt;br /&gt;foo: 1&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, good ol' Ruby handles it just fine:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ ruby -ryaml -e'print YAML::load(File.open("merge.yaml").read).to_yaml'&lt;br /&gt;---&lt;br /&gt;baz: 3&lt;br /&gt;foo: 1&lt;br /&gt;bar: 2&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Kinda strange since Ruby's &lt;code&gt;yaml&lt;/code&gt; and YAML::Syck both use &lt;a href="http://yaml.kwiki.org/index.cgi?LibSyck"&gt;why's syck library&lt;/a&gt;, which has not been updated for quite a while.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1001950722580500441?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1001950722580500441/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/merge-key-support-in-yaml.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1001950722580500441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1001950722580500441'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/merge-key-support-in-yaml.html' title='Merge key support in YAML'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4716282789544457629</id><published>2009-11-10T19:07:00.000-08:00</published><updated>2009-11-17T02:33:14.569-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Dist::Zilla for Module::Starter Users: A 2-Minute Guide</title><content type='html'>So you're a module author. You typically do this when starting a new distribution:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ module-starter --module=Foo::Bar --author="Your Name" --email="you@example.com"&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and then hack away under the resulting &lt;code&gt;Foo-Bar&lt;/code&gt; directory. Easy enough right?&lt;br /&gt;&lt;br /&gt;Problems are:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;too much generated boilerplate code and text;&lt;br /&gt;&lt;li&gt;lack of automation for the building and release process.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I'm sure you have experienced one or more of these:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Having to search+replace copyright year in &lt;i&gt;every&lt;/i&gt; file;&lt;br /&gt;&lt;li&gt;Forgetting to "make clean" or remove backup files before creating tarball;&lt;br /&gt;&lt;li&gt;Forgetting to update MANIFEST;&lt;br /&gt;&lt;li&gt;Feeling tired and bored of all the tedious and laborious tasks;&lt;br /&gt;&lt;li&gt;Wondering if there is a better way.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;You need a &lt;b&gt;distribution builder&lt;/b&gt; like &lt;a href="http://search.cpan.org/dist/Dist-Zilla/"&gt;Dist::Zilla&lt;/a&gt;. It helps:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;eliminate a lot of duplicate text;&lt;br /&gt;&lt;li&gt;automate updating MANIFEST;&lt;br /&gt;&lt;li&gt;automate generating README;&lt;br /&gt;&lt;li&gt;build tarball;&lt;br /&gt;&lt;li&gt;automate a lot of other stuffs;&lt;br /&gt;&lt;li&gt;upload to CPAN;&lt;br /&gt;&lt;li&gt;and more.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Dist::Zilla is flexible and has a lot of plugin/plugin bundles, but it can be less straightforward to use it. Here's a simple step-by-step guide you can follow.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Install these modules from CPAN:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Dist::Zilla&lt;br /&gt;&lt;li&gt;Dist::Zilla::Plugin::PodWeaver&lt;br /&gt;&lt;li&gt;Dist::Zilla::Plugin::ReadmeFromPod&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Create ~/.dzil/config.ini, containing:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;[!new]&lt;br /&gt;author = Your Name &lt;you@example.com&gt;&lt;br /&gt;copyright_holder = Your Name&lt;br /&gt;initial_version = 0.01&lt;br /&gt;&lt;br /&gt;[!release]&lt;br /&gt;user     = YOUR-PAUSE-ID&lt;br /&gt;password = YOUR-PAUSE-PASSWORD&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Now, instead of using &lt;code&gt;module-starter&lt;/code&gt;, you run &lt;code&gt;dzil new&lt;/code&gt; to start your new distribution:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ dzil new Foo-Bar&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Instead of a bunch of files under &lt;code&gt;Foo-Bar/&lt;/code&gt;, there's now just one file,  &lt;code&gt;dist.ini&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;name    = Foo-Bar&lt;br /&gt;version = 0.01&lt;br /&gt;author  = youruser&lt;br /&gt;license = Perl_5&lt;br /&gt;copyright_holder = youruser&lt;br /&gt;&lt;br /&gt;[@Classic]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;There's currently a small bug in Dist::Zilla not supplying the correct author/copyright_holder, so edit &lt;code&gt;dist.ini&lt;/code&gt;, as well as for adding some lines:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;name    = Foo-Bar&lt;br /&gt;version = 0.01&lt;br /&gt;author  = &lt;b&gt;Your Name &amp;lt;you@example.com&amp;gt;&lt;/b&gt;&lt;br /&gt;license = Perl_5&lt;br /&gt;copyright_holder = &lt;b&gt;Your Name&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;[@Classic]&lt;br /&gt;&lt;b&gt;[PodWeaver]&lt;br /&gt;[ReadmeFromPod]&lt;/b&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Create the most basic distribution structure:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ mkdir -p lib/Foo t&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Put some test files into &lt;code&gt;t/&lt;/code&gt;. Default tests generated from &lt;code&gt;module-starter&lt;/code&gt; like &lt;code&gt;00-load.t&lt;/code&gt; might be a good start.&lt;br /&gt;&lt;br /&gt;Create &lt;code&gt;Changes&lt;/code&gt; file. You can copy paste from the one generated by &lt;code&gt;module-starter&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0.01    2009-11-11&lt;br /&gt;        First version, released on an unsuspecting world.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As for &lt;code&gt;lib/Foo/Bar.pm&lt;/code&gt;, here's what I use for template. You can just fill out the [[...]] parts:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;package Foo::Bar;&lt;br /&gt;# ABSTRACT: [[Abstract of module]]&lt;br /&gt;&lt;br /&gt;use strict;&lt;br /&gt;use warnings;&lt;br /&gt;&lt;br /&gt;[[YOUR CODE]]&lt;br /&gt;&lt;br /&gt;1;&lt;br /&gt;__END__&lt;br /&gt;=head1 SYNOPSIS&lt;br /&gt;&lt;br /&gt; [[YOUR SYNOPSIS]]&lt;br /&gt;=head1 DESCRIPTION&lt;br /&gt;&lt;br /&gt;[[YOUR DESCRIPTION]]&lt;br /&gt;&lt;br /&gt;=cut&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It's much simpler and shorter than what &lt;b&gt;module-starter&lt;/b&gt; generates. Some POD sections like VERSION, NAME, AUTHOR, LICENSE AND COPYRIGHT are deliberately omitted. They will be generated by Dist::Zilla later when building the distro.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;Hack away. Write your code in &lt;code&gt;lib/Foo/Bar.pm&lt;/code&gt;. Add some tests in &lt;code&gt;t/&lt;/code&gt;. Add other files when needed.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;To test the distribution, run &lt;code&gt;dzil test&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;To build the distribution, run &lt;code&gt;dzil build&lt;/code&gt;. This will create &lt;code&gt;Foo-Bar-0.01.tar.gz&lt;/code&gt; which contains all the necessary goodies of a standard classic distribution, like &lt;code&gt;README&lt;/code&gt;, &lt;code&gt;LICENSE&lt;/code&gt;, &lt;code&gt;MANIFEST&lt;/code&gt;, &lt;code&gt;META.yml&lt;/code&gt;, etc.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;To release the distribution, run &lt;code&gt;dzil release&lt;/code&gt;. This will upload your module to CPAN. Sweet!&lt;br /&gt;&lt;br /&gt;&lt;li&gt;To release a new distribution, just update version number in &lt;code&gt;dist.ini&lt;/code&gt; and &lt;code&gt;$VERSION&lt;/code&gt; in your main module file. Don't forget to add an entry to &lt;code&gt;Changes&lt;/code&gt;. Repeat &lt;code&gt;dzil test&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;release&lt;/code&gt;.&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;In the future "dzil new" might allow creating a more complete skeleton.&lt;br /&gt;&lt;br /&gt;There are lots of other nice things Dist::Zilla can do for you, like checking Changes file, do automatic version numbering, etc. Welcome to the nice world of Dist::Zilla!&lt;br /&gt;&lt;br /&gt;Comments/corrections are welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4716282789544457629?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4716282789544457629/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/distzilla-for-modulestarter-users-2.html#comment-form' title='7 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4716282789544457629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4716282789544457629'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/distzilla-for-modulestarter-users-2.html' title='Dist::Zilla for Module::Starter Users: A 2-Minute Guide'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-7198260299144626855</id><published>2009-11-10T03:31:00.000-08:00</published><updated>2009-11-10T04:40:49.102-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Regex Editor in Padre 0.50</title><content type='html'>Thanks to Gábor Szabó, we now have a regex editor in Padre. Yay! Sure it's really basic at the moment, but it's a start.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://padre.perlide.org/trac/wiki/Features#RegexEditor"&gt;Padre Features page&lt;/a&gt; says this about the regex editor: "A tool that allows the less experienced users as well to build and debug a regular expressions".&lt;br /&gt;&lt;br /&gt;Well, if your inspiration is &lt;a href="http://www.regexbuddy.com/screen.html"&gt;a tool to *teach* regex&lt;/a&gt;, then maybe. But in general I don't quite agree on the "less experienced users" emphasis. Regex is a minilanguage, and a featureful IDE/editor and debugger helps beginners as well as experienced users a lot. Would you say Padre is a tool for the less experienced Perl programmers? Up to a certain point, it's becoming really hard/cumbersome to debug rather long and complex regular expressions.&lt;br /&gt;&lt;br /&gt;Personally I've only used Rx Toolkit in &lt;a href="http://www.activestate.com/komodo/"&gt;Komodo&lt;/a&gt;. Its interface is simple and not as colorful as some Windows regex editors on the market, but it does the job well. If I can cite a wishlist for Rx Toolkit, it would just be to add position indicator (line number + column + offset)  in each of regex/string/matches subwindow. Being able to step regex is nice too I guess, but not essential. Usually my regexes aren't *that* long/complex.&lt;br /&gt;&lt;br /&gt;Of course the future for Padre's regex editor is to handle Perl 6 grammars, which will be a full-fledged language in itself, so there *should* be step over/trace into/watch/etc debugger features for it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-7198260299144626855?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/7198260299144626855/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/regex-editor-in-padre-050.html#comment-form' title='1 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7198260299144626855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/7198260299144626855'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/regex-editor-in-padre-050.html' title='Regex Editor in Padre 0.50'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-8956398087517444692</id><published>2009-11-03T09:10:00.000-08:00</published><updated>2009-11-03T17:43:33.164-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Creating shortcuts for long Perl module names</title><content type='html'>My main interface with the computer is the shell, the terminal, the keyboard. Thus I love shortcuts. My .bash_profile is littered with one- and two-letter shortcuts like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;alias m='mplayer -fixed-vo -osdlevel 3'&lt;br /&gt;alias mn='mplayer -fixed-vo -osdlevel 3 -nosound'&lt;br /&gt;alias m11='m -speed 1.1'&lt;br /&gt;alias m12='m -speed 1.2'&lt;br /&gt;alias m20='m -xy 2'&lt;br /&gt;alias m21='m20 -speed 1.1'&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And when aliases are not enough, because they do not work outside the shell (like in KDE's mini commander), I create scripts. My ~/bin is also littered with alias commands like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# k&lt;br /&gt;#!/bin/bash&lt;br /&gt;exec konsole "$@"&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As well as my homedir, project directories, and the whole filesystem ornamented with short symlinks to here and there.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ln -s public p&lt;br /&gt;$ ln -s proj/perl pp&lt;br /&gt;$ ln -s sites/steven.builder.localdomain/www .&lt;br /&gt;...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When I have long Perl module names like Spanel::API::Account::Shared, Spanel::API::Account::XenVPS, I would also like to create shortcuts for these.&lt;br /&gt;&lt;br /&gt;There are several modules to do this. I ended up using &lt;a href="http://search.cpan.org/dist/Package-Alias/"&gt;Package::Alias&lt;/a&gt; because I like the interface. Other ones I tried include &lt;a href="http://search.cpan.org/dist/aliased/"&gt;aliased&lt;/a&gt; and &lt;a href="http://search.cpan.org/dist/namespace-alias/"&gt;namespace::alias&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Suppose I want to create a shortcut of SAAS for Spanel::API::Account::Shared (which can export foo). All I need to do is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# in SAAS.pm&lt;br /&gt;use Spanel::API::Account::Shared;&lt;br /&gt;use Package::Alias 'SAAS'=&gt;'Spanel::API::Account::Shared';&lt;br /&gt;1;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now aside from these:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ perl -MSpanel::API::Account::Shared -e'Spanel::API::Account::Shared::foo()'&lt;br /&gt;$ perl -MSpanel::API::Account::Shared=foo -e'foo()'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All of below work too:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ perl -MSAAS -e'Spanel::API::Account::Shared::foo()'&lt;br /&gt;$ perl -MSAAS -e'SAAS::foo()'&lt;br /&gt;$ perl -MSAAS=foo -e'foo()'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My fingers thank Joshua Keros, the author of Package::Alias.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-8956398087517444692?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/8956398087517444692/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/creating-shortcuts-for-long-perl-module.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8956398087517444692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/8956398087517444692'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/creating-shortcuts-for-long-perl-module.html' title='Creating shortcuts for long Perl module names'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2575467400755249194</id><published>2009-11-03T08:53:00.000-08:00</published><updated>2009-11-03T09:08:50.047-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>The while(1) {...last...} construct</title><content type='html'>In the past year or two I've been comfortably using this construct in Perl as well as in PHP (and probably others too):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;while (1) {&lt;br /&gt;    do_stuff;&lt;br /&gt;    do_some_checks;&lt;br /&gt;    do { warn error 1; last } if not OK;&lt;br /&gt;&lt;br /&gt;    do_more_stuff;&lt;br /&gt;    do_some_checks;&lt;br /&gt;    do { warn error 2; last } if not OK;&lt;br /&gt;&lt;br /&gt;    do_even_more_stuff;&lt;br /&gt;    do_some_checks;&lt;br /&gt;    do { warn error 3; last } if not OK;&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;&lt;br /&gt;    #finally&lt;br /&gt;    last;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I prefer it over the one below:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;do_stuff;&lt;br /&gt;do_some_checks;&lt;br /&gt;if (!OK) {&lt;br /&gt;    warn error 1;&lt;br /&gt;} else {&lt;br /&gt;    do_more_stuff;&lt;br /&gt;    do_some_checks;&lt;br /&gt;    if (!OK) {&lt;br /&gt;        warn error 2;&lt;br /&gt;    } else {&lt;br /&gt;        do_even_more_stuff;&lt;br /&gt;        do_some_checks;&lt;br /&gt;        if (!OK) {&lt;br /&gt;             ...&lt;br /&gt;        }&lt;br /&gt;        # finally&lt;br /&gt;        success!&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;while (1) { ... last ... }&lt;/code&gt; style is clearer and avoids extraneous indentation. The only thing biting me in the past when using this construct is that sometimes I forgot to add the final &lt;code&gt;last&lt;/code&gt;, resulting in an infinite loop. But this series-of-checks-and-early-bail pattern happens so often in my code that the construct quickly became second nature.&lt;br /&gt;&lt;br /&gt;Anyone got the same habit, or perhaps using some alternative (like the new &lt;code&gt;given-when&lt;/code&gt;)?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2575467400755249194?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2575467400755249194/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/11/while1-last-construct.html#comment-form' title='4 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2575467400755249194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2575467400755249194'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/11/while1-last-construct.html' title='The while(1) {...last...} construct'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-3502894404539024942</id><published>2009-10-27T09:30:00.000-07:00</published><updated>2009-10-27T07:19:05.239-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Using mod_perl *aside* from deploying web apps?</title><content type='html'>History has it that &lt;a href="http://apache.perl.org/"&gt;mod_perl&lt;/a&gt; was (is?) marketed as a high performance alternative to Perl CGI, and that virtually all &lt;a href="http://apache.perl.org/outstanding/sites.html"&gt;success stories mentioned on the website&lt;/a&gt; are about using it to deploy web apps.&lt;br /&gt;&lt;br /&gt;It is unfortunate because: first of all, mod_perl is much more than just about running web apps, it is actually a tool to customize and extend Apache using Perl instead of C. There's so much you can do with it.&lt;br /&gt;&lt;br /&gt;Second, I believe mod_perl is suboptimal for running web apps: it makes your Apache processes fat (and thus you'll often need a front-end proxy), it's tied to Apache (so you can't experiment with other webservers), it's relatively more complex to configure and tune compared to, say, FastCGI (and thus potentially more insecure), and it's just too damn powerful if you just want a fast CGI.&lt;br /&gt;&lt;br /&gt;mod_perl is also theoretically more insecure because it bundles webserver and the application engine together instead of cleanly separates it. Some of your Perl code might run as root too. All of these are unnecessary if you just want to run web apps.&lt;br /&gt;&lt;br /&gt;Here at work we have been using mod_perl for years, not for deploying web apps but for creating custom Apache handlers in Perl (basically it was because my C sucks). The handlers do the following:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;connect to CGI daemon (because we also write our own CGI daemon, which is much more paranoid in some respects but also more flexible in others like running PHP scripts under different configurations);&lt;br /&gt;&lt;li&gt;filter URLs using own rules (this can be done using a series of regexps with mod_rewrite, but much more readable and comfortable if done with full-fledged Perl code);&lt;br /&gt;&lt;li&gt;authenticate hosting users;&lt;br /&gt;&lt;li&gt;do per-vhost aliases (mod_alias can also do this, but we are using mass/dynamic virtual hosts);&lt;br /&gt;&lt;li&gt;etc.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The servers on which we run mod_perl are shared hosting servers, and we allow users to install their own .htaccess, so we have to patch mod_perl to restrict the Perl* directives from the users. This is because mod_perl does not have something like mod_ruby's &lt;a href="http://wiki.modruby.net/en/?ApacheDirectives"&gt;RubyRestrictDirectives&lt;/a&gt;. This kind of functionality is available as a build-time configuration.&lt;br /&gt;&lt;br /&gt;So there you have it, an unusual/unpopular application of mod_perl: customizing Apache in a shared hosting environment.&lt;br /&gt;&lt;br /&gt;Anyone else using mod_perl not to deploy web apps?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-3502894404539024942?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/3502894404539024942/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/using-modperl-aside-from-deploying-web.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3502894404539024942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/3502894404539024942'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/using-modperl-aside-from-deploying-web.html' title='Using mod_perl *aside* from deploying web apps?'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4862003825987113476</id><published>2009-10-27T02:20:00.000-07:00</published><updated>2009-10-27T02:45:39.784-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Trying out Padre 0.47</title><content type='html'>This is written after a few days of trying Padre. Normally I use emacs, &lt;a href="http://joe-editor.sourceforge.net/"&gt;joe&lt;/a&gt;, &lt;a href="http://www.activestate.com/komodo/"&gt;Komodo Edit/IDE&lt;/a&gt;, kate, and recently geany, so this post is basically about comparing Padre's editing features with these other editors.&lt;br /&gt;&lt;br /&gt;Note: Yup, 0.48 was already out a couple of weeks ago, but I haven't been able to install it due to segfaults in libwx*. Incidentally my box was recently upgraded from Jaunty to Karmic so that might have caused the problem. Anyway, I did read the 0.48's ChangeLog just in case.&lt;br /&gt;&lt;br /&gt;First and foremost, I'm blown away! Between my first try a few months back and 0.47, Padre has tranformed into a very usable editor/IDE, and it's pretty fast too, faster than Komodo IDE/Edit which is notoriously sluggish. Kudos to the hardworking Padre team, you guys rock!&lt;br /&gt;&lt;br /&gt;Here are the features which I find still missing:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;a button (or keyboard shortcut) to quickly toggle on/off the directory tree.&lt;br /&gt;&lt;li&gt;next-tab and prev-tab functionality. There is next-file and prev-file, but after you rearrange the tabs, those two become less useful. Maybe assign Ctrl-PgUp/PgDn or Alt-Left/Right for this?&lt;br /&gt;&lt;li&gt;justify/reflow paragraph/manual word wrap. A la emacs' &lt;b&gt;M-q&lt;/b&gt; or joe's &lt;b&gt;C-kj&lt;/b&gt;.&lt;br /&gt;&lt;li&gt;autodelete trailing whitespaces when saving (and autoadd newline at the end if missing).&lt;br /&gt;&lt;li&gt;remember folding state when reopening files.&lt;br /&gt;&lt;li&gt;(Bug?) the "autofold POD when folding is enabled" feature is very nice, but right now is behaving rather strangely. It only works after I open Preferences and hit Save. Opening or saving files does not automatically fold PODs as advertised.&lt;br /&gt;&lt;li&gt;maybe include something like Rx Toolkit in Komodo? Because I do write a *lot* of regexes when coding in Perl.&lt;br /&gt;&lt;li&gt;(Suggestion) soft characters for automatic bracket completion. I find this feature in Komodo very very nice as I seem to have the habit of typing { or (, and then after thinking a while cancel it.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I'd gladly submit these into Padre's Trac if someone would give me an account. Last time I visited #padre no one had the admin rights to do this. Signup from the website is temporarily disabled to overwhelming amount of spam. &lt;br /&gt;&lt;br /&gt;Anyway, keep up the wonderful work, guys! Looking forward to using Padre more and more often in the future. Envisioning writing Padre config files in Perl, just like in emacs using Lisp... Life will be good...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4862003825987113476?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4862003825987113476/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/trying-out-padre-047.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4862003825987113476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4862003825987113476'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/trying-out-padre-047.html' title='Trying out Padre 0.47'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-2503578284761265831</id><published>2009-10-20T02:48:00.000-07:00</published><updated>2009-10-20T04:04:22.576-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>HTTP-style sub return</title><content type='html'>In a subroutine, we often want to return the &lt;span style="font-weight: bold;"&gt;status&lt;/span&gt; of operation (success/failure/error code) &lt;span style="font-style: italic;"&gt;as well as&lt;/span&gt; the &lt;span style="font-weight: bold;"&gt;result&lt;/span&gt; of the operation.&lt;br /&gt;&lt;br /&gt;When a function does not need to return any result, it can just return the status, usually as an integer scalar. In C and Unix the convention is to return 0 for success and non-zero for the error code. In Perl and many other languages, it is the other way around: zero/false/undef for failure and true values for success. You can also return the result as well right there and then &lt;b&gt;as long as the result evaluates to true&lt;/b&gt;. This can be a problem if there is a possibility that the result be zero/false/undef.&lt;br /&gt;&lt;br /&gt;Alternatively, you can return the result instead. How do we return the error code then? Usually via some global variable like &lt;code&gt;$?&lt;/code&gt; and &lt;code&gt;$!&lt;/code&gt; in Perl. This has drawbacks of its own, like in multithreaded/reentrant code.&lt;br /&gt;&lt;br /&gt;It is safer thus, to return both the status and the result separately and explicitly, e.g. using a 2-element array:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;($status, $result) = foo(...);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For roughly a year now, I have been adopting something like the above, with what I call &lt;span style="font-weight:bold;"&gt;HTTP-style return convention&lt;/span&gt;. Instead of 2, I return a 3-element array in my subs:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;return ($status, $extra_info, $result);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$status&lt;/code&gt; is a 3-digit integer values, with values taken as much as possible from the HTTP spec: 200 means success, 4xx means generic "client side" (i.e. caller side) error like missing or invalid arguments, 404 means not found, 403 means forbidden, 5xx means error in the "server side" (our side, the sub side), 501 means unimplemented, and so on.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$extra_info&lt;/code&gt; is a hashref which contains, well... extra info, like error string, debugging messages, or intermediate results. This is the equivalent of HTTP response headers. But it can be an undef too if the sub does not offer extra information. So it will avoid creating unnecessary hashref.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$result&lt;/code&gt; is the actual result.&lt;br /&gt;&lt;br /&gt;An example code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;my @resp = process_stuff(@stuffs);&lt;br /&gt;if ($resp[0] != 200) {&lt;br /&gt;    die "Failed ($resp[1]{errstr})";&lt;br /&gt;} else {&lt;br /&gt;    print "Number of stuffs input: ",     scalar(@stuffs);&lt;br /&gt;    print "Number of stuffs processed: ", $resp[2];&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Another example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;my @resp = search_stuff($stuff);&lt;br /&gt;if ($resp[0] == 404) {&lt;br /&gt;    die "Stuff $stuff not found";&lt;br /&gt;} elsif ($resp[0] != 200) {&lt;br /&gt;    die "Failed";&lt;br /&gt;} else {&lt;br /&gt;    print "Stuff $stuff found in $resp[2]";&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is a bit confusing for readers not familiar with this style, but I find this clear as it is (i.e., without declaring/using constants for 200, 404, etc).&lt;br /&gt;&lt;br /&gt;The advantages of this return style:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;You can return the status as well as the result as well as extra info.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;The convention for the status codes is already familiar to many. HTTP has been so popular for most of the lifetime of Perl, that most Perl programmers who have dabbed in CGI or Internet programming should be familiar with it. Even many nonprogrammers know what 404 or 500 mean since they often see this while browsing. The 2xx, 4xx, 5xx convention is also used in other protocols like SMTP.&lt;br /&gt;&lt;br /&gt;If you are not, you can always use a comment or a constant to explain the meaning of the numbers.&lt;br /&gt;&lt;br /&gt;&lt;li&gt;You can easily wrap your sub later in a REST API or web service. Just pass $status as HTTP status code, (selected) pairs in $extra_info into HTTP response headers, and $result (possibly encoded in JSON/YAML/whatever).&lt;br /&gt;&lt;br /&gt;&lt;li&gt;A bonus, because Perl has contexts, you can also do this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;if (wantarray) {&lt;br /&gt;    return ($status, $extra_info, $result);&lt;br /&gt;} else {&lt;br /&gt;    return $result;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;so that you can fallback to a very simple style when all the other stuffs are not needed:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;my $result = foo(...); # don't care about status, assume always success&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I find this return style somewhat relevant in the light of PSGI's deservedly speedy upshoot to popularity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-2503578284761265831?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/2503578284761265831/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/http-style-sub-return.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2503578284761265831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/2503578284761265831'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/http-style-sub-return.html' title='HTTP-style sub return'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-4956197360166956782</id><published>2009-10-14T21:07:00.000-07:00</published><updated>2009-10-14T21:46:39.235-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Dumping content to files using Log::Dispatch::Dir</title><content type='html'>Logging frameworks like &lt;a href="http://search.cpan.org/search?mode=module&amp;amp;n=100&amp;amp;query=log%3A%3Alog4perl"&gt;Log::Log4perl&lt;/a&gt; and &lt;a href="http://search.cpan.org/search?mode=module&amp;amp;n=100&amp;amp;query=log%3A%3Adispatch"&gt;Log::Dispatch&lt;/a&gt; are great. They relieve you of the burden of reinventing your own (which, admit it, will probably suck more), and they decouple your code from logging details (which can be changed later independently). You just say I want to log "something something" in the code, and you can later configure whether those messages are actually written to the logs, where those logs are, how the messages are formatted, etc without changing your log-using code.&lt;br /&gt;&lt;br /&gt;Logging can be used, to some extent, to replace debugging or to aid it. Each log message is usually only a single line, like "Starting foo ...", "Ended foo ...", "The value of foo is $val", although we can also log large data structure dumps or file contents.&lt;br /&gt;&lt;br /&gt;When writing web robots like HTML scrapers or interfaces to online banking sites, which are particularly fragile, it is often convenient to save each server's full response into a separate file so you can easily check each step by opening the saved file in a browser.&lt;br /&gt;&lt;br /&gt;If you want to use Log::Log4perl or Log::Dispatch for this, you can too, using  &lt;a href="http://search.cpan.org/search?mode=module&amp;amp;n=100&amp;amp;query=log%3A%3Adispatch%3A%3Adir"&gt;Log::Dispatch::Dir&lt;/a&gt;. This module will write each log message to a separate file in a specified log directory.&lt;br /&gt;&lt;br /&gt;An example, in &lt;a href="http://search.cpan.org/search?mode=module&amp;n=100&amp;query=finance%3A%3Abank%3A%3Aid%3A%3Abase"&gt;Finance::Bank::ID::Base&lt;/a&gt; I have code like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$self-&gt;logger_dump-&gt;trace(&lt;br /&gt;    "&amp;lt;!-- result of mech request #$i ($method ".Dump($args)."):\n".&lt;br /&gt;    $mech-&gt;response-&gt;status_line."\n".&lt;br /&gt;    $mech-&gt;response-&gt;headers-&gt;as_string."\n".&lt;br /&gt;    "--&amp;gt;\n".&lt;br /&gt;    $mech-&gt;content&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;where &lt;code&gt;$mech&lt;/code&gt; is a WWW::Mechanize object. I use &lt;code&gt;$self-&gt;logger&lt;/code&gt; for "normal" log messages and &lt;code&gt;$self-&gt;logger_dump&lt;/code&gt; specifically for dumping contents. Both the &lt;code&gt;logger&lt;/code&gt; and &lt;code&gt;logger_dump&lt;/code&gt; attributes can be supplied by the module user, e.g.:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my $ibank = Finance::Bank::ID::BCA-&gt;new(&lt;br /&gt;    ...&lt;br /&gt;    logger      =&gt; Log::Log4perl-&gt;get_logger("Messages"),&lt;br /&gt;    logger_dump =&gt; Log::Log4perl-&gt;get_logger("Dumps"),&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and the Log::Log4perl configuration is something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;log4perl.logger.Messages=TRACE, SCREEN, LOGFILE&lt;br /&gt;log4perl.logger.Dumps=TRACE, LOGDIR&lt;br /&gt;&lt;br /&gt;log4perl.appender.SCREEN=Log::Log4perl::Appender::ScreenColoredLevels&lt;br /&gt;log4perl.appender.SCREEN.layout=PatternLayout&lt;br /&gt;log4perl.appender.SCREEN.layout.ConversionPattern=[\%r] %m%n&lt;br /&gt;&lt;br /&gt;log4perl.appender.LOGFILE=Log::Log4perl::Appender::File&lt;br /&gt;log4perl.appender.LOGFILE.filename=/path/to/logs/main.log&lt;br /&gt;log4perl.appender.LOGFILE.layout=PatternLayout&lt;br /&gt;log4perl.appender.LOGFILE.layout.ConversionPattern=[\%d] %m%n&lt;br /&gt;&lt;br /&gt;log4perl.appender.LOGDIR=Log::Dispatch::Dir&lt;br /&gt;log4perl.appender.LOGDIR.dirname=/path/to/logs/dumps&lt;br /&gt;log4perl.appender.LOGDIR.layout=PatternLayout&lt;br /&gt;log4perl.appender.LOGDIR.layout.ConversionPattern=%m&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is convenient enough for me, but in the future I want to do some MIME checking to the log messages, so Log::Dispatch::Dir can automatically add a suitable file extension e.g. .html, .txt, .jpg, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-4956197360166956782?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/4956197360166956782/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/dumping-content-to-files-using.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4956197360166956782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/4956197360166956782'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/dumping-content-to-files-using.html' title='Dumping content to files using Log::Dispatch::Dir'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5721324648398280676</id><published>2009-10-14T20:44:00.000-07:00</published><updated>2009-10-14T20:52:54.026-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Mengecek rekening BCA dan Mandiri dengan Perl</title><content type='html'>Akhirnya, kesampean juga merilis modul &lt;a href="http://search.cpan.org/search?query=Finance%3A%3ABank%3A%3AID%3A%3ABCA&amp;amp;mode=all"&gt;Finance::Bank::ID::BCA&lt;/a&gt; dan &lt;a href="http://search.cpan.org/search?query=Finance%3A%3ABank%3A%3AID%3A%3AMandiri&amp;amp;mode=all"&gt;Finance::Bank::ID::Mandiri&lt;/a&gt;. Kini Anda bisa mengecek rekening BCA dan Mandiri dengan Perl!&lt;br /&gt;&lt;br /&gt;Bertahun-tahun lalu saya pernah membuat skrip serupa untuk KlikBCA tapi pake kombinasi curl/wget. Sejak terjadi perubahan layout/program di KlikBCA dari ASP ke Java, gak pernah lagi ngupdate skrip ini sampe beberapa bulan yang lalu. Dan akhirnya minggu lalu dan minggu ini menyempatkan memodulkan kodenya.&lt;br /&gt;&lt;br /&gt;Oya, sebetulnya sebagian kodenya pertama-tama ditulis dalam PHP &lt;code&gt;;-p&lt;/code&gt;. Cuma, kode PHP-nya untuk kantor dan gak dirilis (dan mungkin gak akan pernah dirilis, karena saya males memaintain kode PHP utk publik).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5721324648398280676?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5721324648398280676/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/mengecek-rekening-bca-dan-mandiri.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5721324648398280676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5721324648398280676'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/mengecek-rekening-bca-dan-mandiri.html' title='Mengecek rekening BCA dan Mandiri dengan Perl'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1018461035152778838</id><published>2009-10-12T23:42:00.000-07:00</published><updated>2009-10-13T01:30:24.163-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Planet CPAN</title><content type='html'>Recently I have been enjoying Iron Man blog posts that talk about some particular CPAN module like &lt;a href="http://blog.bluefeet.net/2009/10/use-htmlformhandler/"&gt;HTML::FormHandler&lt;/a&gt;, &lt;a href="http://www.ecocode.net/article.shtml?200910.txt-001"&gt;Finance::Quote&lt;/a&gt;, &lt;a href="http://headrattle.blogspot.com/2009/10/termprogressbar.html"&gt;Term::ProgressBar&lt;/a&gt;, &lt;a href="http://www.lowlevelmanager.com/2009/10/locallib.html"&gt;local::lib&lt;/a&gt;, &lt;a href="http://use.perl.org/%7Epotyl/journal/39688?from=rss"&gt;Log::Log4perl&lt;/a&gt;, &lt;a href="http://jquelin.blogspot.com/2009/10/migration-to-moose-step-1.html"&gt;Dist::Zilla&lt;/a&gt;, even the good ol'&lt;a href="http://howcaniexplainthis.blogspot.com/2009/10/use-digestmd5-its-easy.html"&gt; Digest::MD5&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm hoping though that even more people (authors and users alike) would blog more about CPAN modules, because although we arguably have &lt;a href="http://search.cpan.org/"&gt;one&lt;/a&gt; &lt;a href="http://www.cpanforum.com/"&gt;of&lt;/a&gt; &lt;a href="http://cpanratings.perl.org/"&gt;the&lt;/a&gt; &lt;a href="http://search.cpan.org/%7Ejhi/perl-5.8.1/lib/CPAN/bin/cpan"&gt;richest&lt;/a&gt; &lt;a href="http://search.cpan.org/%7Ekane/CPANPLUS-0.88/bin/cpanp"&gt;sets&lt;/a&gt; of interfaces to our wonderful software library, with more than 16000 modules it's near impossible to browse them all. Feature blog posts certainly help people stumble on interesting stuffs even if they don't follow Recent CPAN Uploads.&lt;br /&gt;&lt;br /&gt;Since ~ 95% of all interesting things in the Perl world are happening inside CPAN (not to belittle the huge efforts of the p5p team or the Parrot &amp;amp; Perl 6 designers/implementors, of course) shouldn't we be blogging more about it?&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Filtering RSS&lt;/h3&gt;On a somewhat unrelated note, lately I've also been tired of all the Microsoft/Windows/Vista/7/8/9 that are filling up from the Slashdot RSS feed. Most are irrelevant to me as I use Linux, besides, those news are really minor/unimportant/of marketing type, like &lt;a href="http://tech.slashdot.org/story/09/10/12/1429214/Revisiting-the-Original-Reviews-of-Windows-Vista"&gt;rereading old Vista reviews&lt;/a&gt;, &lt;a href="http://tech.slashdot.org/story/09/10/08/1432228/Microsoft-Leaks-Details-of-128-bit-Windows-8"&gt;intentionally ambiguous 128-bit version of future Windows&lt;/a&gt;, or repeated news items telling me that products are being delayed yet again. Who cares?&lt;br /&gt;&lt;br /&gt;Nowadays I'm using Google Reader on a cellphone to read most feeds, so less junk would be nice. Google Reader doesn't have filtering yet, so I ended up using &lt;a href="http://pipes.yahoo.com/"&gt;Yahoo! Pipes&lt;/a&gt;. Filtering and doing other stuffs to feeds (and other kinds of data like CSV) are surprisingly quick and easy using this web-based visual editor. A user-friendly Perl- and Unix-killer? :-) Just go to pipes.yahoo.com, click on My Pipes, create a new pipe, and do some drag-and-drops and text field filling, publish your pipe, and get RSS. Perfect (here are two examples of pipes I've created: &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=456791f6d46fb5dbaca9c867361fb5da"&gt;slashdot-noms&lt;/a&gt; and &lt;a href="http://pipes.yahoo.com/pipes/pipe.info?_id=030f8bf58895775832c612703394dcbf"&gt;slashdot-nofb&lt;/a&gt;). Looking forward to a more Microsoft-free news reading ahead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1018461035152778838?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1018461035152778838/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/planet-cpan.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1018461035152778838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1018461035152778838'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/planet-cpan.html' title='Planet CPAN'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5165537157785793429</id><published>2009-10-12T22:40:00.000-07:00</published><updated>2009-10-13T00:53:17.498-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>CPAN download counter? +1!</title><content type='html'>From time to time people (including me once, a few years back) would ask questions like: what are the 'top' (or 'most popular' or 'widely used' or most downloaded) dists/modules on CPAN? Is there a download counter for each dist/module? Like &lt;a href="http://niceperl.blogspot.com/2009/10/cpan-download-counter.html"&gt;this one&lt;/a&gt; from prz, a budding module author.&lt;br /&gt;&lt;br /&gt;The answer is there isn't one, because CPAN is just a bunch of static files. The upside of this, CPAN is very easily mirrored (e.g. via FTP or rsync or offline via CDs) and served (e.g. via FTP, HTTP, or local filesystem). The downside, there isn't a place for much intelligence/logic on the serving side.&lt;br /&gt;&lt;br /&gt;To implement this feature, we can put some stats gathering code on the client side, like what Debian &lt;a href="http://popcon.debian.org/"&gt;has been doing&lt;/a&gt; for a while; in fact you can already see the list of most widely installed Perl modules from the data. Or we can add some stats to &lt;a href="http://search.cpan.org/"&gt;search.cpan.org&lt;/a&gt; like most viewed/clicked/downloaded dists and modules, and maybe top search keywords. Not representative of all mirrors, sure, but it's better than nothing.&lt;br /&gt;&lt;br /&gt;Download counter, or at least Popular/Top Downloads, is a common feature on download/catalog/shopping/news sites, from &lt;a href="http://freshmeat.net/"&gt;freshmeat&lt;/a&gt; and &lt;a href="http://download.com/"&gt;Download.com&lt;/a&gt;, to &lt;a href="http://www.amazon.com/"&gt;Amazon&lt;/a&gt; and &lt;a href="http://www.apple.com/itunes/"&gt;iTunes Store&lt;/a&gt;. So common that many users expect it to be there as a standard feature.&lt;br /&gt;&lt;br /&gt;It's not hard to imagine why people like to know what's popular, what everybody else is using/doing, what's in, what's hot. It's a social side of human nature. And it's beneficial to know which modules are getting downloaded and used more, to direct development efforts to the more important stuffs. Volunteers can surely take the top modules list as one consideration when picking which project to spend their valuable time on.&lt;br /&gt;&lt;br /&gt;What I'm not very clear on though is why, aside from &lt;a href="http://pear.php.net/"&gt;PHP&lt;/a&gt;, &lt;a href="http://search.cpan.org/"&gt;many&lt;/a&gt; &lt;a href="http://gems.rubyforge.org/"&gt;programming&lt;/a&gt; &lt;a href="http://hackage.haskell.org/"&gt;languages&lt;/a&gt;' communities don't like this particular feature? Do we hate competition, do we hate popularity contest, or are we just plain lazy?&lt;br /&gt;&lt;br /&gt;Anyway, effort like &lt;a href="http://cpanhq.com/"&gt;CPANHQ&lt;/a&gt; might soon make the Top/most $foo modules, and more, possible. Yay!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5165537157785793429?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5165537157785793429/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/cpan-download-counter-1.html#comment-form' title='5 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5165537157785793429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5165537157785793429'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/cpan-download-counter-1.html' title='CPAN download counter? +1!'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5990431198973005093</id><published>2009-10-06T19:18:00.000-07:00</published><updated>2009-10-07T19:18:07.586-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Moving from bzr to git</title><content type='html'>&lt;p&gt;As with a lot of coders out there, I've moved on from no source control, to &lt;a href="http://www.nongnu.org/cvs/"&gt;CVS&lt;/a&gt;, to &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;, and recently to one of the distributed ones. In fact, I tried both &lt;a href="http://bazaar-vcs.org/"&gt;Bazaar&lt;/a&gt; and &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; roughly at the same time a couple of years back and have been quite comfortably using both to manage my projects.&lt;/p&gt;&lt;p&gt;Last week though, I've migrated all but one of my projects to git. The only bzr repository left is the one for $work where I want to avoid retraining people to use git since they are not coders.&lt;/p&gt;&lt;p&gt;I had no real complaints with bzr. Sure, it's generally slower than git, the repository size is slightly larger than git's, and branching is a bit more cumbersome than in git, but all of those have never bothered me enough to part with bzr.&lt;/p&gt;&lt;p&gt;The clincher, however, came when I needed to write some post-commit hook to post my commit messages to an internal web-based bulletin board. In bzr you need to write a plugin &lt;strong&gt;written in Python&lt;/strong&gt;. Not that there's anything wrong with it, but I don't think I even want a Perl-based SCM where I need to write a Perl plugin for everything when a two-line shell script will do. Add to that fact that bzr doesn't provide a template/skeleton for the plugin and I have to spend a few minutes to google around the plugin API (in addition to refreshing my memory on Python syntax), etc.&lt;/p&gt;&lt;p&gt;I think I'm much more comfortable with git nowadays.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5990431198973005093?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5990431198973005093/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/moving-from-bzr-to-git.html#comment-form' title='3 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5990431198973005093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5990431198973005093'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/moving-from-bzr-to-git.html' title='Moving from bzr to git'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-1599896174062324989</id><published>2009-10-06T10:28:00.000-07:00</published><updated>2009-10-07T19:21:09.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Some Indonesian-specific modules to check SIM, NPWP, NIK</title><content type='html'>Today for some reason I finally got motivated enough to write and release Business-ID-{&lt;a href="http://search.cpan.org/search?query=Business::ID::NIK"&gt;NIK&lt;/a&gt;,&lt;a href="http://search.cpan.org/search?query=Business::ID::SIM"&gt;SIM&lt;/a&gt;,&lt;a href="http://search.cpan.org/search?query=Business::ID::NPWP"&gt;NPWP&lt;/a&gt;} to &lt;a href="http://search.cpan.org/"&gt;CPAN&lt;/a&gt;. Been wanting to for years, but haven't got around to it due to lack of challenge and, more importantly, reference. For example, so far I haven't found a publicly available and authoritative document explaining the numbering scheme and the valid area codes for the SIM. I had to do some deducing (read: guessing) from some thousands of actual user-submitted &lt;a href="http://id.wikipedia.org/wiki/Surat_Izin_Mengemudi"&gt;SIM&lt;/a&gt;, &lt;a href="http://id.wikipedia.org/wiki/Nomor_Pokok_Wajib_Pajak"&gt;NPWP&lt;/a&gt;, and &lt;a href="http://id.wikipedia.org/wiki/Nomor_Induk_Kependudukan"&gt;NIK/KTP&lt;/a&gt; numbers (some of them most certainly bogus). Isn't it sad?&lt;br /&gt;&lt;br /&gt;If you encounter some valid numbers being rejected by the modules, or vice versa, feel free to report them as bugs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-1599896174062324989?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/1599896174062324989/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/10/some-indonesian-specific-modules-to.html#comment-form' title='0 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1599896174062324989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/1599896174062324989'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/10/some-indonesian-specific-modules-to.html' title='Some Indonesian-specific modules to check SIM, NPWP, NIK'/><author><name>Steven Haryanto</name><uri>http://www.blogger.com/profile/09282042440154229218</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3035323255246508397.post-5695904944302633017</id><published>2009-09-28T22:16:00.000-07:00</published><updated>2009-10-14T20:52:26.929-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lang=id'/><category scheme='http://www.blogger.com/atom/ns#' term='steven'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perlsatu kita teguh, Perlcerai kita runtuh</title><content type='html'>&lt;p&gt;Yup, garing abis judulnya, tapi yang kepikir dalam 10 detik cuma itu sih.&lt;/p&gt;&lt;p&gt;Blog ini pertama dibuat untuk ikutan &lt;a href="http://www.enlightenedperl.org/ironman.html"&gt;Perl Iron Man Blogging Challenge&lt;/a&gt;. Karena gw gak yakin bisa keep up ngeblog sendirian seminggu sekali (tepatnya, 4 post dalam 32 hari) maka gw buat nama blog ini mewakili komunitas Perl Indonesia.&lt;/p&gt;&lt;p&gt;Bila Anda cinta/suka Perl, ingin berbagi tentang Perl, atau sedang belajar Perl, saya harapkan mau ikut bergabung ngeblog di blog ini. Posting boleh dalam bahasa Indonesia maupun English. Gak harus murni tentang Perl, yang kira-kira cuma 10-20% berhubungan dengan Perl juga gpp. Dan sekali-kali OOT juga no problem. Bahasa gak harus resmi, yang penting enak dibaca dan komunikatif. Level post gak harus advanced, semua level diterima.&lt;/p&gt;&lt;p&gt;Berminat? Silakan hubungi Steven di: steven2 &lt;em&gt;setrip &lt;/em&gt;id &lt;em&gt;setrip &lt;/em&gt;perl &lt;em&gt;et &lt;/em&gt;masterweb &lt;em&gt;titik&lt;/em&gt; net. Nanti 'tak tambahkan akun Google Anda ke dalam daftar anggota tim blog ini supaya bisa ikutan ngepost. Yuk?&lt;/p&gt;&lt;p&gt;Buat para pembaca, enjoy dan doakan kita2x!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3035323255246508397-5695904944302633017?l=id-perl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://id-perl.blogspot.com/feeds/5695904944302633017/comments/default' title='Poskan Komentar'/><link rel='replies' type='text/html' href='http://id-perl.blogspot.com/2009/09/steven-perlsatu-kita-teguh-perlcerai.html#comment-form' title='2 Komentar'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5695904944302633017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3035323255246508397/posts/default/5695904944302633017'/><link rel='alternate' type='text/html' href='http://id-perl.blogspot.com/2009/09/steven-perlsatu-kita-teguh-perlcerai.html' title='Perlsatu kita teguh, Perlcerai kita runtuh'/><author><name>Perl Indonesia</name><uri>http://www.blogger.com/profile/09083793321887864209</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
