Well, thats dynamic model class loading from 100% config, with tests. Should be CPANa...
t0m [Wed, 22 Apr 2009 22:31:06 +0000 (23:31 +0100)]
Makefile.PL
dynamicappdemo.conf [deleted file]
dynamicappdemo.yml [new file with mode: 0644]
lib/CatalystX/ModelsFromConfig.pm [new file with mode: 0644]
lib/DynamicAppDemo.pm
lib/SomeModelClass.pm [new file with mode: 0644]
t/04_dynamicmodel.t [new file with mode: 0644]

index a242a27..ac6aff0 100644 (file)
@@ -5,7 +5,8 @@ use inc::Module::Install;
 name 'DynamicAppDemo';
 all_from 'lib/DynamicAppDemo.pm';
 
-requires 'Catalyst::Runtime' => '5.80002';
+requires 'Catalyst::Model::Adaptor';
+requires 'Catalyst::Runtime' => '5.80001';
 requires 'Catalyst::Plugin::ConfigLoader';
 requires 'YAML';
 
diff --git a/dynamicappdemo.conf b/dynamicappdemo.conf
deleted file mode 100644 (file)
index 60ec4d7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# rename this file to DynamicAppDemo.yml and put a : in front of "name" if
-# you want to use yaml like in old versions of Catalyst
-name DynamicAppDemo
diff --git a/dynamicappdemo.yml b/dynamicappdemo.yml
new file mode 100644 (file)
index 0000000..5dbc1db
--- /dev/null
@@ -0,0 +1,4 @@
+---
+name: DynamicAppDemo
+Model::One:
+    class: SomeModelClass
diff --git a/lib/CatalystX/ModelsFromConfig.pm b/lib/CatalystX/ModelsFromConfig.pm
new file mode 100644 (file)
index 0000000..4e0cb3a
--- /dev/null
@@ -0,0 +1,52 @@
+package CatalystX::ModelsFromConfig;
+use Moose::Role;
+use Catalyst::Model::Adaptor ();
+
+requires qw/
+    config
+    setup_components
+    setup_component
+/;
+
+after 'setup_components' => sub { shift->_setup_dynamic_models(@_); };
+
+sub _setup_dynamic_models {
+    my ($app) = @_;
+    
+    my $app_name = blessed($app) || $app;
+    my $model_prefix = 'Model::';
+
+    my $model_hash = $app->config || {};
+    
+    foreach my $model_name ( grep { /^$model_prefix/ } keys %$model_hash ) {
+        my $model_class_name = $app_name . '::' . $model_name;
+        $app->_setup_dynamic_model( $model_class_name, $model_hash->{$model_name} );
+    }
+}
+
+sub _setup_dynamic_model {
+    my ($app, $name, $config) = @_;
+    
+    my $meta = Moose->init_meta( for_class => $name );
+    $meta->superclasses('Catalyst::Model');
+    
+    $meta->add_method( 
+
+      COMPONENT 
+            => sub {
+        my ($model_class_name, $app, $args) = @_;
+        
+        my $class = delete $args->{class};
+        Class::MOP::load_class($class);
+        
+        $class->new($args);
+    });
+
+    $meta->make_immutable;
+
+    my $instance = $app->setup_component($name);
+    $app->components->{ $name } = $instance;
+}
+
+1;
+
index a1714f4..c98596d 100644 (file)
@@ -9,6 +9,10 @@ use Catalyst qw/
 
 extends 'Catalyst';
 
+with qw/
+    CatalystX::ModelsFromConfig
+/;
+
 our $VERSION = '0.01';
 
 __PACKAGE__->config( name => 'DynamicAppDemo' );
diff --git a/lib/SomeModelClass.pm b/lib/SomeModelClass.pm
new file mode 100644 (file)
index 0000000..dbe0c26
--- /dev/null
@@ -0,0 +1,17 @@
+package SomeModelClass;
+use Moose;
+use namespace::clean -except => 'meta';
+
+# Note trivial calling convention.
+# Apply MX::Method::Signatures and MX::Types::Structured to be less lame.
+
+# Introspection should only reflect methods which satisfy the calling convention
+# This is left as an exercise to the reader. :)
+
+sub say_hello {
+    my ($self, $name) = @_;
+    return("Hello $name");
+}
+
+__PACKAGE__->meta->make_immutable;
+
diff --git a/t/04_dynamicmodel.t b/t/04_dynamicmodel.t
new file mode 100644 (file)
index 0000000..9386187
--- /dev/null
@@ -0,0 +1,13 @@
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+use DynamicAppDemo;
+
+# Naughty, should make an app instance.
+my $model = DynamicAppDemo->model('One');
+
+ok $model;
+isa_ok $model, 'SomeModelClass';
+is $model->say_hello('world'), 'Hello world';
+