Real Life Example
file: code/validad/BreadBoard.pm
1: package Winxle::BreadBoard;
2: use Moose;
3: use 5.012;
4: use Bread::Board;
5: use Class::Load;
6:
7: sub setup {
8: my ( $class, $env_class_name, @rest ) = @_;
9:
10: my $env_class = 'Winxle::BreadBoard::Env::' . $env_class_name;
11: Class::Load::load_class($env_class);
12: my $env = $env_class->new( name => $env_class_name );
13:
14: my $apps = container $class => ['Environment'] => as {
15: container 'App' => as {
16: service 'renderservice_worker' => (
17: class => 'Winxle::Service::Render::Worker',
18: dependencies => {
19: yp => '/Environment/yp_client',
20: coder => '/Environment/json_coder',
21: data_provider => '/Environment/data_provider',
22: renderer => '/Environment/TTnowrap',
23: localizer => '/Environment/localizer',
24: root_dir => '/Component/Path/root',
25: } );
26: service 'yp_server' => (
27: class => 'ZMQx::YellowPages::Server',
28: dependencies =>
29: { address => '/Environment/yp_server_address', },
30: parameters => {
31: reset_service_store => { isa=>'Bool',default=>0 },
32: }
33: );
34: service 'renderservice_ventilator' => (
35: class => 'Winxle::Service::Render::Ventilator',
36: dependencies => { yp => '/Environment/yp_client' } );
37:
38: service 'web' => (
39: class => 'Winxle::Web',
40: dependencies => {
41: yp => '/Environment/yp_client',
42: renderer => '/Environment/TT',
43: renderer_nowrap => '/Environment/TTnowrap',
44: dbic => '/Component/DB/schema',
45: static_dir => '/Component/Path/static',
46: session_store => '/Component/Cache/session_store',
47: session_state => '/Component/Cache/session_state_web',
48: localizer => '/Environment/localizer',
49: json => '/Environment/json_coder',
50: kioku => '/Component/DataProvider/Kioku/dir',
51: config => '/Component/Config/config',
52: } );
53: service 'admin' => (
54: class => 'Winxle::Admin',
55: dependencies => {
56: renderer => '/Environment/AdminTT',
57: renderer_nowrap => '/Environment/AdminTTnowrap',
58: dbic => '/Component/DB/schema',
59: static_dir => '/Component/Path/static',
60: session_store => '/Component/Cache/session_store',
61: session_state => '/Component/Cache/session_state_admin',
62: localizer => '/Component/I18N/dummy',#'/Environment/localizer',
63: json => '/Environment/json_coder',
64: kioku => '/Component/DataProvider/Kioku/dir',
65: config => '/Component/Config/config',
66: spreader_client => '/Component/ZMQ/spreader_client',
67: } );
68:
69: service 'campaignspread' => (
70: class => 'Winxle::Service::CampaignSpread::Server',
71: dependencies => {
72: yp => '/Environment/yp_client',
73: dbh => '/Component/DB/dbh',
74: renderer => '/Environment/TTnowrap',
75: root_dir => '/Component/Path/root',
76: } );
77: service 'l10n_service_backend' => (
78: class => 'I18N::GlueKit::LocalizerService',
79: dependencies => {
80: yp => '/Environment/yp_client',
81: dbh => '/Component/DB/dbh',
82: cache => '/Component/Cache/CHI',
83: } );
84: service 'mailer' => (
85: class=>'Winxle::Service::Mailer',
86: dependencies => {
87: schema => '/Component/DB/schema',
88: renderer => '/Environment/TTnowrap',
89: localizer => '/Environment/localizer',
90: config => '/Component/Config/config',
91: }
92: );
93: };
94:
95: # use include
96: container 'Component' => as {
97: container 'Path' => as {
98: service 'home' => (
99: class => 'Path::Class::Dir',
100: lifecycle => 'Singleton',
101: block => sub {
102: ( my $pck = __PACKAGE__ . ".pm" ) =~ s{::}{/}g;
103: my $app_home = $INC{$pck};
104: $app_home =~ s{/lib/$pck$}{};
105: return Path::Class::Dir->new($app_home);
106: },
107: );
108: service 'root' => (
109: class => 'Path::Class::Dir',
110: lifecycle => 'Singleton',
111: block => sub {
112: my $s = shift;
113: return $s->param('home')->subdir(qw(root));
114: },
115: dependencies => ['home'],
116: );
117: service 'templates' => (
118: class => 'Path::Class::Dir',
119: lifecycle => 'Singleton',
120: block => sub {
121: my $s = shift;
122: return $s->param('home')->subdir(qw(root tt));
123: },
124: dependencies => ['home'],
125: );
126: service 'admin_templates' => (
127: class => 'Path::Class::Dir',
128: lifecycle => 'Singleton',
129: block => sub {
130: my $s = shift;
131: return $s->param('home')->subdir(qw(root admin_tt));
132: },
133: dependencies => ['home'],
134: );
135: service 'static' => (
136: class => 'Path::Class::Dir',
137: lifecycle => 'Singleton',
138: block => sub {
139: my $s = shift;
140: return $s->param('home')->subdir(qw(root static));
141: },
142: dependencies => ['home'],
143: );
144: };
145: container 'JSON' => as {
146: service 'pretty' => (
147: class => 'JSON::XS',
148: lifecycle => 'Singleton',
149: block => sub {
150: return JSON::XS->new->pretty->allow_nonref;
151: },
152: );
153: service 'terse' => (
154: class => 'JSON::XS',
155: lifecycle => 'Singleton',
156: block => sub {
157: return JSON::XS->new->allow_nonref;
158: },
159: );
160: };
161: container 'Cache' => as {
162: service 'CHI' => (
163: class => 'CHI',
164: lifecycle => 'Singleton',
165: dependencies => {
166: driver => service( driver => "FastMmap" ),
167: root_dir => service(
168: root_dir => "/tmp/chi-driver-fastmmap-$<"
169: ),
170: } );
171: service 'session_store' => (
172: class => "Plack::Session::Store::Cache",
173: lifecycle => 'Singleton',
174: dependencies => { cache => 'CHI', },
175: );
176: service 'session_state_web' => (
177: class => "Plack::Session::State::Cookie",
178: lifecycle => 'Singleton',
179: dependencies => { session_key=>service( session_key=>'winxle_web') },
180: );
181: service 'session_state_admin' => (
182: class => "Plack::Session::State::Cookie",
183: lifecycle => 'Singleton',
184: dependencies => { session_key=>service( session_key=>'winxle_admin') },
185: );
186: };
187: container 'TT' => as {
188: service 'default_params' => (
189: lifecycle => "Singleton",
190: dependencies =>
191: { include_path => '/Component/Path/templates', },
192: block => sub {
193: my $s = shift;
194: return {
195: TEMPLATE_EXTENSION => ".tt",
196: ERROR => 'site/error.tt',
197: TIMER => 0,
198: ENCODING => 'utf-8',
199: CLASS => "Template::AutoFilter",
200: PRE_PROCESS => 'site/macros.tt',
201: INCLUDE_PATH => [ $s->param('include_path') ],
202: };
203: },
204: );
205: service 'wrapped' => (
206: lifecycle => "Singleton",
207: class => 'Template::AutoFilter',
208: block => sub {
209: my $s = shift;
210: my %param = %{ $s->param('default_params') };
211: return Template::AutoFilter->new( %param,
212: WRAPPER => 'site/wrapper.tt', );
213: },
214: dependencies => ['default_params'],
215: );
216: service 'nowrap' => (
217: lifecycle => "Singleton",
218: class => 'Template::AutoFilter',
219: block => sub {
220: my $s = shift;
221: my %param = %{ $s->param('default_params') };
222: return Template::AutoFilter->new( %param, );
223: },
224: dependencies => ['default_params'],
225: );
226: };
227: container 'AdminTT' => as { # TODO too much copy from TT!
228: service 'default_params' => (
229: lifecycle => "Singleton",
230: dependencies =>
231: { include_path => '/Component/Path/admin_templates', },
232: block => sub {
233: my $s = shift;
234: return {
235: TEMPLATE_EXTENSION => ".tt",
236: ERROR => 'site/error.tt',
237: TIMER => 0,
238: ENCODING => 'utf-8',
239: CLASS => "Template::AutoFilter",
240: PRE_PROCESS => 'site/macros.tt',
241: INCLUDE_PATH => [ $s->param('include_path') ],
242: };
243: },
244: );
245: service 'wrapped' => (
246: lifecycle => "Singleton",
247: class => 'Template::AutoFilter',
248: block => sub {
249: my $s = shift;
250: my %param = %{ $s->param('default_params') };
251: return Template::AutoFilter->new( %param,
252: WRAPPER => 'site/wrapper.tt', );
253: },
254: dependencies => ['default_params'],
255: );
256: service 'nowrap' => (
257: lifecycle => "Singleton",
258: class => 'Template::AutoFilter',
259: block => sub {
260: my $s = shift;
261: my %param = %{ $s->param('default_params') };
262: return Template::AutoFilter->new( %param, );
263: },
264: dependencies => ['default_params'],
265: );
266: };
267: container 'Renderer' => as {
268: service 'TT' => (
269: class => 'Winxle::Render::TT',
270: lifecycle => "Singleton",
271: dependencies => {
272: tt => '/Component/TT/wrapped',
273: localizer => '/Environment/localizer',
274: } );
275: service 'TTnowrap' => (
276: class => 'Winxle::Render::TT',
277: lifecycle => "Singleton",
278: dependencies => {
279: tt => '/Component/TT/nowrap',
280: localizer => '/Environment/localizer',
281: } );
282: service 'AdminTT' => (
283: class => 'Winxle::Render::TT',
284: lifecycle => "Singleton",
285: dependencies => {
286: tt => '/Component/AdminTT/wrapped',
287: localizer => '/Environment/localizer',
288: } );
289: service 'AdminTTnowrap' => (
290: class => 'Winxle::Render::TT',
291: lifecycle => "Singleton",
292: dependencies => {
293: tt => '/Component/AdminTT/nowrap',
294: localizer => '/Environment/localizer',
295: } );
296: };
297: container 'DB' => as {
298: service 'db_connect' => (
299: lifecycle => "Singleton",
300: class => "Winxle::DB::Connect",
301: );
302: service 'schema' => (
303: lifecycle => "Singleton",
304: block => sub {
305: my $s = shift;
306: return $s->param('db_connect')->schema;
307: },
308: dependencies => ['db_connect'],
309: );
310: service 'dbh' => (
311: lifecycle => "Singleton",
312: block => sub {
313: my $s = shift;
314: return $s->param('db_connect')->dbh;
315: },
316: dependencies => ['db_connect'],
317: );
318: service 'dsn' => (
319: lifecycle => "Singleton",
320: block => sub {
321: my $s = shift;
322: return $s->param('db_connect')->dsn;
323: },
324: dependencies => ['db_connect'],
325: );
326: };
327: container 'DataProvider' => as {
328: container 'GoogleSpreadsheet' => as {
329: service 'username' => 'username@gmail.com';
330: service 'password' => '12345';
331: service 'document' =>
332: 'Ohnae8edae3Ee7Othi6x';
333: service 'spreadsheet' => (
334: class => 'Winxle::DataProvider::GoogleSpreadsheet',
335: dependencies => {
336: username => depends_on('username'),
337: password => depends_on('password'),
338: document => depends_on('document'),
339: } );
340: };
341: container 'Kioku' => as {
342: service 'dir' => (
343: class => 'KiokuDB',
344: block => sub {
345: my $s = shift;
346: return KiokuDB->connect(
347: $s->param('dsn'),
348: typemap=>$s->param('typemap'),
349: );
350: },
351: dependencies => {
352: dsn=> '/Component/DB/dsn',
353: typemap => 'typemap'
354: },
355: );
356: service 'typemap' => (
357: class=>'KiokuDB::TypeMap',
358: block=>sub {
359: Class::Load::load_class('KiokuDB::TypeMap::Entry::Naive');
360: my $i = KiokuDB::TypeMap::Entry::Naive->new(
361: intrinsic=>1
362: );
363:
364: return KiokuDB::TypeMap->new(
365: isa_entries => {
366: 'Winxle::DataWrapper::Intrinsic' => $i,
367: },
368: );
369: },
370: );
371: };
372: };
373: container 'I18N' => as {
374: service 'backend_zmq' => (
375: class => 'I18N::GlueKit::Localizer::BackendZMQ',
376: dependencies => { yp => '/Environment/yp_client', } );
377: service 'localizer_zmq' => (
378: class => 'I18N::GlueKit::Localizer',
379: dependencies => {
380: localizer_backend => 'backend_zmq',
381: cache => '/Component/Cache/CHI',
382: } );
383: service 'data_localize' => (
384: class => "I18N::GlueKit::Localize",
385: service_type => "Setter",
386: dependencies =>
387: { add_localizer => depends_on('localizer_zmq'), },
388: );
389: service 'dummy' => (
390: class=>'Winxle::DummyLocalizer',
391: lifecycle => "Singleton",
392: );
393: };
394: container 'ZMQ' => as {
395: service 'spreader_client' => (
396: class=>'Winxle::Service::CampaignSpread::Client',
397: dependencies=> {
398: yp => '/Environment/yp_client',
399: },
400: );
401: };
402: container 'Config' => as {
403: service 'config' => (
404: lifecycle => "Singleton",
405: class=>'Config::JFDI',
406: dependencies => {
407: name=>service( name => "winxle" ),
408: path=>'/Component/Path/home',
409: },
410: );
411: }
412: };
413: };
414:
415: my $bb = $apps->create( 'Environment' => $env, @rest );
416: return $bb;
417: }
418:
419: 1;