AUTOLOAD method

"Vadim O. Ustiansky" <[email protected]>
Newsgroups gmane.comp.web.mason.devel
Message-ID <[email protected]>
Dear developers,

I would like Mason to have the possibility to handle non-existent
methods in a way, similar to perl's AUTOLOAD. In particular one
may want to be able to write components like the following:

  ...
% $m->comp('SELF:foo');
% $m->comp('SELF:bar');
  ...
<%method AUTOLOAD>
<%perl>
  my $method_name = $m->autoload();
  if($method_name eq 'foo'){
    # handle call SELF:foo
  }elsif($method_name eq 'bar'){
    # handle call SELF:bar
  }
</%perl>
</%method>

The attached patch seems to implement this feature.

I would like to here your opinion on this topic.

-- 
Yours sincerely,
Vadim.
p4 (text/plain, 5.4 KB)
diff -ur mason.orig/dist/lib/HTML/Mason/Component.pm mason.4/dist/lib/HTML/Mason/Component.pm
--- mason.orig/dist/lib/HTML/Mason/Component.pm	2004-05-25 17:33:49.000000000 +0400
+++ mason.4/dist/lib/HTML/Mason/Component.pm	2004-06-05 12:57:15.000000000 +0400
@@ -250,8 +250,12 @@
 sub call_method {
     my ($self,$name,@args) = @_;
     my $method;
+    my $m = HTML::Mason::Request->instance();
     if ($self->_locate_inherited('methods',$name,\$method)) {
-	HTML::Mason::Request->instance->comp({base_comp=>$self},$method,@args);
+	$m->comp({base_comp=>$self},$method,@args);
+    } elsif ($m->use_autoload() && $self->_locate_inherited('methods','AUTOLOAD',\$method)) {
+	$m->_set_autoload($name);
+	$m->comp({base_comp=>$self},$method,@args);
     } else {
 	error "no method '$name' for component " . $self->title;
     }
@@ -263,8 +267,12 @@
 sub scall_method {
     my ($self,$name,@args) = @_;
     my $method;
+    my $m = HTML::Mason::Request->instance();
     if ($self->_locate_inherited('methods',$name,\$method)) {
-	HTML::Mason::Request->instance->scomp({base_comp=>$self},$method,@args);
+	$m->scomp({base_comp=>$self},$method,@args);
+    } elsif ($m->use_autoload() && $self->_locate_inherited('methods','AUTOLOAD',\$method)) {
+	$m->_set_autoload($name);
+	$m->comp({base_comp=>$self},$method,@args);
     } else {
 	error "no method '$name' for component " . $self->title;
     }
diff -ur mason.orig/dist/lib/HTML/Mason/Interp.pm mason.4/dist/lib/HTML/Mason/Interp.pm
--- mason.orig/dist/lib/HTML/Mason/Interp.pm	2004-05-25 17:33:49.000000000 +0400
+++ mason.4/dist/lib/HTML/Mason/Interp.pm	2004-06-05 13:22:09.000000000 +0400
@@ -115,6 +115,7 @@
 				  [ error_mode => { type => SCALAR } ],
 				  [ max_recurse => { type => SCALAR } ],
 				  [ out_method => { type => SCALARREF | CODEREF } ],
+				  [ use_autoload => { type => SCALAR | UNDEF } ],
 				]
 			      },
       );
diff -ur mason.orig/dist/lib/HTML/Mason/Request.pm mason.4/dist/lib/HTML/Mason/Request.pm
--- mason.orig/dist/lib/HTML/Mason/Request.pm	2004-05-25 17:33:49.000000000 +0400
+++ mason.4/dist/lib/HTML/Mason/Request.pm	2004-06-05 13:07:34.000000000 +0400
@@ -127,6 +127,10 @@
            public  => 0,
          },
 
+	 use_autoload =>
+         { parse => 'boolean', type => SCALAR|UNDEF, optional => 1,
+           descr => "Whether AUTOLOAD methods available" },
+
         );
 
     __PACKAGE__->contained_objects
@@ -145,9 +149,11 @@
 				 error_format
 				 error_mode
                                  max_recurse
-                                 out_method ); }
+                                 out_method
+                                 use_autoload ); }
 use HTML::Mason::MethodMaker
     ( read_only => [ qw( count
+			 autoload
 			 dhandler_arg
 			 interp
 			 parent_request
@@ -167,6 +173,7 @@
     my $self = $class->SUPER::new(@_);
 
     %$self = (%$self, buffer_stack => undef,
+		      autoload => undef,
 		      count => 0,
 		      dhandler_arg => undef,
 	              execd => 0,
@@ -271,6 +278,12 @@
     return defined $self->{dhandler_name} and length $self->{dhandler_name};
 }
 
+sub _set_autoload
+{
+    my $self = shift;
+    $self->{autoload} = shift;
+}
+
 sub alter_superclass
 {
     my $self = shift;
@@ -927,8 +940,14 @@
 	my ($owner_path,$method_name) = split(':',$path,2);
 	my $owner_comp = $self->fetch_comp($owner_path)
 	    or error "could not find component for path '$owner_path'\n";
-	$owner_comp->_locate_inherited('methods',$method_name,\$method_comp)
-	    or error "no method '$method_name' for component " . $owner_comp->title;
+	unless ($owner_comp->_locate_inherited('methods',$method_name,\$method_comp)) {
+	    if ($self->use_autoload() && $self->{_fetch_autoload_method} &&
+		$owner_comp->_locate_inherited('methods','AUTOLOAD',\$method_comp)) {
+		$self->_set_autoload($method_name);
+	    } else {
+		error "no method '$method_name' for component " . $owner_comp->title;
+	    }
+	}
 	return $method_comp;
     }
 
@@ -1059,9 +1078,12 @@
     #
     my $path;
     if (!ref($comp)) {
+	my $store = $self->{_fetch_autoload_method};
+	$self->{_fetch_autoload_method} = 1;
 	$path = $comp;
 	$comp = $self->fetch_comp($path)
 	    or error "could not find component for path '$path'\n";
+	$self->{_fetch_autoload_method} = $store;
     }
 
     #
diff -ur mason.orig/dist/t/09-component.t mason.4/dist/t/09-component.t
--- mason.orig/dist/t/09-component.t	2004-05-25 17:33:50.000000000 +0400
+++ mason.4/dist/t/09-component.t	2004-06-05 13:41:48.000000000 +0400
@@ -463,6 +463,28 @@
 
 #------------------------------------------------------------
 
+    $group->add_test( name => 'autoload_methods',
+		      interp_params => { use_autoload => 1 },
+		      description => 'Test that AUTOLOAD method works',
+		      component => <<'EOF',
+% $m->base_comp()->call_method('foo');
+<& SELF:bar, arg => 1 &>
+
+<%method AUTOLOAD>
+% my $method_name = $m->autoload();
+Called method: <% $method_name %>, <% join(',', @_) %>.
+</%method>
+EOF
+		      expect => <<'EOF',
+
+Called method: foo, .
+
+Called method: bar, arg,1.
+EOF
+		    );
+
+#------------------------------------------------------------
+
     $group->add_test( name => 'modification_read_only_arg',
 		      description => 'Test that read-only argument cannot be modified through @_',
 		      component => <<'EOF',
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.