-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make TEnumBlock behave as a scope #354
Conversation
f0a9004
to
2bb2d07
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look fine to me, but I can't understand how one is supposed to extract all enum members from the resulting TEnumBlock
object? Do you need to find all the constants defined in that scope with the value new
?
lib/rbi/parser.rb
Outdated
scope = TEnumBlock.new(loc: node_loc(node), comments: node_comments(node)) | ||
current_scope << scope | ||
@scopes_stack << scope | ||
visit(node.block) | ||
@scopes_stack.pop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we be checking that the enums
call has actually been supplied a block and no arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, I added code to handle malformed enums
calls as arbitrary sends. I also added a few tests around this case.
Good point, I added a enum = TEnum.new("Enum") do |enum|
enum << TEnumBlock.new do |block|
block << Const.new("A", "new")
block << Const.new("B", "new")
end
end
assert_equal(["A", "B"], enum.members) |
current_scope << Send.new( | ||
message, | ||
parse_send_args(node.arguments), | ||
loc: node_loc(node), | ||
comments: node_comments(node), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I'm understanding -- if arguments are passed in, we treat enums
as a regular method call? (Which makes sense to me)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes:
class Foo < T::Enum
enums("A", "B", "C")
end
should just be a call to the enums
class method on Foo
(whatever that may be).
lib/rbi/model.rb
Outdated
# Find the names defined by the enum. | ||
sig { returns(T::Array[String]) } | ||
def members | ||
nodes.grep(Const).select { |const| const.value == "new" }.map(&:name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about cases where we might have:
class Foo < T::Enum
enums do
A = new("A")
end
end
Is this not a concern for RBI files, I wonder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it should find these ones too.
I updated the implementation and test to accept any constant definition that matches /^new(\(.*\))?$/
e71066d
to
1682623
Compare
lib/rbi/model.rb
Outdated
# Find the names defined by the enum. | ||
sig { returns(T::Array[String]) } | ||
def members | ||
nodes.grep(Const).select { |const| const.value =~ /^new(\(.*\))?$/ }.map(&:name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if this is pedantic, but I think we need to consider cases without parens as well:
A = new "String"
Breaking change on the TEnumBlock constructor signature. Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
1682623
to
fd81dbf
Compare
Following our conversation earlier I removed the Let's revisit this once we need it 👍 |
To represent
T::Enum
subclasses like this one:We currently use a special node called
TEnumBlock
that only accepts an array of names representing the constants likeA
,B
. On top of being unnecessarily restrictive and complex, it doesn't allow storing the comments attached to each enum constant.In reality,
enums do .. end
is nothing more than a block that can accept constants but also other types of nodes. This PR changes the superclass ofTEnumBlock
to be aTree
that can contain any kind of nodes includingConst
to represent theA
,B
etc. This means we can now attach comments to the constants and parse the TEnum properly.This is a breaking change as we change the API to build
TEnum
which may break some clients.