Project

General

Profile

Actions

Feature #5582

open

Allow clone of singleton methods on a BasicObject

Added by thinkerbot (Simon Chiang) over 12 years ago. Updated about 6 years ago.

Status:
Assigned
Target version:
-
[ruby-core:40805]

Description

Currently I do not know of a way to implement something like 'clone' on a BasicObject subclass. This is as close as I've gotten but as you can see the singleton methods are not propagated to the clone.

require 'test/unit'

class Context < BasicObject
  def _singleton_class_
    class << self
      SINGLETON_CLASS = self
      def _singleton_class_
        SINGLETON_CLASS
      end
    end
    _singleton_class_
  end

  def _class_
    _singleton_class_.superclass
  end

  def _extend_(mod)
    mod.__send__(:extend_object, self)
  end

  def _initialize_clone_(orig)
    # set variables as needed
  end

  def _clone_
    clone = _class_.allocate
    clone._initialize_clone_(self)
    _singleton_class_.included_modules.each {|mod| clone._extend_ mod }
    clone
  end
end

class ContextTest < Test::Unit::TestCase
  module A
    def a
      :a
    end
  end

  def test__clone__inherits_modules
    context = Context.new
    context._extend_ A
    clone = context._clone_
    assert_equal :a, clone.a
  end

  def test__clone__inherits_singleton_methods
    context = Context.new

    def context.a
      :a
    end

    clone = context._clone_
    assert_equal :a, clone.a  # fails
  end
end

Is there a way to do this that I don't see? If not, then I request that a way be added - perhaps by allowing the singleton_class to be set somehow.

In my case I am using Context as the context for a dsl where methods write to a target (an instance variable). I want to be able to clone a context such that I can have multiple contexts with the same methods, including extensions and singletons, that write to different targets.

Thank you.

Updated by kernigh (George Koehler) over 12 years ago

=begin
My first attempt:

module Clone
include Kernel
(instance_methods - [:clone, :initialize_clone]).each {|m| undef_method m}
end

b = BasicObject.new
class << b
include ::Clone
def single; "Quack!"; end
end

c = b.clone
puts c.single

Output:

scratch.rb:3: warning: undefining `object_id' may cause serious problems
Quack!

Clone inherits from Kernel, but undefines all its instance methods except Clone#clone and Clone#initialize_clone. This technique has some awful side effects: Kernel === b and Kernel === c become true. Clone might inherit metamethods from Kernel (because I only undefined instance methods, not metamethods).
=end

Updated by mame (Yusuke Endoh) almost 12 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

Updated by mame (Yusuke Endoh) over 11 years ago

  • Target version changed from 1.9.2 to 2.6

Updated by nobu (Nobuyoshi Nakada) over 11 years ago

=begin
2.0 allows `method transplanting'.

module Clone
%i[clone initialize_copy initialize_dup initialize_clone].each do |m|
define_method(m, Kernel.instance_method(m))
end
end
=end

Actions #5

Updated by naruse (Yui NARUSE) about 6 years ago

  • Target version deleted (2.6)
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0