You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2011/05/05 16:33:36 UTC

svn commit: r1099823 - in /spamassassin/trunk: lib/Mail/SpamAssassin/Conf.pm lib/Mail/SpamAssassin/Conf/Parser.pm lib/Mail/SpamAssassin/Plugin/Test.pm t/if_can.t

Author: mmartinec
Date: Thu May  5 14:33:35 2011
New Revision: 1099823

URL: http://svn.apache.org/viewvc?rev=1099823&view=rev
Log:
Bug 6581: Add a rules conditional function has(), similar to can()

Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Test.pm
    spamassassin/trunk/t/if_can.t

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm?rev=1099823&r1=1099822&r2=1099823&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Thu May  5 14:33:35 2011
@@ -3595,12 +3595,24 @@ C<3.004080>.
 This is a function call that returns C<1> if the plugin named
 C<Name::Of::Plugin> is loaded, or C<undef> otherwise.
 
-=item can(Name::Of::Package::function_name)
+=item has(Name::Of::Package::function_name)
 
 This is a function call that returns C<1> if the perl package named
 C<Name::Of::Package> includes a function called C<function_name>, or C<undef>
 otherwise.  Note that packages can be SpamAssassin plugins or built-in classes,
-there's no difference in this respect.
+there's no difference in this respect.  Internally this invokes UNIVERSAL::can.
+
+=item can(Name::Of::Package::function_name)
+
+This is a function call that returns C<1> if the perl package named
+C<Name::Of::Package> includes a function called C<function_name>
+B<and> that function returns a true value when called with no arguments,
+otherwise C<undef> is returned.
+
+Is similar to C<has>, except that it also calls the named function,
+testing its return value (unlike the perl function UNIVERSAL::can).
+This makes it possible for a 'feature' function to determine its result
+value at run time.
 
 =back
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm?rev=1099823&r1=1099822&r2=1099823&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf/Parser.pm Thu May  5 14:33:35 2011
@@ -497,12 +497,16 @@ sub handle_conditional {
       $eval .= $u . " ";
     }
     elsif ($token eq 'plugin') {
-      # replace with method call
-      $eval .= "\$self->cond_clause_plugin_loaded";
+      # replace with a method call
+      $eval .= '$self->cond_clause_plugin_loaded';
     }
     elsif ($token eq 'can') {
-      # replace with method call
-      $eval .= "\$self->cond_clause_can";
+      # replace with a method call
+      $eval .= '$self->cond_clause_can';
+    }
+    elsif ($token eq 'has') {
+      # replace with a method call
+      $eval .= '$self->cond_clause_has';
     }
     elsif ($token eq 'version') {
       $eval .= $Mail::SpamAssassin::VERSION." ";
@@ -544,16 +548,31 @@ sub cond_clause_plugin_loaded {
 
 sub cond_clause_can {
   my ($self, $method) = @_;
+  $self->cond_clause_can_or_has('can', $method);
+}
+
+sub cond_clause_has {
+  my ($self, $method) = @_;
+  $self->cond_clause_can_or_has('has', $method);
+}
+
+sub cond_clause_can_or_has {
+  my ($self, $fn_name, $method) = @_;
 
   local($1,$2);
-  if ($method =~ /^(.*)::([^:]+)$/) {
+  if (!defined $method) {
+    $self->lint_warn("bad 'if' line, no argument to $fn_name(), ".
+                     "in \"$self->{currentfile}\"", undef);
+  } elsif ($method =~ /^(.*)::([^:]+)$/) {
     no strict "refs";
     my($module, $meth) = ($1, $2);
-    return UNIVERSAL::can($module,$meth) && &{$method}();
+    return 1  if UNIVERSAL::can($module,$meth) &&
+                 ( $fn_name eq 'has' || &{$method}() );
   } else {
-    $self->lint_warn("bad 'if' line, cannot find '::' in can($method), ".
-                "in \"$self->{currentfile}\"", undef);
+    $self->lint_warn("bad 'if' line, cannot find '::' in $fn_name($method), ".
+                     "in \"$self->{currentfile}\"", undef);
   }
+  return undef;
 }
 
 # Let's do some linting here ...

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Test.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Test.pm?rev=1099823&r1=1099822&r2=1099823&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Test.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/Test.pm Thu May  5 14:33:35 2011
@@ -69,4 +69,7 @@ sub check_test_plugin {
   return 1;
 }
 
+sub test_feature_xxxx_false { undef }
+sub test_feature_xxxx_true  { 1 }
+
 1;

Modified: spamassassin/trunk/t/if_can.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/if_can.t?rev=1099823&r1=1099822&r2=1099823&view=diff
==============================================================================
--- spamassassin/trunk/t/if_can.t (original)
+++ spamassassin/trunk/t/if_can.t Thu May  5 14:33:35 2011
@@ -2,33 +2,67 @@
 
 use lib '.'; use lib 't';
 use SATest; sa_t_init("if_can");
-use Test; BEGIN { plan tests => 5 };
+use Test; BEGIN { plan tests => 13 };
 
 # ---------------------------------------------------------------------------
 
 %patterns = (
 
         q{ GTUBE }, 'gtube',
-        q{ SHOULD_BE_CALLED }, 'should_be_called',
+        q{ SHOULD_BE_CALLED1 }, 'should_be_called1',
+        q{ SHOULD_BE_CALLED2 }, 'should_be_called2',
+        q{ SHOULD_BE_CALLED3 }, 'should_be_called3',
+        q{ SHOULD_BE_CALLED4 }, 'should_be_called4',
+        q{ SHOULD_BE_CALLED5 }, 'should_be_called5',
+        q{ SHOULD_BE_CALLED6 }, 'should_be_called6',
+        q{ SHOULD_BE_CALLED7 }, 'should_be_called7',
 
 );
 %anti_patterns = (
 
         q{ SHOULD_NOT_BE_CALLED1 }, 'should_not_be_called1',
         q{ SHOULD_NOT_BE_CALLED2 }, 'should_not_be_called2',
+        q{ SHOULD_NOT_BE_CALLED3 }, 'should_not_be_called3',
+        q{ SHOULD_NOT_BE_CALLED4 }, 'should_not_be_called4',
 
 );
 tstlocalrules (q{
 
         loadplugin Mail::SpamAssassin::Plugin::Test
-        if !can(Mail::SpamAssassin::Plugin::Test::check_test_plugin)
+
+        if (has(Mail::SpamAssassin::Plugin::Test::check_test_plugin))
+          body SHOULD_BE_CALLED1 /./
+        endif
+        if (has(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_true))
+          body SHOULD_BE_CALLED2 /./
+        endif
+        if (has(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_false))
+          body SHOULD_BE_CALLED3 /./
+        endif
+        if (can(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_true))
+          body SHOULD_BE_CALLED4 /./
+        endif
+        if (!can(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_false))
+          body SHOULD_BE_CALLED5 /./
+        endif
+        if (!has(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_nosuch))
+          body SHOULD_BE_CALLED6 /./
+        endif
+        if (!can(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_nosuch))
+          body SHOULD_BE_CALLED7 /./
+        endif
+
+        if !has(Mail::SpamAssassin::Plugin::Test::check_test_plugin)
           body SHOULD_NOT_BE_CALLED1 /./
         endif
-        if (can(Mail::SpamAssassin::Plugin::Test::non_existent_method))
+        if (has(Mail::SpamAssassin::Plugin::Test::non_existent_method))
           body SHOULD_NOT_BE_CALLED2 /./
         endif
-        if (can(Mail::SpamAssassin::Plugin::Test::check_test_plugin))
-          body SHOULD_BE_CALLED /./
+        if (can(Mail::SpamAssassin::Plugin::Test::non_existent_method))
+          body SHOULD_NOT_BE_CALLED3 /./
+        endif
+        if (can(Mail::SpamAssassin::Plugin::Test::test_feature_xxxx_false))
+          body SHOULD_NOT_BE_CALLED4 /./
         endif
 
 });