Inspect, looking in from the outside

Hi--

I've been hadling a lot of OpenStruct like classes the last few days.
It isn;t alwasy smooth sailing. I've been thinking about accessing
certain "metainfo" about an object from the outside rather then from
the inside to ensure certain results. A friend say it goes against the
grain of OOP and polymorphism, but I wonder if certian "metainfo"
shouldn't? What do others think?

Also have a look at my example code below.

Thanks,
T.

···

---

# The Inspect module provides a guaranteed means of inspecting
# an object and seeing it for what it really is. Using a
# separate module prevents the methods from being overridden
# in the class/object being inspected. For example using the
# Inspect module methods, a Proxy object will be seen as a
# Proxy object and not it's delegate.

module Inspect
  extend self

  OBJECT_INSPECTION_METHODS = [
    :send, :dup, :clone, :object_id,
    :class, :is_a?, :kind_of?,
    :respond_to?, :method, :methods,
    :instance_variable_get, :instance_variable_set,
    :instance_eval
  ]

  CLASS_INSPECTION_METHODS = [
    :instance_methods, :class_eval, :module_eval, :method_defined?
  ]

  def define_inspection_method( name, old_name=name, from=Object )
    if from.method_defined?( old_name )
      im = from.instance_method( old_name )
      define_method(name) do |slf,*args|
        im.bind(slf).call(*args)
      end
    end
  end

  define_inspection_method( :id, :object_id )
  define_inspection_method( :var_get, :instance_variable_get )
  define_inspection_method( :var_set, :instance_variable_set )

  OBJECT_INSPECTION_METHODS.each do |m|
    define_inspection_method( m )
  end

  define_inspection_method( :class_of?, :===, Class )

  CLASS_INSPECTION_METHODS.each do |m|
    define_inspection_method( m, m, Class )
  end

  def nil?(obj) ; is_a?(obj, NilClass) ; end
  def false?(obj) ; is_a?(obj, FalseClass) ; end
  def true?(obj) ; is_a?(obj, TrueClass) ; end
  def bool?(obj) ; is_a?(obj, FalseClass) or is_a?(obj, TrueClass) ;
end

  def null?( obj )
    defined?(NullClass) and is_a?(slf,NullClass)
  end

  def nack?( obj )
    defined?(NackClass) and is_a?(slf,NackClass)
  end

  def f?( obj )
    return true if is_a?(obj,NilClass)
    return true if defined?(NullClass) and is_a?(obj,NullClass)
    return true if defined?(NackClass) and is_a?(obj,NackClass)
    false
  end

  def t?( obj )
    return false if is_a?(obj,NilClass)
    return false if defined?(NullClass) and is_a?(obj,NullClass)
    return false if defined?(NackClass) and is_a?(obj,NackClass)
    true
  end

end

class Object
  def instance
    @_instance ||= Functor.new { |op, *args| Inspect.__send__(op, self,
*args) }
  end
end

Trans wrote:

I've been thinking about accessing
certain "metainfo" about an object from the outside rather then from
the inside to ensure certain results. A friend say it goes against the
grain of OOP and polymorphism, but I wonder if certian "metainfo"
shouldn't? What do others think?

I dunno, I've been fine with Object.instance_method(:inspect).bind(obj) so far -- sure, you can wrap it in a module for convenience, but is it really done that frequently?

Florian Groß wrote:

Trans wrote:

> I've been thinking about accessing
> certain "metainfo" about an object from the outside rather then from
> the inside to ensure certain results. A friend say it goes against the
> grain of OOP and polymorphism, but I wonder if certian "metainfo"
> shouldn't? What do others think?

I dunno, I've been fine with Object.instance_method(:inspect).bind(obj)
so far -- sure, you can wrap it in a module for convenience, but is it
really done that frequently?

Ah! You are right. Though writing this out is way too long if you do
use it more then a few times --which I am. Nonetheless I've worked out
another way of dealing with it which wraps it up nicely, so it's no
bother.

require 'mega/blankslate'

class Object

  class Inspector < BlankSlate
    def initialize( obj )
      @obj = obj
    end
    def method_missing( sym, *args, &blk )
      Object.instance_method( sym ).bind(@obj).call(*args, &blk )
    end
  end

  def instance
    @_inspector ||= Inspector.new(self)
  end

end

It would be nice if there could be a module/class method version, as
this still resides in the instance method namespace, but such is not as
strightfoward. Anyway one point of entry in the instance space is
manageable, I guess.

Any additional suggestions? :slight_smile:

Thanks!
T.

I've refined the module idea. I moved the methods to ObjectSpace
instead. So:

  class C
    def object_id ; "Argh!" ; end
  end

  c = C.new
  c.object_id #=> "Argh!"

Yes, we've been thwarted, but OpectSpace to the rescue!

  ObjectSpace.object_id(c) #=> -606603492

There are some shortcuts too like:

  ObjectSpace.id(c) #=> -606603492

One might wonder about the methods that are being overridden in
ObjectSpace itself. Well, despite their very rare potential usage,
that's the whole problem this intends to solve. So,

  ObjectSpace.object_id(ObjectSpace) #=> -605307980

So what do other's think? Is this better then depending on __id__ and a
gaagle of other __xyz__ methods, or no?

T.

"Trans" <transfire@gmail.com> writes:

I've refined the module idea. I moved the methods to ObjectSpace
instead. So:

  class C
    def object_id ; "Argh!" ; end
  end

  c = C.new
  c.object_id #=> "Argh!"

Yes, we've been thwarted, but OpectSpace to the rescue!

  ObjectSpace.object_id(c) #=> -606603492

There are some shortcuts too like:

  ObjectSpace.id(c) #=> -606603492

One might wonder about the methods that are being overridden in
ObjectSpace itself. Well, despite their very rare potential usage,
that's the whole problem this intends to solve. So,

  ObjectSpace.object_id(ObjectSpace) #=> -605307980

    ObjectSpace.object_id_of(ObjectSpace) #=> -605307980
    ObjectSpace.object_id #=> -605307980

So what do other's think? Is this better then depending on __id__ and a
gaagle of other __xyz__ methods, or no?

I've been thinking about having #send and #object_id as external
methods too, and I like the idea.

···

T.

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org