Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add executeas() to change player/label context when running a closure
  • Loading branch information
PseudoKnight committed Apr 16, 2018
1 parent bcf6ac3 commit c5b87af
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
74 changes: 74 additions & 0 deletions src/main/java/com/laytonsmith/core/functions/DataHandling.java
@@ -1,6 +1,7 @@
package com.laytonsmith.core.functions;

import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.abstraction.MCCommandSender;
import com.laytonsmith.annotations.api;
import com.laytonsmith.annotations.breakable;
import com.laytonsmith.annotations.core;
Expand Down Expand Up @@ -3217,6 +3218,79 @@ public CHVersion since() {
}
}

@api
@seealso({com.laytonsmith.tools.docgen.templates.Closures.class})
public static class executeas extends AbstractFunction {

@Override
public String getName() {
return "executeas";
}

@Override
public Integer[] numArgs() {
return new Integer[]{Integer.MAX_VALUE};
}

@Override
public String docs() {
return "mixed {player, label, [values...,] closure} Executes the given closure in the context of a given"
+ " player. A closure that runs player(), for instance, would return the specified player's name."
+ " The label argument sets the permission label that this closure will use. If null is given,"
+ " the current label will be used, like with execute().";
}

@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class};
}

@Override
public Boolean runAsync() {
return null;
}

@Override
public boolean isRestricted() {
return true;
}

@Override
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
if(!(args[args.length - 1] instanceof CClosure)) {
throw new CRECastException("Only a closure (created from the closure function) can be sent to executeas()", t);
}
Construct[] vals = new Construct[args.length - 3];
System.arraycopy(args, 2, vals, 0, args.length - 3);
CClosure closure = (CClosure) args[args.length - 1];
CommandHelperEnvironment cEnv = closure.getEnv().getEnv(CommandHelperEnvironment.class);
GlobalEnv gEnv = closure.getEnv().getEnv(GlobalEnv.class);

MCCommandSender originalSender = cEnv.GetCommandSender();
cEnv.SetCommandSender(Static.GetCommandSender(args[0].val(), t));

String originalLabel = gEnv.GetLabel();
if(!(args[1] instanceof CNull)) {
gEnv.SetLabel(args[1].val());
}

try {
closure.execute(vals);
} catch (FunctionReturnException e) {
return e.getReturn();
} finally {
cEnv.SetCommandSender(originalSender);
gEnv.SetLabel(originalLabel);
}
return CVoid.VOID;
}

@Override
public CHVersion since() {
return CHVersion.V3_3_2;
}
}

@api
public static class _boolean extends AbstractFunction implements Optimizable {

Expand Down
10 changes: 10 additions & 0 deletions src/test/java/com/laytonsmith/core/functions/DataHandlingTest.java
Expand Up @@ -49,6 +49,7 @@ public static void tearDownClass() throws Exception {
public void setUp() {
fakePlayer = StaticTest.GetOnlinePlayer();
fakeServer = StaticTest.GetFakeServer();
when(fakeServer.getPlayer(fakePlayer.getName())).thenReturn(fakePlayer);
env.getEnv(CommandHelperEnvironment.class).SetPlayer(fakePlayer);
}

Expand Down Expand Up @@ -475,6 +476,15 @@ public void testClosure9() throws Exception {
verify(fakePlayer).sendMessage("{Hello World}");
}

@Test(timeout = 10000)
public void testClosure10() throws Exception {
SRun("@a = closure(msg('yes'));"
+ "@b = closure(msg('no'));"
+ "executeas('" + fakePlayer.getName() + "', null, @a);"
+ "execute(@b);", fakeServer.getConsole());
verify(fakePlayer).sendMessage("yes");
}

@Test(timeout = 10000)
public void testWhile() throws Exception {
SRun("assign(@i, 2) while(@i > 0, @i-- msg('hi'))", fakePlayer);
Expand Down

0 comments on commit c5b87af

Please sign in to comment.