Expand annotations to cover all generated methods
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / ManyToMany.pm
index 25cd00b..e715f10 100644 (file)
@@ -5,9 +5,12 @@ use strict;
 use warnings;
 
 use DBIx::Class::Carp;
-use Sub::Name 'subname';
-use Scalar::Util 'blessed';
-use DBIx::Class::_Util 'fail_on_internal_wantarray';
+use DBIx::Class::_Util qw( quote_sub perlstring );
+
+# FIXME - this souldn't be needed
+my $cu;
+BEGIN { $cu = \&carp_unique }
+
 use namespace::clean;
 
 our %_pod_inherit_config =
@@ -26,10 +29,6 @@ sub many_to_many {
     "missing foreign relation in many-to-many"
   ) unless $f_rel;
 
-  {
-    no strict 'refs';
-    no warnings 'redefine';
-
     my $add_meth = "add_to_${meth}";
     my $remove_meth = "remove_from_${meth}";
     my $set_meth = "set_${meth}";
@@ -57,94 +56,123 @@ EOW
       }
     }
 
-    $rel_attrs->{alias} ||= $f_rel;
+    my @main_meth_qsub_args = (
+      {},
+      { attributes => [
+        'DBIC_method_is_indirect_sugar',
+        ( keys( %{$rel_attrs||{}} )
+          ? 'DBIC_method_is_m2m_sugar_with_attrs'
+          : 'DBIC_method_is_m2m_sugar'
+        ),
+      ] },
+    );
 
 
-    my $rs_meth_name = join '::', $class, $rs_meth;
-    *$rs_meth_name = subname $rs_meth_name, sub {
+    quote_sub "${class}::${meth}", sprintf( <<'EOC', $rs_meth ), @main_meth_qsub_args;
 
-      # this little horror is there replicating a deprecation from
-      # within search_rs() itself
-      shift->search_related_rs($rel)
-            ->search_related_rs(
-              $f_rel,
-              undef,
-              ( @_ > 1 and ref $_[-1] eq 'HASH' )
-                ? { %$rel_attrs, %{ pop @_ } }
-                : $rel_attrs
-            )->search_rs(@_)
-      ;
+      DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and DBIx::Class::_Util::fail_on_internal_call;
+      DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_WANTARRAY and my $sog = DBIx::Class::_Util::fail_on_internal_wantarray;
 
-    };
+      my $rs = shift->%s( @_ );
 
+      wantarray ? $rs->all : $rs;
+EOC
 
-    my $meth_name = join '::', $class, $meth;
-    *$meth_name = subname $meth_name, sub {
 
-      DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_WANTARRAY and my $sog = fail_on_internal_wantarray;
+    my @extra_meth_qsub_args = (
+      {
+        '$rel_attrs' => \{ alias => $f_rel, %{ $rel_attrs||{} } },
+        '$carp_unique' => \$cu,
+      },
+      { attributes => [
+        'DBIC_method_is_indirect_sugar',
+        ( keys( %{$rel_attrs||{}} )
+          ? 'DBIC_method_is_m2m_extra_sugar_with_attrs'
+          : 'DBIC_method_is_m2m_extra_sugar'
+        ),
+      ] },
+    );
 
-      my $rs = shift->$rs_meth( @_ );
 
-      wantarray ? $rs->all : $rs;
+    quote_sub "${class}::${rs_meth}", sprintf( <<'EOC', map { perlstring $_ } ( "${class}::${meth}", $rel, $f_rel ) ), @extra_meth_qsub_args;
 
-    };
+      DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS
+        and
+      # allow nested calls from our ->many_to_many, see comment below
+      ( (CORE::caller(1))[3] ne %s )
+        and
+      DBIx::Class::_Util::fail_on_internal_call;
 
+      # this little horror is there replicating a deprecation from
+      # within search_rs() itself
+      shift->related_resultset( %s )
+            ->related_resultset( %s )
+             ->search_rs (
+               undef,
+               ( @_ > 1 and ref $_[-1] eq 'HASH' )
+                 ? { %%$rel_attrs, %%{ pop @_ } }
+                 : $rel_attrs
+             )->search_rs(@_)
+      ;
+EOC
+
+    # the above is the only indirect method, the 3 below have too much logic
+    shift @{$extra_meth_qsub_args[1]{attributes}};
 
-    my $add_meth_name = join '::', $class, $add_meth;
-    *$add_meth_name = subname $add_meth_name, sub {
+
+    quote_sub "${class}::${add_meth}", sprintf( <<'EOC', $add_meth, $rel, $f_rel ), @extra_meth_qsub_args;
 
       ( @_ >= 2 and @_ <= 3 ) or $_[0]->throw_exception(
-        "'$add_meth' expects an object or hashref to link to, and an optional hashref of link data"
+        "'%1$s' expects an object or hashref to link to, and an optional hashref of link data"
       );
 
       $_[0]->throw_exception(
-        "The optional link data supplied to '$add_meth' is not a hashref (it was previously ignored)"
+        "The optional link data supplied to '%1$s' is not a hashref (it was previously ignored)"
       ) if $_[2] and ref $_[2] ne 'HASH';
 
       my( $self, $far_obj ) = @_;
 
       my $guard;
 
-      # the API needs is always expected to return the far object, possibly
+      # the API is always expected to return the far object, possibly
       # creating it in the process
-      if( not defined blessed $far_obj ) {
+      if( not defined Scalar::Util::blessed( $far_obj ) ) {
 
         $guard = $self->result_source->schema->storage->txn_scope_guard;
 
         # reify the hash into an actual object
         $far_obj = $self->result_source
-                         ->related_source( $rel )
-                          ->related_source( $f_rel )
+                         ->related_source( q{%2$s} )
+                          ->related_source( q{%3$s} )
                            ->resultset
                             ->search_rs( undef, $rel_attrs )
                              ->find_or_create( $far_obj );
       }
 
       my $link = $self->new_related(
-        $rel,
+        q{%2$s},
         $_[2] || {},
       );
 
-      $link->set_from_related( $f_rel, $far_obj );
+      $link->set_from_related( q{%3$s}, $far_obj );
 
       $link->insert();
 
       $guard->commit if $guard;
 
       $far_obj;
-    };
+EOC
 
 
-    my $set_meth_name = join '::', $class, $set_meth;
-    *$set_meth_name = subname $set_meth_name, sub {
+    quote_sub "${class}::${set_meth}", sprintf( <<'EOC', $set_meth, $add_meth, $rel, $f_rel ), @extra_meth_qsub_args;
 
       my $self = shift;
 
       my $set_to = ( ref $_[0] eq 'ARRAY' )
         ? ( shift @_ )
         : do {
-          carp_unique(
-            "Calling '$set_meth' with a list of items to link to is deprecated, use an arrayref instead"
+          $carp_unique->(
+            "Calling '%1$s' with a list of items to link to is deprecated, use an arrayref instead"
           );
 
           # gobble up everything from @_ into a new arrayref
@@ -154,11 +182,11 @@ EOW
 
       # make sure folks are not invoking a bizarre mix of deprecated and curent syntax
       $self->throw_exception(
-        "'$set_meth' expects an arrayref of objects or hashrefs to link to, and an optional hashref of link data"
+        "'%1$s' expects an arrayref of objects or hashrefs to link to, and an optional hashref of link data"
       ) if (
         @_ > 1
           or
-        ( @_ and ref $_[0] ne 'HASH' )
+        ( defined $_[0] and ref $_[0] ne 'HASH' )
       );
 
       my $guard;
@@ -169,36 +197,38 @@ EOW
 
       # if there is a where clause in the attributes, ensure we only delete
       # rows that are within the where restriction
-      $self->search_related(
-        $rel,
-        ( $rel_attrs->{where}
-          ? ( $rel_attrs->{where}, { join => $f_rel } )
-          : ()
-        )
-      )->delete;
+      $self->related_resultset( q{%3$s} )
+            ->search_rs(
+              ( $rel_attrs->{where}
+                ? ( $rel_attrs->{where}, { join => q{%4$s} } )
+                : ()
+              )
+            )->delete;
 
       # add in the set rel objects
-      $self->$add_meth(
+      $self->%2$s(
         $_,
         @_, # at this point @_ is either empty or contains a lone link-data hash
       ) for @$set_to;
 
       $guard->commit if $guard;
-    };
+EOC
+
+
+    # the last method needs no captures - just kill it all with fire
+    $extra_meth_qsub_args[0] = {};
 
 
-    my $remove_meth_name = join '::', $class, $remove_meth;
-    *$remove_meth_name = subname $remove_meth_name, sub {
+    quote_sub "${class}::${remove_meth}", sprintf( <<'EOC', $remove_meth, $rel, $f_rel ), @extra_meth_qsub_args;
 
-      $_[0]->throw_exception("'$remove_meth' expects an object")
-        unless defined blessed $_[1];
+      $_[0]->throw_exception("'%1$s' expects an object")
+        unless defined Scalar::Util::blessed( $_[1] );
 
-      $_[0]->search_related_rs( $rel )
-            ->search_rs( $_[1]->ident_condition( $f_rel ), { join => $f_rel } )
+      $_[0]->related_resultset( q{%2$s} )
+            ->search_rs( $_[1]->ident_condition( q{%3$s} ), { join => q{%3$s} } )
              ->delete;
-    };
+EOC
 
-  }
 }
 
 1;