<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Open Swartz &#187; Perl</title>
	<atom:link href="http://www.openswartz.com/category/perl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.openswartz.com</link>
	<description>Perl and open source development</description>
	<lastBuildDate>Mon, 12 Oct 2009 22:01:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Announcing Server::Control and apachectlp</title>
		<link>http://www.openswartz.com/2009/10/12/announcing-servercontrol-and-apachectlp/</link>
		<comments>http://www.openswartz.com/2009/10/12/announcing-servercontrol-and-apachectlp/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 22:01:44 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=110</guid>
		<description><![CDATA[Server::Control allows you to control servers ala apachectl, but with better diagnostics and many more features. It includes both a drop-in replacement for apachectl (&#8221;apachectlp&#8221;) and an OO interface.
Though it was designed with Apache in mind, there are also subclasses for HTTP::Server::Simple and Net::Server, and it&#8217;s general enough to use with any server that has [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://cpan.uwinnipeg.ca/module/Server::Control">Server::Control</a> allows you to control servers ala apachectl, but with better diagnostics and many more features. It includes both a drop-in replacement for apachectl (&#8221;apachectlp&#8221;) and an OO interface.</p>
<p>Though it was designed with Apache in mind, there are also subclasses for <a href="http://cpan.uwinnipeg.ca/module/HTTP::Server::Simple">HTTP::Server::Simple</a> and <a href="http://cpan.uwinnipeg.ca/module/Net::Server">Net::Server</a>, and it&#8217;s general enough to use with any server that has a pid file and listens on a port.</p>
<p>Features include:</p>
<ul>
<li>Checks server status via both pid file and port connect
<li>Detects and handles corrupt or out-of-date pid files
<li>Reports what is using a port when it is busy (via lsof)
<li>Tails the error log when server fails to start
<li>Supports sudo usage for restricted (< 1024) port
<li>Easy to customize for your environment with start/stop hooks, etc.
</ul>
<p>Coming soon: plugins for common tasks associated with starting and stopping servers, such as generating conf files from templates and auto-restarting a server on file change.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/10/12/announcing-servercontrol-and-apachectlp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How not to restart mod_perl servers</title>
		<link>http://www.openswartz.com/2009/09/22/how-not-to-restart-mod_perl-servers/</link>
		<comments>http://www.openswartz.com/2009/09/22/how-not-to-restart-mod_perl-servers/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 01:37:58 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=98</guid>
		<description><![CDATA[One of the traditional problems with mod_perl development is getting the server to recognize module changes, without restarting after every change. I&#8217;m thinking about an improved solution for this.
These are the solutions I know about:
1. Apache2::Reload / Module::Reload

These check whether modules have changed on each request, and if so, clear their symbols and reload them [...]]]></description>
			<content:encoded><![CDATA[<p>One of the traditional problems with mod_perl development is getting the server to recognize module changes, without restarting after every change. I&#8217;m thinking about an improved solution for this.</p>
<p>These are the solutions I know about:</p>
<h4>1. <a href="http://cpan.uwinnipeg.ca/htdocs/Apache-Reload/Apache2/Reload.html">Apache2::Reload</a> / <a href="http://cpan.uwinnipeg.ca/htdocs/Module-Reload/Module/Reload.html">Module::Reload</a></h4>
<p></p>
<p>These check whether modules have changed on each request, and if so, clear their symbols and reload them inside the process.</p>
<p>Problem: some modules fail to reload properly. Sometimes the failure is intermittent, depending on the order of module loading and other esoteric details. Moose and ORM modules seem particularly prone to reload failures. For me, this level of unpredictability makes *::Reload too frustrating to use.</p>
<h4>2. Catalyst Auto-restart</h4>
<p></p>
<p>Catalyst has an engine (<a href="http://cpan.uwinnipeg.ca/htdocs/Catalyst-Engine-HTTP-Prefork/Catalyst/Engine/HTTP/Prefork/Restarter.pm.html">Catalyst::Engine::HTTP::Prefork::Restarter</a>) which forks off a &#8220;watcher&#8221; process that waits for your modules to change. When they change, it restarts the server. The usual effect is that, between the time you hit &#8220;save&#8221; in your editor and reload your page, the server has restarted or at least begun restarting.</p>
<p>Problems: Doesn&#8217;t work well if you make a few changes in a row; the restart only captures your first change. (EDIT: Dave Rolsky points out that this is fixed now under some OS&#8217;s.) Bad user experience if there&#8217;s an error in your module; you have to realize the server has died, find the error message in some shell or log, and manually start up the server again. Finally, you are still ultimately waiting for a full restart.</p>
<h4>3. MaxRequestsPerChild=1</h4>
<p></p>
<p>Perrin Harkins recently alerted me to the MaxRequestsPerChild=1 technique. That is, set MaxRequestsPerChild to 1, then load any potentially-changing modules in the <i>child</i>, not the parent (obviously only for development environments). Each request will hit a fresh child server, which will load all of your potentially-changing modules anew.</p>
<p>This is the nicest solution I&#8217;ve seen so far. The only problem I can see is its performance &#8211; each potentially-changing module has to be loaded on each request. **</p>
<h4>4. My idea: The Pied Piper</h4>
<p></p>
<p>As in 3, load any potentially-changing modules in the child. Leave MaxRequestsPerChild alone. As in 2, fork off a &#8220;watcher&#8221; process that waits for your modules to change. When they change, kill all the server&#8217;s children explicitly.</p>
<p>The end result is that you get reasonable performance when your modules don&#8217;t change (e.g. when you are only futzing with templates), but when modules do change, you should see the effects immediately.</p>
<p>This should be able to work with mod_perl, fastcgi, Net::Server, etc., as long as the parent server responds appropriately to the killing of all its children (by launching new ones). Apache, at least, seems to be ok with this.</p>
<p>Going to try to implement this as a plugin in <a href="http://cpan.uwinnipeg.ca/dist/Server-Control">Server::Control</a>. Will see how it goes.</p>
<hr />
<p>** &#8211; You can try to load things only on demand, but often mod_perl code is written without &#8216;use&#8217; statements as it assumes everything is loaded in the parent. You can also try to minimize the number of potentially-changing modules, but then you run the risk of leaving something off and having to adjust it and restart.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/09/22/how-not-to-restart-mod_perl-servers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>What Mason 2.0 would look like</title>
		<link>http://www.openswartz.com/2009/09/01/what-mason-2-0-would-look-like/</link>
		<comments>http://www.openswartz.com/2009/09/01/what-mason-2-0-would-look-like/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 22:40:05 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=80</guid>
		<description><![CDATA[I&#8217;ve been thinking about what version 2.0 of Mason might look like. It&#8217;s been seven years since the last major version (1.10), and a lot has changed in the Perl world since then!
This is an initial brainstorm. Refinement and details to follow, and feedback is very much encouraged.
Name

HTML::Mason -&#62; Mason. I believe we are finally [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been thinking about what version 2.0 of Mason might look like. It&#8217;s been seven years since the last major version (1.10), and a lot has changed in the Perl world since then!</p>
<p>This is an initial brainstorm. Refinement and details to follow, and feedback is very much encouraged.</p>
<h3>Name</h3>
<ul>
<li><b>HTML::Mason -&gt; Mason</b>. I believe we are finally entitled to a top-level name. <img src='http://www.openswartz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  This will help separate the new Mason from the old.</li>
<p></p>
<li><b>MasonX:: for extensions</b>? This is more problematic, as the <a href="http://cpan.uwinnipeg.ca/search?query=MasonX::&#038;mode=dist">MasonX::</a> namespace already has a number of modules that are specific to the current Mason. Regardless, it needs to be a short and convenient prefix.</li>
<p>
</ul>
<h3>Implementation</h3>
<ul>
<li><b>Moose</b>. We will use Moose for all classes. Moose represents a fundamentally different way of developing Perl, and it was the catalyst that started me thinking about a new Mason. Many of the remaining items in this list fall out of, or are enhanced by, Moosification.</li>
<p></p>
<li><b>Components will be classes</b>. Components started out as subroutines, then became objects. The logical next step is for each component to be its own Moose subclass. This will allow components to benefit from true OO techniques (methods, attributes, roles), instead of Mason&#8217;s current painful pseudo-OO.</li>
<p></p>
<ul>
<li>The entire component will be placed inside a <a href="http://cpan.uwinnipeg.ca/module/MooseX::Declare">MooseX::Declare</a> <tt>class</tt> block, with a class name auto-generated from the component path.</li>
<li>The main component body &#8211; the content and the inline Perl sections &#8211; will be placed into a <tt>main</tt> method.</li>
<li>Calling a component (via <tt>&lt;&#038; &&gt;</tt> or <tt>$m-&gt;comp</tt>) will mean creating a new instance of the component class, and calling its <tt>main</tt> method. Component call parameters will be passed to the constructor. Have to watch for performance impacts here.</li>
<li>A <tt>$self</tt> variable is automatically available, assigned to the component instance.</li>
<li>One of <tt><%args></tt> or <tt><%attr></tt> will be used to generate Moose attributes, rather than subroutine parameters. There will still be some syntactic sugar, but the section will have access to the full power of attributes. e.g.
<pre>
   &lt;%args&gt;
   foo
   bar => (default => 5)
   baz => (default => 5, isa => 'Int')
   &lt;/%args&gt;
</pre>
<p>The advantage of attributes over parameters is that other methods in the component will have access to those values, something that is painful to deal with right now.
</li>
</ul>
<li><b>Subcomponents will become methods</b>. <tt><%def></tt> and <tt><%method></tt> are currently implemented as their own component objects inside the main component. There was never a particularly good reason to do this other than that it seemed like a neat idea, and over the years it has proved more frustrating than helpful &#8211; e.g. <tt>$m->current_comp</tt> and <tt>$m->caller</tt> sometimes defy expectation. Now that components will be classes, it makes sense for a subcomponent to be just another method alongside <tt>main</tt>.</li>
<p></p>
<li><b>Autohandlers will be superclasses</b>. Components will truly inherit from their autohandlers now. e.g. they&#8217;ll be able to call methods in the autohandler, a great way to share code within a hierarchy of components.</li>
<p></p>
<li><b>Smaller core, more extensions</b>. As with other modern Perl frameworks, we should move as much as we can from the core to extensions, where we can do so without overly sacrificing ease of use, performance, etc.
</ul>
<h3>Syntax</h3>
<ul>
<li><b>Same core syntax</b>. The core syntax will be mostly the same &#8211; <tt><% %></tt> blocks, <tt><%perl></tt> and <tt><%init></tt> sections, %-lines. I do sometimes regret not going with the industry-standard <tt><%= %></tt> for expressions, so that <tt><% %></tt> could be used for non-expression Perl; but at this point <tt><% $foo %></tt> may be too deeply embedded in my brain to change it.</li>
<p></p>
<li><b><tt><%once></tt> becomes <tt><%class></tt></b>. The <tt><%class></tt> section will contain code to be placed in the class definition outside the <tt>main</tt> method: &#8216;use&#8217; statements, pure-Perl methods, utility subroutines, pragmas etc.</li>
<p></p>
<li><b>Automatic newline removal</b>. Obvious newlines should be removed by default, so that components can be spaced neatly without adding gratuitous newlines to the output.</li>
<p></p>
<li><b>Consolidated filter syntax</b>. Mason has several kinds of content filters: <tt><%filter></tt> section, components with content, and escapes (e.g. <tt>|h</tt>). All of these filtering methods should be consolidated under a single implementation, if not a single syntax. In addition, we need a way to create new content filters with Perl methods and use them on blocks. Standard filters could be installed on the main component class, and more specific filters on individual components. Example:</li>
<p></p>
<pre>
   &lt;%class&gt;
   filter repeat ($times) {
       my ($self, $content) = @_;
       return $content x $times;
   }
   &lt;/%class&gt;

   ...

   &lt;% repeat (3) { %&gt;
   blah blah
   &lt;% } %&gt;
</pre>
</ul>
<h3>New features</h3>
<ul>
<li><b>More powerful controller mechanisms</b>. Mason has controller mechanisms &#8211; dhandler, autohandler, and the resolver &#8211; that were innovative once but are now underpowered. I don&#8217;t believe (as some do) that Mason should get out of the controller business &#8211; I actually <i>like</i> having my &#8220;C&#8221; and &#8220;V&#8221; in the same place. Mason just needs to provide easy access to the same powerful routing techniques that are used in modern web frameworks, e.g. via <a href="http://cpan.uwinnipeg.ca/module/Path::Dispatcher">Path::Dispatcher</a> or <a href="http://cpan.uwinnipeg.ca/module/Path::Router">Path::Router</a>. For example, an autohandler or dhandler or other special file could indicate how paths under that directory should be routed &#8211; still have to work out the syntactic details. Of course, nothing will prevent people from using an MVC framework&#8217;s routing and treating Mason like a controller-less template language.</li>
<p></p>
<li><b>Logging</b>. Mason will log generously with different levels and categories via <a href="http://cpan.uwinnipeg.ca/module/Log::Any">Log::Any</a>. This was supposed to be put into Mason 1.x years ago but never made it&#8230;</li>
<p></p>
<li><b>Output placeholders</b>. Support the insertion of placeholders whose values can be supplied by code further along in the request. This is motivated by HTML head elements, like title, that you want to output in the top template but determine in a more specific page component.
</ul>
<h3>New extensions</h3>
<ul>
<li><b>MasonX::Tidy and MasonX::Critic</b>. Tidying and criticizing specific to Mason components, analagous to what perltidy and perlcritic do for Perl.</li>
<p></p>
<li><b>MasonX::Safe</b>. Use static code analysis (PPI) to restrict the set of Perl operations that could be executed in a set of Mason components. In the spirit of, but less draconian and broken than, <a href="http://cpan.uwinnipeg.ca/htdocs/Safe/Safe.html">Safe</a>. Useful for environments when non-Perl-programmers are modifying components, or to give the &#8220;don&#8217;t do too much in components&#8221; philosophy some teeth. Intended for friendly policy enforcement, not airtight security.</li>
<p>
</ul>
<h3>What can be deprecated/eliminated</h3>
<ul>
<li><b>Web features</b>. Mason has always ambiguously straddled the line between template language and web framework. This was out of necessity &#8212; when Mason was created, mod_perl was the only &#8220;web framework&#8221; in Perl. With the advent of web frameworks like Catalyst, Jifty and CGI::Application, and interfaces like <a href="http://plackperl.org/">PSGI/Plack</a>, Mason no longer needs to occupy the web space. It should strive to simply be a great templating system that is easy to plug into various web frameworks. This means we can eliminate, among other things, the ApacheHandler and CGIHandler classes from the core.</li>
<p></p>
<li><b>Plugin API</b>. In 1.3 we added a custom Mason plugin API, but Moose method modifiers and roles are a far better and more industry-standard way of supporting plugins.</li>
<p></p>
<li><b><tt>&lt;%cleanup&gt;</tt> section</b>. <tt>&lt;%cleanup&gt;</tt> has always been of dubious value because it is not guaranteed to run in case of an abnormal exit from the component. Now that components are classes, a DESTROY method in the <tt>&lt;%class&gt;</tt> section will be a more appropriate and functional way to perform cleanup.</li>
<p></p>
<li><b><tt>&lt;%shared&gt;</tt> section</b>. Since the various methods in a component are now part of the same class and share attributes, there is no reason to have <tt>&lt;%shared&gt;</tt>.</li>
<p></p>
<li><b><tt>&lt;%attr&gt;</tt> or <tt>&lt;%args&gt;</tt> section</b>. We only need to retain one of these to represent class attributes; the other can be eliminated.</li>
<p></p>
<li><b><tt>&lt;%method&gt;</tt> or <tt>&lt;%def&gt;</tt> section</b>. Perl methods will now be easy to define in the <tt>&lt;%class&gt;</tt> section. It will still be useful to define methods that produce output, but we only need one of these sections.</li>
<p></p>
<li><b>Non-CHI cache APIs</b>. Eliminate the Cache::Cache and 1.0 APIs, and just support <a href="http://cpan.uwinnipeg.ca/dist/CHI">CHI</a>.</li>
<p>
</ul>
<h3>What will be kept, begrudgingly</h3>
<ul>
<li><b>Components returning values</b>. There are some cleanliness arguments for eliminating the ability of components to return values &#8211; one should use methods instead, etc. But I think this feature is too frequently used to discard. This is something to discourage in the docs and for MasonX::Critic to complain about. <img src='http://www.openswartz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<p>
</ul>
<h3>What do you think?</h3>
<p>Mason developers, let me hear your feedback and ideas.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/09/01/what-mason-2-0-would-look-like/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Log::Any released, only two years late</title>
		<link>http://www.openswartz.com/2009/07/13/log-any-released/</link>
		<comments>http://www.openswartz.com/2009/07/13/log-any-released/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 06:02:15 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=70</guid>
		<description><![CDATA[Log::Any has finally been released to CPAN. It allows CPAN modules to log messages in a generic way, while letting the application choose (or decline to choose) a logging mechanism such as Log::Dispatch or Log::Log4perl.
This is something I&#8217;ve been meaning to implement for nearly two years &#8211; talk about procrastination! What pushed me over the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://cpan.uwinnipeg.ca/module/Log::Any">Log::Any</a> has finally been released to CPAN. It allows CPAN modules to log messages in a generic way, while letting the application choose (or decline to choose) a logging mechanism such as Log::Dispatch or Log::Log4perl.</p>
<p>This is something I&#8217;ve been meaning to implement for nearly <a href="http://www.openswartz.com/2007/09/06/standard-logging-api/">two years</a> &#8211; talk about procrastination! What pushed me over the edge was that three of my distributions &#8211; <a href="http://www.masonhq.com/">Mason</a>, <a href="http://cpan.uwinnipeg.ca/module/CHI">CHI</a>, and an upcoming Server::Control &#8211; all needed to log various things, and had no good generic way to do it.</p>
<p>As part of this effort, I surveyed the various general-purpose logging packages on CPAN to see which ones Log::Any should interface with. Log::Dispatch and Log::Log4perl were the heavyweights and obvious first choices, but I was unprepared for the sheer variety of other distributions. Logging, like <a href="http://www.perl.com/lpt/a/580">templating systems</a>, seems to be one of those things that everyone wants to try their hand at. Here&#8217;s a partial list of logging packages that all share roughly the same mission &#8211; dispatching logs to various outputs &#8211; along with the number of distributions that depend on each:</p>
<table border="0">
<tbody>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Log4perl">Log::Log4perl</a></td>
<td align="right">176</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Dispatch">Log::Dispatch</a></td>
<td align="right">40</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Agent">Log::Agent</a></td>
<td align="right">18</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Report">Log::Report</a></td>
<td align="right">16</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Trace">Log::Trace</a></td>
<td align="right">13</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Message">Log::Dispatch::Config</a></td>
<td align="right">9</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Message">Log::Message</a></td>
<td align="right">5</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Channel">Log::Channel</a></td>
<td align="right">3</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Dump">Log::Dump</a></td>
<td align="right">3</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Handler">Log::Handler</a></td>
<td align="right">2</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Info">Log::Info</a></td>
<td align="right">2</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::LogLite">Log::LogLite</a></td>
<td align="right">1</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::FileSimple">Log::FileSimple</a></td>
<td align="right">1</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Message::Simple">Log::Message::Simple</a></td>
<td align="right">1</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::StdLog">Log::StdLog</a></td>
<td align="right">1</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Simple">Log::Simple</a></td>
<td align="right">-</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Simplest">Log::Simplest</a></td>
<td align="right">-</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Trivial">Log::Tiny</a></td>
<td align="right">-</td>
</tr>
<tr>
<td><a href="http://cpan.uwinnipeg.ca/module/Log::Trivial">Log::Trivial</a></td>
<td align="right">-</td>
</tr>
</tbody>
</table>
<p></p>
<p>I particularly like that there are seven packages named with a variation of &#8220;Simple&#8221;, &#8220;Trivial&#8221;, etc. Trying to choose between these would be the opposite of simple.</p>
<p>To be fair, Log::Dispatch, presumably the easier of the two main logging packages to configure, requires this just to log normally to a file:</p>
<pre>
   my $dispatcher = Log::Dispatch->new();
   $dispatcher->add(
       Log::Dispatch::File->new(
           name      => 'foo',
           min_level => 'info',
           filename  => "$dir/test.log",
           mode      => 'append',
           callbacks => sub { my %params = @_; "$params{message}\n" },
       )
   );
   $dispatcher->info('this is a message');
</pre>
<p>It&#8217;s no wonder people tried this and yearned for a simpler alternative. (I&#8217;ve gotten permission from Dave to simplify a few of these things with a maintenance release.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/07/13/log-any-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Things I learned at YAPC&#124;10</title>
		<link>http://www.openswartz.com/2009/06/26/things-i-learned-at-yapc10/</link>
		<comments>http://www.openswartz.com/2009/06/26/things-i-learned-at-yapc10/#comments</comments>
		<pubDate>Fri, 26 Jun 2009 13:52:38 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=63</guid>
		<description><![CDATA[I finally got to my first YAPC this year &#8211; coincidences and conflicts kept me away in previous years. So excuse me for getting all dewy eyed, but it was a great experience! Haven&#8217;t felt that close to a development community since the early Oreilly Perl conferences. I feel all energized about Perl again and [...]]]></description>
			<content:encoded><![CDATA[<p>I finally got to my first <a href="http://yapc10.org/">YAPC</a> this year &#8211; coincidences and conflicts kept me away in previous years. So excuse me for getting all dewy eyed, but it was a great experience! Haven&#8217;t felt that close to a development community since the early Oreilly Perl conferences. I feel all energized about Perl again and it makes me want to host a winter workshop in the bay area someday.</p>
<p>Here are some cool things I learned about:</p>
<ul>
<li><strong><a href="http://search.cpan.org/~andk/CPAN-1.94/lib/CPAN.pm#Configuration_for_individual_distributions_(Distroprefs)">distroprefs</a></strong> &#8211; A way to improve the automatability of CPAN installs; namely, dealing with those pesky distributions that insist on asking you questions. We spent a bunch of time at Hearst writing expect scripts to deal with these so that we could automatically install our large CPAN base on different servers. Wish I&#8217;d known about distroprefs!</li>
<li><strong><a href="http://cpan.uwinnipeg.ca/module/Dist::Zilla">Dist::Zilla</a></strong> &#8211; I&#8217;ve always been vaguely bothered by the amount of boilerplate in my CPAN distributions (copyright, author, version, etc.) but Dist::Zilla has finally provided the means and motivation to do something about it.</li>
<li><strong><a href="http://cpan.uwinnipeg.ca/module/KiokuDB">KiokuDB</a></strong> &#8211; Stevan Little&#8217;s talk on KiokuDB got me excited about leaving behind RDBMSs and the Impedence Mismatch on my next web project. Just store Moose objects! Of course people have been getting excited about object databases since the 80s, and there&#8217;s probably a reason that Oracle is still around. But allow me to enjoy my dream before it smashes into reality.</li>
<li><strong>Memory persistence</strong> &#8211; As Steven Lembark gleefully hammered home, Perl never shrinks a variable. Once $foo has had a million bytes or @foo has a million entries, it&#8217;ll reserve that space forever, even if you empty it. Makes me want to look real close at any globals in persistent web environments.</li>
<li><strong><a href="http://cpan.uwinnipeg.ca/module/CGI::Inspect">CGI::Inspect</a></strong> &#8211; Brock Wilcox wins the award for most satisfying feature demo. Insert CGI::Inspect&#8217;s inspect() somewhere in a web template. When it runs, a dashboard launches in a new browser window, with a stack trace and the ability to inspect and <em>change</em> lexical state before the page resumes its render. Of course, other environments like JSP/Eclipse have had live debugging of web pages for years, but in Perl this still seems groundbreaking <img src='http://www.openswartz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , and the possibilities for extending it are intriguing.</li>
</ul>
<p>Here are the pages for the talks referenced above:</p>
<li><a href="http://yapc10.org/yn2009/talk/1985">CPAN &#8211; A big enough lever to install the world</a></li>
<li><a href="http://yapc10.org/yn2009/talk/1986">Dist::Zilla &#8211; Automating quality since 2008</a></li>
<li><a href="http://yapc10.org/yn2009/talk/1914">KiokuDB &#8211; A Real World Introduction</a></li>
<li><a href="http://yapc10.org/yn2009/talk/1841">Memory Manglement</a></li>
<li><a href="http://yapc10.org/yn2009/talk/2012">Drop-In Web-Based REPL for CGI Applications</a></li>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/06/26/things-i-learned-at-yapc10/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How roles pushed me over to the Moose side</title>
		<link>http://www.openswartz.com/2009/06/01/how-roles-pushed-me-over-to-the-moose-side/</link>
		<comments>http://www.openswartz.com/2009/06/01/how-roles-pushed-me-over-to-the-moose-side/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 18:13:24 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=47</guid>
		<description><![CDATA[Last month I described custom code for wrapping certain methods of CHI driver subclasses, regardless of how far down the class hierarchy they were. I said I felt like I must be reinventing the wheel, and sure enough, Tim Bunce gently pointed me at Moose&#8217;s application of roles to instances.
When I first heard about this [...]]]></description>
			<content:encoded><![CDATA[<p><a href="/2009/04/26/auto-wrapping-subclass-methods/">Last month</a> I described custom code for wrapping certain methods of CHI driver subclasses, regardless of how far down the class hierarchy they were. I said I felt like I must be reinventing the wheel, and sure enough, Tim Bunce gently <a href="http://groups.google.com/group/perl-cache-discuss/msg/612b55fa4b8a547e">pointed me</a> at Moose&#8217;s <a href="http://search.cpan.org/~drolsky/Moose-0.79/lib/Moose/Cookbook/Roles/Recipe3.pod">application of roles to instances</a>.</p>
<p>When I first heard about this feature I instinctively dismissed it because it sounded inefficient, as if each instance were individually marked with a list of roles. In fact, the implementation is perfectly efficient. When you apply a role to an instance, Moose simply applies the role to the instance&#8217;s class to create a new anonymous class, then reblesses the instance into it. This is cached, so the next time you apply the same role to the same kind of object, the cached class can be used.</p>
<p>Now I&#8217;ve eliminated my custom code and have several roles working in CHI, each of which is activated by certain constructor parameters:</p>
<ul>
<li><a href="http://github.com/jonswar/perl-chi/blob/master/lib/CHI/Driver/Role/IsSizeAware.pm">IsSizeAware</a> &#8211; activated if is_size_aware or max_size is specified</li>
<li><a href="http://github.com/jonswar/perl-chi/blob/master/lib/CHI/Driver/Role/HasSubcaches.pm">HasSubcaches</a> &#8211; activated if l1_cache or mirror_cache is specified</li>
<li><a href="http://github.com/jonswar/perl-chi/blob/master/lib/CHI/Driver/Role/IsSubcache.pm">IsSubcache</a> &#8211; activated for subcaches themselves</li>
</ul>
<p>Moving these features out into separate roles has cleaned up the main driver code considerably. It also speeds up the common case, since we don&#8217;t have to check for these things on each call.</p>
<p>This does mean that CHI now depends irrevocably on Moose. For a short time we tried to compromise with Mouse as a way to minimize dependencies and application startup cost, but the role support just isn&#8217;t there, and even the authors of Mouse are now publicly <a href="http://www.nntp.perl.org/group/perl.moose/2009/04/msg653.html">discouraging its use</a>. Given the intelligence and drive of those working on Moose, I feel confident that it will continue to get faster and make its way into ever more Perl installations.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/06/01/how-roles-pushed-me-over-to-the-moose-side/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Auto-wrapping subclass methods</title>
		<link>http://www.openswartz.com/2009/04/26/auto-wrapping-subclass-methods/</link>
		<comments>http://www.openswartz.com/2009/04/26/auto-wrapping-subclass-methods/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 11:45:10 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=31</guid>
		<description><![CDATA[Back in Feb I asked on various lists how I could auto-wrap CHI driver methods, but didn&#8217;t get any completely satisfying answers:

CHI drivers implement methods like remove() and clear(). If you call $cache->remove(), it goes directly to the driver subclass.
The problem is that there are now legitimate reasons to &#8220;wrap&#8221; these methods at the CHI/Driver.pm [...]]]></description>
			<content:encoded><![CDATA[<p>Back in Feb I asked on various lists how I could auto-wrap CHI driver methods, but didn&#8217;t get any completely satisfying answers:</p>
<blockquote>
<p>CHI drivers implement methods like remove() and clear(). If you call $cache->remove(), it goes directly to the driver subclass.</p>
<p>The problem is that there are now legitimate reasons to &#8220;wrap&#8221; these methods at the CHI/Driver.pm superclass level (meaning, do something before and/or after the method). For example, I want to add an optional generic size-awareness feature (the cache can keep track of its own size), which means that we have to adjust size whenever remove() and clear() are called. And I want to log remove() calls the way we currently log get() and set().</p>
<p>So one solution is to define remove() and clear() in CHI/Driver.pm, and have them call _remove() and _clear() in the driver subclasses.  But this kind of change makes me uneasy for several reasons:</p>
<ul>
<li>It changes the driver API, i.e. all existing drivers out there have to modified. And we might have to change it again as we identify new methods to wrap.</li>
<li>The list of &#8216;normal&#8217; versus &#8216;underscore&#8217; methods becomes rather arbitrary &#8211; it&#8217;s &#8220;whatever we&#8217;ve needed to wrap so far&#8221;.</li>
</ul>
</blockquote>
<p>I thought about using regular wrapping modules, like Sub::Prepend or Hook::LexWrap. But this fails when you have subclasses more than one level deep. e.g.:</p>
<pre>
   CHI::Driver -> CHI::Driver::Foo -> CHI::Driver::Foo::Bar
</pre>
<p>Now if you call CHI::Driver::Foo::Bar::remove(), the wrapping code will get called twice, once for each subclass. I only want it to be called once regardless of how deep the subclass is.</p>
<p>Here&#8217;s how I solved this in CHI-0.2. When each CHI driver is used for the first time, e.g. CHI::Driver::Memory:</p>
<pre>
   my $cache = CHI->new('Memory');
</pre>
<p>CHI autogenerates a new class called CHI::Wrapped::CHI::Driver::Memory, which inherits from</p>
<pre>
   ('CHI::Driver::Wrapper', 'CHI::Driver::Memory')
</pre>
<p>then blesses the actual cache object (and future cache objects of this driver) as CHI::Wrapped::CHI::Driver::Memory.</p>
<p>Now, when someone calls a method like $cache->get() or $cache->remove(), CHI::Driver::Wrapper has an opportunity to handle it first, and then pass control to CHI::Driver::Memory. If not, it goes directly to CHI::Driver::Memory.</p>
<p>I was unable to find this solution on CPAN, even though I feel like I must be reinventing the wheel. If someone knows of a distribution that encapsulates this technique, please let me know.</p>
<p>Here&#8217;s the code from <a href="http://cpansearch.perl.org/src/JSWARTZ/CHI-0.2/lib/CHI/Driver/Wrapper.pm">CHI::Driver::Wrapper</a> that creates the wrapper class:</p>
<pre>
   sub create_wrapped_driver_class {
       my ( $proto, $driver_class ) = @_;
       carp "internal class method" if ref($proto);

       if ( !$wrapped_driver_classes{$driver_class} ) {
           my $wrapped_driver_class      = "CHI::Wrapped::$driver_class";
           my $wrapped_driver_class_decl = join( "\n",
               "package $wrapped_driver_class;",
               "use strict;",
               "use warnings;",
               "use base qw(CHI::Driver::Wrapper $driver_class);",
               "sub driver_class { '$driver_class' }",
               "1;" );
           eval($wrapped_driver_class_decl);    ## no critic ProhibitStringyEval
           die $@ if $@;                        ## no critic RequireCarping
           $wrapped_driver_classes{$driver_class} = $wrapped_driver_class;
       }
       return $wrapped_driver_classes{$driver_class};
   }
</pre>
<p>And here&#8217;s the first application of auto-wrapping: when certain methods are called on a cache, automatically call them on the <a href="http://search.cpan.org/~jswartz/CHI-0.2/lib/CHI.pm#SUBCACHES">subcaches</a>, if any.</p>
<pre>
   # Call these methods first on the main cache, then on any subcaches.
   #
   foreach my $method (qw(remove expire expire_if clear purge)) {
       no strict 'refs';
       *{ __PACKAGE__ . "::$method" } = sub {
           my $self = shift;
           my $retval = $self->call_native_driver( $method, @_ );
           $self->call_method_on_subcaches( $method, @_ );
           return $retval;
       };
   }

   # Call the specified $method on the native driver class, e.g. CHI::Driver::Memory.  SUPER
   # cannot be used because it refers to the superclass(es) of the current package and not to
   # the superclass(es) of the object - see perlobj.
   #
   sub call_native_driver {
       my $self                 = shift;
       my $method               = shift;
       my $native_driver_method = join( "::", $self->driver_class, $method );
       $self->$native_driver_method(@_);
   }
</pre>
<p>(See original <a href="http://use.perl.org/~jonswar/journal/38878">use.perl posting</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/04/26/auto-wrapping-subclass-methods/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CHI 0.2 &#8211; Subcaches</title>
		<link>http://www.openswartz.com/2009/04/25/chi-0-2-subcaches/</link>
		<comments>http://www.openswartz.com/2009/04/25/chi-0-2-subcaches/#comments</comments>
		<pubDate>Sat, 25 Apr 2009 13:19:38 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=28</guid>
		<description><![CDATA[I&#8217;ve just released CHI 0.02. The main visible change is that multi-level caches have been fleshed out and made easier to use.
There are two kinds of multi-level relationships that I wanted to be able to express easily with CHI:

L1 (level 1) cache: Sits in front of the primary cache in order faster access for commonly [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just released CHI 0.02. The main visible change is that multi-level caches have been fleshed out and made easier to use.</p>
<p>There are two kinds of multi-level relationships that I wanted to be able to express easily with CHI:</p>
<ul>
<li>L1 (level 1) cache: Sits in front of the primary cache in order faster access for commonly accessed cache entries. i.e. a cache for your cache.</li>
<p>Mirror cache: Sits behind the primary cache and, over time, mirrors its contents. Useful for migrating from one cache to another without a sudden performance hit.</ul>
<p>Initially CHI had a Multilevel driver that would let you place two or more caches inside a container cache object. The problem was that adding an L1 to an existing cache required changing it to a Multilevel cache, causing existing driver-specific calls to fail. (e.g. If I change a File cache to a Multilevel cache, File-specific methods will no longer get handled right.)</p>
<p>In 0.2 I switched to a primary cache / subcache model, which seems more appropriate. Now the File cache has an L1 subcache, and File-specific methods (as well as many ancillary methods on which the L1 relationship has no clear meaning) simply go to the primary cache.</p>
<p>The usage is also simpler. Here we place an in-process Memory cache in front a Memcached cache:</p>
<pre>    my $cache = CHI-&gt;new(
        driver   =&gt; 'Memcached',
        servers  =&gt; [ "10.0.0.15:11211", "10.0.0.15:11212" ],
        l1_cache =&gt; { driver =&gt; 'Memory' }
    );</pre>
<p>Note that there isn&#8217;t a way yet to specify a size limit for the memory cache, which would make this a lot more self-maintaining. <img src='http://www.openswartz.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  That&#8217;s coming soon. In the meantime, I&#8217;m planning to use this for an unlimited request-based cache, clearing it manually at the end of each web request:</p>
<pre>    $cache-&gt;l1_cache-&gt;clear();</pre>
<p>Here we prepare to migrate from an old to a new cache directory:</p>
<pre>    my $cache = CHI-&gt;new(
        driver          =&gt; 'File',
        root_dir        =&gt; '/old/cache/root',
        mirror_cache =&gt; { driver =&gt; 'File', root_dir =&gt; '/new/cache/root' },
    );</pre>
<p>We leave this running for a few hours (or as needed), then replace it with</p>
<pre>    my $cache = CHI-&gt;new(
        driver   =&gt; 'File',
        root_dir =&gt; '/new/cache/root'
    );</pre>
<p>More details in the Subcaches section of the CHI 0.2 documentation.</p>
<p>(See original <a href="http://use.perl.org/~jonswar/journal/38872">use.perl posting</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2009/04/25/chi-0-2-subcaches/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>problems and solutions for typical perl cache usage</title>
		<link>http://www.openswartz.com/2008/02/04/problems-and-solutions-for-typical-perl-cache-usage/</link>
		<comments>http://www.openswartz.com/2008/02/04/problems-and-solutions-for-typical-perl-cache-usage/#comments</comments>
		<pubDate>Mon, 04 Feb 2008 10:43:26 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=22</guid>
		<description><![CDATA[A typical cache usage pattern looks like this:

   # Try to get the value from the cache
   my $result = $cache->get('key');

   # If it isn't there, compute and set in the cache
   if (!defined($result)) {
      my $result = do_something_to_compute_result();
    [...]]]></description>
			<content:encoded><![CDATA[<p>A typical cache usage pattern looks like this:</p>
<pre>
   # Try to get the value from the cache
   my $result = $cache->get('key');

   # If it isn't there, compute and set in the cache
   if (!defined($result)) {
      my $result = do_something_to_compute_result();
      $cache->set('key', $result, $expiration_time);
   }
</pre>
<p>This pattern is popular because it is easy to wrap around existing code, and easy to understand.</p>
<p>Unfortunately, it suffers from two problems:</p>
<ul>
<li>
<p><b>Miss Stampedes</b>: When a cache item expires at the specified time, any processes trying to get it will start to recompute it. If it is a popular cache item and if recomputation is expensive, you may get many recomputations for the same item, which is at best wasteful and at worst can bog down a server.</p>
<p>I originally recognized this problem while working on Mason&#8217;s <a href="http://www.masonhq.com/docs/manual/Devel.html#avoiding_concurrent_recomputatio">busy locking</a>, but am obviously not alone in experiencing it. The term &#8220;miss stampede&#8221; comes from this <a href="http://lists.danga.com/pipermail/memcached/2007-July/004803.html">memcached list discussion</a> &#8211; definitely worth a read.</p>
</li>
<li>
<p><b>Recomputation Latency</b>: When a cache item is recomputed, the client (whether that be a browser, command-line, whatever) has to wait for the computation to complete. Since caching keeps average latencies down, there is a tendency to ignore the unfortunate customer that gets stuck with one or more cache misses.</p>
</li>
</ul>
<p>Here are some ways of tweaking the usage pattern above to address one or both of these problems.  I&#8217;ve added the initials of the problems that each one addresses, and mentioned relevant features from <a href="http://search.cpan.org/search?query=CHI&#038;mode=all">CHI</a>, if any.</p>
<ul>
<li><b>Probabilistic expiration (MS)</b>
<p>Instead of specifying a single expiration time, specify a range of time during which expiration might occur. Then each cache <tt>get</tt> makes an independent probabilistic decision as to whether the item has expired. The probability starts out low at the beginning of the range and increases to 1.0 at the end of the range. What this means for popular cache items is that only one or a handful of <tt>get</tt>s will most likely expire at the same time.</p>
<p>CHI supports this with the <a href="http://cpan.uwinnipeg.ca/htdocs/CHI/CHI.html#expires_variance_FLOAT">expires_variance</a> parameter. It may be passed to individual <tt>set</tt> commands or as a default for all <tt>set</tt>s. Personally, I plan to default it to 0.2 or so in almost all my caches.</p>
<p>Drawbacks: Since this is probabilistic, you get no guarantee of how well stampedes will be avoided (if at all), and you have to try to guess the right variance to use.</p>
</li>
<li><b>Busy locks (MS)</b>
<p>When a cache item expires, flag the item for a short time, either by upping its expiration time or by setting an associated value in the cache. Subsequent misses will see the flag and return the old value instead of duplicating the recompute effort.</p>
<p>CHI supports this with the <a href="http://cpan.uwinnipeg.ca/htdocs/CHI/CHI.html#busy_lock_DURATION">busy_lock</a> parameter, stolen from Mason. It works by temporarily setting the expiration time forward by the specified amount of time.</p>
<p>Drawbacks: Setting a busy lock involves a separate write. If you use this feature liberally, you&#8217;ll double the number of write operations you do. Some backends will suffer from a race condition, a small window of time in which many processes may decide to recompute, before the first lock has been successfully set.</p>
</li>
<li><b>Background recomputation (RL)</b>
<p>When a cache item expires, return the old value immediately, then kick off a recomputation in the background. This spares the client from the cost of the recompute.</p>
<p>This requires a non-traditional usage pattern, since the get and set are effectively happening as part of one operation. In CHI it will look like this:</p>
<pre>
    my $result =
      $cache->compute( 'key', sub { do_something_to_compute_result() },
        $expiration_time );
</pre>
<p>CHI already has a working <a href="http://cpan.uwinnipeg.ca/htdocs/CHI/CHI.html#compute_key_code_set_options">compute</a> API, but doesn&#8217;t yet know how to run things in the background. Coming soon.</p>
<p>Drawbacks: Requires a non-traditional and somewhat ugly code pattern; background processes are harder to track and debug.</p>
<li><b>External recomputation (MS + RL)</b>
<p>Recompute cache items entirely from an external process, either when change events occur or when items approach their expiration time. Items never actually expire as the result of a client request. This is the most efficient and client-friendly solution, if you can manage it.</p>
<p>Drawbacks: Requires extra external processes (more moving parts). Code to recompute caches must be available from the external process, which can result in some unwanted code separation, API contortions, or repetition. It is also difficult to know which items to keep repopulating, and when exactly to recompute them.</p>
</li>
<li><b>Externally initiated recomputation (MS + RL)</b>
<p>Use a periodic external process to trigger events that will naturally utilize your caches (e.g. write a cron job that hits common pages on your website), but pass a special flag making items more likely to expire. This makes it less likely that expiration will occur during a real client request.</p>
<p>This is not yet supported in CHI, but the idea would be to add some kind of easily-accessible lever to temporarily view all expiration times as reduced. e.g.</p>
<pre>
    # Reduction ends when $lex goes out of scope
    my $lex = CHI->reduced_expirations(0.5);
</pre>
<p>Drawbacks: Requires extra external processes (more moving parts). Triggers and their run frequencies must be carefully chosen.</p>
</li>
</ul>
<p>What other techniques have you used, and what success/failures have you had with them?</p>
<p>(See original <a href="http://use.perl.org/~jonswar/journal/35579">use.perl posting</a>)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2008/02/04/problems-and-solutions-for-typical-perl-cache-usage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CHI: Cache Interface for Perl</title>
		<link>http://www.openswartz.com/2008/01/23/chi-cache-interface-for-perl/</link>
		<comments>http://www.openswartz.com/2008/01/23/chi-cache-interface-for-perl/#comments</comments>
		<pubDate>Wed, 23 Jan 2008 08:57:03 +0000</pubDate>
		<dc:creator>Jonathan Swartz</dc:creator>
				<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.openswartz.com/?p=15</guid>
		<description><![CDATA[CHI, a module I&#8217;ve been working on for a few months, has made it to CPAN:

   file: $CPAN/authors/id/J/JS/JSWARTZ/CHI-0.03.tar.gz
   size: 62313 bytes
    md5: ec828f2466ba266e11cd6d1dd5ca2913

CHI provides a unified caching API, designed to assist a developer in persisting data for a specified period of time. It is intended as an evolution [...]]]></description>
			<content:encoded><![CDATA[<p>CHI, a module I&#8217;ve been working on for a few months, has made it to <a href="http://search.cpan.org/search?query=CHI&#038;mode=all">CPAN</a>:</p>
<pre>
   file: $CPAN/authors/id/J/JS/JSWARTZ/CHI-0.03.tar.gz
   size: 62313 bytes
    md5: ec828f2466ba266e11cd6d1dd5ca2913
</pre>
<p>CHI provides a unified caching API, designed to assist a developer in persisting data for a specified period of time. It is intended as an evolution of DeWitt Clinton&#8217;s Cache::Cache package, adhering to the basic Cache API but adding new features and addressing limitations in the Cache::Cache implementation.</p>
<p>You might think of it as a fledgling &#8220;DBI for caching&#8221;.</p>
<p>Driver classes already exist for in-process memory, plain files, memory mapped files and memcached.  Other drivers such as BerkeleyDB and DBI will be coming soon. Fortunately, implementing drivers is fairly easy, on the order of creating a TIE interface to your data store.</p>
<p>Special thanks to the <a href="http://subscribe.hearstmags.com/">Hearst Digital Media group</a>, where CHI was first designed and developed, for blessing the open source release of this code.</p>
<p>There&#8217;s lots more in store for this module, so stay tuned! Feedback welcome here or on the <a href="http://groups.google.com/group/perl-cache-discuss">Perl cache mailing list</a>.</p>
<p>(See original <a href="http://use.perl.org/~jonswar/journal/35472">use.perl posting</a> with comments)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openswartz.com/2008/01/23/chi-cache-interface-for-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
