Determining when inside 'class << self'

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?

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

===============================================================================

Ara.T.Howard wrote:

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?

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

["Ara.T.Howard" <Ara.T.Howard@noaa.gov>, 2005-04-29 06.04 CEST]

i like a method like this

  def inside_metaclass?
    # to be implemented

      self.is_a?(Class) && self.name.empty?
      (?)

···

  end

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

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);
}

Ara.T.Howard a écrit :

  class <<
    p inside_metaclass? #=> true
  end

Sorry for the newbie question, but what does this mean?

···

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> schrieb im Newsbeitrag
news:Pine.LNX.4.62.0504282141220.19121@harp.ngdc.noaa.gov...

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?

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

Have not tested thouroughly but...

  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.

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

···

On 4/28/05, Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

i like a method like this

   def inside_metaclass?
     # to be implemented
   end

Ara.T.Howard wrote:
> 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?

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).

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

···

On 4/28/05, Assaph Mehr <assaph@gmail.com> wrote:

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

[Carlos <angus@quovadis.com.ar>, 2005-04-29 12.33 CEST]

["Ara.T.Howard" <Ara.T.Howard@noaa.gov>, 2005-04-29 06.04 CEST]
> i like a method like this
>
> def inside_metaclass?
> # to be implemented
      self.is_a?(Class) && self.name.empty?
      (?)

        self.is_a?(Class) && !self.ancestors.include?(self)
        (!)

···

> end

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?

cheers.

-a

···

On Fri, 28 Apr 2005, Assaph Mehr wrote:

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).

--

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

===============================================================================

Lionel Thiry wrote:

  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

too.

now - any opinions on whether this violates POLS or not:

···

On Fri, 29 Apr 2005, Robert Klemme wrote:

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

#
# 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?

-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

===============================================================================

Mark Hubbart <discordantus@gmail.com> writes:

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. :wink:

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.

-a

···

On Sat, 30 Apr 2005, Mark Hubbart wrote:

On 4/28/05, Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

i like a method like this

   def inside_metaclass?
     # to be implemented
   end

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?

--

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

===============================================================================

Hi --

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 :slight_smile:

Hmmmm, it's still daytime in Paris, so we may yet learn of some
limitation or reason to avoid it... :slight_smile:

David

···

On Sat, 30 Apr 2005, Mark Hubbart wrote:

--
David A. Black
dblack@wobblini.net

* Mark Hubbart <discordantus@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.

  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

Mark Hubbart wrote:

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.

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

···

On 4/29/05, Florian Groß <florgro@gmail.com> wrote:

Lionel Thiry wrote:

>> 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.

<Ara.T.Howard@noaa.gov> queried:

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
      attribute 'foobar'
    end
  end

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