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: 606ff6907698
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d2ec13ec25ae
Choose a head ref
  • 5 commits
  • 12 files changed
  • 3 contributors

Commits on Aug 26, 2015

  1. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    f3b41ae View commit details
  2. Copy the full SHA
    86c5a1d View commit details
  3. return correct superclass when there's a prepended module in the hier…

    …archy
    
    fixes #3276 (spec was added to rubyspecs thus should land with next merge)
    kares committed Aug 26, 2015
    Copy the full SHA
    2008589 View commit details
  4. Copy the full SHA
    6d5a78e View commit details
  5. Copy the full SHA
    d2ec13e View commit details
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -1116,7 +1116,9 @@ public IRubyObject superclass(ThreadContext context) {
throw runtime.newTypeError("uninitialized class");
}

while (superClazz != null && superClazz.isIncluded()) superClazz = superClazz.superClass;
while (superClazz != null && (superClazz.isIncluded() || superClazz.isPrepended())) {
superClazz = superClazz.superClass;
}

return superClazz != null ? superClazz : runtime.getNil();
}
49 changes: 32 additions & 17 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.IRBlockBody;
import org.jruby.runtime.MethodFactory;
@@ -105,6 +106,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -558,13 +560,13 @@ private String calculateAnonymousName() {
}


@JRubyMethod(name = "refine", required = 1)
@JRubyMethod(name = "refine", required = 1, reads = SCOPE)
public IRubyObject refine(ThreadContext context, IRubyObject classArg, Block block) {
if (!block.isGiven()) throw context.runtime.newArgumentError("no block given");
if (block.isEscaped()) throw context.runtime.newArgumentError("can't pass a Proc as a block to Module#refine");
if (!(classArg instanceof RubyClass)) throw context.runtime.newTypeError(classArg, context.runtime.getClassClass());
if (refinements == Collections.EMPTY_MAP) refinements = new HashMap<>();
if (activatedRefinements == Collections.EMPTY_MAP) activatedRefinements = new HashMap<>();
if (refinements == Collections.EMPTY_MAP) refinements = new IdentityHashMap<>();
if (activatedRefinements == Collections.EMPTY_MAP) activatedRefinements = new IdentityHashMap<>();

RubyClass classWeAreRefining = (RubyClass) classArg;
RubyModule refinement = refinements.get(classWeAreRefining);
@@ -582,7 +584,8 @@ public IRubyObject refine(ThreadContext context, IRubyObject classArg, Block blo
}

private RubyModule createNewRefinedModule(ThreadContext context, RubyClass classWeAreRefining) {
RubyModule newRefinement = new RubyModule(context.runtime, classWeAreRefining);
RubyModule newRefinement = new RubyModule(context.runtime);
newRefinement.setSuperClass(classWeAreRefining);
newRefinement.setFlag(REFINED_MODULE_F, true);
newRefinement.setFlag(RubyObject.USER7_F, false); // Refinement modules should not do implementer check
newRefinement.refinedClass = classWeAreRefining;
@@ -604,14 +607,14 @@ private void yieldRefineBlock(ThreadContext context, RubyModule refinement, Bloc
// 3. refinement is already in the refinementwrapper so we do not need to add it to the wrapper again: return null
private RubyClass getAlreadyActivatedRefinementWrapper(RubyClass classWeAreRefining, RubyModule refinement) {
// We have already encountered at least one refine on this class. Return that wrapper.
RubyClass moduleWrapperForRefinment = activatedRefinements.get(classWeAreRefining);
if (moduleWrapperForRefinment == null) return classWeAreRefining;
RubyClass moduleWrapperForRefinement = activatedRefinements.get(classWeAreRefining);
if (moduleWrapperForRefinement == null) return classWeAreRefining;

for (RubyModule c = moduleWrapperForRefinment; c != null && c.isIncluded(); c = c.getSuperClass()) {
for (RubyModule c = moduleWrapperForRefinement; c != null && c.isIncluded(); c = c.getSuperClass()) {
if (c.getNonIncludedClass() == refinement) return null;
}

return moduleWrapperForRefinment;
return moduleWrapperForRefinement;
}

/*
@@ -621,24 +624,34 @@ private RubyClass getAlreadyActivatedRefinementWrapper(RubyClass classWeAreRefin
*/
// MRI: add_activated_refinement
private void addActivatedRefinement(ThreadContext context, RubyClass classWeAreRefining, RubyModule refinement) {
RubyClass superClass = getAlreadyActivatedRefinementWrapper(classWeAreRefining, refinement);
if (superClass == null) return; // already been refined and added to refinementwrapper

// RubyClass superClass = getAlreadyActivatedRefinementWrapper(classWeAreRefining, refinement);
// if (superClass == null) return; // already been refined and added to refinementwrapper
RubyClass superClass = null;
RubyClass c = activatedRefinements.get(classWeAreRefining);
if (c != null) {
superClass = c;
while (c != null && c.isIncluded()) {
if (((IncludedModuleWrapper)c).getNonIncludedClass() == refinement) {
/* already used refinement */
return;
}
c = c.getSuperClass();
}
}
refinement.setFlag(IS_OVERLAID_F, true);
IncludedModuleWrapper iclass = new IncludedModuleWrapper(context.runtime, superClass, refinement);
RubyClass c = iclass;
c = iclass;
c.refinedClass = classWeAreRefining;
for (refinement = refinement.getSuperClass(); refinement != null; refinement = refinement.getSuperClass()) {
refinement.setFlag(IS_OVERLAID_F, true);
RubyClass superClazz = c.getSuperClass();
c.setModuleSuperClass(new IncludedModuleWrapper(context.runtime, c.getSuperClass(), refinement));
c.setSuperClass(new IncludedModuleWrapper(context.runtime, c.getSuperClass(), refinement));
c = c.getSuperClass();
c.refinedClass = classWeAreRefining;
c = superClazz;
}
activatedRefinements.put(classWeAreRefining, iclass);
}

@JRubyMethod(name = "using", required = 1, frame = true)
@JRubyMethod(name = "using", required = 1, frame = true, reads = SCOPE)
public IRubyObject using(ThreadContext context, IRubyObject refinedModule) {
if (context.getFrameSelf() != this) throw context.runtime.newRuntimeError("Module#using is not called on self");
// FIXME: This is a lame test and I am unsure it works with JIT'd bodies...
@@ -647,7 +660,9 @@ public IRubyObject using(ThreadContext context, IRubyObject refinedModule) {
}

// I pass the cref even though I don't need to so that the concept is simpler to read
usingModule(context, this, refinedModule);
StaticScope staticScope = context.getCurrentStaticScope();
RubyModule overlayModule = staticScope.getOverlayModule(context);
usingModule(context, overlayModule, refinedModule);

return this;
}
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/RubyNumeric.java
Original file line number Diff line number Diff line change
@@ -583,8 +583,8 @@ public RubyNumeric asNumeric() {
*
*/
@JRubyMethod(name = "singleton_method_added")
public IRubyObject sadded(IRubyObject name) {
throw getRuntime().newTypeError("can't define singleton method " + name + " for " + getType().getName());
public static IRubyObject sadded(IRubyObject self, IRubyObject name) {
throw self.getRuntime().newTypeError("can't define singleton method " + name + " for " + self.getType().getName());
}

/** num_init_copy
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/TopSelfFactory.java
Original file line number Diff line number Diff line change
@@ -109,7 +109,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args) {
Arity.checkArgumentCount(context.runtime, args, 1, 1);
RubyModule cref = context.getCurrentStaticScope().getModule();
RubyModule cref = context.getCurrentStaticScope().getOverlayModule(context);
// unclear what the equivalent check would be for us
// rb_control_frame_t * prev_cfp = previous_frame(GET_THREAD());
//
Original file line number Diff line number Diff line change
@@ -153,20 +153,6 @@ public IRubyObject is_java_proxy() {
// utility methods
//

@Deprecated
protected RubyArray buildRubyArray(IRubyObject[] elements) {
RubyArray result = getRuntime().newArray(elements.length);
for (int i = 0; i < elements.length; i++) {
result.append(elements[i]);
}
return result;
}

@Deprecated
protected RubyArray buildRubyArray(final Class<?>[] classes) {
return JavaClass.toRubyArray(getRuntime(), classes);
}

final RubyArray toRubyArray(final IRubyObject[] elements) {
return RubyArray.newArrayNoCopy(getRuntime(), elements);
}
11 changes: 11 additions & 0 deletions core/src/main/java/org/jruby/parser/StaticScope.java
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Signature;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.scope.DummyDynamicScope;

@@ -97,6 +98,8 @@ public class StaticScope implements Serializable {
// scope refers to a method scope or to determined IRScope of the parent of a compiling eval.
private IRScope irScope;

private RubyModule overlayModule;

public enum Type {
LOCAL, BLOCK, EVAL;

@@ -530,4 +533,12 @@ public StaticScope duplicate() {

return dupe;
}

public RubyModule getOverlayModule(ThreadContext context) {
RubyModule omod = overlayModule;
if (omod == null) {
overlayModule = omod = RubyModule.newModule(context.runtime);
}
return omod;
}
}
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -56,7 +56,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -79,7 +79,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -102,7 +102,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -125,7 +125,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -148,7 +148,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -171,7 +171,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -194,7 +194,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -217,7 +217,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
@@ -240,7 +240,7 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

while (refinedScope != null &&
(
(refinements = refinedScope.getModule().getRefinements()).isEmpty() ||
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
1 change: 1 addition & 0 deletions test/mri.index
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ ruby/test_rational2.rb
ruby/test_readpartial.rb
ruby/test_regexp.rb
ruby/test_require.rb
ruby/test_refinement.rb
ruby/test_rubyoptions.rb
# Removed until we can implement the remaining features (#2143)
#ruby/test_settracefunc.rb
30 changes: 30 additions & 0 deletions test/mri/excludes/TestRefinement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
exclude :test_adding_private_method, "needs investigation"
exclude :test_call_refined_method_in_duplicate_module, "needs investigation"
exclude :test_case_dispatch_is_aware_of_refinements, "needs investigation"
exclude :test_include_into_refinement, "needs investigation"
exclude :test_inspect, "needs investigation"
exclude :test_making_private_method_public, "needs investigation"
exclude :test_module_inclusion, "needs investigation"
exclude :test_module_inclusion2, "needs investigation"
exclude :test_module_using, "needs investigation"
exclude :test_module_using_class, "needs investigation"
exclude :test_module_using_in_method, "needs investigation"
exclude :test_module_using_invalid_self, "needs investigation"
exclude :test_new_method, "needs investigation"
exclude :test_new_method_on_subclass, "needs investigation"
exclude :test_override, "needs investigation"
exclude :test_prepend_into_refinement, "needs investigation"
exclude :test_refine_after_using, "needs investigation"
exclude :test_refine_in_class, "needs investigation"
exclude :test_refine_mutual_recursion, "needs investigation"
exclude :test_refine_recursion, "needs investigation"
exclude :test_refine_scoping, "needs investigation"
exclude :test_refine_with_proc, "needs investigation"
exclude :test_refined_method_defined, "needs investigation"
exclude :test_remove_refined_method, "needs investigation"
exclude :test_remove_undefined_refined_method, "needs investigation"
exclude :test_singleton_method_should_not_use_refinements, "needs investigation"
exclude :test_super, "needs investigation"
exclude :test_undefined_refined_method_defined, "needs investigation"
exclude :test_using_in_method, "needs investigation"
exclude :test_using_in_module, "needs investigation"
Loading