markjugg's Journal http://use.perl.org/~markjugg/journal/ markjugg's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:11:34+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 markjugg's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~markjugg/journal/ Moving my Perl blogging from use.perl.org http://use.perl.org/~markjugg/journal/38192?from=rss <p>Joining several others, I'm moving my Perl blogging off of use.perl.org. My personal Perl blog posts will be <a href="http://mark.stosberg.com/blog/perl/">here</a>.</p><p>I sometimes write about Perl on my company blog <a href="http://www.summersault.com/community/weblog/category/perl">here</a>.</p><p>On my own site, I'll be able to see my own traffic stats, control the SEO, and provide a unique design. I think having a plurality of blogs promoting and discussing Perl is a good thing.</p><p>My perl feed also appears as one of the feeds on <a href="http://perlsphere.net/">Perl Sphere</a>.</p> markjugg 2008-12-31T21:28:52+00:00 journal HTTP::Engine drops Moose for Shika, gains massive speedup http://use.perl.org/~markjugg/journal/37998?from=rss When I <a href="http://mark.stosberg.com/blog/2008/11/startup-benchmarks-for-mojo-catalyst-titanium-httpengine-and-cgiapplication.html">recently benchmarked</a> several Perl website development tools, HTTP::Engine had dismal performance. The slowest performer, it took 1.5 seconds just to print "Hello World" in a CGI environment and took 14.6 megs of memory to it. <p> Today the first HTTP::Engine release appeared that replaces <a href="http://search.cpan.org/perldoc?Moose">Moose</a> with <a href="http://search.cpan.org/perldoc?Shika">Shika</a>. Shika provides the essential class-building tools that HTTP::Engine needs with a Moose-compatible syntax, and strips out the rest of the magic. </p><p> The performance improvement was dramatic. The "Hello World" time dropped to 0.19seconds on the same hardware (almost 10 times as fast!) and the memory usage dropped to 6.6 Megs. </p><p> Catalyst is currently slated to use Moose in the next major version. Now that HTTP::Engine has switched away from Moose for better performance and memory savings, will other projects follow suit?</p> markjugg 2008-12-01T23:08:46+00:00 journal Dear Lazyweb: Create a visual timeline of my e-mail folders http://use.perl.org/~markjugg/journal/37687?from=rss <p>Sometimes when I'm scanning an email archive, it would be useful to see it represented as a timeline. So instead of a stored listed, I'd see a cluster of messages in October 2007, and then another bunch in summer 2008, and could zoom in on that.</p><p>The closest interface that comes to mind is the bar graph display seen in modern Movable Type admin areas.</p> markjugg 2008-10-17T13:55:53+00:00 journal Dear Lazyweb: Help me solve a hard bug in a popular module http://use.perl.org/~markjugg/journal/37596?from=rss <p>At some point a CGI::Application::Plugin::ValidateRM test started failing, and I'm having a heck of time figuring out why.</p><p>I'm fairly sure something in the dependency chain changed behavior, and I've been unable to track down what the real issue is.</p><p><a href="http://rt.cpan.org/Public/Bug/Display.html?id=35056">Take a look at the bug report</a> and the <a href="http://www.cpantesters.org/show/CGI-Application-Plugin-ValidateRM.html">test reports</a>.</p><p>I'll be in Portland, OR next week (and will possibly attend the PDX PM meeting), and hopefully Lazyweb will have an answer for me about this when I get back.</p> markjugg 2008-10-03T14:08:03+00:00 journal Progress on making a self-contained Titanium distribution http://use.perl.org/~markjugg/journal/37556?from=rss <p>Today I made progress on making a self-contained distribution of the <a href="http://search.cpan.org/perldoc">Titanium</a> web framework.</p><p>The goal is to have a single archive file you can unpack and have a complete web framework to work with-- no more CPAN dependencies to install! You can play with it on your desktop or laptop with the built-in web server, and upload a directory to your web server when you read to go live.</p><p>After I <a href="http://rt.cpan.org/Ticket/Display.html?id=39644">patched the great local::lib</a> module, I can now use this simple command to create a "Titanium" directory, into which Titanium and all of it's non-core dependencies will be installed.</p><p><code><br>perl -MCPAN -Mlocal::lib=--self-contained,Titanium -e 'install Titanium'<br></code></p><p>The next step is to hopefully eliminate required dependencies on XS code. The following modules need to be address:</p><ul><li> Compress::Raw::Zlib </li><li> HTML::Parser </li><li> Params::Validate </li></ul><p>Params::Validate should be easy to handle, since it has a Pure Perl alternative. I haven't decided now to deal with the other two yet.</p><p>I can post an archive of what I have so far if it's of interest. The XS modules above are compiled for 'i486-linux-gnu-thread-multi'.</p><p>&lt;pokes around &gt;</p><p>Yes, Params::Validate was easy enough to take care of. For the other two, I may just handle them with documentation:</p><p>"If you want to use fill_form()" method, you may need to install the "HTML::Parser" module, which requires access to a C compiler".</p><p>"Likewise, if you want to use Test::WWW::Mechanize, you may need to install Compress::Zlib, which requires also requires access to a C-compiler"</p> markjugg 2008-09-27T21:24:07+00:00 journal Devel::Declare: A good fit for .pmc files? http://use.perl.org/~markjugg/journal/37540?from=rss <p>Devel::Declare seems to be the new hotness, quickly inspiring several more modules to use it including <a href="http://search.cpan.org/perldoc?Method::Signatures">Method::Signatures</a>, <a href="http://search.cpan.org/perldoc?MooseX::Method::Signatures">MooseX::Method::Signatures</a>, <a href="http://search.cpan.org/perldoc?Sub::Curried">Sub::Curried, </a><a href="http://search.cpan.org/perldoc?Sub::Auto">Sub::Auto</a>, and <a href="http://www.erlbaum.net/pipermail/cgiapp/2008q3/000726.html">CGI::Application::Plugin::RunmodeDeclare</a>.</p><p>But whose ready to run this hairy black magic and production? Perhaps this is good match for using<nobr> <wbr></nobr><a href="http://search.cpan.org/perldoc?Module::Compile">.pmc files</a>? If it works, it would mean that Devel::Declare is not actually used in production, but pure Perl ".pmc" file are used instead, which contains code that Devel::Declare generates.</p><p>Workable? Good idea?</p> markjugg 2008-09-25T14:17:50+00:00 journal My favorite part of Perl 6 available now in Perl 5 http://use.perl.org/~markjugg/journal/37509?from=rss <p>Perhaps my favorite parts of Perl 6 are subroutine signatures and getting rid of "<code>my $self = shift;</code>".</p><p>These features available now in Perl 5, without source filters, using <a href="http://search.cpan.org/perldoc?Method::Signatures">Method::Signatures</a>.</p><p>Sure, it's labeled as "ALPHA" involves some dark magic to make it work, but it's there to play with. And if it can be hacked up as a module, surely it would be feasible to add to Perl 5.12....</p> markjugg 2008-09-22T14:34:14+00:00 journal Announcing Titanium, a strong, lightweight web framework http://use.perl.org/~markjugg/journal/37139?from=rss <p>The first developer release of <a href="http://search.cpan.org/perldoc?Titanium">Titanium</a> has now been<br>uploaded to CPAN and should be available shortly.</p><p>Titanium is a next generation web framework based on CGI::Application.<br>Titanium is designed to provide the underlying strength and flexibility of the<br>CGI::Application framework, while being more user-friendly to deploy and<br>develop with.</p><p>To this end, several useful plugins for CGI::Application are bundled by default<br>with CGI::Application and are documented directly in Titanium.</p><p>Several practices are specifically recommended and documented, such as using<br>URI dispatching, while details for alternative and advanced functionality for<br>CGI::Application are not included here. Those advanced docs remain available in<br>CGI::Application.</p><p>Several useful development and testing tools are installed along with Titanium as well.<br>Here's the full list modules that come with it:</p><p><a href="http://search.cpan.org/perldoc?CGI::Application::Dispatch">CGI::Application::Dispatch</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Server">CGI::Application::Server</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::ConfigAuto">CGI::Application::Plugin::ConfigAuto</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::DBH">CGI::Application::Plugin::DBH</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::DebugScreen">CGI::Application::Plugin::DebugScreen</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::DevPopup">CGI::Application::Plugin::DevPopup</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::ErrorPage">CGI::Application::Plugin::ErrorPage</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::FillInForm">CGI::Application::Plugin::FillInForm</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::Forward">CGI::Application::Plugin::Forward</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::LogDispatch">CGI::Application::Plugin::LogDispatch</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::Redirect">CGI::Application::Plugin::Redirect</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::Session">CGI::Application::Plugin::Session</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::Stream">CGI::Application::Plugin::Stream</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Plugin::ValidateRM">CGI::Application::Plugin::ValidateRM</a><br><a href="http://search.cpan.org/perldoc?CGI::Application::Standard::Config">CGI::Application::Standard::Config</a><br><a href="http://search.cpan.org/perldoc?Module::Starter::Plugin::CGIApp">Module::Starter::Plugin::CGIApp</a><br><a href="http://search.cpan.org/perldoc?Test::WWW::Mechanize::CGIApp">Test::WWW::Mechanize::CGIApp</a></p> markjugg 2008-08-09T13:33:49+00:00 modules Tip: Google Code Search to find prior art for code syntax http://use.perl.org/~markjugg/journal/36787?from=rss Sometimes I wonder if a bit uncommon syntax is valid, and if it is, if anyone actually uses it. For example, I don't see "my" on the right side of an assignment operator very often: <p> <code> my $a = my $b; </code> </p><p> I've started <a href="http://www.google.com/codesearch?q=lang%3Aperl+%22%3D+my%22">using Google Code Search to turn up prior art</a>. </p><p> In this case, I quickly discovered that, Yes, that's valid, and people are actually using it. </p><p> Remember to include <code>lang:perl</code> to restrict a search to Perl.</p> markjugg 2008-06-26T13:32:05+00:00 journal Two alternate patches for rows-as-hashrefs in Text::CSV_XS http://use.perl.org/~markjugg/journal/36046?from=rss <p>H.Merijn Brand, the Text::CSV_XS maintainer has been dicussing possibilities for adding parsing rows as hashrefs to that module through this <a href="http://rt.cpan.org//Ticket/Display.html?id=34474">RT ticket.</a></p><p>As fate would have it, our efforts to implement it crossed paths, and we now both have fairly complete but somewhat different patches for the feature. A couple points to get feedback on:</p><p>Which you do find clearer for setting the column names to use as the hash keys:</p><p><code><br>column_names()<br>or<br>hr_keys()<br></code></p><p>I have already been confused about whether "hr" stood for "header row" or "hashref", so I vote for the former.</p><p>The second point, which is currently in neither patch, is "how you design the interface to automatically setting the column names from the first row of the CSV?"</p><p>Parse::CSV uses new( fields =&gt; 'auto' ), but involving new() won't work for Text::CSV_XS.</p><p>I was thinking of perhaps:</p><p><code><br>$csv-&gt;column_names_from_line($io);<br></code></p><p>Which would simply mean:</p><p><code><br>$csv-&gt;column_names( $csv-&gt;getline($io) );<br></code></p><p>We would leave it up to documentation to make sure users called this first thing.</p><p>Alternately, you could have a function that stores the current file position, rewinds and reads the first row, and then returns to the current position. That seems more fragile to me, and I can oly imagine there are some non-rewindable filehandles out there for which it wouldn't work.</p><p>You can leave feedback here and/or in the RT ticket.</p><p>Thanks!</p><p> &nbsp; &nbsp; &nbsp; Mark</p> markjugg 2008-04-03T17:33:12+00:00 journal grokking Haskell http://use.perl.org/~markjugg/journal/35212?from=rss <p>I spent some time today <a href="http://www.haskell.org/tutorial/">learning some Haskell</a>.</p><p>Here's an example of how I defined a function to perform addition in Haskell, and a second function that builds on the first to increment a number by one:</p><p><code><br> &nbsp; add x y = x + y<br> &nbsp; inc = add 1<br></code></p><p>The Haskell syntax here is especially compact and readable. In Perl, the same exercise would be much longer and noisier, as commonly written:</p><p><code><br> &nbsp; &nbsp; sub add {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my ($x,$y) = @_;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return $x + $y;<br> &nbsp; &nbsp; }</code></p><p><code> &nbsp; &nbsp; sub inc {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; my $y = shift;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return add(1,$y);<br> &nbsp; &nbsp; }<br></code></p><p><em>(Yes, Perl could more even more terse, at the expense of readability)</em></p><p>Haskell provides further invisible benefits. If you give 'inc' too many arguments, or try to increment a character instead of a number, Haskell<br>helpfully dies with an error to tell you that you are attempting something that<br>doesn't make sense.</p><p>Perl will less helpfully ignore too many arguments, or pretend it can usefully<br>increment the character 'b'. In both cases, Perl "successfully" returns answers<br>of little use.</p><p>Keep in mind in that <a href="http://www.pugscode.org/">Pugs</a>, an implementation of Perl 6, was written in Haskell, so I dare say Perl 6 shows some influence from Haskell.</p><p>Perhaps someone fluent in Perl 6 could leave a comment illustrating how Perl 6 could more elegantly these two simple functions. (Without using the built-in increment operator, of course! )</p> markjugg 2007-12-27T13:40:24+00:00 perl6 mod_perlite: worth a look http://use.perl.org/~markjugg/journal/34905?from=rss <a href="http://www.majordojo.com/2007/11/mod-perlite-working.php">mod_perlite</a> hopes to offer some of the performance benefits of mod_perl with the ease-of-use of PHP's model. Check it out. markjugg 2007-11-16T04:36:06+00:00 news Increasing the visibility of journals in search engines http://use.perl.org/~markjugg/journal/34082?from=rss <p>use.perl.org journals currently have very unfortunate &lt;title&gt; tags. Every journal entry I create has an &lt;title&gt; like</p><p>"journal of markjugg (123)".</p><p>It should really be something like:</p><p>"Witty Journal Title | markjugg's use.perl blog"</p><p>The current state of things reduces search engine rankings by not having the key words from the title in the tag, and produces pitiful entries in search engine results when you do find them, as seen <a href="http://www.google.com/search?q=CGI%3A%3AApplication+inurl%3Ajournal+site%3Ause.perl.org">here</a>:</p><p>Even though the results are for specific journal entries, you just see:</p><p>Journal of sam (123)<br>Journal of mark (456)<br>Journal of foo (765)</p><p>Ugh. I've <a href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1772335&amp;group_id=4421&amp;atid=104421">submitted a bug to Slashcode</a>, if anyone is able to fix this.</p> markjugg 2007-08-11T15:14:36+00:00 useperl HTML::FillInForm patched for do-what-i-man syntax. http://use.perl.org/~markjugg/journal/34081?from=rss <p>I've now submitted a patch to T.J. Mather for HTML::FillInForm which overhauls the interface and docs to be simpler.</p><p>It boils down to two things:</p><p>1. You can skip the call to new().</p><p>2. You no longer have to declare what format your HTML or data is in, the module just figures it out. Gone are the days of trying to remember whether you needed "fdat" or "fdata", "fobj" or "fobject", "scalaref" or "scalarref"... you don't need any of them!</p><p> &nbsp; &nbsp; &nbsp; &nbsp; In summary, this:<br><code><br> &nbsp; &nbsp; &nbsp; &nbsp; my $fif = HTML::FillInForm-&gt;new;<br> &nbsp; &nbsp; &nbsp; &nbsp; $fif-&gt;fill( scalarref =&gt; \$html, fdat =&gt; \%data );<br></code><br> &nbsp; &nbsp; &nbsp; &nbsp; Has become:<br><code><br> &nbsp; &nbsp; &nbsp; &nbsp; HTML::FillInForm-&gt;fill( \$html, \%data );<br></code></p><p>All the original syntax remains supported for backwards compatibility.</p><p>I'll try post another update once the final release happens.<br>i</p> markjugg 2007-08-11T15:03:52+00:00 journal Welcome, Data::FormValidator::Constraints::MethodFactory http://use.perl.org/~markjugg/journal/33990?from=rss <p>A new module has been released for Data::FormValidator, <a href="http://search.cpan.org/dist/Data-FormValidator-Constraints-MethodsFactory/">Data::FormValidator::Constraints::MethodsFactory</a></p><p>For a quick overview, when I inherited maintenance of Data::FormValidator, it came with a <a href="http://search.cpan.org/dist/Data-FormValidator/lib/Data/FormValidator/ConstraintsFactory.pm">ConstraintsFactory</a> module. It has always seemed unwieldy, and I have hardly ever used and it mostly ignored it, despite being the current official maintainer of it.</p><p>For example, to express that you would like one constraint <em>or</em> another to be used, you would use:</p><p><code>make_or_constraint( $c1, $c2)</code></p><p>Where $c1 and $c2 are constraints.</p><p>Graham TerMarsch upgraded this whole system in two important ways with his module release. First, all of these factory methods are now "constraint methods", meaning that the constraint now has access to the Data::FormValidator object, allowing much greater flexibility.</p><p>Second, he fixed the unwieldy names that bothered me so much. So the above example would be expressed more directly as:</p><p><code>FV_or( $c1, $c2)</code></p><p><em>If you mean "or", you should just able to say "or"!</em>. It's sort of a wart that it includes the "FV_" prefix, but that's consistent with other parts of DFV, so I think that's for the best.</p><p>Enjoy this new form validation tool!</p><p> &nbsp; &nbsp; &nbsp; &nbsp; Mark</p> markjugg 2007-08-04T14:24:49+00:00 journal auto-restart HTTP::Server::Simple when modules change http://use.perl.org/~markjugg/journal/33860?from=rss This weekend I worked on making a feature I liked in Catalyst available to other Perl projects. That feature is the ability to have a simple Pure-Perl web server for development, and have it automatically restart itself when application files changes. <p> By looking at the guts of Catalyst, I found not one, but two modules that could be easily refactored out of Catalyst for shared use. Those are now <a href="http://mark.stosberg/perl/File-Monitor-Simple.pm">File::Monitor::Simple</a>, to monitor the application directory for changes, and <a href="http://mark.stosberg.com/perl/HTTP-Server-Restarter.pm">HTTP::Server::Restarter</a> to handle controlling that process and actually restarting the web server. </p><p> I also needed to <a href="http://rt.cpan.org/Ticket/Display.html?id=28423">patch HTTP::Server::Simple</a> to have better signaling handling. But the result is that this now works: </p><blockquote><div><p> <tt>&nbsp; &nbsp; HTTP::Server::Restarter-&gt;monitor;<br>&nbsp; &nbsp; HTTP::Server::Simple-&gt;new-&gt;run;</tt></p></div> </blockquote><p> While there are options you can give to monitor(), the defaults should work fine for Catalyst and possibly others as well. </p><p> I'm currently in discussions with <code>catalyst-dev</code> to see about the best way to get this code published and the possibility of Catalyst being refactored to use the extracted modules as well. </p><p> The way that Catalyst currently handles this is a bit novel. Instead of sending and receiving a HUP signal, Catalyst sends a (non-standard) RESTART HTTP request from a user-agent to the server, with some some protection that this command comes from the localhost.</p> markjugg 2007-07-23T02:14:14+00:00 journal offline website development with Catalyst and CGI::App http://use.perl.org/~markjugg/journal/33856?from=rss Catalyst brought into my field of the view an easy way to do Perl website development offline. Catalyst generates<nobr> <wbr></nobr><code>./script/myapp_server.pl</code> as part of the project setup. Run the script, connect to <code>http://localhost:3000</code> in the browser, and there I go. <p> <a href="http://www.cgi-app.org/">CGI::Application</a> now has related tools as well, which builds on the work done by the Catalyst team. See <a href="http://search.cpan.org/perldoc?CGI::Application::Dispatch::Server">CGI::Application::Dispatch::Server</a> and <a href="http://search.cpan.org/perldoc?Test::WWW::Mechanize::CGIApp">Test::WWW::Mechanize::CGIApp</a>, which both provide enough of a real web server to let you work on your CGI::Application project. </p><p> Jesse was just blogging <a href="http://bestpractical.typepad.com/worst_impractical/2007/04/actually_i_am_o.html">offline web applications</a>. For applications where it's feasible to share the web-code with the client, Perl's solution with Catalyst and CGI::Application has largely solved the problem, leaving only the database sync'ing issue to remain. Some kinds of database sync'ing are simply not practical-- Think of incrementing the a sequence value in both locations and trying to reconcile!-- but for other applications like PDAs, and groupware clients, we know from example there are feasible solutions. </p><p> I foresee more web developers using these techniques to deploy desktop applications that are really locally run websites with built-in webservers. It's not too difficult to envision a browser toolkit that provides an interface that looks more like a standalone application than a web browser. </p><p> I'm glad Catalyst has helped these tools evolved, but just as I was playing with these offline web servers, as I was reminded why I prefer CGI::Application: The default Catalyst application benchmarked with a virtual memory footprint of 17.4 megs, while an empty application with CGI::Application::Dispatch::Server application benchmarked at 8.8 megs-- almost half the memory usage! Now, that's not a "real world" comparison, but it does illustrate the different philosophies: CGI::Application is the center of more an &#224; la carte framework, while Catalyst has more functionality built-in.</p> markjugg 2007-07-21T20:13:23+00:00 journal New HTML::ReplaceForm helps with quick web-to-email forms http://use.perl.org/~markjugg/journal/33813?from=rss <p>I uploaded <a href="http://search.cpan.org/perldoc?HTML::ReplaceForm">HTML::ReplaceForm</a> today.</p><p>Here's the use case for it:</p><p>The task is to whip up a web-to-email form with sub-degree of complexity. I'm a fan of making the resulting email look as much like the original form to avoid confusion. But, maintaining two similar versions of the same HTML form for the web and the email variations is a drag.</p><p>Enter HTML::ReplaceForm. It provides one function, <code>replace_form()</code> which replaces all the HTML form elements with corresponding values.</p><p>So, you can serve the HTML directly on the web, and run it through this function to generate the corresponding HTML e-mail, without "forking" the form to maintain another copy of it.</p><p>Time saved.</p><p> &nbsp; &nbsp; &nbsp; Mark</p> markjugg 2007-07-16T02:04:29+00:00 journal SQL::Interp 1.00 released as a SQL::Abstract alternative http://use.perl.org/~markjugg/journal/33734?from=rss <p>Perl hashes are natural representation of name/value pairs, and there should be an easy way to translate them in the name/value pairs SQL expects in INSERT and UPDATE statements, as well as WHERE clauses.</p><p>Also, for best security practices, bind variable should be used. This further complicates the problem space, because names and values need to be split up in the resulting SQL.</p><p> <a href="http://search.cpan.org/perldoc?SQL::Abstract">SQL::Abstract</a> is a popular solution for addressing these problems, and I one I used myself for some time. To its credit, it has a fairly intuitive API, and focuses just on SQL generation, not getting involved the actual query execution.</p><p>However, as SQL::Abstract grew over time, it tried to handle more and more complex cases of SQL, and the design failed to scale up well. Here's an example bit of SQL, straight from the SQL::Abstract docs. </p><p>The goal is to generate SQL that looks like this:</p><blockquote><div><p> <tt>&nbsp; &nbsp; WHERE ( user = ? AND<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;( ( workhrs &gt; ? AND geo = ? )<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OR ( workhrs &lt; ? AND geo = ? ) ) )<br>&nbsp; &nbsp; </tt></p></div> </blockquote><p> The SQL abstract solution looks like this:</p><blockquote><div><p> <tt>&nbsp; my @where = (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-and =&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user =&gt; &amp;#8217;nwiger&amp;#8217;,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -nest =&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -and =&gt; [workhrs =&gt; {&amp;#8217;&gt;&amp;#8217;, 20}, geo =&gt; &amp;#8217;ASIA&amp;#8217; ],<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -and =&gt; [workhrs =&gt; {&amp;#8217;&lt;&amp;#8217;, 50}, geo =&gt; &amp;#8217;EURO&amp;#8217; ]<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],<br>&nbsp; );<br>&nbsp; </tt></p></div> </blockquote><p>Now, to generate that structure, you would have to know exactly the SQL structure you wanted, plus you would have to know the special syntax that goes with "-and", "-nest" and the especially cumbersome syntax that translated " &gt; 20 " into " =&gt; {'&gt;', 20}, ". The resulting Perl is actually more cumbersome and ugly to write than the original SQL!</p><p>With <a href="http://search.cpan.org/perldoc?SQL::Interp">SQL::Interp</a>, there is nothing special to learn to handle this case. You just write out the SQL like you want, and drop in the Perl variables you need as references:</p><blockquote><div><p> <tt>&nbsp; &nbsp; "WHERE ( user = ",\$user,"&nbsp; AND<br>&nbsp; &nbsp; ( ( workhrs &gt; ",\$asia_hrs," AND geo = ",\$asia," )<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OR ( workhrs &lt; ",\$euro_hrs," AND geo = ",\$euro," ) ) )"<br>&nbsp; &nbsp; </tt></p></div> </blockquote><p>The result is easy to develop, easy to read, and neatly takes care of managing bind variables for you.</p><p>And, yes, there are shortcuts for managing the common insert and update cases, similar to those offered by SQL::Abstract: </p><p> <strong>Insert</strong> </p><blockquote><div><p> <tt>&nbsp; &nbsp; SQL::Abstract<br>&nbsp; &nbsp; &nbsp; &nbsp; my ($sql, @bind) = $o-&gt;insert('table',\%data)<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do($sql,{},@bind);<br> <br>&nbsp; &nbsp; SQL::Interpolate<br>&nbsp; &nbsp; &nbsp; &nbsp; my ($sql, @bind) = sql_interp("INSERT INTO table",\%data);<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do($sql,{},@bind);<br> <br>&nbsp; &nbsp; DBIx::Interpolate<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do_i("INSERT INTO table",\%data);<br>&nbsp; &nbsp; &nbsp; &nbsp; </tt></p></div> </blockquote><p> <strong>Update</strong> </p><blockquote><div><p> <tt>&nbsp; &nbsp; SQL::Abstract<br>&nbsp; &nbsp; &nbsp; &nbsp; my ($sql, @bind) = $o-&gt;update('table',\%data,\%where);<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do($sql,{},@bind);<br> <br>&nbsp; &nbsp; SQL::Interpolate<br>&nbsp; &nbsp; &nbsp; &nbsp; my ($sql, @bind) = sql_interp("UPDATE table SET", \%data, "WHERE", \%where );<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do($sql,{},@bind);<br> <br>&nbsp; &nbsp; DBIx::Interpolate<br>&nbsp; &nbsp; &nbsp; &nbsp; $dbh-&gt;do_i("UPDATE table SET", \%data, "WHERE", \%where )</tt></p></div> </blockquote> markjugg 2007-07-07T04:32:57+00:00 modules WWW::Mechanize::Plugin::Display released http://use.perl.org/~markjugg/journal/33251?from=rss WWW::Mechanize is great, but it can be tedious to debug why a Mech script fails, because you can't easily "see" what was on the page at the time of failure. <p> At least, until now. I made a small plugin, which connects Mech with the great HTML::Display package, which is makes it easy to display a Mech HTML page in a local browser. </p><p> I usually use Mech over an 'ssh' connection, so what's "local" to Mechanize is usually not my desktop where there's a graphical browser running. So in the example, I show how to use the great console browser, w3m, for display. It (sort of) renders tables, which is usually enough to at least give me an idea of what went wrong. Here's how I might use it with Test::WWW::Mechanize: </p><blockquote><div><p> <tt>&nbsp; $mech-&gt;get_ok($url) || $mech-&gt;display();</tt></p></div> </blockquote><p> If this test fails, I'll see the result in the browser. I don't always leave the calls to "display()" in the code when I'm done, since this wouldn't make sense in the content of a smokebot. </p><p> See <a href="http://search.cpan.org/perldoc?WWW::Mechanize::Plugin::Display">WWW::Mechanize::Plugin::Display</a> on CPAN.</p> markjugg 2007-05-11T15:11:27+00:00 journal CGI.pm uploading bugs fixed http://use.perl.org/~markjugg/journal/33011?from=rss <p>Some years ago, I noticed an oddity when using CGI.pm file uploads. File uploading only worked on first object I created. If I called CGI-&gt;new() again, the file upload would be gone.</p><p>At the time, I considered file uploading to a difficult and mysterious area, and assumed it "had to be this way", so I didn't file a bug report, and learned to work around the issue.</p><p>"CGI.pm is very popular" I reasoned. "Therefore, obvious bugs in it would be spotted and repaired."</p><p>For years, I avoided the problem by using CGI::Application and related plugins. It loads CGI.pm just once and provides access to it through a "query" method. So, as long as all the plugins use this method and don't access CGI.pm directly, the bug can continue avoided.</p><p>Finally, however, it bit me again recently in a way that was very hard to track down. Suddenly, we were getting weird empty files. This seemed impossible, as the files clearly existed and were being validated by Data::FormValidator::Constraints::Upload.</p><p>The files were "disappearing" because they weren't available on a second call to CGI-&gt;new.</p><p>This time, I had more experience and a different attitude. I decided this might be a solvable bug, and I dove into the CGI.pm guts to investigate.</p><p>This time around, I also had an understanding how to write an automated test for a file upload, which had also been a mystery in the past.</p><p>The result was that I was able to verify the issue was real, *and* solvable, and those fixes are what's new in CGI.pm 3.29:</p><p>http://search.cpan.org/src/LDS/CGI.pm-3.29/Changes</p><p>The moral, though, is to not settle for working around weird, mysterious behavior. At least report it to a user's mailing list for the software, or be adventuresome and dive into the code and poke around.</p><p>The fix for the issue was not particular hard and the symptoms were certainly obvious to those who ran into it. I can only conclude that the bug existed for years unfixed because other people like me had an attitude that the issue was "just mysterious" or couldn't be fixed.</p> markjugg 2007-04-17T16:04:28+00:00 journal suggestions for solving the 'pip' bootstrapping problem? http://use.perl.org/~markjugg/journal/32720?from=rss <a href="http://search.cpan.org/dist/pip">pip</a> represents a really neat idea. Make the requirements of any Perl project easy to install, without needed to understand how CPAN works. <p> I was considering trying to use it make the dependencies of this <a href="http://jalcorn.net/weblog/archives/899-iCal-to-Remind-script.html">Ical2remind</a> script easy to install. You should be able to get a Perl script working without needing to understand Perl or CPAN culture. </p><p> 'pip' could help with that, but it has a bootstrapping problem. How to get pip installed without understanding pip or CPAN culture? </p><p> The solution it seems to me would be something like 'par': Distribute 'pip' as a single Perl script with all the dependencies for it glommed into the same file. ("Glommed" may not be a word. Globbed? Stuffed?). </p><p> Suggestions?</p> markjugg 2007-03-17T19:10:20+00:00 modules Adam Kennedy's method for checking perl module memory usage http://use.perl.org/~markjugg/journal/32552?from=rss I wanted to know: How much memory is my perl module consuming? Adam Kennedy had several times referenced the memory size of Perl modules, so I asked him how he figured it out. Here's the recipe he was kind enough to share, which I've reworked and embellished a bit for clarity:<blockquote><div><p>Use ps. </p><blockquote><div><p> <tt>&gt; perl -de 1<br>&gt; use Dependency::Of::YourMod::One;<br>&gt; use Dependency::Of::YourMod::Two;</tt></p></div> </blockquote><p> Then ps the process:</p><blockquote><div><p> <tt>ps -O rss,vsz | grep 'perl -de'</tt></p></div> </blockquote><p>The second and third numbers you'll see are the resident and virtual memory size. </p><blockquote><div><p> <tt>&gt; use YourMod;</tt></p></div> </blockquote><p>Then ps the process again: </p><blockquote><div><p> <tt>ps -O rss,vsz | grep 'perl -de'</tt></p></div> </blockquote><p>That difference covers the needs of the module itself, and ignores the dependencies. </p><p> Now, that assumes that all your initialization runs at compile-time. If you have a singleton implementation you might need to create one to get the full module use. </p></div> </blockquote> markjugg 2007-03-03T14:58:31+00:00 useperl CGI::App: A Generic Base Controller http://use.perl.org/~markjugg/journal/31748?from=rss <p>This is in response to <a href="http://use.perl.org/~LTjake/journal/31738">LTJake's examples of setting up a generic base controller with Catalyst</a> </p><p> Here's what the same thing would look like using CGI::Application.</p><blockquote><div><p> <tt># Normally one CGI::App dispatch table is used for<br># an entire application, not just one module.<br>use CGI::Application::Dispatch;<br>CGI::Application::Dispatch-&gt;dispatch(<br>prefix&nbsp; =&gt; 'MyApp::Controller::Admin::Account',<br>&nbsp; &nbsp; table =&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; 'admin/account/:id/:rm'&nbsp; =&gt; {},<br>&nbsp; &nbsp; &nbsp; &nbsp; 'admin/account/:rm'&nbsp; &nbsp; &nbsp; =&gt; {},<br>&nbsp; &nbsp; &nbsp; &nbsp; ''&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=&gt; {},<br>&nbsp; &nbsp; ]<br> <br>);<br> <br>package MyApp::Controller::Admin::Account;<br>use base 'CGI::Application';<br>use CGI::Application::Plugin::AutoRunmode;<br> <br>use strict;<br>use warnings;<br> <br># default&nbsp; for<nobr> <wbr></nobr>/admin/account/<br>sub list&nbsp; &nbsp; &nbsp;: StartRunmode { die "index of accounts" }<br> <br># methods on<nobr> <wbr></nobr>/admin/account/$rm<br>sub create&nbsp; &nbsp;: Runmode { die "create an account" }<br> <br># methods on<nobr> <wbr></nobr>/admin/account/$id/[$rm]<br>sub instance : Runmode { # do something with $self-&gt;param('id') }<br>sub view&nbsp; &nbsp; &nbsp;: Runmode { die "view account" }<br>sub update&nbsp; &nbsp;: Runmode { die "update account" }<br>1;</tt></p></div> </blockquote><p>The amount of code needed in both cases is comparable, but there are two important philosophical differences here: </p><ol> <li> <strong>Small components</strong> CGI::App encourages small apps that play well together. Here you see that the dispatcher and 'AutoRunmode' extensions get pulled in. Don't need 'em? They don't get loaded. Catalyst has a more monolithic approach, which I believe consumes more memory in a default setup. </li><li> <strong>Global dispatching</strong> allows you to see and adjust the URI to runmode mappings at a bird's eye level, making adjustments across the application in one place. With Catalyst, dispatching logic is stored with each run mode, tying each run mode to one kind of dispatching, and making it difficult to see the big picture of all the mappings defined. </li></ol> markjugg 2006-11-29T01:52:41+00:00 journal New CGI::App article published on Perl.com http://use.perl.org/~markjugg/journal/31362?from=rss A new article I wrote about CGI::Application has now been <a href="http://www.perl.com/pub/a/2006/10/19/cgi_application.html">published on Perl.com</a>. <p> It provides a number of examples how tasks can be simplified with CGI::Application and the plugin system. </p><p> CGI::Application holds the distinction of being over five years old now! </p> markjugg 2006-10-20T01:55:35+00:00 journal Reduction operators http://use.perl.org/~markjugg/journal/31001?from=rss <p>Today I was in a different sort of mood. I decided to play with some Haskell, and ended up with the following. I started with a recursive function in Haskell which computes products:</p><blockquote><div><p> <tt>product [] = 1<br>product (x:xs) = x * product xs</tt></p></div> </blockquote><p>I then decided to write the same functionality in Perl 5 and Perl 6 to see how they compared. Along the way I ran into <a href="http://feather.perl6.nl/syn/S03.html#Reduction_operators">reduction operators</a>, which turn out to appear in some form in all three languages, although I have never used them in any. Here's the function looks lik all three languages. I provide the print statement in only one case, since it is basically the same in all three:</p><blockquote><div><p> <tt>-- Haskell<br>prod = foldr (*) 1<br> <br># Perl 5<br>use List::Util qw(reduce);<br>sub prod { reduce { $a * $b } 1, @_ }<br> <br># Perl 6<br>sub prod (*@xs) { [*] @xs }<br>print prod(2,3,4);</tt></p></div> </blockquote><p> Not only does the Haskell solution look the cleanest to me, it was the only language I didn't find a related bug in. I added tests for [*]() and [+](), which are not yet returning 1 and 0 as expected in Pugs. </p><p>It turns out perl5 List::Util::sum() was returning &quot;undef&quot; for a empty lists instead of 0. I submitted <a href="http://rt.cpan.org//Ticket/Display.html?id=21505">a patch</a> for that. </p> markjugg 2006-09-15T02:59:21+00:00 journal CGI::App to Perl6: Another improvement for references http://use.perl.org/~markjugg/journal/30828?from=rss Earlier I wrote about how <a href="http://use.perl.org/~markjugg/journal/30762">references are gone in Perl6</a>. However, subroutine signature Perl6 expose just opposite-- that really everything is a reference. <p> We use modify-by-reference in CGI::Application to prevent copying large HTML documents into the "postrun" routine. </p><p> This is a technique that should be used sparingly, as returning explicit values creates for clearer code flow. </p><p> Perl6 helps promotes good programming practices in two ways in this regard. 1. You have explicitly turn on modify-by-reference for a subroutine argument, and 2. This explicitness makes it clear that this trick is being employeed. Let's a take a look at the syntax:</p><blockquote><div><p> <tt>&nbsp; Was: sub foo {...};&nbsp; &nbsp; &nbsp; &nbsp; foo(\$bar)<br>&nbsp; Now: sub foo ($bar is rw); foo($bar)</tt></p></div> </blockquote><p>Perl6 is<nobr> <wbr></nobr>/always/ passing references to subroutines in the background, they are just read-only by default. While in Perl5 you might have a dig around to see if modification by reference was happening in a subroutine, in Perl6 you can look no further than the signature. </p><p> If you want a copy of the value passed, Perl6 covers that too:</p><blockquote><div><p> <tt>&nbsp; sub foo ($bar is copy);</tt></p></div> </blockquote><p>Aspects of this may seem formal compared to the looseness of Perl5. So far I've generally liked these changes, as compactness and clarity often come with them.</p> markjugg 2006-08-31T23:25:41+00:00 perl6 CGI::App to Perl6: param() is now 90% shorter http://use.perl.org/~markjugg/journal/30799?from=rss Lot's of OO modules have a param() method: CGI::App, HTML::Template, CGI::Session... and they are mostly all about the same. That is, they are a glorifed hash wrapper. <p> Yet, in Perl5 it's easy for the code for them to be verbose, especiall if you want to accept both a hash<nobr> <wbr></nobr>/and/ a hashref, and provide some error checking on the input. </p><p> The param() method of CGI::App in Perl5 was 33 lines (including some whitespace). The Perl6 translation was <em>3</em> lines! This is possible with subroutine signatures and multi-method dispatch. Further, Perl6 tries somewhat successfully to hid e the difference between a hash and hashref, which eliminates another case to check for. </p><p> For constrast, here's the two pieces of code: </p><p> <strong>In Perl5</strong> </p><blockquote><div><p> <tt>sub param {<br>&nbsp; &nbsp; my $self = shift;<br>&nbsp; &nbsp; my (@data) = (@_);<br> <br>&nbsp; &nbsp; # First use?&nbsp; Create new __PARAMS!<br>&nbsp; &nbsp; $self-&gt;{__PARAMS} = {} unless (exists($self-&gt;{__PARAMS}));<br> <br>&nbsp; &nbsp; my $rp = $self-&gt;{__PARAMS};<br> <br>&nbsp; &nbsp; # If data is provided, set it!<br>&nbsp; &nbsp; if (scalar(@data)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; # Is it a hash, or hash-ref?<br>&nbsp; &nbsp; &nbsp; &nbsp; if (ref($data[0]) eq 'HASH') {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Make a copy, which augments the existing contents (if any)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %$rp = (%$rp, %{$data[0]});<br>&nbsp; &nbsp; &nbsp; &nbsp; } elsif ((scalar(@data) % 2) == 0) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # It appears to be a possible hash (even # of elements)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %$rp = (%$rp, @data);<br>&nbsp; &nbsp; &nbsp; &nbsp; } elsif (scalar(@data) &gt; 1) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; croak("Odd number of elements passed to param().&nbsp; Not a valid hash");<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; } else {<br>&nbsp; &nbsp; &nbsp; &nbsp; # Return the list of param keys if no param is specified.<br>&nbsp; &nbsp; &nbsp; &nbsp; return (keys(%$rp));<br>&nbsp; &nbsp; }<br> <br>&nbsp; &nbsp; # If exactly one parameter was sent to param(), return the value<br>&nbsp; &nbsp; if (scalar(@data) &lt;= 2) {<br>&nbsp; &nbsp; &nbsp; &nbsp; my $param = $data[0];<br>&nbsp; &nbsp; &nbsp; &nbsp; return $rp-&gt;{$param};<br>&nbsp; &nbsp; }</tt></p></div> </blockquote><p> <strong>In Perl6</strong> </p><blockquote><div><p> <tt>multi method param ()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;returns Array { %!params.keys }<br>multi method param (Str $key) returns Array { @( %!params{$key} ) }<br>multi method param (%h,*%h)&nbsp; &nbsp;{ %!params = %(%!params, %h); undef }</tt></p></div> </blockquote><p>I think the difference stands for itself...</p> markjugg 2006-08-30T02:03:11+00:00 perl6 CGI::App to Perl6: Reference handling not needed here http://use.perl.org/~markjugg/journal/30762?from=rss I'm still wrapping my head around what means that <a href="http://svn.openfoundry.org/pugs/docs/Perl6/FAQ/Capture.pod">references have been replaced with Capture objects</a> in Perl6. <p> However, I was pleased to see it means this common idiom is no longer necessary. Often I have a variable that may contain a single scalar value or an arrayref of values. </p><p> <b>Perl5:</b> </p><blockquote><div><p> <tt>my @new = (ref $old eq 'ARRAY' ) ? @$old : ($old);</tt></p></div> </blockquote><p> <b>But Perl6 Does The Right Thing, Easily</b> </p><blockquote><div><p> <tt>my @new = @$old;</tt></p></div> </blockquote><p> Perl5 would complain if you tried to deference $old as an array when it wasn't an arrayref. </p><p> Now I have look through the CGI::Application code and see all the places I can shave off a few bytes with this refactor... </p><p> Here's another case in Perl6 where reference handling is not needed, while Perl5 requires it:</p><blockquote><div><p> <tt># Perl6 will properly assign @a to the 'k' key,<br># without using reference notation.<br>my @a = ( 1,2 );<br>my %h = (<br>&nbsp; &nbsp; k =&gt; @a,<br>&nbsp; &nbsp; j =&gt; 'm',<br>);</tt></p></div> </blockquote> markjugg 2006-08-26T19:59:15+00:00 perl6 CGI::App to Perl6: A detour, improving CGI.pm for p6 http://use.perl.org/~markjugg/journal/30760?from=rss As I looked in my failing tests for CGI::Application for Perl6, I realized that CGI.pm for Perl6 wasn't as developed as I thought. <p> It wasn't an OO interface, apparently because it was developed a while ago before that part of pugs was finished. Further, it didn't yet support creating a new object by passing some params to new. </p><p> A little bit of hacking later, I fixed and commited both those parts of CGI.pm for Perl6. You can now do this in Perl6:</p><blockquote><div><p> <tt>&nbsp; use Test;<br>&nbsp; plan 1;<br> <br>&nbsp; use CGI;<br>&nbsp; my $q = CGI.new( rm =&gt; 'cgiapp_rocks' );<br>&nbsp; is($q.param('rm'), 'cgiapp_rocks');</tt></p></div> </blockquote><p>In fact, that looks a lot like one of tests I wrote.<nobr> <wbr></nobr>;-). </p><p> From there I moved on to <a href="http://groups.google.com/group/perl.perl6.language/browse_thread/thread/a83ffe3615fa8477/55ca68b16b5daac9?auth=DQAAAHYAAADExlSTKqhiPNpyGn0sXIeMMSE2_F15in6NtYvatZdomBzss8nc_jlEe5zQSINr-O151_anQ490BuUZEFo9F0PMeSINwWcXlQYoBqK58zd_s1Lifr5NpU1yksLEFjmbBKad6ZFq41Qnp9aZTAINc9hmdsYVReoQHXUYyEMiPpRWzQ">providing feedback about the documentation spec for Perl6</a>. Damian Conway responded there, and I look forward to reading the updated spec for that should be available soon. </p><p> Until then, back to hacking CGI::Application and Perl6...</p> markjugg 2006-08-26T12:28:58+00:00 perl6