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) = @_;
33 my $appclass = blessed($app) || $app;
35 $type =~ s/^${appclass}:://; # FIXME - I think there is shit in C::Utils to do this.
38 my $meta = Moose->init_meta( for_class => $name );
40 my @superclasses = @{ $config->{superclasses} || [] };
41 push(@superclasses, 'Catalyst::' . $type) unless @superclasses;
42 $meta->superclasses(@superclasses);
44 if (my @roles = @{ $config->{roles}||[] }) {
45 Moose::Util::apply_all_roles( $name, @roles);
48 if ($p->has_custom_component_method) {
49 $meta->add_method(COMPONENT => $p->COMPONENT);
52 $app->$pre_immutable_hook($meta) if $p->has_pre_immutable_hook;
54 foreach my $name (keys %{ $config->{methods}||{} }) {
55 $meta->add_method($name => $config->{methods}->{$name});
57 $meta->make_immutable;
59 my $instance = $app->setup_component($name);
60 $app->components->{ $name } = $instance;
70 CatalystX::DynamicComponent - Parameterised Moose role providing functionality to build Catalyst components at runtime.
74 package My::DynamicComponentType;
76 use namespace::autoclean;
78 with 'CatalystX::DynamicComponent' => {
79 name => '_setup_one_of_my_components', # Name of injected method
82 after setup_components => sub { shift->_setup_all_my_components(@_); };
84 sub _setup_all_my_components {
86 foreach my $component_name ('MyApp::Component1') {
87 my $component_config = $c->config->{$component_name};
88 # Calling this method creates a component, and registers it in your application
89 $self->_setup_one_of_my_components($component_name, $component_config);
95 CatalystX::DynamicComponent aims to provide a flexible and reuseable method of building generic
96 Catalyst components and registering them with your application.
98 To give you this flexibility, it is implemented as a parametrised role which curries a
99 component builder into your current package at application time.
101 Authors of specific dynamic component builders are expected to be implemented as application class
102 roles which compose this role, but provide their own advice around the C<< setup_compontens >>
103 method, and call the curried method from this role once for each component you wish to setup.
109 B<Required> - The name of the component generator method to curry.
113 Optional, either a L<Class::MOP::Method>, or a plain code ref of a COMPONENT method to apply to
114 the dynamically generated package before making it immutable.
116 =head2 pre_immutable_hook
118 Optional, method to call after a component has been generated, but before it is made immutable,
119 constructed, and added to your component registry.
121 =head1 CURRIED COMPONENT GENERATOR
127 =item $component_name (E.g. C<< MyApp::Controller::Foo >>)
129 =item $config (E.g. C<< $c->config->{$component_name} >>)
141 Better default handling of config - by default component should get config from where it normally
146 Abstract handling of role application / class name. This should not just be the component config
151 Have some actual tests which test just this crap, and not all the other classes together.
157 Probably plenty, test suite certainly isn't comprehensive.. Patches welcome.
161 Tomas Doran (t0m) <bobtfish@bobtfish.net>
165 This code is copyright (c) 2009 Tomas Doran. This code is licensed on the same terms as perl