For my PDX.pm presentation tonight on Test::Builder2 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.
First, demonstrating end-of-assert actions, there's die on fail but even cooler is DEBUG on fail! That's right, run your test in the debugger and have it automatically set a breakpoint on a failure. How cool is that?
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.
The second is reimplementing Test::NoWarnings safely. TB2::NoWarnings 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.
You can safely use them all together, though its a crap shoot if DebugOnFail or DieOnFail will trigger first.
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.
There's a pile of stuff to be done in TB2, a lot of them are fairly small and self contained. Have a look. Patches welcome.
Here's a diagram of the "flow" of assert results through Test::Builder version 1.
.-------.
| foo.t |
'-------'
|
|
.-------------. | .----------------.
| Test::More |<--------->| Test::Whatever |
'-------------' '----------------'
| |
| |
| |
| .---------------. |
'---->| Test::Builder |<----'
'---------------'
|
v
.-----.
| TAP |
'-----'
|
v
.---------------.
| Test::Harness |
'---------------'
You write foo.t using Test::More and Test::Whatever. These both
use the same Test::Builder object. It spits out TAP which
Test::Harness converts into something human readable.
The big problem there is Test::Builder is monolithic. There's no
further breakdown of responsibilities. It only spits out TAP, and
only one version of TAP.
Here's what Test::Builder2 looks like:
.-------.
.----------------| foo.t |-------------------.
| '-------' |
| | |
| | |
v v v
.------------. .----------------. .------------------.
| Test::More | | Test::Whatever | | Test::NotUpdated |
'------------' '----------------' '------------------'
| | |
| v v
| .----------------. .---------------.
'---------->| Test::Builder2 |<------| Test::Builder |
'----------------' '---------------'
|
v
.--------------..-------------.
| TB2::History |<---| TB2::Result |
'--------------' '-------------'
|
|
.--------------------------. | .---------------------.
| TB2::Formatter::TAP::v13 |<-----'------>| TB2::Formatter::GUI |
'--------------------------' '---------------------'
| |
v |
.-------------------------------. |
| TB2::Formatter::Streamer::TAP | |
'-------------------------------' |
| |
v |
.-----. |
| TAP | |
'-----' |
| |
v v
.---------------. .-----------------.
| Test::Harness | | Pretty Pictures |
'---------------' '-----------------'
It starts out the same, foo.t uses a bunch of test modules
including Test::More and Test::Whatever using the same Test::Builder2
object, but it also uses Test::NotUpdated which is still using
Test::Builder. That's ok because Test::Builder has been rewritten in
terms of Test::Builder2 (more on that below).
Test::Builder2, rather than being a monolith, produces a
Test::Builder2::Result object for each assert run. This gets stored
in a Test::Builder2::History object for possible later use. It also
gets handed to a Test::Builder2::Formatter object, the default is
Test::Builder2::TAP::v13 which produces TAP version 13. This is fed
to a Streamer that prints it to STDOUT and STDERR which is read by
Test::Harness and made human readable.
Because Test::Builder2 is not monolithic, you can swap out parts. For
example, instead of outputting TAP it could instead hand results to a
formatter that produced a simple GUI representation, maybe a green
bar, or something that hooks into a larger GUI. Or maybe one that
produces JUnit XML.
Here's how Test::Builder and Test::Builder2 Relate.
.-----. .-----.
| TB2 | | TB1 |
'-----' '-----'
| |
| |
| |
| |
v v
.-------------. .--------------. .-------------.
| TB2::Result |------->| TB2::History |<--------| TB2::Result |
'-------------' '--------------' '-------------'
| |
| |
| |
|.----------------. |
'------------->| TB2::Formatter |<--------------'
'----------------'
|
v
.--------.
| Output |
'--------'
Test::Builder and Test::Builder2 coordinate their actions by sharing
the same History and Formatter objects. If you call TB1->ok() it
produces a Result object which it hands to the History singleton and
the Formatter singleton. If you call TB2->ok() it produces a Result
object which it hands to the same History and Formatter objects.
This allows most of the Test::Builder code to remain the same while
still coordinating with Test::Builder2. It also allows radically
different builders to be made without Test::Builder2 dictating how
they're to work.
The downside is that roles applied to Test::Builder2 will not effect
Test::Builder. Because of this, Test::Builder may become more closely
coupled with Test::Builder2 in the future.
Diagrams by App::Asciio.
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.
You can get the 1.30_06 release candidate from the CPAN, or from the following URL if your mirror hasn't synced yet.
http://svn.ali.as/cpan/releases/DBD-SQLite-1.30_06.tar.gz
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.
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.
1. BLOB columns with UTF8 content
- Resolved #54271: Inserting a string with utf-8 flag on
corrupts BLOB data; now BLOB data is always stored as bytes
(without the utf-8 flag) even if it has the flag set (ISHIGAKI)
2. FTS3 queries
- Added support for FTS3 tokenizers written in Perl. Added tests
and documentation on how to use FTS3. Changed compilation flag
to use the recommanded -DSQLITE_ENABLE_FTS3_PARENTHESIS
*** MAY POSSIBLY BREAK OLD APPLICATIONS THAT ALREADY USED FTS3 ***
(DAMI)
If you are currently using FTS3, please see DBD::SQLite::FTS3Transitional which contains a helper function for automatically upgrading old FTS3 queries to the new syntax.
See here.
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.
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.
For example, some random author that is trying to checkout a Catalyst project needs:
1. To have Module::Install installed.
2. To have Module::Install::Catalyst installed.
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.
But in the latter case, you're likely to get something like "Unknown command 'catalyst_ignore'", with no real obvious resolution mechanism.
I think this idea of automatic plugin discovery is starting to hit it's limits in terms of clarity.
And so I'd like to do something counter to my natural instincts here, and make M:I more verbose.
I'm thinking of something like the following for explicitly declaring the use of a non-core Module::Install extension.
use inc::Module::Install qw{ Catalyst XSUtil };
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).
Thoughts?
I've had a grant open for Test::Builder2 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.
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 Test::Builder2 Star if you will.
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.
Step one is I'm going to seal up what's there, write docs where they're missing, and release something.
A release before October or the grant dies.
Yesterday, I got my X-Surf 3cc Ethernet card I broke down and ordered for my Amiga 3000. There's some backstory about serial consoles, Sparcs, and the cluster, but it's not important. The 3000 was also packaged as a Unix machine, running a pretty standard port of SysV. It was the first Amiga standard with an MMU and SCSI. It'll also kick out 1280x resolution graphics at 2bpp. Commodore sold an Ethernet board for it along with Unix on tape.
The X-Surf is really an ISA card, probably NE2000, mounted in a little carrier. There are confusingly few pins attached and the logic on the carrier amounts to a few small 7400 series chips and one slightly larger chip that also couldn't possibly have enough logic on it to do what it does. And then just to convince you that your nuts, it adds an IDE port that alone has more lines than the one little adapter chip does. The Amiga really is a machine for psychopaths, by psychopaths. Everyone sits around all of the time trying to out psycho everyone else. Just take a look at the demo scene for the thing. Amiga virtually defined the demo scene.
I have/had Amiga OS 3.9 on the thing. 3.9 is post-Commodore death. Someone bought the rights and sold them and someone bought them and sold them and so on until a sue happy band of self righteous ruffians managed to convince the remaining user base buying the rights at garage sale prices entitled them to be king of the squalid kingdom so that they could go around lynching anyone else trying to do anything for the Amiga. Anyway, OS 3.9 is pretty recent as far as Amiga stuff goes, even though it's ten years old. Most people stopped at 3.1. 3.9 only came out on CD-ROM. The 3000 doesn't have a bay but it does have SCSI, so the CD-ROM, when needed, gets hung off the side with the case open. I could also set up an enclosure and plug it into the back. I could also probably buy one of those.
X-Surf's stuff did not want to install.
X-Surf actually had an installer, which is impressive. AmigaOS 3.x has a scripting language for installers and an interpreter for that. This installer gave you the choice of two TCP stacks. AmigaOS 3.9 comes with a TCP stack but you can still swap it out. It's a bit Windows 3.1-like in that regard. The options are GENESiS/AmiTCP and Miami. GENESiS, the AmiTCP configurerer and dialer that cames with AmiTCP, was shipped in a version requiring libraries not included in AmigaOS3.9 so it wouldn't run. AmiTCP would, and AmiTCP was on the HD, though buried a bit. Miami is shareware/crippleware. It required the same library, MagicUI, that I didn't have.
I spent hours sorting out what required what and what I did and didn't have and how these various packages worked and fit together. That's ignoring the device driver for the ethernet card which is straight forward. The Amiga has a directory for libraries (which end in
Amiga programmers love to do ports of Unix software and add GUIs. They've been doing this for ages. They've had gcc since the early ages of gcc, and I ran the Amylaar MUD driver on AmigaOS 1.3 to do development locally, also in the dark ages. Kicking around on aminet.net from the Amiga, I see PHP, MySQL, Apache, bittorrent, Python, bind9, samba, VNC, and all sorts of stuff. No one ports just the client. If they port the client, they port the server, too. In the case of AmiTCP, the suite of utilities you'd expect are there, such as host, finger, traceroute, and so on, but to configure TCP/IP, you run a little GUI program and it asks you questions. It took Linux ages to get to this point and Amiga was doing it long before. One of the extras on the Extras disc, even as far back as 1.3, was a version of emacs with drop down menus.
Completely unsurprisingly, the 16mhz 68030 processor running AWeb (which does some JavaScript) is vastly faster than firefox on my 1.2ghz Centrino Linux machine. Amiga programmers do not write slow software. It's entirely against their nature. Threading is fantastic. It'll do downloads, render several jpgs in the page, update the page layout as HTML comes across, and never lose snappy UI responsiveness. On firefox, I yank on the scrollbar only to have it ignore me and snap back, or else the scroll bar doesn't move at all, or the whole thing just goes away for a few heart sinking seconds, making me wonder if it just crashed.
My ambition is to get a desk in a shared office space going and stick this baby there with an updated video card that does high res, high bit depth graphics. If I'm willing to start replacing and upgrading chips on the motherboard, I can take the thing up to a gig of RAM, too, and NetBSD supports it if I ever decide I want to see how firefox runs on a 16mhz processor. What I'm really hoping for is someone to take the latest Coldfire chips from Motorola's spin off, Freescale, and do an 800mhz accelerator card for the Amiga 2000/3000/4000. That would RULE.
-scott
On Thursday, August 19, 2010 at 9:30, Flore Louise Apolline Bruhat-Souche was born. She weighs 3.02 kg and measures 48 cm.
Word already spread through IRC (#perlfr and #yapc mostly) and via email and telephone.
The mother is fine, the father is slightly tired and the big sister is happy.
There is one photo online.
I'm a bit behind the times here, but I read today that one of the two remaining developers of IronRuby has left Microsoft:
Overall, I see a serious lack of commitment to IronRuby, and dynamic language on
.NET in general. At the time of my leaving Tomas and myself were the only Microsoft employees working on IronRuby.
http://blog.jimmy.schementi.com/2010/08/start-spreading-news-future-of-jimmy.ht
So if Microsoft's interest in dynamic languages is wilting, and Oracle's litigation scares everyone away from Java, will that leave Parrot as the last one standing?
* yep, that's a formatting bug. I assume that it's not worth reporting while the site's future is unclear.