<?xml version="1.0" encoding="UTF-8"?>

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns="http://purl.org/rss/1.0/"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
 xmlns:admin="http://webns.net/mvcb/"
>

<channel rdf:about="http://sartak.org">
<title>sartak</title>
<link>http://sartak.org</link>
<description></description>
<items>
 <rdf:Seq>
  <rdf:li rdf:resource="http://sartak.org/2011/09/why-i-read-books-on-my-ipod.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/09/todo-vim-ack.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/08/july-2011.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/07/&#xE3;&#x83;&#x8B;&#xE3;&#x83;&#xBC;&#xE3;&#x83;&#x88;&#xE3;&#x81;&#xA7;&#xE3;&#x81;&#x82;&#xE3;&#x82;&#x8B;&#xE3;&#x81;&#x93;&#xE3;&#x81;&#xA8;&#xE3;&#x81;&#xAB;&#xE3;&#x81;&#xA4;&#xE3;&#x81;&#x84;&#xE3;&#x81;&#xA6;&#xE3;&#x81;&#xAE;&#xE8;&#xA8;&#x98;&#xE8;&#xBF;&#xB0;.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/03/end-of-line-whitespace-in-vim.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/01/interhack-and-taeb-postmortem.html" />
  <rdf:li rdf:resource="http://sartak.org/2011/01/replace-a-lightweight-git-tag-with-an-annotated-tag.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/12/installing-imager-file-gif-and-imager-file-jpeg-with-homebrew.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/09/&#xE9;&#xA0;&#x91;&#xE5;&#xBC;&#xB5;&#xE3;&#x82;&#x89;&#xE3;&#x81;&#xAA;&#xE3;&#x81;&#x8D;&#xE3;&#x82;&#x83;&#xEF;&#xBC;&#x81;.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/09/piggybacking-motivation.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/08/super-mario-world.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/04/learning-japanese-with-sentences.html" />
  <rdf:li rdf:resource="http://sartak.org/2010/01/on-learning.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/10/jifty-s-request-inspector.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/09/google-wave-mania.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/09/yapc-asia-2009-moose-course.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/06/reflections-on-yapc-na-2009.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/06/shawn-m-moose-at-yapc-na-2009.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/05/the-design-of-parameterized-roles.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/05/perl-critic-dynamic-moose.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/04/the-new-moose-warning-and-the-new-moose-critic.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/03/breaking-sys-protect.html" />
  <rdf:li rdf:resource="http://sartak.org/2009/01/parametric-roles-in-perl-5.html" />
  <rdf:li rdf:resource="http://sartak.org/2007/09/devel-repl-now-with-multiline-support.html" />
 </rdf:Seq>
</items>
</channel>
<item rdf:about="http://sartak.org/2011/09/why-i-read-books-on-my-ipod.html">
<title>Why I Read Books on My iPod</title>
<link>http://sartak.org/2011/09/why-i-read-books-on-my-ipod.html</link>
<description>
&#x3C;h4&#x3E;I can copy Japanese sentences I understand into my Anki flash card deck:&#x3C;/h4&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/ipod-reading/copy-sentence.png&#x22; alt=&#x22;&#x22; /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/ipod-reading/paste-sentence.png&#x22; alt=&#x22;&#x22; /&#x3E;
&#x3C;hr /&#x3E;
&#x3C;h4&#x3E;I can copy Japanese words I &#x3C;em&#x3E;don&#x27;t&#x3C;/em&#x3E; understand into a dictionary:
 &#x3C;sup id=&#x22;fnr-1&#x22;&#x3E;
  &#x3C;a href=&#x22;#fn-1&#x22;&#x3E;1&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/h4&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/ipod-reading/copy-word.png&#x22; alt=&#x22;&#x22; /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/ipod-reading/paste-word.png&#x22; alt=&#x22;&#x22; /&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;There are a few reasons why I&#x27;m pretty excited about the iPhone 5 announcement. There will supposedly be a fat home button which allows gestures for easy switching of apps. If that feature indeed lands on the new iPhone, it will save me a couple moments and clicks, thousands of times over, as I flip between iBooks, Anki, and &#x5927;&#x8F9E;&#x6797; while studying. Also I&#x27;m still rocking a third-gen iPod Touch which does not have anything near a retina display, so that&#x27;ll be great for turning those kanji from muddy to crisp.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I don&#x27;t foresee myself getting a new Kindle any time soon, even though those Kindle Touches look pretty damn good.&#x3C;/p&#x3E;
&#x3C;div class=&#x22;footnotes&#x22;&#x3E;
 &#x3C;hr /&#x3E;
 &#x3C;ol&#x3E;
  &#x3C;li id=&#x22;fn-1&#x22;&#x3E;
   &#x3C;span&#x3E;iBooks has a built-in dictionary, but it&#x27;s not useful for my study because it&#x27;s English-only. One way to make that button universally useful would be to let you set it up to launch some other application, but unfortunately built-in apps typically don&#x27;t give you that much rope. Update: a reader has pointed me to iBunkos which is designed for reading Japanese text. iBunkos not only gives you the rope to launch the URLs of your choosing (which means you can launch any app that supports being launched to), but also has a builtin dictionary and a builtin link to &#x5927;&#x8F9E;&#x6797;. Perfect!&#x3C;/span&#x3E;
   &#x3C;sup&#x3E;
    &#x3C;a class=&#x22;footnoteBackLink&#x22; href=&#x22;#fnr-1&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
   &#x3C;/sup&#x3E;
  &#x3C;/li&#x3E;
 &#x3C;/ol&#x3E;
&#x3C;/div&#x3E;</description>
<dc:date>2011-09-28</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/09/todo-vim-ack.html">
<title>TODO? vim &#x2665; ack</title>
<link>http://sartak.org/2011/09/todo-vim-ack.html</link>
<description>
&#x3C;p&#x3E;One pattern I frequently find myself following is acking for a very specific set of results...&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;ack -a &#x27;uri_for.*(contact|address|phone)&#x27;&#x3C;/pre&#x3E;
&#x3C;p&#x3E;Then I launch vim to start editing the files that were matched here...&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;vim `ack -la &#x27;uri_for.*(contact|address|phone)&#x27;`&#x3C;/pre&#x3E;
&#x3C;p&#x3E;Then I rewrite the search term using vim&#x27;s regular expressions instead of Perl&#x27;s far superior syntax...&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;/uri_for.*\(contact\|address\|phone\)&#x3C;/pre&#x3E;
&#x3C;p&#x3E;Then finally I get along with my editing, using both &#x3C;code&#x3E;n&#x3C;/code&#x3E; and &#x3C;code&#x3E;:bn&#x3C;/code&#x3E; to advance to the each match as needed.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;It&#x27;s generally at the &#x22;mentally translate the Perl regex to vim&#x22; stage where I just say fuck it and fudge it a little bit. There&#x27;s gotta be something better here. How do you do this? Do you &#x3C;em&#x3E;somehow&#x3C;/em&#x3E; have an editor that works better for this than mine? Surely there&#x27;s room enough in this world for an ack + vim lovechild that not only loads the proper files into vim, but also automatically starts you off with the (translated!) regex in your search buffer, cursor already waiting at the first result.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Do I have to write this thing myself?&#x3C;/p&#x3E;
&#x3C;p&#x3E;Update: apparently the answer is no! &#x3C;a href=&#x22;http://twitter.com/trs&#x22;&#x3E;Thomas Sibley&#x3C;/a&#x3E; wrote a new tool called &#x3C;a href=&#x22;https://github.com/tsibley/viack&#x22;&#x3E;&#x3C;code&#x3E;viack&#x3C;/code&#x3E;&#x3C;/a&#x3E; and I&#x27;m happy with how simple it is. \v gives a close enough approximation of Perl regexes.
&#x3C;/p&#x3E;</description>
<dc:date>2011-09-20</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/08/july-2011.html">
<title>July 2011</title>
<link>http://sartak.org/2011/08/july-2011.html</link>
<description>
&#x3C;p&#x3E;A telling side effect of my month of doing (mostly) nothing but studying Japanese:&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/july2011.png&#x22; /&#x3E;</description>
<dc:date>2011-08-01</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/07/&#xE3;&#x83;&#x8B;&#xE3;&#x83;&#xBC;&#xE3;&#x83;&#x88;&#xE3;&#x81;&#xA7;&#xE3;&#x81;&#x82;&#xE3;&#x82;&#x8B;&#xE3;&#x81;&#x93;&#xE3;&#x81;&#xA8;&#xE3;&#x81;&#xAB;&#xE3;&#x81;&#xA4;&#xE3;&#x81;&#x84;&#xE3;&#x81;&#xA6;&#xE3;&#x81;&#xAE;&#xE8;&#xA8;&#x98;&#xE8;&#xBF;&#xB0;.html">
<title>&#x30CB;&#x30FC;&#x30C8;&#x3067;&#x3042;&#x308B;&#x3053;&#x3068;&#x306B;&#x3064;&#x3044;&#x3066;&#x306E;&#x8A18;&#x8FF0;</title>
<link>http://sartak.org/2011/07/&#xE3;&#x83;&#x8B;&#xE3;&#x83;&#xBC;&#xE3;&#x83;&#x88;&#xE3;&#x81;&#xA7;&#xE3;&#x81;&#x82;&#xE3;&#x82;&#x8B;&#xE3;&#x81;&#x93;&#xE3;&#x81;&#xA8;&#xE3;&#x81;&#xAB;&#xE3;&#x81;&#xA4;&#xE3;&#x81;&#x84;&#xE3;&#x81;&#xA6;&#xE3;&#x81;&#xAE;&#xE8;&#xA8;&#x98;&#xE8;&#xBF;&#xB0;.html</link>
<description>
&#x3C;p&#x3E;&#x304A;&#x4E45;&#x3057;&#x3076;&#x308A;&#x3067;&#x3059;&#x306D;&#xFF01;&#xFF01;&#x4ECA;&#x65E5;&#x306E;&#x591A;&#x8AAD;&#x3092;&#x4F11;&#x6B62;&#x3057;&#x3088;&#x3046;&#x3068;&#x601D;&#x3063;&#x305F;&#x304C;&#x3001;&#x65E5;&#x5E38;&#x306E;&#x51FA;&#x6765;&#x4E8B;&#x306B;&#x3064;&#x3044;&#x3066;&#x30C4;&#x30A4;&#x30FC;&#x30C8;&#x3088;&#x308A;&#x9577;&#x3044;&#x8AAC;&#x660E;&#x3092;&#x66F8;&#x304F;&#x3002;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x7B2C;&#x4E00;&#x306B;&#x3001;&#x5148;&#x6708;&#x306B;&#x4F1A;&#x793E;&#x3092;&#x8F9E;&#x3081;&#x305F;&#x3002;Infinity Interactive&#x306B;&#x96C7;&#x308F;&#x308C;&#x305F;&#xFF01;&#x3C;a href=&#x22;http://moose.perl.org&#x22;&#x3E;Moose&#x3C;/a&#x3E;&#x3068;&#x304B;&#x3C;a href=&#x22;http://www.iinteractive.com/kiokudb/&#x22;&#x3E;KiokuDB&#x3C;/a&#x3E;&#x3068;&#x304B;&#x3C;a href=&#x22;http://beta.metacpan.org/module/Path::Router&#x22;&#x3E;Path::Router&#x3C;/a&#x3E;&#x3068;&#x304B;&#x3C;a href=&#x22;http://beta.metacpan.org/module/Bread::Board&#x22;&#x3E;Bread::Board&#x3C;/a&#x3E;&#x3092;&#x30EA;&#x30EA;&#x30FC;&#x30B9;&#x3057;&#x305F;&#x4F1A;&#x793E;&#x306A;&#x3093;&#x3060;&#x3002;&#x30EF;&#x30AF;&#x30EF;&#x30AF;&#x3057;&#x306A;&#x304C;&#x3089;&#x59CB;&#x307E;&#x308B;&#x306E;&#x3092;&#x5F85;&#x3063;&#x3066;&#x308B;&#xFF01;&#x307E;&#x3060;&#x59CB;&#x307E;&#x3089;&#x306A;&#x304B;&#x3063;&#x305F;&#x7406;&#x7531;&#x306F;&#x3001;&#x307E;&#x308B;1&#x30F6;&#x6708;&#x306E;&#x4F11;&#x307F;&#x3092;&#x53D6;&#x308A;&#x305F;&#x304B;&#x3063;&#x305F;&#x3093;&#x3060;&#x3002;7&#x6708;&#x4E2D;&#x306B;&#x6FC0;&#x3057;&#x304F;&#x65E5;&#x672C;&#x8A9E;&#x3092;&#x30EC;&#x30D9;&#x30EB;&#x30A2;&#x30C3;&#x30D7;&#x3057;&#x305F;&#x3044;&#x3093;&#x3060;&#x305C;&#xFF01;
&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x5148;&#x9031;&#x306B;&#x3C;a href=&#x22;http://www.yapc2011.us/yn2011/&#x22;&#x3E;YAPC::NA&#x3C;/a&#x3E;&#x3092;&#x53C2;&#x52A0;&#x3057;&#x3066;&#x3001;2&#x3064;&#x306E;&#x6F14;&#x8AAC;(?)&#x3084;&#x3063;&#x305F;&#x3002;1&#x3064;&#x76EE;&#x306F;&#x3001;&#x3C;a href=&#x22;http://perldoc.jp/docs/modules/Pod-Cpandoc-0.09/Cpandoc.pod&#x22;&#x3E;cpandoc&#x3C;/a&#x3E;&#x306B;&#x3064;&#x3044;&#x3066;LT&#x3060;&#x3063;&#x305F;&#x3002;&#x30A4;&#x30F3;&#x30BF;&#x30FC;&#x30CD;&#x30C3;&#x30C8;&#x304C;&#x5FC5;&#x8981;&#x3060;&#x3063;&#x305F;&#x751F;&#x306E;&#x5B9F;&#x6F14;&#x3067;&#x3001;cpandoc&#x3092;&#x4F7F;&#x3046;&#x65B9;&#x6CD5;&#x3092;&#x6559;&#x3048;&#x305F;&#x304C;&#x3001;&#x697D;&#x3057;&#x304B;&#x3063;&#x305F;&#xFF01;2&#x3064;&#x76EE;&#x306F;&#x3001;&#x3C;a href=&#x22;http://beta.metacpan.org/module/Announcements&#x22;&#x3E;Announcements&#x3C;/a&#x3E;&#x5165;&#x9580;&#x3092;20&#x5206;&#x8A71;&#x3057;&#x305F;&#x3002;YAPC&#x3067;&#x3001;miyagawa&#x3055;&#x3093;&#x304C;&#x50D5;&#x306B;&#x300C;How does it feel to be a &#x30CB;&#x30FC;&#x30C8;?&#x300D;&#x3063;&#x3066;&#x5197;&#x8AC7;&#x306B;&#x805E;&#x3044;&#x305F;&#x306E;&#x3067;&#x3001;&#x3053;&#x306E;&#x30D6;&#x30ED;&#x30B0;&#x306E;&#x8868;&#x984C;&#x3092;&#x304F;&#x308C;&#x305F;&#x3002;
&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x6700;&#x8FD1;&#x3001;DTrace&#x3092;&#x7FD2;&#x3063;&#x3066;&#x307F;&#x305F;&#x3002;&#x5F37;&#x529B;&#x3059;&#x304E;&#x306A;&#x30C4;&#x30FC;&#x30EB;&#x3060;&#x304B;&#x3089;&#x3001;&#x4F7F;&#x308F;&#x306A;&#x304F;&#x3066;&#x306F;&#x3044;&#x3051;&#x306A;&#x3044;&#x3002;printf&#x5F0F;&#x3067;&#x306E;&#x30C7;&#x30D0;&#x30B0;&#x304C;&#x597D;&#x304D;&#x306A;&#x30D7;&#x30ED;&#x30B0;&#x30E9;&#x30DE;&#x30FC;&#x3001;DTrace&#x3092;&#x8ABF;&#x67FB;&#x3057;&#x3066;&#x4E0B;&#x3055;&#x3044;&#xFF01;&#x3C;a href=&#x22;http://pinboard.in&#x22;&#x3E;Pinboard&#x3C;/a&#x3E;&#x3067;DTrace&#x3092;&#x8A18;&#x8FF0;&#x3059;&#x308B;&#x8A18;&#x4E8B;&#x3092;&#x96C6;&#x3081;&#x3066;&#x3044;&#x308B;: [&#x3C;a href=&#x22;http://pinboard.in/u:sartak/t:dtrace&#x22;&#x3E;&#x3059;&#x3079;&#x3066;&#x3C;/a&#x3E;] [&#x3C;a href=&#x22;http://pinboard.in/u:sartak/t:%E6%97%A5%E6%9C%AC%E8%AA%9E/t:dtrace/&#x22;&#x3E;&#x65E5;&#x672C;&#x8A9E;&#x3060;&#x3051;&#x3C;/a&#x3E;]&#x3002;Perl&#x306F;DTrace&#x306E;&#x30D7;&#x30ED;&#x30FC;&#x30D6;&#x304C;&#x3042;&#x308B;&#x3051;&#x3069;&#x3001;&#x95A2;&#x6570;&#x306E;&#x547C;&#x3073;&#x3068;&#x95A2;&#x6570;&#x306E;&#x8FD4;&#x3057;&#x3057;&#x304B;&#x30C8;&#x30EC;&#x30FC;&#x30B9;&#x3067;&#x304D;&#x306A;&#x3044;&#x3002;&#x3057;&#x304B;&#x3057;&#x3001;&#x50D5;&#x304C;Perl&#x306B;&#x30D7;&#x30ED;&#x30FC;&#x30D6;&#x8FFD;&#x52A0;&#x3057;&#x3088;&#x3046;&#x3068;&#x3057;&#x3066;&#x308B;&#x3002;&#x4E00;&#x56DE;&#x76EE;&#x306B;&#x3001;&#x3C;code&#x3E;${^GLOBAL_PHASE}&#x3C;/code&#x3E;&#x3068;&#x3044;&#x3046;&#x306E;&#x5909;&#x6570;(&#x3C;a href=&#x22;http://perldoc.perl.org/perlvar.html#%24%7b%5eGLOBAL_PHASE%7d&#x22;&#x3E;perldoc&#x3092;&#x53C2;&#x7167;&#x3C;/a&#x3E;)&#x306E;&#x5909;&#x5316;&#x3092;&#x77E5;&#x3089;&#x305B;&#x305F;&#x3044;&#x3002;&#x305D;&#x308C;&#x3060;&#x304B;&#x3089;&#x3001;p5p&#x306B;&#x3C;a href=&#x22;https://rt.perl.org/rt3/Public/Bug/Display.html?id=94234&#x22;&#x3E;&#x30D1;&#x30C3;&#x30C1;&#x3C;/a&#x3E;&#x3092;&#x3042;&#x3052;&#x305F;&#x3002;&#x6B21;&#x306E;&#x30D7;&#x30ED;&#x30FC;&#x30D6;&#x3092;&#x8FFD;&#x52A0;&#x3059;&#x308B;&#x306E;&#x306F;&#x3001;&#x6587;&#x5B57;&#x5217;&#x5F0F;&#x306E;eval&#x3001;&#x305F;&#x3076;&#x3093;&#x3002;&#x4ECA;&#x5E74;&#x306E;YAPC::Asia&#x3067;&#x3001;&#x50D5;&#x306E;&#x8A71;&#x306F;DTrace&#x306E;&#x30C6;&#x30FC;&#x30DE;&#x3068;&#x601D;&#x3046;&#x3002;&#x3C;a href=&#x22;http://pghpw.org/ppw2011/&#x22;&#x3E;PPW&#x3C;/a&#x3E;&#x3082;&#x3001;&#x3082;&#x3057;&#x50D5;&#x304C;&#x884C;&#x3063;&#x305F;&#x3089;&#x3002;
&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x6B21;&#x56DE;&#x306B;&#x3001;&#x6700;&#x65B0;&#x306E;&#x56FD;&#x8A9E;&#x306E;&#x52C9;&#x5F37;&#x3092;&#x7269;&#x8A9E;&#x308B;&#x3002;&#x3055;&#x3089;&#x3070;&#x3060;&#xFF01;&#x3C;/p&#x3E;</description>
<dc:date>2011-07-08</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/03/end-of-line-whitespace-in-vim.html">
<title>End-of-Line Whitespace in Vim</title>
<link>http://sartak.org/2011/03/end-of-line-whitespace-in-vim.html</link>
<description>
&#x3C;p&#x3E;Whitespace characters at the ends of lines are sloppy and (almost completely) useless. Not to mention when you notice and remove them, they clutter up your version control history. That can be mitigated by using &#x3C;code&#x3E;git diff --ignore-space-at-eol&#x3C;/code&#x3E;, but it&#x27;s better to never let it become a problem. So I have two settings in &#x3C;a href=&#x22;https://github.com/sartak/conf/blob/master/vimrc&#x22;&#x3E;my vimrc&#x3C;/a&#x3E; that help me avoid committing EOL whitespace to any of my hobby or work projects.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;The first one highlights EOL whitespace so you can tell that it&#x27;s even there, but in a way that isn&#x27;t &#x3C;em&#x3E;obnoxious&#x3C;/em&#x3E;. Vim does offer a builtin option to do this. But it sucks.
&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;vim code_snippet&#x22;&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;set&#x3C;/span&#x3E; &#x3C;span class=&#x22;synPreProc&#x22;&#x3E;list&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;set&#x3C;/span&#x3E; &#x3C;span class=&#x22;synPreProc&#x22;&#x3E;listchars&#x3C;/span&#x3E;=trail&#x3C;span class=&#x22;synStatement&#x22;&#x3E;:&#x3C;/span&#x3E;.
&#x3C;/pre&#x3E;
&#x3C;p&#x3E;These two settings make it so when whitespace occurs at the end of a line, each character is displayed as a blue period. This is good in theory, but actually it means that whenever you&#x27;re typing new content, these blue periods show up every single time you&#x27;re done typing a word and continue on to the next one. This is what I mean by &#x3C;em&#x3E;obnoxious&#x3C;/em&#x3E;. Of course there&#x27;s going to be lots of fleeting EOL whitespace if I&#x27;m typing a sentence or a line of code! So a few years ago &#x3C;a href=&#x22;http://tozt.net&#x22;&#x3E;Jesse Luehrs&#x3C;/a&#x3E; and I banged our heads against our own separate walls until we came up with something that worked for us. I haven&#x27;t seen this used anywhere else but it works perfectly for us so I wanted to share it.
&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;vim code_snippet&#x22;&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;autocmd&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;InsertEnter&#x3C;/span&#x3E; * &#x3C;span class=&#x22;synStatement&#x22;&#x3E;syn&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;clear&#x3C;/span&#x3E; EOLWS | &#x3C;span class=&#x22;synStatement&#x22;&#x3E;syn&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;match&#x3C;/span&#x3E; EOLWS &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;excludenl&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;/\s\+\%#\@!$/&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;autocmd&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;InsertLeave&#x3C;/span&#x3E; * &#x3C;span class=&#x22;synStatement&#x22;&#x3E;syn&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;clear&#x3C;/span&#x3E; EOLWS | &#x3C;span class=&#x22;synStatement&#x22;&#x3E;syn&#x3C;/span&#x3E; &#x3C;span class=&#x22;synType&#x22;&#x3E;match&#x3C;/span&#x3E; EOLWS &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;excludenl&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;/\s\+$/&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;highlight&#x3C;/span&#x3E; EOLWS &#x3C;span class=&#x22;synType&#x22;&#x3E;ctermbg&#x3C;/span&#x3E;=red &#x3C;span class=&#x22;synType&#x22;&#x3E;guibg&#x3C;/span&#x3E;=red
&#x3C;/pre&#x3E;
&#x3C;p&#x3E;What this does is highlight EOL whitespace with a red background &#x3C;strong&#x3E;except on the line you&#x27;re editing&#x3C;/strong&#x3E;. Which means it&#x27;s not obnoxiously telling you about every time you hit the space bar. The highlighting only occurs when you leave insert mode or if you move the cursor to a different line, such as by hitting enter. Which we&#x27;ve found to be exactly the kind of highlighting we want.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;The &#x3C;code&#x3E;syn clear EOLS&#x3C;/code&#x3E; is needed so when you switch modes, the appropriate syntax highlighting rule runs instead of both of them. The first line has two components of abominable Vim-specific regex: &#x3C;code&#x3E;\%#&#x3C;/code&#x3E; matches cursor position, and &#x3C;code&#x3E;\@!&#x3C;/code&#x3E; is like a negative lookahead from Perl for the previous atom. So in effect this matches end of line whitespace, except when the cursor is inside that whitespace.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;The other tool I use to combat EOL whitespace is to unceremoniously execute it.&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;vim code_snippet&#x22;&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;nmap&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;leader&#x26;gt;&#x3C;/span&#x3E;w :%s/\s\+$//&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;CR&#x26;gt;&#x3C;/span&#x3E;:let @/=&#x27;&#x27;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;CR&#x26;gt;&#x3C;/span&#x3E;
&#x3C;/pre&#x3E;
&#x3C;p&#x3E;This sets up a new normal-mode command &#x3C;code&#x3E;&#x26;lt;leader&#x26;gt;w&#x3C;/code&#x3E;. The &#x3C;code&#x3E;&#x26;lt;leader&#x26;gt;&#x3C;/code&#x3E; is like a user-specific namespace for custom commands; for most people it&#x27;s going to be &#x3C;code&#x3E;,&#x3C;/code&#x3E; but I have it set to &#x3C;code&#x3E;\&#x3C;/code&#x3E;. The &#x3C;code&#x3E;:let @/=&#x27;&#x27;&#x3C;/code&#x3E; bit empties the &#x3C;code&#x3E;/&#x3C;/code&#x3E; register so that the &#x3C;code&#x3E;/\s\+$/&#x3C;/code&#x3E; regular expression is not used for the &#x3C;code&#x3E;n&#x3C;/code&#x3E; command or &#x3C;code&#x3E;hlsearch&#x3C;/code&#x3E; highlighting. Unfortunately you lose whatever was in &#x3C;code&#x3E;@/&#x3C;/code&#x3E; before you ran &#x3C;code&#x3E;\w&#x3C;/code&#x3E; but that kind of problem hasn&#x27;t affected me in practice.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Some people run a whitespace stripper like this in a &#x3C;code&#x3E;BufWritePre&#x3C;/code&#x3E; autocommand. But I don&#x27;t like that solution because sometimes whitespace at the end of a line &#x3C;em&#x3E;is&#x3C;/em&#x3E; important &#x26;mdash; such as in &#x3C;a href=&#x22;http://daringfireball.net/projects/markdown/syntax#p&#x22;&#x3E;Markdown&#x3C;/a&#x3E;. Instead, the configuration I&#x27;ve described gives you tools for dealing with EOL whitespace sanely. Got any more?
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Several people on &#x3C;a href=&#x22;http://www.reddit.com/r/vim/comments/fvj70/detecting_and_deleting_endofline_whitespace/&#x22;&#x3E;reddit&#x3C;/a&#x3E; have offered alternate highlighting solutions.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Update - I&#x27;m stealing reddit user Amablue&#x27;s &#x3C;a href=&#x22;http://www.reddit.com/r/vim/comments/fvj70/detecting_and_deleting_endofline_whitespace/c1j0uiy&#x22;&#x3E;improvements&#x3C;/a&#x3E; to the whitespace stripper because it no longer stomps on &#x3C;code&#x3E;@/&#x3C;/code&#x3E; and it reinstates the cursor position. I also like his &#x3C;code&#x3E;&#x26;lt;leader&#x26;gt;&#x26;lt;space&#x26;gt;&#x3C;/code&#x3E; over &#x3C;code&#x3E;&#x26;lt;leader&#x26;gt;w&#x3C;/code&#x3E;.
&#x3C;/p&#x3E;
&#x3C;pre class=&#x22;vim code_snippet&#x22;&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;function&#x3C;/span&#x3E;! &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;SID&#x26;gt;&#x3C;/span&#x3E;StripTrailingWhitespace&#x3C;span class=&#x22;synStatement&#x22;&#x3E;()&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synComment&#x22;&#x3E;    &#x26;quot;&#x3C;/span&#x3E; &#x3C;span class=&#x22;synPreProc&#x22;&#x3E;Preparation:&#x3C;/span&#x3E;&#x3C;span class=&#x22;synComment&#x22;&#x3E; save last search, and cursor position.&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;let&#x3C;/span&#x3E; _s&#x3C;span class=&#x22;synStatement&#x22;&#x3E;=&#x3C;/span&#x3E;@/
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;let&#x3C;/span&#x3E; l &#x3C;span class=&#x22;synStatement&#x22;&#x3E;=&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;line&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;.&#x26;quot;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;)&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;let&#x3C;/span&#x3E; c &#x3C;span class=&#x22;synStatement&#x22;&#x3E;=&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;col&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;.&#x26;quot;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;)&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synComment&#x22;&#x3E;    &#x26;quot; Do the business:&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;s&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;/&#x3C;/span&#x3E;\s\+$&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;//e&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synComment&#x22;&#x3E;    &#x26;quot; Clean up: restore previous search history, and cursor position&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;let&#x3C;/span&#x3E; @/&#x3C;span class=&#x22;synStatement&#x22;&#x3E;=&#x3C;/span&#x3E;_s
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;call&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;cursor&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;(&#x3C;/span&#x3E;l, c&#x3C;span class=&#x22;synStatement&#x22;&#x3E;)&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;endfunction&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;nmap&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;silent&#x26;gt;&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;Leader&#x26;gt;&#x26;lt;space&#x26;gt;&#x3C;/span&#x3E; :call &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;SID&#x26;gt;&#x3C;/span&#x3E;StripTrailingWhitespace()&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;&#x26;lt;CR&#x26;gt;&#x3C;/span&#x3E;
&#x3C;/pre&#x3E;</description>
<dc:date>2011-03-01</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/01/interhack-and-taeb-postmortem.html">
<title>Interhack and TAEB Postmortem</title>
<link>http://sartak.org/2011/01/interhack-and-taeb-postmortem.html</link>
<description>
&#x3C;h5&#x3E;&#x3C;a href=&#x22;http://interhack.us&#x22;&#x3E;Interhack&#x3C;/a&#x3E;&#x3C;/h5&#x3E;

&#x3C;p&#x3E;Interhack, a &#x22;smart&#x22; telnet client for server &#x3C;a href=&#x22;http://www.nethack.org/&#x22;&#x3E;NetHack&#x3C;/a&#x3E; play, initially started because the annual &#x3C;a href=&#x22;http://nethack.devnull.net/&#x22;&#x3E;/dev/null&#x3C;/a&#x3E; tournament didn&#x27;t have any of &#x3C;a href=&#x22;http://alt.org/nethack&#x22;&#x3E;nethack.alt.org&#x3C;/a&#x3E;&#x27;s interface patches - most importantly &#x3C;a href=&#x22;http://bilious.homelinux.org/?45&#x22;&#x3E;Color HP Monitor&#x3C;/a&#x3E;. In vanilla NetHack, your HP display doesn&#x27;t change color as you take damage, so in the tournament we would simply not notice we were being slaughtered because we had been subconsciously trained to notice damage using only our peripheral vision, which detects changes in color far more effectively than changes in numbers.&#x3C;/p&#x3E;

&#x3C;p&#x3E;To avoid rewriting history, I should note that in &#x3C;a href=&#x22;http://interhack.us/genesis-irc.txt&#x22;&#x3E;the IRC logs from Interhack&#x27;s inception&#x3C;/a&#x3E; (I&#x27;m in there as Eidolos), someone else named Stevie-O first wrote his own similar tool that made it obvious to him that his character was growing hungry. But we quickly took the idea (but importantly, neither the code nor the name) and ran with it. Interhack developed many more features beyond what we initially brainstormed but it was never designed to be driven by some other code. Interhack was always merely user interface enhancements. What was cool about the project was that such enhancements did not require patching NetHack, so Interhack could be used on NAO and /dev/null.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Also, I only added (or permitted) features that would not take actions on the user&#x27;s behalf. I was worried that such actions could misfire because of bugs in Interhack and cause someone to lose their game. In which case they&#x27;d have every right to be angry at me personally. In all of Interhack&#x27;s usage I only heard of a couple of incidents where Interhack screwed someone up badly. In one, the person didn&#x27;t get their wish because of a bug in Interhack&#x27;s accidental-wish-escape protection. When you press an arrow key or other non-character keys, NetHack sees that as a sequence of characters beginning with escape, so it thinks you&#x27;re trying to cancel your wish, which earns you a random item instead of a really powerful, useful one. We added code to catch that escape key and prompt you, asking if you really did mean to cancel your wish, which was certainly useful and saved wishes that would have been lost, but for whatever reason in that one instance Interhack hung at that prompt, so he had to kill it. When he restarted NetHack, which doesn&#x27;t keep enough state in its save file to remember that you were at a wish prompt, it came back up with a wasted wish. Oops!&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://interhack.us/img/wish-escape.png&#x22; /&#x3E;

&#x3C;p&#x3E;Interhack lost steam because of a poor implementation (&#x3C;a href=&#x22;http://perldoc.perl.org/functions/do.html&#x22;&#x3E;&#x3C;tt&#x3E;do FILE&#x3C;/tt&#x3E;&#x3C;/a&#x3E; is entirely insufficient for a plugin system. No, really.) and NetHack bot development.&#x3C;/p&#x3E;

&#x3C;h5&#x3E;&#x3C;a href=&#x22;http://taeb.sartak.org/&#x22;&#x3E;TAEB&#x3C;/a&#x3E;&#x3C;/h5&#x3E;

&#x3C;p&#x3E;TAEB started as my &#x3C;a href=&#x22;http://taeb.sartak.org/history.html&#x22;&#x3E;fifth or so NetHack bot&#x3C;/a&#x3E;, this time with a thoughtful design instead of just winging it (see above). Because as designed TAEB&#x27;s AI was separate from the rest of the codebase, and thus very trivially pluggable, TAEB&#x27;s name (Tactical Amulet Extraction Bot) has actually &#x3C;em&#x3E;never&#x3C;/em&#x3E; been accurate. But it was such a great name, inciting laughter in anyone we told who was at least as geeky as we are, so we naturally wouldn&#x27;t change it. TAEB was really a bot &#x3C;em&#x3E;framework&#x3C;/em&#x3E; which &#x3C;em&#x3E;happened&#x3C;/em&#x3E; to ship with a bunch of different AIs. We also (partly as a joke, but partly as a debugging tool) included a &#x3C;a href=&#x22;https://github.com/sartak/TAEB/blob/master/lib/TAEB/AI/Human.pm&#x22;&#x3E;Human AI&#x3C;/a&#x3E; that just prompted the terminal what to do every turn. I was fond of labeling TAEB &#x22;a framework for programmatic NetHack&#x22;. Nowadays I&#x27;d just shorten that to &#x22;a NetHack API&#x22;, but I was a little more pretentious back then.&#x3C;/p&#x3E;

&#x3C;h5&#x3E;&#x3C;tt&#x3E;TAEB::AI::Interhack&#x3C;/tt&#x3E;&#x3C;/h5&#x3E;

&#x3C;p&#x3E;That &#x22;programmatic NetHack&#x22; label hints at the fundamental design difference between TAEB and Interhack. Because TAEB asserts complete control over the interaction with NetHack (exposing a proper API instead of proxying a practically opaque stream of characters representing NetHack commands), we could go so much further with new interface features that were only a dream in Interhack. For example, autoexplore could never work in Interhack - its conception of the map was about as good as your terminal&#x27;s (i.e. just a 2d array of colored characters) - but autoexplore would be trivial in TAEB. I even had a pretty good design for an autoplay feature: just use one of TAEB&#x27;s AI modules until a sufficiently challenging situation came up, then ask the human what to do. Beyond that the human could advise the bot on strategical issues (head to Minetown first, then Sokoban, then Mine&#x27;s End) instead of tactical or trifling issues (like remembering to pick up food and eating, fighting weak monsters, and navigating across levels to a particular landmark like the nearest altar). In addition to autoexplore and autoplay we could have plugins like: remember which tiles you&#x27;ve ever stepped on for finding the vibrating square and astral portals and even just evading hidden traps, perfect memory of where every item on the ground is (even if your character has been stricken with amnesia), estimating the risk of monsters to determine if they can be windshielded or if they need to be taken out with more caution using magic; ranged weapons; kiting; etc, and even little things like an automap that doesn&#x27;t suck - it would just know which level you&#x27;re on and fill in the unexplored sections of the map for you.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I wanted someone else to build &#x3C;em&#x3E;that&#x3C;/em&#x3E; Interhack on top of TAEB so that I could continue working on the TAEB bits and contribute the occasional patch to the new Interhack. But no one was ever up for the task. It could very well have been that TAEB was &#x3C;a href=&#x22;http://taeb.sartak.org/future.html&#x22;&#x3E;not complete enough&#x3C;/a&#x3E; (which absolutely does matter when it asserts complete control over the interaction with NetHack) to embark on that project. But I know now that if I had just started working on a cool useful project, contributors would have come and eventually someone else could have taken over. Actually, now that I think of it, TAEB gained far more contributors than any other project I&#x27;ve ever started. We&#x27;ve even given a &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/2148&#x22;&#x3E;few&#x3C;/a&#x3E; &#x3C;a href=&#x22;http://www.perloasis.info/opw2010/talk/2476&#x22;&#x3E;talks&#x3C;/a&#x3E; about &#x3C;a href=&#x22;https://github.com/sartak/TAEB/blob/master/lib/TAEB/AI/YAPC.pm&#x22;&#x3E;it&#x3C;/a&#x3E; at Perl conferences.&#x3C;/p&#x3E;

&#x3C;p&#x3E;In all it was a great time and I&#x27;m proud of what we accomplished. But I no longer have any desire to break NetHack. Hell I barely even play it any more (much less any other roguelike). Maybe if there&#x27;s a new release I&#x27;ll come back just to noodle with all the new stuff. In the meantime I&#x27;ll continue working on my newer less programmatic hobbies.&#x3C;/p&#x3E;
</description>
<dc:date>2011-01-24</dc:date>
</item>
<item rdf:about="http://sartak.org/2011/01/replace-a-lightweight-git-tag-with-an-annotated-tag.html">
<title>Replace a Lightweight Git Tag with an Annotated Tag</title>
<link>http://sartak.org/2011/01/replace-a-lightweight-git-tag-with-an-annotated-tag.html</link>
<description>
&#x3C;p&#x3E;When I released &#x3C;a href=&#x22;http://p3rl.org/Jifty::DBI&#x22;&#x3E;Jifty-DBI&#x3C;/a&#x3E; versions &#x3C;a href=&#x22;https://github.com/bestpractical/jifty-dbi/tree/0.63&#x22;&#x3E;0.63&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://github.com/bestpractical/jifty-dbi/tree/0.64&#x22;&#x3E;0.64&#x3C;/a&#x3E;, I used a &#x3C;i&#x3E;lightweight tag&#x3C;/i&#x3E; (a simple pointer to a commit) instead of an &#x3C;i&#x3E;annotated tag&#x3C;/i&#x3E; (nearly the equivalent of a commit) to tag the release. At work, we&#x27;re moving toward using annotated tags for our releases so that they are cryptographically signed, contain author and date, and perhaps most importantly, work better with &#x3C;a href=&#x22;http://www.kernel.org/pub/software/scm/git/docs/git-describe.html&#x22;&#x3E;&#x3C;tt&#x3E;git describe&#x3C;/tt&#x3E;&#x3C;/a&#x3E;. I was asked to fix the lightweight tags I made for Jifty-DBI releases, which involved a few git incantations I had never used before; hence this post. The basic procedure is:&#x3C;/p&#x3E;

&#x3C;ol&#x3E;
&#x3C;li&#x3E;check out the lightweight tag&#x3C;/li&#x3E;
&#x3C;li&#x3E;delete it locally&#x3C;/li&#x3E;
&#x3C;li&#x3E;create the annotated commit (backdated to the commit it points to)&#x3C;/li&#x3E;
&#x3C;li&#x3E;delete the remote lightweight tag&#x3C;/li&#x3E;
&#x3C;li&#x3E;quickly push the annotated tag&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;

&#x3C;p&#x3E;Here&#x27;s the syntax for each of these commands to upgrade tag &#x3C;strong&#x3E;0.64&#x3C;/strong&#x3E; from lightweight to annotated.&#x3C;/p&#x3E;


&#x3C;pre class=&#x22;sh code_snippet&#x22;&#x3E;
git checkout &#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;.&#x3C;span class=&#x22;synConstant&#x22;&#x3E;64&#x3C;/span&#x3E;
git tag &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;-d&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;.&#x3C;span class=&#x22;synConstant&#x22;&#x3E;64&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;GIT_COMMITTER_DATE&#x3C;/span&#x3E;=&#x3C;span class=&#x22;synStatement&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synPreProc&#x22;&#x3E;$(&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;git show --&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;format&#x3C;/span&#x3E;=&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;%aD &#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;|&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E; head &#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span class=&#x22;synPreProc&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E; git tag &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;-s&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;.&#x3C;span class=&#x22;synConstant&#x22;&#x3E;64&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;-m&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;&#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0.64&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;&#x27;&#x3C;/span&#x3E;
git push origin :refs/tags/&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;.&#x3C;span class=&#x22;synConstant&#x22;&#x3E;64&#x3C;/span&#x3E;
git push &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--tags&#x3C;/span&#x3E;
&#x3C;/pre&#x3E;
</description>
<dc:date>2011-01-11</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/12/installing-imager-file-gif-and-imager-file-jpeg-with-homebrew.html">
<title>Installing Imager::File::GIF and Imager::File::JPEG with homebrew</title>
<link>http://sartak.org/2010/12/installing-imager-file-gif-and-imager-file-jpeg-with-homebrew.html</link>
<description>
More for my future reference than anything else :)

&#x3C;pre class=&#x22;sh code_snippet&#x22;&#x3E;
brew &#x3C;span class=&#x22;synStatement&#x22;&#x3E;install&#x3C;/span&#x3E; giflib
brew &#x3C;span class=&#x22;synStatement&#x22;&#x3E;install&#x3C;/span&#x3E; libjpeg
cpanm &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--look&#x3C;/span&#x3E; Imager::File::GIF
    perl Makefile.PL &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--libpath=~/.brew/lib&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--incpath=~/.brew/include&#x3C;/span&#x3E;
    make &#x3C;span class=&#x22;synStatement&#x22;&#x3E;test&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;install&#x3C;/span&#x3E;
cpanm &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--look&#x3C;/span&#x3E; Imager::File::JPEG
    perl Makefile.PL &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--libpath=~/.brew/lib&#x3C;/span&#x3E; &#x3C;span class=&#x22;synSpecial&#x22;&#x3E;--incpath=~/.brew/include&#x3C;/span&#x3E;
    make &#x3C;span class=&#x22;synStatement&#x22;&#x3E;test&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;install&#x3C;/span&#x3E;
&#x3C;/pre&#x3E;
</description>
<dc:date>2010-12-27</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/09/&#xE9;&#xA0;&#x91;&#xE5;&#xBC;&#xB5;&#xE3;&#x82;&#x89;&#xE3;&#x81;&#xAA;&#xE3;&#x81;&#x8D;&#xE3;&#x82;&#x83;&#xEF;&#xBC;&#x81;.html">
<title>&#x9811;&#x5F35;&#x3089;&#x306A;&#x304D;&#x3083;&#xFF01;</title>
<link>http://sartak.org/2010/09/&#xE9;&#xA0;&#x91;&#xE5;&#xBC;&#xB5;&#xE3;&#x82;&#x89;&#xE3;&#x81;&#xAA;&#xE3;&#x81;&#x8D;&#xE3;&#x82;&#x83;&#xEF;&#xBC;&#x81;.html</link>
<description>
&#x3C;p&#x3E;&#x3C;a href=&#x22;/2010/09/piggybacking-motivation.html&#x22;&#x3E;(this but in english)&#x3C;/a&#x3E;&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x50D5;&#x306B;&#x306F;&#x501F;&#x308A;&#x305F;wii&#x3092;&#x8FD4;&#x3057;&#x305F;&#x304B;&#x3089;&#x3001;&#x3068;&#x3046;&#x3068;&#x3046;&#x30B9;&#x30FC;&#x30D1;&#x30FC;&#x30DE;&#x30EA;&#x30AA;&#x30AE;&#x30E3;&#x30E9;&#x30AF;&#x30B7;&#x30FC;2&#x3092;&#x3084;&#x3063;&#x3066;&#x308A;&#x307E;&#x3059;&#x3002;&#x30B9;&#x30FC;&#x30D1;&#x30FC;&#x30DE;&#x30EA;&#x30AA;&#x30AE;&#x30E3;&#x30E9;&#x30AF;&#x30B7;&#x30FC;&#x304C;&#x5927;&#x597D;&#x304D;&#x3067;&#x3059;&#x304C;&#x7D9A;&#x7DE8;&#x306E;&#x65B9;&#x304C;&#x697D;&#x3057;&#x3044;&#x3068;&#x805E;&#x304D;&#x307E;&#x3059;&#x306D;&#x3002;&#x3057;&#x304B;&#x3057;&#xFF01;&#x65E5;&#x672C;&#x8A9E;&#x304C;&#x52C9;&#x5F37;&#x3059;&#x308B;&#x306E;&#x306B;&#x3001;&#x82F1;&#x8A9E;&#x7248;&#x3092;&#x8CB7;&#x3044;&#x307E;&#x3057;&#x305F;&#x3002;&#x305F;&#x3076;&#x3093;&#x539F;&#x4F5C;&#x3092;&#x8CB7;&#x3048;&#x307E;&#x3057;&#x305F;&#x3002;&#x3067;&#x3082;&#x3001;&#x30A2;&#x30E1;&#x30EA;&#x30AB;&#x306E;wii&#x3067;&#x51FA;&#x6765;&#x306A;&#x3044;&#x304C;&#x65E5;&#x672C;&#x306E;wii&#x304C;&#x5FC5;&#x8981;&#x304C;&#x3042;&#x308B;&#x3053;&#x3068;&#x306F;&#x9762;&#x5012;&#x3067;&#x9AD8;&#x3044;&#x3067;&#x3059;&#x306D;&#x3002;&#x3057;&#x304B;&#x3082;&#x3001;&#x30DE;&#x30EA;&#x30AA;&#x306E;&#x30B2;&#x30FC;&#x30E0;&#x306F;&#x6587;&#x66F8;&#x304C;&#x5C11;&#x3057;&#x3057;&#x304B;&#x306A;&#x3044;&#x304B;&#x3089;&#x3001;&#x3084;&#x308B;&#x3053;&#x3068;&#x306F;&#x52C9;&#x5F37;&#x3067;&#x306F;&#x3042;&#x308A;&#x307E;&#x305B;&#x3093;&#x306D;&#x3002;&#x4ED6;&#x65B9;&#x3001;&#x30ED;&#x30FC;&#x30EB;&#x30D7;&#x30EC;&#x30A4;&#x30F3;&#x30B0;&#x30B2;&#x30FC;&#x30E0;&#x306F;&#x2026;&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/discipline/ps4.png&#x22;&#x3E;

&#x3C;p&#x3E;&#x52C9;&#x5F37;&#x3059;&#x3079;&#x304D;&#x3060;&#x304B;&#x3089;&#x3001;&#x30B9;&#x30FC;&#x30D1;&#x30FC;&#x30DE;&#x30EA;&#x30AA;&#x30AE;&#x30E3;&#x30E9;&#x30AF;&#x30B7;&#x30FC;2&#x3092;&#x3057;&#x3066;&#x308B;&#x6642;&#x306F;&#x3061;&#x3087;&#x3063;&#x3068;&#x6B8B;&#x5FF5;&#x3067;&#x3059;&#x3002;&#x3042;&#x308B;&#x8003;&#x3048;&#x304C;&#x601D;&#x3044;&#x6D6E;&#x304B;&#x3093;&#x3060;&#x3068;&#x601D;&#x3044;&#x307E;&#x3059;&#x3002;&#x305D;&#x308C;&#x305E;&#x308C;&#x306E;&#x30B9;&#x30BF;&#x30FC;&#x3092;&#x96C6;&#x3081;&#x308B;&#x3053;&#x3068;&#x306F;&#x3001;&#x4E00;&#x5B57;&#x306E;&#x6F22;&#x5B57;&#x3092;&#x7FD2;&#x3063;&#x305F;&#x3089;&#x2026;&#xFF1F;&#x591A;&#x3044;&#x30B9;&#x30BF;&#x30FC;&#x304C;&#x3042;&#x308B;&#x304B;&#x3089;&#x3001;&#x591A;&#x3044;&#x6F22;&#x5B57;&#x3092;&#x7FD2;&#x3046;&#x3067;&#x3057;&#x3087;&#x3046;&#x306D;&#x3002;&#x78BA;&#x304B;&#x306B;&#x5168;&#x3066;&#x306E;&#x30B9;&#x30BF;&#x30FC;&#x3092;&#x96C6;&#x3081;&#x3088;&#x3046;&#x3068;&#x3057;&#x307E;&#x3059;&#xFF01;&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x898F;&#x5F8B;&#x6B63;&#x3057;&#x3044;&#x751F;&#x6D3B;&#x3092;&#x51FA;&#x6765;&#x308B;&#x304B;&#x306A;&#xFF01;&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3061;&#x306A;&#x307F;&#x306B;&#x3001;&#x3053;&#x306E;&#x30D6;&#x30ED;&#x30B0;&#x3092;&#x66F8;&#x3044;&#x3066;&#x305F;&#x6642;&#x306F;&#x3001;&#x305F;&#x304F;&#x3055;&#x3093;&#x8F9E;&#x66F8;&#x3092;&#x5F15;&#x3044;&#x305F;&#x306E;&#x3067;&#x3001;&#x305F;&#x3076;&#x3093;&#x5206;&#x304B;&#x308A;&#x306B;&#x304F;&#x3044;&#x3067;&#x3059;&#x3002;&#x307E;&#x3060;&#x9811;&#x5F35;&#x3089;&#x306A;&#x304D;&#x3083;&#xFF01;&#x3C;/p&#x3E;
</description>
<dc:date>2010-09-12</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/09/piggybacking-motivation.html">
<title>Piggybacking Motivation</title>
<link>http://sartak.org/2010/09/piggybacking-motivation.html</link>
<description>
&#x3C;p&#x3E;&#x3C;a href=&#x22;/2010/09/&#x9811;&#x5F35;&#x3089;&#x306A;&#x304D;&#x3083;&#xFF01;.html&#x22;&#x3E;(&#x3053;&#x308C;&#x3092;&#x8A33;&#x3057;&#x307E;&#x3057;&#x305F;)&#x3C;/a&#x3E;&#x3C;/p&#x3E;

&#x3C;p&#x3E;I&#x27;m finally playing Super Mario Galaxy 2 after having been returned my long overdue Wii. I loved the first game to bits and from everything I&#x27;ve heard, this sequel is somehow even better.&#x3C;/p&#x3E;

&#x3C;p&#x3E;But! it&#x27;s in English and I&#x27;m learning Japanese. I could have gotten the Japanese version, but the Wii is region-locked so I&#x27;d have to get a Japanese Wii and that is a &#x3C;em&#x3E;lot&#x3C;/em&#x3E; of hassle. Plus, the game isn&#x27;t exactly chock-full of text, so it&#x27;s kind of cheating to call playing this studying. A JRPG, on the other hand...&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/discipline/ps4.png&#x22;&#x3E;

&#x3C;p&#x3E;Anyway, so I feel (only a little) bad about playing Galaxy 2 instead of studying. But maybe I can harness my massive desire to play the game by forcing myself to study before playing more. So, what if I demand &#x3C;b&#x3E;learning a new kanji&#x3C;/b&#x3E; (&#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Remembering_the_Kanji&#x22;&#x3E;the method for which&#x3C;/a&#x3E; I still need to write about) &#x3C;b&#x3E;for each star&#x3C;/b&#x3E;? This would result in lots of kanji learned, since the game has lots of stars. It&#x27;s also very likely that I will get every star because Mario games are goddamn &#x3C;em&#x3E;brilliant&#x3C;/em&#x3E;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The only question is: do I have the discipline to pull this off? Let&#x27;s find out...&#x3C;/p&#x3E;
</description>
<dc:date>2010-09-11</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/08/super-mario-world.html">
<title>Super Mario World</title>
<link>http://sartak.org/2010/08/super-mario-world.html</link>
<description>
&#x3C;p&#x3E;I was curious how the Japanese version of Super Mario World was different from what I grew up with, so I played it a little bit. Turns out it&#x27;s less different than I had expected. Given an in-game screenshot, there&#x27;s nothing that jumps out at me as being different.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/mario/ghosts.png&#x22; alt=&#x22;Ordinary screenshot of Super Mario World&#x22; /&#x3E;
&#x3C;p&#x3E;I expected at least one or both of the two words on the screen to have been written as &#x30DE;&#x30EA;&#x30AA; or &#x79D2;/&#x30BF;&#x30A4;&#x30E0;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;When you&#x27;re on the world map, the level names are in Japanese.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/mario/soda-lake.png&#x22; alt=&#x22;Super Mario World world map&#x22; /&#x3E;
&#x3C;p&#x3E;As is most of the rest of the in-game text, especially hint boxes, dialog, and narration. &#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/mario/castle.png&#x22; alt=&#x22;Mario destroying a castle&#x22; /&#x3E;
&#x3C;p&#x3E;Remember the Special Zone? You had to unlock it by finding the secret exit in the last level of the already-secret Star World. Your reward for beating this (difficult-to-my-8-year-old-self) Special Zone is a set of graphical changes: a sprite swap of many of the enemies and a slightly different world map.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/mario/special-zone.png&#x22; alt=&#x22;The Special Zone of SMW&#x22; /&#x3E;
&#x3C;p&#x3E;In English, these levels&#x27; names were taken from surfer slang.&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
 &#x3C;li&#x3E;Gnarly&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Tubular&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Way Cool&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Awesome&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Groovy&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Mondo&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Outrageous&#x3C;/li&#x3E;
 &#x3C;li&#x3E;Funky&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;I figured I&#x27;d play through and see what they originally were. Turns out there are only four names for the eight levels. The first and second level share a name, as do the third and fourth, etc.&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
 &#x3C;li&#x3E;&#x304A;&#x305F;&#x306E;&#x3057;&#x307F;&#x3000;&#x30B3;&#x30FC;&#x30B9; (&#x3C;em&#x3E;Fun Level&#x3C;/em&#x3E;)
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;&#x30DE;&#x30EA;&#x30AA;&#x30B9;&#x30BF;&#x30C3;&#x30D5;&#x3082;&#x30D3;&#x30C3;&#x30AF;&#x30EA;&#x3000;&#x30B3;&#x30FC;&#x30B9; (&#x3C;em&#x3E;Mario Staff Also Surprised Level&#x3C;/em&#x3E;)
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;&#x30B9;&#x30DA;&#x30B7;&#x30E3;&#x30EA;&#x30B9;&#x30C8;&#x306E;&#x305F;&#x3081;&#x306E;&#x30B3;&#x30FC;&#x30B9; (&#x3C;em&#x3E;Level for Specialists&#x3C;/em&#x3E;)
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;&#x30C1;&#x30E3;&#x30F3;&#x30D4;&#x30AA;&#x30F3;&#x30B7;&#x30C3;&#x30D7;&#x306E;&#x30B3;&#x30FC;&#x30B9; (&#x3C;em&#x3E;Level for the Championship&#x3C;/em&#x3E;)
 &#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;At the very end of Funky (the last Special Zone stage), you are rewarded with &#x27;YOU ARE A SUPER PLAYER!!&#x27; written with coins. I was hoping earning the championship would have netted me a &#x30B9;&#x30FC;&#x30D1;&#x30FC;&#x30D7;&#x30EC;&#x30FC;&#x30E4;&#x3060;&#x3088;&#xFF01;&#xFF01; or something. But instead it says &#x27;YOU ARE SUPER PLAYER!!&#x27; with the &#x27;A&#x27; article very much missing.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/mario/super-player.png&#x22; alt=&#x22;You are super player!!&#x22; /&#x3E;
&#x3C;p&#x3E;People I meet sometimes ask how I &#x3C;em&#x3E;learned&#x3C;/em&#x3E; Japanese (yeah, past tense, what?). This blog post forms part of that answer. I&#x27;m learning by having fun. :)
&#x3C;/p&#x3E;
</description>
<dc:date>2010-08-22</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/04/learning-japanese-with-sentences.html">
<title>Learning Japanese with Sentences</title>
<link>http://sartak.org/2010/04/learning-japanese-with-sentences.html</link>
<description>
&#x3C;h2&#x3E;Sentences&#x3C;/h2&#x3E;

&#x3C;p&#x3E;One of the major components of my Japanese study is &#x3C;em&#x3E;sentences&#x3C;/em&#x3E;. I add sentences written in Japanese to my &#x3C;a href=&#x22;http://blog.sartak.org/2010/01/on-learning.html&#x22;&#x3E;spaced repetition program&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://ichi2.net/anki/&#x22;&#x3E;Anki&#x3C;/a&#x3E;. When I review a sentence card, my job is to read the sentence aloud (to confirm that I know the readings for each kanji) and to understand the sentence.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_1&#x22; name=&#x22;footnote_back_1&#x22;&#x3E;[1]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;For simpler sentences which I know well, usually this is automatic and immediate. For new or complicated sentences, understanding sometimes demands translation into English. As I get more exposure to the language, my brain will get better at skipping that slow and lossy translation step. That&#x27;s the plan anyway!
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/gehennom.png&#x22; alt=&#x22;Reviewing a sentence&#x22; /&#x3E;
&#x3C;p&#x3E;Reviewing a sentence card where the answer and translation have both been revealed. &#x3C;a href=&#x22;http://www.jnethack.org/&#x22;&#x3E;jNetHack&#x3C;/a&#x3E; is a great source of sentences for me because I know NetHack so well.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;I &#x3C;strong&#x3E;always&#x3C;/strong&#x3E; translate &#x3C;em&#x3E;from&#x3C;/em&#x3E; Japanese &#x3C;em&#x3E;into&#x3C;/em&#x3E; English. Never the other way around. For one, the &#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Comprehensible_input&#x22;&#x3E;comprehensible input hypothesis&#x3C;/a&#x3E;, which is my guiding light for language study, suggests that production is only a side-effect of language ability, which is developed only when input is received. The input hypothesis even goes so far as to suggest that premature production is &#x3C;em&#x3E;harmful&#x3C;/em&#x3E;, because in doing so you are probably reinforcing incorrect usage.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_2&#x22; name=&#x22;footnote_back_2&#x22;&#x3E;[2]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;Also, more pragmatically, because I am not a native Japanese speaker, or even close to fluent, it is difficult for me to judge whether two sentences have the same meaning, or even similar nuance. So I would have trouble grading myself. This problem doesn&#x27;t occur when I am producing English, which I have a &#x3C;em&#x3E;bit&#x3C;/em&#x3E; more experience with. For Japanese, I rely only upon correct sentences written by native speakers, instead of whatever nonsense I come up with. :)
&#x3C;/p&#x3E;
&#x3C;p&#x3E;I also avoid studying soulless
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_3&#x22; name=&#x22;footnote_back_3&#x22;&#x3E;[3]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;vocabulary lists. Briefly, consider the difference between a &#x3C;em&#x3E;lethal injection&#x3C;/em&#x3E; and a &#x3C;em&#x3E;mortal injection&#x3C;/em&#x3E;. Because you&#x27;ve never heard of a mortal injection before,
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_4&#x22; name=&#x22;footnote_back_4&#x22;&#x3E;[4]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;it sounds wrong, even though &#x3C;em&#x3E;lethal&#x3C;/em&#x3E; and &#x3C;em&#x3E;mortal&#x3C;/em&#x3E; both mean &#x3C;em&#x3E;deadly&#x3C;/em&#x3E;.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;If I want to learn a new word, I force myself to find a complete sentence which uses it. So where am I getting these sentences? It turns out the answer is &#x22;from all over the place.&#x22; But before I can talk about that, I want to explain a bit more about Anki.&#x3C;/p&#x3E;
&#x3C;h2&#x3E;Facts vs Cards&#x3C;/h2&#x3E;
&#x3C;p&#x3E;Anki is great for separating &#x3C;em&#x3E;facts&#x3C;/em&#x3E; from &#x3C;em&#x3E;cards&#x3C;/em&#x3E;. A card is familiar; each has a front (the question) and a back (the answer). A fact, on the other hand, is a set of key/value pairs. You create a fact then generate one or more cards from it. For example, if you are studying world nations, you could have a fact for each country which includes Country Name, Capital, Languages, etc. Then you could generate many cards which test you on going from country to capital, country to language, capital to country, etc. Anki&#x27;s pleasant design turns out to be a great timesaver since it frees you from repeating yourself. You only type the country&#x27;s name once but it can be used in many cards.
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/nation.png&#x22; alt=&#x22;Creating a new fact in Anki&#x22; /&#x3E;
&#x3C;p&#x3E;This is fact creation screen, which you will see a lot.&#x3C;/p&#x3E;
&#x3C;br /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/generate.png&#x22; alt=&#x22;Generating cards from facts in Anki&#x22; /&#x3E;
&#x3C;p&#x3E;This is the card template screen, which you will rarely look at.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_5&#x22; name=&#x22;footnote_back_5&#x22;&#x3E;[5]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;
&#x3C;p&#x3E;We added only four facts, but from them we created twenty-eight cards, each of which tests a single piece of data. This way, your &#x22;language of Australia&#x22; card will be independently spaced from your &#x22;capital of Australia&#x22;, which is good when you have trouble with one of them. If you already know &#x22;English&#x22; but &#x22;Canberra&#x22; just won&#x27;t stick in your mind, that&#x27;s okay. You won&#x27;t have to review that the Australians use English nearly as often as you review their capital city.&#x3C;/p&#x3E;
&#x3C;h2&#x3E;Sources&#x3C;/h2&#x3E;
&#x3C;p&#x3E;One of the fields that my sentence facts have is &#x27;Source&#x27;. Other than the sentence itself, Source is the only field that I require myself to fill in. Translation, readings, context, etc. are optional. Knowing where each sentence came from is useful because it lets me gauge the trustworthiness of each sentence. I always trust the correctness of sentences uttered in, say, film, whereas an offhand remark on Twitter could easily have a typo or unusually playful grammar. It&#x27;s also useful to know whether I have accidentally incorporated feminine language into my lexicon.&#x3C;/p&#x3E;
&#x3C;p&#x3E;My diligence in citing every sentence I learn also lets me geek out and analyze precisely how I am learning Japanese. I wrote a script to pull all the values for the Source field out of the database and categorize them according to rules like:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synConstant&#x22;&#x3E;qr{The Matrix}&#x3C;/span&#x3E; =&#x26;gt; { speech, native, movie, source(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;The Matrix&#x26;quot;&#x3C;/span&#x3E;) },
&#x3C;span class=&#x22;synConstant&#x22;&#x3E;qr{iPod USB/dock cable box}&#x3C;/span&#x3E; =&#x26;gt; {
    text, native,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;medium&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;misc&#x27;&#x3C;/span&#x3E;,
    source(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Miscellaneous&#x26;quot;&#x3C;/span&#x3E;),
},
&#x3C;span class=&#x22;synConstant&#x22;&#x3E;qr{IRC PM with &#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;(\w+)&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;}&#x3C;/span&#x3E; =&#x26;gt; {
    student, correspondence, author(defer { &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$1&#x3C;/span&#x3E; }),
},
&#x3C;span class=&#x22;synConstant&#x22;&#x3E;qr{mt&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;endeworks&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;jp}&#x3C;/span&#x3E; =&#x26;gt; { blog(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;lestrrat&#x27;&#x3C;/span&#x3E;) },
&#x3C;span class=&#x22;synConstant&#x22;&#x3E;qr{Conversation at Ebisuya}&#x3C;/span&#x3E; =&#x26;gt; { convo, native },
&#x3C;/pre&#x3E;

&#x3C;h2&#x3E;My Input&#x3C;/h2&#x3E;
&#x3C;p&#x3E;Another component of my study is &#x3C;em&#x3E;immersion&#x3C;/em&#x3E;. I try to always have Japanese music in my environment. I can&#x27;t escape the deluge of Japanese tweets from those I follow. There&#x27;s also movies, books, IRC, and when I&#x27;m lucky even in-person conversation. I expose myself to as much Japanese-meant-for-native-speakers as possible. Every now and then I get a sentence I &#x3C;em&#x3E;almost&#x3C;/em&#x3E; understand, except for a word or a reading. For example, as for the sentence in the marked-up image at the top of this post, I already knew and understood everything except the reading for &#x9580; (gate) which is &#x3082;&#x3093; (mon). So for each so-called &#x3C;em&#x3E;i+1&#x3C;/em&#x3E; sentence
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_6&#x22; name=&#x22;footnote_back_6&#x22;&#x3E;[6]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;, I look up the one piece I&#x27;m missing then add it to Anki. Repeat until fluent.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;But this, for sanity&#x27;s sake, is tempered with Japanese-as-a-second-language materials. It would be frustrating to listen to and read complete gibberish all day, so I begrudingly use a &#x3C;a href=&#x22;http://www.guidetojapanese.org/learn/grammar&#x22;&#x3E;grammar guide&#x3C;/a&#x3E;. I also use various other second-language materials
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_7&#x22; name=&#x22;footnote_back_7&#x22;&#x3E;[7]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;, as long as they meet my impossibly high standards.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_8&#x22; name=&#x22;footnote_back_8&#x22;&#x3E;[8]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Turns out my setences are almost exactly evenly split between these two types. Eventually the number of sentences which are intended for native speakers will dwarf the sentences intended for students. I seem to be on the right track, as evidenced by this shiny chart
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_9&#x22; name=&#x22;footnote_back_9&#x22;&#x3E;[9]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;(the x-axis is of course time but the unit is unimportant).
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/audience.png&#x22; alt=&#x22;A chart of the intended audience by week&#x22; /&#x3E;
&#x3C;p&#x3E;It&#x27;s also interesting to look at the ratio of added sentences which I have &#x3C;em&#x3E;read&#x3C;/em&#x3E; (94%) versus sentences I have &#x3C;em&#x3E;heard&#x3C;/em&#x3E; (6%).
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/media-type.png&#x22; alt=&#x22;A chart of sentences I have read versus those I have heard&#x22; /&#x3E;
&#x3C;p&#x3E;There are a few reasons for this disparity. I am reluctant to add sentences from music. Though lyrics are usually grammatically correct, it&#x27;s fair to say they probably utilize some iffy language in order to fit the struture of the song. Also there&#x27;s the peculiarity of kanji and &#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Remembering_the_kanji&#x22;&#x3E;how I&#x27;m studying them&#x3C;/a&#x3E;. I do much better with words written in kanji than those nd usually not a lot of context is needed (as opposed to a sentence in the middle of a book). The games from which I&#x27;ve mined most are Phantasy Star 4 and jNetHack (which I beat yesterday!). I&#x27;m not really into anime, but the sentences I have are from Fist of the North Star:&#x3C;/p&#x3E;

&#x3C;object width=&#x22;480&#x22; height=&#x22;385&#x22;&#x3E;&#x3C;param name=&#x22;movie&#x22; value=&#x22;http://www.youtube.com/v/_N2pPrIxboI&#x26;hl=ja_JP&#x26;fs=1&#x26;rel=0&#x22;&#x3E;&#x3C;/param&#x3E;&#x3C;param name=&#x22;allowFullScreen&#x22; value=&#x22;true&#x22;&#x3E;&#x3C;/param&#x3E;&#x3C;param name=&#x22;allowscriptaccess&#x22; value=&#x22;always&#x22;&#x3E;&#x3C;/param&#x3E;&#x3C;embed src=&#x22;http://www.youtube.com/v/_N2pPrIxboI&#x26;hl=ja_JP&#x26;fs=1&#x26;rel=0&#x22; type=&#x22;application/x-shockwave-flash&#x22; allowscriptaccess=&#x22;always&#x22; allowfullscreen=&#x22;true&#x22; width=&#x22;480&#x22; height=&#x22;385&#x22;&#x3E;&#x3C;/embed&#x3E;&#x3C;/object&#x3E;

&#x3C;p&#x3E;It&#x27;s also worth noting that knowing the entire English script of The Matrix has been helpful for watching and learning from the Japanese dub. Just sayin&#x27;.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/sentences/matrix-pie.png&#x22; alt=&#x22;Truisms&#x22; /&#x3E;
&#x3C;p&#x3E;I got this idea of learning from sentences using spaced repetition from the guys at &#x3C;a href=&#x22;http://www.antimoon.com/&#x22;&#x3E;Antimoon&#x3C;/a&#x3E;. They learned English to native levels while living in Poland.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;In a year, I will rerun the script I used to generate these charts to see how they compare. In the meantime, I better get to back to &#x3C;a href=&#x22;http://twitter.com/sartak/status/12501182382&#x22;&#x3E;studying&#x3C;/a&#x3E;!
&#x3C;/p&#x3E;
&#x3C;h5&#x3E;Footnotes&#x3C;/h5&#x3E;
&#x3C;hr /&#x3E;
&#x3C;ol class=&#x22;footnotes&#x22;&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_1&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;I too-often have to mark sentence cards incorrect for flubbing a reading even though I &#x3C;em&#x3E;know&#x3C;/em&#x3E; what the sentence means. So I am sorely tempted to generate two separate cards for each sentence, one which tests readings and one which tests understanding. It would be easy to do, but I&#x27;m not entirely convinced that I should.
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_1&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_2&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Though, of course, it&#x27;s really fun to converse with speakers of your second language. The whole point of language is to communicate after all. So production there is fine. You just should not do it during review.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_2&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_3&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;I&#x27;ve been using this word a lot lately. It&#x27;s excellent.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_3&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_4&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Except when listening to language blowhards like me explain this point.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_4&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_5&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;If you&#x27;re familiar with &#x3C;a href=&#x22;http://moose.perl.org&#x22;&#x3E;Moose&#x3C;/a&#x3E;, then maybe a useful analogy is that the Add Facts screen is like &#x3C;code&#x3E;use Moose&#x3C;/code&#x3E;, but the Card Template screen is like delving into &#x3C;code&#x3E;Class::MOP&#x3C;/code&#x3E;.
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_5&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_6&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Here, &#x3C;em&#x3E;i&#x3C;/em&#x3E; is everything I understood about Japanese before adding the Gehennom sentence. &#x3C;em&#x3E;+1&#x3C;/em&#x3E; represents the reading of gate that I learned through SRSing this sentence. Now my &#x3C;em&#x3E;i&#x3C;/em&#x3E; is a little bit higher, and I&#x27;m a little bit more prepared for the next sentence.
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_6&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_7&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Such as various Japanese-English dictionaries. I haven&#x27;t started using a monolingual dictionary yet. That is a scary - but necessary - step to take. Very soon!&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_7&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_8&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;I avoid learning sentences written or spoken by fellow learners - even those who are far better than me with the language. Sorry! Nothing personal, but my goal is to eventually confuse people into thinking my first language is Japanese. :)&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_8&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_9&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;The charts in this post were generated with &#x3C;a href=&#x22;http://p3rl.org/Chart::Clicker&#x22;&#x3E;Chart::Clicker&#x3C;/a&#x3E;, written by the inimitable &#x3C;a href=&#x22;http://www.onemogin.com/&#x22;&#x3E;Cory Watson&#x3C;/a&#x3E;. Any anti-Tuftean errors are mine, not the module&#x27;s.
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_9&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
</description>
<dc:date>2010-04-20</dc:date>
</item>
<item rdf:about="http://sartak.org/2010/01/on-learning.html">
<title>On Learning</title>
<link>http://sartak.org/2010/01/on-learning.html</link>
<description>
&#x3C;p&#x3E;At a party last night, I explained spaced repetition and Anki to two separate groups of people.&#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_1&#x22; name=&#x22;footnote_back_1&#x22;&#x3E;[1]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E; I&#x26;#39;m really enthusiastic about Anki so I&#x26;#39;m shooting for as many converts as I can in a twenty-four hour period.
&#x3C;/p&#x3E;
&#x3C;h2&#x3E;Spaced Repetition&#x3C;/h2&#x3E;
&#x3C;p&#x3E;
 &#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Spaced_repetition&#x22;&#x3E;Spaced repetition&#x3C;/a&#x3E; is the principle that the best time to review a fact is just before you forget it.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;If spaced repetition weren&#x26;#39;t so effective, I bet the advertising industry would be far smaller. Try completing these slogans:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
 &#x3C;li&#x3E;I can&#x26;#39;t believe it&#x26;#39;s not 
  &#x3C;span class=&#x22;spoiler&#x22;&#x3E;butter&#x3C;/span&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;Melts in your mouth, not in your 
  &#x3C;span class=&#x22;spoiler&#x22;&#x3E;hand&#x3C;/span&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;Just do 
  &#x3C;span class=&#x22;spoiler&#x22;&#x3E;it&#x3C;/span&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li&#x3E;The breakfast of 
  &#x3C;span class=&#x22;spoiler&#x22;&#x3E;champions&#x3C;/span&#x3E;
 &#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;You haven&#x26;#39;t explicitly memorized these slogans, but I bet you&#x26;#39;d be hard-pressed to forget them. &#x26;#40;Most of?&#x26;#41; you know them effortlessly because you see and hear them every now and then. The same principle underlies spaced repetition.&#x3C;/p&#x3E;
&#x3C;p&#x3E;A spaced repetition system &#x26;#40;SRS&#x26;#41; is basically a program that tests you using flash cards. The major departure from an ordinary flash card program is that an SRS has a &#x3C;em&#x3E;scheduler&#x3C;/em&#x3E; which decides when to test you on each fact. The scheduling of a fact is influenced by how well you know that fact. That&#x26;#39;s the essence of an SRS; many SRS programs have all sorts of extra functionality on top of that since they&#x26;#39;re used &#x26;#40;and developed&#x26;#41; by people who are humorlessly serious about learning. Like me.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;I really like spaced repetition because it is rarely boring. You are never bogged down reviewing the same dozen cards that you &#x3C;em&#x3E;know&#x3C;/em&#x3E;. With traditional flash cards, facts you know very well and facts you don&#x26;#39;t have the same precedence. Spaced repetition software tests you on facts you know well far less often than facts you don&#x26;#39;t know well yet. Unlike people, not all facts are created equal. You don&#x26;#39;t need to review every day that Boston is the capital of Massachusetts, especially if that&#x26;#39;s where you live. On the other hand, you may need to be reminded often that Regina is the capital of Saskatchewan. I sure do. Who even lives there.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Ready for another example? The kanji &#x96D1; &#x26;#40;miscellaneous&#x26;#41; is pretty new to me, so I&#x26;#39;m likely to see it again in the next day or two. On the other hand, every time I&#x26;#39;ve been tested on the kanji &#x526F; &#x26;#40;vice-&#x26;#41; I&#x26;#39;ve gotten it correct, so I&#x26;#39;m not going to see it again for four months. And I bet I will remember it come May. If not, Anki will adjust the card&#x26;#39;s interval accordingly.&#x3C;/p&#x3E;
&#x3C;p&#x3E;As of this writing I have 960 cards in my deck. It would take hours to review all of them every night. Not to mention that such reviews would be boring as hell, since I know most of the facts very well.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_2&#x22; name=&#x22;footnote_back_2&#x22;&#x3E;[2]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;Thanks to spaced repetition knowing that I am capable of &#x3C;em&#x3E;learning&#x3C;/em&#x3E;, I review only about 64 cards per day. That may still seem like a lot, but such a review takes only fifteen or twenty minutes a day. I&#x26;#39;ll gladly review 64 distinct cards a day over doing hundreds &#x26;#40;thousands?&#x26;#41; of repetitions of the same set of flash cards the night before an exam. Furthermore, SRS is designed to build memories that last longer than a semester.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Most spaced repetition systems will actually let you grade yourself based on how well you know the fact. There&#x26;#39;s obviously a large gap between struggling to recall a fact before eventually getting it and having the answer pop into your head before you even finish reading the question. You will see cards of the former type more often than cards of the latter type.&#x3C;/p&#x3E;
&#x3C;h2&#x3E;Anki&#x3C;/h2&#x3E;
&#x3C;p&#x3E;
 &#x3C;a href=&#x22;http://ichi2.net/anki/&#x22;&#x3E;Anki&#x3C;/a&#x3E; is one of the best spaced repetition systems. I use it to learn Japanese. I trust Anki so much that I feel if my deck lacks a particular word, phrase, kanji, or proper name, then &#x3C;em&#x3E;I do not know it&#x3C;/em&#x3E;.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;I have recently begun to use Anki for more than just Japanese. I have a Miscellaneous deck into which I put whatever I feel is worth knowing. I learn state capitals, Canadian province capitals
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_3&#x22; name=&#x22;footnote_back_3&#x22;&#x3E;[3]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;, and words that I am not comfortable using in a sentence or whose definitions are vague. I should also start putting in different kinds of things like maps with one country&#x26;#39;s label erased and Perl&#x26;#39;s more unusual special variables. Maybe I&#x26;#39;ll even prepare for the CPAN drinking game. :&#x26;#41; Getting more exotic, there are people who put 
 &#x3C;a href=&#x22;http://supermemoadventures.blogspot.com/2009/12/art.html&#x22;&#x3E;art&#x3C;/a&#x3E; into the SRS to learn more about art history, and even quotes from 
 &#x3C;a href=&#x22;http://www.alljapaneseallthetime.com/blog/why-the-way-we-read-sucks-and-how-to-fix-it-part-4-why-srs-personal-development-books&#x22;&#x3E;personal development books&#x3C;/a&#x3E; so that the ideas are constantly in mind, which is more likely to effect change.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;I am not in school any more, but if I were, I would definitely have an Anki deck for each of my classes.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I used Anki to learn the Japanese poem 
 &#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Iroha&#x22;&#x3E;Iroha&#x3C;/a&#x3E;. I&#x26;#39;m not very into poetry, but Iroha is worth knowing for several reasons. It&#x26;#39;s a pangram of the &#x26;#40;circa 1000AD&#x26;#41; Japanese syllabary, so it immediately has Cool Points. The order of the kana in Iroha is still used in modern Japan for labeling Go boards and theater seats. I use it to practice writing all the kana.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;Iroha is far too long to use only one card, so the best way to learn it &#x26;#40;as pointed out by 
 &#x3C;a href=&#x22;http://study-shack.com/creating-cards-models-for-all-classes&#x22;&#x3E;Study Shack&#x3C;/a&#x3E;&#x26;#41; is by using eight cards, one for each line of the poem. Each card has a different line blanked out and your job is to produce the missing line. Here&#x26;#39;s what Anki&#x26;#39;s review interface looks like &#x26;#40;with the answer revealed in the lower half&#x26;#41;:
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/iroha.png&#x22; /&#x3E;
&#x3C;p&#x3E;Anki has a convenient feature called &#x26;#39;cloze deletion&#x26;#39; that makes creating eight similar cards like this take only a minute.&#x3C;/p&#x3E;
&#x3C;p&#x3E;By the way seeing the other seven lines of the poem in every card is like even more spaced repetition, for free.&#x3C;/p&#x3E;
&#x3C;h3&#x3E;Design&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Facts are not limited to a front and back. Each fact belongs to a &#x3C;em&#x3E;model&#x3C;/em&#x3E;. The model lets you control which fields are available &#x26;#40;including requiredness and uniqueness constraints on each field&#x26;#41;. Some models I use are Sentence &#x26;#40;which has fields &#x65E5;&#x672C;&#x8A9E;, Meaning, Readings, and Source&#x26;#41; and Capital &#x26;#40;Region, Capital&#x26;#41;. Models also control how cards of that model are displayed.
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/model.png&#x22; /&#x3E;
&#x3C;p&#x3E;As you can see, you can also generate several cards from a single fact. Not only do I want to test myself to be able to produce the capital of a given region, but I also want to test myself on producing a region given just its capital city.&#x3C;/p&#x3E;
&#x3C;p&#x3E;You can have as many fields in a model as you want, and you can generate many different types of cards for each fact. You could create eight cards based on ten fields if you were so inclined. This is powerful stuff! Anki lets you uphold the Don&#x26;#39;t Repeat Yourself principle dear to many programmers.&#x3C;/p&#x3E;
&#x3C;h3&#x3E;Interface&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Anki has a lot of gears and widgets, but what matters most is the interface you see when you&#x26;#39;re reviewing a fact. It may not look like it, but Anki&#x26;#39;s review interface is actually a fully-featured web browser. &#x3C;em&#x3E;With Javascript.&#x3C;/em&#x3E; It has, for example, 
 &#x3C;code&#x3E;alert&#x26;#40;&#x26;#41;&#x3C;/code&#x3E;. Providing a full web browser gives Anki basically limitless flexibility!
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/alert.png&#x22; /&#x3E;
&#x3C;p&#x3E;Being able to use arbitrary fields in a model works out amazingly well when you have Javascript at your disposal. You can make one of the fields a YouTube video and show it if you want.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_4&#x22; name=&#x22;footnote_back_4&#x22;&#x3E;[4]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;
&#x3C;h3&#x3E;Plugins&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Anki is written in Python. Not only is its UI extensible, but the backend seems to be designed that way as well. There are a dozens of plugins that are easily available in File &#x26;gt; Download &#x26;gt; Shared Plugin. A lot of them offer incremental improvements, but there are two that have made Anki significantly better for me.&#x3C;/p&#x3E;
&#x3C;h4&#x3E;Learn Mode&#x3C;/h4&#x3E;
&#x3C;p&#x3E;I&#x26;#39;ve noticed a nasty corner case of spaced repetition as implemented by Anki. If you get a &#x26;#40;usually brand new&#x26;#41; card wrong, you&#x26;#39;ll see it again very soon, sometime within the same review. You&#x26;#39;ll probably then remember it easily thanks to short-term memory &#x26;#40;or perhaps very fleeting long-term memory&#x26;#41;. So you mark it honestly, as a three, which schedules it for review in two or three days. By the time you review it again you&#x26;#39;ll have forgoten it. Lame.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The Learn mode plugin alleviates this problem by performing a review with &#x3C;em&#x3E;much&#x3C;/em&#x3E; shorter intervals. Cards are scheduled only seconds and minutes in the future, rather than d until there are no more cards for review &#x26;#40;since they&#x26;#39;rel scheduled a few minutes into the future&#x26;#41;. This usually results in 10 or 15 reviews for each fact. Then I go back to the  Anki on your iPod or iPhone. You sync with regular Anki using http over wifi; the plugin provides a web server.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_5&#x22; name=&#x22;footnote_back_5&#x22;&#x3E;[5]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;There&#x26;#39;s another interface if your iPod/iPhone is jailbroken - Anki Mini - with more features but I had less luck in getting it to work correctly.
&#x3C;/p&#x3E;
&#x3C;p&#x3E;The iAnki interface is much simpler than Anki&#x26;#39;s.  You can&#x26;#39;t add or edit cards, or even look at your card list. You can use iAnki only to review. Despite that, iAnki is still worth having. Maybe someday they &#x26;#40;or I!&#x26;#41; will add lots more functionality.&#x3C;/p&#x3E;
&#x3C;p&#x3E;When learning kanji it&#x26;#39;s really important to practice writing them out. For a while I used the air or the back of my hand. Turns out I&#x26;#39;m way too forgiving of errors when I do that. So I really wanted a canvas directly in iAnki that I could use to grade myself properly.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I found 
 &#x3C;a href=&#x22;http://www.mblondel.org/journal/2008/08/01/web-canvas/&#x22;&#x3E;Web Canvas&#x3C;/a&#x3E; which turned out to be quite good in terms of functionality and ease-of-use. I had to patch it to accept my iPod&#x26;#39;s touch gestures &#x26;#40;which was incorporated upstream&#x26;#41; but after that it was pretty smooth sailing. (update: I&#x27;ve also submitted some &#x3C;a href=&#x22;http://github.com/sartak/ianki&#x22;&#x3E;patches&#x3C;/a&#x3E; to iAnki itself). Here&#x26;#39;s what my iAnki looks like for testing a kanji:
&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/IMG_0021.PNG&#x22; /&#x3E;
&#x3C;p&#x3E;This is asking us to produce the kanji for &#x26;#34;frost&#x26;#34;.&#x3C;/p&#x3E;
&#x3C;br /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/IMG_0023.PNG&#x22; /&#x3E;
&#x3C;p&#x3E;If I have trouble remembering the kanji, I can look at the primitive story of the kanji. Stories are a peculiarity of the 
 &#x3C;a href=&#x22;http://www.amazon.com/gp/product/0824831659?ie=UTF8&#x26;#38;tag=sartak-20&#x26;#38;linkCode=as2&#x26;#38;camp=1789&#x26;#38;creative=390957&#x26;#38;creativeASIN=0824831659&#x22;&#x3E;method I am using to learn kanji&#x3C;/a&#x3E; which will be the topic of another post. The &#x26;#34;&#x26;#40;primitives&#x26;#41;&#x26;#34; link had a javascript onclick handler that replaced itself with the story. Hiding the story behind a link is handy because I usually do not want to see the story unless I am stuck.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_6&#x22; name=&#x22;footnote_back_6&#x22;&#x3E;[6]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;
&#x3C;br /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/IMG_0024.PNG&#x22; /&#x3E;
&#x3C;p&#x3E;Now I&#x26;#39;ve written out the kanji. As fun as touchscreens are, it&#x26;#39;s &#x3C;em&#x3E;really&#x3C;/em&#x3E; hard to demonstrate good penmanship with them. This is actually embarrassingly bad.
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_7&#x22; name=&#x22;footnote_back_7&#x22;&#x3E;[7]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;
&#x3C;br /&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/IMG_0025.PNG&#x22; /&#x3E;
&#x3C;p&#x3E;Finally I check the answer against what I wrote. Since I got this correct, and I recalled it effortlessly, I marked it as a four. Anki scheduled this kanji to appear again in about eight weeks.&#x3C;/p&#x3E;
&#x3C;h3&#x3E;Graphs&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Most importantly, Anki lets you measure your worth with graphs and statistics! This is a graph of facts I&#x26;#39;ve added over the past month. The spike on the fifth is when I played Phantasy Star IV
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_8&#x22; name=&#x22;footnote_back_8&#x22;&#x3E;[8]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;all day and added a bunch of sentences.
&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/graph.png&#x22; /&#x3E;
&#x3C;p&#x3E;It also tells you how difficult each card is. So here are the cards that trouble me most. I should give them special treatment, such as cramming them for a while or something.&#x3C;/p&#x3E;
&#x3C;img src=&#x22;http://sartak.org/misc/blog/anki/ease.png&#x22; /&#x3E;
&#x3C;p&#x3E;All of your cards are stored in a SQLite database so if Anki doesn&#x26;#39;t offer exactly the kind of information you want, you can still get at it. I used the database directly to produce a 
 &#x3C;a href=&#x22;http://sartak.org/misc/kanji.html&#x22;&#x3E;calendar of kanji&#x3C;/a&#x3E; I&#x26;#39;ve learned. That was a little worrying; I didn&#x26;#39;t realize how few kanji I learned in November and December &#x26;#40;compared to October&#x26;#41;. But for the same reason it was also motivating.
&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;Anki is a wonderful program. &#x3C;strong&#x3E;I will use Anki and its successors for the rest of my life.&#x3C;/strong&#x3E; It&#x26;#39;s almost too bad Anki is free software.. I would have liked to be able to retire on commission. ;&#x26;#41;
 &#x3C;sup&#x3E;
  &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_9&#x22; name=&#x22;footnote_back_9&#x22;&#x3E;[9]&#x3C;/a&#x3E;
 &#x3C;/sup&#x3E;
&#x3C;/p&#x3E;

&#x3C;p&#x3E;If I&#x27;ve sold you on SRS then download &#x3C;a href=&#x22;http://ichi2.net/anki/&#x22;&#x3E;Anki&#x3C;/a&#x3E; then head on over to the &#x3C;a href=&#x22;http://study-shack.com/table-of-contents&#x22;&#x3E;Study Shack&#x3C;/a&#x3E; which talks about what kind of cards are good, and other SRS management tips.&#x3C;/p&#x3E;

&#x3C;hr /&#x3E;
&#x3C;h5&#x3E;Footnotes&#x3C;/h5&#x3E;
&#x3C;ol class=&#x22;footnotes&#x22;&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_1&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Yes I know I attend wild parties. :&#x26;#41;&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_1&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_2&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Similarly, writing this is boring as hell because I know all of this. But you don&#x26;#39;t. So you&#x26;#39;re welcome. As if you were even grateful to begin with... Just get out my face and click this:&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_2&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_3&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Do you remember the capital of Saskatchewan? It&#x26;#39;s still 
   &#x3C;span class=&#x22;spoiler&#x22;&#x3E;Regina&#x3C;/span&#x3E;
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_3&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_4&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;I don&#x26;#39;t know. That&#x26;#39;s a useless example. I have a better one later. It lives between where you came from and where you are now.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_4&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_5&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;The web server is WSGI-based. Also the Javascript bits of iAnki use Joose. We have these things in Perl F.Y.I.!&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_5&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_6&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;This is the better example I was talking about. Case closed.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_6&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_7&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;In ten years I&#x26;#39;m going to happen upon this image and cry.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_7&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_8&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;which owns
   &#x3C;sup&#x3E;
    &#x3C;a class=&#x22;footnote_link&#x22; href=&#x22;#footnote_10&#x22; name=&#x22;footnote_back_10&#x22;&#x3E;[10]&#x3C;/a&#x3E;
   &#x3C;/sup&#x3E;
  &#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_8&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_9&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Quick! Capital of Saskatchewan! Go! Don&#x26;#39;t look at footnote 3 either.&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_9&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
 &#x3C;li class=&#x22;footnote&#x22;&#x3E;
  &#x3C;a name=&#x22;footnote_10&#x22;&#x3E;&#x3C;/a&#x3E;
  &#x3C;span class=&#x22;footnote_content&#x22;&#x3E;Sorry about all the footnotes. I made it really easy to make them. :&#x26;#41;&#x3C;/span&#x3E;
  &#x3C;sup&#x3E;
   &#x3C;a href=&#x22;#footnote_back_10&#x22; class=&#x22;footnote_link_top&#x22;&#x3E;&#x26;#8617;&#x3C;/a&#x3E;
  &#x3C;/sup&#x3E;
 &#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
</description>
<dc:date>2010-01-01</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/10/jifty-s-request-inspector.html">
<title>Jifty&#x27;s Request Inspector</title>
<link>http://sartak.org/2009/10/jifty-s-request-inspector.html</link>
<description>
&#x3C;p&#x3E;&#x3C;a href=&#x22;http://jifty.org&#x22;&#x3E;Jifty&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://p3rl.org/Jifty::Plugin::RequestInspector&#x22;&#x3E;RequestInspector plugin&#x3C;/a&#x3E; provides you with debugging information for HTTP requests. You can examine the SQL queries that were issued in servicing the request, inspect a &#x3C;a href=&#x22;http://p3rl.org/Devel::NYTProf&#x22;&#x3E;Devel::NYTProf&#x3C;/a&#x3E; profile of the request, and more. The information is presented in an (admittedly ugly) admin panel. Here&#x27;s what our &#x3C;a href=&#x22;https://github.com/bestpractical/App-Changeloggr&#x22;&#x3E;Changelogger&#x3C;/a&#x3E;&#x27;s request inspector page looks like:&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/requestinspector-basic.png&#x22; /&#x3E;

&#x3C;p&#x3E;If we click into one of the requests, we can get an overview of that request.&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/requestinspector-request.png&#x22; /&#x3E;

&#x3C;p&#x3E;We can inspect in detail a particular part of a request with another click.&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/requestinspector-dumpreqres.png&#x22; /&#x3E;

&#x3C;h2&#x3E;Backend&#x3C;/h2&#x3E;

&#x3C;p&#x3E;The frontend is good enough. It gets the job done. But what I am really interested in, and what I had far more fun creating, is the backend that powers this.&#x3C;/p&#x3E;

&#x3C;p&#x3E;RequestInspector is a Jifty plugin. Its job is to manage all of the other plugins that inspect requests (such as &#x3C;a href=&#x22;http://p3rl.org/Jifty::Plugin::SQLQueries&#x22;&#x3E;SQLQueries&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://p3rl.org/Jifty::Plugin::DumpRequestResponse&#x22;&#x3E;DumpRequestResponse&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://p3rl.org/Jifty::Plugin::NYTProf&#x22;&#x3E;NYTProf&#x3C;/a&#x3E;, and &#x3C;a href=&#x22;http://p3rl.org/Jifty::Plugin::Gladiator&#x22;&#x3E;Gladiator&#x3C;/a&#x3E;). RequestInspector informs the plugins of interesting events such as: a new request is beginning, that request finished.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Each plugin produces various kinds of data. That data is &#x3C;em&#x3E;completely opaque&#x3C;/em&#x3E; to RequestInspector. The data can be an object, a number, a code reference, or whatever else. All RequestInspector does is keep track of that data, handing the data to the plugin when it needs to do something with the data.&#x3C;/p&#x3E;

&#x3C;p&#x3E;When a new request begins, RequestInspector calls the &#x3C;tt&#x3E;inspect_before_request&#x3C;/tt&#x3E; method on each plugin. When the request ends, &#x3C;tt&#x3E;inspect_after_request&#x3C;/tt&#x3E; is called on each plugin. The interesting bit is that the opaque data is threaded between the return values and parameters of these methods. The return value of &#x3C;tt&#x3E;inspect_before_request&#x3C;/tt&#x3E; is passed to that plugin&#x27;s &#x3C;tt&#x3E;inspect_after_request&#x3C;/tt&#x3E;. &#x3C;tt&#x3E;inspect_after_request&#x3C;/tt&#x3E;&#x27;s return value is stored for later rendering. (In what amounts to a global variable &#x26;mdash; sorry!)&#x3C;/p&#x3E;

&#x3C;p&#x3E;When the user wants to see a request, RequestInspector calls the &#x3C;tt&#x3E;inspect_render_summary&#x3C;/tt&#x3E; method on each plugin. When the user wants to see the detailed analysis by a particular plugin for a particular request, RequestInspector calls the &#x3C;tt&#x3E;inspect_render_analysis&#x3C;/tt&#x3E; method on that plugin. It is completely up to the plugin to decide what to render. Both methods receive the data it returned from &#x3C;tt&#x3E;inspect_after_request&#x3C;/tt&#x3E; for that request.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Benefits&#x3C;/h3&#x3E;

&#x3C;p&#x3E;You might wonder why this design is better than, say, a specific data format to which each plugin must adhere.&#x3C;/p&#x3E;

&#x3C;p&#x3E;It is unclear what such a data format would look like. I don&#x27;t think a single data format could usefully encompass the different kinds of data that these plugins produce. While SQLQueries&#x27;s data is complex data structure with a lot of information, NYTProf&#x27;s is basically just a random number used to track the on-disk profile directory.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The format would certainly evolve over time. This means that plugins would have to change as well just to keep up with RequestInspector. With my design, plugins really only need to change when they want to support newer RequestInspector features.&#x3C;/p&#x3E;

&#x3C;p&#x3E;It&#x27;s simpler for plugins to let &#x3C;em&#x3E;them&#x3C;/em&#x3E; dictate how they want to store whatever they are tracking. It&#x27;s simpler for the RequestInspector core too, since it is free from having to examine the plugins&#x27; data.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Finally, the RequestInspector plugin can get arbitrarily complex and the plugins do not have to care about it. The RequestInspector already lets you filter out URLs you know you will not want to inspect. The individual request inspector plugins do not have to implement that functionality.&#x3C;/p&#x3E;

&#x3C;p&#x3E;In the future, I plan to add a feature to RequestInspector that lets you see which requests took the most amount of database time, or leaked the most amount of memory, etc. All the feature will require of plugins is that they implement an optional &#x3C;tt&#x3E;inspect_compare_requests&#x3C;/tt&#x3E; method. The method will receive that plugin&#x27;s data from two requests and returns -1, 0, or 1. So trivial that I should just do it now.. :)&#x3C;/p&#x3E;

&#x3C;p&#x3E;Basically, RequestInspector leverages the &#x3C;a href=&#x22;http://en.wikipedia.org/wiki/Principle_of_least_knowledge&#x22;&#x3E;Principle of Least Knowledge&#x3C;/a&#x3E; to keep things simple, easy, and flexible. Shriram Krishnamurthi&#x27;s &#x3C;a href=&#x22;http://www.international-lisp-conference.org/2009/speakers#krishnamurthi_shriram&#x22;&#x3E;Moby Scheme Compiler&#x3C;/a&#x3E; talk was particularly influential on this design. He described a similar (though simpler) system that he uses to make programming fun and interesting for middle school kids.&#x3C;/p&#x3E;
</description>
<dc:date>2009-10-07</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/09/google-wave-mania.html">
<title>Google Wave Mania</title>
<link>http://sartak.org/2009/09/google-wave-mania.html</link>
<description>
&#x3C;p&#x3E;I&#x27;ve been on Google Wave since June 11th, thanks to a friend at Google. I haven&#x27;t been using the account much due to other pursuits in my life. But tonight, since they&#x27;re rolling to production (I&#x27;m in as sartak@googlewave.com), they gave those in the developer preview invitations. Since I know a lot of people are very excited about Google Wave I thought I would be fair and ask on Twitter...&#x3C;/p&#x3E;

&#x3C;blockquote&#x3E;I have google wave invites. DM me if you want one.&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;Almost immediately I was flooded with random people who have been scouring Twitter for idiots like me.&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/wave-twitter.png&#x22; /&#x3E;

&#x3C;p&#x3E;They also followed me on Twitter because that will help their chances I guess?? (edit: miyagawa pointed out that they did this so I could DM them their invitation)&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/wave-gmail.png&#x22; /&#x3E;

&#x3C;p&#x3E;Of course, friends who saw my tweet pestered me elsewhere too..&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/wave-irc.png&#x22; /&#x3E;

&#x3C;p&#x3E;I lacked the foresight to turn off the DM-to-cell-phone Twitter notifications.&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/wave-phone.png&#x22; /&#x3E;

&#x3C;p&#x3E;Dayum... Google really knows how to generate interest.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Update: Oh god it will never end&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/wave-jshirley.png&#x22; /&#x3E;
</description>
<dc:date>2009-09-30</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/09/yapc-asia-2009-moose-course.html">
<title>YAPC::Asia 2009 Moose Course</title>
<link>http://sartak.org/2009/09/yapc-asia-2009-moose-course.html</link>
<description>
&#x3C;a href=&#x22;http://www.flickr.com/photos/sartak/3921128445/&#x22; title=&#x22;Moose course by sartak, on Flickr&#x22;&#x3E;&#x3C;img src=&#x22;http://farm3.static.flickr.com/2451/3921128445_ffa1471fef.jpg&#x22; width=&#x22;500&#x22; height=&#x22;375&#x22; alt=&#x22;Moose course&#x22; /&#x3E;&#x3C;/a&#x3E;

&#x3C;p&#x3E;I have received a lot of good feedback about my &#x3C;a href=&#x22;http://conferences.yapcasia.org/ya2009/&#x22;&#x3E;YAPC::Asia 2009&#x3C;/a&#x3E; &#x3C;a href=&#x22;http://moose.perl.org&#x22;&#x3E;Moose&#x3C;/a&#x3E; &#x3C;a href=&#x22;http://conferences.yapcasia.org/ya2009/talk/2192&#x22;&#x3E;course&#x3C;/a&#x3E;. Several people on IRC and Twitter &#x3C;a href=&#x22;http://twitter.com/lesamoureuses/statuses/4029397889&#x22;&#x3E;thanked me&#x3C;/a&#x3E;. I got second-hand reports of students taking the course then immediately being able to write useful Moose code. That is nothing short of ideal. It makes me very happy that people not only enjoyed the course, but that it was practical.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Several people also wrote blog posts about the course&#x27;s content and my presentation.&#x3C;/p&#x3E;

&#x3C;ul&#x3E;
    &#x3C;li&#x3E;lesamoureuses&#x27;s &#x3C;a href=&#x22;http://d.hatena.ne.jp/lesamoureuses/20090915/1253023402&#x22;&#x3E;YAPC::Asia2009&#x306E;&#x7279;&#x5225;&#x7814;&#x4FEE;&#x300C;Moose&#x5165;&#x9580;&#x3001;&#x30E2;&#x30C0;&#x30FC;&#x30F3;&#x306A;&#x30AA;&#x30D6;&#x30B8;&#x30A7;&#x30AF;&#x30C8;&#x6307;&#x5411;&#x30B7;&#x30B9;&#x30C6;&#x3E;&#x30E0;&#x300D;&#x304C;&#x8D85;&#x826F;&#x304B;&#x3063;&#x305F;&#xFF01;&#x3C;/a&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;ziguzagu&#x27;s &#x3C;a href=&#x22;http://ziguzagu.org/2009/09/yapcasia-2009--.html&#x22;&#x3E;YAPC::Asia 2009 &#x7279;&#x5225;&#x7814;&#x4FEE; - Moose &#x5165;&#x9580;&#x3C;/a&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;Gardejo&#x27;s &#x3C;a href=&#x22;http://blog.eorzea.asia/2009/09/post_65.html&#x22;&#x3E;Moose&#x306E;&#x4E2D;&#x306E;&#x4EBA;&#x306B;&#x3088;&#x308B;Moose&#x7814;&#x4FEE;&#x304C;&#x7D20;&#x6674;&#x3089;&#x3057;&#x3059;&#x304E;&#x308B; (YAPC::Asia 2009)&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;

&#x3C;p&#x3E;As expected, the students loved the exercises. I feel very strongly that the exercises are the best part of the course. They force you to make sure you &#x3C;em&#x3E;understand&#x3C;/em&#x3E; what you have just learned. It&#x27;s handy to have a Moose man there to help students when they get stuck. My only regret about this iteration of the course is that we had to skip the last two exercises for time constraints. To the students&#x27; credit, every single one did stay well over an hour past the scheduled end time.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I was pleasantly surprised that I received such nice remarks about my live coding. As these are not my slides, I sometimes had to dive into vim to explain a tangential point about Moose. For example, demonstrating the use of &#x3C;tt&#x3E;has&#x3C;/tt&#x3E; after &#x3C;tt&#x3E;__PACKAGE__-&#x26;gt;meta-&#x26;gt;make_immutable&#x3C;/tt&#x3E; (which led to &#x3C;a href=&#x22;http://rt.cpan.org/Public/Bug/Display.html?id=49680&#x22;&#x3E;a bug report&#x3C;/a&#x3E; and then &#x3C;a href=&#x22;http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo/Class-MOP.git;a=commitdiff;h=e347ce3fe9e40dc060e73e07f282729f4191c878&#x22;&#x3E;a bug fix&#x3C;/a&#x3E; &#x26;mdash; all during the course!). I very much enjoy this style of presentation, but it is difficult to come up with real examples on the fly. It feels great when it all just works.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I had a whole lot of help in making this course happen. A very big thanks to &#x3C;b&#x3E;Daisuke Maki&#x3C;/b&#x3E; and the &#x3C;a href=&#x22;http://japan.perlassociation.org/jpa&#x22;&#x3E;Japan Perl Association&#x3C;/a&#x3E; for establishing and marketing the course (and of course running this excellent YAPC::Asia!). Thanks to &#x3C;b&#x3E;Emerson Mills&#x3C;/b&#x3E; for working with me to make the course happen, and for translating the exercises. Thanks to &#x3C;b&#x3E;Nathaniel&#x3C;/b&#x3E; for interpreting my presentation. I did not make it easy for him! Thanks to &#x3C;b&#x3E;Kenichi Ishigaki&#x3C;/b&#x3E; (charsbar++) for helping out with translation, for buying (with his own money) my throat lots of tea, and for being generally awesome. Thanks to all of the students for asking very good, deep questions. It&#x27;s very satisfying to know one&#x27;s audience is attentive and thoughtful. Finally, thanks to &#x3C;b&#x3E;Dave Rolsky&#x3C;/b&#x3E; for letting me use his &#x3C;a href=&#x22;http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo/moose-presentations.git;a=tree;f=moose-class&#x22;&#x3E;course material&#x3C;/a&#x3E; yet again. Next week he at long last gets to &#x3C;a href=&#x22;http://blog.urth.org/2009/09/moose-class-in-minneapolis-september-23-2009.html&#x22;&#x3E;teach his own course&#x3C;/a&#x3E; for the first time in Minneapolis.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I look forward to giving this course again. I really enjoy spreading the Moose love.&#x3C;/p&#x3E;
</description>
<dc:date>2009-09-17</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/06/reflections-on-yapc-na-2009.html">
<title>Reflections on YAPC::NA 2009</title>
<link>http://sartak.org/2009/06/reflections-on-yapc-na-2009.html</link>
<description>
&#x3C;p&#x3E;I had a lot of fun at &#x3C;a href=&#x22;http://yapc10.org/yn2009/&#x22;&#x3E;YAPC::NA&#x3C;/a&#x3E; this year. I met some &#x3C;a href=&#x22;http://pbfcomics.com/?cid=PBF152-Scorpy_the_Forest_Friend.gif&#x22;&#x3E;forest friends&#x3C;/a&#x3E; that didn&#x27;t make it last year, such as &#x3C;a href=&#x22;http://ilmari.org/&#x22;&#x3E;ilmari&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://clownpenis.fart/&#x22;&#x3E;Nick Perez&#x3C;/a&#x3E;, and &#x3C;a href=&#x22;http://dylan.hardison.net&#x22;&#x3E;Dylan Hardison&#x3C;/a&#x3E;. I also laughed until it hurt. A few times.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I was a hermit on Sunday and Monday nights because I had not finished my slides. That was very unfortunate, so I will have future talks ready well in advance. Jitting slides is so not my style.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Moose Course&#x3C;/h3&#x3E;

&#x3C;p&#x3E;The eight hour Moose course went very well. I was a passable &#x3C;a href=&#x22;http://blog.urth.org/2009/06/i-wont-be-at-yapc-10.html&#x22;&#x3E;Rolsky-substitute&#x3C;/a&#x3E;. The &#x3C;a href=&#x22;http://blog.afoolishmanifesto.com/archives/844&#x22;&#x3E;feedback&#x3C;/a&#x3E; I recieved was (nearly) unanimously good, so I&#x27;m thrilled that people enjoyed it. There were some minor complaints, so if I ever teach a course again I&#x27;ll be sure to keep them in mind. This year, YAPC::NA is running surveys on talks and courses, so I expect I&#x27;ll learn more ways that the class could be improved. If you attended the class, please do not worry about offending Dave or me if you disliked something.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I was under-prepared for the class, but &#x3C;a href=&#x22;http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo/moose-presentations.git;a=tree;f=moose-class&#x22;&#x3E;the course material&#x3C;/a&#x3E; was very good. I got the impression that the exercises were extremely helpful. In particular, having a good test suite (powered by the metaobject protocol!) was very useful. The exercises were also useful for me because they let me sit down. Speaking on your feet for so many hours is tough.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Like the first version of anything, the course material contained some typos, inconsistencies, and bugs. It was pleasant to fix these &#x3C;em&#x3E;and push them back to the source repository&#x3C;/em&#x3E; while people worked on the exercises. For some reason, we could not get public (i.e. noncommitter) access to the repository working, perhaps due to DNS issues. It would have been useful to have people pull my changes to fix the exercises. Instead, I settled for announcing what the problems were and how to fix them.&#x3C;/p&#x3E;

&#x3C;h4 id=&#x22;context&#x22;&#x3E;Context&#x3C;/h4&#x3E;

&#x3C;p&#x3E;Early in the course I had a vitriolic rant about Perl&#x27;s notion of &#x3C;i&#x3E;context&#x3C;/i&#x3E;. On the whole I think context is a nice solution to a certain class of problems, but it definitely has some edge cases where it really bites programmers. For example, propagating context is very fiddly. You &#x3C;em&#x3E;must&#x3C;/em&#x3E; propagate context if you wrap a function to do work after it is called without affecting its return value.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;method &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synComment&#x22;&#x3E;# call SUPER::method in the right context.&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synComment&#x22;&#x3E;# not handling void context is a BUG!&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@ret&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synStatement&#x22;&#x3E;wantarray&#x3C;/span&#x3E;) {
        &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@ret&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;SUPER&#x3C;/span&#x3E;::method(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;);
    }
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;elsif&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synStatement&#x22;&#x3E;defined&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;wantarray&#x3C;/span&#x3E;) {
        &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$ret[&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;]&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;SUPER&#x3C;/span&#x3E;::method(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;);
    }
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;else&#x3C;/span&#x3E; {
        &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;SUPER&#x3C;/span&#x3E;::method(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;);
    }
    
    &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;called_method&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;called_method&#x3C;/span&#x3E; + &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;);
    
    &#x3C;span class=&#x22;synComment&#x22;&#x3E;# return what the caller asked for.&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synComment&#x22;&#x3E;# void context doesn&#x27;t need to be explicitly handled here&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synComment&#x22;&#x3E;# .. or does it? maybe!&#x3C;/span&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@ret&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;wantarray&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$ret[&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;]&#x3C;/span&#x3E;;
} 
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;I don&#x27;t recall mentioning in the class that Moose does all of this for us in the &#x3C;tt&#x3E;after&#x3C;/tt&#x3E; method modifier:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
after &#x3C;span class=&#x22;synConstant&#x22;&#x3E;method&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;called_method&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;called_method&#x3C;/span&#x3E; + &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;);
}; 
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;The other painful detail about context is in returning a list in scalar context. Most people know that an &#x3C;strong&#x3E;array&#x3C;/strong&#x3E; in scalar context evaluates to the number of elements:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;users &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@users&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;objects&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;users&#x27;&#x3C;/span&#x3E;);
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@users&#x3C;/span&#x3E;;
}

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$users&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$game-&#x26;gt;users&#x3C;/span&#x3E;; &#x3C;span class=&#x22;synComment&#x22;&#x3E;# 51 &#x3C;/span&#x3E;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;However, a lot of people don&#x27;t know that there is an irritating amount of subtlety in evaluating a &#x3C;strong&#x3E;list&#x3C;/strong&#x3E; in scalar context:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;administrators &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Sartak&#x27;&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;autarch&#x27;&#x3C;/span&#x3E;);
}

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$admins&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$game-&#x26;gt;administrators&#x3C;/span&#x3E;; &#x3C;span class=&#x22;synComment&#x22;&#x3E;# autarch &#x3C;/span&#x3E;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Instead of receiving the &#x3C;em&#x3E;count&#x3C;/em&#x3E; of administrators, we get the last element of the list. The problem is actually the &#x3C;em&#x3E;comma&#x3C;/em&#x3E;. Due to C&#x27;s strong influence on Perl 5, the comma is not just a list separator. In scalar context it acts as a sequencing operator. We&#x27;re evaluating the string &#x27;Sartak&#x27;, throwing it away, then evaluating the string &#x27;autarch&#x27;. &#x3C;strong&#x3E;There is no list at all here!&#x3C;/strong&#x3E;&#x3C;/p&#x3E;

&#x3C;blockquote&#x3E;Binary &#x22;,&#x22; is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value.  This is just like C&#x27;s comma operator.&#x3C;br /&#x3E;&#x3C;br /&#x3E;&#x3C;span class=&#x22;attribution&#x22;&#x3E;&#x26;ndash; &#x3C;tt&#x3E;&#x3C;a href=&#x22;http://perldoc.perl.org/perlop.html#Comma-Operator&#x22;&#x3E;perldoc perlop&#x3C;/a&#x3E;&#x3C;/tt&#x3E;&#x3C;/span&#x3E;&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;Almost everywhere else in the language, arrays and lists are interchangeable. I wish this inconsistency could be excised. Thanks to &#x3C;tt&#x3E;do BLOCK&#x3C;/tt&#x3E;, we do not need C&#x27;s comma operator at all.&#x3C;/p&#x3E;


&#x3C;h3&#x3E;Extending Moose&#x3C;/h3&#x3E;

&#x3C;p&#x3E;On Tuesday morning I presented &#x3C;a href=&#x22;http://sartak.org/talks/yapc-na-2009/extending-moose/extending-moose.pdf&#x22;&#x3E;Extending Moose for Applications&#x3C;/a&#x3E; &#x3C;a href=&#x22;http://sartak.org/talks/yapc-na-2009/extending-moose/extending-moose.key&#x22;&#x3E;(keynote source)&#x3C;/a&#x3E;. There were maybe 20 attendees. I blame the 8AM start time. Oh well.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I&#x27;m told that at one point someone walked out saying the talk got &#x22;too abstract&#x22;. It certainly is a very abstract topic, but I hope the examples showed that there is value to be had in using the ideas I presented.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Some good questions were asked, and some people did get it. I conveyed the point I wanted to make, which is that the metaobject protocol uses concepts you already know well.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I encourage you to read the slides. There are notes which is basically what I spoke when I was presenting, so they should be pretty readable. Please let me know how I did. I&#x27;ve received very little feedback on this talk.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;TAEB&#x3C;/h3&#x3E;

&#x3C;p&#x3E;One of my good friends &#x3C;a href=&#x22;http://tozt.net/&#x22;&#x3E;Jesse Luehrs (doy)&#x3C;/a&#x3E; gave a lightning talk about our NetHack bot, &#x3C;a href=&#x22;http://taeb.sartak.org/&#x22;&#x3E;TAEB&#x3C;/a&#x3E;.&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/doy-taeb.jpg&#x22; /&#x3E;

&#x3C;p&#x3E;The line &#x22;The code I&#x27;m working on isn&#x27;t really a NetHack bot; it&#x27;s more of a framework for writing NetHack bots&#x22; got quite a few laughs. It&#x27;s completely true, too. The topic of the talk was writing a new AI for this bot framework.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The bitrotted web interface seemed to please people. It&#x27;s too bad they saw how it was when I first wrote it. Since I took those screenshots, I improved it quite a bit, making it use NetHack&#x27;s colors and providing an AJAXy interface. Oh well, I should really get that working again.&#x3C;/p&#x3E;

&#x3C;p&#x3E;This lightning talk was a hit. Several people &#x3C;em&#x3E;cheered&#x3C;/em&#x3E;! Great job, Jesse.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Others&#x27; Talks&#x3C;/h3&#x3E;

&#x3C;p&#x3E;My favorite talk, by far, was &#x3C;a href=&#x22;http://thelackthereof.org&#x22;&#x3E;Brock Wilcox&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://thelackthereof.org/CGI_Inspect&#x22;&#x3E;CGI::Inspect talk&#x3C;/a&#x3E;. As I said during the talk, when I wrote &#x3C;a href=&#x22;http://p3rl.org/Carp::REPL&#x22;&#x3E;Carp::REPL&#x3C;/a&#x3E;, I was &#x3C;em&#x3E;actually&#x3C;/em&#x3E; aiming for exactly what &#x3C;a href=&#x22;http://p3rl.org/CGI::Inspect&#x22;&#x3E;CGI::Inspect&#x3C;/a&#x3E; &#x3C;em&#x3E;is&#x3C;/em&#x3E;. And I meant it! About two years ago, it was mentioned to me how when there&#x27;s an error in your Django application, it opens an AJAXy REPL for you. I figured out how to do some of that - REPL on error - but I never actually hooked it up to &#x3C;a href=&#x22;http://jifty.org&#x22;&#x3E;Jifty&#x3C;/a&#x3E;. Now I don&#x27;t have to. Bravo, Brock!&#x3C;/p&#x3E;

&#x3C;p&#x3E;Another talk I enjoyed was &#x3C;a href=&#x22;http://rjbs.manxome.org/&#x22;&#x3E;Ricardo Signes&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/1942&#x22;&#x3E;Git is Easy talk&#x3C;/a&#x3E;. I knew most of the material presented, but since seeing that talk I have had a lot more confidence in using git. In particular, remotes now make sense to me. I also now use &#x3C;a href=&#x22;http://gitx.frim.nl/&#x22;&#x3E;GitX&#x3C;/a&#x3E; to visualize where other developers are relative to me.&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://slowass.net/~scott/&#x22;&#x3E;Scott Walter&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/1974&#x22;&#x3E;Perl in Vegas talk&#x3C;/a&#x3E; was fascinating. He drew an interesting parallel between the incredible strictures of Vegas slot machines versus America&#x27;s completely opaque and mostly unregulated voting machines. One strange requirement of the slot machines is that code must be compiled. Though Perl is an interpreted language, it provides a &#x3C;a href=&#x22;http://www.perl.com/doc/manual/html/utils/perlcc.html&#x22;&#x3E;perlcc&#x3C;/a&#x3E; utility to &#x22;compile&#x22; the code.&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://weftsoar.net/~hdp/&#x22;&#x3E;Hans Dieter Pearcey&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/1986&#x22;&#x3E;Dist::Zilla - Automating quality since 2008&#x3C;/a&#x3E; reminded me of its excellent plugin-centric design:&#x3C;/p&#x3E;

&#x3C;img src=&#x22;http://sartak.org/misc/blog/dist-zilla-plugins.png&#x22; /&#x3E;

&#x3C;p&#x3E;This slide &#x3C;em&#x3E;directly&#x3C;/em&#x3E; caused me to submit a talk about &#x3C;a href=&#x22;http://sartak.org/talks/yapc-asia-2009/api-design/abstract.txt&#x22;&#x3E;API Design&#x3C;/a&#x3E; to &#x3C;a href=&#x22;http://conferences.yapcasia.org/ya2009/&#x22;&#x3E;YAPC::Asia 2009&#x3C;/a&#x3E;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Finally, &#x3C;a href=&#x22;http://bulknews.vox.com/&#x22;&#x3E;miyagawa&#x3C;/a&#x3E;&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/2018&#x22;&#x3E;Build a desktop application with Perl, HTTP::Engine, SQLite and jQuery&#x3C;/a&#x3E; talk was exciting. I&#x27;ve been working toward using his &#x3C;a href=&#x22;&#x22;&#x3E;perl-app-builder&#x3C;/a&#x3E; for TAEB since he &#x3C;a href=&#x22;http://remediecode.org/2009/06/binary-builds-for-os-x-leopard-users.html&#x22;&#x3E;blogged about it&#x3C;/a&#x3E;. The talk showed how we can write standalone, web-based, GUI apps, in Perl, without inflicting CPAN on our users. Because Perl has been a web language ever since the web has had languages, the tools for generating HTML, serving pages, etc. are &#x3C;em&#x3E;very good&#x3C;/em&#x3E;. The traditional GUI tools are mediocre at best. They are why my applications have been strictly web- and curses-based.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Thanks!&#x3C;/h3&#x3E;

&#x3C;p&#x3E;Thank you Robert Blackwell, Casey West, Tom Moertel, Dan Wright, and anyone else who helped! This YAPC was fantastic.&#x3C;/p&#x3E;

&#x3C;p&#x3E;If you have never been to YAPC, you should seriously consider going to the next one!&#x3C;/p&#x3E;
</description>
<dc:date>2009-06-28</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/06/shawn-m-moose-at-yapc-na-2009.html">
<title>Shawn M Moose at YAPC::NA 2009</title>
<link>http://sartak.org/2009/06/shawn-m-moose-at-yapc-na-2009.html</link>
<description>
&#x3C;p&#x3E;&#x3C;a href=&#x22;http://yapc10.org/yn2009/&#x22;&#x3E;YAPC::NA 2009&#x3C;/a&#x3E; begins Monday; it&#x27;s not too late to sign up! Don&#x27;t miss the affectionately-titled &#x3C;a href=&#x22;http://yapc10.org/yn2009/talks/tag/moose&#x22;&#x3E;Moose track&#x3C;/a&#x3E;.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Extending Moose talk&#x3C;/h3&#x3E;

&#x3C;p&#x3E;I&#x27;m giving a 50 minute talk about &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/1880&#x22;&#x3E;Extending Moose for Applications&#x3C;/a&#x3E;. The content will be similar to the &#x3C;a href=&#x22;http://sartak.org/mmop.html&#x22;&#x3E;Moose&#x27;s MOP&#x3C;/a&#x3E; series, though focusing more on how all the metaprogramming features work together in harmony. I&#x27;ve been writing the articles so I can learn how to teach the concept and utility of a metaobject protocol.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I&#x27;m still writing the talk, but you can have a look at what I have so far: &#x3C;a href=&#x22;http://sartak.org/talks/yapc-na-2009/extending-moose/extending-moose.pdf&#x22;&#x3E;[pdf]&#x3C;/a&#x3E; &#x3C;a href=&#x22;http://sartak.org/talks/yapc-na-2009/extending-moose/extending-moose.key&#x22;&#x3E;[keynote source]&#x3C;/a&#x3E;. Suggestions for improvement or clarification would be very welcome. I have the &#x22;script&#x22; included as notes at the bottom of each slide, so you can learn even without me there speaking at you. If you intend to attend the talk (or the Moose course on Sunday) you should probably not read it. I stick to the script, terrible jokes and all. When it is done and presented, I&#x27;ll post about the final version.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Moose class&#x3C;/h3&#x3E;

&#x3C;p&#x3E;Due to health problems, Dave Rolsky will sadly &#x3C;a href=&#x22;http://blog.urth.org/2009/06/i-wont-be-at-yapc-10.html&#x22;&#x3E;not be attending YAPC this year&#x3C;/a&#x3E;. He was scheduled to give an eight hour class about Moose on Sunday. It would be a lot of hassle for organizers and disappointment for students to cancel the class, so I stepped up to present the bulk of it. &#x3C;a href=&#x22;http://jrock.us/&#x22;&#x3E;Jon Rockway&#x3C;/a&#x3E; will be helping as well. I don&#x27;t make great use of Moose&#x27;s types, but he does, so we are forcing him to teach the types portion of the class.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I will also be presenting my Extending Moose talk at the end of the class (if we turn out to be short on time). This way you can see Matt Trout&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/1975&#x22;&#x3E;Future of DBIx::Class&#x3C;/a&#x3E; or Christopher Nehren&#x27;s &#x3C;a href=&#x22;http://yapc10.org/yn2009/talk/2016&#x22;&#x3E;CLI apps don&#x27;t have to suck&#x3C;/a&#x3E;. Both will probably be Moose-heavy and certainly worth seeing. Or.. you can sleep in!&#x3C;/p&#x3E;

&#x3C;p&#x3E;Please let me know if you have any questions about the talk or class. I&#x27;ve given a few talks before, but never an extended class, so it will certainly be interesting!&#x3C;/p&#x3E;

&#x3C;p&#x3E;I look forward to seeing many of you next week. I&#x27;ll try to squeeze in a post or eight about talks and all the other good stuff at YAPCs.&#x3C;/p&#x3E;
</description>
<dc:date>2009-06-17</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/05/the-design-of-parameterized-roles.html">
<title>The Design of Parameterized Roles</title>
<link>http://sartak.org/2009/05/the-design-of-parameterized-roles.html</link>
<description>
&#x3C;p&#x3E;There has been a lot of good discussion about roles lately, due to &#x3C;a href=&#x22;http://www.modernperlbooks.com/cgi-bin/mt/mt-search.cgi?blog_id=1&#x26;tag=roles&#x26;limit=20&#x22;&#x3E;chromatic&#x3C;/a&#x3E; and &#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal&#x22;&#x3E;Ovid&#x3C;/a&#x3E;. We&#x27;re starting to attract people from outside of not only the &#x3C;a href=&#x22;http://moose.perl.org&#x22;&#x3E;Moose&#x3C;/a&#x3E; and &#x3C;a href=&#x22;http://dev.perl.org/perl6/&#x22;&#x3E;Perl 6&#x3C;/a&#x3E; communities, but outside of the greater Perl community. I&#x27;m thrilled, because roles are an excellent complement to inheritance, and deserve to be widely adopted.&#x3C;/p&#x3E;

&#x3C;p&#x3E;In &#x3C;a href=&#x22;http://www.modernperlbooks.com/mt/2009/04/the-why-of-perl-roles.html&#x22;&#x3E;The Why of Perl Roles&#x3C;/a&#x3E;, chromatic quickly describes &#x3C;em&#x3E;parametric roles&#x3C;/em&#x3E;, also known as parameterized roles. A &#x3C;b&#x3E;parameterized role&#x3C;/b&#x3E; is a role whose application can be customized. Such a role accepts parameters at composition time to alter its behavior &#x3C;em&#x3E;any way it wishes&#x3C;/em&#x3E;. This increases the flexibility of the role, fostering opportunities for greater code reuse.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Example&#x3C;/h3&#x3E;

&#x3C;p&#x3E;My &#x3C;a href=&#x22;http://taeb.sartak.org&#x22;&#x3E;NetHack bot TAEB&#x3C;/a&#x3E; has a &#x3C;a href=&#x22;https://github.com/sartak/TAEB/blob/master/lib/TAEB/Action/Role/Item.pm&#x22;&#x3E;&#x3C;tt&#x3E;TAEB::Action::Role::Item&#x3C;/tt&#x3E;&#x3C;/a&#x3E; parameterized role. It accepts one parameter, a list of names for item attributes. These attributes (which specify a type constraint of &#x3C;a href=&#x22;http://p3rl.org/NetHack::Item&#x22;&#x3E;&#x3C;tt&#x3E;NetHack::Item&#x3C;/tt&#x3E;&#x3C;/a&#x3E; and a custom &#x22;provided&#x22; trait) are added to the class upon composition. The role provides a few other things as well: a &#x3C;tt&#x3E;current_item&#x3C;/tt&#x3E; attribute and a method for dealing with missing-item exceptions. The &#x3C;tt&#x3E;current_item&#x3C;/tt&#x3E; attribute&#x27;s value is a lazy default, pointing to the first item in the parameterized list of attribute names. This is an application of the well-trodden Don&#x27;t Repeat Yourself principle &#x26;mdash; each class does not have to repeat its item attribute names. Parameterized roles are pretty good enablers of &#x3C;i&#x3E;DRY&#x3C;/i&#x3E;!&#x3C;/p&#x3E;

&#x3C;p&#x3E;Since NetHack is a &#x3C;em&#x3E;very&#x3C;/em&#x3E; item-oriented game, this role has many consumers. The &#x3C;a href=&#x22;https://github.com/sartak/TAEB/blob/master/lib/TAEB/Action/Dip.pm&#x22;&#x3E;&#x3C;tt&#x3E;TAEB::Action::Dip&#x3C;/tt&#x3E;&#x3C;/a&#x3E; consumer specifies &#x3C;tt&#x3E;item&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;into&#x3C;/tt&#x3E; for the list of attribute names, so it gets those two attributes (as well as whatever else the role provides). Likewise, &#x3C;a href=&#x22;https://github.com/sartak/TAEB/blob/master/lib/TAEB/Action/Wield.pm&#x22;&#x3E;&#x3C;tt&#x3E;TAEB::Action::Wield&#x3C;/tt&#x3E;&#x3C;/a&#x3E; gets a &#x3C;tt&#x3E;weapon&#x3C;/tt&#x3E; attribute. Most of the consumers specify nothing for this parameter, so they get the default list of &#x3C;tt&#x3E;item&#x3C;/tt&#x3E;. Consuming a parameterized role without specifying any parameters is syntactically identical to applying vanilla roles, which is a (minor) convenience.&#x3C;/p&#x3E;

&#x3C;p&#x3E;In older versions of the code, &#x3C;tt&#x3E;TAEB::Action::Role::Item&#x3C;/tt&#x3E; was not parameterized. This role always gave you a single attribute named &#x3C;tt&#x3E;item&#x3C;/tt&#x3E;. The &#x3C;tt&#x3E;into&#x3C;/tt&#x3E; attribute of &#x3C;tt&#x3E;TAEB::Action::Dip&#x3C;/tt&#x3E; was a second-class citizen. There are a number of ways a second-class item attribute can go wrong, such as not having a type constraint, or not being visible to &#x3C;tt&#x3E;current_item&#x3C;/tt&#x3E;&#x27;s lazy default. It also prevented us from renaming the &#x3C;tt&#x3E;item&#x3C;/tt&#x3E; attribute to, say, &#x3C;tt&#x3E;weapon&#x3C;/tt&#x3E; for &#x3C;tt&#x3E;TAEB::Action::Wield&#x3C;/tt&#x3E;. We drastically improved the code&#x27;s clarity and expressiveness by parameterizing the role.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Design&#x3C;/h3&#x3E;

&#x3C;p&#x3E;In December, I wrote the &#x3C;a href=&#x22;http://p3rl.org/MooseX::Role::Parameterized&#x22;&#x3E;&#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E;&#x3C;/a&#x3E; extension. I had grown tired of people (primarily myself!) putting off coding because the proper implementation of &#x3C;i&#x3E;whatever&#x3C;/i&#x3E; demanded parameterized roles. I am not exaggerating:&#x3C;/p&#x3E;

&#x3C;ul class=&#x22;irc&#x22;&#x3E;
&#x3C;li&#x3E;&#x22;hoping once we have parameterised roles we can do that&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;you will have [...] parameterized roles which will allow such things very easily&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;let&#x27;s see what the parameterized roles end up giving us&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;once we have parameterised roles I shall be providing one to produce all three trivially&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;parameterized roles will probably do all that you want&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;I&#x27;m hoping parameterised roles will let me get rid of that&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;what&#x27;s the status of parameterized roles? I could really use them&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;has there been any progress on parameterized roles?&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;we don&#x27;t have parameterized roles yet?!&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;are parametrized roles somewhere on the roadmap&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x22;that &#x3C;em&#x3E;sounds&#x3C;/em&#x3E; like parameterized roles, which someone should implement some time&#x22;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;

&#x3C;p&#x3E;I think the biggest roadblock in the way of implementing a parameterized role system was Moose&#x27;s lack of support for anonymous roles. So I did that hard part first then wrote &#x3C;a href=&#x22;http://p3rl.org/MooseX::Role::Parameterized&#x22;&#x3E;MooseX::Role::Parameterized&#x3C;/a&#x3E;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Designers of parameterized role systems (perhaps three or four of us by now?) must decide how much freedom each role is given. How much parameterizability is permissible? In &#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E;, and &#x3C;a href=&#x22;http://rakudo.org/2009/01/parametric-roles.html&#x22;&#x3E;Perl 6&#x27;s parametric roles&#x3C;/a&#x3E;, there are &#x3C;strong&#x3E;no&#x3C;/strong&#x3E; limitations. You can parameterize anything.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Maximizing your user&#x27;s freedom is certainly laudable, but I am not convinced that it is &#x3C;em&#x3E;completely&#x3C;/em&#x3E; beneficial. There is value in stricture, for example, to improve the efficacy of class/role browsers. I will leave such meditations for the next parameterized role designer. At least for Moose, we have several more chances to get the design right; there are plenty of other namespaces available on CPAN: &#x3C;tt&#x3E;MooseX::Role::Parametric&#x3C;/tt&#x3E;, &#x3C;tt&#x3E;MooseX::Role::Parameterizable&#x3C;/tt&#x3E;, &#x3C;tt&#x3E;MooseX::Role::Parameterised&#x3C;/tt&#x3E;, and so on.&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E; works, in short, by executing a procedure for each role application. This procedure takes as an argument a &#x22;parameters&#x22; object. It is executed in the dynamic extent of an anonymous role metaobject. All of the usual role keywords (&#x3C;tt&#x3E;has&#x3C;/tt&#x3E;, &#x3C;tt&#x3E;around&#x3C;/tt&#x3E;, &#x3C;tt&#x3E;requires&#x3C;/tt&#x3E;, etc) operate on this anonymous role. The procedure may use the &#x22;parameters&#x22; object in building up the role using these keywords.&#x3C;/p&#x3E;

&#x3C;p&#x3E;This is also a reasonable description of how vanilla roles are created, from a backstage point-of-view. The primary difference is that the procedure is only ever executed once for vanilla roles, whereas it is executed potentially many times, building up a different role metaobject each time, for parameterized roles.&#x3C;/p&#x3E;

&#x3C;p&#x3E;This difference is precisely what makes the syntax of &#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E; slightly unusual, at least in the context of core Moose:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Counter&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;MooseX::Role::Parameterized;

parameter &#x3C;span class=&#x22;synConstant&#x22;&#x3E;name&#x3C;/span&#x3E; =&#x26;gt; (
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;isa&#x3C;/span&#x3E;      =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Str&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;required&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;,
);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;You explicitly specify which parameters the role can take. This improves introspectability, and makes it immediately obvious (if you&#x27;ve written Moose code) how to specify that a parameter is required, or has a type constraint; default value; or predicate, etc.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
role {
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p-&#x26;gt;name&#x3C;/span&#x3E;;

    has &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; =&#x26;gt; (
        &#x3C;span class=&#x22;synConstant&#x22;&#x3E;is&#x3C;/span&#x3E;  =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;rw&#x27;&#x3C;/span&#x3E;,
        &#x3C;span class=&#x22;synConstant&#x22;&#x3E;isa&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Int&#x27;&#x3C;/span&#x3E;,
    );

    method &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;increment_&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
        &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;$name&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;$name&#x3C;/span&#x3E; + &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;);
    };
};
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;The &#x3C;tt&#x3E;role&#x3C;/tt&#x3E; keyword exists for specifying the aforementioned role-building procedure. This is the unusual syntax. &#x3C;a href=&#x22;http://p3rl.org/MooseX::Declare&#x22;&#x3E;&#x3C;tt&#x3E;MooseX::Declare&#x3C;/tt&#x3E;&#x3C;/a&#x3E; could improve upon this a lot, once some tuits are spent.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The &#x3C;tt&#x3E;method&#x3C;/tt&#x3E; keyword is required (instead of the usual &#x3C;tt&#x3E;sub name { ... }&#x3C;/tt&#x3E;) because Perl handles &#x3C;em&#x3E;named, inner subroutines&#x3C;/em&#x3E; in a way that is not useful for this design. The details are many, but mostly unimportant. The salient point is that such subroutines do not properly close over &#x3C;tt&#x3E;$p&#x3C;/tt&#x3E;, rendering them unparameterizable. The anonymous subroutine passed to &#x3C;tt&#x3E;method&#x3C;/tt&#x3E; can properly capture &#x3C;tt&#x3E;$p&#x3C;/tt&#x3E;. The &#x3C;tt&#x3E;method&#x3C;/tt&#x3E; keyword has a fringe benefit over &#x3C;tt&#x3E;sub&#x3C;/tt&#x3E; in easing the parameterization of the method&#x27;s name.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Current and future work&#x3C;/h3&#x3E;

&#x3C;p&#x3E;I recently fixed &#x3C;a href=&#x22;http://rt.cpan.org/Public/Bug/Display.html?id=45393&#x22;&#x3E;a bug&#x3C;/a&#x3E; in &#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E; that prevented parameterized roles from participating in role summation. Role summation is what provides protection against method name conflicts &#x3C;em&#x3E;at compile time&#x3C;/em&#x3E;, among other things. Being unable to partake in composition limited parameterized roles&#x27; usefulness. I&#x27;m very happy to have fixed the one crippling issue with this extension.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The fix involved a bait-and-switch hook in Moose&#x27;s role summation code. The hook is fairly contrived, but it might possibly be useful to other role extensions.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I&#x27;m currently noodling around with the &#x3C;i&#x3E;partial application&#x3C;/i&#x3E; of parameterized roles. Currently, if a role consumes a parameterized role, it must specify all of the required parameters. In fact, the parameterized role is bound (the procedure is executed) at that moment. &#x3C;tt&#x3E;MooseX::Role::Parameterized&#x3C;/tt&#x3E; does not care about whether it is being consumed by a class or a role. Instead, I&#x27;d like the consuming role to be able to specify &#x3C;em&#x3E;some&#x3C;/em&#x3E; of the parameters. Any unbound parameters will be parameters in the composite role.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The only blocker stopping me from working on partial application of parameterized roles is a use case. Adding complexity for no reason is clumsy.&#x3C;/p&#x3E;
</description>
<dc:date>2009-05-12</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/05/perl-critic-dynamic-moose.html">
<title>Perl::Critic::Dynamic::Moose</title>
<link>http://sartak.org/2009/05/perl-critic-dynamic-moose.html</link>
<description>
&#x3C;p&#x3E;In &#x3C;a href=&#x22;/2009/04/the-new-moose-warning-and-the-new-moose-critic.html&#x22;&#x3E;my previous post&#x3C;/a&#x3E;, I wrote &#x22;What we need is a set of Perl::Critic policies for Moose.&#x22; I&#x27;ve put my money where my mouth is and implemented five of them.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;CPAN?&#x3C;/h3&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;Perl::Critic::Dynamic::Moose&#x3C;/tt&#x3E; is not on CPAN yet because &#x3C;tt&#x3E;Perl::Critic&#x3C;/tt&#x3E; does not currently distinguish between &#x22;safe&#x22; (static) and &#x22;possibly unsafe&#x22; (dynamic) policies. &#x3C;tt&#x3E;Perl::Critic&#x3C;/tt&#x3E; usually works by statically inspecting some Perl document. This allows users to &#x3C;a href=&#x22;http://perlcritic.com/&#x22;&#x3E;critique untrusted code&#x3C;/a&#x3E;. Most of the policies I wrote are &#x3C;i&#x3E;dynamic&#x3C;/i&#x3E;. These dynamic policies work by executing the code to be critiqued, then analyzing any new metaclasses that were created. While this limits their utility to analyzing only trusted code, this dynamicism does magnify analytic potential. Instead of inspecting &#x3C;a href=&#x22;http://p3rl.org/PPI&#x22;&#x3E;PPI&#x3C;/a&#x3E; DOMs, these policies can inspect any and every metaobject in the system. A large part of why the metaobject protocol exists is for sane and consistent inspection, so these dynamic policies work well.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Anyway, &#x3C;tt&#x3E;Perl::Critic&#x3C;/tt&#x3E; uses &#x3C;a href=&#x22;http://p3rl.org/Module::Pluggable&#x22;&#x3E;&#x3C;tt&#x3E;Module::Pluggable&#x3C;/tt&#x3E;&#x3C;/a&#x3E; to unconditionally load every module in the &#x3C;tt&#x3E;Perl::Critic::Policy&#x3C;/tt&#x3E; namespace. It would be harmful to add unsafe modules to that namespace, so I am going to make sure that a new &#x3C;tt&#x3E;Perl::Critic&#x3C;/tt&#x3E; that runs only safe policies is released before I begin publishing dynamic policies. It should be a very simple matter of programming...&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Perl::Critic::DynamicMoosePolicy&#x3C;/h3&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;Perl::Critic::DynamicMoosePolicy&#x3C;/tt&#x3E; is a base class for dynamic Moose policies. It&#x27;s written, of course, with Moose (extending &#x3C;tt&#x3E;Perl::Critic::Policy&#x3C;/tt&#x3E; using &#x3C;a href=&#x22;http://p3rl.org/MooseX::NonMoose&#x22;&#x3E;&#x3C;tt&#x3E;MooseX::NonMoose&#x3C;/tt&#x3E;&#x3C;/a&#x3E;). It does the things that every dynamic Moose policy needs to do:&#x3C;/p&#x3E;

&#x3C;ol&#x3E;
&#x3C;li&#x3E;Compile the document being analyzed&#x3C;/li&#x3E;
&#x3C;li&#x3E;Find all the metaclasses that were just created&#x3C;/li&#x3E;
&#x3C;li&#x3E;Call your policy&#x27;s &#x3C;tt&#x3E;violates_metaclass&#x3C;/tt&#x3E; for each metaclass&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;

&#x3C;p&#x3E;Ideally, policies would just implement &#x3C;tt&#x3E;violates_metaclass&#x3C;/tt&#x3E; and it would all just work. However, there are (seemingly always) some details.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Since this analysis is entirely divorced from the source code, it is impossible (in general) to provide a useful file and line number pointing to the violation. Instead of making each policy provide an arbitrary location in the document for violations, &#x3C;tt&#x3E;DynamicMoosePolicy&#x3C;/tt&#x3E; just does it for you. If you&#x27;re combining PPI and metaobject inspection, then you can of course provide a more useful violation location when you have one. Instead of a location, I recommend that you be as detailed as possible in your error report (include the class name!)&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://p3rl.org/Perl::Critic::DynamicPolicy&#x22;&#x3E;&#x3C;tt&#x3E;Perl::Critic::DynamicPolicy&#x3C;/tt&#x3E;&#x3C;/a&#x3E; runs each policy in a forked process, to prevent the analyzed code from mucking with the analyzing process&#x27;s operation. Dynamic policies communicate violations with perlcritic via a &#x3C;a href=&#x22;http://perldoc.perl.org/functions/pipe.html&#x22;&#x3E;parent-child pipe&#x3C;/a&#x3E;, with all violation objects frozen and thawed with &#x3C;a href=&#x22;http://p3rl.org/Storable&#x22;&#x3E;Storable&#x3C;/a&#x3E;. This means your violations cannot include code references (such as those created by &#x3C;a href=&#x22;http://p3rl.org/Scalar::Defer&#x22;&#x3E;&#x3C;tt&#x3E;Scalar::Defer&#x3C;/tt&#x3E;&#x3C;/a&#x3E;), or anything else that &#x3C;tt&#x3E;Storable&#x3C;/tt&#x3E; cannot handle. I spent a while scratching my head trying to figure out what was causing this error:&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;Cannot restore overloading on HASH(0xc42f0c) (package &#x26;lt;unknown&#x26;gt;) at blib/lib/Storable.pm  (autosplit into blib/lib/auto/Storable/thaw.al) line 415&#x3C;/tt&#x3E;&#x3C;/p&#x3E;

&#x3C;p&#x3E;It turned out to be the &#x3C;tt&#x3E;PPI::Document&#x3C;/tt&#x3E; object that the violation was using as an arbitrary location. Specifying the first element in the document made that error go away. I&#x27;m not going to ask too many questions here, just smile and nod.&#x3C;/p&#x3E;

&#x3C;h4&#x3E;augment/inner&#x3C;/h4&#x3E;

&#x3C;p&#x3E;Policies may define a &#x3C;tt&#x3E;applies_to_metaclass&#x3C;/tt&#x3E; method that filters for only the metaclasses that sensibly apply. I utilized the rarely-seen &#x3C;a href=&#x22;http://p3rl.org/Moose::Cookbook::Basics::Recipe6&#x22;&#x3E;&#x3C;tt&#x3E;augment&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;inner&#x3C;/tt&#x3E;&#x3C;/a&#x3E; for this method (as well as &#x3C;tt&#x3E;default_themes&#x3C;/tt&#x3E;). The default implementation of &#x3C;tt&#x3E;applies_to_metaclass&#x3C;/tt&#x3E; is:

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;applies_to_metaclass &#x3C;/span&#x3E;{ &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Class::MOP::Class&#x27;&#x3C;/span&#x3E;, inner() }
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;If the policy wants to analyze &#x3C;em&#x3E;only&#x3C;/em&#x3E; role metaobjects, then they can ignore the method&#x27;s inverse nature by writing the standard:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;applies_to_metaclass &#x3C;/span&#x3E;{ &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Moose::Meta::Role&#x27;&#x3C;/span&#x3E; }
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;If the policy wants to analyze &#x3C;em&#x3E;only&#x3C;/em&#x3E; class metaobjects, then they do not have to augment this method. The parent&#x27;s &#x3C;tt&#x3E;inner&#x3C;/tt&#x3E; in such cases is a no-op, returning the empty list.&#x3C;/p&#x3E;

&#x3C;p&#x3E;However, if a policy wants to analyze &#x3C;em&#x3E;both&#x3C;/em&#x3E; classes and roles (which I suspect happens when the actual subject for analysis is attributes and methods), the policy can include:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
augment &#x3C;span class=&#x22;synConstant&#x22;&#x3E;applies_to_metaclass&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Moose::Meta::Role&#x27;&#x3C;/span&#x3E;
};
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;augment&#x3C;/tt&#x3E; signals that the method resolution order &#x3C;em&#x3E;descends&#x3C;/em&#x3E; the class hierarchy: grandparent -&#x26;gt; parent -&#x26;gt; child. &#x3C;tt&#x3E;inner&#x3C;/tt&#x3E; calls the next most specific method. The end result of calling the above method is the list &#x3C;tt&#x3E;(&#x27;Class::MOP::Class&#x27;, &#x27;Moose::Meta::Role&#x27;)&#x3C;/tt&#x3E;.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;PCP::DynamicMoose::ProhibitPublicBuilder&#x3C;/h3&#x3E;

&#x3C;p&#x3E;I wrote this policy first because I knew this area of the metaobject protocol well. Any problems were likely caused by the fork-and-eval side, not the inspection side. Pick your battles.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Each attribute can have a &#x3C;tt&#x3E;builder&#x3C;/tt&#x3E; method that is called to provide a default value for that attribute. This facilitates changing this default value by subclassing and role application better than the &#x3C;tt&#x3E;default&#x3C;/tt&#x3E; option does.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The inspection is straightforward. For each attribute on the class (or role), ensure that, if it has a builder, its name begins with an underscore. The only reason for this is because I sometimes forget my builders would be public API, when they generally should not be.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Handling roles for this policy sucks because attributes in roles are just inert hash references. Since there have been threats to improve roles to make use of real objects, I will elide handling roles here for brevity.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;for&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$meta-&#x26;gt;get_attribute_list&#x3C;/span&#x3E;) {
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$attribute&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$meta-&#x26;gt;get_attribute&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E;);

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$builder&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$attribute-&#x26;gt;builder&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;or&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$builder&#x3C;/span&#x3E; !~ &#x3C;span class=&#x22;synStatement&#x22;&#x3E;/&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;^_&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;/&#x3C;/span&#x3E;) {
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$desc&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Builder method &#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$builder&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27; of attribute ...&#x26;quot;&#x3C;/span&#x3E;;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;push&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;,
            &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;violation&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$desc&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$PL&#x3C;/span&#x3E;);
    }
}
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;&#x3C;tt&#x3E;get_attribute_list&#x3C;/tt&#x3E; returns the names of attributes defined in this &#x3C;em&#x3E;local&#x3C;/em&#x3E; class. Inherited attributes are not considered. I figure you would be running these policies on every class and role in your project anyway.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;PCP::DynamicMoose::RequireMakeImmutable&#x3C;/h3&#x3E;

&#x3C;p&#x3E;Next up is another easy policy. This is &#x3C;em&#x3E;by far&#x3C;/em&#x3E; the simplest. It performs one simple check on the metaclass (&#x3C;tt&#x3E;is_immutable&#x3C;/tt&#x3E;).&#x3C;/p&#x3E;

&#x3C;p&#x3E;Elliot Shank wrote &#x3C;a href=&#x22;http://p3rl.org/Perl::Critic::Policy::Moose::RequireMakeImmutable&#x22;&#x3E;Perl::Critic::Policy::Moose::RequireMakeImmutable&#x3C;/a&#x3E;, a static policy that checks for &#x3C;tt&#x3E;__PACKAGE__-&#x26;gt;meta-&#x26;gt;make_immutable&#x3C;/tt&#x3E;. There is room enough for both a static and a dynamic policy. Not every class can &#x3C;tt&#x3E;make_immutable&#x3C;/tt&#x3E; in that specific way. Class::MOP, for example calls &#x3C;tt&#x3E;make_immutable&#x3C;/tt&#x3E; on all of its classes at once. In other cases, the programmer may have accidentally forgotten to call &#x3C;tt&#x3E;make_immutable&#x3C;/tt&#x3E; on a dynamically-generated class.&#x3C;/p&#x3E;

&#x3C;p&#x3E;As with most static policies, &#x3C;tt&#x3E;PCP::Moose::RequireMakeImmutable&#x3C;/tt&#x3E; admirably handles the common cases, but might not handle strange corner cases well. Dynamic policies can fill such gaps.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;PCP::Moose::RequireMethodModifiers&#x3C;/h3&#x3E;

&#x3C;p&#x3E;Moose provides a rich set of method modifiers:&#x3C;/p&#x3E;

&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;tt&#x3E;before&#x3C;/tt&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;tt&#x3E;after&#x3C;/tt&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;tt&#x3E;around&#x3C;/tt&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;tt&#x3E;override&#x3C;/tt&#x3E; / &#x3C;tt&#x3E;super&#x3C;/tt&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;tt&#x3E;augment&#x3C;/tt&#x3E; / &#x3C;tt&#x3E;inner&#x3C;/tt&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;

&#x3C;p&#x3E;There&#x27;s a method modifier for just about every way you&#x27;d want to interact with homonymous methods. If you define a method that is already present through inheritance, then this policy asks you to explicitly use a method modifier. This way, you might be able to catch &#x3C;em&#x3E;accidental&#x3C;/em&#x3E; method overrides. If you do want to completely replace an ancestor&#x27;s method, then you can use &#x3C;tt&#x3E;override&#x3C;/tt&#x3E; without calling &#x3C;tt&#x3E;super&#x3C;/tt&#x3E;. That too provides some typo protection, since &#x3C;tt&#x3E;override&#x3C;/tt&#x3E; will confirm that an ancestral method exists.&#x3C;/p&#x3E;

&#x3C;p&#x3E;This is the first novel dynamic policy; the previous policies could be implemented statically, but this one would have little chance. Let&#x27;s walk through its entire &#x3C;tt&#x3E;violates_metaclass&#x3C;/tt&#x3E;.&#x3C;/p&#x3E;


&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;violates_metaclass &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E;  = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;This policy does not apply to roles, and does not require Moose-specific features (such as, well, roles), so it can use the default &#x3C;tt&#x3E;applies_to_metaclass&#x3C;/tt&#x3E;. We also need a place to store the list of violations, since many methods could be implicitly overriding inherited methods.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;for&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;get_method_list&#x3C;/span&#x3E;) {
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;get_method&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E;);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;We iterate over the class&#x27;s &#x3C;em&#x3E;local&#x3C;/em&#x3E; methods. &#x3C;tt&#x3E;get_method_list&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;get_method&#x3C;/tt&#x3E; do not look at inherited methods at all. Methods brought in from &#x3C;em&#x3E;locally-consumed roles&#x3C;/em&#x3E; are also included in this list &#x26;mdash; this is a feature called &#x3C;em&#x3E;flattening&#x3C;/em&#x3E;. (If in your code you &#x3C;em&#x3E;do&#x3C;/em&#x3E; want to consider inheritance, use &#x3C;tt&#x3E;get_all_methods&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;find_method_by_name&#x3C;/tt&#x3E;)&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# override and augment modifiers are always fine.&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;isa&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Moose::Meta::Method::Overridden&#x27;&#x3C;/span&#x3E;)
             || &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;isa&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Moose::Meta::Method::Augmented&#x27;&#x3C;/span&#x3E;);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;This quickly excludes two of the five method modifiers. Such modifiers have their own metaclasses for various reasons, not least of which is our usage here: to allow detection that the method is just a modifier.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# Since we can implicitly override and wrap in the same class, we&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# need to be a little more careful here.&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;isa&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Class::MOP::Method::Wrapped&#x27;&#x3C;/span&#x3E;)) {
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$orig_method&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;get_original_method&#x3C;/span&#x3E;;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;associated_metaclass-&#x26;gt;name&#x3C;/span&#x3E;
                 &#x3C;span class=&#x22;synStatement&#x22;&#x3E;ne&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$orig_method-&#x26;gt;associated_metaclass-&#x26;gt;name&#x3C;/span&#x3E;;
        }
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Handling the other three method modifiers (&#x3C;tt&#x3E;before&#x3C;/tt&#x3E;, &#x3C;tt&#x3E;after&#x3C;/tt&#x3E;, and &#x3C;tt&#x3E;around&#x3C;/tt&#x3E;) is trickier. You can both define a method and wrap it with these three modifiers in the same class. This is useful for, say, running code &#x3C;tt&#x3E;before&#x3C;/tt&#x3E; an attribute&#x27;s &#x3C;tt&#x3E;clearer&#x3C;/tt&#x3E;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;If the method we&#x27;re wrapping is from a different metaclass, then we must be wrapping an inherited method, which is fine. If we&#x27;re wrapping a local method, then we need to peel off a layer. We do not need peel off many layers in a loop, since multiple local modifiers coalesce into one layer.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# Generated methods&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method-&#x26;gt;isa&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Class::MOP::Method::Generated&#x27;&#x3C;/span&#x3E;);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;This one worries me a little. Generated methods are those created for you by Moose. Examples include accessors, &#x3C;tt&#x3E;new&#x3C;/tt&#x3E; (but only after a &#x3C;tt&#x3E;make_immutable&#x3C;/tt&#x3E;), and delegation methods. Since these methods are generated for you, you have no way to indicate that they are overriding an inherited method.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Because you can certainly accidentally override an inherited method with a generated method, this check should be optional.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# &#x3C;/span&#x3E;&#x3C;span class=&#x22;synTodo&#x22;&#x3E;XXX&#x3C;/span&#x3E;&#x3C;span class=&#x22;synComment&#x22;&#x3E;: this freaking sucks&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;eq&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;meta&#x27;&#x3C;/span&#x3E;
             || &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;eq&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;BUILD&#x27;&#x3C;/span&#x3E;
             || &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;eq&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;DEMOLISH&#x27;&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;This &#x22;freaking sucks&#x22; for two reasons. &#x3C;tt&#x3E;meta&#x3C;/tt&#x3E; is installed into your local class by Moose. That&#x27;s fine (though we will eventually support renaming or excluding it). The metaclass of the &#x3C;tt&#x3E;meta&#x3C;/tt&#x3E; method is not &#x3C;tt&#x3E;Class::MOP::Method::Generated&#x3C;/tt&#x3E; like it should be, it&#x27;s &#x3C;tt&#x3E;Moose::Meta::Method&#x3C;/tt&#x3E;. This misclassification makes it look like a regular method defined by the user. &#x3C;tt&#x3E;meta&#x3C;/tt&#x3E; would receive special consideration even if it were properly labeled as a generated method, because every class gets its own.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The other reason this sucks is the hardcoded &#x3C;tt&#x3E;BUILD&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;DEMOLISH&#x3C;/tt&#x3E;. These are special methods with unusual dispatch semantics. Every &#x3C;tt&#x3E;BUILD&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;DEMOLISH&#x3C;/tt&#x3E; method is called in your hierarchy automatically; there is no choice about redispatching to your inherited method. This is a useful feature, because too often do we forget to do this which can silently mess up initialization or destruction. Anyway, this list of special methods should be inspectable from the metaclass, and given their own &#x3C;tt&#x3E;Class::MOP::Method&#x3C;/tt&#x3E; subclass.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$next&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;find_next_method_by_name&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E;);

        &#x3C;span class=&#x22;synComment&#x22;&#x3E;# Adding new methods is always fine.&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; !&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$next&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Simple enough, right? It finds the inherited method by a given name, if any. If there is none, then it must be an entirely new method with a unique name, which is perfectly fine.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;push&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;violation&#x3C;/span&#x3E;(
            &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;The &#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$name&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27; method of class &#x26;quot;&#x3C;/span&#x3E; . &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;name&#x3C;/span&#x3E;
          . &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot; does not use a method modifier to&#x26;quot;&#x3C;/span&#x3E;
          . &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot; override its superclass implementation.&#x26;quot;&#x3C;/span&#x3E;,
          &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$EXPL&#x3C;/span&#x3E;);
    }

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;;
}
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;That&#x27;s all. We&#x27;ve exhausted all the acceptable ways for a method to interact with its super-methods, so what remains must be a violation.&#x3C;/p&#x3E;


&#x3C;h3&#x3E;PCP::DynamicMoose::ClassOverridesRole&#x3C;/h3&#x3E;

&#x3C;p&#x3E;Ahhh, the violation that launched a thousand comments. I&#x27;ve already &#x3C;a href=&#x22;/2009/04/the-new-moose-warning-and-the-new-moose-critic.html&#x22;&#x3E;summed up the what and the why&#x3C;/a&#x3E; of this violation.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I wrote this policy today. It required keeping track of more metadata in Moose. There exist a handful of &#x3C;tt&#x3E;Moose::Meta::Role::Application&#x3C;/tt&#x3E; classes, which track, among other things, an application of a role to a class. We were creating these objects but then discarding them once the application was completed. Instead, I improved Moose so we now keep track of them. Progress!&#x3C;/p&#x3E;

&#x3C;p&#x3E;Let&#x27;s walk through this implementation as well.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;violates_metaclass &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E;  = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Familiar enough.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;for&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$application&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;role_applications&#x3C;/span&#x3E;) {
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$application-&#x26;gt;role&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Every time you consume a role with &#x3C;tt&#x3E;with&#x3C;/tt&#x3E;, it creates an object of class &#x3C;tt&#x3E;Moose::Meta::Role::Application::ToClass&#x3C;/tt&#x3E; and adds it to your metaclass. This object has, among other things, a &#x3C;tt&#x3E;role&#x3C;/tt&#x3E; attribute.&#x3C;/p&#x3E;

&#x3C;p&#x3E;As an aside, it might be interesting to make the &#x3C;tt&#x3E;does&#x3C;/tt&#x3E; method return these role application objects. They&#x27;re certainly true values, and there is precedent: the true value that &#x3C;tt&#x3E;can&#x3C;/tt&#x3E; returns is a code reference.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;for&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role-&#x26;gt;get_method_list&#x3C;/span&#x3E;) {
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$application-&#x26;gt;is_method_excluded&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E;);
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$application-&#x26;gt;is_method_aliased&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E;);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;We need to consider every method in the role. If a method has been excluded or aliased, then that is explicit overriding, so the violation does not apply.&#x3C;/p&#x3E;

&#x3C;p&#x3E;To allow for this explicit override is exactly why I needed to add role-application tracking to Moose, and why I could not implement this policy until today.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method_object&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;get_method&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E;)
                &#x3C;span class=&#x22;synStatement&#x22;&#x3E;or&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E;;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;We inspect the method&#x27;s metaobject from the class. Again, we use &#x3C;tt&#x3E;get_method&#x3C;/tt&#x3E; and not &#x3C;tt&#x3E;find_method_by_name&#x3C;/tt&#x3E; because we do not want to consider inheritance. At this point, the method is definitely there, since it hasn&#x27;t been excluded. What matters now is whether the role provided it or if the class did.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method_object-&#x26;gt;isa&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Moose::Meta::Role::Method&#x27;&#x3C;/span&#x3E;)) {
                &#x3C;span class=&#x22;synStatement&#x22;&#x3E;next&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method_object-&#x26;gt;body&#x3C;/span&#x3E;
                     == &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role-&#x26;gt;get_method&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E;)-&#x26;gt;body;
            }
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Methods of class &#x3C;tt&#x3E;Moose::Meta::Role::Method&#x3C;/tt&#x3E; were originally pulled in from a role. If the method was not provided by a role, then it was a silent class override.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The inside statement makes sure that the method was provided from the correct role, not just any role. If you sequentially apply &#x3C;tt&#x3E;Role::Dog&#x3C;/tt&#x3E; then &#x3C;tt&#x3E;Role::Tree&#x3C;/tt&#x3E;, you would want to know about the implicit override of Dog&#x27;s &#x3C;tt&#x3E;bark&#x3C;/tt&#x3E; method with Tree&#x27;s.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The inside statement also attempts to handle the method coming in from the same role multiple ways. Suppose you have a &#x3C;tt&#x3E;Foo::Basic&#x3C;/tt&#x3E; role with a method &#x3C;tt&#x3E;kerplow&#x3C;/tt&#x3E; that is consumed by both the &#x3C;tt&#x3E;Foo::Advanced&#x3C;/tt&#x3E; and &#x3C;tt&#x3E;Foo::Safe&#x3C;/tt&#x3E; roles. A class that sequentially consumes &#x3C;tt&#x3E;Foo::Advanced&#x3C;/tt&#x3E; then &#x3C;tt&#x3E;Foo::Safe&#x3C;/tt&#x3E; would get the &#x3C;tt&#x3E;kerplow&#x3C;/tt&#x3E; method twice. But since it&#x27;s the exact same implementation (i.e. the same code reference), it&#x27;s not worth warning about. I trust that the programmer will utilize &#x3C;a href=&#x22;http://p3rl.org/Test::Perl::Critic&#x22;&#x3E;&#x3C;tt&#x3E;Test::Perl::Critic&#x3C;/tt&#x3E;&#x3C;/a&#x3E;, so that the divergence of the two &#x3C;tt&#x3E;kerplow&#x3C;/tt&#x3E; methods would become a violation.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class_name&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class-&#x26;gt;name&#x3C;/span&#x3E;;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role_name&#x3C;/span&#x3E;  = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role-&#x26;gt;name&#x3C;/span&#x3E;;

            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$desc&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Class &#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$class_name&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27; method &#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$method&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;&#x26;quot;&#x3C;/span&#x3E;
                     . &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot; implicitly overrides the same method&#x26;quot;&#x3C;/span&#x3E;
                     . &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot; from role &#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$role_name&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;&#x26;quot;&#x3C;/span&#x3E;;
            &#x3C;span class=&#x22;synStatement&#x22;&#x3E;push&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;violation&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$desc&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$EXPL&#x3C;/span&#x3E;);
        }
    }

    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@violations&#x3C;/span&#x3E;;
}
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;And that&#x27;s it.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;PCP::Moose::ProhibitMultipleWiths&#x3C;/h3&#x3E;

&#x3C;p&#x3E;I did write one static policy, which prohibits multiple calls to &#x3C;tt&#x3E;with&#x3C;/tt&#x3E; in one package. Roles provide powerful and safe means of combination, but these are only activated if you actually &#x3C;em&#x3E;combine&#x3C;/em&#x3E; the roles. If you sequentially apply multiple roles to a class, conflicting method names are silently ignored. This could possibly be fixed in the future, but for now we&#x27;ll have to live with this behavior. At least we can now warn you about it.&#x3C;/p&#x3E;

&#x3C;p&#x3E;This implementation is pretty simple as far as &#x3C;tt&#x3E;Perl::Critic&#x3C;/tt&#x3E; policies go. I wrote this one as a static policy because PPI-based analysis is still very worthwhile. It actually would have been easier to implement dynamically. However, as I explained earlier, you would lose out the &#x22;location&#x22; of the violation &#x26;mdash; the second &#x3C;tt&#x3E;with&#x3C;/tt&#x3E;.&#x3C;/p&#x3E;

&#x3C;h3&#x3E;Conclusion&#x3C;/h3&#x3E;

&#x3C;p&#x3E;I&#x27;m quite happy with how dynamic Moose policies are coming along. We now have policies for all the ideas I listed in my previous post. The only one I didn&#x27;t cover, &#x22;Declaring a &#x3C;tt&#x3E;new&#x3C;/tt&#x3E; method instead of using the many object construction hooks&#x22;, was written quickly after my post by Elliot as a static policy.&#x3C;/p&#x3E;

&#x3C;p&#x3E;As far as writing more policies, I think it&#x27;s largely limited by creativity. I was able to write all the policies I wanted. There were some hairy bits, but mostly it was quite pleasant and a novel use of the metaobject protocol.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Ovid has submitted a bug to the Moose RT queue: &#x3C;a href=&#x22;http://rt.cpan.org/Public/Bug/Display.html?id=45591&#x22;&#x3E;Excluded methods should be added to &#x27;requires&#x27;&#x3C;/a&#x3E;. I&#x27;m not sure I agree with his assertion that &#x22;since &#x3C;tt&#x3E;My::Class-&#x26;gt;meta-&#x26;gt;does(&#x27;My::Role::Foo&#x27;)&#x3C;/tt&#x3E;, there&#x27;s a promise that it will provide the &#x3C;tt&#x3E;&#x26;foo&#x3C;/tt&#x3E; method&#x22;. Since this may not make it into core Moose, I invite Ovid to write a policy covering this case. It would look quite similar to the &#x3C;tt&#x3E;ClassOverridesRole&#x3C;/tt&#x3E; policy.&#x3C;/p&#x3E;

&#x3C;p&#x3E;If you have ideas for more policies, or (better yet) would like help implementing them, get in touch with me! I&#x27;d be thrilled to help you out.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The code for the DynamicMoose policies is in &#x3C;a href=&#x22;https://jules.scsys.co.uk/gitweb/gitweb.cgi?p=gitmo/Perl-Critic-Dynamic-Moose.git;a=summary&#x22;&#x3E;Moose&#x27;s git repository&#x3C;/a&#x3E;. Commit bits to this repo are handed out liberally, just ask in &#x3C;tt&#x3E;#moose&#x3C;/tt&#x3E; on &#x3C;tt&#x3E;irc.perl.org&#x3C;/tt&#x3E;. Providing a patch with your request will win you much favor.&#x3C;/p&#x3E;

&#x3C;p&#x3E;These policies have not been battle tested on large codebases, only on the microscopic class hierarchies in its test cases. I expect that &#x3C;tt&#x3E;DynamicMoosePolicy&#x3C;/tt&#x3E; will need more work before it is all ready for wide use. Get your bug reports in before I move on to the next interesting project&#x3C;a href=&#x22;http://github.com/sartak/Class-Browser/tree/master&#x22;&#x3E;.&#x3C;/a&#x3E; :)&#x3C;/p&#x3E;
</description>
<dc:date>2009-05-03</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/04/the-new-moose-warning-and-the-new-moose-critic.html">
<title>The New Moose Warning and the New Moose Critic</title>
<link>http://sartak.org/2009/04/the-new-moose-warning-and-the-new-moose-critic.html</link>
<description>
&#x3C;h4&#x3E;Role Design&#x3C;/h4&#x3E;

&#x3C;blockquote&#x3E;A role is something that classes do. Usually, a role encapsulates some piece of behavior or state that can be shared between classes. It is important to understand that &#x3C;i&#x3E;roles are not classes&#x3C;/i&#x3E;. You cannot inherit from a role, and a role cannot be instantiated. We sometimes say that roles are &#x3C;i&#x3E;consumed&#x3C;/i&#x3E;, either by classes or other roles.&#x3C;br /&#x3E;&#x3C;br /&#x3E;A role can be &#x3C;i&#x3E;composed&#x3C;/i&#x3E; into a class. In practical terms, this means that all of the methods and attributes defined in a role are added directly to (we sometimes say &#x22;flattened into&#x22;) the class that consumes the role. These attributes and methods then appear as if they were defined in the class itself. A subclass of the consuming class will inherit all of these methods and attributes.&#x3C;br /&#x3E;&#x3C;br /&#x3E;&#x3C;span class=&#x22;attribution&#x22;&#x3E;&#x26;ndash; Dave Rolsky in &#x3C;a href=&#x22;http://p3rl.org/Moose::Manual::Roles&#x22;&#x3E;Moose::Manual::Roles&#x3C;/a&#x3E;&#x3C;/span&#x3E;&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;Roles can be composed to create new roles. This is not like inheritance; this operation is actually &#x3C;i&#x3E;commutative summation&#x3C;/i&#x3E;. This does not establish a hierarchy, instead it creates a composite role with the methods, attributes, requirements, etc. of its component roles. If two or more roles in the composition provide different methods with the same name, a &#x3C;i&#x3E;conflict&#x3C;/i&#x3E; is generated. Such conflicts do not immediately issue fatal errors, but they must be &#x3C;i&#x3E;resolved&#x3C;/i&#x3E; at composition time. One of the ways a role consumer can resolve such a conflict is by providing its own implementation of the conflicted method name. The method could do whatever the programmer sees fit, but it is most sensible for this custom implementation to invoke the conflicting methods from the component roles.&#x3C;/p&#x3E;

&#x3C;p&#x3E;For example, consider two roles that provide a &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method. A class can consume the summation of these two roles. Since the two component roles each attempted to contribute a &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method, &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; is a conflicted method in the composite role. To resolve this conflict, a consuming class must define its own &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method. The class&#x27;s &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method should generally call the &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method of both roles. However, the class needs some way to disambiguate the two roles&#x27; &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; methods so that it can call each in turn. For this reason, roles support &#x3C;i&#x3E;method aliasing&#x3C;/i&#x3E;. The consumer can alias each role&#x27;s &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; methods. Aliasing only adds a new name for a method; it does not change the name of any method. That means the original &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; methods are still conflicting. The consuming class can provide a &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method to resolve this conflict, whose implementation calls each role&#x27;s &#x3C;i&#x3E;aliased&#x3C;/i&#x3E; &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E;.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synComment&#x22;&#x3E;# this &#x26;quot;with&#x26;quot; sums the two roles then applies one role to the class&#x3C;/span&#x3E;
with (
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Role::Foo&#x27;&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;alias&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;validate&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;validate_foo&#x27;&#x3C;/span&#x3E; } },
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Role::Bar&#x27;&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;alias&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;validate&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;validate_bar&#x27;&#x3C;/span&#x3E; } },
);

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;validate &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;validate_foo&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;);
    &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self-&#x26;gt;validate_bar&#x3C;/span&#x3E;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;);
}
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;While this may seem like a lot of effort, role design has very nice theoretical &#x3C;em&#x3E;and practical&#x3C;/em&#x3E; properties. Unlike multiple inheritance and mixins, &#x3C;b&#x3E;roles issue an error when there is an unresolved naming conflict&#x3C;/b&#x3E;. The programmer has good tools for resolving conflicts: method aliasing, method &#x3C;i&#x3E;exclusion&#x3C;/i&#x3E;, and method &#x3C;i&#x3E;overriding&#x3C;/i&#x3E;. In our above example, the consuming class could have excluded the &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method from one of the two roles so that there would be no conflict (since only one role is providing a method with that name). Finally, the consuming class could have overridden the conflicted &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; method. The overriding implementation may not need to call the component roles&#x27; &#x3C;tt&#x3E;validate&#x3C;/tt&#x3E; methods, perhaps obviating the need for aliasing. The example above used a combination of aliasing and overriding. All of these features are available even when there are no method conflicts, granting additional flexibility to roles.&#x3C;/p&#x3E;

&#x3C;h4&#x3E;The New Moose Warning&#x3C;/h4&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal/&#x22;&#x3E;Ovid&#x3C;/a&#x3E; has written eleven articles on roles since March 4th (as of this posting). Most of them have &#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal/38662&#x22;&#x3E;praised roles&#x3C;/a&#x3E; and explained his happiness with how &#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal/38785&#x22;&#x3E;comprehensible&#x3C;/a&#x3E; his large &#x3C;s&#x3E;class&#x3C;/s&#x3E; role space has become. However, in &#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal/38809&#x22;&#x3E;Not All Features Are Useful (Moose Roles)&#x3C;/a&#x3E;, Ovid describes his frustration at spending a long time trying to discover an unintentional use of the &#x3C;i&#x3E;method overriding&#x3C;/i&#x3E; feature. Which is silent.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Marcus Ramberg was the first to suggest the addition a warning to the Moose core when a class overrides a method from a role it consumes. This way we could push the &#x22;frontier&#x22; of the beloved collision detection a little further, into boundary between roles and classes. The warning (which was uncannily easy to implement, as if it had existed in a past &#x3C;i&#x3E;Alces&#x3C;/i&#x3E;) would read like:&#x3C;/p&#x3E;

&#x3C;blockquote&#x3E;The Quux class has implicitly overridden the method (validate) from role Role::Foo. If this is intentional, please exclude the method from composition to silence this warning (see Moose::Cookbook::Roles::Recipe2)&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;I was one of the &#x3C;em&#x3E;very&#x3C;/em&#x3E; few vocal proponents of this new warning. Suggesting to users that they explicitly list which methods they &#x3C;em&#x3E;intended&#x3C;/em&#x3E; to exclude from composition would benefit maintainability. Other developers would not have to guess whether each method override was intentional or not; intention would be evident from the exclusions, or lack thereof. In a large, evolving system, accidental name collisions are bound to happen. I&#x27;d much prefer a &#x3C;em&#x3E;compile-time&#x3C;/em&#x3E; warning over spending even ten minutes debugging why my application decided to start connecting to a database named &#x22;Shawn Moore&#x22;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;However, &#x3C;strong&#x3E;many&#x3C;/strong&#x3E; people were unhappy with this warning, because it complained about perfectly valid &#x3C;em&#x3E;semantics&#x3C;/em&#x3E;. Classes overriding local role methods has been in the design of roles since they were conceived as &#x3C;a href=&#x22;http://scg.unibe.ch/research/traits&#x22;&#x3E;traits&#x3C;/a&#x3E; by Smalltalk researchers. Due to limitations in Perl&#x27;s builtin warning system, the warning was also difficult to disable for a particular scope.&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://www.modernperlbooks.com/&#x22;&#x3E;chromatic&#x3C;/a&#x3E; in particular decried this new warning in his article &#x3C;a href=&#x22;http://www.modernperlbooks.com/mt/2009/04/the-value-of-a-warning.html&#x22;&#x3E;The Value of a Warning&#x3C;/a&#x3E;. While I continue to disagree with a few of his specific points, the argument he made in a comment on Ovid&#x27;s &#x3C;a href=&#x22;http://use.perl.org/~Ovid/journal/38862&#x22;&#x3E;Well, Now I Know (Roles)&#x3C;/a&#x3E; article struck a chord.&#x3C;/p&#x3E;

&#x3C;blockquote&#x3E;The moment you throw a mandatory default warning on two of the four appropriate and specified uses of roles, you&#x27;ve penalized them. You&#x27;re subtly encouraging people not to use the most important and most powerful features of roles! You&#x27;re actively discouraging people from taking advantage of alloorphism using well-established and long-recommended design techniques explicitly made safer and more understandable by roles.&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;He&#x27;s absolutely correct. Even subtly discouraging users from perfectly good designs is unacceptable. I reverted the warning.&#x3C;/p&#x3E;

&#x3C;h4&#x3E;The New Moose Critic&#x3C;/h4&#x3E;

&#x3C;p&#x3E;One of the suggested ideas was to leave the warning disabled by default. For a while I thought it was quite ridiculous to turn Perl&#x27;s own warnings on in your class, but leave Moose&#x27;s own warnings off. After all, we have &#x3C;a href=&#x22;http://p3rl.org/Modern::Perl&#x22;&#x3E;grown&#x3C;/a&#x3E; as a community to love &#x3C;tt&#x3E;use warnings&#x3C;/tt&#x3E;; it would be silly to repeat that default-off mistake.&#x3C;/p&#x3E;

&#x3C;p&#x3E;The final section of chromatic&#x27;s &#x3C;a href=&#x22;http://www.modernperlbooks.com/mt/2009/04/the-value-of-a-warning.html&#x22;&#x3E;The Value of a Warning&#x3C;/a&#x3E; held the best compromise. I was dead set against warnings that were off by default, so I didn&#x27;t give the ideas the thorough consideration they deserved.&#x3C;/p&#x3E;

&#x3C;blockquote&#x3E;Compare that to optional &#x3C;a href=&#x22;http://p3rl.org/Perl::Critic&#x22;&#x3E;Perl::Critic&#x3C;/a&#x3E; warnings. If your project decides that a method length of more than 24 lines is a code smell, you can determine that yourself. If you decide that a specified, implemented, and tested feature of Perl 5 is troublesome (&#x3C;tt&#x3E;tie&#x3C;/tt&#x3E;), you can disallow it yourself locally.&#x3C;/blockquote&#x3E;

&#x3C;p&#x3E;What we need is a set of Perl::Critic policies for Moose. Elliot Shank has already started a &#x3C;a href=&#x22;http://p3rl.org/Perl::Critic::Moose&#x22;&#x3E;Perl::Critic::Moose&#x3C;/a&#x3E; for, among other things, ensuring (statically) that you make your classes immutable.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Moose stores plenty of data in its metaobjects, rich for plunder. Though nearly all of Perl::Critic performs &#x3C;i&#x3E;static&#x3C;/i&#x3E; analysis, there &#x3C;em&#x3E;is&#x3C;/em&#x3E; precedent for &#x3C;a href=&#x22;http://p3rl.org/Perl::Critic::Dynamic&#x22;&#x3E;dynamic Perl::Critic policies&#x3C;/a&#x3E;. We could stand on the shoulders of the Perl::Critic giants so as to reuse and contribute to their &#x3C;a href=&#x22;http://p3rl.org/Perl::Critic#CONFIGURATION&#x22;&#x3E;configuration system&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://p3rl.org/Test::Perl::Critic&#x22;&#x3E;testing modules&#x3C;/a&#x3E;, and great community.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Some easily-implemented dynamic Moose policies (of varying severity) could highlight:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Classes overriding methods from locally consumed roles&#x3C;/li&#x3E;
&#x3C;li&#x3E;Classes overriding methods from their superclasses without using method modifiers (including the &#x3C;a href=&#x22;http://p3rl.org/Moose#override&#x22;&#x3E;override&#x3C;/a&#x3E; modifier)&#x3C;/li&#x3E;
&#x3C;li&#x3E;Declaring &#x3C;a href=&#x22;http://p3rl.org/Moose#builder&#x22;&#x3E;builder methods&#x3C;/a&#x3E; without leading underscores&#x3C;/li&#x3E;
&#x3C;li&#x3E;Leaving classes mutable&#x3C;/li&#x3E;
&#x3C;li&#x3E;Declaring &#x3C;tt&#x3E;new&#x3C;/tt&#x3E; methods instead of using the many &#x3C;a href=&#x22;http://p3rl.org/Moose::Cookbook::Basics::Recipe11&#x22;&#x3E;object construction hooks&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;

&#x3C;p&#x3E;I think this is an excellent compromise and I can&#x27;t wait to begin implementing Moose policies.&#x3C;/p&#x3E;
</description>
<dc:date>2009-04-24</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/03/breaking-sys-protect.html">
<title>Breaking Sys::Protect</title>
<link>http://sartak.org/2009/03/breaking-sys-protect.html</link>
<description>
&#x3C;p&#x3E;&#x3C;a href=&#x22;http://p3rl.org/Sys::Protect&#x22;&#x3E;Sys::Protect&#x3C;/a&#x3E; does not bill itself as unbreakable protection, but it&#x27;s fun to break it anyway.&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://p3rl.org/PadWalker&#x22;&#x3E;PadWalker&#x3C;/a&#x3E; is used as an example of an XS module that could seriously mess with other code. &#x3C;a href=&#x22;http://p3rl.org/Math::BigInt::FastCalc&#x22;&#x3E;Math::BigInt::FastCalc&#x3C;/a&#x3E; is specifically allowed by Sys::Protect to perform unsafe operations because its domain is only big integers, it is used by a lot of other modules, and because its XS code has been verified to be safe.&#x3C;/p&#x3E;


&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synPreProc&#x22;&#x3E;#!/usr/bin/env perl&#x3C;/span&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;no strict&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use warnings&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Sys::Protect;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Test::More &#x3C;span class=&#x22;synConstant&#x22;&#x3E;tests&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;;

XSLoader::load(&#x3C;span class=&#x22;synStatement&#x22;&#x3E;bless&#x3C;/span&#x3E; {}, &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Break::Sys::Protect&#x27;&#x3C;/span&#x3E;);

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$password&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;c53eb8f992b4fdf70a03a4d437820028&#x27;&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$authenticate&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{ &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;eq&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$password&#x3C;/span&#x3E; };
is(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;${&#x3C;/span&#x3E;PadWalker::closed_over(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$authenticate&#x3C;/span&#x3E;)&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;-&#x26;gt;{&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;$password&#x27;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;}}&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$password&#x3C;/span&#x3E;);

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Break::Sys::Protect&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use overload&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;q{&#x26;quot;&#x26;quot;}&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Math::BigInt::FastCalc&#x26;quot;&#x3C;/span&#x3E;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;if&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;caller&#x3C;/span&#x3E; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;eq&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Sys::Protect&#x27;&#x3C;/span&#x3E;;

    &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$_[&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;]&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;PadWalker&#x26;quot;&#x3C;/span&#x3E;;
}; 
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Don&#x27;t use Sys::Protect. :)&#x3C;/p&#x3E;

&#x3C;p&#x3E;edit: I&#x27;ve been told by Sys::Protect&#x27;s authors that it is a proof of concept for testing Perl code under environments similar to what Google App Engine supports. Such a platform would presumably remove the dangerous opcodes entirely, so vulnerabilities like this couldn&#x27;t exist.&#x3C;/p&#x3E;
</description>
<dc:date>2009-03-25</dc:date>
</item>
<item rdf:about="http://sartak.org/2009/01/parametric-roles-in-perl-5.html">
<title>Parametric Roles in Perl 5</title>
<link>http://sartak.org/2009/01/parametric-roles-in-perl-5.html</link>
<description>
&#x3C;p&#x3E;Jonathon Worthington just wrote about &#x3C;a href=&#x22;http://use.perl.org/~JonathanWorthington/journal/38308&#x22;&#x3E;Perl 6&#x27;s new support for parametric roles&#x3C;/a&#x3E;. Excellent!&#x3C;/p&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;http://p3rl.org/Moose&#x22;&#x3E;Moose&#x3C;/a&#x3E; supports this feature too, through the &#x3C;a href=&#x22;http://p3rl.org/MooseX::Role::Parameterized&#x22;&#x3E;MooseX::Role::Parameterized&#x3C;/a&#x3E; extension I wrote a little over a month ago. It has proved to be a very useful pattern. I&#x27;m pleased that Perl 6 has it built in.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Out of curiosity, I ported the examples Jonathon provided to MXRP. I&#x27;ll have to work more with rafl to make &#x3C;a href=&#x22;http://p3rl.org/MooseX::Declare&#x22;&#x3E;MooseX::Declare&#x3C;/a&#x3E; support something resembling Perl 6&#x27;s much nicer syntax. We do plan on having syntax for positional parameters in much the same way Perl 6&#x27;s parametric roles do.&#x3C;/p&#x3E;


&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Greet&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;MooseX::Role::Parameterized;

parameter &#x3C;span class=&#x22;synConstant&#x22;&#x3E;greeting&#x3C;/span&#x3E; =&#x26;gt; (
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;is&#x3C;/span&#x3E;       =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;ro&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;isa&#x3C;/span&#x3E;      =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Str&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;required&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;,
);

role {
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$greeting&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p-&#x26;gt;greeting&#x3C;/span&#x3E;;

    method &#x3C;span class=&#x22;synConstant&#x22;&#x3E;greet&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;print&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$greeting&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;!&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;\n&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E;;
    };
};

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; EnglishMan&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Greet&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;greeting&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Hello&#x26;quot;&#x3C;/span&#x3E; };

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Slovak&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Greet&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;greeting&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Ahoj&#x26;quot;&#x3C;/span&#x3E; };

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Lolcat&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Greet&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;greeting&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;OH HAI&#x26;quot;&#x3C;/span&#x3E; };

EnglishMan-&#x26;gt;new-&#x26;gt;greet; &#x3C;span class=&#x22;synComment&#x22;&#x3E;# Hello!&#x3C;/span&#x3E;
Slovak-&#x26;gt;new-&#x26;gt;greet; &#x3C;span class=&#x22;synComment&#x22;&#x3E;# Ahoj!&#x3C;/span&#x3E;
Lolcat-&#x26;gt;new-&#x26;gt;greet; &#x3C;span class=&#x22;synComment&#x22;&#x3E;# OH HAI!&#x3C;/span&#x3E;
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;I&#x27;ll skip the second example because it&#x27;s contained by the third example.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Moose doesn&#x27;t give you multiple dispatch. &#x3C;i&#x3E;sigh!&#x3C;/i&#x3E; Instead we model the problem with a default value for the transform, which is a code reference. In this way we meet the original requirement of EnglishMan and Lolcat not needing to provide a nominative-&#x26;gt;accusative transform.&#x3C;/p&#x3E;


&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Request&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;MooseX::Role::Parameterized;

parameter &#x3C;span class=&#x22;synConstant&#x22;&#x3E;statement&#x3C;/span&#x3E; =&#x26;gt; (
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;is&#x3C;/span&#x3E;       =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;ro&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;isa&#x3C;/span&#x3E;      =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;Str&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;required&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;1&#x3C;/span&#x3E;,
);

parameter &#x3C;span class=&#x22;synConstant&#x22;&#x3E;transform&#x3C;/span&#x3E; =&#x26;gt; (
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;is&#x3C;/span&#x3E;      =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;ro&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;isa&#x3C;/span&#x3E;     =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x27;CodeRef&#x27;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;default&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{ &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$_[&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;]&#x3C;/span&#x3E; }, &#x3C;span class=&#x22;synComment&#x22;&#x3E;# identity function&#x3C;/span&#x3E;
    },
);

role {
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$statement&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p-&#x26;gt;statement&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$transform&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$p-&#x26;gt;transform&#x3C;/span&#x3E;;

    method &#x3C;span class=&#x22;synConstant&#x22;&#x3E;request&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;{
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; (&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$self&#x3C;/span&#x3E;, &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$object&#x3C;/span&#x3E;) = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;@_&#x3C;/span&#x3E;;
        &#x3C;span class=&#x22;synStatement&#x22;&#x3E;print&#x3C;/span&#x3E; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$statement&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E; &#x26;quot;&#x3C;/span&#x3E; . &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$transform&#x3C;/span&#x3E;-&#x26;gt;(&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$object&#x3C;/span&#x3E;) . &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;?&#x3C;/span&#x3E;&#x3C;span class=&#x22;synSpecial&#x22;&#x3E;\n&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;&#x3C;/span&#x3E;;
    };
};

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Language::Slovak&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;sub &#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;accusative &#x3C;/span&#x3E;{
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$nom&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synStatement&#x22;&#x3E;shift&#x3C;/span&#x3E;;
    (&#x3C;span class=&#x22;synStatement&#x22;&#x3E;my&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$acc&#x3C;/span&#x3E; = &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$nom&#x3C;/span&#x3E;) =~ &#x3C;span class=&#x22;synStatement&#x22;&#x3E;s/&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;a$&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;/&#x3C;/span&#x3E;&#x3C;span class=&#x22;synConstant&#x22;&#x3E;u&#x3C;/span&#x3E;&#x3C;span class=&#x22;synStatement&#x22;&#x3E;/&#x3C;/span&#x3E;;
    &#x3C;span class=&#x22;synStatement&#x22;&#x3E;return&#x3C;/span&#x3E; &#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;$acc&#x3C;/span&#x3E;;
}

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; EnglishMan&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Request&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;statement&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Please can I have a&#x26;quot;&#x3C;/span&#x3E; };

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Slovak&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Request&#x3C;/span&#x3E; =&#x26;gt; {
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;statement&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;Prosim si&#x26;quot;&#x3C;/span&#x3E;,
    &#x3C;span class=&#x22;synConstant&#x22;&#x3E;transform&#x3C;/span&#x3E; =&#x26;gt; \&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;&#x26;amp;&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E;Language::Slovak::&#x3C;/span&#x3E;&#x3C;span class=&#x22;synIdentifier&#x22;&#x3E;accusative&#x3C;/span&#x3E;,
};

&#x3C;span class=&#x22;synStatement&#x22;&#x3E;package&#x3C;/span&#x3E;&#x3C;span class=&#x22;synType&#x22;&#x3E; Lolcat&#x3C;/span&#x3E;;
&#x3C;span class=&#x22;synStatement&#x22;&#x3E;use &#x3C;/span&#x3E;Moose;
with &#x3C;span class=&#x22;synConstant&#x22;&#x3E;Request&#x3C;/span&#x3E; =&#x26;gt; { &#x3C;span class=&#x22;synConstant&#x22;&#x3E;statement&#x3C;/span&#x3E; =&#x26;gt; &#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;I CAN HAZ&#x26;quot;&#x3C;/span&#x3E; };

EnglishMan-&#x26;gt;new-&#x26;gt;request(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;yorkshire pudding&#x26;quot;&#x3C;/span&#x3E;);
Slovak-&#x26;gt;new-&#x26;gt;request(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;boravicka&#x26;quot;&#x3C;/span&#x3E;);
Lolcat-&#x26;gt;new-&#x26;gt;request(&#x3C;span class=&#x22;synConstant&#x22;&#x3E;&#x26;quot;CHEEZEBURGER&#x26;quot;&#x3C;/span&#x3E;);
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;I have no conclusion, except that Perl 5 hasn&#x27;t been stagnant, though its new features can be a lot more verbose than in Perl 6.&#x3C;/p&#x3E;
</description>
<dc:date>2009-01-17</dc:date>
</item>
<item rdf:about="http://sartak.org/2007/09/devel-repl-now-with-multiline-support.html">
<title>Devel::REPL: Now with Multiline Support</title>
<link>http://sartak.org/2007/09/devel-repl-now-with-multiline-support.html</link>
<description>
&#x3C;p&#x3E;I&#x27;ve been using &#x3C;a href=&#x22;http://p3rl.org/Devel::REPL&#x22;&#x3E;Devel::REPL&#x3C;/a&#x3E; for a while now. Like all good modules (&#x3C;a href=&#x22;http://p3rl.org/Perl::Critic&#x22;&#x3E;Perl::Critic&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://p3rl.org/POE&#x22;&#x3E;POE&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://p3rl.org/Plagger&#x22;&#x3E;Plagger&#x3C;/a&#x3E;, etc), it&#x27;s very extensible. &#x3C;a href=&#x22;http://chainsawblues.vox.com/library/post/a-perl-read-excute-print-loop-repl.html&#x22;&#x3E;Devel::REPL&#x27;s design&#x3C;/a&#x3E; is worth studying: keep a simple core and ship all the fancy behavior as plugins. &#x3C;a href=&#x22;http://p3rl.org/Moose&#x22;&#x3E;Moose&#x3C;/a&#x3E; amplifies the power and convenience of this design with roles, method modifiers, and general awesomeness.&#x3C;/p&#x3E;

&#x3C;p&#x3E;There are plugins to dump output with &#x3C;a href=&#x22;http://p3rl.org/Data::Dump::Streamer&#x22;&#x3E;Data::Dump::Streamer&#x3C;/a&#x3E;, enable tab completion of the current lexical environment and loaded modules, save input history across sessions, and more. However, if you dabble in other P-languages such as Python and Ruby (know thy enemy.. honest!) you&#x27;ll find yourself wanting more out of Devel::REPL. Let&#x27;s take the example of writing a factorial function in python:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;perl code_snippet&#x22;&#x3E;
% python
Python 2.3.5 (#1, Dec  7 2006, 14:50:51)
[GCC 4.0.1 (Apple Computer, Inc. build 5363) (+4864187)] on darwin
Type &#x22;help&#x22;, &#x22;copyright&#x22;, &#x22;credits&#x22; or &#x22;license&#x22; for more information.
&#x26;gt;&#x26;gt;&#x26;gt; def fact(n):
...     if n &#x26;lt; 2:
...         return 1
...     return n * fact(n - 1)
...
&#x26;gt;&#x26;gt;&#x26;gt; fact(10)
3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;in irb:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% irb
irb(main):001:0&#x26;gt; def fact(n)
irb(main):002:1&#x26;gt; if n &#x26;lt; 2
irb(main):003:2&#x26;gt; 1
irb(main):004:2&#x26;gt; else
irb(main):005:2* n * fact(n-1)
irb(main):006:2&#x26;gt; end
irb(main):007:1&#x26;gt; end
=&#x26;gt; nil
irb(main):008:0&#x26;gt; fact 10
=&#x26;gt; 3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;in lua:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% lua
Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio
&#x26;gt; function fact(n)
&#x26;gt;&#x26;gt; if n &#x26;lt; 2 then
&#x26;gt;&#x26;gt; return 1
&#x26;gt;&#x26;gt; else
&#x26;gt;&#x26;gt; return n * fact(n-1)
&#x26;gt;&#x26;gt; end
&#x26;gt;&#x26;gt; end
&#x26;gt; =fact(10)
3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;and in Devel::REPL:&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% re.pl
$ sub fact {
Compile error: Missing right curly or square bracket at (eval 60) line
8, at end of line
syntax error at (eval 60) line 8, at EOF
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;D&#x27;oh. OK, let&#x27;s try again..&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% re.pl
$ sub fact { my $n = shift; return 1 if $n &#x26;lt; 2; $n * fact($n - 1) }

$ fact 10
3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;Well, that works in this case, but one big line of code quickly becomes unmanageable.&#x3C;/p&#x3E;

&#x3C;p&#x3E;Recently I had the idea to use &#x3C;a href=&#x22;http://p3rl.org/PPI&#x22;&#x3E;PPI&#x3C;/a&#x3E; to figure out if the current line of code is complete. PPI::Dumper quickly confirmed that I can detect the most important case: a PPI::Structure that doesn&#x27;t have both a -&#x26;gt;start and -&#x26;gt;finish. Structures encompass { {nested { blocks } } }, (parentheses), [array indexing], {hash indexing}, and so on. Hopefully future versions of PPI will be able to figure out that, say, an s/// or quoted string is incomplete.&#x3C;/p&#x3E;&#x3C;p&#x3E;Here&#x27;s what the factorial example looks like with the MultiLine::PPI plugin.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% re.pl
$ load_plugin &#x27;MultiLine::PPI&#x27;
1
$ sub fact {
&#x26;gt; my $n = shift;
&#x26;gt; return 1 if $n &#x26;lt; 2;
&#x26;gt; $n * fact($n - 1);
&#x26;gt; }

$ fact 10
3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;I believe Devel::REPL is the only Perl REPL that can do this. Hooray! :)&#x3C;/p&#x3E;

&#x3C;p&#x3E;You can change the default prompts with my FancyPrompt plugin. Here&#x27;s how I actually have my prompt (code is slightly different to show off nesting). It may look like &#x22;ugh&#x22;, but it&#x27;s actually really nice when you&#x27;re in the driver&#x27;s seat.&#x3C;/p&#x3E;

&#x3C;pre class=&#x22;code_snippet&#x22;&#x3E;
% re.pl
&#x26;gt; sub fact {
&#x26;gt;&#x26;gt; my $n = shift;
&#x26;gt;&#x26;gt; if ($n &#x26;lt; 2) {
&#x26;gt;&#x26;gt;&#x26;gt; return 1;
&#x26;gt;&#x26;gt;&#x26;gt; }
&#x26;gt;&#x26;gt; else {
&#x26;gt;&#x26;gt;&#x26;gt; return $n * fact($n-1);
&#x26;gt;&#x26;gt;&#x26;gt; }
&#x26;gt;&#x26;gt; }

&#x26;gt; fact 10
3628800
&#x3C;/pre&#x3E;

&#x3C;p&#x3E;MultiLine::PPI hasn&#x27;t been CPANed yet, but you can get it (and other new plugins) from &#x3C;a href=&#x22;http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Devel-REPL.git;a=summary&#x22;&#x3E;the Devel::REPL git repository&#x3C;/a&#x3E;.&#x3C;/p&#x3E;

&#x3C;p&#x3E;I&#x27;ll continue stealing good features from other REPLs. :)&#x3C;/p&#x3E;
</description>
<dc:date>2007-09-21</dc:date>
</item>
</rdf:RDF>
