Given a singleton class:
irb(main):001:0> class Foo
irb(main):002:1> def self.singleton_class
irb(main):003:2> return class << self; self; end
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> sc = Foo.singleton_class
=> #Class:Foo
How can I get class that the singleton class is a singleton class of?
(and is there a name for this?)
class << sc
def un_singleton_class
# ?
end
end
sc.un_singleton_class #=> Foo
I know only of the brute-force solution:
irb(main):011:0> sc = Foo.singleton_class
=> #Class:Foo
irb(main):012:0> class Class; def singleton_class; class << self;
self; end; end; end
=> nil
irb(main):013:0> ObjectSpace.each_object(Class) { |c| break c if
c.singleton_class == sc }
=> Foo
But I was hoping I had overlooked something.
Paul
On Sep 17, 2008, at 1:23 PM, Paul B. wrote:
How can I get class that the singleton class is a singleton class of?
(and is there a name for this?)
it might not be a class… but will this work?
cfp:~ > cat a.rb
class Object
def singleton_class &block
sc =
class << self
self
end
unless sc.respond_to?(:parent)
parent_id = self.object_id #Module === self ? self : self.class
sc.instance_eval "def parent()
ObjectSpace._id2ref(#{ parent_id }) end"
end
block ? sc.module_eval(&block) : sc
end
end
p File.singleton_class.parent
p Array.new.singleton_class.parent
p Hash.new.singleton_class.parent
p Hash.new.singleton_class{ parent }
p Hash.singleton_class{ parent }
options = { :key => :value }
options.singleton_class do
def getopt opt
fetch(opt.to_s.to_sym) rescue fetch(opt.to_s)
end
end
p options.getopt(:key)
cfp:~ > ruby a.rb
File
[]
{}
{}
Hash
:value
a @ http://codeforpeople.com/
Paul B. wrote:
How can I get class that the singleton class is a singleton class of?
In general, an eigenclass (or singleton class) can be an eigenclass of
anything, and not only of a class. It can be like this:
class<<“asd”;self;end.
irb(main):013:0> ObjectSpace.each_object(Class) { |c| break c if
c.singleton_class == sc }
=> Foo
Why complicate?
a=anything
ec=class<<a;self;end
a_=nil
ObjectSpace.each_object(ec){|aa| a_=aa}
a.equal?(a_) #=> true
The object space will call the block only once.
TPR.
Thomas B. [2008-09-17 23:07]:
Why complicate?
a=anything
ec=class<<a;self;end
a_=nil
ObjectSpace.each_object(ec){|aa| a_=aa}
a.equal?(a_) #=> true
thanks, absorbed
http://prometheus.rubyforge.org/ruby-nuggets/classes/Object.html#M000085
cheers
jens
On Thu, Sep 18, 2008 at 04:43:40AM +0900, ara.t.howard wrote:
it might not be a class… but will this work?
It would, except that calling #singleton_class isn’t the only way to get
a singleton class.
unless sc.respond_to?(:parent)
parent_id = self.object_id #Module === self ? self : self.class
sc.instance_eval "def parent() ObjectSpace._id2ref(#{ parent_id })
end"
end
Does doing this allow a class to be garbage-collected but allow its
singleton class to stick around?
Probably better to use define_method with a block in this case.
Paul
On Sep 18, 2008, at 8:07 AM, Paul B. wrote:
On Thu, Sep 18, 2008 at 04:43:40AM +0900, ara.t.howard wrote:
it might not be a class… but will this work?
It would, except that calling #singleton_class isn’t the only way to
get
a singleton class.
yup - i was afraid you’d say that…
singleton class to stick around?
yes. you don’t have to worry about the object being stale when this
is called since the singleton class if owned by the object it’s
looking up by id
Probably better to use define_method with a block in this case.
i was worried about the gc. also you use define_method you have to get
into the singleton class of a singleton class - which starts to get
yucky. ‘def’ works at the instance scope so my approach seemed safer
and simpler. but i think define_method could be made to work…
Paul
cheers.
a @ http://codeforpeople.com/
Paul B. [2008-09-18 20:23]:
=> #Class:Base
irb(main):006:0> ObjectSpace.each_object(sc) { |c| p c }
Derived
Base
=> 2
good catch! but this should work then:
irb(main):006:0> ObjectSpace.each_object(sc) { |c| p c if
sc.equal?(class << c; self; end) }
Base
=> 2
i’ll update my implementation in ruby-nuggets tomorrow (moving the
check that i’m doing anyway inside the loop; thanks).
cheers
jens
On Thu, Sep 18, 2008 at 06:07:29AM +0900, Thomas B. wrote:
Why complicate?
a=anything
ec=class<<a;self;end
a_=nil
ObjectSpace.each_object(ec){|aa| a_=aa}
a.equal?(a_) #=> true
I like your idea, though consider:
irb(main):001:0> class Base; end
=> nil
irb(main):002:0> class Derived < Base; end
=> nil
irb(main):003:0> sc = class << Derived; self; end
=> #Class:Derived
irb(main):004:0> ObjectSpace.each_object(sc) { |c| p c }
Derived
=> 1
irb(main):005:0> sc = class << Base; self; end
=> #Class:Base
irb(main):006:0> ObjectSpace.each_object(sc) { |c| p c }
Derived
Base
=> 2
Thomas B. [2008-09-18 21:39]:
Now I’m wondering if it is possible to construct such an object
that belong to a foreign eigenclass and not be a class itself. In
other words, how to make my code fail even though a is not a
Class. Any ideas?
not sure what you mean by that. but it fails for the singleton
classes of objects like true, false, and nil (TrueClass, FalseClass,
and NilClass resp.), which can safely be special-cased. here’s the
updated implementation:
strictly speaking it belongs under Class,
but i like to keep things together in this case
class Object
def singleton_object
[true, false, nil].each { |obj|
return obj if self.equal?(obj.singleton_class)
}
# raises TypeError if neither class nor module
ObjectSpace.each_object(self) { |obj|
return obj if self.equal?(obj.singleton_class)
}
# if we got here it can't be a singleton class
# or its singleton object doesn't exist anymore
raise TypeError
rescue TypeError
raise TypeError, ‘not a singleton class’
end
end
cheers
jens
Paul B. wrote:
On Thu, Sep 18, 2008 at 06:07:29AM +0900, Thomas B. wrote:
Why complicate?
a=anything
ec=class<<a;self;end
a_=nil
ObjectSpace.each_object(ec){|aa| a_=aa}
a.equal?(a_) #=> true
irb(main):006:0> ObjectSpace.each_object(sc) { |c| p c }
Derived
Base
=> 2
You’re right. I was thinking about “regular” object’s eigenclasses and
not eigenclasses of classes, and with them I think my solution will
work. My mistake.
But now I finally understand the remark I read somewhere and ignored,
because I didn’t think it was important. It said that the “method
lookup” for classes includes eigenclasses of their ancestors.
Now I’m wondering if it is possible to construct such an object that
belong to a foreign eigenclass and not be a class itself. In other
words, how to make my code fail even though a is not a Class. Any ideas?
TPR.