package net.cakenet.jsaton.script.ruby;
import net.cakenet.jsaton.script.debug.*;
import net.cakenet.jsaton.script.debug.collections.*;
import org.jruby.*;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.builtin.Variable;
import java.lang.reflect.Array;
import java.util.BitSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class RubyExtractor implements VariableExtractor<IRubyObject> {
public DebugObject extractFrom(final Object o) {
return new OnDemandDebugObject(new RubyDebugObjectProvider(o));
}
private DebugObject provide(final Object o) {
if(o == null)
return new SimpleDebugObject(null, null, "nil");
if(o instanceof RubyNil)
return new SimpleDebugObject(null, null, "nil");
if(o instanceof DebugObject)
return (DebugObject) o;
Class c = o.getClass();
if(c.isArray()) {
final int len = Array.getLength(o);
DebugArrayObject dao = new DebugArrayObject(new DebugArrayProvider() {
private BitSet map = new BitSet(len);
private DebugArrayElement[] provided = new DebugArrayElement[len];
public int size() {
return len;
}
public DebugArrayElement get(int index) {
if(map.get(index))
return provided[index];
DebugObject v = extractFrom(Array.get(o, index));
DebugArrayElement created = new DebugArrayElement(index, v);
provided[index] = created;
map.set(index);
return created;
}
public int indexOf(Object child) {
for(int i = 0; i < provided.length; i++) {
Object p = map.get(i)? provided[i]: get(i);
if(p == child || (p != null && p.equals(child)))
return i;
}
return -1;
}
});
return dao;
}
IRubyObject iro = (IRubyObject) o;
if(o instanceof JavaProxy)
return JavaExtractor.instance.extractFrom(((JavaProxy) o).getObject());
if(iro instanceof RubyArray)
return extractFrom(((RubyArray) iro).toJavaArray());
if (iro instanceof RubyHash) {
final RubyHash hash = (RubyHash) o;
final Iterator kit = hash.directKeySet().iterator();
final Iterator vit = hash.directValues().iterator();
DebugObject dobj = new DebugMapObject(new AbstractDebugMapProvider() {
protected DebugMapElement next() {
DebugObject val = extractFrom(vit.next());
DebugObject key = extractFrom(kit.next());
return new DebugMapElement(key, val);
}
public int size() {
return hash.size();
}
});
return dobj;
}
// numeric...
if(iro instanceof RubyFloat)
return new SimpleDebugObject(null, iro.getType().toString(), ((RubyFloat) iro).getDoubleValue());
if(iro instanceof RubyNumeric)
return new SimpleDebugObject(null, iro.getType().toString(),
JavaExtractor.instance.extractFrom(((RubyNumeric) iro).getBigIntegerValue()));
if(iro instanceof RubyString)
return new SimpleDebugObject(null, iro.getType().toString(),
JavaExtractor.instance.extractFrom(((RubyString) iro).getUnicodeValue()));
if(iro instanceof RubySymbol)
return new SimpleDebugObject(null, iro.getType().toString(), ":" + iro.asJavaString());
RubyClass clazz = iro.getType();
List<String> names = iro.getVariableNameList();
List<Variable<Object>> values = iro.getVariableList();
SimpleDebugObject dobj = new SimpleDebugObject(null, iro.getType().toString(), iro);
List<DebugObject> vars = new LinkedList<>();
for(int i = 0; i < names.size(); i++) {
DebugObject val = extractFrom(values.get(i).getValue());
val.setName(names.get(i));
vars.add(val);
}
List<String> classVarNames = clazz.getClassVariableNameList();
for(String classVarName: classVarNames) {
DebugObject val = extractFrom(clazz.getClassVar(classVarName));
val.setName(classVarName);
vars.add(val);
}
dobj.variables = vars;
return dobj;
}
class RubyDebugObjectProvider implements DebugObjectProvider {
private Object source;
public RubyDebugObjectProvider(Object source) {
this.source = source;
}
public DebugObject provide() {
return RubyExtractor.this.provide(source);
}
}
}