on-demand ->new to make run_if_script safer
Matt S Trout [Tue, 18 Nov 2014 19:37:17 +0000 (19:37 +0000)]
lib/Web/Simple/Application.pm
t/run_if_script.t

index 68f8b2c..84937a2 100644 (file)
@@ -52,20 +52,11 @@ sub _build_final_dispatcher {
 sub run_if_script {
   my ( $self, @args ) = @_;
   # ->to_psgi_app is true for require() but also works for plackup
-  return $self->to_psgi_app if caller(1);
-  $self = ref($self) ? $self : $self->_build_for_run_if_script(@args);
+  return $self->to_psgi_app(@args) if caller(1);
+  $self = ref($self) ? $self : $self->new(@args);
   $self->run;
 }
 
-sub _build_for_run_if_script {
-  my ( $self, @args ) = @_;
-  try { $self->new(@args) }
-  catch {
-    die "Failed to create new '$self' object during run_if_script"
-      . " (should your .pm file end with just '1;'?) : $_\n";
-  };
-}
-
 sub _run_cgi {
   my $self = shift;
   require Plack::Handler::CGI;
@@ -79,7 +70,20 @@ sub _run_fcgi {
 }
 
 sub to_psgi_app {
-  my $self = ref($_[0]) ? $_[0] : $_[0]->new;
+  my ($invocant, @args) = @_;
+
+  unless (ref($invocant)) {
+    my $app;
+    return sub {
+      $app ||= do {
+        try { $invocant->new(@args)->to_psgi_app }
+        catch { die "Failed to auto-create new ${invocant} object for to_psgi_app: $_"; }
+      };
+      $app->(@_);
+    };
+  }
+
+  my $self = $invocant;
   my $app = $self->_dispatcher->to_app;
 
   # Close over $self to keep $self alive even though
@@ -364,8 +368,9 @@ a separate C<*.psgi> file -
     mount '/another' => AnotherWSApp->to_psgi_app;
   };
 
-This method can be called as a class method, in which case it implicitly
-calls ->new, or as an object method ... in which case it doesn't.
+This method can be called as a class method, in which case it will implicitly
+call ->new when the PSGI coderef is first invoked, or as an object method ...
+in which case it doesn't.
 
 =head2 run
 
index 0839046..f0157a0 100644 (file)
@@ -49,8 +49,8 @@ is(
 );
 
 like(
-    exception { DieTest->_build_for_run_if_script },    #
-    qr/^Failed to create new 'DieTest' object during/,
+    exception { DieTest->run_if_script->() },    #
+    qr/^Failed to auto-create new DieTest object/,
     "object creation in run_if_script decorates failure with useful information"
 );