Skip to content

Commit

Permalink
Showing 3 changed files with 52 additions and 55 deletions.
63 changes: 25 additions & 38 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
@@ -2286,12 +2286,12 @@ public IRubyObject methods(ThreadContext context, IRubyObject[] args, boolean us
Set<String> seen = new HashSet<String>();

if (getMetaClass().isSingleton()) {
getMetaClass().populateInstanceMethodNames(seen, methods, PRIVATE, true, useSymbols, false);
getMetaClass().populateInstanceMethodNames(seen, methods, PRIVATE, false, true, false);
if (all) {
getMetaClass().getSuperClass().populateInstanceMethodNames(seen, methods, PRIVATE, true, useSymbols, true);
getMetaClass().getSuperClass().populateInstanceMethodNames(seen, methods, PRIVATE, false, true, true);
}
} else if (all) {
getMetaClass().populateInstanceMethodNames(seen, methods, PRIVATE, true, useSymbols, true);
getMetaClass().populateInstanceMethodNames(seen, methods, PRIVATE, false, true, true);
} else {
// do nothing, leave empty
}
@@ -2395,56 +2395,43 @@ private IRubyObject[] trueIfNoArgument(ThreadContext context, IRubyObject[] args
*/
// TODO: This is almost RubyModule#instance_methods on the metaClass. Perhaps refactor.
public RubyArray singleton_methods(ThreadContext context, IRubyObject[] args) {
return singletonMethods(context, args, methodsCollector);
}

public RubyArray singleton_methods19(ThreadContext context, IRubyObject[] args) {
return singletonMethods(context, args, methodsCollector19);
}

private RubyArray singletonMethods(ThreadContext context, IRubyObject[] args, MethodsCollector collect) {
Ruby runtime = context.runtime;
boolean all = true;
if(args.length == 1) {
all = args[0].isTrue();
}

if (getMetaClass().isSingleton()) {
IRubyObject[] methodsArgs = new IRubyObject[]{context.runtime.getFalse()};
RubyArray singletonMethods = collect.instanceMethods(getMetaClass(), methodsArgs);
RubyClass klass = metaClass;
RubyModule origin = klass.getMethodLocation();

if (klass.isSingleton()) {
Set<RubySymbol> names = new HashSet<>();
for (Map.Entry<String, DynamicMethod> entry : klass.getMethods().entrySet()) {
if (entry.getValue().getVisibility() == PRIVATE) continue;
// TODO: needs to use method_entry_i logic from MRI
names.add(runtime.newSymbol(entry.getKey()));
}

if (all) {
RubyClass superClass = getMetaClass().getSuperClass();
while (superClass.isSingleton() || superClass.isIncluded()) {
singletonMethods.concat(collect.instanceMethods(superClass, methodsArgs));
superClass = superClass.getSuperClass();
klass = klass.getSuperClass();
while (klass != null && (klass.isSingleton() || klass.isIncluded())) {
if (klass != origin) {
for (Map.Entry<String, DynamicMethod> entry : klass.getMethods().entrySet()) {
if (entry.getValue().getVisibility() == PRIVATE) continue;
// TODO: needs to use method_entry_i logic from MRI
names.add(runtime.newSymbol(entry.getKey()));
}
}
klass = klass.getSuperClass();
}
}

singletonMethods.uniq_bang(context);
return singletonMethods;
return RubyArray.newArray(runtime, names);
}

return context.runtime.newEmptyArray();
}

private abstract static class MethodsCollector {
public abstract RubyArray instanceMethods(RubyClass rubyClass, IRubyObject[] args);
};

private static final MethodsCollector methodsCollector = new MethodsCollector() {
@Override
public RubyArray instanceMethods(RubyClass rubyClass, IRubyObject[] args) {
return rubyClass.instance_methods(args);
}
};

private static final MethodsCollector methodsCollector19 = new MethodsCollector() {
@Override
public RubyArray instanceMethods(RubyClass rubyClass, IRubyObject[] args) {
return rubyClass.instance_methods19(args);
}
};

/** rb_obj_method
*
* call-seq:
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
@@ -1990,7 +1990,7 @@ public static IRubyObject private_methods19(ThreadContext context, IRubyObject s

@JRubyMethod(name = "singleton_methods", optional = 1)
public static RubyArray singleton_methods19(ThreadContext context, IRubyObject self, IRubyObject[] args) {
return ((RubyBasicObject)self).singleton_methods19(context, args);
return ((RubyBasicObject)self).singleton_methods(context, args);
}

@JRubyMethod(name = "method", required = 1)
42 changes: 26 additions & 16 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -46,7 +46,6 @@
import org.jruby.anno.JavaMethodDescriptor;
import org.jruby.anno.TypePopulator;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.common.RubyWarnings;
import org.jruby.embed.Extension;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.AliasMethod;
@@ -2241,41 +2240,52 @@ public IRubyObject attr_accessor(ThreadContext context, IRubyObject[] args) {
* @param not if true only find methods not matching supplied visibility
* @return a RubyArray of instance method names
*/
private RubyArray instance_methods(IRubyObject[] args, final Visibility visibility, boolean not, boolean useSymbols) {
private RubyArray instance_methods(IRubyObject[] args, final Visibility visibility, boolean not) {
boolean includeSuper = args.length > 0 ? args[0].isTrue() : true;
return instanceMethods(visibility, includeSuper, false, not);
}

public RubyArray instanceMethods(final Visibility visibility, boolean includeSuper, boolean obj, boolean not) {
Ruby runtime = getRuntime();
RubyArray ary = runtime.newArray();
Set<String> seen = new HashSet<String>();

populateInstanceMethodNames(seen, ary, visibility, not, useSymbols, includeSuper);
populateInstanceMethodNames(seen, ary, visibility, obj, not, includeSuper);

return ary;
}

public void populateInstanceMethodNames(Set<String> seen, RubyArray ary, final Visibility visibility, boolean not, boolean useSymbols, boolean includeSuper) {
public void populateInstanceMethodNames(Set<String> seen, RubyArray ary, final Visibility visibility, boolean obj, boolean not, boolean recur) {
Ruby runtime = getRuntime();
RubyModule mod = this;
boolean prepended = false;

for (RubyModule type = this; type != null; type = type.getSuperClass()) {
RubyModule realType = type.getNonIncludedClass();
for (Map.Entry entry : type.getMethods().entrySet()) {
if (!recur && methodLocation != this) {
mod = methodLocation;
prepended = true;
}

for (; mod != null; mod = mod.getSuperClass()) {
RubyModule realType = mod.getNonIncludedClass();
for (Map.Entry entry : mod.getMethods().entrySet()) {
String methodName = (String) entry.getKey();

if (! seen.contains(methodName)) {
seen.add(methodName);

DynamicMethod method = (DynamicMethod) entry.getValue();
if ((method.isImplementedBy(realType) || method.isImplementedBy(type)) &&
if ((method.isImplementedBy(realType) || method.isImplementedBy(mod)) &&
(!not && method.getVisibility() == visibility || (not && method.getVisibility() != visibility)) &&
! method.isUndefined()) {

ary.append(useSymbols ? runtime.newSymbol(methodName) : runtime.newString(methodName));
ary.append(runtime.newSymbol(methodName));
}
}
}

if (!includeSuper && type == methodLocation) {
break;
}
if (mod.isIncluded() && !prepended) continue;
if (obj && mod.isSingleton()) continue;
if (!recur) break;
}
}

@@ -2285,7 +2295,7 @@ public RubyArray instance_methods(IRubyObject[] args) {

@JRubyMethod(name = "instance_methods", optional = 1)
public RubyArray instance_methods19(IRubyObject[] args) {
return instance_methods(args, PRIVATE, true, true);
return instance_methods(args, PRIVATE, true);
}

public RubyArray public_instance_methods(IRubyObject[] args) {
@@ -2294,7 +2304,7 @@ public RubyArray public_instance_methods(IRubyObject[] args) {

@JRubyMethod(name = "public_instance_methods", optional = 1)
public RubyArray public_instance_methods19(IRubyObject[] args) {
return instance_methods(args, PUBLIC, false, true);
return instance_methods(args, PUBLIC, false);
}

@JRubyMethod(name = "instance_method", required = 1)
@@ -2316,7 +2326,7 @@ public RubyArray protected_instance_methods(IRubyObject[] args) {

@JRubyMethod(name = "protected_instance_methods", optional = 1)
public RubyArray protected_instance_methods19(IRubyObject[] args) {
return instance_methods(args, PROTECTED, false, true);
return instance_methods(args, PROTECTED, false);
}

/** rb_class_private_instance_methods
@@ -2328,7 +2338,7 @@ public RubyArray private_instance_methods(IRubyObject[] args) {

@JRubyMethod(name = "private_instance_methods", optional = 1)
public RubyArray private_instance_methods19(IRubyObject[] args) {
return instance_methods(args, PRIVATE, false, true);
return instance_methods(args, PRIVATE, false);
}

/** rb_mod_prepend_features

0 comments on commit a9ce5d3

Please sign in to comment.