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: ae9056333a98
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 477eb70ccb11
Choose a head ref
  • 4 commits
  • 2 files changed
  • 1 contributor

Commits on Nov 8, 2016

  1. Copy the full SHA
    afe5e51 View commit details
  2. Copy the full SHA
    e6ccd18 View commit details
  3. Copy the full SHA
    d909f04 View commit details
  4. Merge pull request #4233 from headius/fix_clone_hierarchy

    Fix clone hierarchy
    headius authored Nov 8, 2016
    Copy the full SHA
    477eb70 View commit details
Showing with 38 additions and 3 deletions.
  1. +7 −3 core/src/main/java/org/jruby/RubyBasicObject.java
  2. +31 −0 spec/ruby/core/kernel/clone_spec.rb
10 changes: 7 additions & 3 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
@@ -959,7 +959,7 @@ public IRubyObject rbClone() {

// We're cloning ourselves, so we know the result should be a RubyObject
RubyBasicObject clone = (RubyBasicObject)getMetaClass().getRealClass().allocate();
clone.setMetaClass(getSingletonClassClone());
clone.setMetaClass(getSingletonClassCloneAndAttach(clone));
if (isTaint()) clone.setTaint(true);

initCopy(runtime.getCurrentContext(), clone, this, true);
@@ -968,21 +968,25 @@ public IRubyObject rbClone() {
return clone;
}

protected RubyClass getSingletonClassClone() {
return getSingletonClassCloneAndAttach(UNDEF);
}

/** rb_singleton_class_clone
*
* Will make sure that if the current objects class is a
* singleton, it will get cloned.
*
* @return either a real class, or a clone of the current singleton class
*/
protected RubyClass getSingletonClassClone() {
protected RubyClass getSingletonClassCloneAndAttach(IRubyObject attach) {
RubyClass klass = getMetaClass();

if (!klass.isSingleton()) {
return klass;
}

MetaClass clone = new MetaClass(getRuntime(), klass.getSuperClass(), ((MetaClass) klass).getAttached());
RubyClass clone = new MetaClass(getRuntime(), klass.getSuperClass(), attach);
clone.flags = flags;

if (this instanceof RubyClass) {
31 changes: 31 additions & 0 deletions spec/ruby/core/kernel/clone_spec.rb
Original file line number Diff line number Diff line change
@@ -62,4 +62,35 @@ class << clone
nil.clone
}.should raise_error(TypeError)
end

it "replaces a singleton object's metaclass with a new copy with the same superclass" do
cls = Class.new do
def bar
['a']
end
end

object = cls.new
object.define_singleton_method(:bar) do
['b', *super()]
end
object.bar.should == ['b', 'a']

cloned = object.clone

cloned.singleton_methods.should == [:bar]

# bar should replace previous one
cloned.define_singleton_method(:bar) do
['c', *super()]
end
cloned.bar.should == ['c', 'a']

# bar should be removed and call through to superclass
cloned.singleton_class.class_eval do
remove_method :bar
end

cloned.bar.should == ['a']
end
end