Commit | Line | Data |
59fc9d16 |
1 | package CatalystX::DynamicComponent; |
53a42ae0 |
2 | use MooseX::Role::Parameterized; |
0b07685c |
3 | use MooseX::Types::Moose qw/Str CodeRef ArrayRef/; |
046d763d |
4 | use namespace::autoclean; |
59fc9d16 |
5 | |
104abdae |
6 | our $VERSION = 0.000001; |
7 | |
53a42ae0 |
8 | parameter 'name' => ( |
0b07685c |
9 | isa => Str, |
53a42ae0 |
10 | required => 1, |
11 | ); |
12 | |
13 | parameter 'pre_immutable_hook' => ( |
0b07685c |
14 | isa => Str, |
53a42ae0 |
15 | predicate => 'has_pre_immutable_hook', |
16 | ); |
17 | |
cd6bd40d |
18 | parameter 'COMPONENT' => ( |
0b07685c |
19 | isa => CodeRef, |
cd6bd40d |
20 | predicate => 'has_custom_component_method', |
21 | ); |
22 | |
53a42ae0 |
23 | role { |
24 | my $p = shift; |
25 | my $name = $p->name; |
cd6bd40d |
26 | my $pre_immutable_hook = $p->pre_immutable_hook; |
0b07685c |
27 | |
53a42ae0 |
28 | method $name => sub { |
c52d8688 |
29 | my ($app, $name, $config) = @_; |
30 | |
31 | $config ||= {}; |
53a42ae0 |
32 | |
33 | my $appclass = blessed($app) || $app; |
34 | my $type = $name; |
35 | $type =~ s/^${appclass}:://; # FIXME - I think there is shit in C::Utils to do this. |
36 | $type =~ s/::.*$//; |
37 | |
38 | my $meta = Moose->init_meta( for_class => $name ); |
279c014c |
39 | |
0b07685c |
40 | my @superclasses = @{ $config->{superclasses} || [] }; |
41 | push(@superclasses, 'Catalyst::' . $type) unless @superclasses; |
42 | $meta->superclasses(@superclasses); |
43 | |
279c014c |
44 | if (my @roles = @{ $config->{roles}||[] }) { |
45 | Moose::Util::apply_all_roles( $name, @roles); |
46 | } |
00b934f1 |
47 | |
cd6bd40d |
48 | if ($p->has_custom_component_method) { |
49 | $meta->add_method(COMPONENT => $p->COMPONENT); |
50 | } |
00b934f1 |
51 | |
cd6bd40d |
52 | $app->$pre_immutable_hook($meta) if $p->has_pre_immutable_hook; |
00b934f1 |
53 | |
c52d8688 |
54 | foreach my $name (keys %{ $config->{methods}||{} }) { |
55 | $meta->add_method($name => $config->{methods}->{$name}); |
549d6abc |
56 | } |
53a42ae0 |
57 | $meta->make_immutable; |
58 | |
59 | my $instance = $app->setup_component($name); |
60 | $app->components->{ $name } = $instance; |
61 | }; |
62 | }; |
59fc9d16 |
63 | |
64 | 1; |
65 | |
dc7781e3 |
66 | __END__ |
67 | |
68 | =head1 NAME |
69 | |
70 | CatalystX::DynamicComponent - Parameterised Moose role providing functionality to build Catalyst components at runtime. |
71 | |
72 | =head1 SYNOPSIS |
73 | |
74 | package My::DynamicComponentType; |
75 | use Moose::Role; |
76 | use namespace::autoclean; |
77 | |
78 | with 'CatalystX::DynamicComponent' => { |
79 | name => '_setup_one_of_my_components', # Name of injected method |
80 | }; |
81 | |
82 | after setup_components => sub { shift->_setup_all_my_components(@_); }; |
83 | |
84 | sub _setup_all_my_components { |
85 | my ($self, $c) = @_; |
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); |
90 | } |
91 | } |
92 | |
93 | =head1 DESCRIPTION |
94 | |
95 | CatalystX::DynamicComponent aims to provide a flexible and reuseable method of building generic |
96 | Catalyst components and registering them with your application. |
97 | |
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. |
100 | |
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. |
104 | |
105 | =head1 PARAMETERS |
106 | |
107 | =head2 name |
108 | |
109 | B<Required> - The name of the component generator method to curry. |
110 | |
111 | =head2 COMPONENT |
112 | |
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. |
115 | |
116 | =head2 pre_immutable_hook |
117 | |
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. |
120 | |
121 | =head1 CURRIED COMPONENT GENERATOR |
122 | |
123 | =head2 ARGUMENTS |
124 | |
125 | =over |
126 | |
127 | =item $component_name (E.g. C<< MyApp::Controller::Foo >>) |
128 | |
129 | =item $config (E.g. C<< $c->config->{$component_name} >>) |
130 | |
131 | =head2 OPERATION |
132 | |
133 | FIXME |
134 | |
135 | =head1 TODO |
136 | |
137 | =over |
138 | |
139 | =item * |
140 | |
141 | Better default handling of config - by default component should get config from where it normally |
142 | does! |
143 | |
144 | =item * |
145 | |
146 | Abstract handling of role application / class name. This should not just be the component config |
147 | by default. |
148 | |
149 | =item * |
150 | |
151 | Have some actual tests which test just this crap, and not all the other classes together. |
152 | |
153 | =back |
154 | |
155 | =head1 BUGS |
156 | |
157 | Probably plenty, test suite certainly isn't comprehensive.. Patches welcome. |
158 | |
159 | =head1 AUTHOR |
160 | |
161 | Tomas Doran (t0m) <bobtfish@bobtfish.net> |
162 | |
163 | =head1 LICENSE |
164 | |
165 | This code is copyright (c) 2009 Tomas Doran. This code is licensed on the same terms as perl |
166 | itself. |
167 | |
168 | =cut |
169 | |