Access module's anonymous parent


#1

I want the following eval to output “Foo called”, without having a named
constant, since in leaks in to the calling scope:

m = Module.new
m.instance_eval do
def foo
puts “Foo called”
end
ParentSelf = self
class self::A
ParentSelf.foo # How do I do this without a constant?
end
end
a = m.const_get(‘A’).new
puts ParentSelf # This should raise - constant should not exist

I have found given self and a global function, I can use the string
representation of the anon module to find it in ObjectSpace. Clearly
this is dodgy though:

def depend(instance, file)
q = self.to_s.split(’::’).first.to_s
found = nil
ObjectSpace.each_object(Module) do |m|
found = m if q == m.to_s
end
found.depend(file)
end

m = Module.new
m.instance_eval do
def depend(file)
puts “Depend called with file: #{file}”
end

class self::A
depend(self, ‘afile.rb’)
end
end


#2

Is this what you’re looking for?

m = Module.new
m.instance_eval do
def foo
puts “Foo called”
end
parent = self
child = class self::A; self; end
child.class_eval { parent.foo }
end
a = m.const_get(‘A’).new
puts ParentSelf # This should raise - constant should not exist

(you can also use ‘m.foo’ instead of ‘parent.foo’, which means you can
remove the assignment ‘parent = self’)


#3

Brian C. wrote:

Is this what you’re looking for?

m = Module.new
m.instance_eval do
def foo
puts “Foo called”
end
parent = self
child = class self::A; self; end
child.class_eval { parent.foo }
end
a = m.const_get(‘A’).new
puts ParentSelf # This should raise - constant should not exist

(you can also use ‘m.foo’ instead of ‘parent.foo’, which means you can
remove the assignment ‘parent = self’)

I would have liked to keep the more familiar class syntax without
resorting to class_eval

parent = self
child = class self::A; self; end
child.class_eval { parent.foo }

I’m autoloading a file, it contains this part, so it’s basically the
public interface.

class self::A
parent.foo

And for that reason this is a much nicer, I think. But if it can’t be
done like this, it can’t be done…


#4

2008/10/27 Xavier S. removed_email_address@domain.invalid:

I’m autoloading a file, it contains this part, so it’s basically the
public interface.

class self::A
parent.foo

And for that reason this is a much nicer, I think. But if it can’t be
done like this, it can’t be done…

Xavier, I don’t know why you want to have an anonymous module with a
local constant, but if you really need this and are willing to change
the public interface a little bit you could do

m = Module.new
m.module_eval do
# methods for dependent classes
def depend(file)
puts “#{self} depends on #{file}”
end
# methods to define a dependent class
def self.const_missing(name)
const_set(name, Class.new)
end
def self.dependent_class(cls, &blk)
parent_module = self
cls.class_eval do extend(parent_module) end
cls.class_eval(&blk)
end
# public interface for dependent classes
dependent_class self::A do
depend(“afile.rb”)
end
end

Regards,
Pit


#5

Pit C. wrote:

2008/10/27 Xavier S. removed_email_address@domain.invalid:

I’m autoloading a file, it contains this part, so it’s basically the
public interface.

class self::A
parent.foo

And for that reason this is a much nicer, I think. But if it can’t be
done like this, it can’t be done…

Xavier, I don’t know why you want to have an anonymous module with a
local constant
Hot loading of code. I’m being a bit anal about it, also I’m just
curious :slight_smile:
Would be nice to not need the dependent_class bit, but it’s not so bad.

I had to hack your code a bit to get what I want, which is this:

m = Module.new
m.instance_eval do
self::Depend = []

def self.const_missing(name)
const_set(name, Class.new)
end

def self.dependent_class(cls, &blk)
parent_module = self
(class << cls; self; end).send(:define_method, :depend) do |file|
parent_module::Depend << file
end
cls.class_eval(&blk)
end

dependent_class self::A do
depend(“afile.rb”)

def foo
  "foo"
end

end
end

a = m.const_get(‘A’).new
puts a.foo # => foo
puts m::Depend.inspect # => [“afile.rb”]

Thanks!
Xavier