Bug #19067
closedModule methods not usable at toplevel under wrapped script
Description
#foo.rb
module Foo
end
private_constant :Foo
module MyModule; end
load "./foo.rb", MyModule
# undefined method `private_constant' for main:Object (NoMethodError)
#
# private_constant :Foo
# ^^^^^^^^^^^^^^^^
# Did you mean? private_methods
However, this works:
module MyModule
module Foo
end
private_constant :Foo
end
load
loads the code under the wrap
module, so this seems like a bug to me.
This applies to all methods on Module
, which are usable inside a normal module definition but not usable when the module is the wrap
argument to load
.
I think these should all be usable in this context. If they cannot, then clarity is needed about what "being executed under" means in the documentation for load
.
Updated by shioyama (Chris Salzberg) about 2 years ago
- Subject changed from `private_constant` does not work at toplevel in wrapped module context to private_constant does not work at toplevel in wrapped module context
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
- Subject changed from private_constant does not work at toplevel in wrapped module context to private_constant raises NoMethodError when called at toplevel under wrapped script
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
- Subject changed from private_constant raises NoMethodError when called at toplevel under wrapped script to private_constant and other Module methods not usable at toplevel under wrapped script
Updated by shioyama (Chris Salzberg) about 2 years ago
- Subject changed from private_constant and other Module methods not usable at toplevel under wrapped script to Module class methods not usable at toplevel under wrapped script
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
- Subject changed from Module class methods not usable at toplevel under wrapped script to Module methods not usable at toplevel under wrapped script
Updated by fxn (Xavier Noria) about 2 years ago
I have always been skeptical about the ability to pass a module to Kernel#load
.
As an author of the target file I no longer control the nesting, which is fundamental to know the constant references I am writing are the ones I actually mean. Now, the nesting is always in the hands of the caller, and that to me is a red flag.
In this case, private_constant
does not work at the top-level, why should I write that code in the first place? You can't either define methods for that matter. This feature is not like writing module WrappingModule
at the top of the file.
The documentation is unclear about what does "being executed under" mean. Without that definition, we cannot know if this is a bug.
Updated by shioyama (Chris Salzberg) about 2 years ago
The documentation is unclear about what does "being executed under" mean. Without that definition, we cannot know if this is a bug.
This is true. I am labelling it as a "bug" but it should be understood as "inconsistency".
Updated by shioyama (Chris Salzberg) about 2 years ago
As an author of the target file I no longer control the nesting, which is fundamental to know the constant references I am writing are the ones I actually mean.
You cannot be sure the constant you are referencing is the one you mean, ever. I can define "my" Foo
, then load your file which does something with "your" Foo
, and your assumptions about Foo
may be incorrect because of what my Foo
has in it.
If you want to absolutely be sure what a constant is referencing, you would need to disallow load
altogether.
Updated by mame (Yusuke Endoh) about 2 years ago
I think we can say the following by the same reasoning:
# foo.rb
p self
module MyModule; end
load "./foo.rb", MyModule #=> current: self, expected?: MyModule
because:
module MyModule
p self #=> MyModule
end
This is a bit incompatible, but I wonder if it is better than dealing with Module#using
, Module#private_method
, etc. individually.
Updated by shioyama (Chris Salzberg) about 2 years ago
This is a bit incompatible, but I wonder if it is better than dealing with
Module#using
,Module#private_method
, etc. individually.
Yes that's a fair point, and to be honest, I didn't realize how much failed to work as "expected" until after I had created this issue.
Still, I think this is worth thinking about. Previously, it was not possible to control the module to load
, so this was not really an issue. But now it is.
And I do think it's slightly ambiguous what is supposed to happen here.
e.g.
# foo.rb
require "my_dependency"
# ... code that depends on my_dependency
module MyModule
def require(filename)
puts "required #{filename}!"
end
end
load "./foo.rb", MyModule
#=> required my_dependency!
In this case, because top_self
extends the top_wrapper
module, require
is (re-)defined and foo.rb
does not actually require its dependency.
This is interesting, but I don't think it was the original intention of extending top_self
with top_wrapper
.
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
- Description updated (diff)
Updated by shioyama (Chris Salzberg) about 2 years ago
This is actually even confusing prior to the recent change:
If the optional wrap parameter is true, the loaded script will be executed under an anonymous module, protecting the calling program's global namespace.
# foo.rb
def foo
end
foo
load "foo.rb", true
This "works", but it does not do this, which is what I think would be expected:
Module.new do
def foo
end
foo
end
# undefined local variable or method `foo' for #<Module:0x00007f0823a7efb8> (NameError)
I think what load
actually does is powerful and I've stated so elsewhere, but it is not simply "executing it under an anonymous namespace".
Updated by matz (Yukihiro Matsumoto) about 2 years ago
load "foo.rb"
should work (similar enough) with or without wrapping module. In that sense, replacing self
is unacceptable.
Probably you want to get the "target class/module" which is the target of constant/method definitions. I have no idea of notation right now.
Matz.
Updated by matz (Yukihiro Matsumoto) about 2 years ago
- Status changed from Open to Rejected