Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 80966bea3f8f
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4036c08fd1cf
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Mar 23, 2016

  1. [ji] keep (deprecated) JavaPackageModuleTemplate constant for compati…

    …bility
    
    ... its probably fine to remove - but just in case
    kares committed Mar 23, 2016

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f226b78 View commit details
  2. [ji] packages shall try to handle respond_to? and respond_to_missing?…

    … right
    
    ... also restored singleton method hooks for compatibility with previous versions
    kares committed Mar 23, 2016
    Copy the full SHA
    4036c08 View commit details
Showing with 126 additions and 28 deletions.
  1. +98 −24 core/src/main/java/org/jruby/javasupport/JavaPackage.java
  2. +28 −4 test/jruby/test_higher_javasupport.rb
122 changes: 98 additions & 24 deletions core/src/main/java/org/jruby/javasupport/JavaPackage.java
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
import org.jruby.IncludedModuleWrapper;
import org.jruby.MetaClass;
import org.jruby.Ruby;
import org.jruby.RubyBoolean;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.RubyString;
@@ -38,12 +39,15 @@
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.NullMethod;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ClassProvider;

import static org.jruby.runtime.Visibility.PRIVATE;

/**
* A "thin" Java package wrapper (for the runtime to see them as Ruby objects).
*
@@ -67,6 +71,10 @@ static RubyModule createJavaPackageClass(final Ruby runtime, final RubyModule Ja
Java.setConstant("JavaPackage", JavaPackage); // Java::JavaPackage
// JavaPackage.setReifiedClass(JavaPackage.class);

// @deprecated JavaPackageModuleTemplate used previously
runtime.getObject().setConstant("JavaPackageModuleTemplate", JavaPackage); // JavaPackageModuleTemplate
runtime.getObject().deprecateConstant(runtime, "JavaPackageModuleTemplate");

JavaPackage.defineAnnotatedMethods(JavaPackage.class);
return JavaPackage;
}
@@ -169,13 +177,70 @@ RubyModule relativeJavaProxyClass(final Ruby runtime, final IRubyObject name) {
return Java.getProxyClass(runtime, javaClass);
}

@JRubyMethod(name = "respond_to?")
public IRubyObject respond_to_p(final ThreadContext context, IRubyObject name) {
return respond_to(context, name, false);
}

@JRubyMethod(name = "respond_to?")
public IRubyObject respond_to_p(final ThreadContext context, IRubyObject name, IRubyObject includePrivate) {
return respond_to(context, name, includePrivate.isTrue());
}

private IRubyObject respond_to(final ThreadContext context, IRubyObject mname, final boolean includePrivate) {
String name = mname.asJavaString();
if ( getMetaClass().isMethodBound(name, !includePrivate, true) ) {
return context.runtime.getTrue();
}
/*
if ( ( name = BlankSlateWrapper.handlesMethod(name) ) != null ) {
RubyBoolean bound = checkMetaClassBoundMethod(context, name, includePrivate);
if ( bound != null ) return bound;
return context.runtime.getFalse(); // un-bound (removed) method
}
*/

//if ( ! (mname instanceof RubySymbol) ) mname = context.runtime.newSymbol(name);
//IRubyObject respond = Helpers.invoke(context, this, "respond_to_missing?", mname, context.runtime.newBoolean(includePrivate));
//return context.runtime.newBoolean(respond.isTrue());

return context.nil; // NOTE: this is wrong - should be true but compatibility first, for now
}

private RubyBoolean checkMetaClassBoundMethod(final ThreadContext context, final String name, final boolean includePrivate) {
// getMetaClass().isMethodBound(name, !includePrivate, true)
DynamicMethod method = getMetaClass().searchMethod(name);
if ( ! method.isUndefined() && ! method.isNotImplemented() ) {
if ( ! includePrivate && method.getVisibility() == PRIVATE ) {
return context.runtime.getFalse();
}
return context.runtime.getTrue();
}
return null;
}

@JRubyMethod(name = "respond_to_missing?")
public IRubyObject respond_to_missing_p(final ThreadContext context, IRubyObject name) {
return respond_to_missing(context, name, false);
}

@JRubyMethod(name = "respond_to_missing?")
public IRubyObject respond_to_missing_p(final ThreadContext context, IRubyObject name, IRubyObject includePrivate) {
return respond_to_missing(context, name, includePrivate.isTrue());
}

private RubyBoolean respond_to_missing(final ThreadContext context, IRubyObject mname, final boolean includePrivate) {
final String name = mname.asJavaString();
if ( BlankSlateWrapper.handlesMethod(name) != null ) {
return context.runtime.getFalse(); // not missing!
}
return context.runtime.getTrue();
}

@JRubyMethod(name = "method_missing", visibility = Visibility.PRIVATE)
public IRubyObject method_missing(ThreadContext context, final IRubyObject name) {
final RubyModule result = Java.getProxyOrPackageUnderPackage(context, this, name.toString(), true);
// NOTE: getProxyOrPackageUnderPackage binds the (cached) method for us

if ( result == null ) return context.nil; // TODO this is wrong
return result;
return Java.getProxyOrPackageUnderPackage(context, this, name.toString(), true);
}

@JRubyMethod(name = "method_missing", rest = true, visibility = Visibility.PRIVATE)
@@ -247,57 +312,66 @@ static final class BlankSlateWrapper extends IncludedModuleWrapper {
}

@Override
protected DynamicMethod searchMethodCommon(final String name) {
protected DynamicMethod searchMethodCommon(String name) {
// this module is special and only searches itself;

// TODO implement a switch to allow for 'more-aligned' behavior

// do not go to superclasses except for special methods :
return (name = handlesMethod(name)) != null ? superClass.searchMethodInner(name) : NullMethod.INSTANCE;
}

private static String handlesMethod(final String name) {
switch (name) {
case "class" : case "singleton_class" :
case "object_id" : case "name" :
case "class" : case "singleton_class" : return name;
case "object_id" : case "name" : return name;
// these are handled already at the JavaPackage.class :
// case "const_get" : case "const_missing" : case "method_missing" :
case "const_set" :
case "inspect" : case "to_s" :
case "const_set" : return name;
case "inspect" : case "to_s" : return name;
// these are handled bellow in switch (name.charAt(0))
// case "__method__" : case "__send__" : case "__id__" :

//case "require" : case "load" :
case "throw" : case "catch" : //case "fail" : case "raise" :
//case "exit" : case "at_exit" :
return superClass.searchMethodInner(name);

case "__constants__" : // @Deprecated compatibility with 1.7
return superClass.searchMethodInner("constants");
case "__methods__" : // @Deprecated compatibility with 1.7
return superClass.searchMethodInner("methods");
return name;

case "singleton_method_added" :
// JavaPackageModuleTemplate handled "singleton_method_added"
case "singleton_method_undefined" :
case "singleton_method_removed" :
case "define_singleton_method" :
return name;

// NOTE: these should maybe get re-thought and deprecated (for now due compatibility)
case "__constants__" : return "constants";
case "__methods__" : return "methods";
}

final int last = name.length() - 1;
if ( last >= 0 ) {
switch (name.charAt(last)) {
case '?' : case '!' : case '=' :
return name;
}
switch (name.charAt(0)) {
case '<' : case '>' : case '=' : // e.g. ==
return superClass.searchMethodInner(name);
return name;
case '_' : // e.g. __send__
if ( last > 0 && name.charAt(1) == '_' ) {
return superClass.searchMethodInner(name);
return name;
}
}
switch (name.charAt(last)) {
case '?' : case '!' : case '=' :
return superClass.searchMethodInner(name);
}
}

//if ( last >= 5 && (
// name.indexOf("method") >= 0 || // method, instance_methods, singleton_methods ...
// name.indexOf("variable") >= 0 || // class_variables, class_variable_get, instance_variables ...
// name.indexOf("constant") >= 0 ) ) { // constants, :public_constant, :private_constant
// return superClass.searchMethodInner(name);
// return true;
//}

return NullMethod.INSTANCE;
return null;
}

@Override
32 changes: 28 additions & 4 deletions test/jruby/test_higher_javasupport.rb
Original file line number Diff line number Diff line change
@@ -850,8 +850,11 @@ def test_that_misspelt_fq_class_names_dont_stop_future_fq_class_names_with_same_
end

def test_that_subpackages_havent_leaked_into_other_packages
assert_equal(false, Java::java.respond_to?(:zip))
assert_equal(false, Java::com.respond_to?(:util))
assert ! Java::java.respond_to?(:zip)
assert ! Java::com.respond_to?(:util)

assert Java::java.respond_to_missing?(:zip)
assert Java::comx.respond_to_missing?(:foo)
end

def test_that_sub_packages_called_java_javax_com_org_arent_short_circuited
@@ -902,6 +905,26 @@ def test_package_object_id
assert Java::java::lang.object_id.is_a?(Fixnum)
end

def test_package_singleton_method_hooks
assert org.respond_to?(:singleton_method_added, true)
assert java.lang.respond_to?(:singleton_method_removed, true)

assert_nil org.__send__(:singleton_method_added, :sym)
assert_nil java.lang.__send__(:singleton_method_removed, :sym)
end

def test_package_does_not_respond_to_hidden_methods
assert Kernel.respond_to?(:test)
assert ! org.respond_to?(:test)
assert ! java.lang.respond_to?(:test, true)
end

def test_package_does_respond_to_missing
assert org.respond_to_missing?(:test)
assert java.lang.respond_to_missing?(:test)
assert java.lang.respond_to_missing?(:test, true)
end

@@include_proc = Proc.new do
Thread.stop
java_import "java.lang.System"
@@ -1240,9 +1263,10 @@ def test_that_classes_beginning_with_small_letter_can_be_referenced
# JRUBY-1076
def test_package_module_aliased_methods
assert java.lang.respond_to?(:__constants__)
assert java.lang.respond_to?(:__methods__)
assert java.lang.respond_to?(:__methods__, true)

java.lang.String # ensure java.lang.String has been loaded
java.lang.String # ensure java.lang.
# String has been loaded
assert java.lang.__constants__.include?(:String)
end