Issue #19521 has been updated by Eregon (Benoit Daloze).
Dan0042 (Daniel DeLorme) wrote in #note-32:
Ah interesting, I didn't realize it was already
used that way. Since the ruby main repo already demonstrates how to "lie" about
the class name in a sensible and useful way, I believe this is perfectly fine.
I think there is a misunderstanding, currently there is no lying in exception messages
showing the module name of such a labeled module:
```ruby
# labeled_class from the description
c = labeled_class("Parent")
c.new.foo # => undefined method `foo' for
#<#<Class:0x00007f1c4c1f5878>:0x00007f1c4c1f50a8> (NoMethodError)
```
If `set_temporary_name` is unrestricted, it would be (for
`labeled_class("Parent")`):
```ruby
c.new.foo # => undefined method `foo' for #<Parent:0x00007f1c4c1f50a8>
(NoMethodError)
```
which would naturally make you look for a class called `Parent` except either there
isn't one or it's not the same class, which is rather confusing.
However, this will prevent
labeled_class/labeled_module from using set_temporary_name, at least until those labels
are updated to be "not a constant name" or we remove this restriction.
This seems very easy to address, labeled_module/labeled_class could wrap the name in
`<...>` or `#<...>` or `#<Class:...>` or the callers could start with a
lowercase letter, etc. All these make it clear those are not the constant paths (and never
have been) of these anonymous modules, which is what I believe is most important here.
Every Rubyist expects the name of a module if it looks like a constant path to be a way to
reach it, let's preserve that. Yes it's not a guarantee and yes it's possible
to break it, but production code doing that would just be broken code. And this
unrestricted `set_temporary_name` would make super easy to break it, without even
realizing that, that I believe would make it a very confusing and dangerous feature,
because it breaks something that every Rubyist relies on every day, not on purpose.
It's easy to add the restriction that `set_temporary_name` can only be used with a
name which is not a valid constant path now. It's impossible to add it later. I am
sure many Rubyists will regret it if we don't add this restriction which preserves the
design of Ruby module naming.
----------------------------------------
Feature #19521: Support for `Module#name=` and `Class#name=`.
https://bugs.ruby-lang.org/issues/19521#change-103600
* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
----------------------------------------
See
https://bugs.ruby-lang.org/issues/19450 for previous discussion and motivation.
[This
proposal](https://github.com/ruby/ruby/pull/7483) introduces `Module#name=` (and
thus also `Class#name=`) to set the temporary class name. The name assignment has no
effect if the module/class already has a permanent name.
```ruby
c = Class.new do
self.name = "fake name"
end
c = Class.new
c.name = "fake name"
```
Alternatively, we could use `set_name`:
```ruby
Class.new do
set_name "fake_name"
end
```
Setting the name of a class changes its current name, irrespective of whether it's
been assigned a permanent name, or has nested modules/classes which have cached a previous
name. We might like to limit the cases where a name is set, e.g. only once, only if the
name is nil, or only if it's not already permanent. There is no real harm in any of
those options, just inconsistency.
## Example usage
The current Ruby test suite has code which shows the usefulness of this new method:
```ruby
def labeled_module(name, &block)
Module.new do
singleton_class.class_eval {
define_method(:to_s) {name}
alias inspect to_s
alias name to_s
}
class_eval(&block) if block
end
end
module_function :labeled_module
def labeled_class(name, superclass = Object, &block)
Class.new(superclass) do
singleton_class.class_eval {
define_method(:to_s) {name}
alias inspect to_s
alias name to_s
}
class_eval(&block) if block
end
end
module_function :labeled_class
```
The updated code would look like this:
```ruby
def labeled_module(name, &block)
Module.new do
self.name = name
class_eval(&block) if block
end
end
def labeled_class(name, superclass = Object, &block)
Class.new(superclass) do
self.name = name
class_eval(&block) if block
end
end
module_function :labeled_class
```
Because the name cannot be set as part of `.new`, we have to have a separate block to set
the name, before calling `class_eval`. I think the ergonomics and performance of this are
slightly worse than the [counter
proposal](https://bugs.ruby-lang.org/issues/19520).
--
https://bugs.ruby-lang.org/