def inside_metaclass?
# to be implemented
end
class C
class << self
p inside_metaclass? #=> true
end
p inside_metaclass? #=> false
end
p inside_metaclass? #=> false
class << []
p inside_metaclass? #=> true
end
can this be done?
cheers.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================
Would you settle for testing if you're inside an anonymous class?
Anonymous classes have names that look like:
#<Class:...>
So you can define your method as:
def inside_metaclass?
Integer === (self.to_s =~ /^#<Class:/)
end
Which will evaluate to true for anonymous classes. Since (I believe)
all meta-classes are anonymous that can give you a pretty good guess
(or at least has the same result as your sample).
Out of curiosity I've run:
ObjectSpace.each_object { |o| p [o, o.class] if o.to_s =~ /^#<Class:/ }
Which returned ~30 such objects (anonymous classes, unless I'm
mistaken). So unless you're opening an anonymous class, you should be
OK (and I'm not even sure you can reopen an anonymous class).
HTH,
Assaph
To expand on that... metaclasses have a peculiar inspect value. This
code is breakable, but probably only if you try to:
class Class
def metaclass?
id = inspect[/\A\#<Class:\#<.+?\:0x(.+?)>>\Z/, 1]
ObjectSpace._id2ref(id.to_i(16)/2) if id
end
end
The metaclass? method will return nil if the receiver is not a
metaclass, or it's instance if it *is* a metaclass. Use it like this:
class << (a="test")
p self.metaclass? #==> prints "test"
end
class Foo
p self.metaclass? #==> prints nil
end
There's probably a safer way to do this using ruby/dl, or evil.rb. I
don't know, though.
cheers,
Mark
> i like a method like this
>
> def inside_metaclass?
> # to be implemented
> end
>
> class C
> class << self
> p inside_metaclass? #=> true
> end
>
> p inside_metaclass? #=> false
> end
>
> p inside_metaclass? #=> false
>
> class << []
> p inside_metaclass? #=> true
> end
>
> can this be done?
Is this cheating?:
#include "ruby.h"
VALUE metaclass_p(VALUE self) {
if (FL_TEST(self, FL_SINGLETON))
return Qtrue;
else
return Qfalse;
}
void Init_test(void) {
rb_define_method(rb_cClass, "metaclass?", metaclass_p, 0);
}
> To expand on that... metaclasses have a peculiar inspect value. This
> code is breakable, but probably only if you try to:
>
> [...]
>
> There's probably a safer way to do this using ruby/dl, or evil.rb. I
> don't know, though.
I'm not sure if you consider this safer, but while you can subclass
anonymous and normal classes you can not do so for idioclasses so this
ought to work:
class Class
def idioclass?()
Class.new(self)
return true
rescue TypeError
return false
end
end
Of course somebody /could/ raise a TypeError in the inherited hook, but
that is quite unlikely to happen.
evil-ruby can of course check the actual RTYPE of the class which is
unbreakable, but that is a dependency you might not want to have.
> Would you settle for testing if you're inside an anonymous class? Anonymous
> classes have names that look like: #<Class:...>
>
> So you can define your method as:
>
> def inside_metaclass?
> Integer === (self.to_s =~ /^#<Class:/)
> end
>
> Which will evaluate to true for anonymous classes. Since (I believe) all
> meta-classes are anonymous that can give you a pretty good guess (or at
> least has the same result as your sample).
>
> Out of curiosity I've run:
> ObjectSpace.each_object { |o| p [o, o.class] if o.to_s =~ /^#<Class:/ }
>
> Which returned ~30 such objects (anonymous classes, unless I'm mistaken). So
> unless you're opening an anonymous class, you should be OK (and I'm not even
> sure you can reopen an anonymous class).
hmm. that will probably work. what i want is something for my attributes
module that does
class C
attribute 'foobar' #=> defines instance method
class_attribute 'foobar' #=> defines class instance method
class << self
attribute 'foobar' #=> defines class instance method
end
end
eg. i want the metacode generater 'attribute' to be context sensitive as in
def attribute name
if inside_metaclass? and self.is_a? Class
class_attribute name
else
...
end
end
the above should work but may give unforseen problems... any spring to mind?
Sorry for the newbie question, but what does this mean?
--
Lionel Thiry
Personal website: http://users.skynet.be/lthiry/
Yes, like this:
class Object
def inside_metaclass?() false end
end
class Class
def inside_metaclass?
begin
self.allocate
false
rescue TypeError => e
/virtual class/i =~ e.to_s and true
end
end
end
irb(main):058:0> class <<Object.new; p inside_metaclass? end
true
=> nil
irb(main):059:0> p inside_metaclass?
false
=> nil
irb(main):060:0> class String; p inside_metaclass? end
false
=> nil
Cheers
robert
>> class << []
>> p inside_metaclass? #=> true
>> end
>
> Sorry for the newbie question, but what does this mean?
class << obj enters the idioclass of an object which is a class that
contains method that will only be defined for that particular object.
When
obj = "Pacman -> (<"
then
class << obj
def reverse() ">) <- Pacman" end
end
is the same as
def obj.reverse() ">) <- Pacman" end
So we provide a custom implementation of reverse() for a single method
only -- you can also use this for adding completely new functionality.
So why is the class << obj syntax necessary at all?
To apply other class abilities to a single object. You might want to
create an accessor for only one single object:
obj = Array.new
class << obj
attr_accessor :creator
end
obj.creator # => nil
obj.creator = ENV["username"]
obj.creator # => "flgr" (your result may vary ;))
obj << "foo"
obj << "bar"
obj # => ["foo", "bar"]
But even after that code:
ary = Array.new
ary.creator # raises NoMethodError
Oh, and p obj just outputs an object's state for debugging. (It is the
same as doing puts obj.inspect)
hmm. i like this more than the pure matching version - which seemed a bit
fragile.
seems like i could do
harp:~ > cat a.rb
class Object
def inside_metaclass?
begin
allocate()
false
rescue NoMethodError
false
rescue TypeError => e
%r/virtual class/i =~ e.to_s and true
end
end
end
obj = Object::new
klass = Class::new
p inside_metaclass? #=> false
class << obj
p inside_metaclass? #=> true
end
class << klass
p inside_metaclass? #=> true
end
class << self
p inside_metaclass? #=> true
end
harp:~ > ruby a.rb
false
true
true
true
too.
now - any opinions on whether this violates POLS or not:
#
# my attributes module - hoping to become a collection of better 'attr' like
# metamethods...
#
require 'attributes'
class C
#
# define a class attr => used like C::foo
#
class_attribute 'foo'
#
# define an instance attr => C::new.bar
#
attribute 'bar'
class << self
#
# define a class attr => used like C::foobar
#
# note that this would be the SAME as using class_attribute 'foobar'
# outside of metaclass
#
attribute 'foobar'
end
end
so, you see, Object::attribute would be context sensitive to being inside a
metaclass or not - if inside a Class.metaclass it's defining a class
attribute, else an instance attribute.
thoughts?
Florian: Great explanation.
Lionel: If 'class << []' itself seems a little odd to you, read on...
The class << obj notation can be used in ways that you might not
expect. Since ruby syntax is not as ridged as some other languages,
any expression can take the place of 'obj' in that notation. For
example, if you want to create a temporary/mock object of some sort:
def clear
class << (a = Object.new)
def inspect() `clear` end
end
end
(this example was pulled right out of my irbrc)
As you can see, 'a' was assigned to, and then the resulting object was
opened for modification. So this code:
class << []
# do stuff
end
.. just creates an anonymous array and opens it's metaclass (or
idioclass or singleton class or virtual class, whatever). However, the
array is never assigned to a variable, so it will probably be garbage
collected pretty soon. You will probably never see this exact thing in
someone's code, but it is possible.
cheers,
Mark
class Object
def idioclass? ; false ; end
end
class Class
alias :newnew :new
def new( *args )
class << self
def idioclass? ; !super ; end
end
newnew( *args )
end
end
# test
class A
def initialize
p idioclass? #=> false
class << self
p idioclass? #=> true
end
end
end
a = A.new
produces
false
true
T.
Yeah, great. :)
But I already knew about the singleton methods and their container object, the
said idioclass. But I didn't know well all the subtleties of 'class << obj',
hence my initial question.
>
> Lionel: If 'class << []' itself seems a little odd to you, read on...
>
Ok, I read, I read! :)
> The class << obj notation can be used in ways that you might not
> expect. Since ruby syntax is not as ridged as some other languages,
> any expression can take the place of 'obj' in that notation. For
> example, if you want to create a temporary/mock object of some sort:
>
> def clear
> class << (a = Object.new)
> def inspect() `clear` end
> end
> end
>
> (this example was pulled right out of my irbrc)
>
> As you can see, 'a' was assigned to, and then the resulting object was
> opened for modification. So this code:
>
> class << []
> # do stuff
> end
>
> .. just creates an anonymous array and opens it's metaclass (or
> idioclass or singleton class or virtual class, whatever). However, the
> array is never assigned to a variable, so it will probably be garbage
> collected pretty soon. You will probably never see this exact thing in
> someone's code, but it is possible.
This probably explains why it was so odd to me, I've mainly met the 'class <<
self' version.
Thanks a lot to you all! :)
The way it works is analogous to "def attribute_name", which is
unsurprising. I like it.
I also like the setter capability of the getter methods (setting attributes
in a block passed to the constructor looks very clean), and I'm sure I'll be
using your module a in future.
Cheers,
Dave
While experimenting with this, I discovered something interesting: it
is possible to instantiate a metaclass. By duping a metaclass, you
regain the ability to instantiate it, apparently without losing any
functionality.
name = "Jack Smith"
def name.reverse
split.reverse.join ", "
end
name.reverse #==> "Smith, Jack"
# dup name's metaclass
nameclass = class << name; self; end.dup
name2 = nameclass.new "John Doe"
name2.reverse #==> "Doe, John"
Any thoughts? Am I strange for finding this a bit surprising?
cheers,
Mark
> While experimenting with this, I discovered something interesting: it
> is possible to instantiate a metaclass. By duping a metaclass, you
> regain the ability to instantiate it, apparently without losing any
> functionality.
>
> name = "Jack Smith"
> def name.reverse
> split.reverse.join ", "
> end
> name.reverse #==> "Smith, Jack"
>
> # dup name's metaclass
> nameclass = class << name; self; end.dup
>
> name2 = nameclass.new "John Doe"
> name2.reverse #==> "Doe, John"
>
> Any thoughts? Am I strange for finding this a bit surprising?
Well, duping a metaclass doesn't really return a metaclass. That is,
it is no longer a thing tied to one object; it's just a free-roaming
class like any other. (I won't comment on whether or not that's
"surprising" -- *wanting* to #dup a singleton class is surprising
enough for me. ;-)
What you may have noticed is that #dup-ing a class doesn't copy it's
singleton-class-ness, but #clone-ing does. Replace your `dup' with
`clone', and you'll get an error, since you can't instantiate the
clone:
irb(main):001:0> s = ''
=> ""
irb(main):002:0> (class << s; self; end).clone.new
TypeError: can't create instance of singleton class
from (irb):2:in `new'
from (irb):2
The weirdness here is that the clone is a singleton class (as implied
by the error message), but can have no instance!
i dunno - but that's cool.
On Sat, 30 Apr 2005, Mark Hubbart wrote:
> While experimenting with this, I discovered something interesting: it
> is possible to instantiate a metaclass. By duping a metaclass, you
> regain the ability to instantiate it, apparently without losing any
> functionality.
>
> name = "Jack Smith"
> def name.reverse
> split.reverse.join ", "
> end
> name.reverse #==> "Smith, Jack"
>
> # dup name's metaclass
> nameclass = class << name; self; end.dup
>
> name2 = nameclass.new "John Doe"
> name2.reverse #==> "Doe, John"
>
> Any thoughts? Am I strange for finding this a bit surprising?
I find it pretty startling. I've often wondered whether there was a
way to do essentially this. I'd concluded there wasn't. Maybe, at
the time, there wasn't....
I subjected it to one further test, to make sure that the
name2.reverse is actually a different method (since if two objects
were sharing a singleton method, that would have to be considered a
bug):
class << name
def reverse
"hi"
end
end
name.reverse # hi
name2.reverse # Doe, John
"hello".reverse # olleh <= just to be totally sure :-)
Hmmmm, it's still daytime in Paris, so we may yet learn of some
limitation or reason to avoid it... :-)
David
--
David A. Black
dbl...@wobblini.net
> Hmmmm, it's still daytime in Paris, so we may yet learn of some limitation
> or reason to avoid it... :-)
he __is__ amazing isn't he!
> While experimenting with this, I discovered something interesting: it
> is possible to instantiate a metaclass. By duping a metaclass, you
> regain the ability to instantiate it, apparently without losing any
> functionality.
As is said later, duping the object 'erases' the singleton methods
while 'cloning' carries them over.
I've always considered duping as a nice way of erasing the 'specialness'
of an object while returning it to its natural state.
o = Object.new
def o.inspect; `clear`; end
p o # clears the screen
o = o.dup
p o # #<Object:0x3e3d4>
Try this in irb (but you don't need the 'p's)
--
Jim Freeze
Code Red. Code Ruby
Sure enough, this doesn't work in 1.6.8. Also, the singleton class
inspects as "String" in 1.6.8, which I find interesting.
> I subjected it to one further test, to make sure that the
> name2.reverse is actually a different method (since if two objects
> were sharing a singleton method, that would have to be considered a
> bug):
>
> class << name
> def reverse
> "hi"
> end
> end
>
> name.reverse # hi
> name2.reverse # Doe, John
> "hello".reverse # olleh <= just to be totally sure :-)
>
> Hmmmm, it's still daytime in Paris, so we may yet learn of some
> limitation or reason to avoid it... :-)
indeed :)
cheers,
Mark
>* Mark Hubbart <discor...@gmail.com> [2005-04-30 16:35:16 +0900]:
>
>
>
>>While experimenting with this, I discovered something interesting: it
>>is possible to instantiate a metaclass. By duping a metaclass, you
>>regain the ability to instantiate it, apparently without losing any
>>functionality.
>>
>>
>
>As is said later, duping the object 'erases' the singleton methods
>while 'cloning' carries them over.
>
>I've always considered duping as a nice way of erasing the 'specialness'
>of an object while returning it to its natural state.
>
>
It's true that duping erases class method for general
objects - it's FALSE for Module objects!
---
module A
def self.bla
puts "bla"
end
end
A.dup.bla # bla
Foo = class << 1.0; def self.bar; puts "bar" end; self end.dup
class Bar < Foo
puts ancestors.join(" < ")
# Bar < Foo < Float < Precision < Numeric < Comparable < Object <
Kernel
end
Bar.bar # bar
---
I am not sure if I would read to much into this behavior.
Here is another curiosity. If you clone a singleton you end up
with a "virtual class" which is not the virtual class of any living
Object. I guess the only usefully thing you can do with this class
is duping it:-)
---
Once = class << one = []; self end
Twice = Once.clone
begin
Class.new(Twice)
rescue TypeError=> mes
puts mes # can't make subclass of virtual class
end
class Once
def okay
end
end
class Twice
def fails
end
end
one.okay
begin
one.fails
rescue NoMethodError=> mes
puts mes # undefined method `fails' for []:Array
end
found = nil
ObjectSpace.each_object do |o|
found = o if Twice == class << o; self end
end
p found # nil
class Third < Twice.dup
end
p Third.new(1){3} # [3]
---
/Christoph
> Jim Freeze schrieb:
>
> >I've always considered duping as a nice way of erasing the 'specialness'
> >of an object while returning it to its natural state.
> >
> >
> It's true that duping erases class method for general
> objects - it's FALSE for Module objects!
>
> ---
> module A
> def self.bla
> puts "bla"
> end
> end
>
> A.dup.bla # bla
I'm not sure I understand your point here.
A typical use is below:
irb(main):001:0> module M
irb(main):002:1> def fred; "fred"; end
irb(main):003:1> end
=> nil
irb(main):004:0> class C; end
=> nil
irb(main):005:0> c = C.new
=> #<C:0x46b10>
irb(main):006:0> c.extend M
=> #<C:0x46b10>
irb(main):007:0> c.fred
=> "fred"
irb(main):008:0> c = c.dup
=> #<C:0x871d8>
irb(main):009:0> c.fred
NoMethodError: undefined method `fred' for #<C:0x871d8>
from (irb):9
from :0
But, if you have module methods and extended an object,
what would be the point? How do module methods show up
in extended objects? I thought they didn't.
> I'm not sure I understand your point here.
>
>A typical use is below:
>
> irb(main):001:0> module M
> irb(main):002:1> def fred; "fred"; end
> irb(main):003:1> end
> => nil
> irb(main):004:0> class C; end
> => nil
> irb(main):005:0> c = C.new
> => #<C:0x46b10>
> irb(main):006:0> c.extend M
> => #<C:0x46b10>
> irb(main):007:0> c.fred
> => "fred"
> irb(main):008:0> c = c.dup
> => #<C:0x871d8>
> irb(main):009:0> c.fred
> NoMethodError: undefined method `fred' for #<C:0x871d8>
> from (irb):9
> from :0
>
>But, if you have module methods and extended an object,
>what would be the point? How do module methods show up
>in extended objects? I thought they didn't.
>
>
Cloning a Module object and cloning an object that
was extend by Module is very different and cloning
a Class object is jet another subject - speaking of which
The following abuse creates an unprintable Class object
---
class O
end
P = class << O; self end.dup
class << P
p superclass
rescue SystemStackError => mes
puts mes # stack level too deep
end
---
/Christoph