A few notes on tests using outside Cat
[catagits/Catalyst-Runtime.git] / TODO
1 # Known Bugs:
2
3    - Bug ->go or ->visit causes actions which have Args or CaptureArgs called
4      twice when called via ->go or ->visit.
5
6      Test app: http://github.com/bobtfish/catalyst-app-bug-go_chain/tree/master
7
8 # Compatibility warnings to add:
9
10   - $self->config should warn as config should only ever be called as a
11     class method (TESTS).
12
13 # Proposed functionality / feature additions:
14
15 ## Log setup needs to be less lame
16
17 So Catalyst::Plugin::Log::* can die
18 in a fire. Having $c->log_class would be a good start. kane volunteered
19 to do some of this.
20
21 Simple example: Catalyst::Plugin::Log::Colorful should just be a
22 subclass of Catalyst::Log, no ::Plugin:: needed.
23
24 See also: Catalyst::Plugin::Log::Dispatch and
25 http://github.com/willert/catalyst-plugin-log4perl-simple/tree
26
27 # REFACTORING
28
29 ##  The horrible hack for plugin setup - replacing it:
30
31  * Have a look at the Devel::REPL BEFORE_PLUGIN stuff
32    I wonder if what we need is that combined with plugins-as-roles
33
34 ## App / ctx split:
35
36   NOTE - these are notes that t0m thought up after doing back compat for
37          catalyst_component_class, may be inaccurate, wrong or missing things
38          bug mst (at least) to correct before trying more than the first 2
39          steps. Please knock yourself out on the first two however :)
40
41   - Eliminate actions in MyApp from the main test suite
42   - Uncomment warning in C::C::register_action_methods, add tests it works
43     by mocking out the logging..
44   - Remove MyApp @ISA controller (ask metaclass if it has attributes, and if
45                                   so you need back compat :/)
46   - Make Catalyst::Context, move the per request stuff in there, handles from
47     main app class to delegate
48   - Make an instance of the app class which is a global variable
49   - Make new instance of the context class, not the app class per-request
50   - Remove the components as class data, move to instance data on the app
51     class (you probably have to do this for _all_ the class data, good luck!)
52   - Make it possible for users to spin up different instances of the app class
53     (with different config etc each)
54   - Profit! (Things like changing the complete app config per vhost, i.e.
55     writing a config loader / app class role which dispatches per vhost to
56     differently configured apps is piss easy)
57
58 ## GSOC
59
60 ### Next large steps, planned:
61
62 For all components that have been discovered, in whatever way, we create a service:
63  - that's a catalyst component service
64  - which is basically just a constructor injection
65  - except the constructor name is COMPONENT
66  - and we're "implicitly" passing along some constructor args
67  - Lifecycle => Singleton
68
69  - Fix B::B so that Service::WithParametrs' parameters attribute has a builder
70  - Fix ConstructorInjection so that default parameters are supplied (for accept_context_args)
71  - Fix ConstructorInjection's 'suffix' - should be called 'config_key' or something, and
72    should be an attribute on the service (as it never changes), rather than a parameter
73    to the service 
74
75  - We make a 'components' sub container in the main container.
76    - This gets the ConstructorInjection COMPONENT services, as model_Foo.
77    - Lifecycle of these services is Singleton
78    - This simplifies the code for MyApp->components, as it need only list one sub-container
79
80  - We create a second service (depending on the first one) for ACCEPT_CONTEXT
81    - This has a custom service which calls ACCEPT_CONTEXT when the instance is fetched
82    - Not Singleton lifecycle
83  
84    Note - ACCEPT_CONTEXT can be called on app values - if you have a Model::Foo, with an ACCEPT_CONTEXT
85    and you call MyApp->model('Foo') then ACCEPT_CONTEXT gets invoked with a $c of 'MyApp' (this is not\
86    the normal case, but we need to preserve for compat)
87
88 ### Next steps - less planned:
89
90   - Creating service()-like sugar for component
91
92   - Test cases for extending the container in an application.
93     - Using the sugar added in the previous item
94     - Test when Model::Foo depends_on Model::Bar
95
96   - Tests for using the container outside of Catalyst
97     - Custom container which adds some (very simple) services which are initialized from
98       the application config file (note plain services, not components)
99     - Depend on (and test) these inside Catalyst
100     - Test loading container outside Catalyst, and these services working
101     - Test Catalyst / MyApp is not loaded
102
103 #### Extending my app, notes
104
105 Basically try to implement something like this (starting out without the sugar!), and see how it breaks
106 and what needs to be done to fix it!
107
108 ##### Eventual syntax
109
110 package MyApp::Container;
111 use Catalyst::IOC;
112     
113     container $self, as { 
114             container model => as {
115                 component Foo => (); # As per default!
116                 component Bar => (dependencies => ['/model/Foo']); # Magic!
117                 component Baz => ( lifecycle => 'InstancePerContext );
118                 component Quux => ( lifecycle => 'Singleton' ); # ACCEPT_CONTEXT not called
119             };                    
120             # Note - implementation of BB may need to be changed to support making sure existing 
121             # services actually get overridden. not sure how the default container behaves when doing that
122             # above code would build the constructor injection as it currently does,
123             # defaulting to the class name in the right namespace as declared by the surrounding container
124             # as well as adding using the catalyst-specific service class
125     };
126
127 1;
128
129 ##### To start with
130
131 package MyApp::Container;
132 use Moose;
133
134 extends 'Catalyst::Container;
135
136 after BUILD => sub {
137     my $self = shift;
138     my $model_container = $self->get_sub_container('model');
139     my $service = Catalyst::IOC::ConstructorInjection->new(
140         name      => 'Baz',
141         class     => 'MyApp::Model::Baz',
142         dependencies => [
143             depends_on( '/application_name' ),
144             depends_on( '/config' ),
145             depends_on( '/model/Foo' ),
146         ],
147         lifecycle => 'InstancePerContext',
148     );
149     $model_container->add_service( 'Foo', $service );
150 };
151
152 ### To polish off / t0m review
153
154     +Same as L<build_model_subcontainer>, but for controllers. The difference is
155     +that there is no ACCEPT_CONTEXT for controllers.
156     ^^ This is wrong!!
157     
158     -    my $accept_context_args = $self->param('accept_context_args');
159     +    my $accept_context_args = $params{accept_context_args};
160     ^^ This (may be) wrong! I am thinking the service should be allowed to mangle the 
161        accept_context args, no?
162        Without this change, the user could make a custom service which mangled the param, and use 
163        Catalyst/IOC/Service/WithAcceptContext.pm, with this change, that module will always see the
164        un-mangled version?? However, without this change, shit doesn't work...
165
166 ### Known issues
167
168     - Broken $instance->expand_modules() in setup_components and figure
169       out later how to bring it back
170
171     - expand_component_module
172
173     - People wrapping locate_components in Catalyst.pm