Just a Theory

Trans rights are human rights

Posts about App::Info

The Main Event

I released a new version of App::Info on Thursday. This is a major new version because I’ve added a new feature: event handling.

Dave Rolsky had raised some issues regarding how App::Info clients might be able to interact with the API in order to confirm the data it has found or to help it find data that it can’t on its own. I had been thinking of App::Info as a non-interactive API on which interactive APIs could be built. In other words, if someone got data from App::Info, but wanted to confirm it via some interface, they would have to write the wrapper code around App::Info to do it.

But I started thinking about the problem, since, as Dave pointed out, such a wrapper would be very thin. It seemed unnecessary. I didn’t want to just add code to the App::Info subclasses that would prompt users and such, or issue print statements to notify the user that something had happened, so I pondered on other, more elegant solutions. I was somewhat stumped until I happened to be leafing through the GOF, where the chain of responsibility pattern hit me as a near ideal solution.

This pattern inspired a major new feature for App::Info: events and event handling. I added methods to the App::Info base class that can be used by subclasses to trigger different kinds of events. By default, these event requests aren’t handled, but clients can associate event handler objects with a given App::Info object, and those handlers can handle the event requests any way they please. The advantage to this approach is that, by and large, subclass implementors don’t have to think about how to handle certain types of events, only where they need to trigger them. At the same time, the pattern frees App::Info users to handle those events in any way they wish. If they want to ignore them, they can. If they want to print them to STDOUT or to a log file, they can. If they want to prompt the user for more information, why, they can do that, too.

The result is what I think of as a really solid API for gathering information about locally-installed software in a highly flexible and configurable fashion. There are four different types of events:

  • info events, which simply send a message describing what the object is doing.

  • error events, which send a message when something has gone wrong – i.e., non-fatal errors.

  • unknown events, which occur when the object is not able to collect a relevant piece of data on its own.

  • confirm events, which are triggered when a central piece of information has been collected, and the object needs to ensure that it’s the correct data.

Any one or all of these types of events can be handled or not, by one event handling object or different ones, however the client user sees fit. A single event can even be handled by multiple events! I also provided some example event handler classes that will likely cover the majority of uses. They print messages to file handles, trigger Carp functions, or prompt the user for data to be entered. But because of the event architecture, event handling is in no way limited to these approaches. Someone might want to write a handler that uses Log::Dispatch to record the events. Or maybe a developer wants to write a GUI installer, and so needs to handle unknown events by presenting a Tk dialog box to her users. The new event architecture allows these approaches and more.

I’d be interested in any feedback on this design. I gave it quite a bit of thought, and I think it’s pretty good. But I’m just one developer, and the opinions of others will help make it a better API going forward (just as Dave’s comments triggered this development). I’d also like to encourage folks to start thinking about new subclasses. There are a lot of software packages and libraries out there that people depend to get their work done, and, IMHO, App::Info provides a good standardized platform for determining those dependencies.

In the meantime, I think I’ll start by offering a patch to DBD::Pg’s Makefile.PL so that it can figure out where the PostgreSQL libraries are without forcing people to set the POSTGRES_INCLUDE and POSTGRES_LIB environment variables. Look for a patch later this week. I might also propose an OSCON lightening talk on this topic; I’ll have to give that some thought.

Originally published on use Perl;

More App::Info

Yes, I put out a new version of App::Info today. Well, a couple of versions, actually.

First of all, all the problems with the unit tests should be fixed. They actually aren’t all that comprehensive, but since the values returned form the various methods can vary, it didn’t make sense for them to be super precise. I have internal unit tests that are more precise, and they don’t execute when folks download App::Info from the CPAN.

But the major change in version 0.10 is the addition of error levels. Now when you construct an App::Info object, you can specify an error level that corresponds to a Carp function. Subclass writers (currently just your truly) then just have to use the error() method to record errors (although serious problems should probably just croak. Client code can specify how it wants to handle errors. The default is “carp”, but the CPAN unit tests, for example, use “silent”.

This functionality makes App::Info much more customizable for creating installation utilities, as the problems the subclasses run into – such as not being able to find a files they need, or not being able to parse a value from a file – can be set to be as verbose as necessary.

Next up, Matt Seargent suggests that I borrow from the AxKit Makefile.PL to make interrogating libiconv much more robust. Maybe in a couple of weeks. I’ve been back-burnering work that I really need to get done in order to work on this!

Originally published on use Perl;

All about App::Info

Yesterday I released App::Info to the CPAN. I started it on Friday, and put the finishing touches on it just yesterday. It was a busy weekend.

I got the idea for App::Info after looking at the work Sam Tregar has done building an installer for Bricolage. He had done all this work to determine whether and how Apache, PostgreSQL, Expat, and libiconv had been installed, and it seemed a shame not to take that code and generalize it for use by others. So I whipped up App::Info, with the idea of building a framework for aggregating data about applications of all kinds, specifically for the purpose of determining dependencies before installing software.

I think it has turned out rather well so far. I added code to determine the version numbers of libiconv and Expat, although it’s imperfect (and that accounts for the CPAN-Testers failures – I’ll have a better release with some of the bugs fixed shortly). But overall the idea is for this to be a uniform architecture for learning about software installed on a system, and I’d like to invite folks to contribute new App::Info subclasses that provide metadata for the applications for which they’re most familiar.

That said, this is a new module, and still in flux. I’ve been talking to Dave Rolsky about it, as he has been thinking about the need for something like this, himself. In the past, Dave and I have talked about creating a generalized API for installing software, and Dave has even set up a Savannah project for that purpose. In truth, I had envisioned App::Info as one part of such an initiative – the part responsible for determining what’s already installed. And while the API I’ve created is good for this, Dave points out that it’s not enough. We need something that can also prompt the user for information – to determine if the right copy of an application was found, for example.

I think I can work this in to App::Info relatively easily, however. Currently, if App::Info can’t find the data it needs, it issues warnings. But this isn’t the best approach, I think. Sometimes, you might want such errors to trigger exceptions. Other times, you might want them totally silent. So I was planning to add a flag to the API such that you can specify the behavior for such errors. Something like DBI’s RaiseError or PrintError options. But then, it’s just another step to add a prompting option. Such an option can be changed to prompt for new data at every step of the process, or only at important points (like finding the proper copy of httpd on the file system) or only when data can’t be found.

So I hope to find the tuits to add this functionality in the next week. In the meantime, I’m going to try to keep up-to-date on my journal more.

Originally published on use Perl;