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
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’)
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…
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
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
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