Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate jruby/core_ext Class#subclasses #5181

Merged
merged 4 commits into from May 23, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Expand Up @@ -936,6 +936,16 @@ public void addModule(RubyModule module) {
allModules.add(module);
}
}

public void eachModule(Consumer<RubyModule> func) {
synchronized (allModules) {
for (RubyModule module : allModules) {
func.accept(module);
}
}
}

@Deprecated
public void eachModule(Function1<Object, IRubyObject> func) {
synchronized (allModules) {
for (RubyModule module : allModules) {
Expand Down
16 changes: 5 additions & 11 deletions core/src/main/java/org/jruby/RubyObjectSpace.java
Expand Up @@ -45,7 +45,6 @@
import static org.jruby.runtime.Visibility.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.collections.WeakValuedIdentityMap;
import org.jruby.util.func.Function1;

@JRubyModule(name="ObjectSpace")
public class RubyObjectSpace {
Expand Down Expand Up @@ -129,17 +128,13 @@ public static IRubyObject each_objectInternal(final ThreadContext context, IRuby
if (rubyClass == runtime.getClassClass() || rubyClass == runtime.getModule()) {

final ArrayList<IRubyObject> modules = new ArrayList<>(96);
runtime.eachModule(new Function1<Object, IRubyObject>() {
public Object apply(IRubyObject arg1) {
if (rubyClass.isInstance(arg1)) {
if (arg1 instanceof IncludedModule) {
runtime.eachModule((module) -> {
if (rubyClass.isInstance(module)) {
if (!(module instanceof IncludedModule)) {
// do nothing for included wrappers or singleton classes
} else {
modules.add(arg1); // store the module to avoid concurrent modification exceptions
modules.add(module); // store the module to avoid concurrent modification exceptions
}
}
return null;
}
});

final int count = modules.size();
Expand All @@ -155,9 +150,8 @@ public Object apply(IRubyObject arg1) {
block.yield(context, attached); int count = 1;
if (attached instanceof RubyClass) {
for (RubyClass child : ((RubyClass) attached).subclasses(true)) {
if (child instanceof IncludedModule) {
if (!(child instanceof IncludedModule)) {
// do nothing for included wrappers or singleton classes
} else {
count++; block.yield(context, child);
}
}
Expand Down
55 changes: 50 additions & 5 deletions core/src/main/java/org/jruby/ext/jruby/JRubyLibrary.java
Expand Up @@ -37,21 +37,18 @@
import org.jruby.anno.JRubyModule;
import org.jruby.ast.Node;
import org.jruby.ast.RootNode;
import org.jruby.ast.util.ArgsUtil;
import org.jruby.ir.IRBuilder;
import org.jruby.ir.IRManager;
import org.jruby.ir.IRScriptBody;
import org.jruby.ir.targets.JVMVisitor;
import org.jruby.ir.targets.JVMVisitorMethodContext;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.Library;
import org.jruby.util.ByteList;
import org.jruby.util.ClasspathLauncher;

import java.io.ByteArrayInputStream;

Expand Down Expand Up @@ -307,4 +304,52 @@ public static IRubyObject load_string_ext(ThreadContext context, IRubyObject rec
return context.nil;
}

@JRubyMethod(module = true)
public static IRubyObject subclasses(ThreadContext context, IRubyObject recv, IRubyObject arg) {
return subclasses(context, recv, arg instanceof RubyClass ? (RubyClass) arg : arg.getMetaClass(), false);
}

@JRubyMethod(module = true)
public static IRubyObject subclasses(ThreadContext context, IRubyObject recv, IRubyObject arg, IRubyObject opts) {
boolean recurseAll = false;
opts = ArgsUtil.getOptionsArg(context.runtime, opts);
if (opts != context.nil) {
IRubyObject all = ((RubyHash) opts).fastARef(context.runtime.newSymbol("all"));
if (all != null) recurseAll = all.isTrue();
}
return subclasses(context, recv, arg instanceof RubyClass ? (RubyClass) arg : arg.getMetaClass(), recurseAll);
}

private static RubyArray subclasses(ThreadContext context, final IRubyObject recv,
final RubyClass klass, final boolean recurseAll) {

final RubyArray subclasses = RubyArray.newArray(context.runtime);

RubyClass singletonClass = ((RubyClass) klass).getSingletonClass();
RubyObjectSpace.each_objectInternal(context, recv, new IRubyObject[] { singletonClass },
new Block(new JavaInternalBlockBody(context.runtime, Signature.ONE_ARGUMENT) {

@Override
public IRubyObject yield(ThreadContext context, IRubyObject[] args) {
return doYield(context, null, args[0]);
}

@Override
protected IRubyObject doYield(ThreadContext context, Block block, IRubyObject value) {
if (klass != value) {
if (recurseAll) {
return subclasses.append(value);
}
if (((RubyClass) value).superclass(context) == klass) {
return subclasses.append(value);
}
}
return context.nil;
}

})
);
return subclasses;
}

}
5 changes: 2 additions & 3 deletions core/src/main/java/org/jruby/util/func/Function1.java
Expand Up @@ -29,6 +29,5 @@

package org.jruby.util.func;

public interface Function1<R,A0> {
public R apply(A0 a0);
}
@Deprecated
public interface Function1<R, A0> extends java.util.function.Function<A0, R> {}
5 changes: 5 additions & 0 deletions core/src/main/ruby/jruby/jruby.rb
Expand Up @@ -38,6 +38,11 @@ def compile_ir(content = nil, filename = DEFAULT_FILENAME, extra_position_info =
# @note implemented in *org.jruby.ext.jruby.JRubyLibrary*
def compile(content, filename = '', extra_position_info = false); end if false

# Get all known subclasses of passed class.
# If recurse: true, include all (non-direct) descendants recursively.
# @return Enumerable[Class]
def subclasses_of(klass, recurse: false) end if false

end

# NOTE: This is not a public API and is subject to change at our whim.
Expand Down
15 changes: 3 additions & 12 deletions lib/ruby/stdlib/jruby/core_ext/class.rb
Expand Up @@ -27,19 +27,10 @@ class Class
private_constant :JClass

##
# Get an array of all known subclasses of this class. If recursive == true,
# include all descendants.
# @deprecated since JRuby 9.2, use `JRuby.subclasses_of(klass)`
def subclasses(recursive = false)
subclasses = []
ObjectSpace.each_object(singleton_class) do |klass|
next if klass.equal? self
if recursive
subclasses << klass
else
subclasses << klass if klass.superclass.equal? self
end
end
subclasses
warn("klass.subclasses is deprecated, use JRuby.subclasses(klass) instead", uplevel: 1)
JRuby.subclasses(self, all: recursive)
end

##
Expand Down