package org.enumerable.lambda.support.jruby;
import static java.util.Arrays.*;
import static org.enumerable.lambda.Parameters.*;
import static org.enumerable.lambda.support.jruby.LambdaJRuby.*;
import static org.junit.Assert.*;
import groovy.lang.Closure;
import java.util.List;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.enumerable.lambda.Fn1;
import org.enumerable.lambda.Lambda;
import org.enumerable.lambda.enumerable.Enumerable;
import org.enumerable.lambda.support.clojure.ClojureTest;
import org.enumerable.lambda.support.clojure.LambdaClojure;
import org.enumerable.lambda.support.groovy.GroovyTest;
import org.enumerable.lambda.support.groovy.LambdaGroovy;
import org.enumerable.lambda.support.javascript.JavaScriptTest;
import org.enumerable.lambda.support.javascript.LambdaJavaScript;
import org.enumerable.lambda.support.scala.LambdaScala;
import org.enumerable.lambda.support.scala.ScalaTest;
import org.enumerable.lambda.support.scala.ScalaTest.ScalaInterpreter;
import org.jruby.Ruby;
import org.jruby.RubyProc;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.builtin.IRubyObject;
import org.junit.Before;
import org.junit.Test;
import scala.Function2;
import sun.org.mozilla.javascript.internal.Function;
import clojure.lang.IFn;
public class JRubyTest {
ScriptEngine rb;
@Test
public void interactingWithJRuby() throws ScriptException {
rb.put("block", lambda(n, n * 2));
assertEquals(asList(2L, 4L, 6L), rb.eval("[1, 2, 3].collect &block"));
}
@Test
public void defaultValuesForJRubyProcs() throws ScriptException {
rb.put("block", lambda(n = 2, n * 2));
assertEquals(4L, rb.eval("block.call"));
rb.put("block", lambda(n, m = 2, n * m));
assertEquals(8L, rb.eval("block.call 4"));
rb.put("block", lambda(n = 2, m = 2, n * m));
assertEquals(4L, rb.eval("block.call"));
rb.put("block", lambda(s, n = 2, m = 2, s + n * m));
assertEquals("#: 4", rb.eval("block.call '#: '"));
}
@Test(expected = IllegalArgumentException.class)
public void defaultValuesThrowsExceptionIfOnlyProvidedForEarlierParameterForJRubyProcs() throws ScriptException {
rb.put("block", lambda(n = 2, m, n * m));
}
@Test(expected = IllegalArgumentException.class)
public void defaultValuesThrowsExceptionIfOnlyProvidedForMiddleParameterForJRubyProcs() throws ScriptException {
rb.put("block", lambda(s, n = 2, m, n * m));
}
@Test(expected = IllegalArgumentException.class)
public void defaultValuesThrowsExceptionIfOnlyProvidedForAllEarlierParametersForJRubyProcs()
throws ScriptException {
rb.put("block", lambda(s = "", n = 2, m, n * m));
}
@Test
public void convertFnToRubyProc() throws ScriptException {
Ruby ruby = Ruby.getGlobalRuntime();
RubyProc proc = toProc(Lambda.λ(s, s.toUpperCase()));
assertEquals(ruby.newString("HELLO"), proc.call(ruby.getThreadService().getCurrentContext(),
new IRubyObject[] { ruby.newString("hello") }));
}
@Test
public void convertFnToRubyProcKeepsDefaultValues() throws ScriptException {
Ruby ruby = Ruby.getGlobalRuntime();
RubyProc proc = toProc(Lambda.λ(s = "world", s.toUpperCase()));
assertEquals(ruby.newString("WORLD"), proc.call(ruby.getThreadService().getCurrentContext(),
new IRubyObject[] {}));
}
@Test(expected = RaiseException.class)
public void convertedRubyProcRaisesArgumentErrorWhenCalledWithTooFewArguments() throws ScriptException {
Ruby ruby = Ruby.getGlobalRuntime();
try {
RubyProc proc = toProc(Lambda.λ(s, s.toUpperCase()));
proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[0]);
} catch (RaiseException e) {
assertEquals(ruby.getArgumentError(), e.getException().getType());
throw e;
}
}
@Test(expected = RaiseException.class)
public void convertedRubyProcRaisesArgumentErrorWhenCalledWithTooManyArguments() throws ScriptException {
Ruby ruby = Ruby.getGlobalRuntime();
try {
RubyProc proc = toProc(Lambda.λ(s, s.toUpperCase()));
proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[] { ruby.newString("hello"),
ruby.newString("world") });
} catch (RaiseException e) {
assertEquals(ruby.getArgumentError(), e.getException().getType());
throw e;
}
}
@Test
public void convertRubyProcToFn() throws ScriptException {
RubyProc proc = (RubyProc) rb.eval("lambda {|s| s.upcase}");
assertEquals("HELLO", toFn1(proc).call("hello"));
}
@Test
public void convertRubyMethodProcToFn() throws ScriptException {
RubyProc proc = (RubyProc) rb.eval("(\"hello\".method :upcase).to_proc");
assertEquals("HELLO", toFn0(proc).call());
}
@Test
public void convertRubyMethodProcToFnKeepsDefaultValues() throws ScriptException {
RubyProc proc = (RubyProc) rb.eval("def my_upcase(s = 'world') s.upcase end; method(:my_upcase).to_proc");
assertEquals("WORLD", toFn1(proc).call());
}
@Test
public void interactingWithEnumerableJava() throws Exception {
List<Integer> list = asList(1, 2, 3);
Fn1<Object, Object> block = toFn1((RubyProc) rb.eval("lambda {|n| n * 2}"));
assertEquals(asList(2L, 4L, 6L), Enumerable.collect(list, block));
}
@Test
public void interactingWithClojure() throws Exception {
Ruby ruby = Ruby.getGlobalRuntime();
IFn star = (IFn) ClojureTest.getClojureEngine().eval("*");
RubyProc proc = toProc(LambdaClojure.toFn2(star));
assertEquals(ruby.newFixnum(6), proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[] {
ruby.newFixnum(2), ruby.newFixnum(3) }));
rb.put("block", proc);
assertEquals(120L, rb.eval("[1, 2, 3, 4, 5].inject &block"));
}
@Test
public void interactingWithJavaScript() throws Exception {
Ruby ruby = Ruby.getGlobalRuntime();
ScriptEngine js = JavaScriptTest.getJavaScriptEngine();
Function f = (Function) js.eval("var f = function(n, m) { return n * m; }; f;");
RubyProc proc = toProc(LambdaJavaScript.toFn2(f));
assertEquals(ruby.newFloat(6), proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[] {
ruby.newFixnum(2), ruby.newFixnum(3) }));
rb.put("block", proc);
assertEquals(120.0, rb.eval("[1, 2, 3, 4, 5].inject &block"));
}
@Test
public void interactingWithGroovy() throws Exception {
Ruby ruby = Ruby.getGlobalRuntime();
ScriptEngine groovy = GroovyTest.getGroovyEngine();
Closure<?> closure = (Closure<?>) groovy.eval("{ n, m -> n * m }");
RubyProc proc = toProc(LambdaGroovy.toFn2(closure));
assertEquals(ruby.newFixnum(6), proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[] {
ruby.newFixnum(2), ruby.newFixnum(3) }));
rb.put("block", proc);
assertEquals(120L, rb.eval("[1, 2, 3, 4, 5].inject &block"));
}
@SuppressWarnings("unchecked")
@Test
public void interactingWithScala() throws Exception {
Ruby ruby = Ruby.getGlobalRuntime();
ScalaInterpreter scala = ScalaTest.getScalaInterpreter();
Function2<Integer, Integer, Integer> f = (Function2<Integer, Integer, Integer>) scala.eval("(n: Long, m: Long) => n * m");
RubyProc proc = toProc(LambdaScala.toFn2(f));
assertEquals(ruby.newFixnum(6), proc.call(ruby.getThreadService().getCurrentContext(), new IRubyObject[] {
ruby.newFixnum(2), ruby.newFixnum(3) }));
rb.put("block", proc);
assertEquals(120L, rb.eval("[1, 2, 3, 4, 5].inject &block"));
}
@Before
public void initEngine() {
rb = getJRubyEngine();
}
public static ScriptEngine getJRubyEngine() {
System.setProperty("org.jruby.embed.localvariable.behavior", "persistent");
ScriptEngineManager manager = new ScriptEngineManager();
return manager.getEngineByName("jruby");
}
}