forked from bobtfish/catalystx-dynamiccomponent
-
Notifications
You must be signed in to change notification settings - Fork 1
/
README
180 lines (140 loc) · 6.12 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
NAME
CatalystX::DynamicComponent - Parameterised Moose role providing
functionality to build Catalyst components at runtime.
SYNOPSIS
package My::DynamicComponentType;
use Moose::Role;
use namespace::autoclean;
with 'CatalystX::DynamicComponent' => {
name => '_setup_one_of_my_components', # Name of injected method
};
after setup_components => sub { shift->_setup_all_my_components(@_); };
sub _setup_all_my_components {
my ($self, $c) = @_;
my $app = ref($self) || $self;
foreach my $component_name ('Controller::Foo') {
my %component_config = %{ $c->config->{$component_name} };
# Shallow copy so we avoid stuffing methods back in the config, as that's lame!
$component_config{methods} = {
some_method => sub { 'foo' },
};
# Calling this method creates a component, and registers it in your application
# This component will subclass 'MyApp::ControllerBase', do 'MyApp::ControllerRole'
# and have a method called 'some_method' which will return the value 'foo'..
$self->_setup_one_of_my_components($app . '::' . $component_name, \%component_config);
}
}
package MyApp;
use Moose;
use namespace::autoclean;
use Catalyst qw/
+My::DynameComponentType
/;
__PACKAGE__->config(
name => 'MyApp',
'Controller::Foo' => {
superclasses => [qw/MyApp::ControllerBase/],
roles => [qw/MyApp::ControllerRole/],
},
);
__PACKAGE__->setup;
DESCRIPTION
CatalystX::DynamicComponent aims to provide a flexible and reuseable
method of building Roles which can be added to Catalyst applications,
which generate components dynamically at application startup using the
Moose meta model.
Thi is implemented as a parametrised role which curries a component
builder method into your current package at application time.
Authors of specific dynamic component builders are expected implement an
application class roles which composes this role, and their own advice
after the "setup_compontents" method, which will call the component
generation method provided by using this role once for each component
you wish to create.
PARAMETERS
name
Required - The name of the component generator method to curry.
methods
Optional, a hash reference with keys being method names, and values
being a Class::MOP::Method, or a plain code ref of a method to apply to
the dynamically generated package before making it immutable.
roles
Optional, an array reference of roles to apply to the generated
component
superclasses
Optional, an array reference of superclasses to give the generated
component.
If this is not defined, and not passed in as an argument to the
generation method, then Catalyst::(Model|View|Controller) will used as
the base class (as appropriate given the requested namespace of the
generated class, otherwise Catalyst::Component will be used.
FIXME - Need tests for this.
pre_immutable_hook
Optional, either a coderef, which will be called with the component
$meta and the merged $config, or a string name of a method to call on
the application class, with the same parameters.
This hook is called after a component has been generated and methods
added, but before it is made immutable, constructed, and added to your
component registry.
CURRIED COMPONENT GENERATOR
ARGUMENTS
* $component_name (E.g. "MyApp::Controller::Foo")
* $config (E.g. "$c->config->{$component_name}")
config
It is possible to set each of the roles, methods and superclasses
parameters for each generated package individually by defining those
keys in the $config parameter to your curried component generation
method.
By default, roles and methods supplied from the curried role, and those
passed as config will be merged.
Superclasses, no the other hand, will replace those from the curried
configuration if passed as options. This is to discourage accidental use
of multiple inheritence, if you need this feature enabled, you should
probably be using Roles instead!
It is possible to change the default behavior of each parameter by
passing a " $param_name.'_resolve_strategy' " parameter when currying a
class generator, with values of either "merge" or "replace".
Example:
package My::ComponentGenerator;
use Moose;
with 'CatalystX::DynamicComponent' => {
name => 'generate_magic_component',
roles => ['My::Role'],
roles_resolve_strategy => 'replace',
};
package MyApp;
use Moose;
use Catalyst qw/
My::ComponentGenerator
/;
extends 'Catalyst';
after 'setup_components' => sub {
my ($app) = @_;
# Component generated has no roles
$app->generate_magic_component('MyApp::Controller::Foo', { roles => [] });
# Component generated does My::Role
$app->generate_magic_component('MyApp::Controller::Foo', {} );
};
__PACKAGE__->setup;
OPERATION
FIXME
TODO
* Test pre_immutable hook in tests
* More tests fixme?
* Unlame needing to pass fully qualified component name in, that's
retarded...
Remember to fix the docs and clients too ;)
* Tests for roles giving advice to methods which have just been
added..
LINKS
Catalyst, MooseX::MethodAttributes,
CatalystX::DynamicComponent::ModelsFromConfig.
BUGS
Probably plenty, test suite certainly isn't comprehensive.. Patches
welcome.
Source code can be found on github:
http://github.com/bobtfish/catalyst-dynamicappdemo/tree/master
AUTHOR
Tomas Doran (t0m) <bobtfish@bobtfish.net>
LICENSE
This code is copyright (c) 2009 Tomas Doran. This code is licensed on
the same terms as perl itself.