pudge's Friends' Journals http://use.perl.org/~pudge/journal/friends/ pudge's Friends' use Perl Journals 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-25T01:45:11+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 pudge's Friends' Journals http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~pudge/journal/friends/ Finally, some Test::Builder2 examples! http://use.perl.org/~schwern/journal/40528?from=rss <p>For my PDX.pm presentation tonight on <a href="http://github.com/schwern/test-more/tree/Test-Builder2">Test::Builder2</a> I threw together some quick examples of some of its killer features, in particular demonstrating changing how Test::Builder2 behaves using method modifiers and applying object roles.</p><p>First, demonstrating end-of-assert actions, there's <a href="http://github.com/schwern/test-more/blob/Test-Builder2/examples/TB2/lib/TB2/DieOnFail.pm">die on fail</a> but even cooler is <a href="http://github.com/schwern/test-more/blob/Test-Builder2/examples/TB2/lib/TB2/DebugOnFail.pm">DEBUG on fail</a>! That's right, run your test in the debugger and have it automatically set a breakpoint on a failure. How cool is that?</p><p>I'm sure somebody with better debugger foo than I can make it even cooler and stop at the top of the assert stack rather than inside DebugOnFail.</p><p>The second is reimplementing <a href="http://search.cpan.org/perldoc?Test::NoWarnings">Test::NoWarnings</a> safely. <a href="http://github.com/schwern/test-more/blob/Test-Builder2/examples/TB2/lib/TB2/NoWarnings.pm">TB2::NoWarnings</a> demonstrates hooking into the start and end of the test as well as safely altering the number of tests planned by trapping the call to set_plan.</p><p>You can safely use them all together, though its a crap shoot if DebugOnFail or DieOnFail will trigger first.</p><p>While roles and method modifiers are relatively new to the Perl community, using them in lieu of designing my own event system for TB2 has two great advantages. First, I didn't have to design and debug my own event system.<nobr> <wbr></nobr>:) Second, rather than having to learn the quirks of a one-off system, you learn the quirks of Mo[uo]se and then can apply that knowledge all over the place.</p><p>There's <a href="http://github.com/schwern/test-more/issues/labels/Test-Builder2">a pile of stuff to be done in TB2</a>, a lot of them are fairly small and self contained. Have a look. Patches welcome.</p> schwern 2010-09-09T08:33:42+00:00 journal Test::Builder2 at 10k Feet http://use.perl.org/~schwern/journal/40527?from=rss <p>Here's a diagram of the "flow" of assert results through Test::Builder version 1.</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| foo.t |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp;.-------------.&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp;.----------------.<br>&nbsp; &nbsp; &nbsp;| Test::More&nbsp; |&lt;---------&gt;| Test::Whatever |<br>&nbsp; &nbsp; &nbsp;'-------------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'----------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp;.---------------.&nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '----&gt;| Test::Builder |&lt;----'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '---------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-----.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| TAP |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-----'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.---------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Test::Harness |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '---------------'</tt></p></div> </blockquote><p>You write foo.t using Test::More and Test::Whatever. These both<br>use the same Test::Builder object. It spits out TAP which<br>Test::Harness converts into something human readable.</p><p>The big problem there is Test::Builder is monolithic. There's no<br>further breakdown of responsibilities. It only spits out TAP, and<br>only one version of TAP.</p><p>Here's what Test::Builder2 looks like:</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.-------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.----------------| foo.t |-------------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '-------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.------------.&nbsp; &nbsp; &nbsp;.----------------.&nbsp; &nbsp; &nbsp;.------------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Test::More |&nbsp; &nbsp; &nbsp;| Test::Whatever |&nbsp; &nbsp; &nbsp;| Test::NotUpdated |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '------------'&nbsp; &nbsp; &nbsp;'----------------'&nbsp; &nbsp; &nbsp;'------------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.----------------.&nbsp; &nbsp; &nbsp; &nbsp;.---------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'----------&gt;| Test::Builder2 |&lt;------| Test::Builder |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'----------------'&nbsp; &nbsp; &nbsp; &nbsp;'---------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.--------------.&nbsp; &nbsp;<nobr> <wbr></nobr>.-------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| TB2::History |&lt;---| TB2::Result |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'--------------'&nbsp; &nbsp; '-------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp;<nobr> <wbr></nobr>.--------------------------.&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;.---------------------.<br>&nbsp; &nbsp; | TB2::Formatter::TAP::v13 |&lt;-----'------&gt;| TB2::Formatter::GUI |<br>&nbsp; &nbsp; '--------------------------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '---------------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp;<nobr> <wbr></nobr>.-------------------------------.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; | TB2::Formatter::Streamer::TAP |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; '-------------------------------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-----.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| TAP |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-----'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.---------------.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-----------------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Test::Harness |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| Pretty Pictures |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '---------------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-----------------'</tt></p></div> </blockquote><p>It starts out the same, foo.t uses a bunch of test modules<br>including Test::More and Test::Whatever using the same Test::Builder2<br>object, but it also uses Test::NotUpdated which is still using<br>Test::Builder. That's ok because Test::Builder has been rewritten in<br>terms of Test::Builder2 (more on that below).</p><p>Test::Builder2, rather than being a monolith, produces a<br>Test::Builder2::Result object for each assert run. This gets stored<br>in a Test::Builder2::History object for possible later use. It also<br>gets handed to a Test::Builder2::Formatter object, the default is<br>Test::Builder2::TAP::v13 which produces TAP version 13. This is fed<br>to a Streamer that prints it to STDOUT and STDERR which is read by<br>Test::Harness and made human readable.</p><p>Because Test::Builder2 is not monolithic, you can swap out parts. For<br>example, instead of outputting TAP it could instead hand results to a<br>formatter that produced a simple GUI representation, maybe a green<br>bar, or something that hooks into a larger GUI. Or maybe one that<br>produces JUnit XML.</p><p>Here's how Test::Builder and Test::Builder2 Relate.</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.-----.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-----.<br>&nbsp; &nbsp; &nbsp; &nbsp; | TB2 |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| TB1 |<br>&nbsp; &nbsp; &nbsp; &nbsp; '-----'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-----'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v<br>&nbsp; &nbsp;<nobr> <wbr></nobr>.-------------.&nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.--------------.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.-------------.<br>&nbsp; &nbsp; | TB2::Result |-------&gt;| TB2::History |&lt;--------| TB2::Result |<br>&nbsp; &nbsp; '-------------'&nbsp; &nbsp; &nbsp; &nbsp; '--------------'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.----------------.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'-------------&gt;| TB2::Formatter |&lt;--------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '----------------'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;v<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<nobr> <wbr></nobr>.--------.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Output |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '--------'</tt></p></div> </blockquote><p>Test::Builder and Test::Builder2 coordinate their actions by sharing<br>the same History and Formatter objects. If you call TB1-&gt;ok() it<br>produces a Result object which it hands to the History singleton and<br>the Formatter singleton. If you call TB2-&gt;ok() it produces a Result<br>object which it hands to the same History and Formatter objects.</p><p>This allows most of the Test::Builder code to remain the same while<br>still coordinating with Test::Builder2. It also allows radically<br>different builders to be made without Test::Builder2 dictating how<br>they're to work.</p><p>The downside is that roles applied to Test::Builder2 will not effect<br>Test::Builder. Because of this, Test::Builder may become more closely<br>coupled with Test::Builder2 in the future.</p><p>Diagrams by <a href="http://search.cpan.org/dist/App-Asciio">App::Asciio</a>.</p> schwern 2010-09-09T08:15:22+00:00 journal DBD::SQLite 1.31 releasing next week and may break your code http://use.perl.org/~Alias/journal/40526?from=rss <p>After 6 or 7 months (mainly waiting around for the next "recommended upgrade instruction" from the SQLite project) the latest DBD::SQLite release should occur next week.</p><p>You can get the 1.30_06 release candidate from the CPAN, or from the following URL if your mirror hasn't synced yet.</p><p><a href="http://svn.ali.as/cpan/releases/DBD-SQLite-1.30_06.tar.gz">http://svn.ali.as/cpan/releases/DBD-SQLite-1.30_06.tar.gz</a></p><p>Apart from the normal batch of SQLite upgrades (from 3.6.22 to 3.7.2), bug fixes, and minor enhancements, this release has two changes that may break your code.</p><p>These changes have been in the dev releases for some time, but you may want to take the opportunity to test more intensively if you use either of the following features.</p><p>1. BLOB columns with UTF8 content</p><blockquote><div><p> <tt>- Resolved #54271: Inserting a string with utf-8 flag on<br>&nbsp; corrupts BLOB data; now BLOB data is always stored as bytes<br> &nbsp; (without the utf-8 flag) even if it has the flag set (ISHIGAKI)</tt></p></div> </blockquote><p>2. FTS3 queries</p><blockquote><div><p> <tt>- Added support for FTS3 tokenizers written in Perl. Added tests<br>&nbsp; and documentation on how to use FTS3. Changed compilation flag<br>&nbsp; to use the recommanded -DSQLITE_ENABLE_FTS3_PARENTHESIS<br>&nbsp; *** MAY POSSIBLY BREAK OLD APPLICATIONS THAT ALREADY USED FTS3 ***<br>&nbsp; (DAMI)</tt></p></div> </blockquote><p>If you are currently using FTS3, please see <a href="http://search.cpan.org/perldoc?DBD::SQLite::FTS3Transitional">DBD::SQLite::FTS3Transitional</a> which contains a helper function for automatically upgrading old FTS3 queries to the new syntax.</p> Alias 2010-09-09T02:11:54+00:00 journal use Perl; Shutting Down Indefinitely http://use.perl.org/~pudge/journal/40525?from=rss <p>See <a href="http://use.perl.org/article.pl?sid=10/09/08/2053239">here</a>.</p> pudge 2010-09-08T22:07:47+00:00 useperl Should Module::Install move to explicit plugin declaration? http://use.perl.org/~Alias/journal/40523?from=rss <p>Module::Install has been through a long period of gradual stability over the last year, without any really dramatic improvements to the grammar or APIs.</p><p>With the more urgent "it doesn't work with blah" stuff mostly solved now, one of the big remaining issues is around error clarity and excessive magic.</p><p>For example, some random author that is trying to checkout a Catalyst project needs:</p><p>1. To have Module::Install installed.<br>2. To have Module::Install::Catalyst installed.</p><p>In the case of the former, you get the semi-cryptic but at least standard "Can't find inc/Module/Install.pm in @INC" message, so the error is resolvable.</p><p>But in the latter case, you're likely to get something like "Unknown command 'catalyst_ignore'", with no real obvious resolution mechanism.</p><p>I think this idea of automatic plugin discovery is starting to hit it's limits in terms of clarity.</p><p>And so I'd like to do something counter to my natural instincts here, and make M:I more verbose.</p><p>I'm thinking of something like the following for explicitly declaring the use of a non-core Module::Install extension.</p><blockquote><div><p> <tt>use inc::Module::Install qw{ Catalyst XSUtil };</tt></p></div> </blockquote><p>This would both allow M:I to error with a much more meaningful error when you don't have a plugin, and also prevent the loading of unused plugins which should prevent accidental plugin collisions (some of which I've seen occurring in the CPAN Testers machines).</p><p>Thoughts?</p> Alias 2010-09-06T02:26:06+00:00 journal A month of Test::Builder2 http://use.perl.org/~schwern/journal/40517?from=rss <p>I've had <a href="http://www.perlfoundation.org/test_builder_2">a grant open for Test::Builder2</a> for, oh god over two years now. Since I started it, Perl 6 has had a release! I think its the second oldest running dev grant.</p><p>I've cleared the decks of other responsibilities and can dedicate September to, if not finishing, then at least releasing something people can poke at. First alpha release was supposed to be "two weeks after the start" ha ha ha! oh god. The design has evolved and simplified greatly in the intervening two years, but its time to get something the hell out the door. At least a <a href="http://github.com/schwern/test-more/tree/Test-Builder2">Test::Builder2</a> Star if you will.</p><p>There's critical components missing. There's no diagnostics, YAML or otherwise. The issues with nested asserts are still congealing. Plans are not enforced. Result objects are in the middle of being remodeled... again. But Test::Builder is using what parts of Test::Builder2 are usable. Multiple output formats and streams work. Asserts can be nested in the common, simple cases without having to fiddle with $Level. And you can hook into various events.</p><p>Step one is I'm going to seal up what's there, write docs where they're missing, and release something.</p><p>A release before October or the grant dies.</p> schwern 2010-08-28T04:08:39+00:00 journal Will parrot be the last one standing? http://use.perl.org/~nicholas/journal/40509?from=rss <p>I'm a bit behind the times here, but I read today that one of the two remaining developers of IronRuby has left Microsoft:</p><blockquote><div><p>Overall, I see a serious lack of commitment to IronRuby, and dynamic language on<nobr> <wbr></nobr>.NET in general. At the time of my leaving Tomas and myself were the only Microsoft employees working on IronRuby.</p></div></blockquote><p> <a href="http://blog.jimmy.schementi.com/2010/08/start-spreading-news-future-of-jimmy.html">http://blog.jimmy.schementi.com/2010/08/start-spreading-news-future-of-jimmy.ht<nobr>m<wbr></nobr> l</a>*</p><p>So if Microsoft's interest in dynamic languages is wilting, and Oracle's litigation scares everyone away from Java, will that leave <a href="http://parrot.org/">Parrot</a> as the last one standing?</p><p> <small>* yep, that's a formatting bug. I assume that it's not worth reporting while the site's future is unclear.</small> </p> nicholas 2010-08-20T09:37:19+00:00 journal Speaking at Microsoft TechEd - Any issues you want raised? http://use.perl.org/~Alias/journal/40508?from=rss <p>Next week I will at Microsoft's TechEd Australia event, courtesy of Microsoft Australia and Microsoft Open Source Labs.</p><p>More specifically, I'll be attending the Open Source mini-conf and discussion day on Tuesday, and presenting in the Community Presentations to Microsoft session on the current state of Perl and Windows on Wednesday.</p><p>Likely topics will include a review of the first year of the CPAN Testing Lab and a second-generation based on their Cloud Services, free code signing certificates for open source developers, and what issues are slowing us down or blocking progress.</p><p>So consider this your opportunity to raise any outstanding issues you have with Microsoft and Perl. What problems are you still seeing, what would like fixed or changed, and what is on your want-to-have list?</p><p>I'll try to address as many of your issues as possible in the time I have available with them (which is actually pretty substantial).</p> Alias 2010-08-20T03:20:46+00:00 journal Cute caps http://use.perl.org/~jdavidb/journal/40507?from=rss <p>I'm doing some quick code generation (the output is Java), and I found myself writing the below routine. I like it because of the names I picked for the variables. Not exactly self-documenting (although it is when you think about it), but this is throwaway. You can probably tell what the code is doing and why I named the variables as I did, and you might be entertained.</p><blockquote><div><p> <tt>sub uc_prop<br>{<br>&nbsp; my($prop) = @_;<br>&nbsp; my $p = substr($prop, 0, 1);<br>&nbsp; my $P = uc($p);<br>&nbsp; my $rop = substr($prop, 1);<br>&nbsp; return "$P$rop";<br>}</tt></p></div> </blockquote> jdavidb 2010-08-19T21:55:41+00:00 journal Consistent GUIs; Or, Using WPF for Good and Not Evil http://use.perl.org/~Mark+Leighton+Fisher/journal/40505?from=rss <p> <a href="http://www.rollthunder.com/SoftwareThatDoesntSuck/WpfForGoodAndNotEvil.htm">Using WPF for Good and Not Evil</a> is a nice little write-up on how we, as developers, need to consider why and how we might change the user interface of programs developed in WPF. My take on it is that "Just because you can do something does not mean you SHOULD do something."</p><p> <i>(Ob.Perl: Perlesque should let you program directly in WPF by using the<nobr> <wbr></nobr>.NET libraries.)</i> </p> Mark Leighton Fisher 2010-08-19T16:43:59+00:00 others Alien::SVN - new release, new management http://use.perl.org/~schwern/journal/40503?from=rss <p>Those of you still stuck using Subversion will be happy to find <a href="http://search.cpan.org/~mlanier/Alien-SVN-1.6.12.0/">a new release of Alien::SVN</a>. It drags it forward to 1.6.12, doesn't do much else.</p><p>Also, Alien::SVN has finally found a new manager! From out of the blue comes <a href="http://search.cpan.org/~mlanier/">Matthew Lanier</a> with a patch and the will and a PAUSE ID. He'll be taking care of things from now on. Its his first CPAN module, be gentle. Godspeed, Matthew.</p> schwern 2010-08-18T22:33:29+00:00 journal Class::XSAccessor now even faster'er http://use.perl.org/~Alias/journal/40497?from=rss <p>The new 1.07 release of <a href="http://search.cpan.org/perldoc?Class::XSAccessor">Class::XSAccessor</a> mentions the use a new somewhat-evil technique for making the code even faster than it was previously.</p><p>But how much faster is it?</p><p>The following are being run on a fairly typical corporate Windows XP machine, with Strawberry Perl 5.10.1 and thread support.</p><p>First, some benchmarks using the previous 1.05 release (two runs)</p><blockquote><div><p> <tt>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 1 wallclock secs ( 2.51 usr +&nbsp; 0.00 sys =&nbsp; 2.51 CPU) @ 3976143.14/s (n=10000000)<br>accessor_set:&nbsp; 2 wallclock secs ( 3.09 usr +&nbsp; 0.00 sys =&nbsp; 3.09 CPU) @ 3233107.02/s (n=10000000)<br>constructor: 16 wallclock secs (15.67 usr +&nbsp; 0.00 sys = 15.67 CPU) @ 638080.65/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.91 usr +&nbsp; 0.00 sys =&nbsp; 1.91 CPU) @ 5243838.49/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 1 wallclock secs ( 2.34 usr +&nbsp; 0.00 sys =&nbsp; 2.34 CPU) @ 4266211.60/s (n=10000000)<br> &nbsp; predicate:&nbsp; 1 wallclock secs ( 2.38 usr +&nbsp; 0.00 sys =&nbsp; 2.38 CPU) @ 4210526.32/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 2 wallclock secs ( 3.27 usr +&nbsp; 0.00 sys =&nbsp; 3.27 CPU) @ 3061849.36/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 1 wallclock secs ( 1.80 usr +&nbsp; 0.00 sys =&nbsp; 1.80 CPU) @ 5564830.27/s (n=10000000)<br> &nbsp; <br>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 3 wallclock secs ( 2.51 usr +&nbsp; 0.00 sys =&nbsp; 2.51 CPU) @ 3976143.14/s (n=10000000)<br>accessor_set:&nbsp; 3 wallclock secs ( 3.14 usr +&nbsp; 0.00 sys =&nbsp; 3.14 CPU) @ 3183699.46/s (n=10000000)<br>constructor: 15 wallclock secs (15.73 usr +&nbsp; 0.00 sys = 15.73 CPU) @ 635566.29/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.86 usr +&nbsp; 0.00 sys =&nbsp; 1.86 CPU) @ 5379236.15/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 3 wallclock secs ( 2.50 usr +&nbsp; 0.00 sys =&nbsp; 2.50 CPU) @ 4000000.00/s (n=10000000)<br> &nbsp; predicate:&nbsp; 3 wallclock secs ( 2.47 usr +&nbsp; 0.00 sys =&nbsp; 2.47 CPU) @ 4050222.76/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 4 wallclock secs ( 3.13 usr +&nbsp; 0.00 sys =&nbsp; 3.13 CPU) @ 3200000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.98 usr +&nbsp; 0.00 sys =&nbsp; 1.98 CPU) @ 5037783.38/s (n=10000000)</tt></p></div> </blockquote><p>And now again with the new 1.07 release.</p><blockquote><div><p> <tt>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 2 wallclock secs ( 1.75 usr +&nbsp; 0.00 sys =&nbsp; 1.75 CPU) @ 5711022.27/s (n=10000000)<br>accessor_set:&nbsp; 1 wallclock secs ( 2.69 usr +&nbsp; 0.00 sys =&nbsp; 2.69 CPU) @ 3721622.63/s (n=10000000)<br>constructor: 15 wallclock secs (15.62 usr +&nbsp; 0.00 sys = 15.62 CPU) @ 640000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 1 wallclock secs ( 1.28 usr +&nbsp; 0.00 sys =&nbsp; 1.28 CPU) @ 7806401.25/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 1 wallclock secs ( 1.56 usr +&nbsp; 0.00 sys =&nbsp; 1.56 CPU) @ 6397952.66/s (n=10000000)<br> &nbsp; predicate:&nbsp; 2 wallclock secs ( 1.92 usr +&nbsp; 0.00 sys =&nbsp; 1.92 CPU) @ 5205622.07/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 3 wallclock secs ( 2.50 usr +&nbsp; 0.00 sys =&nbsp; 2.50 CPU) @ 4000000.00/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.55 usr +&nbsp; 0.00 sys =&nbsp; 1.55 CPU) @ 6464124.11/s (n=10000000)<br> &nbsp; <br>Benchmark: timing 10000000 iterations of accessor_get, accessor_set, constructor, false, getter, predicate, setter, true...<br>accessor_get:&nbsp; 2 wallclock secs ( 1.78 usr +&nbsp; 0.00 sys =&nbsp; 1.78 CPU) @ 5614823.13/s (n=10000000)<br>accessor_set:&nbsp; 3 wallclock secs ( 2.63 usr +&nbsp; 0.00 sys =&nbsp; 2.63 CPU) @ 3809523.81/s (n=10000000)<br>constructor: 16 wallclock secs (15.69 usr +&nbsp; 0.00 sys = 15.69 CPU) @ 637429.88/s (n=10000000)<br>&nbsp; &nbsp; &nbsp;false:&nbsp; 2 wallclock secs ( 1.22 usr +&nbsp; 0.00 sys =&nbsp; 1.22 CPU) @ 8203445.45/s (n=10000000)<br>&nbsp; &nbsp; getter:&nbsp; 2 wallclock secs ( 1.53 usr +&nbsp; 0.00 sys =&nbsp; 1.53 CPU) @ 6535947.71/s (n=10000000)<br> &nbsp; predicate:&nbsp; 2 wallclock secs ( 1.78 usr +&nbsp; 0.00 sys =&nbsp; 1.78 CPU) @ 5614823.13/s (n=10000000)<br>&nbsp; &nbsp; setter:&nbsp; 2 wallclock secs ( 2.56 usr +&nbsp; 0.00 sys =&nbsp; 2.56 CPU) @ 3903200.62/s (n=10000000)<br>&nbsp; &nbsp; &nbsp; true:&nbsp; 2 wallclock secs ( 1.48 usr +&nbsp; 0.00 sys =&nbsp; 1.48 CPU) @ 6738544.47/s (n=10000000)</tt></p></div> </blockquote><p>The numbers are pretty impressive.</p><p>The 'accessor', 'setter', 'predicate' and 'true' methods are about 25% faster, while 'getter' is a whopping 60% faster and (curiously) 'false' is about 50% faster as well.</p><p>Constructors are really the only thing that hasn't changed.</p><p>Impressive work, even if the code is a bit risky.</p> Alias 2010-08-16T03:04:05+00:00 journal Why does Object::Tiny only support getters http://use.perl.org/~Alias/journal/40496?from=rss <p><a href="http://perlalchemy.blogspot.com/2010/08/objecttinyrw-and-moosexnonmoose.html">http://perlalchemy.blogspot.com/2010/08/objecttinyrw-and-moosexnonmoose.html</a></p><p>Zbigniew Lukasiak tries out <a href="http://search.cpan.org/peldoc?Object::Tiny">Object::Tiny</a> and wonders why it is that I didn't allow for the creation of setters when it is only a one line change.</p><p>Like most<nobr> <wbr></nobr>::Tiny modules the reason is a bit complex and the result of compromises.</p><p>Object::Tiny began as an attempt to create a lighter, faster, version of Class::Accessor. A way to bulk-generate the accessor code I had to type over and over again.</p><p>However, where I differ is a strong preference for light and elegant API design.</p><p>And so I decided to implement mine with as little implementation code as possible, and as little API code as possible.</p><p>Once you have decided to go down the simplicity path, there's a couple of standard techniques you often end up using.</p><p>The first and most important is state reduction.</p><p>In their introduction to Erlang, the founders of that language describe state as one of the main sources of failures in programs. And so anything that removes state, at the very least unnecessary state, is a positive. Especially if the state reduction also results in code reduction, and a reduction in computation.</p><p>So take the following example, where we create an object with some attributes and then run some code that will use those object attributes..</p><blockquote><div><p> <tt>my $object = Class-&gt;new;<br>$object-&gt;foo(1);<br>$object-&gt;bar(2);<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>This is a use case that we see fairly often, but it's really quite horrible code. It is really only the object-oriented equivalent of something like the following.</p><blockquote><div><p> <tt>our $Object::foo = 1;<br>our $Object::bar = 2;<br>do_something('Object');</tt></p></div> </blockquote><p>It is especially bad code if the following code would throw an exception.</p><blockquote><div><p> <tt>my $object = Class-&gt;new;<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>If this blows up, then you are REALLY doing something wrong, because you have allowed the creation of completely invalid objects. Now anybody taking one of these objects as a parameters needs to do with following.</p><blockquote><div><p> <tt>sub foo {<br>&nbsp; &nbsp; my $object = shift;<br>&nbsp; &nbsp; unless (<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;isa('Class')<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; defined $object-&gt;foo<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;foo &gt; 0<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; defined $object-&gt;bar<br>&nbsp; &nbsp; &nbsp; &nbsp; and<br>&nbsp; &nbsp; &nbsp; &nbsp; $object-&gt;bar &gt; 2<br>&nbsp; &nbsp; ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; die "Invalid object";<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>If you are going to create an object for something, you HAVE to be sure that the objects are trustworthy.</p><p>And so you should never allow objects to exist that are invalid. EVERY object should be a valid object.</p><p>At the absolute minimum objects should be able to default every attribute to something reasonable and unlikely to cause problems.</p><p>But this still results in excess and wasteful work, because the object has to transition through two or more states.</p><p>You start with an object with parameters and defaults, and you validate them. And then you change on of the attributes immediately, validating it AGAIN. In the mean time, your object exists in a state that it will never actually be used in.</p><p>And so everywhere you possibly can, you should be setting attributes in the constructor rather than afterwards.</p><blockquote><div><p> <tt>my $object = Class-&gt;new(<br>&nbsp; &nbsp; foo =&gt; 1,<br>&nbsp; &nbsp; bar =&gt; 2,<br>);<br>$object-&gt;do_something;</tt></p></div> </blockquote><p>Less state, less complexity, less CPU, and less bugs.</p><p>If we accept this model of pushing all the configuration into the object up front to reduce state, then why change the object arbitrarily?</p><p>In fact, anything that you ARE going to change should be done under very controlled conditions.</p><p>It should require a dedicated method to apply the change, it should require validation, and work. It shouldn't be trivial, and it shouldn't be automatic.</p><p>If I had my way, Moose would set is =&gt; 'ro' by default, to make people think before they go about simply allowing stuff to change.</p><p>It also happens to let you shrink down the API markedly.</p><p>There are three potential use cases available when implementing accessors. Everything readonly, everything readwrite, or mixed.</p><p>With Object::Tiny, I was aiming for the smallest possible code.</p><p>Implementing either all-readonly or all-readwrite can be done with the following.</p><blockquote><div><p> <tt>use Class qw{<br>&nbsp; &nbsp; foo<br>&nbsp; &nbsp; bar<br>};</tt></p></div> </blockquote><p>By contrast, if we want to allow mixed readonly and readwrite, we would need some way of distinguishing. Something like the following.</p><blockquote><div><p> <tt>use Class {<br>&nbsp; &nbsp; readonly =&gt; [ 'foo' ],<br>&nbsp; &nbsp; readwrite =&gt; [ 'bar' ],<br>};<br> &nbsp; <br>use Class [ qw{<br>&nbsp; &nbsp; foo<br>} ], [ {<br>&nbsp; &nbsp; bar<br>} ];<br> &nbsp; <br>use Class {<br>&nbsp; &nbsp; foo =&gt; 'ro',<br>&nbsp; &nbsp; bar =&gt; 'rw',<br>};</tt></p></div> </blockquote><p>No matter how you try, there's always an inherent additional element of complexity that results from the split between them.</p><p>And so the decision to go with all-readonly in Object::Tiny is a combination of these two issues.</p><p>If went with all-readwrite, I'm practically encouraging bad behaviour and more bugs. If I went with mixed accessors, the API would remain relative complex.</p><p>In the end, the best way to achieve both API simplicity and code safety is to only provide read-only accessors, and anything more complex should require both though and effort.</p> Alias 2010-08-15T01:39:50+00:00 journal use Perl; http://use.perl.org/~pudge/journal/40493?from=rss <p>I am no longer working for Slashdot/Geeknet as of September 30. I am actively seeking new employment. Unless you want to hire me, you don't need to care, unless you also care about <a href="http://use.perl.org/">use Perl;</a>, because it has been generously hosted by Geeknet since I started the site over 10 years ago, shortly after I was hired by Andover.Net to work on Slashdot.</p><p>Long story short, I have not done much with the site in recent years, so my options at this point are to do nothing; migrate the site to a new server and keep it running as-is; or take the data and do something with it on a new site. Or something I haven't thought of.</p><p>I am hereby accepting proposals for what to do with use Perl;. In short, I would like to donate it to someone who will give it a good home. If you're interested, give me your best pitch.</p><p>Cross-posted on <a href="http://pudge.net/glob/2010/08/use-perl.html">&lt;pudge/*&gt;</a>.</p> pudge 2010-08-11T23:34:11+00:00 journal Matt Trout, aka mst, is insane http://use.perl.org/~pudge/journal/40492?from=rss <p>Wow. I occasionally, but not too often, go into #perl. Very busy with family and life. So I go in today, and for no reason, <a href="http://www.trout.me.uk/">mst</a> bans me and tells me to not come back.</p><p>What's up with him being such an irrational dick?</p> pudge 2010-08-11T16:41:54+00:00 journal Test::Builder2::Design http://use.perl.org/~schwern/journal/40487?from=rss <p>In an effort to shed some light on what Test::Builder2 is about, I took a few hours and performed a brain dump about its goals and design. You can see the result in the new <a href="http://github.com/schwern/test-more/blob/Test-Builder2/lib/Test/Builder2/Design.pod">Test::Builder2::Design</a> document.</p><p>The key design goals are 1) that it has to work, 2) that it has to work everywhere and 3) that it has to test everything. This throws out a lot of 98% solutions.</p> schwern 2010-08-10T02:31:05+00:00 journal Trailer Theory - Reinvented for Ignite Sydney as Economics http://use.perl.org/~Alias/journal/40480?from=rss <p>Back in 2005 in <a href="http://use.perl.org/~Alias/journal/23820">only my fifth use.perl post ever</a>, I outlined an idea I had been developing for a couple of years that I called "Trailer Theory".</p><p>A few years ago on my Portable Perl world hack'a'tour, I took with me a lightning talk version of the concept. It was a pretty crude talk but was received, it seemed, fairly well by the development community.</p><p>Since that trip, and inspired by the unexpected conversion of my "Perl is unparsable" claims in the PPI docs into a formal mathematical proof (complete with "Kennedy's Lemma") I've been wondering if this "Trailer Theory" idea could really be developed as a proper scientific proof, and if so what would that look like.</p><p>A couple of months ago I presented a new version of the talk at Ignite Sydney, speaking to an mixed audience of Twitterati, social media, advertising and journalist types.</p><p>I've rebuilt the talk from scratch and tried to outline the same idea, but in the form of a kind of layman's Economics Proof.</p><p>I hope you enjoy the result.</p><p><a href="http://igniteshow.com/videos/using-economics-make-movies-suck-less">Adam Kennedy - Using Economics to make movies suck less</a></p><p><i><br>Notes for other speakers:</i></p><p><i>1. Ignite advances slides every 15 seconds, no clickers allowed. This turns out to take a shitload of practice to get right.</i></p><p><i>2. When someone says to you "Here's your mark, you need to stay on this line to be in the fixed spot" it helps to pay attention. FAIL<nobr> <wbr></nobr>:)<br></i></p> Alias 2010-08-04T05:40:53+00:00 journal Protesting the Moose with sugary alternatives http://use.perl.org/~Alias/journal/40477?from=rss <p>At work, we've been experimenting with Moose because in our enormous and complex codebase we think we can probably benefit a lot from the extra rigour that it brings.</p><p>Before I continue, let me note that ours is a typical mod_perl enterprise setup with 6gig of memory per machine, so any memory consumed before the Apache fork is essentially free.</p><p>So none of the issues people (including me) have with startup code and memory consumption apply in this case, and I won't be addressing performance issues in this post.</p><p>The consensus of the half-dozen people at work is how Moose tries to look like a declarative extension, but doesn't actually act like it.</p><p>The following is what Moose seems to have been aiming for.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use Moose;<br> &nbsp; <br>extends 'Bar';<br>with&nbsp; &nbsp; 'Role1';<br>with&nbsp; &nbsp; 'Role2';<br> &nbsp; <br>has this =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>has that =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>Unfortunately, this is what we've had to do instead.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use Moose;<br> &nbsp; <br>BEGIN { # When we use Catalyst<br>&nbsp; &nbsp; extends 'Bar';<br>}<br> &nbsp; <br>has this =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>has that =&gt; (<br>&nbsp; &nbsp; is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa =&gt; 'Str',<br>);<br> &nbsp; <br>with&nbsp; &nbsp; 'Role1';<br>with&nbsp; &nbsp; 'Role2';<br>no Moose;<br>__PACKAGE-&gt;meta-&gt;make_immutable;</tt></p></div> </blockquote><p>This "real Moose" code totally spoils the dream of what we felt like we were going to get when we started to play with it.</p><p>Most of our current options for fixing this amount to either.</p><p>a) Add this extra dependency that will unscrew one of the other of the problems (namespace::autoclean)</p><p>b) Use this SECOND heavy sugar layer on top of the FIRST sugar layer, on top of Class::MOP.</p><p>Is fixing the syntax or writing light weight sugar really so hard?</p><p>As a kind of protest, I tried it for myself and managed to create <a href="http://search.cpan.org/perldoc?MooseX::Atom">MooseX::Atom</a>.</p><p>This still has some flaws, but the current equivalent of the above would just be this.</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use MooseX::Atom [<br>&nbsp; &nbsp; extends =&gt; 'Bar',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; 'Role1',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; 'Role2',<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isa =&gt; 'Str',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;),<br>&nbsp; &nbsp; ],<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;that =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;is&nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isa =&gt; 'Str',<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;),<br>&nbsp; &nbsp; ]<br>];<br> &nbsp; <br>1;</tt></p></div> </blockquote><p>You can do the same thing for roles with <a href="http://search.cpan.org/perldoc?MooseX::Role::Atom">MooseX::Role::Atom</a>.</p><p>Now clearly, this might have some issues. It's the work of an hour and not a whole lot of thought.</p><p>But it's still light and clean, with all the class spec in one place up the top where people are used to seeing the declarative stuff in Perl modules.</p><p>Perhaps something like this might be a little better...</p><blockquote><div><p> <tt>package Foo;<br> &nbsp; <br>use MooseX::Hash {<br>&nbsp; &nbsp; extends =&gt; 'Bar',<br>&nbsp; &nbsp; with&nbsp; &nbsp; =&gt; [ 'Role1', 'Role2' ],<br>&nbsp; &nbsp; default =&gt; { is =&gt; 'ro' },<br>&nbsp; &nbsp; has&nbsp; &nbsp; &nbsp;=&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; this =&gt; { isa =&gt; 'Str' },<br>&nbsp; &nbsp; &nbsp; &nbsp; that =&gt; { isa =&gt; 'Str' },<br>&nbsp; &nbsp; },<br>);<br> &nbsp; <br>1;</tt></p></div> </blockquote> Alias 2010-08-03T05:09:02+00:00 journal Method::Signatures returns! 5.12, func() and fast! http://use.perl.org/~schwern/journal/40474?from=rss <p>Chip submitted a minor performance patch to Method::Signatures today. That drove me to push out <a href="http://github.com/schwern/method-signatures/blob/v20100730/Changes">a new release</a> making it friendly to 5.12 and adding func() for non methods!</p><p> &nbsp; &nbsp; &nbsp; &nbsp; func hello(:$greeting = "Hello",<nobr> <wbr></nobr>:$place = "World") {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print "$greeting, $place!\n";<br> &nbsp; &nbsp; &nbsp; &nbsp; }</p><p> &nbsp; &nbsp; &nbsp; &nbsp; hello( place =&gt; "Earth" );</p><p>For those who don't know, one of the neato features of <a href="http://search.cpan.org/perldoc?Method::Signatures">Method::Signatures</a> is that it can <a href="http://search.cpan.org/~mschwern/Method-Signatures-20090620/lib/Method/Signatures.pm#Aliased_references">alias references</a> to make working with references less of a trial:</p><p> &nbsp; &nbsp; &nbsp; &nbsp; func popn(\@array, $howmany) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return splice @array, -$howmany;<br> &nbsp; &nbsp; &nbsp; &nbsp; }</p><p> &nbsp; &nbsp; &nbsp; &nbsp; my @stuff = (1,2,3,4,5);<br> &nbsp; &nbsp; &nbsp; &nbsp; my @last_three = popn(\@stuff, 3); # 3,4,5<br> &nbsp; &nbsp; &nbsp; &nbsp; print @last_three;</p><p>It does this with the amazing <a href="http://search.cpan.org/perldoc?Data::Alias">Data::Alias</a> module. Unfortunately, 5.12 broke its black magic and its non-trivial to fix. Method::Signatures now makes Devel::Alias an optional dependency. If its available, it'll use it. Otherwise, no aliasing for you.</p><p>But that's ok, because perl5i makes working with references enjoyable. And while perl5i is adding its own simple signatures, they're forward compatible with Method::Signatures! They play together, so if you want perl5i and the full power of Method::Signatures you can have them.</p><p> &nbsp; &nbsp; &nbsp; &nbsp; use perl5i::2;<br> &nbsp; &nbsp; &nbsp; &nbsp; use Method::Signatures;</p><p> &nbsp; &nbsp; &nbsp; &nbsp; func echo($message is ro) {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; say $message;<br> &nbsp; &nbsp; &nbsp; &nbsp; }</p><p>Just make sure you load MS after perl5i. The last one loaded wins.</p><p>Finally, I was comparing Method::Signatures with MooseX::Method::Signatures and made a disturbing discovery. I always new MooseX::Method::Signatures would have a performance penalty, it does more checks than Method::Signatures, I just didn't realize how bad it was.</p><p>Here's comparing an empty signature: <code>method foo() {}</code>.</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Rate&nbsp; &nbsp; MMS&nbsp; &nbsp; &nbsp;MS&nbsp; &nbsp; Std<br>MMS&nbsp; &nbsp; 3207/s&nbsp; &nbsp; &nbsp;--&nbsp; -100%&nbsp; -100%<br>MS&nbsp; 1498875/s 46644%&nbsp; &nbsp; &nbsp;--&nbsp; &nbsp; -1%<br>Std 1508351/s 46940%&nbsp; &nbsp; &nbsp;1%&nbsp; &nbsp; &nbsp;--</tt></p></div> </blockquote><p>That's showing MooseX::Method::Signatures is 450x slower than either Method::Signatures or a normal method call creaking out a mere 3500 method calls per second as compared to the 1.5 million it should be doing. And that's for a method with an empty signature!</p><p>To be clear, that's the speed of calling a method, not compiling them.</p><p>Here's one comparing a simple signature that requires a check, so MS can't optimize it away: <code>method foo($arg!) { return $arg + 1 }</code> That's a required positional argument.</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Rate&nbsp; &nbsp; MMS&nbsp; &nbsp; &nbsp;MS&nbsp; &nbsp; Std<br>MMS&nbsp; &nbsp; 2928/s&nbsp; &nbsp; &nbsp;--&nbsp; -100%&nbsp; -100%<br>MS&nbsp; &nbsp;983127/s 33481%&nbsp; &nbsp; &nbsp;--&nbsp; &nbsp; -2%<br>Std 1005357/s 34240%&nbsp; &nbsp; &nbsp;2%&nbsp; &nbsp; &nbsp;--</tt></p></div> </blockquote><p>3000 method calls instead of a million.</p><p>Now I'm the first to counter arguments bemoaning method call overhead. Usually it doesn't matter. Usually the extra cost of calling a method and checking arguments is insignificant compared to what that method actually does. And MooseX::Method::Signatures has features Method::Signatures does not, most significantly type checking. But my god! Three orders of magnitude of performance lost! And its not even using the extra MMS features. That's just too much.</p> schwern 2010-07-31T00:49:55+00:00 journal Perl 6 Is The Language Your Language Could Smell Like http://use.perl.org/~schwern/journal/40472?from=rss <p><a href="http://www.youtube.com/watch?v=owGykVbfgUE">Hello programmers</a>. Look at your code, now at Perl 6, now back at your code, now back at Perl 6! Sadly, your code is not written in Perl 6. But if you use <a href="http://rakudo.org/announce/rakudo-star/2010.07">Rakudo Star</a> then Perl 6 is the language your code could be written in!</p><p><a href="http://github.com/rakudo/star/downloads">Now Microsoft scented!</a></p> schwern 2010-07-29T19:24:09+00:00 journal Stupid Lucene Tricks: Document Frequencies and NOT http://use.perl.org/~Mark+Leighton+Fisher/journal/40471?from=rss <ol> <li>You can get the document frequency of a term (i.e. how many documents have that term) through <b>Lucene.Index.IndexReader.DocFreq(t As Term) As Integer</b>.</li><li>You can get the <b>IndexReader</b> for a <b>Lucene.Search.IndexSearcher</b> through <b>IndexSearcher.GetIndexReader()</b>.</li><li>If you want to display the document frequencies for the individual keywords of a search, and a piece is a NOT phrase (like <i>-antibiotic</i> in <i>antimicrobial -antibiotic</i>), you cannot use <b>DocFreq()</b> directly. In that case, the document frequency can be computed as:<blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; DOCFREQ = count of all documents - DocFreq(TERM_NO_NOT)</tt></p></div> </blockquote><p>as in:</p><blockquote><div><p> <tt>&nbsp; &nbsp; &nbsp; DOCFREQ = 60227 - DocFreq(New Term("all", "antibiotic"))</tt></p></div> </blockquote><p> where the NOT piece was <i>-antibiotic</i> and <b>all</b> is the Lucene document field in question.</p></li></ol><p> <i>(Ob. Perl: Although PLucene is now 5 years out of date, <a href="http://code.google.com/p/csmeta/">Perlesque</a> should eventually let you get at Lucene.NET via a strongly-typed Perl 6.)</i> </p> Mark Leighton Fisher 2010-07-29T16:13:30+00:00 others Help? http://use.perl.org/~Alias/journal/40470?from=rss <p>(Before I begin, I should clarify I did not write this code, I'm just trying to maintain it)</p><p>The following error is the first thing spat out by make test for the Padre sync server, located at <a href="http://svn.perlide.org/padre/trunk/Madre-Sync">http://svn.perlide.org/padre/trunk/Madre-Sync</a>.</p><p>Wasn't the move of Catalyst to Moose going to make things easier?</p><p>Can someone explain how you debug this?</p><p>I get the basics, I can see the "Can't locate Madre/Sync/Schema.pm". But that file should be, I think, automatically generated. And I don't really get how to dig down the 75 caller levels from the start to the end to work out where the actual functionality is failing...</p><blockquote><div><p> <tt>not ok 1 - use Catalyst::Test;<br> &nbsp; <br>#&nbsp; &nbsp;Failed test 'use Catalyst::Test;'<br>#&nbsp; &nbsp;at t\01app.t line 7.<br>#&nbsp; &nbsp; &nbsp;Tried to use 'Catalyst::Test'.<br>#&nbsp; &nbsp; &nbsp;Error:&nbsp; Couldn't load class (Madre::Sync) because: Couldn't instantiate component "Madre::Sync::Model::padreDB", "Can't locate Madre/Sync/Schema.pm i<br>n @INC (@INC contains: blib\lib blib\arch C:/strawberry/perl/lib C:/strawberry/perl/site/lib C:\strawberry\perl\vendor\lib<nobr> <wbr></nobr>.). at C:\strawberry\perl\vendor<br>\lib/Class/MOP.pm line 132<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Catalyst/Model/DBIC/Schema/Types.pm line 21<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::Types::__ANON__[C:\strawberry\perl\vendor\lib/C<nobr>a<wbr></nobr> talyst/Model/DBIC/Schema/Types.pm:21]('Madre::Sync::Schema') called<br>at C:\strawberry\perl\vendor\lib/Moose/Meta/TypeCoercion.pm line 63<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeCoercion::__ANON__[C:\strawberry\perl\vendor\lib/Moose/Meta/T<nobr>y<wbr></nobr> peCoercion.pm:67]('Madre::Sync::Schema') called at C:\strawberry\per<br>l\vendor\lib/Moose/Meta/TypeCoercion.pm line 97<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeCoercion::coerce('Moose::Meta::TypeCoercion=HASH(0x4a2b444)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/Moose<br>/Meta/TypeConstraint.pm line 90<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::TypeConstraint::coerce('Moose::Meta::TypeConstraint=HASH(0x4a2985<nobr>4<wbr></nobr> )', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\lib/M<br>ooseX/Types/TypeDecorator.pm line 206<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 205<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a<nobr>3<wbr></nobr> 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l<br>ib/Moose/Meta/Attribute.pm line 743<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b46<nobr>7<wbr></nobr> fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db<br>7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(<nobr>0<wbr></nobr> x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M<br>odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C<br>lass.pm line 540<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm<br>line 256<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin<br>e 25<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/<br>Traits/Pluggable.pm line 131<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen<br>t/Traits.pm line 146<br>#&nbsp; &nbsp; &nbsp; &nbsp;CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl<br>ass/MOP/Method/Wrapped.pm line 48<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '<br>HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C<br>atalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven<br>dor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62<br>#&nbsp; &nbsp; &nbsp; &nbsp;require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7<br>#&nbsp; at C:\strawberry\perl\vendor\lib/MooseX/Types/TypeDecorator.pm line 208<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Types::TypeDecorator::AUTOLOAD('MooseX::Types::TypeDecorator=HASH(0x4a<nobr>3<wbr></nobr> 1424)', 'Madre::Sync::Schema') called at C:\strawberry\perl\vendor\l<br>ib/Moose/Meta/Attribute.pm line 743<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::_coerce_and_verify('Moose::Meta::Attribute=HASH(0x4b46<nobr>7<wbr></nobr> fc)', 'Madre::Sync::Schema', 'Madre::Sync::Model::padreDB=HASH(0x4db<br>7c64)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Attribute.pm line 398<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Attribute::initialize_instance_slot('Moose::Meta::Attribute=HASH(<nobr>0<wbr></nobr> x4b467fc)', 'Moose::Meta::Instance=HASH(0x4db7ed4)', 'Madre::Sync::M<br>odel::padreDB=HASH(0x4db7c64)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Class.pm line 567<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::_construct_instance('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Class/MOP/C<br>lass.pm line 540<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Meta/Class.pm<br>line 256<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Meta::Class::new_object('Moose::Meta::Class=HASH(0x4942ffc)', 'HASH(0x4db53ac)') called at C:\strawberry\perl\vendor\lib/Moose/Object.pm lin<br>e 25<br>#&nbsp; &nbsp; &nbsp; &nbsp;Moose::Object::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at generated method (unknown origin) line 4<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::new('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4b404ec)') called at C:\strawberry\perl\vendor\lib/MooseX/<br>Traits/Pluggable.pm line 131<br>#&nbsp; &nbsp; &nbsp; &nbsp;MooseX::Traits::Pluggable::new_with_traits('Madre::Sync::Model::padreDB', 'Madre::Sync') called at C:\strawberry\perl\vendor\lib/CatalystX/Componen<br>t/Traits.pm line 146<br>#&nbsp; &nbsp; &nbsp; &nbsp;CatalystX::Component::Traits::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Cl<br>ass/MOP/Method/Wrapped.pm line 48<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:49]('Madre::Sync::Model::padreDB', 'Madre::Sync', '<br>HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Model::DBIC::Schema::COMPONENT('Madre::Sync::Model::padreDB', 'Madre::Sync', 'HASH(0x4c6b93c)') called at C:\strawberry\perl\vendor\lib/C<br>atalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2502<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_component('Madre::Sync', 'Madre::Sync::Model::padreDB') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 2416<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP/Method/Wrapped.pm line 54<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::Method::Wrapped::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP/<nobr>M<wbr></nobr> ethod/Wrapped.pm:64]('Madre::Sync') called at C:\strawberry\perl\ven<br>dor\lib/Class/MOP/Method/Wrapped.pm line 89<br>#&nbsp; &nbsp; &nbsp; &nbsp;Madre::Sync::setup_components('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst.pm line 1142<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::setup('Madre::Sync') called at blib\lib/Madre/Sync.pm line 62<br>#&nbsp; &nbsp; &nbsp; &nbsp;require Madre/Sync.pm called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 114<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:118]() called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 74<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 67<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at blib\lib/Madre/Sync.pm line 0<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7"Compilation failed in require at C:\strawberry\perl\vendor\lib/Class<br>/MOP.pm line 114.<br>#&nbsp; at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 121<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::__ANON__[C:\strawberry\perl\vendor\lib/Class/MOP.pm:125]('Couldn\'<nobr>t<wbr></nobr> instantiate component "Madre::Sync::Model::padreDB"...') called at<br>C:\strawberry\perl\vendor\lib/Try/Tiny.pm line 98<br>#&nbsp; &nbsp; &nbsp; &nbsp;Try::Tiny::try('CODE(0x36d759c)', 'Try::Tiny::Catch=REF(0x33a9584)') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 125<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_first_existing_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Class/MOP.pm line 137<br>#&nbsp; &nbsp; &nbsp; &nbsp;Class::MOP::load_class('Madre::Sync') called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 24<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::__ANON__[C:\strawberry\perl\vendor\lib/Catalyst/Test.pm:93]('C<nobr>a<wbr></nobr> talyst::Test', 'all', 'HASH(0x36d768c)', 'HASH(0x25de3a4)') called a<br>t C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 493<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_group('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d4994)', 'HASH(0x25de3a4)', 'HASH(0x36d755c)', 'HASH(0x25de334)') call<br>ed at C:\strawberry\perl\vendor\lib/Sub/Exporter.pm line 424<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::_expand_groups('Catalyst::Test', 'HASH(0x36d4ce4)', 'ARRAY(0x36d723c)', 'HASH(0x25de3a4)') called at C:\strawberry\perl\vendor\lib/S<br>ub/Exporter.pm line 742<br>#&nbsp; &nbsp; &nbsp; &nbsp;Sub::Exporter::__ANON__[C:\strawberry\perl\vendor\lib/Sub/Exporter.pm:756]('Ca<nobr>t<wbr></nobr> alyst::Test', '-all', 'HASH(0x36cc8d4)') called at C:\strawberry\per<br>l\vendor\lib/Catalyst/Test.pm line 112<br>#&nbsp; &nbsp; &nbsp; &nbsp;Catalyst::Test::import('Catalyst::Test', 'Madre::Sync') called at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;main::BEGIN() called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval {...} called at C:\strawberry\perl\vendor\lib/Catalyst/Test.pm line 2<br>#&nbsp; &nbsp; &nbsp; &nbsp;eval 'package main;<br># use Catalyst::Test @{$args[0]};<br># 1;<br>#<br>#<nobr> <wbr></nobr>;' called at C:/strawberry/perl/lib/Test/More.pm line 858<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::_eval('package main;\x{a}use Catalyst::Test @{$args[0]};\x{a}1;\x{a}', 'ARRAY(0x2308474)') called at C:/strawberry/perl/lib/Test/More.p<br>m line 833<br>#&nbsp; &nbsp; &nbsp; &nbsp;Test::More::use_ok('Catalyst::Test', 'Madre::Sync') called at t\01app.t line 7<br># BEGIN failed--compilation aborted at (eval 11)[C:/strawberry/perl/lib/Test/More.pm:858] line 2.</tt></p></div> </blockquote> Alias 2010-07-29T13:23:44+00:00 journal Some you win, some you loose http://use.perl.org/~nicholas/journal/40467?from=rss <p>So, my attempt to avoid <a href="http://www.lightbluetouchpaper.org/2010/01/26/how-online-card-security-fails/">3D Secure</a> was successful, but seems to have had the unintended side effect that I <a href="http://conferences.yapceurope.org/ye2010/news/616">sold my soul for 3 days</a>.</p><p>I feel that I have to categorically deny that my product roadmap is in doubt, and that the rumours of forking me to regain control are completely unfounded, and unworthy of any further comment.<nobr> <wbr></nobr>:-)</p><p>See you all at <a href="http://conferences.yapceurope.org/ye2010/">YAPC::Europe</a> next week. Right now, there's <a href="http://conferences.yapceurope.org/ye2010/news/617">another free ticket up for grabs</a>, thanks to <a href="http://www.shadowcat.co.uk/">Shadowcat</a>.</p> nicholas 2010-07-28T19:50:24+00:00 journal Desperate Perl; or A Tale of Two Languages http://use.perl.org/~Mark+Leighton+Fisher/journal/40463?from=rss <p>Piers Cawley's <a href="http://www.bofh.org.uk/2010/07/25/a-tale-of-two-languages">A tale of two languages</a> (if you haven't already seen it) speaks to the public perception that Perl remains a desperation language ("Desperate Perl") suited only for gluing things together when nothing else will do.</p><p>Meanwhile elsewhere in the real world, there is plenty (possibly a majority IMHO) of maintainable, understandable, well-written, efficient Perl code ("Large Scale Perl" as described by Piers). Worth a read.</p><p> <i>(Although I like the name "Desperate Perl" a lot, I think that the names "Scripting Perl" and "Programming Perl" also describe these separate Perl programming styles in a less-emotional fashion (which is occasionally useful.))</i> </p> Mark Leighton Fisher 2010-07-27T17:25:47+00:00 links Strawberry Perl install rolled back http://use.perl.org/~jdavidb/journal/40462?from=rss <p>Strawberry Perl 5.12.0 was almost completely installed when suddenly it flashed some message I didn't see into the install wizard and the progress bars started moving backward! I have never seen anything like it. I realized the progress bar caption had been changed to simply "Rolling Back Action" and watched as at least three anonymous "actions" were rolled back, progress bar by progress bar. Then the install wizard simply told me "Strawberry Perl Setup Wizard ended prematurely Strawberry Perl Setup Wizard ended prematurely because of an error. Your system has not been modified. To install this program at a later time, run Setup Wizard again. Click the Finish button to exit the Setup Wizard."</p><p>I wish it would tell me what the error was so I might have some hope of correcting it.</p> jdavidb 2010-07-26T20:34:33+00:00 journal For people running Perl conferences http://use.perl.org/~Alias/journal/40461?from=rss <p>Leo Lapworth comments in <a href="http://blogs.perl.org/users/leo_lapworth/2010/07/for-speakers-at-perl-conferences.html">"For speakers at Perl conferences"</a> that you should record your own talks at conferences, because organisers cannot be trusted to release the videos they take of you.</p><p>I wholeheartedly agree. I've spoken at numerous conferences, including several large ones, and only in about 10-20% of cases have the videos of me EVER appeared.</p><p>I'm amazed that conference organisers can put in so much effort into recording (dozens of tapes, multiple cameras, multiple operators) and then never produce anything as a result.</p><p>The only time I'm aware of that a full talk of mine has appeared online was at a Linux.conf.au, who had a dedicated video team of eight people.</p><p>Where is all this footage, and why does it never get processed? Why even bother recording it? If you don't have time, send me the raw tape of my own talk and I will do it myself if needed.</p><p>YAPC::NA? You listening?</p> Alias 2010-07-25T12:55:04+00:00 journal A reminder - Padre Second Birthday Hackathon this weekend http://use.perl.org/~Alias/journal/40460?from=rss <p>This is just a quick reminder that this weekend is the Padre's second birthday party and hackathon.</p><p>If you are a Padre user, please drop in and say hello to the team. We'd love to hear how you are using Padre and where your main needs are for the next year.</p><p>If you are interested in trying out Padre for the first time, or trying your hand at improving it for the first time, it's a great time to get started because we'll have plenty of people around to provide guidance and advice.</p><p>Some of the plans for this weekend are to bring all the plugins up to date with the latest versions of the plugin API, to start the merge of the ConfigSync branch, and if we can, to start on the Madre server that will serve as the ConfigSync and Telemetry server for Padre.</p><p>I look forward to seeing you there!</p> Alias 2010-07-23T03:53:28+00:00 journal Profiling your website while live on a production cluster http://use.perl.org/~Alias/journal/40457?from=rss <p>As I mentioned in my last post, by day I wrangle a large web application that occasionally verges on being too complex to for mere humans to understand.</p><p>Curiously, because it is private and the income rate is high (we probably average something like $5 in gross turnover per page view) we don't have to deal with a lot of servers to deliver it, by internet standards anyway.</p><p>But the application is still way too big to profile easily by normal methods, and certainly on production it's way too heavy, even if we applied targeted profiling using something like <a href="http://search.cpan.org/perldoc?Aspect::Library::NYTProf">Aspect::Library::NYTProf</a>.</p><p>Between the web servers, transaction server, database, search engine and cache server, we are probably only dealing with 12 servers and 30 CPUs. Of course, these servers are all horribly expensive, because they are all server-virtualised, network-virtualised, doubly redundant (high-availability + disaster-recovery) and heavily monitored with high end support contracts.</p><p>One of our most sensitive issues is database load.</p><p>We have a ton of database tables (about 200) and lots of medium sized queries running across them. One of our main failure modes is that some deep change to code boosts the quantity of some significant query, which stresses the database enough to cause contention and lock-storms, leading to site failure.</p><p>Complicating things, big parts of some pages are embedded in other pages. So attributing load and lag to one part of the website, or to Oracle, is tricky and hard to benchmark in advance (although we do load test the main load paths to catch the worst cases).</p><p>For a long time, we've had a mechanism for zoned profiling the production site, so we can allocate wallclock costs to different general areas of the site.</p><p>But it is fragile and unreliable, requiring perfect maintenance and every developer to remember to write this kind of thing everywhere.</p><blockquote><div><p> <tt># Embed a foo widget in the current page<br>$perf-&gt;push_timing('foo');<br>foo($bar);<br>$perf-&gt;pop_timing;</tt></p></div> </blockquote><p>Since you don't know this profiling system exists unless you've seen it somewhere else in the code before, and it's hard to care about something that is orthogonal to the problem you are actuall solving, this mechanism has degraded over time. While we still get some pretty cacti graphs showing load breakdown, they are highly unreliable and you can never be entirely sure if the load attribution is correct.</p><p>This kind of performance monitoring as a "cross-cutting concern" is a textbook use case for Aspect-Oriented Programming, and so in our Christmas 2009 code freeze window I set about trying to rewrite the push/pop_timing profiler using <a href="http://search.cpan.org/perldoc?Aspect">Aspect.pm</a>.</p><p>Unfortunately, Aspect.pm turned out to be a bit too slow and naive for my needs. But after a 6 month delay to do a 90% rewrite of Aspect.pm, I now finally have something sophisticated enough (and fast enough) to meet my needs.</p><p>So today I'm releasing the shiny new <a href="http://search.cpan.org/perldoc?Aspect::Library::ZoneTimer">Aspect::Library::ZoneTimer</a>, which will serve as the main plank of our new production profiling system.</p><p>The idea behind ZoneTimer is to define each performance zone as a pointcut. The aspect will track the movement of your code across each zone boundaries and build a running total of the exclusive time spent in each performance zone.</p><p>When your program exits the top-most performance zone, the totals will be sent to a handler function.</p><p>A typical use of the ZoneTimer aspect looks something like this</p><blockquote><div><p> <tt>use Aspect;<br> &nbsp; <br>aspect ZoneTimer =&gt; (<br>&nbsp; &nbsp; zones =&gt; {<br>&nbsp; &nbsp; &nbsp; &nbsp; main&nbsp; &nbsp; &nbsp; =&gt; call 'MyProgram::main' &amp; highest,<br>&nbsp; &nbsp; &nbsp; &nbsp; search&nbsp; &nbsp; =&gt; call 'MyProgram::search',<br>&nbsp; &nbsp; &nbsp; &nbsp; widgets&nbsp; &nbsp;=&gt; call qr/^MyProgram::widget_.*/,<br>&nbsp; &nbsp; &nbsp; &nbsp; templates =&gt; call 'MyProgram::render',<br>&nbsp; &nbsp; &nbsp; &nbsp; dbi&nbsp; &nbsp; &nbsp; &nbsp;=&gt; call qr/^DB[DI]::.*?\b(?:prepare|execute|fetch.*)$/,<br>&nbsp; &nbsp; &nbsp; &nbsp; system&nbsp; &nbsp; =&gt; (<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call qr/^IPC::System::Simple::(?:run|runx|capture)/<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call 'IPC::Run3::run3'<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call qr/^Capture::Tiny::(?:capture|tee).*/<br>&nbsp; &nbsp; &nbsp; &nbsp; )<br>&nbsp; &nbsp; },<br>&nbsp; &nbsp; handler =&gt; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; my $top&nbsp; &nbsp; &nbsp; &nbsp;= shift; # "main"<br>&nbsp; &nbsp; &nbsp; &nbsp; my $start&nbsp; &nbsp; &nbsp;= shift; # [ 1279763446, 796875 ]<br>&nbsp; &nbsp; &nbsp; &nbsp; my $stop&nbsp; &nbsp; &nbsp; = shift; # [ 1279763473, 163153 ]<br>&nbsp; &nbsp; &nbsp; &nbsp; my $exclusive = shift; # { main =&gt; 23123412, dbi =&gt; 3231231 }<br> &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; print "Profiling from zone $top\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; print "Started recording at " . scalar(localtime $start) . "\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; print "Stopped recording at " . scalar(localtime $stop)&nbsp; . "\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; foreach my $zone ( sort keys %$exclusive ) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print "Spent $exclusive-&gt;{$zone} microseconds in zone $zone\n";<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; },<br>);</tt></p></div> </blockquote><p>This example breaks out the cost of a typical small web application into a general zone, a special zone for the search page, and then splits the costs of generating widgets, rendering the HTML template, waiting for the database, and making calls to the underlying system.</p><p>Start and stop times are returned as a two element array exactly as returned by C, and the exclusive zone totals are returned as integer microseconds (all math is done in these integer microseconds to prevent floating point corruption).</p><p>The use of Aspect allows us to easily mix special cases via the pointcuts, such as the use of "highest" which makes sure that "main" only matches the first time it is seen, and any widget which that does a re-entry into main still has that cost attributed to the widget. We've also hooked into multiple system call modules to measure system call cost, because we know different modules our program consumes will use different methods for interacting with the system.</p><p>While the handler I've shown here will just print out a summary of the call, in our environment at work the profile report handler will format the exclusive times into a special log message and then send it via the super-quick and non-blocking <a href="http://search.cpan.org/perldoc?Log::Syslog::Fast">Log::Syslog::Fast</a> module to the UDP localhost syslog service, where it is mirrored to disk for debugging use, and then forwarded on to our main company-wide syslog server.</p><p>On our setup, we can then use an excellent commercial log analysis product called <a href="http://www.splunk.com/">Splunk</a> (limited free version also available if you want to try it out) to do our tracking and trending of the performance for the entire application across the entire cluster.</p><p>The nicest thing about the Aspect system is that it scales the performance cost and complexity risk directly to the complexity of the use case you are using it for.</p><p>If it turns out that the Aspect hooks are too intrusive and causing a performance drain, or accidentally causing some weird edge case behaviour, you can simply turn off that the Aspect and restart the servers and the performance penalty just vanishes.</p><p>Maintenance of the profiler zones is really easy, because they are all listed clearly in one place.</p><p>Depending on your use case, you could even define the performance zones in your website configuration, and then adjust the profiler zone boundaries directly on production (although I'm not sure I'd want to do that in our specific case, since we're fairly paranoid about untested code going into production).</p><p>This ZoneTimer is just the first of several Aspect-based tools I plan to release over the next few months. If you get a chance to try out any of these new toys, I'd love to hear feedback on how well they work for you.</p><p>In addition to the value of the ZoneTimer aspect itself, one other thing that some people might find of interest is just how little code it took to get this all working.</p><p>The entire Aspect::Library::ZoneTimer was implemented in about 80 lines of code, which you can see at <a href="http://cpansearch.perl.org/src/ADAMK/Aspect-Library-Timer-0.04/lib/Aspect/Library/ZoneTimer.pm">http://cpansearch.perl.org/src/ADAMK/Aspect-Library-Timer-0.04/lib/Aspect/Libra<nobr>r<wbr></nobr> y/ZoneTimer.pm</a></p><p>This is small enough that you could just clone the module and tweak it for your own use case, if you wanted to creat a new and tricky customised profiler.</p> Alias 2010-07-22T02:27:33+00:00 journal How we deploy massive Perl applications at work http://use.perl.org/~Alias/journal/40453?from=rss <p>Every now and then, we hear people talking about mechanisms for doing Perl in a commercial environment and how they deal with packaging and dependencies.</p><p>This is mine.</p><p>At Corporate Express, our main Perl application is a 250,000 line non-public monster of a website that has over 100,000 physical users and turns over about a billion dollars. It implements huge amounts of complex business functionality, and has layer upon layer of security and reliability functions in it because we supply to multinationals, governments and the military (only the stuff that doesn't blow up of course). Our<nobr> <wbr></nobr>.pm file count is around 750, and our test suite runs for about 4 hours (and is only around one third complete).</p><p>Lest you suspect that 200,000 lines is wasted in re-implementing stuff, the main Build.PL script has around 110 DIRECT dependencies, and somewhere in the 300-500 range of recursive dependencies. Loading the main codebase into memory takes around 150-200meg of RAM.</p><p>When I joined the team, the build system was horribly out of date. The application was stuck on an old version of RedHat due to go out of support, and as a Tier 1 application we are absolutely forbidden from using unsupported platform.</p><p>So I took on the task of upgrading both the operating system and the build system for the project. And it's a build system with a history.</p><p>Once upon a time, long ago, the project went through a period where the development team was exceptionally strong and high skilled. And so of course, they created a roll-your-own build system called "VBuild".</p><p>They built their own Perl, and along with it they also built their own Apache, mod_perl, and half a dozen other things needed by the project. This is similar to many suggestions I hear from high-skilled people today, that at a certain point it's better just to build your own Perl. VBuild this created in the pre-commercial Linux era, so it's not an entirely unreasonable decision for that time period.</p><p>Unfortunately, a few years later the quality of the team dropped off and VBuild turned into a maintenance nightmare because it required a high-skill person to maintain it.</p><p>At the time, the Tier 1 "Must be supported" policy was coming into effect, and after the problems with custom-compiling they decided to go with the completely opposite approach of using only vendor provided packages, in a system called "UnVBuild".</p><p>Since their platform of choice was RedHat, this had become troublesome even before I arrived. Worse, in the change from RHEL 4 to RHEL 5, some of the vendor packages for things like XSLT support were dropped entirely leaving us in a bind.</p><p>My first instinct was to return to the build everything approach, but the stories (and commit commentary) from that time period reinforced the idea that complete custom build was a bad idea. Office supplies is hardly a sexy industry, and the ability to entice good developers into it is a quite legitimate risk.</p><p>So in the end, I went with an approach we ended up nicknaming "HalfBuild". The concept behind it is "Vendor where possible, build where needed".</p><p>We use a fairly reasonable chunk of vendor packages under this model. Perl itself, the Oracle client, XML::LibXML and a variety of other things where our version needs are modest and RHEL5 contains it. We also use a ton of C libraries from RHEL5 that are consumed by the CPAN modules, like all the image libraries needed by Imager, some PDF and Postscript libraries, and so on.</p><p>One RPM "platform-deps" meta-package defines the full list of these system dependencies, and that RPM is maintained exclusively by server operations so that we as developers are cryptographically unable to add major non-Perl dependencies without consulting them first.</p><p>On top of this is one enormous "platform-cpan" RPM package built by the dev team that contains every single CPAN dependency needed by all of our Perl projects.</p><p>This package lives in its own home at<nobr> <wbr></nobr>/opt/cpan and is built using a process rather similar to the core parts of Strawberry Perl. With PREFIX pointing into<nobr> <wbr></nobr>/opt/cpan, we first build a hand-crafted list of distribution tarballs to upgrade RHEL5 to a modern install of CPAN.pm (without overwriting any normal system files).</p><p>We then boot up the CPAN client from<nobr> <wbr></nobr>/opt/cpan, and tell it to install all the rest of the dependencies from a private internal CPAN mirror which is rsynced by hand specifically for each new CPAN build. This ensures that the build process is deterministic, and that we can fix bugs in the build process if we need to without being forced to upgrade the modules themselves).</p><p>The CPAN client grinds away installing for an hour, and then we're left with our "CPAN Layer", which we can include in our application with some simple changes to @INC at the beginning of our bootstrapping module.</p><p>The<nobr> <wbr></nobr>/opt/cpan directory for our project currently weighs in at about 110meg and contains 2,335<nobr> <wbr></nobr>.pm files.</p><p>Updating<nobr> <wbr></nobr>/opt/cpan is still something of an exercise even under this model because of potential upgrade problems (Moose forbidding +attributes in roles hit us on our most recent upgrade) but the whole process is fully automated from end to end, and can be maintained by a medium-skill Perl hacker, rather than needing an uberhacker.</p><p>Over the last 2 years, we've upgraded it around once every 6 months and usually because we needed to add five or ten more dependencies. We tend to add these new dependencies as early as we can, when work that needs them is confirmed but unscheduled.</p><p>We also resort to the occasional hand-copied or inlined pure-Perl<nobr> <wbr></nobr>.pm file in emergencies, but this is temporary and we only do so about once a year when caught unprepared (most recently Text::Unidecode for some "emergency ascii'fication" of data where Unicode had accidentally slipped in).</p><p>While not ideal, we've been quite happy with the<nobr> <wbr></nobr>/opt/cpan approach so far.</p><p>It means we only have to maintain 5 RPM packages rather than 500, and updating it takes one or two man-days per 6 months, if there aren't any API changes in the upgrade.</p><p>And most importantly it provides us with much better bus sensitivity, which is hugely important in applications with working lives measured in decades.</p> Alias 2010-07-20T02:25:21+00:00 journal Hiveminder: personal RT, for free http://use.perl.org/~jdavidb/journal/40452?from=rss <p>You mean someone will provide RT for me to use for free on the web? And they've built an awesome AJAX-y frontend for it? And they allow me to tag tasks and they encourage me to keep my work todo list and as many personal todo lists as I want in here? And they give me awesome search utilities for figuring this out and keeping it organized?</p><p>It's almost like <a href="http://hiveminder.com/">a dream come true</a>.</p> jdavidb 2010-07-19T16:58:36+00:00 journal