Tuesday, October 2, 2012

New website design for jackmaney.com

So, I have this website, and I've finished revamping the design. The new design not only looks spiffier, but it's put together on the back-end via a template and Template::Toolkit.

Feel free to check it out and let me know what you think!

Wednesday, September 26, 2012

Hypatia: Now with Column Guessing!

The latest versions of Hypatia and Hypatia::Chart::Clicker (versions 0.025 and 0.02, respectively) have hit CPAN (and, of course, they're also up on GitHub).

The main feature is the added robustness of not necessarily requiring a columns attribute (specifying, for example, which column names correspond to x-values and which correspond to y-values), and trying to Do The Right Thing if you leave it out.

So, to twist the example in my previous Hypatia post, we can do the following:

use strict;
use warnings;
use Hypatia;
 
my $hypatia=Hypatia->new({
back_end=>"Chart::Clicker",
graph_type=>"Line",
dbi=>{
 dsn=>"dbi:MySQL:dbname=database;host=localhost",
 username=>"jdoe",
 password=>"sooperseekrit",
 query=>"select datediff(now(),date_created) as num_days_ago,sum(revenue) as daily_revenue
  from widget_sales
  group by datediff(now(),date_created) as num_days_ago"
    }
});
  
#grabs data from the query and puts it into a Chart::Clicker line graph
my $cc=$hypatia->chart;
  
#Since $cc is a Chart::Clicker object, we can now do whatever we want to it.
  
$cc->title->text("Total Daily Revenue for Widget Sales");
$cc->write_output("daily_revenue.png");
and Hypatia will be able to detect that you (presumably) meant for the num_days_ago to yield x-values and daily_revenue to yield y-values.

I also put together a large battery of unit tests (probably too large...) to help ensure that these guesses work correctly. Take a look and tell me what you think.

PS My thanks to wk who noticed the bug in my previous (fictitious) example: namely that all of the graphs via Hypatia by way of Chart::Clicker require numeric x-values (and not dates).

Tuesday, September 25, 2012

CentOS Quest I: Quest for the DBD::mysql Installation

So, to troubleshoot a potential bug found by wk (as mentioned in the comment thread of this post), I realized I had to set up MySQL (since I don't have an installation of it to play with at work).

Thankfully, setting up a MySQL instance on my web server was made fairly painless due to Plesk. So, all I have to do now is install DBD::mysql, and I should be good to go, right? Well, that's what I thought... Unfortunately, the make step failed to work, due to what seemed to be a bunch of cascading linker errors, and it seemed to start with mysql.h not being found.

Some rounds of Googling brought me to this MySQL bug report page, where it was suggested that mysql-devel needed to be installed.

Okay...so, one yum install mysql-devel later, and I'm met with the following:


Running rpm_check_debug
ERROR with rpm_check_debug vs depsolve:
mysql is needed by (installed) mysql-server-5.5.14-11071510.x86_64
mysql is needed by (installed) plesk-mysql-5.5-11053114.x86_64
Complete!

*sigh* So, some more Googling brought me to an answer left by a kind soul that contains a link to a specific RPM. Miraculously, the RPM installed and I was then able to successfully install DBD::mysql.

I swear, running my own Linux box (well, okay, a VM, but still...) sometimes feels like I'm playing an old-school adventure game.

Monday, September 3, 2012

Hypatia Released!

It took longer than I would've liked--partially due to $work and partially due to other issues--but Hypatia has finally been released!

As explained in a previous post, Hypatia is an API layer that sits between DBI and data visualization modules. For the moment, only Chart::Clicker is supported as a visualization back-end, but work is underway on bindings for GraphViz2.*

There's a examples folder with the distribution of Hypatia::Chart::Clicker, but here's a possible (fictitious) example:
use strict;
use warnings;
use Hypatia;
 
my $hypatia=Hypatia->new({
back_end=>"Chart::Clicker",
graph_type=>"Line",
dbi=>{
 dsn=>"dbi:MySQL:dbname=database;host=localhost",
 username=>"jdoe",
 password=>"sooperseekrit",
 query=>"select DATE(time_of_sale) as date,sum(revenue) as daily_revenue
  from widget_sales
  group by DATE(time_of_sale)"
    },
  columns=>{"x"=>"date","y"=>"daily_revenue"}
  });
  
#grabs data from the query and puts it into a Chart::Clicker line graph
my $cc=$hypatia->chart;
  
#Since $cc is a Chart::Clicker object, we can now do whatever we want to it.
  
$cc->title->text("Total Daily Revenue for Widget Sales");
$cc->write_output("daily_revenue.png");

Oh, and in case you're wondering how the module got its name, Hypatia was one of the librarians of the Great Library of Alexandria and one of the first female names in mathematics.

Is it the best code that anyone's ever written? No. Does it have bugs? Quite possibly, although I did release it with some unit tests and tried to eliminate every bug I could find. Of course, bug reports and constructive criticism are more than welcome.


* - Yes, I'm aware that GraphViz2::DBI exists. However, I hope to make an interface that is a bit more "plug-and-play" with not just GraphViz2, but other data visualization modules.

Monday, May 28, 2012

Moose ProTip #1...

When using BUILDARGS, make sure to return the class's constructor when you're done. That would've saved me some of the hairs that I've been ripping out of my head...

Also, MooseX::AbstractFactory makes dependency injection a bit easier, although its route handling is a bit limited in that it only takes one string argument to determine an implementation. I've worked around this for now, but in the long run, I think I'll make a wrapper class (or maybe even a patch?). I'm envisioning something that provides Dancer-esque "route handlers" to objects that would add more customizability--and perhaps even the ability to generate new classes on the fly (maybe...that would probably involve prodding into the Dark Magic behind Moose, which is a daunting task).

Thursday, May 24, 2012

Dependency Injection with Moose

I'm close to finishing the initial release of Hypatia. The internal part of the API has changed quite a bit, thanks to suggestions by Cory 'G' Watson. The biggest change by far is the ability to call what back-end you want and to have that load automatically, eg

What makes this a bit more difficult than simply loading the module given by the back_end attribute and moving merrily upon our way is that these modules have lots of methods (eg chart) that should be used by the base object. However, this is not insurmountable, and Moose provides two ways to get around this (TIMTOWTDI, after all): loading dependencies as roles or as modules.
For the sake of illustration, let's look at something simpler than Hypatia (but still as geeky): writing an object system for characters in a fantasy RPG setting. For simplicity's sake, let's also assume that we have the standard classes of Fighter, Rogue, and Mage, and races of Human, Elf, Dwarf, and Halfling.

Etc, etc. As of right now, class and race are just strings. However, there may be a lot of things that depend on race and class, such as stats (eg halflings are more dexterous than dwarves but are weaker), skills/abilities (elves are better with magic but are more frail), and both classes and races can have equipment restrictions (halflings can't wield polearms and mages can't wear plate mail). Now yes, it's possible to go through a bunch of if-then statements to suss the logic out in one place, but what if you add other classes or races? Down this way lies spaghetti coding

So, let's take a look at getting around this via roles and via modules. In either case, it's BUILD to the rescue!

Roles (consumed into your main class)

All that we need to know is which roles go with which combinations of class and race. This has to be hard coded somewhere, but this hard-coding will be the single, unambiguous, authoritative representation of these dependencies within our system.

So, if, for example, we've chosen a halfling rogue and we've stored the roles that we need to load in the array @roles (containing, say, Stat::Bonuses::Halfling, Allowable::Equipment::Small, Skills::Rogue, etc), then our BEGIN would look something like this:

And that's prettymuch it. If all goes well, the roles should be loaded. The only thing you need to watch for is to avoid duplicating method or attribute names within these roles, but that should be easy enough if you design them carefully.

Modules (loaded into attributes)

The idea here is somewhat similar, but a bit different in that we're loading modules based upon our choices into attributes of our main class. If you want to call upon attributes and methods of each of these class/race related module within your main Character module, then you'll have to use handles.

Of course, it might be tempting to immediately pull down every method and attribute from each class via handles=>qr/.*/, but this is actually a bad idea since this also includes the Moose-specific magical BUILD and BUILDARGS methods. So, we need to be a bit more specific with our regex.

Also, to avoid confusion, it's a good idea to name the attributes differently from the corresponding module. So, let's assume that we've stored this information in the hash %modules (which might, for example, contain a key-value pair of "skills"=>"Skills::Rogue"). We'll also make use of Module::Load's load function:

Unfortunately, I've skipped over a couple of potentially important details....what if you want to pass arguments to the constructor of $module that were initially passed to the main class (this is definitely the case in Hypatia)? Then you'll have to sift through that information beforehand, either before the while loop above or separately in BUILDARGS. Also, what if you don't always want $attr to be read-only? Well, you'll have to suss out that information (including it in %modules, perhaps) and load that dynamically.

Summary

So, dependency injection in Moose can be done at run-time by either dynamically loading classes or by tying modules to attributes. The first approach seems simpler and is less likely to shatter the encapsulation-fourth-wall. However, it leaves all of the attributes and methods of all of the dynamically-loaded roles sitting in your primary class. The second approach does a better job of bucketing these attributes and methods, but can be much more difficult to set up if you have to pass arguments along (believe me...I've learned this the long and hard way).