1 package CatalystX::DynamicComponent;
2 use MooseX::Role::Parameterized;
3 use MooseX::Types::Moose qw/Str CodeRef ArrayRef/;
4 use namespace::autoclean;
6 our $VERSION = 0.000001;
13 parameter 'pre_immutable_hook' => (
15 predicate => 'has_pre_immutable_hook',
18 parameter 'COMPONENT' => (
20 predicate => 'has_custom_component_method',
26 my $pre_immutable_hook = $p->pre_immutable_hook;
29 my ($app, $name, $config, $methods) = @_;
31 my $appclass = blessed($app) || $app;
33 $type =~ s/^${appclass}:://; # FIXME - I think there is shit in C::Utils to do this.
36 my $meta = Moose->init_meta( for_class => $name );
38 my @superclasses = @{ $config->{superclasses} || [] };
39 push(@superclasses, 'Catalyst::' . $type) unless @superclasses;
40 $meta->superclasses(@superclasses);
42 if (my @roles = @{ $config->{roles}||[] }) {
43 Moose::Util::apply_all_roles( $name, @roles);
46 if ($p->has_custom_component_method) {
47 $meta->add_method(COMPONENT => $p->COMPONENT);
50 $app->$pre_immutable_hook($meta) if $p->has_pre_immutable_hook;
53 foreach my $name (keys %$methods) {
54 $meta->add_method($name => $methods->{$name});
56 $meta->make_immutable;
58 my $instance = $app->setup_component($name);
59 $app->components->{ $name } = $instance;
69 CatalystX::DynamicComponent - Parameterised Moose role providing functionality to build Catalyst components at runtime.
73 package My::DynamicComponentType;
75 use namespace::autoclean;
77 with 'CatalystX::DynamicComponent' => {
78 name => '_setup_one_of_my_components', # Name of injected method
81 after setup_components => sub { shift->_setup_all_my_components(@_); };
83 sub _setup_all_my_components {
85 foreach my $component_name ('MyApp::Component1') {
86 my $component_config = $c->config->{$component_name};
87 # Calling this method creates a component, and registers it in your application
88 $self->_setup_one_of_my_components($component_name, $component_config);
94 CatalystX::DynamicComponent aims to provide a flexible and reuseable method of building generic
95 Catalyst components and registering them with your application.
97 To give you this flexibility, it is implemented as a parametrised role which curries a
98 component builder into your current package at application time.
100 Authors of specific dynamic component builders are expected to be implemented as application class
101 roles which compose this role, but provide their own advice around the C<< setup_compontens >>
102 method, and call the curried method from this role once for each component you wish to setup.
108 B<Required> - The name of the component generator method to curry.
112 Optional, either a L<Class::MOP::Method>, or a plain code ref of a COMPONENT method to apply to
113 the dynamically generated package before making it immutable.
115 =head2 pre_immutable_hook
117 Optional, method to call after a component has been generated, but before it is made immutable,
118 constructed, and added to your component registry.
120 =head1 CURRIED COMPONENT GENERATOR
126 =item $component_name (E.g. C<< MyApp::Controller::Foo >>)
128 =item $config (E.g. C<< $c->config->{$component_name} >>)
140 Better default handling of config - by default component should get config from where it normally
145 Abstract handling of role application / class name. This should not just be the component config
150 Have some actual tests which test just this crap, and not all the other classes together.
156 Probably plenty, test suite certainly isn't comprehensive.. Patches welcome.
160 Tomas Doran (t0m) <bobtfish@bobtfish.net>
164 This code is copyright (c) 2009 Tomas Doran. This code is licensed on the same terms as perl