package com.jbidwatcher.scripting;
import com.jbidwatcher.util.config.JConfig;
import org.jruby.RubyInstanceConfig;
import org.jruby.Ruby;
import org.jruby.internal.runtime.GlobalVariable;
import org.jruby.internal.runtime.ValueAccessor;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* User: Morgan
* Date: Dec 16, 2007
* Time: 6:53:02 PM
*
* Scripting interface so things can call Ruby methods easily.
*/
public class Scripting {
private static Object sRuby = null;
private static FauxOutputStream sOutput;
private static FauxInputStream sInput;
private static class FauxOutputStream extends OutputStream {
private OutputStream mOut = System.out;
public void write(int b) throws IOException { mOut.write(b); }
public void write(byte[] bs) throws IOException { mOut.write(bs); }
public void write(byte[] bs, int offset, int length) throws IOException { mOut.write(bs, offset, length); }
public OutputStream setOutput(OutputStream newOutput) {
OutputStream old = mOut;
mOut = newOutput;
return old;
}
}
private static class FauxInputStream extends InputStream {
private InputStream mIn = System.in;
public int read() throws IOException {
return mIn.read();
}
public InputStream setInput(InputStream newInput) {
InputStream old = mIn;
mIn = newInput;
return old;
}
}
private Scripting() { }
public static Ruby getRuntime() { return (Ruby)sRuby; }
public static void setOutput(OutputStream stream) { sOutput.setOutput(stream); }
public static void setInput(InputStream stream) { sInput.setInput(stream); }
public static void initialize() throws ClassNotFoundException {
// Test for JRuby's presence
Class.forName("org.jruby.RubyInstanceConfig", true, Thread.currentThread().getContextClassLoader());
sOutput = new FauxOutputStream();
sInput = new FauxInputStream();
final RubyInstanceConfig config = new RubyInstanceConfig() {
{
String[] args = new String[3];
args[0] = "--readline";
args[1] = "--prompt-mode";
args[2] = "default";
setInput(sInput);
setOutput(new PrintStream(sOutput));
setError(new PrintStream(sOutput));
setArgv(args);
}
};
final Ruby runtime = Ruby.newInstance(config);
runtime.getGlobalVariables().defineReadonly("$$", new ValueAccessor(runtime.newFixnum(System.identityHashCode(runtime))), GlobalVariable.Scope.GLOBAL);
if(JConfig.queryConfiguration("platform.path") != null) {
runtime.getLoadService().addPaths(JConfig.queryConfiguration("platform.path"));
}
runtime.getLoadService().addPaths("uri:classloader:lib/jbidwatcher", "uri:classloader:lib/jbidwatcher/nokogiri-1.5.2-java/lib");
sRuby = runtime;
}
public static void require(String file) {
getRuntime().evalScriptlet("require '" + file + "';");
}
public static void setGlobalVariable(String variable, Object value) {
getRuntime().getGlobalVariables().defineReadonly(variable, new ValueAccessor(JavaUtil.convertJavaToRuby(getRuntime(), value)), GlobalVariable.Scope.GLOBAL);
}
public static Object ruby(String command) {
if(sRuby != null) {
return ((Ruby)sRuby).evalScriptlet(command);
} else {
return null;
}
}
public static Object rubyMethod(String method, Object... method_params) {
return doRuby("JBidwatcher", method, method_params);
}
private static Map<String, Object> expressionCache = new HashMap<String, Object>();
/**
* Forget a cached expression result for doRuby's use.
*
* @param what The expression to un-cache.
*/
public static void forget(String what) {
expressionCache.remove(what);
}
/**
* Execute a ruby method on an arbitrary Ruby object. The ruby expression
* to call the method on is cached, so later calls to execute methods on the
* same object won't have to look up the object first. If you need to clear
* the cache, @see Scripting.forget.
*
* @param on An expression that results in a Ruby object.
* @param method The method name to call on the Ruby object.
* @param method_params Any parameters to pass to the method.
*
* @return Whatever return value the method returns.
*/
public static Object doRuby(String on, String method, Object... method_params) {
if (sRuby == null) return null;
Object actOn = expressionCache.get(on);
if(actOn == null) {
actOn = ruby(on);
if(actOn != null) {
expressionCache.put(on, actOn);
}
}
if(actOn != null) {
return JavaEmbedUtils.invokeMethod((Ruby)sRuby, actOn, method, method_params, Object.class);
}
return null;
}
}