I had really high hopes for getting Template::Declare to play nicely with MooseX::Declare (or even vanilla Moose), but that is proving a little too difficult. TD does a lot of symbol table fuckery. My big problem is that the template declarator is caller aware. It takes the caller package, and stores it into the dispatch table and also munges the symbol table for the current package to store the code ref. The problem is that if you want to subclass something and apply a role that advises some methods, that advice will never be called because the invocant was set in stone at the time the declarator was called. And since everything in TD is essentially singleton, class based, that means the place where your advice lives, in the sub class, is never called.
Oh sure you could use something like MooseX::CompileTime::Traits to advise various things, but the problem is that is very very global and not at all appropriate for what I am trying to do. You couldn't have two different grid things because the advice would apply to /all/ of them.
Aside from that, it has been a significant, constant uphill battle trying to make things work and I have run out of time. So I'll be throwing together the current work project using plain old TT, but still use DBIC::API and the javascript goodness that I found.
Consider me really put out by this.
Monday, November 23, 2009
Monday, November 16, 2009
Template::Declare + MooseX::Declare == Win
So, I've been playing around with getting TD to work with MXD nicely. This is the result for the most part:
What this will buy me is a more sane wrapper strategy with role application. I'd rather have 'around' keywords than the insanity that is TD's create_wrapper stuff. But mainly, I want type constraint checking that comes with MooseX::Method::Signatures. In the end, this is win. This lets me step back a little bit from TD, write some sanity, and then hook it up to the dispatcher via the template() function.
Granted it is a little unwieldy at first, but I am thinking I could distill this out into it's own thingy. We will see as the week progresses.
What this will buy me is a more sane wrapper strategy with role application. I'd rather have 'around' keywords than the insanity that is TD's create_wrapper stuff. But mainly, I want type constraint checking that comes with MooseX::Method::Signatures. In the end, this is win. This lets me step back a little bit from TD, write some sanity, and then hook it up to the dispatcher via the template() function.
Granted it is a little unwieldy at first, but I am thinking I could distill this out into it's own thingy. We will see as the week progresses.
Datagrid
For those of you who have hacked in other languages, you know how easy it is at time to just display a grid of data (either to the user via the web or with a desktop application). Sadly, there isn't any as cohesive for Perl and Catalyst. And I really need one for the project I have at work. So this next week I am aiming to build one. The underlying tools will be Catalyst::Controller::DBIC::API, along with Template::Declare (specifically Catalyst::View::TD), using jquery plugins Collections and JSON-REST for the front end.
The premise is rather simple. Subclass one of the DBIC::API's concrete implementations (REST), provide an index end point that forwards to a TD view that spits out the grid. From then on, the javascript in the grid will actually manage the data via the REST api. To make customization easier, the grid, each "row" and each element in a row will have their own TD class. A helper script will be written that will generate these to subclass from the distributed classes to enable customization.
The goal is to provide four things: Controller that subclasses DBIC::API, Views that implement the grid and it's functionality, the ability to, within the Perl code, provide overridden behavior for all of the functionality of the grid (ie, methods on the TD classes that spit out the right javascript), and a helper class that makes it as painless as possible to expose a table via the datagrid in your application.
My hope is that with these four things in place, we'll have a coherent distribution with this functionality bundled (including the javascript) and people can stop reinventing this wheel and instead improve this one. We'll see how it goes.
The premise is rather simple. Subclass one of the DBIC::API's concrete implementations (REST), provide an index end point that forwards to a TD view that spits out the grid. From then on, the javascript in the grid will actually manage the data via the REST api. To make customization easier, the grid, each "row" and each element in a row will have their own TD class. A helper script will be written that will generate these to subclass from the distributed classes to enable customization.
The goal is to provide four things: Controller that subclasses DBIC::API, Views that implement the grid and it's functionality, the ability to, within the Perl code, provide overridden behavior for all of the functionality of the grid (ie, methods on the TD classes that spit out the right javascript), and a helper class that makes it as painless as possible to expose a table via the datagrid in your application.
My hope is that with these four things in place, we'll have a coherent distribution with this functionality bundled (including the javascript) and people can stop reinventing this wheel and instead improve this one. We'll see how it goes.
Sunday, November 8, 2009
Nerd Hackery
So I play a little space MMO that some of you may know (eve-online.com). And the game is rather vast when it comes to in game items. And a lot of these items have blueprints which allow you manufacture the items provided you have the necessary skills and materials. I was puttering around this past weekend trying to find a list of all the blueprints and what materials were required and simply could not find one that was current. But I did stumble upon a complete static dump of the game database for items, etc. And given some SQL-fu I could gather the information I wanted.
Sadly, my SQL-fu is not strong for scarily interrelated datasets, but that is why awesome people like mst came up with DBIx::Class and other modules of the same vain such as DBIx::Class::Schema::Loader. I got a hold of the database that CCP distributed and someone was kind enough to do a sqlite conversion. I threw Schema::Loader at it and got back a whole set Result classes ready for use.
Next step was to write a quick little script that would do the little calculations that I want and print out via STDOUT a CSV file suitable to be read in by OpenOffice. Earlier I read and commented on jnapiorkowski's blog about his very awesome MooseX::Role::BuildInstanceOfmodule. And so I took his module and used it in a class to spin up an attribute of the Schema class. Then I threw some MooseX::Getopt at the class to allow easy runtime option definition for things like what field separator to use.
Once that was all in place, the script ran and I now I have a rudimentary spreadsheet that allows me to find blueprints that take the materials that I readily have available. And what was my total time in developing this little 68 line script? 30 minutes.
Nerd hackery for the win!
Sadly, my SQL-fu is not strong for scarily interrelated datasets, but that is why awesome people like mst came up with DBIx::Class and other modules of the same vain such as DBIx::Class::Schema::Loader. I got a hold of the database that CCP distributed and someone was kind enough to do a sqlite conversion. I threw Schema::Loader at it and got back a whole set Result classes ready for use.
Next step was to write a quick little script that would do the little calculations that I want and print out via STDOUT a CSV file suitable to be read in by OpenOffice. Earlier I read and commented on jnapiorkowski's blog about his very awesome MooseX::Role::BuildInstanceOfmodule. And so I took his module and used it in a class to spin up an attribute of the Schema class. Then I threw some MooseX::Getopt at the class to allow easy runtime option definition for things like what field separator to use.
Once that was all in place, the script ran and I now I have a rudimentary spreadsheet that allows me to find blueprints that take the materials that I readily have available. And what was my total time in developing this little 68 line script? 30 minutes.
Nerd hackery for the win!
Sunday, November 1, 2009
More PCJ refactoring
So I spent the week analyzing in greater depth the patterns I've naturally seen as I started developing POEx modules and how they could be more readily applied to my effort to refactor and generally modernize POE::Component::Jabber. A couple of things came to light.
When I was working on Voltron over the summer to have ready for YAPC10, one of the more base components to the system was the ability to proxy sessions. Hence, POEx::ProxySession was born. And in there, I recognized that I needed that role that defined behavior for sending messages: POEx::ProxySession::MessageSender. And while looking at PCJ, I realized that I needed a more generic MessageSender role that could cover the obvious pattern of accessing a POE::Wheel and call put() with some data. Sending a message via a Wheel is such a common task, that I've decided to break it out into its own role: POEx::Role::MessageSender. And it covers just the behavior described above plus the ability to store context about a particular message.
In a case like PXPS, storing context is important since every message is really a request that is expecting a response. I modeled the protocol very similar to how XMPP functions with tagging a particular message request with an 'id'. And the more I thought about it, in an asynchronous system like POE, you would have to model most of your request/response interactions the same way. So that was built into POEx::Role::MessageSender.
And on a tangent while working this up, I debated how errors should be handled. I glanced at a bunch of different projects I had written in POE over the years and came to the conclusion that exception handling is rather lacking inside POE. POE, by default, executes each handler inside an eval. If for whatever reason that event dies, the $@ is captured and delivered to the owning session via a signal. If you don't have a signal handler installed for the "DIE" signal, then you actually won't get a chance to handle it. And you won't know about it "immediately." I put that in quotes for a reason.
The "DIE" signal is one of the "terminal" signals that POE checks for when dealing with signals. That means it will kill the session and propagate up, eventually stopping the Kernel, unless handled. But that can take a awhile if you have a lot of stuff going on, for some value of "awhile". This means if you are debugging your app while developing, you are going to be very annoyed at the all the stuff you have to wade through to trace the events that lead up to the exception. And this behavior is controllable via a folded constant, but I digress.
POEx::Role::MessageSender actually throws an exception if it is unable to obtain the wheel you want to use to send a message. This requires of course people to make use of the "DIE" signal facilities which a lot of people just don't do. So the second role that I am going to develop is POEx::Role::ExceptionDispatch. This will install a simple dispatch table as a DIE signal handler and expose a hash attribute with the keys being ClassNames and the values being tuples of session id/alias/ref, and event name. The reason I decided on tuples instead of postbacks or coderef, is I wanted to leave the door open for any kind of exception management, whether that be chained (install multiple handlers per exception class with each step given the option of stopping execution), execute-all (multiple handlers per exception class that all execute), or only one handler per exception type. Instead of building all of that logic into the role and trying to fit all of those needs, I opted to use the default moose method modifiers approach. If you want to do any complex exception handling, just advise your handlers with before/around/after. Problem solved. Code kept simple.
Just 'with' the role inside a POEx::Role::SessionInstantiation enabled object, and you have a much better exception handling interface.
POEx::Role::MessageSender is up on github(http://github.com/nperez/pxrms) , but it isn't finished at this point. I still need to flesh out the types and write tests. And soonish, I should have POEx::Role::ExceptionDispatch up there too.
My big picture goal is to develop as many of these kinds of roles as possible during the course of my work on various projects in the hopes that it will encourage further Moose + POE interaction. So any patterns of behavior that I see myself repeating between projects, I will be consolidating and generically developing into their own stand alone roles where needed. And I really hope more developers follow my lead by publishing roles to CPAN. I know many people write roles for their jobs, and with just a tiny bit of effort, for an enormous amount of gain, these generic behaviors can be made available. Because I see the future of CPAN in roles that can be easily composed and utilized
When I was working on Voltron over the summer to have ready for YAPC10, one of the more base components to the system was the ability to proxy sessions. Hence, POEx::ProxySession was born. And in there, I recognized that I needed that role that defined behavior for sending messages: POEx::ProxySession::MessageSender. And while looking at PCJ, I realized that I needed a more generic MessageSender role that could cover the obvious pattern of accessing a POE::Wheel and call put() with some data. Sending a message via a Wheel is such a common task, that I've decided to break it out into its own role: POEx::Role::MessageSender. And it covers just the behavior described above plus the ability to store context about a particular message.
In a case like PXPS, storing context is important since every message is really a request that is expecting a response. I modeled the protocol very similar to how XMPP functions with tagging a particular message request with an 'id'. And the more I thought about it, in an asynchronous system like POE, you would have to model most of your request/response interactions the same way. So that was built into POEx::Role::MessageSender.
And on a tangent while working this up, I debated how errors should be handled. I glanced at a bunch of different projects I had written in POE over the years and came to the conclusion that exception handling is rather lacking inside POE. POE, by default, executes each handler inside an eval. If for whatever reason that event dies, the $@ is captured and delivered to the owning session via a signal. If you don't have a signal handler installed for the "DIE" signal, then you actually won't get a chance to handle it. And you won't know about it "immediately." I put that in quotes for a reason.
The "DIE" signal is one of the "terminal" signals that POE checks for when dealing with signals. That means it will kill the session and propagate up, eventually stopping the Kernel, unless handled. But that can take a awhile if you have a lot of stuff going on, for some value of "awhile". This means if you are debugging your app while developing, you are going to be very annoyed at the all the stuff you have to wade through to trace the events that lead up to the exception. And this behavior is controllable via a folded constant, but I digress.
POEx::Role::MessageSender actually throws an exception if it is unable to obtain the wheel you want to use to send a message. This requires of course people to make use of the "DIE" signal facilities which a lot of people just don't do. So the second role that I am going to develop is POEx::Role::ExceptionDispatch. This will install a simple dispatch table as a DIE signal handler and expose a hash attribute with the keys being ClassNames and the values being tuples of session id/alias/ref, and event name. The reason I decided on tuples instead of postbacks or coderef, is I wanted to leave the door open for any kind of exception management, whether that be chained (install multiple handlers per exception class with each step given the option of stopping execution), execute-all (multiple handlers per exception class that all execute), or only one handler per exception type. Instead of building all of that logic into the role and trying to fit all of those needs, I opted to use the default moose method modifiers approach. If you want to do any complex exception handling, just advise your handlers with before/around/after. Problem solved. Code kept simple.
Just 'with' the role inside a POEx::Role::SessionInstantiation enabled object, and you have a much better exception handling interface.
POEx::Role::MessageSender is up on github(http://github.com/nperez/pxrms) , but it isn't finished at this point. I still need to flesh out the types and write tests. And soonish, I should have POEx::Role::ExceptionDispatch up there too.
My big picture goal is to develop as many of these kinds of roles as possible during the course of my work on various projects in the hopes that it will encourage further Moose + POE interaction. So any patterns of behavior that I see myself repeating between projects, I will be consolidating and generically developing into their own stand alone roles where needed. And I really hope more developers follow my lead by publishing roles to CPAN. I know many people write roles for their jobs, and with just a tiny bit of effort, for an enormous amount of gain, these generic behaviors can be made available. Because I see the future of CPAN in roles that can be easily composed and utilized
Subscribe to:
Posts (Atom)