Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 55 additions & 21 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -1127,21 +1127,28 @@ public IRubyObject inspect() {
// MRI: rb_obj_inspect
public IRubyObject inspect(ThreadContext context) {
return !isImmediate() && !(this instanceof RubyModule) && hasVariables() ?
hashyInspect() : to_s(context);
hashyInspect(context) : to_s(context);
}

@Deprecated(since = "10.1.0.0")
public final IRubyObject hashyInspect() {
final Ruby runtime = getRuntime();
return hashyInspect(getRuntime().getCurrentContext());
}

public final IRubyObject hashyInspect(ThreadContext context) {
IRubyObject ivars = Helpers.invokeChecked(context, this, sites(context).instance_variables_to_inspect_checked);

RubyString part = inspectPrefix(runtime.getCurrentContext(), metaClass.getRealClass(), inspectHashCode());
RubyString part = inspectPrefix(context, metaClass.getRealClass(), inspectHashCode());

Ruby runtime = context.runtime;

if (runtime.isInspecting(this)) {
encStrBufCat(runtime, part, SPACE_DOT_DOT_DOT_GT);
return part;
}
try {
runtime.registerInspecting(this);
return inspectObj(runtime, part);
return inspectObj(context, part, ivars);
} finally {
runtime.unregisterInspecting(this);
}
Expand Down Expand Up @@ -1182,31 +1189,58 @@ protected int inspectHashCode() {
* The internal helper method that takes care of the part of the
* inspection that inspects instance variables.
*/
private RubyString inspectObj(final Ruby runtime, RubyString part) {
final ThreadContext context = runtime.getCurrentContext();
private RubyString inspectObj(final ThreadContext context, RubyString part, IRubyObject ivars) {
Ruby runtime = context.runtime;

if (ivars == null) {
// no ivars specified, do all of them
boolean first = true;
for (Map.Entry<String, VariableAccessor> entry : metaClass.getVariableTableManager().getVariableAccessorsForRead().entrySet()) {
VariableAccessor accessor = entry.getValue();
String name = entry.getKey();

boolean first = true;
for (Map.Entry<String, VariableAccessor> entry : metaClass.getVariableTableManager().getVariableAccessorsForRead().entrySet()) {
Object value = entry.getValue().get(this);
if (!(value instanceof IRubyObject)) continue;
RubySymbol symbol = asSymbol(context, entry.getKey());
if (!symbol.validInstanceVariableName()) continue;
if (appendInstanceVariable(context, part, accessor, name, first, runtime)) continue;

IRubyObject obj = (IRubyObject) value;
first = false;
}
} else if (!ivars.isNil()) {
// ivars specified, do only those
RubyArray ivarsAry = Convert.castAsArray(context, ivars);

if (!first) encStrBufCat(runtime, part, COMMA);
encStrBufCat(runtime, part, SPACE);
// FIXME: bytelist_love: EPICLY wrong but something in MRI gets around identifiers of arbitrary encoding.
encStrBufCat(runtime, part, symbol.asString().encode(context, encodingService(context).convertEncodingToRubyEncoding(part.getEncoding())).asString().getByteList());
encStrBufCat(runtime, part, EQUALS);
encStrBufCat(runtime, part, sites(context).inspect.call(context, obj, obj).convertToString().getByteList());
boolean first = true;
Map<String, VariableAccessor> accessors = metaClass.getVariableTableManager().getVariableAccessorsForRead();
for (int i = 0; i < ivarsAry.size(); i++) {
String name = ivarsAry.eltOk(i).toString();
VariableAccessor accessor = accessors.get(name);
if (accessor == null) continue;

if (appendInstanceVariable(context, part, accessor, name, first, runtime)) continue;

first = false;
}
} // else ivars was provided and is nil, so do none

first = false;
}
encStrBufCat(runtime, part, GT);
return part;
}

private boolean appendInstanceVariable(ThreadContext context, RubyString part, VariableAccessor accessor, String name, boolean first, Ruby runtime) {
Object value = accessor.get(this);
if (!(value instanceof IRubyObject)) return true;
RubySymbol symbol = asSymbol(context, name);
if (!symbol.validInstanceVariableName()) return true;

IRubyObject obj = (IRubyObject) value;

if (!first) encStrBufCat(runtime, part, COMMA);
encStrBufCat(runtime, part, SPACE);
// FIXME: bytelist_love: EPICLY wrong but something in MRI gets around identifiers of arbitrary encoding.
encStrBufCat(runtime, part, symbol.asString().encode(context, encodingService(context).convertEncodingToRubyEncoding(part.getEncoding())).asString().getByteList());
encStrBufCat(runtime, part, EQUALS);
encStrBufCat(runtime, part, sites(context).inspect.call(context, obj, obj).convertToString().getByteList());
return false;
}

// Methods of the Object class (rb_obj_*):


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public static IRubyObject inspect(IRubyObject recv) {

@JRubyMethod
public static IRubyObject inspect(ThreadContext context, IRubyObject recv) {
return recv instanceof RubyBasicObject basic ? basic.hashyInspect() : recv.inspect(context);
return recv instanceof RubyBasicObject basic ? basic.hashyInspect(context) : recv.inspect(context);
}

@JRubyMethod
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public static class BasicObjectSites {
public final CallSite match = new FunctionalCachingCallSite("=~");
public final CallSite call = new FunctionalCachingCallSite("call");
public final CallSite op_equal = new FunctionalCachingCallSite("==");
public final CheckedSites instance_variables_to_inspect_checked = new CheckedSites("instance_variables_to_inspect");
}

public static class ObjectSites {
Expand Down
Loading