Piers Cawley has described Devel::Declare as possibly the most hostilely documented library [he's] ever come across. I'm hard-pressed to think of a more accurate description. For example, here's this gem from the docs:
For a simpler way to install new methods, see also Devel::Declare::MethodInstaller::Simple
The problem with that line is that Devel::Declare::MethodInstaller::Simple has no documentation at all! I now think I understand what's it's doing, but my brain hurts.
What I want to do is transform something like this:
repackage $some_package { use Moose; extends 'Some::Class'; with 'Some::Role'; }
Into this:
eval <<"END_DYNAMIC_REPACKAGING"; package $some_package; use Moose; extends 'Some::Class'; with 'Some::Role'; END_DYNAMIC_REPACKAGING if ( my $error = $@ ) { require Carp; Carp::Confess($error); }
While I now know that I can just use Moose::Meta::Class to do this, but this is actually a problem I encounter from time to time in other contexts and rather than explicitly doing a string eval (which breaks syntax highlighting and hides the code from PPI), I'd like that 'repackage' to handle that.
In fact, delaying evaluation of a block until runtime is moderately common and that's really what we're trying to do here. Unfortunately, you have to call a string eval to do this. I think Devel::Declare can handle this, but the parser currently has me defeated. I'll try again later, but if you want to simply post the answer, I won't mind :)
I guess that your example above is a gross simplification of what you're actually trying to do?
In fact, re-reading your post, you say:
While I now know that I can just use Moose::Meta::Class to do this, but this is actually a problem I encounter from time to time in other contexts and rather than explicitly doing a string eval (which breaks syntax highlighting and hides the code from PPI), I'd like that 'repackage' to handle that.
As I'm sure you know, your example above can be written as:
Moose::Meta::Class->create( $some_package. superclasses => 'Some::Class', roles => 'Some::Role', );
So what is actually stopping you from just doing that, I don't understand?
I mean, you say other contexts, but if you're explicitly using roles, then you're making Moose classes anyway - so I don't see how it's a different context.
If you're just using more plain perl OO, then I'd be tempted to just use Class::MOP::Class->create instead.
If you really want to play with Devel::Declare just cause you want to play - fair enough however
Re:Simplification?
Ovid on 2009-06-19T19:19:12
When I say "other contexts", I just mean that I do a lot of code generation work and I often need to dynamically declare a package. Deferring code compilation via eval is a common enough thing in general that I think it's worth generalizing it.
Right, but I don't get how dynamically generate/declaring a package using Moose isn't waaay easier and nicer than using a string eval?
What problem are you trying to solve that won't work by just generating classes through the meta-model, or why does that solution not work for you?
As an example of this taken to extremes, see the tests for my CX::DynamicComponent dist - I generate the models for my application totally dynamically from configuration, and then go on to generate the application controllers dynamically by introspecting the model - so I have two whole application layers of code which doesn't exist till compile time..
Re:Meta model
Ovid on 2009-06-19T21:16:50
I only used the Moose example because that's what I was working on today. I still have found myself on several occasions writing this:
eval <<"END";
package $package;
our \@ISA = $some_base_class;
sub some_sub {... }
END
croak($@) if $@;So yet, I definitely found the Moose meta stuff was easier and nicer than a string eval, but again, I often need non-Moose packages generated at runtime and the code bound to that package. This often requires string eval (and it quickly gets very annoying if you want to work around it).
Re:Meta model
bobtfish on 2009-06-19T21:52:10
I often need non-Moose packages generated at runtimeRight, I guessed that this was where you were going, but why do they need to be non-moose classes? Sure, if you don't need all of Moose, use the Class::MOP api.
Your generated classes don't have to subclass Class::MOP::Class, don't have to have a 'meta' method, it all still works..
All I'm hearing is you saying 'string eval sucks', which is totally correct.. I still don't understand why you think you need to use it to solve your issue.
If you really need the speed and flexibility that only string eval gives you for your special case, then surely you want to abstract it away as fast as possible (see simple example to do inlined CAF specific accessores)
Re:Meta model
Ovid on 2009-06-20T07:48:42
Right, I guessed that this was where you were going, but why do they need to be non-moose classes?
A package might very well be procedural code and not class-based. Plus, for wanting to abstract away this code, why would anyone thing "I must now use Moose or Class::Mop"? That's a straight jacket which is just wrong
:) Re:Meta model
bobtfish on 2009-06-20T11:13:15
Nothing but nothing is stopping your from using the MOP to construct packages without constructors which you call procedurally. Hell, you can just use Class::MOP::Package standalone to at least get away from manual symbol table twiddling.
And yes - TIMTOWTDI. If you really want the originally floated syntax without requiring MOP then you're gonna need another technique, and Devel::Declare is a good way of not doing string concatenation fed into eval, but it also involves a lot more fiddling with perl guts.
Also - is Devel::Declare really a less exacting (or at least platform constraining) dependency requirement than plain MOP?
Either way - can we call my solution laziness, plain string eval with concatenation impatience, and your solution hubris, and have done with this discussion?
They all have advantages and disadvantages, and if you write it - I'll probably use it at some point - I was just trying to point out that this isn't the only way to achieve what you want..
Um. I think Piers's post is from March: the docs for DD were released in April... Yes indeed, the current docs are the friendly, useful version
The