Skip to content

Instantly share code, notes, and snippets.

@Xliff
Created February 26, 2019 09:57
Show Gist options
  • Save Xliff/b4c5b6c100d8aba52d54d31e809b5777 to your computer and use it in GitHub Desktop.
Save Xliff/b4c5b6c100d8aba52d54d31e809b5777 to your computer and use it in GitHub Desktop.

Hello, Perl6'ers.

When dealing with objects, sometimes you'd like to keep outside code from running methods from your class. To this effect, I have tried to bring a semblance of the protected method to Perl6.

I can sum up much of the problem with the following few pieces of code.

role GTK::Roles::Protection {
  has @!prefixes;

  # cw: This is a HACK, but it should work with careful use.
  method CALLING-METHOD($nf is copy = 3) {
    my $c = callframe($nf).code;
    while $c !~~ Routine {
      my $cf = callframe(++$nf);
      die 'Exceeded backtrace when searching for calling routine' 
        if $cf ~~ Failure;
      $c = $cf.code;
      # Special casing. It's (not) FUUUN!
      next if $c.^name eq <NQPRoutine Block>.any;
      # Special casing is hell! -- Allow for shortcircuit
      $c.^name.say;
      unless  
        $c.package.^name ne <
          GLOBAL Any::IterateOneWithoutPhasers List
        >.any
        ##||
        #'is-hidden-from-backtrace' ∈ $c.^roles.map( .^name )
      { 
        $c = False;
        next;
      }
    }
    "{ $c.package.^name }.{ $c.name }";
  }

  # Do NOT use this method unless you are adding a widget. If adding widgets,
  # please be sure to use a discrete namespace for them.
  #
  # For example:
  #   - It is not sufficient to self.ADD-PREFIX('YourProject') if
  #     the YourProject:: code has non-GTK derivative code. In that case, it
  #     would be appreciated if you would put all widgets into the
  #     YourProject::Widgets namespace and then you can do:
  #         self.ADD-PREFIX('YourProject::Widgets::')
  #     in submethod BUILD.
  #
  # THANKS!
  method ADD-PREFIX($p) {
    @!prefixes.push: $p;
  }

  # Should never be called ouside of the GTK::Widget hierarchy, but
  # how can the watcher watch itself?
  method IS-PROTECTED {
    # Really kinda violates someone's idea of "object-oriented" somewhere,
    # but I am more results-oriened.
    my $c = self.CALLING-METHOD;
    # Must be done, otherwise error. Note: Regexes do not like attributes.
    #my @p = @!prefixes;
    my $t = False;
    # Hardcoded 'GTK::'. There should be a better mechanism to do this, but
    # we use what works.
    for 'GTK::', |@!prefixes {
      last if ( $t = $c.starts-with($_) );
    }
    die "Cannot call method from outside of a GTK:: object ({ $c })"
      unless $t;
    True;
  }
}

The point of this piece of code is to use the callframe function to step back through the frames to find the first non-internal routine and check if its name is acceptable.

However I am now getting this error from a piece of code that uses this protection. I thought an --ll-exception would shed some light on the topic, but unfortunately, it does not.

perl6 --ll-exception -I../cairo-p6-paths/lib -I../p6-Pango/lib -I../p6-GtkPlus/lib -Ilib t/04-simple-ui.t Cannot resolve caller ACCEPTS(Routine:U: NQPRoutine); none of these signatures match:
    (Mu:U: \topic, *%_)
    (Mu:U: Mu:U \topic, *%_)
    (Any:D: Mu:D \a, *%_)
    (Any:D: Mu:U, *%_ --> Bool::False)
    (Any:U: \topic, *%_ --> Bool)
    (Code:D $self: Mu $topic is raw, *%_)
  in method CALLING-METHOD at /home/cbwood/Projects/p6-WebkitGtk/../p6-GtkPlus/lib/GTK/Roles/Protection.pm6 (GTK::Roles::Protection) line 8
  in method IS-PROTECTED at /home/cbwood/Projects/p6-WebkitGtk/../p6-GtkPlus/lib/GTK/Roles/Protection.pm6 (GTK::Roles::Protection) line 53
  in method RESOLVE-UINT at /home/cbwood/Projects/p6-WebkitGtk/../p6-GtkPlus/lib/GTK/Roles/Types.pm6 (GTK::Roles::Types) line 80
  in block  at /home/cbwood/Projects/p6-WebkitGtk/../p6-GtkPlus/lib/GTK/Widget.pm6 (GTK::Widget) line 1169
  in block <unit> at t/04-simple-ui.t line 76

Any ideas on how to sidestep or solve this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment