Feature #20993
openAllow `class <constant-path> = <expression>` syntax
Description
This is meant as a solution for: https://bugs.ruby-lang.org/issues/20943
Context¶
When using Struct.new
or Data.define
, you often see one of these patterns:
class MyStruct < Struct.new(:foo, :bar)
# ...
end
Or:
MyStruct = Struct.new(:foo, :bar) do
# ...
end
The first one is OK, but not ideal because MyStruct
inherits from an anonymous class. That's not that big of a deal, but it's an extra, generally useless class:
>> MyClass.ancestors
=> [MyClass, #<Class:0x000000012a811548>, Struct, ...]
The second one is OK too, but can lead to two mistakes.
First, since it doesn't create a nesting, if you assign a constant, it won't be set where you expect it.
MyStruct = Struct.new(:foo) do
BAR = 1 # This sets Object::BAR, not MyStruct::BAR
end
The second potential issue is that the class only get named after the block complete, so some inherited
or included
hooks that rely on the
class name may break.
Proposal¶
The "ideal" way to define a Struct
or Data
would be:
MyStruct = Struct.new(:foo, :bar)
class MyStruct
# body
end
But it's a bit awkward.
Given that class <constant-path> < <expression>
is valid, this makes me think we could also accept class <constant-path> = <expression>
such as:
class MyStruct = Struct.new(:foo, :bar)
# body
end
Would be valid syntax and the recommended way to define Struct
and Data
classes.
Of course module <constant-path> = <expression>
would be valid as well.
If the expression doesn't return the expected type (either Class
or Module
), it would raise a TypeError
.
Files
Updated by byroot (Jean Boussier) 5 days ago
- Related to Bug #20943: Constant defined in `Data.define` block added
Updated by nobu (Nobuyoshi Nakada) 5 days ago
- File feature-20993.diff feature-20993.diff added
class MyStruct = Struct.new(:foo, :bar)
p instance_methods(false) #=> [:foo=, :bar=, :foo, :bar]
end