-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
556e965
commit d321f86
Showing
4 changed files
with
495 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
module RBI | ||
module TempHelpers | ||
extend T::Sig | ||
end | ||
|
||
module Rewriters | ||
class ReplaceAttributesWithMethods < Visitor | ||
extend T::Sig | ||
include TempHelpers | ||
|
||
sig { override.params(node: T.nilable(Node)).void } | ||
def visit(node) | ||
return unless node | ||
|
||
case node | ||
when Tree | ||
node.nodes.dup.each do |child| | ||
visit(child) | ||
next unless (attr = child).is_a?(Attr) | ||
|
||
new_methods = convert_to_methods(attr) | ||
|
||
child.replace_with_multiple(new_methods) | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
sig { params(attr: Attr).returns(T::Array[Method]) } | ||
def convert_to_methods(attr) | ||
sig, attribute_type = parse_sig_of(attr) | ||
|
||
case attr | ||
when AttrReader then convert_attr_reader_to_methods(attr, sig, attribute_type) | ||
when AttrWriter then convert_attr_writer_to_methods(attr, sig, attribute_type) | ||
when AttrAccessor then convert_attr_accessor_to_methods(attr, sig, attribute_type) | ||
else raise NotImplementedError, "Unknown attribute type: #{attr.class}" | ||
end | ||
end | ||
|
||
sig { params(attr: AttrReader, sig: T.nilable(Sig), attribute_type: T.nilable(String)).returns(T::Array[Method]) } | ||
def convert_attr_reader_to_methods(attr, sig, attribute_type) | ||
attr.names.map do |name| | ||
create_getter_method(name.to_s, sig, attr.visibility, attr.loc, attr.comments) | ||
end | ||
end | ||
|
||
sig { params(attr: AttrWriter, sig: T.nilable(Sig), attribute_type: T.nilable(String)).returns(T::Array[Method]) } | ||
def convert_attr_writer_to_methods(attr, sig, attribute_type) | ||
attr.names.map do |name| | ||
create_setter_method(name.to_s, sig, attribute_type, attr.visibility, attr.loc, attr.comments) | ||
end | ||
end | ||
|
||
sig do | ||
params(attr: AttrAccessor, sig: T.nilable(Sig), attribute_type: T.nilable(String)).returns(T::Array[Method]) | ||
end | ||
def convert_attr_accessor_to_methods(attr, sig, attribute_type) | ||
readers = attr.names.flat_map do |name| | ||
create_getter_method(name.to_s, sig, attr.visibility, attr.loc, attr.comments) | ||
end | ||
|
||
writers = attr.names.map do |name| | ||
create_setter_method(name.to_s, sig, attribute_type, attr.visibility, attr.loc, attr.comments) | ||
end | ||
|
||
readers + writers | ||
end | ||
|
||
sig { params(attr: Attr).returns([T.nilable(Sig), T.nilable(String)]) } | ||
def parse_sig_of(attr) | ||
raise "Attributes cannot have more than 1 sig" if 1 < attr.sigs.count | ||
|
||
sig = attr.sigs.first | ||
return [nil, nil] unless sig | ||
|
||
attribute_type = case attr | ||
when AttrReader, AttrAccessor then sig.return_type | ||
when AttrWriter then sig.params.first&.type | ||
end | ||
|
||
[sig, attribute_type] | ||
end | ||
|
||
sig do | ||
params( | ||
name: String, | ||
sig: T.nilable(Sig), | ||
visibility: Visibility, | ||
loc: T.nilable(Loc), | ||
comments: T::Array[Comment], | ||
).returns(Method) | ||
end | ||
def create_getter_method(name, sig, visibility, loc, comments) | ||
Method.new( | ||
name, | ||
params: [], | ||
visibility: visibility, | ||
sigs: sig ? [sig] : [], | ||
loc: loc, | ||
comments: comments, | ||
) | ||
end | ||
|
||
sig do | ||
params( | ||
name: String, | ||
sig: T.nilable(Sig), | ||
attribute_type: T.nilable(String), | ||
visibility: Visibility, | ||
loc: T.nilable(Loc), | ||
comments: T::Array[Comment], | ||
).returns(Method) | ||
end | ||
def create_setter_method(name, sig, attribute_type, visibility, loc, comments) # rubocop:disable Metrics/ParameterLists | ||
sig = if sig # Modify the original sig to correct the name, and remove the return type | ||
params = attribute_type ? [SigParam.new(name, attribute_type)] : [] | ||
sig.new_with(params: params, return_type: "void") | ||
end | ||
|
||
Method.new( | ||
"#{name}=", | ||
params: [ReqParam.new(name)], | ||
visibility: visibility, | ||
sigs: sig ? [sig] : sig, | ||
loc: loc, | ||
comments: comments, | ||
) | ||
end | ||
end | ||
end | ||
|
||
class Tree | ||
extend T::Sig | ||
|
||
sig { void } | ||
def replace_attributes_with_methods! | ||
visitor = Rewriters::ReplaceAttributesWithMethods.new | ||
visitor.visit(self) | ||
end | ||
end | ||
end |
Oops, something went wrong.