rbi 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c7c65440f9d48552a65ab2c087b141ab728a4eb03ba330b55e885df49792379
4
- data.tar.gz: 4ed1352e4bdf88b220597979bc3b478e7f66227e156ce5fbfe71fcb5bf73ad34
3
+ metadata.gz: 20c28ba58d5d78165f3a26c3f354d3bd32c610ebf8364b4611a3a34ec69c360d
4
+ data.tar.gz: f446a5d9a2ce20676a082260cdf61c016deb31940dace2fce9891b797d8c5d20
5
5
  SHA512:
6
- metadata.gz: 9d21c501fe9927818ed2afe2c7e68e0e4838c1d835a5c40ccbc57d49144fee05a4e8c2a447893bc4d8d6a0e774d4f5757791ec8202388a37e33fa445ec2946c8
7
- data.tar.gz: 4b24fcee126547e8d0981e419994a1a39ff8f70a55aa93259fcaf7837d837a8842769da9205db28d414ed9920fb3a651eccdaa36c91dcf67ca323833926bca6d
6
+ metadata.gz: 5256315c81ad44aab890dc0c35cbc996787af24a650d21ab55d6405ab8ceec99f5e108ed085418b1e3207c05d7a4c5bbfc28c95b0c4ec49bd6a95ab665b9a3e6
7
+ data.tar.gz: f12fc80dcf8d4804fba40343956ddefc1f6fa60aeb237a5037977375835264db312f28d5d25920f90eb07190f0379de6631811824d81a588132633e8940f843f
data/README.md CHANGED
@@ -1,25 +1,33 @@
1
1
  # RBI generation framework
2
2
 
3
- `RBI` provides a Ruby API to compose Ruby interface files consumed by Sorbet.
3
+ `RBI` provides a Ruby API to build, parse, print, format, rewrite, and merge Ruby Interface files consumed by Sorbet.
4
4
 
5
5
  ## Installation
6
6
 
7
+ `rbi` requires Ruby 3.3 or newer.
8
+
7
9
  Add this line to your application's Gemfile:
8
10
 
9
11
  ```ruby
10
- gem 'rbi'
12
+ gem "rbi"
11
13
  ```
12
14
 
13
15
  And then execute:
14
16
 
15
- $ bundle install
17
+ ```sh
18
+ bundle install
19
+ ```
16
20
 
17
21
  Or install it yourself as:
18
22
 
19
- $ gem install rbi
23
+ ```sh
24
+ gem install rbi
25
+ ```
20
26
 
21
27
  ## Usage
22
28
 
29
+ ### Generating RBI
30
+
23
31
  ```rb
24
32
  require "rbi"
25
33
 
@@ -42,33 +50,166 @@ module Foo
42
50
  end
43
51
  ```
44
52
 
53
+ ### Parsing RBI
54
+
55
+ ```rb
56
+ require "rbi"
57
+
58
+ tree = RBI::Parser.parse_string(<<~RBI)
59
+ class Foo
60
+ def bar; end
61
+ end
62
+ RBI
63
+
64
+ puts tree.nodes.first.fully_qualified_name # => ::Foo
65
+ ```
66
+
67
+ ### Formatting and rewriting RBI
68
+
69
+ ```rb
70
+ require "rbi"
71
+
72
+ tree = RBI::Parser.parse_string(<<~RBI)
73
+ class Foo
74
+ def bar; end
75
+ end
76
+ RBI
77
+
78
+ formatter = RBI::Formatter.new(add_sig_templates: true, group_nodes: true, sort_nodes: true)
79
+ formatter.format_tree(tree)
80
+
81
+ puts tree.string
82
+ ```
83
+
84
+ will produce:
85
+
86
+ ```rb
87
+ class Foo
88
+ # TODO: fill in signature with appropriate type information
89
+ sig { returns(::T.untyped) }
90
+ def bar; end
91
+ end
92
+ ```
93
+
94
+ ### Merging RBI trees
95
+
96
+ ```rb
97
+ require "rbi"
98
+
99
+ left = RBI::Parser.parse_string(<<~RBI)
100
+ class Foo
101
+ def a; end
102
+ end
103
+ RBI
104
+
105
+ right = RBI::Parser.parse_string(<<~RBI)
106
+ class Foo
107
+ def b; end
108
+ end
109
+ RBI
110
+
111
+ puts left.merge(right).string
112
+ ```
113
+
114
+ will produce:
115
+
116
+ ```rb
117
+ class Foo
118
+ def a; end
119
+ def b; end
120
+ end
121
+ ```
122
+
123
+ ### Working with Sorbet types
124
+
125
+ ```rb
126
+ require "rbi"
127
+
128
+ type = RBI::Type.parse_string("T.nilable(String)")
129
+
130
+ puts type # => ::T.nilable(String)
131
+ puts type.rbs_string # => String?
132
+ ```
133
+
134
+ ### Translating RBS comments to Sorbet signatures
135
+
136
+ ```rb
137
+ require "rbi"
138
+
139
+ tree = RBI::Parser.parse_string(<<~RBI)
140
+ #: (String) -> Integer
141
+ def foo(name); end
142
+ RBI
143
+
144
+ tree.translate_rbs_sigs!
145
+
146
+ puts tree.string
147
+ ```
148
+
149
+ will produce:
150
+
151
+ ```rb
152
+ sig { params(name: String).returns(Integer) }
153
+ def foo(name); end
154
+ ```
155
+
156
+ ### Printing RBS
157
+
158
+ ```rb
159
+ require "rbi"
160
+
161
+ file = RBI::File.new do |f|
162
+ f << RBI::Class.new("User") do |klass|
163
+ klass << RBI::Method.new("name", sigs: [RBI::Sig.new(return_type: "String")])
164
+ end
165
+ end
166
+
167
+ puts file.rbs_string
168
+ ```
169
+
170
+ will produce:
171
+
172
+ ```rbs
173
+ class User
174
+ def name: -> String
175
+ end
176
+ ```
177
+
45
178
  ## Features
46
179
 
47
180
  * RBI generation API
48
- * RBI parsing with Whitequark
49
- * RBI formatting
50
- * RBI validation
51
- * RBI merging
181
+ * RBI parsing with Prism
182
+ * RBI printing and formatting
183
+ * RBI tree merging
184
+ * RBI normalization rewrites
185
+ * Sorbet type parsing and modeling
186
+ * RBS comments to Sorbet signature translation
187
+ * RBS output via `RBI::RBSPrinter`
52
188
 
53
189
  ## Development
54
190
 
55
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
191
+ After checking out the repo, run `bin/setup` to install dependencies.
192
+
193
+ Useful commands:
56
194
 
57
- This repo uses itself (`rbi`) to retrieve and generate gem RBIs. You can run `dev rbi` to update local gem RBIs with RBIs from the central repo.
195
+ * `bin/test` runs the test suite
196
+ * `bin/typecheck` runs Sorbet
197
+ * `bin/style` runs RuboCop
198
+ * `bin/console` starts an interactive prompt
58
199
 
59
200
  ## Releasing
60
201
 
61
202
  ### Bump the gem version
62
203
 
63
- - [ ] Locally, update the version number in [`version.rb`](https://github.com/Shopify/spoom/blob/main/lib/rbi/version.rb)
64
- - [ ] Run `bundle install` to update the version number in `Gemfile.lock`
65
- - [ ] Commit this change with the message `Bump version to vx.y.z`
66
- - [ ] Push this change directly to main or open a PR
204
+ * [ ] Locally, update the version number in [`version.rb`](https://github.com/Shopify/rbi/blob/main/lib/rbi/version.rb)
205
+ * [ ] Run `bundle install` to update the version number in `Gemfile.lock`
206
+ * [ ] Commit this change with the message `Bump version to vx.y.z`
207
+ * [ ] Push this change directly to main or open a PR
67
208
 
68
209
  ### Create a new tag
69
210
 
70
- - [ ] Locally, create a new tag with the new version number: `git tag vx.y.z`
71
- - [ ] Push this tag up to the remote `git push origin vx.y.z`
211
+ * [ ] Locally, create a new tag with the new version number: `git tag vx.y.z`
212
+ * [ ] Push this tag up to the remote `git push origin vx.y.z`
72
213
 
73
214
  ### Release workflow will run automatically
74
215
 
@@ -76,12 +217,12 @@ We have a [release workflow](https://github.com/Shopify/rbi/actions/workflows/re
76
217
 
77
218
  ## Contributing
78
219
 
79
- Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/rbi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Shopify/rbi/blob/master/CODE_OF_CONDUCT.md).
220
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/rbi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md).
80
221
 
81
222
  ## License
82
223
 
83
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
224
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
84
225
 
85
226
  ## Code of Conduct
86
227
 
87
- Everyone interacting in the Rbi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/rbi/blob/master/CODE_OF_CONDUCT.md).
228
+ Everyone interacting in this project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
data/lib/rbi/model.rb CHANGED
@@ -599,14 +599,36 @@ module RBI
599
599
 
600
600
  # @abstract
601
601
  class Param < NodeWithComments
602
+ #: (?loc: Loc?, ?comments: Array[Comment]?) -> void
603
+ def initialize(loc: nil, comments: nil)
604
+ super(loc: loc, comments: comments)
605
+ end
606
+
607
+ #: -> String?
608
+ def name
609
+ case self
610
+ when ReqParam, OptParam, KwParam, KwOptParam, RestParam, KwRestParam, BlockParam
611
+ name
612
+ end
613
+ end
614
+
615
+ # @abstract
616
+ #: -> bool
617
+ def anonymous?
618
+ raise NotImplementedError, "Abstract method called"
619
+ end
620
+ end
621
+
622
+ class ReqParam < Param
623
+ # @override
602
624
  #: String
603
625
  attr_reader :name
604
626
 
605
- #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) -> void
606
- def initialize(name, loc: nil, comments: nil)
627
+ #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (ReqParam node) -> void } -> void
628
+ def initialize(name, loc: nil, comments: nil, &block)
607
629
  super(loc: loc, comments: comments)
608
630
  @name = name.to_s #: String
609
- @anonymous = name.start_with?("_") #: bool
631
+ block&.call(self)
610
632
  end
611
633
 
612
634
  # @override
@@ -615,42 +637,61 @@ module RBI
615
637
  name
616
638
  end
617
639
 
640
+ # @override
618
641
  #: -> bool
619
642
  def anonymous?
620
- @anonymous
643
+ false
621
644
  end
622
645
 
623
646
  #: (Object? other) -> bool
624
647
  def ==(other)
625
- self.class === other &&
626
- (name == other.name || anonymous? || other.anonymous?)
627
- end
628
- end
629
-
630
- class ReqParam < Param
631
- #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (ReqParam node) -> void } -> void
632
- def initialize(name, loc: nil, comments: nil, &block)
633
- super(name, loc: loc, comments: comments)
634
- block&.call(self)
648
+ ReqParam === other && (name == other.name)
635
649
  end
636
650
  end
637
651
 
638
652
  class OptParam < Param
653
+ # @override
654
+ #: String
655
+ attr_reader :name
656
+
639
657
  #: String
640
658
  attr_reader :value
641
659
 
642
660
  #: (String name, String value, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (OptParam node) -> void } -> void
643
661
  def initialize(name, value, loc: nil, comments: nil, &block)
644
- super(name, loc: loc, comments: comments)
662
+ super(loc: loc, comments: comments)
663
+ @name = name.to_s #: String
645
664
  @value = value
646
665
  block&.call(self)
647
666
  end
667
+
668
+ # @override
669
+ #: -> String
670
+ def to_s
671
+ "#{name} = #{value}"
672
+ end
673
+
674
+ # @override
675
+ #: -> bool
676
+ def anonymous?
677
+ false
678
+ end
679
+
680
+ #: (Object? other) -> bool
681
+ def ==(other)
682
+ OptParam === other && (name == other.name)
683
+ end
648
684
  end
649
685
 
650
686
  class RestParam < Param
651
- #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (RestParam node) -> void } -> void
687
+ # @override
688
+ #: String?
689
+ attr_reader :name
690
+
691
+ #: (String? name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (RestParam node) -> void } -> void
652
692
  def initialize(name, loc: nil, comments: nil, &block)
653
- super(name, loc: loc, comments: comments)
693
+ super(loc: loc, comments: comments)
694
+ @name = name&.to_s #: String?
654
695
  block&.call(self)
655
696
  end
656
697
 
@@ -659,12 +700,28 @@ module RBI
659
700
  def to_s
660
701
  "*#{name}"
661
702
  end
703
+
704
+ # @override
705
+ #: -> bool
706
+ def anonymous?
707
+ name.nil?
708
+ end
709
+
710
+ #: (Object? other) -> bool
711
+ def ==(other)
712
+ RestParam === other && (name == other.name || anonymous? || other.anonymous?)
713
+ end
662
714
  end
663
715
 
664
716
  class KwParam < Param
717
+ # @override
718
+ #: String
719
+ attr_reader :name
720
+
665
721
  #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (KwParam node) -> void } -> void
666
722
  def initialize(name, loc: nil, comments: nil, &block)
667
- super(name, loc: loc, comments: comments)
723
+ super(loc: loc, comments: comments)
724
+ @name = name.to_s #: String
668
725
  block&.call(self)
669
726
  end
670
727
 
@@ -673,15 +730,31 @@ module RBI
673
730
  def to_s
674
731
  "#{name}:"
675
732
  end
733
+
734
+ # @override
735
+ #: -> bool
736
+ def anonymous?
737
+ false
738
+ end
739
+
740
+ #: (Object? other) -> bool
741
+ def ==(other)
742
+ KwParam === other && (name == other.name)
743
+ end
676
744
  end
677
745
 
678
746
  class KwOptParam < Param
747
+ # @override
748
+ #: String
749
+ attr_reader :name
750
+
679
751
  #: String
680
752
  attr_reader :value
681
753
 
682
754
  #: (String name, String value, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (KwOptParam node) -> void } -> void
683
755
  def initialize(name, value, loc: nil, comments: nil, &block)
684
- super(name, loc: loc, comments: comments)
756
+ super(loc: loc, comments: comments)
757
+ @name = name.to_s #: String
685
758
  @value = value
686
759
  block&.call(self)
687
760
  end
@@ -689,28 +762,60 @@ module RBI
689
762
  # @override
690
763
  #: -> String
691
764
  def to_s
692
- "#{name}:"
765
+ "#{name}: #{value}"
766
+ end
767
+
768
+ # @override
769
+ #: -> bool
770
+ def anonymous?
771
+ false
772
+ end
773
+
774
+ #: (Object? other) -> bool
775
+ def ==(other)
776
+ KwOptParam === other && (name == other.name)
693
777
  end
694
778
  end
695
779
 
696
780
  class KwRestParam < Param
697
- #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (KwRestParam node) -> void } -> void
781
+ # @override
782
+ #: String?
783
+ attr_reader :name
784
+
785
+ #: (String? name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (KwRestParam node) -> void } -> void
698
786
  def initialize(name, loc: nil, comments: nil, &block)
699
- super(name, loc: loc, comments: comments)
787
+ super(loc: loc, comments: comments)
788
+ @name = name&.to_s #: String?
700
789
  block&.call(self)
701
790
  end
702
791
 
703
792
  # @override
704
793
  #: -> String
705
794
  def to_s
706
- "**#{name}:"
795
+ "**#{name}"
796
+ end
797
+
798
+ # @override
799
+ #: -> bool
800
+ def anonymous?
801
+ name.nil?
802
+ end
803
+
804
+ #: (Object? other) -> bool
805
+ def ==(other)
806
+ KwRestParam === other && (name == other.name || anonymous? || other.anonymous?)
707
807
  end
708
808
  end
709
809
 
710
810
  class BlockParam < Param
711
- #: (String name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (BlockParam node) -> void } -> void
811
+ # @override
812
+ #: String?
813
+ attr_reader :name
814
+
815
+ #: (String? name, ?loc: Loc?, ?comments: Array[Comment]?) ?{ (BlockParam node) -> void } -> void
712
816
  def initialize(name, loc: nil, comments: nil, &block)
713
- super(name, loc: loc, comments: comments)
817
+ super(loc: loc, comments: comments)
818
+ @name = name
714
819
  block&.call(self)
715
820
  end
716
821
 
@@ -719,6 +824,17 @@ module RBI
719
824
  def to_s
720
825
  "&#{name}"
721
826
  end
827
+
828
+ # @override
829
+ #: -> bool
830
+ def anonymous?
831
+ name.nil?
832
+ end
833
+
834
+ #: (Object? other) -> bool
835
+ def ==(other)
836
+ BlockParam === other && (name == other.name || anonymous? || other.anonymous?)
837
+ end
722
838
  end
723
839
 
724
840
  # Mixins
@@ -1023,11 +1139,17 @@ module RBI
1023
1139
  def initialize(name, type, loc: nil, comments: nil, &block)
1024
1140
  super(loc: loc, comments: comments)
1025
1141
  @name = name.to_s #: String
1026
- @anonymous = name.start_with?("_") #: bool
1142
+ @anonymous = name == "*" || name == "**" || name == "&" #: bool
1027
1143
  @type = type
1028
1144
  block&.call(self)
1029
1145
  end
1030
1146
 
1147
+ # @override
1148
+ #: -> String
1149
+ def to_s
1150
+ name
1151
+ end
1152
+
1031
1153
  #: -> bool
1032
1154
  def anonymous?
1033
1155
  @anonymous
data/lib/rbi/parser.rb CHANGED
@@ -726,7 +726,7 @@ module RBI
726
726
  )
727
727
  when Prism::RestParameterNode
728
728
  RestParam.new(
729
- param.name&.to_s || "*args",
729
+ param.name&.to_s,
730
730
  loc: node_loc(param),
731
731
  comments: node_comments(param),
732
732
  )
@@ -745,13 +745,13 @@ module RBI
745
745
  )
746
746
  when Prism::KeywordRestParameterNode
747
747
  KwRestParam.new(
748
- param.name&.to_s || "**kwargs",
748
+ param.name&.to_s,
749
749
  loc: node_loc(param),
750
750
  comments: node_comments(param),
751
751
  )
752
752
  when Prism::BlockParameterNode
753
753
  BlockParam.new(
754
- param.name&.to_s || "",
754
+ param.name&.to_s,
755
755
  loc: node_loc(param),
756
756
  comments: node_comments(param),
757
757
  )
@@ -977,11 +977,21 @@ module RBI
977
977
  #: (Prism::AssocNode node) -> void
978
978
  def visit_assoc_node(node)
979
979
  @current.params << SigParam.new(
980
- node_string!(node.key).delete_suffix(":"),
980
+ sig_param_name(node.key),
981
981
  node_string!(node.value),
982
982
  )
983
983
  end
984
984
 
985
+ #: (Prism::Node node) -> String
986
+ def sig_param_name(node)
987
+ case node
988
+ when Prism::SymbolNode
989
+ node.value.to_s
990
+ else
991
+ node_string!(node).delete_suffix(":")
992
+ end
993
+ end
994
+
985
995
  #: (Prism::CallNode node, String value) -> bool
986
996
  def allow_incompatible_override?(node, value)
987
997
  args = node.arguments&.arguments
data/lib/rbi/printer.rb CHANGED
@@ -363,51 +363,43 @@ module RBI
363
363
  # @override
364
364
  #: (ReqParam node) -> void
365
365
  def visit_req_param(node)
366
- print(node.name)
366
+ self.print(node.to_s)
367
367
  end
368
368
 
369
369
  # @override
370
370
  #: (OptParam node) -> void
371
371
  def visit_opt_param(node)
372
- print(node.name)
373
- print(" = ")
374
- print(node.value)
372
+ self.print(node.to_s)
375
373
  end
376
374
 
377
375
  # @override
378
376
  #: (RestParam node) -> void
379
377
  def visit_rest_param(node)
380
- print("*")
381
- print(node.name)
378
+ self.print(node.to_s)
382
379
  end
383
380
 
384
381
  # @override
385
382
  #: (KwParam node) -> void
386
383
  def visit_kw_param(node)
387
- print(node.name)
388
- print(":")
384
+ self.print(node.to_s)
389
385
  end
390
386
 
391
387
  # @override
392
388
  #: (KwOptParam node) -> void
393
389
  def visit_kw_opt_param(node)
394
- print(node.name)
395
- print(": ")
396
- print(node.value)
390
+ self.print(node.to_s)
397
391
  end
398
392
 
399
393
  # @override
400
394
  #: (KwRestParam node) -> void
401
395
  def visit_kw_rest_param(node)
402
- print("**")
403
- print(node.name)
396
+ self.print(node.to_s)
404
397
  end
405
398
 
406
399
  # @override
407
400
  #: (BlockParam node) -> void
408
401
  def visit_block_param(node)
409
- print("&")
410
- print(node.name) unless node.name.empty?
402
+ self.print(node.to_s)
411
403
  end
412
404
 
413
405
  # @override
@@ -522,7 +514,7 @@ module RBI
522
514
  # @override
523
515
  #: (SigParam node) -> void
524
516
  def visit_sig_param(node)
525
- print(node.name)
517
+ print(node.anonymous? ? node.name.inspect : node.name)
526
518
  print(": ")
527
519
  self.print(node.type.to_s)
528
520
  end
@@ -694,25 +686,15 @@ module RBI
694
686
  def print_param_comment_leading_space(node, last:)
695
687
  printn
696
688
  printt
697
- print(" " * (node.name.size + 1))
689
+ print(" " * (node.to_s.size + 1))
698
690
  print(" ") unless last
699
- case node
700
- when OptParam
701
- print(" " * (node.value.size + 3))
702
- when RestParam, KwParam, BlockParam
703
- print(" ")
704
- when KwRestParam
705
- print(" ")
706
- when KwOptParam
707
- print(" " * (node.value.size + 2))
708
- end
709
691
  end
710
692
 
711
693
  #: (SigParam node, last: bool) -> void
712
694
  def print_sig_param_comment_leading_space(node, last:)
713
695
  printn
714
696
  printt
715
- print(" " * (node.name.size + node.type.to_s.size + 3))
697
+ print(" " * (node.to_s.size + node.type.to_s.size + 3))
716
698
  print(" ") unless last
717
699
  end
718
700
 
@@ -64,7 +64,7 @@ module RBI
64
64
  block_param = @method.params.grep(RBI::BlockParam).first
65
65
  raise Error, "No block param found" unless block_param
66
66
 
67
- block_name = block_param.name.empty? ? "block" : block_param.name
67
+ block_name = block_param.name || "&"
68
68
  block_type = translate_type(type.type) #: as RBI::Type::Proc
69
69
 
70
70
  bind = type.self_type
@@ -123,15 +123,27 @@ module RBI
123
123
  param_name = param.name&.to_s
124
124
 
125
125
  unless param_name
126
- method_param_name = @method.params[index]
127
- raise Error, "No method param name found for parameter ##{index}" unless method_param_name
126
+ method_param = @method.params[index]
127
+ raise Error, "No method param name found for parameter ##{index}" unless method_param
128
128
 
129
- param_name = method_param_name.name
129
+ param_name = method_param.name || anonymous_param_name(method_param)
130
130
  end
131
131
 
132
132
  SigParam.new(param_name, param_type)
133
133
  end
134
134
 
135
+ #: (Param) -> String?
136
+ def anonymous_param_name(param)
137
+ case param
138
+ when RestParam
139
+ "*"
140
+ when KwRestParam
141
+ "**"
142
+ when BlockParam
143
+ "&"
144
+ end
145
+ end
146
+
135
147
  #: (untyped) -> Type
136
148
  def translate_type(type)
137
149
  @type_translator.translate(type)
@@ -613,7 +613,8 @@ module RBI
613
613
  # @override
614
614
  #: (KwRestParam node) -> void
615
615
  def visit_kw_rest_param(node)
616
- print("**#{node.name}: untyped")
616
+ print("**untyped")
617
+ print(" #{node.name}") if node.name
617
618
  end
618
619
 
619
620
  # @override
@@ -912,25 +913,15 @@ module RBI
912
913
  def print_param_comment_leading_space(node, last:)
913
914
  printn
914
915
  printt
915
- print(" " * (node.name.size + 1))
916
+ print(" " * (node.to_s.size + 1))
916
917
  print(" ") unless last
917
- case node
918
- when OptParam
919
- print(" " * (node.value.size + 3))
920
- when RestParam, KwParam, BlockParam
921
- print(" ")
922
- when KwRestParam
923
- print(" ")
924
- when KwOptParam
925
- print(" " * (node.value.size + 2))
926
- end
927
918
  end
928
919
 
929
920
  #: (SigParam node, last: bool) -> void
930
921
  def print_sig_param_comment_leading_space(node, last:)
931
922
  printn
932
923
  printt
933
- print(" " * (node.name.size + node.type.to_s.size + 3))
924
+ print(" " * (node.to_s.size + node.type.to_s.size + 3))
934
925
  print(" ") unless last
935
926
  end
936
927
 
@@ -45,7 +45,21 @@ module RBI
45
45
  return unless method.sigs.empty?
46
46
 
47
47
  method.sigs << Sig.new(
48
- params: method.params.map { |param| SigParam.new(param.name, "::T.untyped") },
48
+ params: method.params.map do |param|
49
+ case param
50
+ when RBI::RestParam
51
+ SigParam.new(param.name || "*", "::T.untyped")
52
+ when RBI::KwRestParam
53
+ SigParam.new(param.name || "**", "::T.untyped")
54
+ when RBI::BlockParam
55
+ SigParam.new(param.name || "&", "::T.untyped")
56
+ else
57
+ SigParam.new(
58
+ param.name, #: as !nil
59
+ "::T.untyped",
60
+ )
61
+ end
62
+ end,
49
63
  return_type: "::T.untyped",
50
64
  )
51
65
  add_todo_comment(method)
@@ -464,11 +464,17 @@ module RBI
464
464
  # @override
465
465
  #: (Node other) -> bool
466
466
  def compatible_with?(other)
467
- other.is_a?(Method) &&
468
- name == other.name &&
469
- params == other.params &&
470
- at_most_one_side_anonymous?(other) &&
471
- (sigs.empty? || other.sigs.empty? || sigs == other.sigs)
467
+ return false unless other.is_a?(Method)
468
+ return false unless name == other.name
469
+ return false unless params.size == other.params.size
470
+
471
+ if sigs.empty? && other.sigs.empty?
472
+ compatible_params?(other)
473
+ elsif sigs.empty? || other.sigs.empty?
474
+ true
475
+ else
476
+ compatible_params?(other) && sigs == other.sigs
477
+ end
472
478
  end
473
479
 
474
480
  # @override
@@ -478,15 +484,15 @@ module RBI
478
484
 
479
485
  super
480
486
 
481
- # If self is the all-anonymous side (since compatible_with? ensures
482
- # at most one side is), or if self has no sigs but other does, adopt
483
- # other's non-anonymous param names and sigs.
484
- if params.all?(&:anonymous?) || (sigs.empty? && !other.sigs.empty?)
487
+ if sigs.empty? && !other.sigs.empty?
485
488
  @params = other.params.dup
486
- @sigs = other.sigs.dup unless other.sigs.empty?
489
+ @sigs = other.sigs.dup
487
490
  return
488
491
  end
489
492
 
493
+ @params = merge_params(params, other.params)
494
+ rename_sigs_params(sigs, @params)
495
+
490
496
  other.sigs.each do |sig|
491
497
  sigs << sig unless sigs.include?(sig)
492
498
  end
@@ -495,10 +501,47 @@ module RBI
495
501
  private
496
502
 
497
503
  #: (Method other) -> bool
498
- def at_most_one_side_anonymous?(other)
499
- (params.all?(&:anonymous?) && other.params.none?(&:anonymous?)) ||
500
- (params.none?(&:anonymous?) && other.params.all?(&:anonymous?)) ||
501
- (params.none?(&:anonymous?) && other.params.none?(&:anonymous?))
504
+ def compatible_params?(other)
505
+ return true if params == other.params
506
+
507
+ params.zip(other.params).all? do |p1, p2|
508
+ p1.compatible_with?(p2)
509
+ end
510
+ end
511
+
512
+ #: (Array[Param] preferred, Array[Param] fallback) -> Array[Param]
513
+ def merge_params(preferred, fallback)
514
+ preferred.zip(fallback).map do |p1, p2|
515
+ if p1.anonymous?
516
+ p2.dup #: as !nil
517
+ else
518
+ p1.dup
519
+ end
520
+ end
521
+ end
522
+
523
+ #: (Array[Sig] sigs, Array[Param] params) -> void
524
+ def rename_sigs_params(sigs, params)
525
+ sigs.each do |sig|
526
+ sig_params = sig.params.zip(params).map do |sig_param, param|
527
+ param = param #: as !nil
528
+ name = if sig_param.anonymous? && !param.anonymous?
529
+ param.name #: as !nil
530
+ else
531
+ sig_param.name
532
+ end
533
+ SigParam.new(name, sig_param.type)
534
+ end
535
+ sig.params.replace(sig_params)
536
+ end
537
+ end
538
+ end
539
+
540
+ class Param
541
+ # @override
542
+ #: (Node? other) -> bool
543
+ def compatible_with?(other)
544
+ self.class === other && (anonymous? || other.anonymous? || name == other.name)
502
545
  end
503
546
  end
504
547
 
data/lib/rbi/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RBI
5
- VERSION = "0.3.16"
5
+ VERSION = "0.4.0"
6
6
  end
data/rbi/rbi.rbi CHANGED
@@ -187,7 +187,7 @@ end
187
187
  class RBI::BlockParam < ::RBI::Param
188
188
  sig do
189
189
  params(
190
- name: ::String,
190
+ name: T.nilable(::String),
191
191
  loc: T.nilable(::RBI::Loc),
192
192
  comments: T.nilable(T::Array[::RBI::Comment]),
193
193
  block: T.nilable(T.proc.params(node: ::RBI::BlockParam).void)
@@ -195,6 +195,15 @@ class RBI::BlockParam < ::RBI::Param
195
195
  end
196
196
  def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
197
197
 
198
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
199
+ def ==(other); end
200
+
201
+ sig { override.returns(T::Boolean) }
202
+ def anonymous?; end
203
+
204
+ sig { override.returns(T.nilable(::String)) }
205
+ def name; end
206
+
198
207
  sig { override.returns(::String) }
199
208
  def to_s; end
200
209
  end
@@ -537,6 +546,15 @@ class RBI::KwOptParam < ::RBI::Param
537
546
  end
538
547
  def initialize(name, value, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
539
548
 
549
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
550
+ def ==(other); end
551
+
552
+ sig { override.returns(T::Boolean) }
553
+ def anonymous?; end
554
+
555
+ sig { override.returns(::String) }
556
+ def name; end
557
+
540
558
  sig { override.returns(::String) }
541
559
  def to_s; end
542
560
 
@@ -555,6 +573,15 @@ class RBI::KwParam < ::RBI::Param
555
573
  end
556
574
  def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
557
575
 
576
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
577
+ def ==(other); end
578
+
579
+ sig { override.returns(T::Boolean) }
580
+ def anonymous?; end
581
+
582
+ sig { override.returns(::String) }
583
+ def name; end
584
+
558
585
  sig { override.returns(::String) }
559
586
  def to_s; end
560
587
  end
@@ -562,7 +589,7 @@ end
562
589
  class RBI::KwRestParam < ::RBI::Param
563
590
  sig do
564
591
  params(
565
- name: ::String,
592
+ name: T.nilable(::String),
566
593
  loc: T.nilable(::RBI::Loc),
567
594
  comments: T.nilable(T::Array[::RBI::Comment]),
568
595
  block: T.nilable(T.proc.params(node: ::RBI::KwRestParam).void)
@@ -570,6 +597,15 @@ class RBI::KwRestParam < ::RBI::Param
570
597
  end
571
598
  def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
572
599
 
600
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
601
+ def ==(other); end
602
+
603
+ sig { override.returns(T::Boolean) }
604
+ def anonymous?; end
605
+
606
+ sig { override.returns(T.nilable(::String)) }
607
+ def name; end
608
+
573
609
  sig { override.returns(::String) }
574
610
  def to_s; end
575
611
  end
@@ -729,7 +765,13 @@ class RBI::Method < ::RBI::NodeWithComments
729
765
  private
730
766
 
731
767
  sig { params(other: ::RBI::Method).returns(T::Boolean) }
732
- def at_most_one_side_anonymous?(other); end
768
+ def compatible_params?(other); end
769
+
770
+ sig { params(preferred: T::Array[::RBI::Param], fallback: T::Array[::RBI::Param]).returns(T::Array[::RBI::Param]) }
771
+ def merge_params(preferred, fallback); end
772
+
773
+ sig { params(sigs: T::Array[::RBI::Sig], params: T::Array[::RBI::Param]).void }
774
+ def rename_sigs_params(sigs, params); end
733
775
  end
734
776
 
735
777
  class RBI::MixesInClassMethods < ::RBI::Mixin
@@ -898,6 +940,18 @@ class RBI::OptParam < ::RBI::Param
898
940
  end
899
941
  def initialize(name, value, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
900
942
 
943
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
944
+ def ==(other); end
945
+
946
+ sig { override.returns(T::Boolean) }
947
+ def anonymous?; end
948
+
949
+ sig { override.returns(::String) }
950
+ def name; end
951
+
952
+ sig { override.returns(::String) }
953
+ def to_s; end
954
+
901
955
  sig { returns(::String) }
902
956
  def value; end
903
957
  end
@@ -905,20 +959,17 @@ end
905
959
  class RBI::Param < ::RBI::NodeWithComments
906
960
  abstract!
907
961
 
908
- sig { params(name: ::String, loc: T.nilable(::RBI::Loc), comments: T.nilable(T::Array[::RBI::Comment])).void }
909
- def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil)); end
910
-
911
- sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
912
- def ==(other); end
962
+ sig { params(loc: T.nilable(::RBI::Loc), comments: T.nilable(T::Array[::RBI::Comment])).void }
963
+ def initialize(loc: T.unsafe(nil), comments: T.unsafe(nil)); end
913
964
 
914
- sig { returns(T::Boolean) }
965
+ sig { abstract.returns(T::Boolean) }
915
966
  def anonymous?; end
916
967
 
917
- sig { returns(::String) }
918
- def name; end
968
+ sig { override.params(other: T.nilable(::RBI::Node)).returns(T::Boolean) }
969
+ def compatible_with?(other); end
919
970
 
920
- sig { override.returns(::String) }
921
- def to_s; end
971
+ sig { returns(T.nilable(::String)) }
972
+ def name; end
922
973
  end
923
974
 
924
975
  class RBI::ParseError < ::RBI::Error
@@ -985,6 +1036,9 @@ class RBI::Parser::SigBuilder < ::RBI::Parser::Visitor
985
1036
  sig { returns(::RBI::Sig) }
986
1037
  def current; end
987
1038
 
1039
+ sig { params(node: ::Prism::Node).returns(::String) }
1040
+ def sig_param_name(node); end
1041
+
988
1042
  sig { override.params(node: ::Prism::AssocNode).void }
989
1043
  def visit_assoc_node(node); end
990
1044
 
@@ -1400,6 +1454,9 @@ class RBI::RBS::MethodTypeTranslator
1400
1454
 
1401
1455
  private
1402
1456
 
1457
+ sig { params(param: ::RBI::Param).returns(T.nilable(::String)) }
1458
+ def anonymous_param_name(param); end
1459
+
1403
1460
  sig { params(param: ::RBS::Types::Function::Param, index: ::Integer).returns(::RBI::SigParam) }
1404
1461
  def translate_function_param(param, index); end
1405
1462
 
@@ -1740,6 +1797,18 @@ class RBI::ReqParam < ::RBI::Param
1740
1797
  ).void
1741
1798
  end
1742
1799
  def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
1800
+
1801
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
1802
+ def ==(other); end
1803
+
1804
+ sig { override.returns(T::Boolean) }
1805
+ def anonymous?; end
1806
+
1807
+ sig { override.returns(::String) }
1808
+ def name; end
1809
+
1810
+ sig { override.returns(::String) }
1811
+ def to_s; end
1743
1812
  end
1744
1813
 
1745
1814
  class RBI::RequiresAncestor < ::RBI::NodeWithComments
@@ -1761,7 +1830,7 @@ end
1761
1830
  class RBI::RestParam < ::RBI::Param
1762
1831
  sig do
1763
1832
  params(
1764
- name: ::String,
1833
+ name: T.nilable(::String),
1765
1834
  loc: T.nilable(::RBI::Loc),
1766
1835
  comments: T.nilable(T::Array[::RBI::Comment]),
1767
1836
  block: T.nilable(T.proc.params(node: ::RBI::RestParam).void)
@@ -1769,6 +1838,15 @@ class RBI::RestParam < ::RBI::Param
1769
1838
  end
1770
1839
  def initialize(name, loc: T.unsafe(nil), comments: T.unsafe(nil), &block); end
1771
1840
 
1841
+ sig { params(other: T.nilable(::Object)).returns(T::Boolean) }
1842
+ def ==(other); end
1843
+
1844
+ sig { override.returns(T::Boolean) }
1845
+ def anonymous?; end
1846
+
1847
+ sig { override.returns(T.nilable(::String)) }
1848
+ def name; end
1849
+
1772
1850
  sig { override.returns(::String) }
1773
1851
  def to_s; end
1774
1852
  end
@@ -2252,6 +2330,9 @@ class RBI::SigParam < ::RBI::NodeWithComments
2252
2330
  sig { returns(::String) }
2253
2331
  def name; end
2254
2332
 
2333
+ sig { override.returns(::String) }
2334
+ def to_s; end
2335
+
2255
2336
  sig { returns(T.any(::RBI::Type, ::String)) }
2256
2337
  def type; end
2257
2338
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.16
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa