renaming application_name -> catalyst_application
[catagits/Catalyst-Runtime.git] / lib / Catalyst / IOC.pm
index 0c6ad6e..19e2c47 100644 (file)
@@ -1,84 +1,93 @@
 package Catalyst::IOC;
 use strict;
 use warnings;
-use Bread::Board;
+use Bread::Board qw/depends_on/;
 use Catalyst::IOC::ConstructorInjection;
 
-# FIXME - All of these imports need to get the importing package
-#         as the customise_container and current_container variables
-#         NEED to be in the containers package so there can be multiple
-#         containers..
 use Sub::Exporter -setup => {
     exports => [qw/
+        depends_on
         component
         model
+        view
+        controller
         container
     /],
     groups  => { default => [qw/
+        depends_on
         component
         model
+        view
+        controller
         container
     /]},
 };
-#use Sub::Exporter -setup => [
-#    qw(
-#        Bread::Board::as
-#        Bread::Board::container
-#        Bread::Board::depends_on
-#        Bread::Board::service
-#        Bread::Board::alias
-#        Bread::Board::wire_names
-#        Bread::Board::include
-#        Bread::Board::typemap
-#        Bread::Board::infer
-#    )
-#];
-# I'm probably doing it wrong.
-# Anyway, I'll just use Moose::Exporter. Do I really have to use Sub::Exporter?
-#use Moose::Exporter;
-#Moose::Exporter->setup_import_methods(
-#    also => ['Bread::Board'],
-#);
-our $customise_container;
-our $current_container;
 
 sub container (&) {
     my $code = shift;
-    $customise_container = sub {
-        warn("In customise container");
-        local $current_container = shift();
+    my $caller = caller;
+
+    no strict 'refs';
+    ${"${caller}::customise_container"} = sub {
+        local ${"${caller}::current_container"} = shift;
         $code->();
     };
 }
 
-sub model (&) {
+sub model (&)      { &_subcontainer }
+sub view (&)       { &_subcontainer }
+sub controller (&) { &_subcontainer }
+
+sub _subcontainer {
     my $code = shift;
-    local $current_container = $current_container->get_sub_container('model');
+
+    my ( $caller, $f, $l, $subcontainer ) = caller(1);
+    $subcontainer =~ s/^Catalyst::IOC:://;
+
+    no strict 'refs';
+    local ${"${caller}::current_container"} =
+        ${"${caller}::current_container"}->get_sub_container($subcontainer);
     $code->();
 }
 
-sub component {
+sub component ($;%) {
     my ($name, %args) = @_;
+    my $current_container;
+
+    {
+        no strict 'refs';
+        my $caller = caller;
+        $current_container = ${"${caller}::current_container"};
+    }
+
     $args{dependencies} ||= {};
-    $args{dependencies}{application_name} = depends_on( '/application_name' );
+    $args{dependencies}{catalyst_application} = depends_on( '/catalyst_application' );
+
+    my $lifecycle    = $args{lifecycle} || 'Singleton';
+    $args{lifecycle} = grep( m/^$lifecycle$/, qw/COMPONENTSingleton Request/ )
+                     ? "+Catalyst::IOC::LifeCycle::$lifecycle"
+                     : $lifecycle
+                     ;
 
     # FIXME - check $args{type} here!
 
-    my $service = Catalyst::IOC::ConstructorInjection->new(
-        %args,
-        name             => $name,
-        lifecycle        => 'Singleton',
-        # XX FIXME - needs to become possible to intuit catalyst_component_name
-        #            from dependencies (like config)
-        catalyst_component_name => 'TestAppCustomContainer::Model::Bar',
+    my $component_name = join '::', (
+        $current_container->resolve(service => '/catalyst_application'),
+        ucfirst($current_container->name),
+        $name
+    );
+
+    $current_container->add_service(
+        Catalyst::IOC::ConstructorInjection->new(
+            %args,
+            name => $name,
+            catalyst_component_name => $component_name,
+        )
     );
-    $current_container->add_service($service);
 }
 
 1;
 
-# FIXME - should the code example below be on this file or Catalyst::IOC::Container?
-
 __END__
 
 =pod
@@ -90,43 +99,69 @@ Catalyst::IOC - IOC for Catalyst, based on Bread::Board
 =head1 SYNOPSIS
 
     package MyApp::Container;
+    use Moose;
     use Catalyst::IOC;
+    extends 'Catalyst::IOC::Container';
+
+    container {
+        model {
+            # default component
+            component Foo => ();
+
+            # model Bar needs model Foo to be built before
+            # and Bar's constructor gets Foo as a parameter
+            component Bar => ( dependencies => [
+                depends_on('/model/Foo'),
+            ]);
+
+            # Baz is rebuilt once per HTTP request
+            component Baz => ( lifecycle => 'Request' );
+
+            # built only once per application life time
+            component Quux => ( lifecycle => 'Singleton' );
+
+            # built once per app life time and uses an external model,
+            # outside the default directory
+            # no need for wrappers or Catalyst::Model::Adaptor
+            component Fnar => (
+                lifecycle => 'Singleton',
+                class => 'My::External::Class',
+            );
+        };
+        view {
+            component HTML => ();
+        };
+        controller {
+            component Root => ();
+        };
+    }
 
-    sub BUILD {
-        my $self = shift;
+=head1 DESCRIPTION
 
-        container $self => as {
-            container model => as {
+Catalyst::IOC provides "sugar" methods to extend the behavior of the default
+Catalyst container.
 
-                # default component
-                component Foo => ();
+=head1 METHODS
 
-                # model Bar needs model Foo to be built before
-                # and Bar's constructor gets Foo as a parameter
-                component Bar => ( dependencies => [
-                    depends_on('/model/Foo'),
-                ]);
+=head2 container
 
-                # Baz is rebuilt once per HTTP request
-                component Baz => ( lifecycle => 'Request' );
+Sets up the root container to be customised.
 
-                # built only once per application life time
-                component Quux => ( lifecycle => 'Singleton' );
+=head2 model
 
-                # built once per app life time and uses an external model,
-                # outside the default directory
-                # no need for wrappers or Catalyst::Model::Adaptor
-                component Fnar => (
-                    lifecycle => 'Singleton',
-                    class => 'My::External::Class',
-                );
-            };
-        }
-    }
+Sets up the model container to be customised.
 
-=head1 DESCRIPTION
+=head2 view
 
-=head1 METHODS
+Sets up the view container to be customised.
+
+=head2 controller
+
+Sets up the controller container to be customised.
+
+=head2 component
+
+Adds a component to the sub-container. Works like L<Bread::Board::service>.
 
 =head1 AUTHORS