syntax_tree 2.2.0 → 2.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.
@@ -3,9 +3,21 @@
3
3
  module SyntaxTree
4
4
  # Represents the location of a node in the tree from the source code.
5
5
  class Location
6
- attr_reader :start_line, :start_char, :start_column, :end_line, :end_char, :end_column
6
+ attr_reader :start_line,
7
+ :start_char,
8
+ :start_column,
9
+ :end_line,
10
+ :end_char,
11
+ :end_column
7
12
 
8
- def initialize(start_line:, start_char:, start_column:, end_line:, end_char:, end_column:)
13
+ def initialize(
14
+ start_line:,
15
+ start_char:,
16
+ start_column:,
17
+ end_line:,
18
+ end_char:,
19
+ end_column:
20
+ )
9
21
  @start_line = start_line
10
22
  @start_char = start_char
11
23
  @start_column = start_column
@@ -39,7 +51,7 @@ module SyntaxTree
39
51
  [start_line, start_char, start_column, end_line, end_char, end_column]
40
52
  end
41
53
 
42
- def deconstruct_keys(keys)
54
+ def deconstruct_keys(_keys)
43
55
  {
44
56
  start_line: start_line,
45
57
  start_char: start_char,
@@ -62,7 +74,14 @@ module SyntaxTree
62
74
  end
63
75
 
64
76
  def self.fixed(line:, char:, column:)
65
- new(start_line: line, start_char: char, start_column: column, end_line: line, end_char: char, end_column: column)
77
+ new(
78
+ start_line: line,
79
+ start_char: char,
80
+ start_column: column,
81
+ end_line: line,
82
+ end_char: char,
83
+ end_column: column
84
+ )
66
85
  end
67
86
  end
68
87
 
@@ -102,6 +121,10 @@ module SyntaxTree
102
121
  visitor = Visitor::JSONVisitor.new
103
122
  visitor.visit(self).to_json(*opts)
104
123
  end
124
+
125
+ def construct_keys
126
+ PP.format(+"") { |q| Visitor::MatchVisitor.new(q).visit(self) }
127
+ end
105
128
  end
106
129
 
107
130
  # BEGINBlock represents the use of the +BEGIN+ keyword, which hooks into the
@@ -140,7 +163,7 @@ module SyntaxTree
140
163
 
141
164
  alias deconstruct child_nodes
142
165
 
143
- def deconstruct_keys(keys)
166
+ def deconstruct_keys(_keys)
144
167
  {
145
168
  lbrace: lbrace,
146
169
  statements: statements,
@@ -192,7 +215,7 @@ module SyntaxTree
192
215
 
193
216
  alias deconstruct child_nodes
194
217
 
195
- def deconstruct_keys(keys)
218
+ def deconstruct_keys(_keys)
196
219
  { value: value, location: location, comments: comments }
197
220
  end
198
221
 
@@ -243,7 +266,7 @@ module SyntaxTree
243
266
 
244
267
  alias deconstruct child_nodes
245
268
 
246
- def deconstruct_keys(keys)
269
+ def deconstruct_keys(_keys)
247
270
  {
248
271
  lbrace: lbrace,
249
272
  statements: statements,
@@ -298,7 +321,7 @@ module SyntaxTree
298
321
 
299
322
  alias deconstruct child_nodes
300
323
 
301
- def deconstruct_keys(keys)
324
+ def deconstruct_keys(_keys)
302
325
  { value: value, location: location, comments: comments }
303
326
  end
304
327
 
@@ -323,6 +346,8 @@ module SyntaxTree
323
346
  # symbols (note that this includes dynamic symbols like
324
347
  # :"left-#{middle}-right").
325
348
  class Alias < Node
349
+ # Formats an argument to the alias keyword. For symbol literals it uses the
350
+ # value of the symbol directly to look like bare words.
326
351
  class AliasArgumentFormatter
327
352
  # [DynaSymbol | SymbolLiteral] the argument being passed to alias
328
353
  attr_reader :argument
@@ -374,7 +399,7 @@ module SyntaxTree
374
399
 
375
400
  alias deconstruct child_nodes
376
401
 
377
- def deconstruct_keys(keys)
402
+ def deconstruct_keys(_keys)
378
403
  { left: left, right: right, location: location, comments: comments }
379
404
  end
380
405
 
@@ -435,7 +460,7 @@ module SyntaxTree
435
460
 
436
461
  alias deconstruct child_nodes
437
462
 
438
- def deconstruct_keys(keys)
463
+ def deconstruct_keys(_keys)
439
464
  {
440
465
  collection: collection,
441
466
  index: index,
@@ -496,7 +521,7 @@ module SyntaxTree
496
521
 
497
522
  alias deconstruct child_nodes
498
523
 
499
- def deconstruct_keys(keys)
524
+ def deconstruct_keys(_keys)
500
525
  {
501
526
  collection: collection,
502
527
  index: index,
@@ -558,7 +583,7 @@ module SyntaxTree
558
583
 
559
584
  alias deconstruct child_nodes
560
585
 
561
- def deconstruct_keys(keys)
586
+ def deconstruct_keys(_keys)
562
587
  { arguments: arguments, location: location, comments: comments }
563
588
  end
564
589
 
@@ -606,7 +631,7 @@ module SyntaxTree
606
631
 
607
632
  alias deconstruct child_nodes
608
633
 
609
- def deconstruct_keys(keys)
634
+ def deconstruct_keys(_keys)
610
635
  { parts: parts, location: location, comments: comments }
611
636
  end
612
637
 
@@ -642,7 +667,7 @@ module SyntaxTree
642
667
 
643
668
  alias deconstruct child_nodes
644
669
 
645
- def deconstruct_keys(keys)
670
+ def deconstruct_keys(_keys)
646
671
  { value: value, location: location, comments: comments }
647
672
  end
648
673
 
@@ -679,7 +704,7 @@ module SyntaxTree
679
704
 
680
705
  alias deconstruct child_nodes
681
706
 
682
- def deconstruct_keys(keys)
707
+ def deconstruct_keys(_keys)
683
708
  { value: value, location: location, comments: comments }
684
709
  end
685
710
 
@@ -729,7 +754,7 @@ module SyntaxTree
729
754
 
730
755
  alias deconstruct child_nodes
731
756
 
732
- def deconstruct_keys(keys)
757
+ def deconstruct_keys(_keys)
733
758
  { value: value, location: location, comments: comments }
734
759
  end
735
760
 
@@ -745,6 +770,7 @@ module SyntaxTree
745
770
  # [one, two, three]
746
771
  #
747
772
  class ArrayLiteral < Node
773
+ # Formats an array of multiple simple string literals into the %w syntax.
748
774
  class QWordsFormatter
749
775
  # [Args] the contents of the array
750
776
  attr_reader :contents
@@ -761,7 +787,7 @@ module SyntaxTree
761
787
  if part.is_a?(StringLiteral)
762
788
  q.format(part.parts.first)
763
789
  else
764
- q.text(part.value[1..-1])
790
+ q.text(part.value[1..])
765
791
  end
766
792
  end
767
793
  end
@@ -770,6 +796,7 @@ module SyntaxTree
770
796
  end
771
797
  end
772
798
 
799
+ # Formats an array of multiple simple symbol literals into the %i syntax.
773
800
  class QSymbolsFormatter
774
801
  # [Args] the contents of the array
775
802
  attr_reader :contents
@@ -791,6 +818,28 @@ module SyntaxTree
791
818
  end
792
819
  end
793
820
 
821
+ # Formats an array that contains only a list of variable references. To make
822
+ # things simpler, if there are a bunch, we format them all using the "fill"
823
+ # algorithm as opposed to breaking them into a ton of lines. For example,
824
+ #
825
+ # [foo, bar, baz]
826
+ #
827
+ # instead of becoming:
828
+ #
829
+ # [
830
+ # foo,
831
+ # bar,
832
+ # baz
833
+ # ]
834
+ #
835
+ # would instead become:
836
+ #
837
+ # [
838
+ # foo, bar,
839
+ # baz
840
+ # ]
841
+ #
842
+ # provided the line length was hit between `bar` and `baz`.
794
843
  class VarRefsFormatter
795
844
  # [Args] the contents of the array
796
845
  attr_reader :contents
@@ -816,6 +865,32 @@ module SyntaxTree
816
865
  end
817
866
  end
818
867
 
868
+ # This is a special formatter used if the array literal contains no values
869
+ # but _does_ contain comments. In this case we do some special formatting to
870
+ # make sure the comments gets indented properly.
871
+ class EmptyWithCommentsFormatter
872
+ # [LBracket] the opening bracket
873
+ attr_reader :lbracket
874
+
875
+ def initialize(lbracket)
876
+ @lbracket = lbracket
877
+ end
878
+
879
+ def format(q)
880
+ q.group do
881
+ q.text("[")
882
+ q.indent do
883
+ lbracket.comments.each do |comment|
884
+ q.breakable(force: true)
885
+ comment.format(q)
886
+ end
887
+ end
888
+ q.breakable(force: true)
889
+ q.text("]")
890
+ end
891
+ end
892
+ end
893
+
819
894
  # [LBracket] the bracket that opens this array
820
895
  attr_reader :lbracket
821
896
 
@@ -842,7 +917,7 @@ module SyntaxTree
842
917
 
843
918
  alias deconstruct child_nodes
844
919
 
845
- def deconstruct_keys(keys)
920
+ def deconstruct_keys(_keys)
846
921
  {
847
922
  lbracket: lbracket,
848
923
  contents: contents,
@@ -867,6 +942,11 @@ module SyntaxTree
867
942
  return
868
943
  end
869
944
 
945
+ if empty_with_comments?
946
+ EmptyWithCommentsFormatter.new(lbracket).format(q)
947
+ return
948
+ end
949
+
870
950
  q.group do
871
951
  q.format(lbracket)
872
952
 
@@ -919,6 +999,13 @@ module SyntaxTree
919
999
  q.maxwidth * 2
920
1000
  )
921
1001
  end
1002
+
1003
+ # If we have an empty array that contains only comments, then we're going
1004
+ # to do some special printing to ensure they get indented correctly.
1005
+ def empty_with_comments?
1006
+ contents.nil? && lbracket.comments.any? &&
1007
+ lbracket.comments.none?(&:inline?)
1008
+ end
922
1009
  end
923
1010
 
924
1011
  # AryPtn represents matching against an array pattern using the Ruby 2.7+
@@ -939,6 +1026,7 @@ module SyntaxTree
939
1026
  # and an optional array of positional matches that occur after the splat.
940
1027
  # All of the in clauses above would create an AryPtn node.
941
1028
  class AryPtn < Node
1029
+ # Formats the optional splat of an array pattern.
942
1030
  class RestFormatter
943
1031
  # [VarField] the identifier that represents the remaining positionals
944
1032
  attr_reader :value
@@ -1001,7 +1089,7 @@ module SyntaxTree
1001
1089
 
1002
1090
  alias deconstruct child_nodes
1003
1091
 
1004
- def deconstruct_keys(keys)
1092
+ def deconstruct_keys(_keys)
1005
1093
  {
1006
1094
  constant: constant,
1007
1095
  requireds: requireds,
@@ -1033,6 +1121,8 @@ module SyntaxTree
1033
1121
  q.text("[")
1034
1122
  q.seplist(parts) { |part| q.format(part) }
1035
1123
  q.text("]")
1124
+ elsif parts.empty?
1125
+ q.text("[]")
1036
1126
  else
1037
1127
  q.group { q.seplist(parts) { |part| q.format(part) } }
1038
1128
  end
@@ -1042,17 +1132,17 @@ module SyntaxTree
1042
1132
  # Determins if the following value should be indented or not.
1043
1133
  module AssignFormatting
1044
1134
  def self.skip_indent?(value)
1045
- (value.is_a?(Call) && skip_indent?(value.receiver)) ||
1046
- [
1047
- ArrayLiteral,
1048
- HashLiteral,
1049
- Heredoc,
1050
- Lambda,
1051
- QSymbols,
1052
- QWords,
1053
- Symbols,
1054
- Words
1055
- ].include?(value.class)
1135
+ case value
1136
+ in ArrayLiteral | HashLiteral | Heredoc | Lambda | QSymbols | QWords |
1137
+ Symbols | Words
1138
+ true
1139
+ in Call[receiver:]
1140
+ skip_indent?(receiver)
1141
+ in DynaSymbol[quote:]
1142
+ quote.start_with?("%s")
1143
+ else
1144
+ false
1145
+ end
1056
1146
  end
1057
1147
  end
1058
1148
 
@@ -1090,7 +1180,7 @@ module SyntaxTree
1090
1180
 
1091
1181
  alias deconstruct child_nodes
1092
1182
 
1093
- def deconstruct_keys(keys)
1183
+ def deconstruct_keys(_keys)
1094
1184
  { target: target, value: value, location: location, comments: comments }
1095
1185
  end
1096
1186
 
@@ -1152,12 +1242,12 @@ module SyntaxTree
1152
1242
 
1153
1243
  alias deconstruct child_nodes
1154
1244
 
1155
- def deconstruct_keys(keys)
1245
+ def deconstruct_keys(_keys)
1156
1246
  { key: key, value: value, location: location, comments: comments }
1157
1247
  end
1158
1248
 
1159
1249
  def format(q)
1160
- if value&.is_a?(HashLiteral)
1250
+ if value.is_a?(HashLiteral)
1161
1251
  format_contents(q)
1162
1252
  else
1163
1253
  q.group { format_contents(q) }
@@ -1210,7 +1300,7 @@ module SyntaxTree
1210
1300
 
1211
1301
  alias deconstruct child_nodes
1212
1302
 
1213
- def deconstruct_keys(keys)
1303
+ def deconstruct_keys(_keys)
1214
1304
  { value: value, location: location, comments: comments }
1215
1305
  end
1216
1306
 
@@ -1248,7 +1338,7 @@ module SyntaxTree
1248
1338
 
1249
1339
  alias deconstruct child_nodes
1250
1340
 
1251
- def deconstruct_keys(keys)
1341
+ def deconstruct_keys(_keys)
1252
1342
  { value: value, location: location, comments: comments }
1253
1343
  end
1254
1344
 
@@ -1283,7 +1373,7 @@ module SyntaxTree
1283
1373
 
1284
1374
  alias deconstruct child_nodes
1285
1375
 
1286
- def deconstruct_keys(keys)
1376
+ def deconstruct_keys(_keys)
1287
1377
  { value: value, location: location, comments: comments }
1288
1378
  end
1289
1379
 
@@ -1296,21 +1386,28 @@ module SyntaxTree
1296
1386
  # hash or bare hash. It first determines if every key in the hash can use
1297
1387
  # labels. If it can, it uses labels. Otherwise it uses hash rockets.
1298
1388
  module HashKeyFormatter
1389
+ # Formats the keys of a hash literal using labels.
1299
1390
  class Labels
1391
+ LABEL = /^[@$_A-Za-z]([_A-Za-z0-9]*)?([!_=?A-Za-z0-9])?$/
1392
+
1300
1393
  def format_key(q, key)
1301
1394
  case key
1302
- when Label
1395
+ in Label
1303
1396
  q.format(key)
1304
- when SymbolLiteral
1397
+ in SymbolLiteral
1305
1398
  q.format(key.value)
1306
1399
  q.text(":")
1307
- when DynaSymbol
1400
+ in DynaSymbol[parts: [TStringContent[value: LABEL] => part]]
1401
+ q.format(part)
1402
+ q.text(":")
1403
+ in DynaSymbol
1308
1404
  q.format(key)
1309
1405
  q.text(":")
1310
1406
  end
1311
1407
  end
1312
1408
  end
1313
1409
 
1410
+ # Formats the keys of a hash literal using hash rockets.
1314
1411
  class Rockets
1315
1412
  def format_key(q, key)
1316
1413
  case key
@@ -1384,7 +1481,7 @@ module SyntaxTree
1384
1481
 
1385
1482
  alias deconstruct child_nodes
1386
1483
 
1387
- def deconstruct_keys(keys)
1484
+ def deconstruct_keys(_keys)
1388
1485
  { assocs: assocs, location: location, comments: comments }
1389
1486
  end
1390
1487
 
@@ -1426,7 +1523,7 @@ module SyntaxTree
1426
1523
 
1427
1524
  alias deconstruct child_nodes
1428
1525
 
1429
- def deconstruct_keys(keys)
1526
+ def deconstruct_keys(_keys)
1430
1527
  { bodystmt: bodystmt, location: location, comments: comments }
1431
1528
  end
1432
1529
 
@@ -1474,7 +1571,7 @@ module SyntaxTree
1474
1571
 
1475
1572
  alias deconstruct child_nodes
1476
1573
 
1477
- def deconstruct_keys(keys)
1574
+ def deconstruct_keys(_keys)
1478
1575
  { statement: statement, location: location, comments: comments }
1479
1576
  end
1480
1577
 
@@ -1534,7 +1631,7 @@ module SyntaxTree
1534
1631
 
1535
1632
  alias deconstruct child_nodes
1536
1633
 
1537
- def deconstruct_keys(keys)
1634
+ def deconstruct_keys(_keys)
1538
1635
  {
1539
1636
  left: left,
1540
1637
  operator: operator,
@@ -1552,12 +1649,12 @@ module SyntaxTree
1552
1649
  q.text(" ") unless power
1553
1650
 
1554
1651
  if operator == :<<
1555
- q.text(operator)
1652
+ q.text(operator.to_s)
1556
1653
  q.text(" ")
1557
1654
  q.format(right)
1558
1655
  else
1559
1656
  q.group do
1560
- q.text(operator)
1657
+ q.text(operator.to_s)
1561
1658
 
1562
1659
  q.indent do
1563
1660
  q.breakable(power ? "" : " ")
@@ -1649,7 +1746,7 @@ module SyntaxTree
1649
1746
 
1650
1747
  alias deconstruct child_nodes
1651
1748
 
1652
- def deconstruct_keys(keys)
1749
+ def deconstruct_keys(_keys)
1653
1750
  { params: params, locals: locals, location: location, comments: comments }
1654
1751
  end
1655
1752
 
@@ -1693,7 +1790,7 @@ module SyntaxTree
1693
1790
 
1694
1791
  alias deconstruct child_nodes
1695
1792
 
1696
- def deconstruct_keys(keys)
1793
+ def deconstruct_keys(_keys)
1697
1794
  { name: name, location: location, comments: comments }
1698
1795
  end
1699
1796
 
@@ -1789,7 +1886,7 @@ module SyntaxTree
1789
1886
 
1790
1887
  alias deconstruct child_nodes
1791
1888
 
1792
- def deconstruct_keys(keys)
1889
+ def deconstruct_keys(_keys)
1793
1890
  {
1794
1891
  statements: statements,
1795
1892
  rescue_clause: rescue_clause,
@@ -1835,6 +1932,7 @@ module SyntaxTree
1835
1932
 
1836
1933
  # Responsible for formatting either a BraceBlock or a DoBlock.
1837
1934
  class BlockFormatter
1935
+ # Formats the opening brace or keyword of a block.
1838
1936
  class BlockOpenFormatter
1839
1937
  # [String] the actual output that should be printed
1840
1938
  attr_reader :text
@@ -1900,9 +1998,9 @@ module SyntaxTree
1900
1998
  end
1901
1999
 
1902
2000
  q.group do
1903
- q.if_break { format_break(q, break_opening, break_closing) }.if_flat do
1904
- format_flat(q, flat_opening, flat_closing)
1905
- end
2001
+ q
2002
+ .if_break { format_break(q, break_opening, break_closing) }
2003
+ .if_flat { format_flat(q, flat_opening, flat_closing) }
1906
2004
  end
1907
2005
  end
1908
2006
 
@@ -2027,7 +2125,7 @@ module SyntaxTree
2027
2125
 
2028
2126
  alias deconstruct child_nodes
2029
2127
 
2030
- def deconstruct_keys(keys)
2128
+ def deconstruct_keys(_keys)
2031
2129
  {
2032
2130
  lbrace: lbrace,
2033
2131
  block_var: block_var,
@@ -2042,12 +2140,12 @@ module SyntaxTree
2042
2140
  end
2043
2141
  end
2044
2142
 
2045
- # Formats either a Break or Next node.
2143
+ # Formats either a Break, Next, or Return node.
2046
2144
  class FlowControlFormatter
2047
2145
  # [String] the keyword to print
2048
2146
  attr_reader :keyword
2049
2147
 
2050
- # [Break | Next] the node being formatted
2148
+ # [Break | Next | Return] the node being formatted
2051
2149
  attr_reader :node
2052
2150
 
2053
2151
  def initialize(keyword, node)
@@ -2056,32 +2154,123 @@ module SyntaxTree
2056
2154
  end
2057
2155
 
2058
2156
  def format(q)
2059
- arguments = node.arguments
2060
-
2061
2157
  q.group do
2062
2158
  q.text(keyword)
2063
2159
 
2064
- if arguments.parts.any?
2065
- if arguments.parts.length == 1
2066
- part = arguments.parts.first
2067
-
2068
- if part.is_a?(Paren)
2069
- q.format(arguments)
2070
- elsif part.is_a?(ArrayLiteral)
2071
- q.text(" ")
2072
- q.format(arguments)
2073
- else
2074
- format_arguments(q, "(", ")")
2075
- end
2076
- else
2077
- format_arguments(q, " [", "]")
2078
- end
2160
+ case node.arguments.parts
2161
+ in []
2162
+ # Here there are no arguments at all, so we're not going to print
2163
+ # anything. This would be like if we had:
2164
+ #
2165
+ # break
2166
+ #
2167
+ in [Paren[
2168
+ contents: {
2169
+ body: [ArrayLiteral[contents: { parts: [_, _, *] }] => array]
2170
+ }
2171
+ ]]
2172
+ # Here we have a single argument that is a set of parentheses wrapping
2173
+ # an array literal that has at least 2 elements. We're going to print
2174
+ # the contents of the array directly. This would be like if we had:
2175
+ #
2176
+ # break([1, 2, 3])
2177
+ #
2178
+ # which we will print as:
2179
+ #
2180
+ # break 1, 2, 3
2181
+ #
2182
+ q.text(" ")
2183
+ format_array_contents(q, array)
2184
+ in [Paren[contents: { body: [ArrayLiteral => statement] }]]
2185
+ # Here we have a single argument that is a set of parentheses wrapping
2186
+ # an array literal that has 0 or 1 elements. We're going to skip the
2187
+ # parentheses but print the array itself. This would be like if we
2188
+ # had:
2189
+ #
2190
+ # break([1])
2191
+ #
2192
+ # which we will print as:
2193
+ #
2194
+ # break [1]
2195
+ #
2196
+ q.text(" ")
2197
+ q.format(statement)
2198
+ in [Paren[contents: { body: [statement] }]] if skip_parens?(statement)
2199
+ # Here we have a single argument that is a set of parentheses that
2200
+ # themselves contain a single statement. That statement is a simple
2201
+ # value that we can skip the parentheses for. This would be like if we
2202
+ # had:
2203
+ #
2204
+ # break(1)
2205
+ #
2206
+ # which we will print as:
2207
+ #
2208
+ # break 1
2209
+ #
2210
+ q.text(" ")
2211
+ q.format(statement)
2212
+ in [Paren => part]
2213
+ # Here we have a single argument that is a set of parentheses. We're
2214
+ # going to print the parentheses themselves as if they were the set of
2215
+ # arguments. This would be like if we had:
2216
+ #
2217
+ # break(foo.bar)
2218
+ #
2219
+ q.format(part)
2220
+ in [ArrayLiteral[contents: { parts: [_, _, *] }] => array]
2221
+ # Here there is a single argument that is an array literal with at
2222
+ # least two elements. We skip directly into the array literal's
2223
+ # elements in order to print the contents. This would be like if we
2224
+ # had:
2225
+ #
2226
+ # break [1, 2, 3]
2227
+ #
2228
+ # which we will print as:
2229
+ #
2230
+ # break 1, 2, 3
2231
+ #
2232
+ q.text(" ")
2233
+ format_array_contents(q, array)
2234
+ in [ArrayLiteral => part]
2235
+ # Here there is a single argument that is an array literal with 0 or 1
2236
+ # elements. In this case we're going to print the array as it is
2237
+ # because skipping the brackets would change the remaining. This would
2238
+ # be like if we had:
2239
+ #
2240
+ # break []
2241
+ # break [1]
2242
+ #
2243
+ q.text(" ")
2244
+ q.format(part)
2245
+ in [_]
2246
+ # Here there is a single argument that hasn't matched one of our
2247
+ # previous cases. We're going to print the argument as it is. This
2248
+ # would be like if we had:
2249
+ #
2250
+ # break foo
2251
+ #
2252
+ format_arguments(q, "(", ")")
2253
+ else
2254
+ # If there are multiple arguments, format them all. If the line is
2255
+ # going to break into multiple, then use brackets to start and end the
2256
+ # expression.
2257
+ format_arguments(q, " [", "]")
2079
2258
  end
2080
2259
  end
2081
2260
  end
2082
2261
 
2083
2262
  private
2084
2263
 
2264
+ def format_array_contents(q, array)
2265
+ q.if_break { q.text("[") }
2266
+ q.indent do
2267
+ q.breakable("")
2268
+ q.format(array.contents)
2269
+ end
2270
+ q.breakable("")
2271
+ q.if_break { q.text("]") }
2272
+ end
2273
+
2085
2274
  def format_arguments(q, opening, closing)
2086
2275
  q.if_break { q.text(opening) }
2087
2276
  q.indent do
@@ -2091,6 +2280,17 @@ module SyntaxTree
2091
2280
  q.breakable("")
2092
2281
  q.if_break { q.text(closing) }
2093
2282
  end
2283
+
2284
+ def skip_parens?(node)
2285
+ case node
2286
+ in FloatLiteral | Imaginary | Int | RationalLiteral
2287
+ true
2288
+ in VarRef[value: Const | CVar | GVar | IVar | Kw]
2289
+ true
2290
+ else
2291
+ false
2292
+ end
2293
+ end
2094
2294
  end
2095
2295
 
2096
2296
  # Break represents using the +break+ keyword.
@@ -2124,7 +2324,7 @@ module SyntaxTree
2124
2324
 
2125
2325
  alias deconstruct child_nodes
2126
2326
 
2127
- def deconstruct_keys(keys)
2327
+ def deconstruct_keys(_keys)
2128
2328
  { arguments: arguments, location: location, comments: comments }
2129
2329
  end
2130
2330
 
@@ -2156,6 +2356,211 @@ module SyntaxTree
2156
2356
  end
2157
2357
  end
2158
2358
 
2359
+ # This is probably the most complicated formatter in this file. It's
2360
+ # responsible for formatting chains of method calls, with or without arguments
2361
+ # or blocks. In general, we want to go from something like
2362
+ #
2363
+ # foo.bar.baz
2364
+ #
2365
+ # to
2366
+ #
2367
+ # foo
2368
+ # .bar
2369
+ # .baz
2370
+ #
2371
+ # Of course there are a lot of caveats to that, including trailing operators
2372
+ # when necessary, where comments are places, how blocks are aligned, etc.
2373
+ class CallChainFormatter
2374
+ # [Call | MethodAddBlock] the top of the call chain
2375
+ attr_reader :node
2376
+
2377
+ def initialize(node)
2378
+ @node = node
2379
+ end
2380
+
2381
+ def format(q)
2382
+ children = [node]
2383
+ threshold = 3
2384
+
2385
+ # First, walk down the chain until we get to the point where we're not
2386
+ # longer at a chainable node.
2387
+ loop do
2388
+ case children.last
2389
+ in Call[receiver: Call]
2390
+ children << children.last.receiver
2391
+ in Call[receiver: MethodAddBlock[call: Call]]
2392
+ children << children.last.receiver
2393
+ in MethodAddBlock[call: Call]
2394
+ children << children.last.call
2395
+ else
2396
+ break
2397
+ end
2398
+ end
2399
+
2400
+ # Here, we have very specialized behavior where if we're within a sig
2401
+ # block, then we're going to assume we're creating a Sorbet type
2402
+ # signature. In that case, we really want the threshold to be lowered so
2403
+ # that we create method chains off of any two method calls within the
2404
+ # block. For more details, see
2405
+ # https://github.com/prettier/plugin-ruby/issues/863.
2406
+ parents = q.parents.take(4)
2407
+ if (parent = parents[2])
2408
+ # If we're at a do_block, then we want to go one more level up. This is
2409
+ # because do blocks have BodyStmt nodes instead of just Statements
2410
+ # nodes.
2411
+ parent = parents[3] if parent.is_a?(DoBlock)
2412
+
2413
+ case parent
2414
+ in MethodAddBlock[call: FCall[value: { value: "sig" }]]
2415
+ threshold = 2
2416
+ else
2417
+ end
2418
+ end
2419
+
2420
+ if children.length >= threshold
2421
+ q.group do
2422
+ q
2423
+ .if_break { format_chain(q, children) }
2424
+ .if_flat { node.format_contents(q) }
2425
+ end
2426
+ else
2427
+ node.format_contents(q)
2428
+ end
2429
+ end
2430
+
2431
+ def format_chain(q, children)
2432
+ # We're going to have some specialized behavior for if it's an entire
2433
+ # chain of calls without arguments except for the last one. This is common
2434
+ # enough in Ruby source code that it's worth the extra complexity here.
2435
+ empty_except_last =
2436
+ children
2437
+ .drop(1)
2438
+ .all? { |child| child.is_a?(Call) && child.arguments.nil? }
2439
+
2440
+ # Here, we're going to add all of the children onto the stack of the
2441
+ # formatter so it's as if we had descending normally into them. This is
2442
+ # necessary so they can check their parents as normal.
2443
+ q.stack.concat(children)
2444
+ q.format(children.last.receiver)
2445
+
2446
+ q.group do
2447
+ if attach_directly?(children.last)
2448
+ format_child(q, children.pop)
2449
+ q.stack.pop
2450
+ end
2451
+
2452
+ q.indent do
2453
+ # We track another variable that checks if you need to move the
2454
+ # operator to the previous line in case there are trailing comments
2455
+ # and a trailing operator.
2456
+ skip_operator = false
2457
+
2458
+ while (child = children.pop)
2459
+ case child
2460
+ in Call[
2461
+ receiver: Call[message: { value: "where" }],
2462
+ message: { value: "not" }
2463
+ ]
2464
+ # This is very specialized behavior wherein we group
2465
+ # .where.not calls together because it looks better. For more
2466
+ # information, see
2467
+ # https://github.com/prettier/plugin-ruby/issues/862.
2468
+ in Call
2469
+ # If we're at a Call node and not a MethodAddBlock node in the
2470
+ # chain then we're going to add a newline so it indents properly.
2471
+ q.breakable("")
2472
+ else
2473
+ end
2474
+
2475
+ format_child(
2476
+ q,
2477
+ child,
2478
+ skip_comments: children.empty?,
2479
+ skip_operator: skip_operator,
2480
+ skip_attached: empty_except_last && children.empty?
2481
+ )
2482
+
2483
+ # If the parent call node has a comment on the message then we need
2484
+ # to print the operator trailing in order to keep it working.
2485
+ case children.last
2486
+ in Call[message: { comments: [_, *] }, operator:]
2487
+ q.format(CallOperatorFormatter.new(operator))
2488
+ skip_operator = true
2489
+ else
2490
+ skip_operator = false
2491
+ end
2492
+
2493
+ # Pop off the formatter's stack so that it aligns with what would
2494
+ # have happened if we had been formatting normally.
2495
+ q.stack.pop
2496
+ end
2497
+ end
2498
+ end
2499
+
2500
+ if empty_except_last
2501
+ case node
2502
+ in Call
2503
+ node.format_arguments(q)
2504
+ in MethodAddBlock[block:]
2505
+ q.format(block)
2506
+ end
2507
+ end
2508
+ end
2509
+
2510
+ def self.chained?(node)
2511
+ case node
2512
+ in Call | MethodAddBlock[call: Call]
2513
+ true
2514
+ else
2515
+ false
2516
+ end
2517
+ end
2518
+
2519
+ private
2520
+
2521
+ # For certain nodes, we want to attach directly to the end and don't
2522
+ # want to indent the first call. So we'll pop off the first children and
2523
+ # format it separately here.
2524
+ def attach_directly?(node)
2525
+ [ArrayLiteral, HashLiteral, Heredoc, If, Unless, XStringLiteral].include?(
2526
+ node.receiver.class
2527
+ )
2528
+ end
2529
+
2530
+ def format_child(
2531
+ q,
2532
+ child,
2533
+ skip_comments: false,
2534
+ skip_operator: false,
2535
+ skip_attached: false
2536
+ )
2537
+ # First, format the actual contents of the child.
2538
+ case child
2539
+ in Call
2540
+ q.group do
2541
+ unless skip_operator
2542
+ q.format(CallOperatorFormatter.new(child.operator))
2543
+ end
2544
+ q.format(child.message) if child.message != :call
2545
+ child.format_arguments(q) unless skip_attached
2546
+ end
2547
+ in MethodAddBlock
2548
+ q.format(child.block) unless skip_attached
2549
+ end
2550
+
2551
+ # If there are any comments on this node then we need to explicitly print
2552
+ # them out here since we're bypassing the normal comment printing.
2553
+ if child.comments.any? && !skip_comments
2554
+ child.comments.each do |comment|
2555
+ comment.inline? ? q.text(" ") : q.breakable
2556
+ comment.format(q)
2557
+ end
2558
+
2559
+ q.break_parent
2560
+ end
2561
+ end
2562
+ end
2563
+
2159
2564
  # Call represents a method call.
2160
2565
  #
2161
2566
  # receiver.message
@@ -2207,7 +2612,7 @@ module SyntaxTree
2207
2612
 
2208
2613
  alias deconstruct child_nodes
2209
2614
 
2210
- def deconstruct_keys(keys)
2615
+ def deconstruct_keys(_keys)
2211
2616
  {
2212
2617
  receiver: receiver,
2213
2618
  operator: operator,
@@ -2219,6 +2624,34 @@ module SyntaxTree
2219
2624
  end
2220
2625
 
2221
2626
  def format(q)
2627
+ # If we're at the top of a call chain, then we're going to do some
2628
+ # specialized printing in case we can print it nicely. We _only_ do this
2629
+ # at the top of the chain to avoid weird recursion issues.
2630
+ if !CallChainFormatter.chained?(q.parent) &&
2631
+ CallChainFormatter.chained?(receiver)
2632
+ q.group do
2633
+ q
2634
+ .if_break { CallChainFormatter.new(self).format(q) }
2635
+ .if_flat { format_contents(q) }
2636
+ end
2637
+ else
2638
+ format_contents(q)
2639
+ end
2640
+ end
2641
+
2642
+ def format_arguments(q)
2643
+ case arguments
2644
+ in ArgParen
2645
+ q.format(arguments)
2646
+ in Args
2647
+ q.text(" ")
2648
+ q.format(arguments)
2649
+ else
2650
+ # Do nothing if there are no arguments.
2651
+ end
2652
+ end
2653
+
2654
+ def format_contents(q)
2222
2655
  call_operator = CallOperatorFormatter.new(operator)
2223
2656
 
2224
2657
  q.group do
@@ -2241,7 +2674,7 @@ module SyntaxTree
2241
2674
  q.format(message) if message != :call
2242
2675
  end
2243
2676
 
2244
- q.format(arguments) if arguments
2677
+ format_arguments(q)
2245
2678
  end
2246
2679
  end
2247
2680
  end
@@ -2289,7 +2722,7 @@ module SyntaxTree
2289
2722
 
2290
2723
  alias deconstruct child_nodes
2291
2724
 
2292
- def deconstruct_keys(keys)
2725
+ def deconstruct_keys(_keys)
2293
2726
  {
2294
2727
  keyword: keyword,
2295
2728
  value: value,
@@ -2354,7 +2787,7 @@ module SyntaxTree
2354
2787
 
2355
2788
  alias deconstruct child_nodes
2356
2789
 
2357
- def deconstruct_keys(keys)
2790
+ def deconstruct_keys(_keys)
2358
2791
  {
2359
2792
  value: value,
2360
2793
  operator: operator,
@@ -2443,7 +2876,7 @@ module SyntaxTree
2443
2876
 
2444
2877
  alias deconstruct child_nodes
2445
2878
 
2446
- def deconstruct_keys(keys)
2879
+ def deconstruct_keys(_keys)
2447
2880
  {
2448
2881
  constant: constant,
2449
2882
  superclass: superclass,
@@ -2507,8 +2940,8 @@ module SyntaxTree
2507
2940
  end
2508
2941
 
2509
2942
  alias deconstruct child_nodes
2510
-
2511
- def deconstruct_keys(keys)
2943
+
2944
+ def deconstruct_keys(_keys)
2512
2945
  { value: value, location: location }
2513
2946
  end
2514
2947
  end
@@ -2546,7 +2979,7 @@ module SyntaxTree
2546
2979
 
2547
2980
  alias deconstruct child_nodes
2548
2981
 
2549
- def deconstruct_keys(keys)
2982
+ def deconstruct_keys(_keys)
2550
2983
  {
2551
2984
  message: message,
2552
2985
  arguments: arguments,
@@ -2558,26 +2991,25 @@ module SyntaxTree
2558
2991
  def format(q)
2559
2992
  q.group do
2560
2993
  q.format(message)
2561
- q.text(" ")
2562
-
2563
- if align?(self)
2564
- q.nest(message.value.length + 1) { q.format(arguments) }
2565
- else
2566
- q.format(arguments)
2567
- end
2994
+ align(q, self) { q.format(arguments) }
2568
2995
  end
2569
2996
  end
2570
2997
 
2571
2998
  private
2572
2999
 
2573
- def align?(node)
3000
+ def align(q, node, &block)
2574
3001
  case node.arguments
2575
3002
  in Args[parts: [Def | Defs | DefEndless]]
2576
- false
3003
+ q.text(" ")
3004
+ yield
3005
+ in Args[parts: [IfOp]]
3006
+ q.if_flat { q.text(" ") }
3007
+ yield
2577
3008
  in Args[parts: [Command => command]]
2578
- align?(command)
3009
+ align(q, command, &block)
2579
3010
  else
2580
- true
3011
+ q.text(" ")
3012
+ q.nest(message.value.length + 1) { yield }
2581
3013
  end
2582
3014
  end
2583
3015
  end
@@ -2629,7 +3061,7 @@ module SyntaxTree
2629
3061
 
2630
3062
  alias deconstruct child_nodes
2631
3063
 
2632
- def deconstruct_keys(keys)
3064
+ def deconstruct_keys(_keys)
2633
3065
  {
2634
3066
  receiver: receiver,
2635
3067
  operator: operator,
@@ -2649,9 +3081,15 @@ module SyntaxTree
2649
3081
  q.format(message)
2650
3082
  end
2651
3083
 
2652
- if arguments
3084
+ case arguments
3085
+ in Args[parts: [IfOp]]
3086
+ q.if_flat { q.text(" ") }
3087
+ q.format(arguments)
3088
+ in Args
2653
3089
  q.text(" ")
2654
3090
  q.nest(argument_alignment(q, doc)) { q.format(arguments) }
3091
+ else
3092
+ # If there are no arguments, print nothing.
2655
3093
  end
2656
3094
  end
2657
3095
  end
@@ -2745,7 +3183,7 @@ module SyntaxTree
2745
3183
  end
2746
3184
 
2747
3185
  def ignore?
2748
- value[1..-1].strip == "stree-ignore"
3186
+ value[1..].strip == "stree-ignore"
2749
3187
  end
2750
3188
 
2751
3189
  def comments
@@ -2762,7 +3200,7 @@ module SyntaxTree
2762
3200
 
2763
3201
  alias deconstruct child_nodes
2764
3202
 
2765
- def deconstruct_keys(keys)
3203
+ def deconstruct_keys(_keys)
2766
3204
  { value: value, inline: inline, location: location }
2767
3205
  end
2768
3206
 
@@ -2808,7 +3246,7 @@ module SyntaxTree
2808
3246
 
2809
3247
  alias deconstruct child_nodes
2810
3248
 
2811
- def deconstruct_keys(keys)
3249
+ def deconstruct_keys(_keys)
2812
3250
  { value: value, location: location, comments: comments }
2813
3251
  end
2814
3252
 
@@ -2850,7 +3288,7 @@ module SyntaxTree
2850
3288
 
2851
3289
  alias deconstruct child_nodes
2852
3290
 
2853
- def deconstruct_keys(keys)
3291
+ def deconstruct_keys(_keys)
2854
3292
  {
2855
3293
  parent: parent,
2856
3294
  constant: constant,
@@ -2897,7 +3335,7 @@ module SyntaxTree
2897
3335
 
2898
3336
  alias deconstruct child_nodes
2899
3337
 
2900
- def deconstruct_keys(keys)
3338
+ def deconstruct_keys(_keys)
2901
3339
  {
2902
3340
  parent: parent,
2903
3341
  constant: constant,
@@ -2942,7 +3380,7 @@ module SyntaxTree
2942
3380
 
2943
3381
  alias deconstruct child_nodes
2944
3382
 
2945
- def deconstruct_keys(keys)
3383
+ def deconstruct_keys(_keys)
2946
3384
  { constant: constant, location: location, comments: comments }
2947
3385
  end
2948
3386
 
@@ -2978,7 +3416,7 @@ module SyntaxTree
2978
3416
 
2979
3417
  alias deconstruct child_nodes
2980
3418
 
2981
- def deconstruct_keys(keys)
3419
+ def deconstruct_keys(_keys)
2982
3420
  { value: value, location: location, comments: comments }
2983
3421
  end
2984
3422
 
@@ -3022,7 +3460,7 @@ module SyntaxTree
3022
3460
 
3023
3461
  alias deconstruct child_nodes
3024
3462
 
3025
- def deconstruct_keys(keys)
3463
+ def deconstruct_keys(_keys)
3026
3464
  {
3027
3465
  name: name,
3028
3466
  params: params,
@@ -3037,7 +3475,10 @@ module SyntaxTree
3037
3475
  q.group do
3038
3476
  q.text("def ")
3039
3477
  q.format(name)
3040
- q.format(params) if !params.is_a?(Params) || !params.empty?
3478
+
3479
+ if !params.is_a?(Params) || !params.empty? || params.comments.any?
3480
+ q.format(params)
3481
+ end
3041
3482
  end
3042
3483
 
3043
3484
  unless bodystmt.empty?
@@ -3104,7 +3545,7 @@ module SyntaxTree
3104
3545
 
3105
3546
  alias deconstruct child_nodes
3106
3547
 
3107
- def deconstruct_keys(keys)
3548
+ def deconstruct_keys(_keys)
3108
3549
  {
3109
3550
  target: target,
3110
3551
  operator: operator,
@@ -3172,7 +3613,7 @@ module SyntaxTree
3172
3613
 
3173
3614
  alias deconstruct child_nodes
3174
3615
 
3175
- def deconstruct_keys(keys)
3616
+ def deconstruct_keys(_keys)
3176
3617
  { value: value, location: location, comments: comments }
3177
3618
  end
3178
3619
 
@@ -3238,7 +3679,7 @@ module SyntaxTree
3238
3679
 
3239
3680
  alias deconstruct child_nodes
3240
3681
 
3241
- def deconstruct_keys(keys)
3682
+ def deconstruct_keys(_keys)
3242
3683
  {
3243
3684
  target: target,
3244
3685
  operator: operator,
@@ -3257,7 +3698,10 @@ module SyntaxTree
3257
3698
  q.format(target)
3258
3699
  q.format(CallOperatorFormatter.new(operator), stackable: false)
3259
3700
  q.format(name)
3260
- q.format(params) if !params.is_a?(Params) || !params.empty?
3701
+
3702
+ if !params.is_a?(Params) || !params.empty? || params.comments.any?
3703
+ q.format(params)
3704
+ end
3261
3705
  end
3262
3706
 
3263
3707
  unless bodystmt.empty?
@@ -3310,7 +3754,7 @@ module SyntaxTree
3310
3754
 
3311
3755
  alias deconstruct child_nodes
3312
3756
 
3313
- def deconstruct_keys(keys)
3757
+ def deconstruct_keys(_keys)
3314
3758
  {
3315
3759
  keyword: keyword,
3316
3760
  block_var: block_var,
@@ -3390,7 +3834,7 @@ module SyntaxTree
3390
3834
 
3391
3835
  alias deconstruct child_nodes
3392
3836
 
3393
- def deconstruct_keys(keys)
3837
+ def deconstruct_keys(_keys)
3394
3838
  { left: left, right: right, location: location, comments: comments }
3395
3839
  end
3396
3840
 
@@ -3438,7 +3882,7 @@ module SyntaxTree
3438
3882
 
3439
3883
  alias deconstruct child_nodes
3440
3884
 
3441
- def deconstruct_keys(keys)
3885
+ def deconstruct_keys(_keys)
3442
3886
  { left: left, right: right, location: location, comments: comments }
3443
3887
  end
3444
3888
 
@@ -3460,7 +3904,7 @@ module SyntaxTree
3460
3904
  # quotes, then single quotes would deactivate it.)
3461
3905
  def self.locked?(node)
3462
3906
  node.parts.any? do |part|
3463
- part.is_a?(TStringContent) && part.value.match?(/#[@${]|[\\]/)
3907
+ part.is_a?(TStringContent) && part.value.match?(/\\|#[@${]/)
3464
3908
  end
3465
3909
  end
3466
3910
 
@@ -3525,7 +3969,7 @@ module SyntaxTree
3525
3969
 
3526
3970
  alias deconstruct child_nodes
3527
3971
 
3528
- def deconstruct_keys(keys)
3972
+ def deconstruct_keys(_keys)
3529
3973
  { parts: parts, quote: quote, location: location, comments: comments }
3530
3974
  end
3531
3975
 
@@ -3566,9 +4010,14 @@ module SyntaxTree
3566
4010
  matching = Quotes.matching(quote[2])
3567
4011
  pattern = /[\n#{Regexp.escape(matching)}'"]/
3568
4012
 
3569
- if parts.any? { |part|
3570
- part.is_a?(TStringContent) && part.value.match?(pattern)
3571
- }
4013
+ # This check is to ensure we don't find a matching quote inside of the
4014
+ # symbol that would be confusing.
4015
+ matched =
4016
+ parts.any? do |part|
4017
+ part.is_a?(TStringContent) && part.value.match?(pattern)
4018
+ end
4019
+
4020
+ if matched
3572
4021
  [quote, matching]
3573
4022
  elsif Quotes.locked?(self)
3574
4023
  ["#{":" unless hash_key}'", "'"]
@@ -3577,7 +4026,7 @@ module SyntaxTree
3577
4026
  end
3578
4027
  elsif Quotes.locked?(self)
3579
4028
  if quote.start_with?(":")
3580
- [hash_key ? quote[1..-1] : quote, quote[1..-1]]
4029
+ [hash_key ? quote[1..] : quote, quote[1..]]
3581
4030
  else
3582
4031
  [hash_key ? quote : ":#{quote}", quote]
3583
4032
  end
@@ -3620,7 +4069,7 @@ module SyntaxTree
3620
4069
 
3621
4070
  alias deconstruct child_nodes
3622
4071
 
3623
- def deconstruct_keys(keys)
4072
+ def deconstruct_keys(_keys)
3624
4073
  {
3625
4074
  keyword: keyword,
3626
4075
  statements: statements,
@@ -3686,7 +4135,7 @@ module SyntaxTree
3686
4135
 
3687
4136
  alias deconstruct child_nodes
3688
4137
 
3689
- def deconstruct_keys(keys)
4138
+ def deconstruct_keys(_keys)
3690
4139
  {
3691
4140
  predicate: predicate,
3692
4141
  statements: statements,
@@ -3758,7 +4207,7 @@ module SyntaxTree
3758
4207
 
3759
4208
  alias deconstruct child_nodes
3760
4209
 
3761
- def deconstruct_keys(keys)
4210
+ def deconstruct_keys(_keys)
3762
4211
  { value: value, location: location }
3763
4212
  end
3764
4213
 
@@ -3792,8 +4241,8 @@ module SyntaxTree
3792
4241
  end
3793
4242
 
3794
4243
  alias deconstruct child_nodes
3795
-
3796
- def deconstruct_keys(keys)
4244
+
4245
+ def deconstruct_keys(_keys)
3797
4246
  { value: value, location: location }
3798
4247
  end
3799
4248
  end
@@ -3822,8 +4271,8 @@ module SyntaxTree
3822
4271
  end
3823
4272
 
3824
4273
  alias deconstruct child_nodes
3825
-
3826
- def deconstruct_keys(keys)
4274
+
4275
+ def deconstruct_keys(_keys)
3827
4276
  { value: value, location: location }
3828
4277
  end
3829
4278
  end
@@ -3854,8 +4303,8 @@ module SyntaxTree
3854
4303
  end
3855
4304
 
3856
4305
  alias deconstruct child_nodes
3857
-
3858
- def deconstruct_keys(keys)
4306
+
4307
+ def deconstruct_keys(_keys)
3859
4308
  { value: value, location: location }
3860
4309
  end
3861
4310
  end
@@ -3894,7 +4343,7 @@ module SyntaxTree
3894
4343
 
3895
4344
  alias deconstruct child_nodes
3896
4345
 
3897
- def deconstruct_keys(keys)
4346
+ def deconstruct_keys(_keys)
3898
4347
  {
3899
4348
  keyword: keyword,
3900
4349
  statements: statements,
@@ -3948,7 +4397,7 @@ module SyntaxTree
3948
4397
 
3949
4398
  alias deconstruct child_nodes
3950
4399
 
3951
- def deconstruct_keys(keys)
4400
+ def deconstruct_keys(_keys)
3952
4401
  { value: value, location: location, comments: comments }
3953
4402
  end
3954
4403
 
@@ -3991,7 +4440,7 @@ module SyntaxTree
3991
4440
 
3992
4441
  alias deconstruct child_nodes
3993
4442
 
3994
- def deconstruct_keys(keys)
4443
+ def deconstruct_keys(_keys)
3995
4444
  {
3996
4445
  value: value,
3997
4446
  arguments: arguments,
@@ -4002,7 +4451,16 @@ module SyntaxTree
4002
4451
 
4003
4452
  def format(q)
4004
4453
  q.format(value)
4005
- q.format(arguments)
4454
+
4455
+ if arguments.is_a?(ArgParen) && arguments.arguments.nil? &&
4456
+ !value.is_a?(Const)
4457
+ # If you're using an explicit set of parentheses on something that looks
4458
+ # like a constant, then we need to match that in order to maintain valid
4459
+ # Ruby. For example, you could do something like Foo(), on which we
4460
+ # would need to keep the parentheses to make it look like a method call.
4461
+ else
4462
+ q.format(arguments)
4463
+ end
4006
4464
  end
4007
4465
  end
4008
4466
 
@@ -4042,7 +4500,7 @@ module SyntaxTree
4042
4500
 
4043
4501
  alias deconstruct child_nodes
4044
4502
 
4045
- def deconstruct_keys(keys)
4503
+ def deconstruct_keys(_keys)
4046
4504
  {
4047
4505
  parent: parent,
4048
4506
  operator: operator,
@@ -4088,7 +4546,7 @@ module SyntaxTree
4088
4546
 
4089
4547
  alias deconstruct child_nodes
4090
4548
 
4091
- def deconstruct_keys(keys)
4549
+ def deconstruct_keys(_keys)
4092
4550
  { value: value, location: location, comments: comments }
4093
4551
  end
4094
4552
 
@@ -4140,7 +4598,7 @@ module SyntaxTree
4140
4598
 
4141
4599
  alias deconstruct child_nodes
4142
4600
 
4143
- def deconstruct_keys(keys)
4601
+ def deconstruct_keys(_keys)
4144
4602
  {
4145
4603
  constant: constant,
4146
4604
  left: left,
@@ -4204,7 +4662,7 @@ module SyntaxTree
4204
4662
 
4205
4663
  alias deconstruct child_nodes
4206
4664
 
4207
- def deconstruct_keys(keys)
4665
+ def deconstruct_keys(_keys)
4208
4666
  {
4209
4667
  index: index,
4210
4668
  collection: collection,
@@ -4261,7 +4719,7 @@ module SyntaxTree
4261
4719
 
4262
4720
  alias deconstruct child_nodes
4263
4721
 
4264
- def deconstruct_keys(keys)
4722
+ def deconstruct_keys(_keys)
4265
4723
  { value: value, location: location, comments: comments }
4266
4724
  end
4267
4725
 
@@ -4275,6 +4733,32 @@ module SyntaxTree
4275
4733
  # { key => value }
4276
4734
  #
4277
4735
  class HashLiteral < Node
4736
+ # This is a special formatter used if the hash literal contains no values
4737
+ # but _does_ contain comments. In this case we do some special formatting to
4738
+ # make sure the comments gets indented properly.
4739
+ class EmptyWithCommentsFormatter
4740
+ # [LBrace] the opening brace
4741
+ attr_reader :lbrace
4742
+
4743
+ def initialize(lbrace)
4744
+ @lbrace = lbrace
4745
+ end
4746
+
4747
+ def format(q)
4748
+ q.group do
4749
+ q.text("{")
4750
+ q.indent do
4751
+ lbrace.comments.each do |comment|
4752
+ q.breakable(force: true)
4753
+ comment.format(q)
4754
+ end
4755
+ end
4756
+ q.breakable(force: true)
4757
+ q.text("}")
4758
+ end
4759
+ end
4760
+ end
4761
+
4278
4762
  # [LBrace] the left brace that opens this hash
4279
4763
  attr_reader :lbrace
4280
4764
 
@@ -4301,7 +4785,7 @@ module SyntaxTree
4301
4785
 
4302
4786
  alias deconstruct child_nodes
4303
4787
 
4304
- def deconstruct_keys(keys)
4788
+ def deconstruct_keys(_keys)
4305
4789
  { lbrace: lbrace, assocs: assocs, location: location, comments: comments }
4306
4790
  end
4307
4791
 
@@ -4319,7 +4803,18 @@ module SyntaxTree
4319
4803
 
4320
4804
  private
4321
4805
 
4322
- def format_contents(q)
4806
+ # If we have an empty hash that contains only comments, then we're going
4807
+ # to do some special printing to ensure they get indented correctly.
4808
+ def empty_with_comments?
4809
+ assocs.empty? && lbrace.comments.any? && lbrace.comments.none?(&:inline?)
4810
+ end
4811
+
4812
+ def format_contents(q)
4813
+ if empty_with_comments?
4814
+ EmptyWithCommentsFormatter.new(lbrace).format(q)
4815
+ return
4816
+ end
4817
+
4323
4818
  q.format(lbrace)
4324
4819
 
4325
4820
  if assocs.empty?
@@ -4359,7 +4854,14 @@ module SyntaxTree
4359
4854
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
4360
4855
  attr_reader :comments
4361
4856
 
4362
- def initialize(beginning:, ending: nil, dedent: 0, parts: [], location:, comments: [])
4857
+ def initialize(
4858
+ beginning:,
4859
+ ending: nil,
4860
+ dedent: 0,
4861
+ parts: [],
4862
+ location:,
4863
+ comments: []
4864
+ )
4363
4865
  @beginning = beginning
4364
4866
  @ending = ending
4365
4867
  @dedent = dedent
@@ -4378,7 +4880,7 @@ module SyntaxTree
4378
4880
 
4379
4881
  alias deconstruct child_nodes
4380
4882
 
4381
- def deconstruct_keys(keys)
4883
+ def deconstruct_keys(_keys)
4382
4884
  {
4383
4885
  beginning: beginning,
4384
4886
  location: location,
@@ -4393,8 +4895,12 @@ module SyntaxTree
4393
4895
  # prettyprint module. It's when you want to force a newline, but don't
4394
4896
  # want to force the break parent.
4395
4897
  breakable = -> do
4396
- q.target <<
4397
- PrettyPrint::Breakable.new(" ", 1, indent: false, force: true)
4898
+ q.target << PrettyPrint::Breakable.new(
4899
+ " ",
4900
+ 1,
4901
+ indent: false,
4902
+ force: true
4903
+ )
4398
4904
  end
4399
4905
 
4400
4906
  q.group do
@@ -4450,7 +4956,7 @@ module SyntaxTree
4450
4956
 
4451
4957
  alias deconstruct child_nodes
4452
4958
 
4453
- def deconstruct_keys(keys)
4959
+ def deconstruct_keys(_keys)
4454
4960
  { value: value, location: location, comments: comments }
4455
4961
  end
4456
4962
 
@@ -4467,6 +4973,7 @@ module SyntaxTree
4467
4973
  # end
4468
4974
  #
4469
4975
  class HshPtn < Node
4976
+ # Formats a key-value pair in a hash pattern. The value is optional.
4470
4977
  class KeywordFormatter
4471
4978
  # [Label] the keyword being used
4472
4979
  attr_reader :key
@@ -4493,6 +5000,7 @@ module SyntaxTree
4493
5000
  end
4494
5001
  end
4495
5002
 
5003
+ # Formats the optional double-splat from the pattern.
4496
5004
  class KeywordRestFormatter
4497
5005
  # [VarField] the parameter that matches the remaining keywords
4498
5006
  attr_reader :keyword_rest
@@ -4542,7 +5050,7 @@ module SyntaxTree
4542
5050
 
4543
5051
  alias deconstruct child_nodes
4544
5052
 
4545
- def deconstruct_keys(keys)
5053
+ def deconstruct_keys(_keys)
4546
5054
  {
4547
5055
  constant: constant,
4548
5056
  keywords: keywords,
@@ -4565,27 +5073,52 @@ module SyntaxTree
4565
5073
  q.text(" then") if !constant && keyword_rest && keyword_rest.value.nil?
4566
5074
  end
4567
5075
 
5076
+ # If there is a constant, we're going to format to have the constant name
5077
+ # first and then use brackets.
4568
5078
  if constant
4569
- q.format(constant)
4570
- q.group(0, "[", "]", &contents)
5079
+ q.group do
5080
+ q.format(constant)
5081
+ q.text("[")
5082
+ q.indent do
5083
+ q.breakable("")
5084
+ contents.call
5085
+ end
5086
+ q.breakable("")
5087
+ q.text("]")
5088
+ end
4571
5089
  return
4572
5090
  end
4573
5091
 
5092
+ # If there's nothing at all, then we're going to use empty braces.
4574
5093
  if parts.empty?
4575
5094
  q.text("{}")
4576
- elsif PATTERNS.include?(q.parent.class)
4577
- q.text("{ ")
4578
- contents.call
4579
- q.text(" }")
4580
- else
5095
+ return
5096
+ end
5097
+
5098
+ # If there's only one pair, then we'll just print the contents provided
5099
+ # we're not inside another pattern.
5100
+ if !PATTERNS.include?(q.parent.class) && parts.size == 1
4581
5101
  contents.call
5102
+ return
5103
+ end
5104
+
5105
+ # Otherwise, we're going to always use braces to make it clear it's a hash
5106
+ # pattern.
5107
+ q.group do
5108
+ q.text("{")
5109
+ q.indent do
5110
+ q.breakable
5111
+ contents.call
5112
+ end
5113
+ q.breakable
5114
+ q.text("}")
4582
5115
  end
4583
5116
  end
4584
5117
  end
4585
5118
 
4586
5119
  # The list of nodes that represent patterns inside of pattern matching so that
4587
5120
  # when a pattern is being printed it knows if it's nested.
4588
- PATTERNS = [AryPtn, Binary, FndPtn, HshPtn, RAssign]
5121
+ PATTERNS = [AryPtn, Binary, FndPtn, HshPtn, RAssign].freeze
4589
5122
 
4590
5123
  # Ident represents an identifier anywhere in code. It can represent a very
4591
5124
  # large number of things, depending on where it is in the syntax tree.
@@ -4615,7 +5148,7 @@ module SyntaxTree
4615
5148
 
4616
5149
  alias deconstruct child_nodes
4617
5150
 
4618
- def deconstruct_keys(keys)
5151
+ def deconstruct_keys(_keys)
4619
5152
  { value: value, location: location, comments: comments }
4620
5153
  end
4621
5154
 
@@ -4632,7 +5165,7 @@ module SyntaxTree
4632
5165
  def self.call(parent)
4633
5166
  queue = [parent]
4634
5167
 
4635
- while node = queue.shift
5168
+ while (node = queue.shift)
4636
5169
  return true if [Assign, MAssign, OpAssign].include?(node.class)
4637
5170
  queue += node.child_nodes
4638
5171
  end
@@ -4641,6 +5174,65 @@ module SyntaxTree
4641
5174
  end
4642
5175
  end
4643
5176
 
5177
+ # In order for an `if` or `unless` expression to be shortened to a ternary,
5178
+ # there has to be one and only one consequent clause which is an Else. Both
5179
+ # the body of the main node and the body of the Else node must have only one
5180
+ # statement, and that statement must not be on the denied list of potential
5181
+ # statements.
5182
+ module Ternaryable
5183
+ class << self
5184
+ def call(q, node)
5185
+ case q.parents.take(2)[1]
5186
+ in Paren[contents: Statements[body: [node]]]
5187
+ # If this is a conditional inside of a parentheses as the only
5188
+ # content, then we don't want to transform it into a ternary.
5189
+ # Presumably the user wanted it to be an explicit conditional because
5190
+ # there are parentheses around it. So we'll just leave it in place.
5191
+ false
5192
+ else
5193
+ # Otherwise, we're going to check the conditional for certain cases.
5194
+ case node
5195
+ in predicate: Assign | Command | CommandCall | MAssign | OpAssign
5196
+ false
5197
+ in {
5198
+ statements: { body: [truthy] },
5199
+ consequent: Else[statements: { body: [falsy] }]
5200
+ }
5201
+ ternaryable?(truthy) && ternaryable?(falsy)
5202
+ else
5203
+ false
5204
+ end
5205
+ end
5206
+ end
5207
+
5208
+ private
5209
+
5210
+ # Certain expressions cannot be reduced to a ternary without adding
5211
+ # parentheses around them. In this case we say they cannot be ternaried
5212
+ # and default instead to breaking them into multiple lines.
5213
+ def ternaryable?(statement)
5214
+ # This is a list of nodes that should not be allowed to be a part of a
5215
+ # ternary clause.
5216
+ no_ternary = [
5217
+ Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfMod, IfOp,
5218
+ Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super,
5219
+ Undef, Unless, UnlessMod, Until, UntilMod, VarAlias, VoidStmt, While,
5220
+ WhileMod, Yield, Yield0, ZSuper
5221
+ ]
5222
+
5223
+ # Here we're going to check that the only statement inside the
5224
+ # statements node is no a part of our denied list of nodes that can be
5225
+ # ternaries.
5226
+ #
5227
+ # If the user is using one of the lower precedence "and" or "or"
5228
+ # operators, then we can't use a ternary expression as it would break
5229
+ # the flow control.
5230
+ !no_ternary.include?(statement.class) &&
5231
+ !(statement.is_a?(Binary) && %i[and or].include?(statement.operator))
5232
+ end
5233
+ end
5234
+ end
5235
+
4644
5236
  # Formats an If or Unless node.
4645
5237
  class ConditionalFormatter
4646
5238
  # [String] the keyword associated with this conditional
@@ -4655,6 +5247,13 @@ module SyntaxTree
4655
5247
  end
4656
5248
 
4657
5249
  def format(q)
5250
+ # If we can transform this node into a ternary, then we're going to print
5251
+ # a special version that uses the ternary operator if it fits on one line.
5252
+ if Ternaryable.call(q, node)
5253
+ format_ternary(q)
5254
+ return
5255
+ end
5256
+
4658
5257
  # If the predicate of the conditional contains an assignment (in which
4659
5258
  # case we can't know for certain that that assignment doesn't impact the
4660
5259
  # statements inside the conditional) then we can't use the modifier form
@@ -4664,17 +5263,19 @@ module SyntaxTree
4664
5263
  return
4665
5264
  end
4666
5265
 
4667
- if node.consequent || node.statements.empty?
5266
+ if node.consequent || node.statements.empty? || contains_conditional?
4668
5267
  q.group { format_break(q, force: true) }
4669
5268
  else
4670
5269
  q.group do
4671
- q.if_break { format_break(q, force: false) }.if_flat do
4672
- Parentheses.flat(q) do
4673
- q.format(node.statements)
4674
- q.text(" #{keyword} ")
4675
- q.format(node.predicate)
5270
+ q
5271
+ .if_break { format_break(q, force: false) }
5272
+ .if_flat do
5273
+ Parentheses.flat(q) do
5274
+ q.format(node.statements)
5275
+ q.text(" #{keyword} ")
5276
+ q.format(node.predicate)
5277
+ end
4676
5278
  end
4677
- end
4678
5279
  end
4679
5280
  end
4680
5281
  end
@@ -4700,6 +5301,61 @@ module SyntaxTree
4700
5301
  q.breakable(force: force)
4701
5302
  q.text("end")
4702
5303
  end
5304
+
5305
+ def format_ternary(q)
5306
+ q.group do
5307
+ q
5308
+ .if_break do
5309
+ q.text("#{keyword} ")
5310
+ q.nest(keyword.length + 1) { q.format(node.predicate) }
5311
+
5312
+ q.indent do
5313
+ q.breakable
5314
+ q.format(node.statements)
5315
+ end
5316
+
5317
+ q.breakable
5318
+ q.group do
5319
+ q.format(node.consequent.keyword)
5320
+ q.indent do
5321
+ # This is a very special case of breakable where we want to
5322
+ # force it into the output but we _don't_ want to explicitly
5323
+ # break the parent. If a break-parent shows up in the tree, then
5324
+ # it's going to force it all the way up to the tree, which is
5325
+ # going to negate the ternary. Maybe this should be an option in
5326
+ # prettyprint? As in force: :no_break_parent or something.
5327
+ q.target << PrettyPrint::Breakable.new(" ", 1, force: true)
5328
+ q.format(node.consequent.statements)
5329
+ end
5330
+ end
5331
+
5332
+ q.breakable
5333
+ q.text("end")
5334
+ end
5335
+ .if_flat do
5336
+ Parentheses.flat(q) do
5337
+ q.format(node.predicate)
5338
+ q.text(" ? ")
5339
+
5340
+ statements = [node.statements, node.consequent.statements]
5341
+ statements.reverse! if keyword == "unless"
5342
+
5343
+ q.format(statements[0])
5344
+ q.text(" : ")
5345
+ q.format(statements[1])
5346
+ end
5347
+ end
5348
+ end
5349
+ end
5350
+
5351
+ def contains_conditional?
5352
+ case node
5353
+ in statements: { body: [If | IfMod | IfOp | Unless | UnlessMod] }
5354
+ true
5355
+ else
5356
+ false
5357
+ end
5358
+ end
4703
5359
  end
4704
5360
 
4705
5361
  # If represents the first clause in an +if+ chain.
@@ -4744,7 +5400,7 @@ module SyntaxTree
4744
5400
 
4745
5401
  alias deconstruct child_nodes
4746
5402
 
4747
- def deconstruct_keys(keys)
5403
+ def deconstruct_keys(_keys)
4748
5404
  {
4749
5405
  predicate: predicate,
4750
5406
  statements: statements,
@@ -4794,7 +5450,7 @@ module SyntaxTree
4794
5450
 
4795
5451
  alias deconstruct child_nodes
4796
5452
 
4797
- def deconstruct_keys(keys)
5453
+ def deconstruct_keys(_keys)
4798
5454
  {
4799
5455
  predicate: predicate,
4800
5456
  truthy: truthy,
@@ -4812,7 +5468,8 @@ module SyntaxTree
4812
5468
  Yield0, ZSuper
4813
5469
  ]
4814
5470
 
4815
- if force_flat.include?(truthy.class) || force_flat.include?(falsy.class)
5471
+ if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) ||
5472
+ force_flat.include?(falsy.class)
4816
5473
  q.group { format_flat(q) }
4817
5474
  return
4818
5475
  end
@@ -4932,7 +5589,7 @@ module SyntaxTree
4932
5589
 
4933
5590
  alias deconstruct child_nodes
4934
5591
 
4935
- def deconstruct_keys(keys)
5592
+ def deconstruct_keys(_keys)
4936
5593
  {
4937
5594
  statement: statement,
4938
5595
  predicate: predicate,
@@ -4973,7 +5630,7 @@ module SyntaxTree
4973
5630
 
4974
5631
  alias deconstruct child_nodes
4975
5632
 
4976
- def deconstruct_keys(keys)
5633
+ def deconstruct_keys(_keys)
4977
5634
  { value: value, location: location, comments: comments }
4978
5635
  end
4979
5636
 
@@ -5020,7 +5677,7 @@ module SyntaxTree
5020
5677
 
5021
5678
  alias deconstruct child_nodes
5022
5679
 
5023
- def deconstruct_keys(keys)
5680
+ def deconstruct_keys(_keys)
5024
5681
  {
5025
5682
  pattern: pattern,
5026
5683
  statements: statements,
@@ -5079,7 +5736,7 @@ module SyntaxTree
5079
5736
 
5080
5737
  alias deconstruct child_nodes
5081
5738
 
5082
- def deconstruct_keys(keys)
5739
+ def deconstruct_keys(_keys)
5083
5740
  { value: value, location: location, comments: comments }
5084
5741
  end
5085
5742
 
@@ -5089,7 +5746,7 @@ module SyntaxTree
5089
5746
  # the values, then we're going to insert them every 3 characters
5090
5747
  # starting from the right.
5091
5748
  index = (value.length + 2) % 3
5092
- q.text(" #{value}"[index..-1].scan(/.../).join("_").strip)
5749
+ q.text(" #{value}"[index..].scan(/.../).join("_").strip)
5093
5750
  else
5094
5751
  q.text(value)
5095
5752
  end
@@ -5123,7 +5780,7 @@ module SyntaxTree
5123
5780
 
5124
5781
  alias deconstruct child_nodes
5125
5782
 
5126
- def deconstruct_keys(keys)
5783
+ def deconstruct_keys(_keys)
5127
5784
  { value: value, location: location, comments: comments }
5128
5785
  end
5129
5786
 
@@ -5168,7 +5825,7 @@ module SyntaxTree
5168
5825
 
5169
5826
  alias deconstruct child_nodes
5170
5827
 
5171
- def deconstruct_keys(keys)
5828
+ def deconstruct_keys(_keys)
5172
5829
  { value: value, location: location, comments: comments }
5173
5830
  end
5174
5831
 
@@ -5205,7 +5862,7 @@ module SyntaxTree
5205
5862
 
5206
5863
  alias deconstruct child_nodes
5207
5864
 
5208
- def deconstruct_keys(keys)
5865
+ def deconstruct_keys(_keys)
5209
5866
  { name: name, location: location, comments: comments }
5210
5867
  end
5211
5868
 
@@ -5251,7 +5908,7 @@ module SyntaxTree
5251
5908
 
5252
5909
  alias deconstruct child_nodes
5253
5910
 
5254
- def deconstruct_keys(keys)
5911
+ def deconstruct_keys(_keys)
5255
5912
  { value: value, location: location, comments: comments }
5256
5913
  end
5257
5914
 
@@ -5285,8 +5942,8 @@ module SyntaxTree
5285
5942
  end
5286
5943
 
5287
5944
  alias deconstruct child_nodes
5288
-
5289
- def deconstruct_keys(keys)
5945
+
5946
+ def deconstruct_keys(_keys)
5290
5947
  { value: value, location: location }
5291
5948
  end
5292
5949
  end
@@ -5322,7 +5979,7 @@ module SyntaxTree
5322
5979
 
5323
5980
  alias deconstruct child_nodes
5324
5981
 
5325
- def deconstruct_keys(keys)
5982
+ def deconstruct_keys(_keys)
5326
5983
  {
5327
5984
  params: params,
5328
5985
  statements: statements,
@@ -5344,25 +6001,27 @@ module SyntaxTree
5344
6001
  end
5345
6002
 
5346
6003
  q.text(" ")
5347
- q.if_break do
5348
- force_parens =
5349
- q.parents.any? do |node|
5350
- node.is_a?(Command) || node.is_a?(CommandCall)
6004
+ q
6005
+ .if_break do
6006
+ force_parens =
6007
+ q.parents.any? do |node|
6008
+ node.is_a?(Command) || node.is_a?(CommandCall)
6009
+ end
6010
+
6011
+ q.text(force_parens ? "{" : "do")
6012
+ q.indent do
6013
+ q.breakable
6014
+ q.format(statements)
5351
6015
  end
5352
6016
 
5353
- q.text(force_parens ? "{" : "do")
5354
- q.indent do
5355
6017
  q.breakable
6018
+ q.text(force_parens ? "}" : "end")
6019
+ end
6020
+ .if_flat do
6021
+ q.text("{ ")
5356
6022
  q.format(statements)
6023
+ q.text(" }")
5357
6024
  end
5358
-
5359
- q.breakable
5360
- q.text(force_parens ? "}" : "end")
5361
- end.if_flat do
5362
- q.text("{ ")
5363
- q.format(statements)
5364
- q.text(" }")
5365
- end
5366
6025
  end
5367
6026
  end
5368
6027
  end
@@ -5391,7 +6050,7 @@ module SyntaxTree
5391
6050
 
5392
6051
  alias deconstruct child_nodes
5393
6052
 
5394
- def deconstruct_keys(keys)
6053
+ def deconstruct_keys(_keys)
5395
6054
  { value: value, location: location, comments: comments }
5396
6055
  end
5397
6056
 
@@ -5424,7 +6083,7 @@ module SyntaxTree
5424
6083
 
5425
6084
  alias deconstruct child_nodes
5426
6085
 
5427
- def deconstruct_keys(keys)
6086
+ def deconstruct_keys(_keys)
5428
6087
  { value: value, location: location, comments: comments }
5429
6088
  end
5430
6089
 
@@ -5457,7 +6116,7 @@ module SyntaxTree
5457
6116
 
5458
6117
  alias deconstruct child_nodes
5459
6118
 
5460
- def deconstruct_keys(keys)
6119
+ def deconstruct_keys(_keys)
5461
6120
  { value: value, location: location, comments: comments }
5462
6121
  end
5463
6122
 
@@ -5507,7 +6166,7 @@ module SyntaxTree
5507
6166
 
5508
6167
  alias deconstruct child_nodes
5509
6168
 
5510
- def deconstruct_keys(keys)
6169
+ def deconstruct_keys(_keys)
5511
6170
  { target: target, value: value, location: location, comments: comments }
5512
6171
  end
5513
6172
 
@@ -5554,11 +6213,27 @@ module SyntaxTree
5554
6213
 
5555
6214
  alias deconstruct child_nodes
5556
6215
 
5557
- def deconstruct_keys(keys)
6216
+ def deconstruct_keys(_keys)
5558
6217
  { call: call, block: block, location: location, comments: comments }
5559
6218
  end
5560
6219
 
5561
6220
  def format(q)
6221
+ # If we're at the top of a call chain, then we're going to do some
6222
+ # specialized printing in case we can print it nicely. We _only_ do this
6223
+ # at the top of the chain to avoid weird recursion issues.
6224
+ if !CallChainFormatter.chained?(q.parent) &&
6225
+ CallChainFormatter.chained?(call)
6226
+ q.group do
6227
+ q
6228
+ .if_break { CallChainFormatter.new(self).format(q) }
6229
+ .if_flat { format_contents(q) }
6230
+ end
6231
+ else
6232
+ format_contents(q)
6233
+ end
6234
+ end
6235
+
6236
+ def format_contents(q)
5562
6237
  q.format(call)
5563
6238
  q.format(block)
5564
6239
  end
@@ -5599,7 +6274,7 @@ module SyntaxTree
5599
6274
 
5600
6275
  alias deconstruct child_nodes
5601
6276
 
5602
- def deconstruct_keys(keys)
6277
+ def deconstruct_keys(_keys)
5603
6278
  { parts: parts, location: location, comma: comma, comments: comments }
5604
6279
  end
5605
6280
 
@@ -5643,7 +6318,7 @@ module SyntaxTree
5643
6318
 
5644
6319
  alias deconstruct child_nodes
5645
6320
 
5646
- def deconstruct_keys(keys)
6321
+ def deconstruct_keys(_keys)
5647
6322
  { contents: contents, location: location, comments: comments }
5648
6323
  end
5649
6324
 
@@ -5699,7 +6374,7 @@ module SyntaxTree
5699
6374
 
5700
6375
  alias deconstruct child_nodes
5701
6376
 
5702
- def deconstruct_keys(keys)
6377
+ def deconstruct_keys(_keys)
5703
6378
  {
5704
6379
  constant: constant,
5705
6380
  bodystmt: bodystmt,
@@ -5766,7 +6441,7 @@ module SyntaxTree
5766
6441
 
5767
6442
  alias deconstruct child_nodes
5768
6443
 
5769
- def deconstruct_keys(keys)
6444
+ def deconstruct_keys(_keys)
5770
6445
  { parts: parts, location: location, comments: comments }
5771
6446
  end
5772
6447
 
@@ -5815,7 +6490,7 @@ module SyntaxTree
5815
6490
 
5816
6491
  alias deconstruct child_nodes
5817
6492
 
5818
- def deconstruct_keys(keys)
6493
+ def deconstruct_keys(_keys)
5819
6494
  { arguments: arguments, location: location, comments: comments }
5820
6495
  end
5821
6496
 
@@ -5852,7 +6527,7 @@ module SyntaxTree
5852
6527
 
5853
6528
  alias deconstruct child_nodes
5854
6529
 
5855
- def deconstruct_keys(keys)
6530
+ def deconstruct_keys(_keys)
5856
6531
  { value: value, location: location, comments: comments }
5857
6532
  end
5858
6533
 
@@ -5898,7 +6573,7 @@ module SyntaxTree
5898
6573
 
5899
6574
  alias deconstruct child_nodes
5900
6575
 
5901
- def deconstruct_keys(keys)
6576
+ def deconstruct_keys(_keys)
5902
6577
  {
5903
6578
  target: target,
5904
6579
  operator: operator,
@@ -5966,7 +6641,16 @@ module SyntaxTree
5966
6641
  # This approach maintains the nice conciseness of the inline version, while
5967
6642
  # keeping the correct semantic meaning.
5968
6643
  module Parentheses
5969
- NODES = [Args, Assign, Assoc, Binary, Call, Defined, MAssign, OpAssign]
6644
+ NODES = [
6645
+ Args,
6646
+ Assign,
6647
+ Assoc,
6648
+ Binary,
6649
+ Call,
6650
+ Defined,
6651
+ MAssign,
6652
+ OpAssign
6653
+ ].freeze
5970
6654
 
5971
6655
  def self.flat(q)
5972
6656
  return yield unless NODES.include?(q.parent.class)
@@ -5998,6 +6682,8 @@ module SyntaxTree
5998
6682
  # def method(param) end
5999
6683
  #
6000
6684
  class Params < Node
6685
+ # Formats the optional position of the parameters. This includes the label,
6686
+ # as well as the default value.
6001
6687
  class OptionalFormatter
6002
6688
  # [Ident] the name of the parameter
6003
6689
  attr_reader :name
@@ -6021,6 +6707,8 @@ module SyntaxTree
6021
6707
  end
6022
6708
  end
6023
6709
 
6710
+ # Formats the keyword position of the parameters. This includes the label,
6711
+ # as well as an optional default value.
6024
6712
  class KeywordFormatter
6025
6713
  # [Ident] the name of the parameter
6026
6714
  attr_reader :name
@@ -6047,6 +6735,8 @@ module SyntaxTree
6047
6735
  end
6048
6736
  end
6049
6737
 
6738
+ # Formats the keyword_rest position of the parameters. This can be the **nil
6739
+ # syntax, the ... syntax, or the ** syntax.
6050
6740
  class KeywordRestFormatter
6051
6741
  # [:nil | ArgsForward | KwRestParam] the value of the parameter
6052
6742
  attr_reader :value
@@ -6060,11 +6750,7 @@ module SyntaxTree
6060
6750
  end
6061
6751
 
6062
6752
  def format(q)
6063
- if value == :nil
6064
- q.text("**nil")
6065
- else
6066
- q.format(value)
6067
- end
6753
+ value == :nil ? q.text("**nil") : q.format(value)
6068
6754
  end
6069
6755
  end
6070
6756
 
@@ -6145,7 +6831,7 @@ module SyntaxTree
6145
6831
 
6146
6832
  alias deconstruct child_nodes
6147
6833
 
6148
- def deconstruct_keys(keys)
6834
+ def deconstruct_keys(_keys)
6149
6835
  {
6150
6836
  location: location,
6151
6837
  requireds: requireds,
@@ -6166,21 +6852,22 @@ module SyntaxTree
6166
6852
  ]
6167
6853
 
6168
6854
  parts << rest if rest && !rest.is_a?(ExcessedComma)
6169
- parts +=
6170
- [
6171
- *posts,
6172
- *keywords.map { |(name, value)| KeywordFormatter.new(name, value) }
6173
- ]
6855
+ parts += [
6856
+ *posts,
6857
+ *keywords.map { |(name, value)| KeywordFormatter.new(name, value) }
6858
+ ]
6174
6859
 
6175
6860
  parts << KeywordRestFormatter.new(keyword_rest) if keyword_rest
6176
6861
  parts << block if block
6177
6862
 
6178
6863
  contents = -> do
6179
6864
  q.seplist(parts) { |part| q.format(part) }
6180
- q.format(rest) if rest && rest.is_a?(ExcessedComma)
6865
+ q.format(rest) if rest.is_a?(ExcessedComma)
6181
6866
  end
6182
6867
 
6183
- if [Def, Defs, DefEndless].include?(q.parent.class)
6868
+ if ![Def, Defs, DefEndless].include?(q.parent.class) || parts.empty?
6869
+ q.nest(0, &contents)
6870
+ else
6184
6871
  q.group(0, "(", ")") do
6185
6872
  q.indent do
6186
6873
  q.breakable("")
@@ -6188,8 +6875,6 @@ module SyntaxTree
6188
6875
  end
6189
6876
  q.breakable("")
6190
6877
  end
6191
- else
6192
- q.nest(0, &contents)
6193
6878
  end
6194
6879
  end
6195
6880
  end
@@ -6227,7 +6912,7 @@ module SyntaxTree
6227
6912
 
6228
6913
  alias deconstruct child_nodes
6229
6914
 
6230
- def deconstruct_keys(keys)
6915
+ def deconstruct_keys(_keys)
6231
6916
  {
6232
6917
  lparen: lparen,
6233
6918
  contents: contents,
@@ -6278,7 +6963,7 @@ module SyntaxTree
6278
6963
 
6279
6964
  alias deconstruct child_nodes
6280
6965
 
6281
- def deconstruct_keys(keys)
6966
+ def deconstruct_keys(_keys)
6282
6967
  { value: value, location: location, comments: comments }
6283
6968
  end
6284
6969
 
@@ -6311,7 +6996,7 @@ module SyntaxTree
6311
6996
 
6312
6997
  alias deconstruct child_nodes
6313
6998
 
6314
- def deconstruct_keys(keys)
6999
+ def deconstruct_keys(_keys)
6315
7000
  { statements: statements, location: location, comments: comments }
6316
7001
  end
6317
7002
 
@@ -6356,7 +7041,7 @@ module SyntaxTree
6356
7041
 
6357
7042
  alias deconstruct child_nodes
6358
7043
 
6359
- def deconstruct_keys(keys)
7044
+ def deconstruct_keys(_keys)
6360
7045
  {
6361
7046
  beginning: beginning,
6362
7047
  elements: elements,
@@ -6410,18 +7095,9 @@ module SyntaxTree
6410
7095
  end
6411
7096
 
6412
7097
  alias deconstruct child_nodes
6413
-
6414
- def deconstruct_keys(keys)
6415
- { value: value, location: location }
6416
- end
6417
-
6418
- def pretty_print(q)
6419
- q.group(2, "(", ")") do
6420
- q.text("qsymbols_beg")
6421
7098
 
6422
- q.breakable
6423
- q.pp(value)
6424
- end
7099
+ def deconstruct_keys(_keys)
7100
+ { value: value, location: location }
6425
7101
  end
6426
7102
  end
6427
7103
 
@@ -6456,7 +7132,7 @@ module SyntaxTree
6456
7132
 
6457
7133
  alias deconstruct child_nodes
6458
7134
 
6459
- def deconstruct_keys(keys)
7135
+ def deconstruct_keys(_keys)
6460
7136
  {
6461
7137
  beginning: beginning,
6462
7138
  elements: elements,
@@ -6510,8 +7186,8 @@ module SyntaxTree
6510
7186
  end
6511
7187
 
6512
7188
  alias deconstruct child_nodes
6513
-
6514
- def deconstruct_keys(keys)
7189
+
7190
+ def deconstruct_keys(_keys)
6515
7191
  { value: value, location: location }
6516
7192
  end
6517
7193
  end
@@ -6543,7 +7219,7 @@ module SyntaxTree
6543
7219
 
6544
7220
  alias deconstruct child_nodes
6545
7221
 
6546
- def deconstruct_keys(keys)
7222
+ def deconstruct_keys(_keys)
6547
7223
  { value: value, location: location, comments: comments }
6548
7224
  end
6549
7225
 
@@ -6571,8 +7247,8 @@ module SyntaxTree
6571
7247
  end
6572
7248
 
6573
7249
  alias deconstruct child_nodes
6574
-
6575
- def deconstruct_keys(keys)
7250
+
7251
+ def deconstruct_keys(_keys)
6576
7252
  { value: value, location: location }
6577
7253
  end
6578
7254
  end
@@ -6596,8 +7272,8 @@ module SyntaxTree
6596
7272
  end
6597
7273
 
6598
7274
  alias deconstruct child_nodes
6599
-
6600
- def deconstruct_keys(keys)
7275
+
7276
+ def deconstruct_keys(_keys)
6601
7277
  { value: value, location: location }
6602
7278
  end
6603
7279
  end
@@ -6629,7 +7305,7 @@ module SyntaxTree
6629
7305
 
6630
7306
  alias deconstruct child_nodes
6631
7307
 
6632
- def deconstruct_keys(keys)
7308
+ def deconstruct_keys(_keys)
6633
7309
  { value: value, location: location, comments: comments }
6634
7310
  end
6635
7311
 
@@ -6667,8 +7343,8 @@ module SyntaxTree
6667
7343
  end
6668
7344
 
6669
7345
  alias deconstruct child_nodes
6670
-
6671
- def deconstruct_keys(keys)
7346
+
7347
+ def deconstruct_keys(_keys)
6672
7348
  { beginning: beginning, parts: parts, location: location }
6673
7349
  end
6674
7350
  end
@@ -6700,8 +7376,8 @@ module SyntaxTree
6700
7376
  end
6701
7377
 
6702
7378
  alias deconstruct child_nodes
6703
-
6704
- def deconstruct_keys(keys)
7379
+
7380
+ def deconstruct_keys(_keys)
6705
7381
  { value: value, location: location }
6706
7382
  end
6707
7383
  end
@@ -6734,8 +7410,8 @@ module SyntaxTree
6734
7410
  end
6735
7411
 
6736
7412
  alias deconstruct child_nodes
6737
-
6738
- def deconstruct_keys(keys)
7413
+
7414
+ def deconstruct_keys(_keys)
6739
7415
  { value: value, location: location }
6740
7416
  end
6741
7417
  end
@@ -6776,10 +7452,11 @@ module SyntaxTree
6776
7452
 
6777
7453
  alias deconstruct child_nodes
6778
7454
 
6779
- def deconstruct_keys(keys)
7455
+ def deconstruct_keys(_keys)
6780
7456
  {
6781
7457
  beginning: beginning,
6782
7458
  ending: ending,
7459
+ options: options,
6783
7460
  parts: parts,
6784
7461
  location: location,
6785
7462
  comments: comments
@@ -6787,7 +7464,7 @@ module SyntaxTree
6787
7464
  end
6788
7465
 
6789
7466
  def format(q)
6790
- braces = ambiguous?(q) || include?(%r{\/})
7467
+ braces = ambiguous?(q) || include?(%r{/})
6791
7468
 
6792
7469
  if braces && include?(/[{}]/)
6793
7470
  q.group do
@@ -6814,18 +7491,22 @@ module SyntaxTree
6814
7491
  end
6815
7492
 
6816
7493
  q.text("}")
6817
- q.text(ending[1..-1])
7494
+ q.text(options)
6818
7495
  end
6819
7496
  else
6820
7497
  q.group do
6821
7498
  q.text("/")
6822
7499
  q.format_each(parts)
6823
7500
  q.text("/")
6824
- q.text(ending[1..-1])
7501
+ q.text(options)
6825
7502
  end
6826
7503
  end
6827
7504
  end
6828
7505
 
7506
+ def options
7507
+ ending[1..]
7508
+ end
7509
+
6829
7510
  private
6830
7511
 
6831
7512
  def include?(pattern)
@@ -6881,7 +7562,7 @@ module SyntaxTree
6881
7562
 
6882
7563
  alias deconstruct child_nodes
6883
7564
 
6884
- def deconstruct_keys(keys)
7565
+ def deconstruct_keys(_keys)
6885
7566
  {
6886
7567
  exceptions: exceptions,
6887
7568
  variable: variable,
@@ -6956,7 +7637,10 @@ module SyntaxTree
6956
7637
 
6957
7638
  if consequent
6958
7639
  consequent.bind_end(end_char, end_column)
6959
- statements.bind_end(consequent.location.start_char, consequent.location.start_column)
7640
+ statements.bind_end(
7641
+ consequent.location.start_char,
7642
+ consequent.location.start_column
7643
+ )
6960
7644
  else
6961
7645
  statements.bind_end(end_char, end_column)
6962
7646
  end
@@ -6972,7 +7656,7 @@ module SyntaxTree
6972
7656
 
6973
7657
  alias deconstruct child_nodes
6974
7658
 
6975
- def deconstruct_keys(keys)
7659
+ def deconstruct_keys(_keys)
6976
7660
  {
6977
7661
  keyword: keyword,
6978
7662
  exception: exception,
@@ -7039,7 +7723,7 @@ module SyntaxTree
7039
7723
 
7040
7724
  alias deconstruct child_nodes
7041
7725
 
7042
- def deconstruct_keys(keys)
7726
+ def deconstruct_keys(_keys)
7043
7727
  {
7044
7728
  statement: statement,
7045
7729
  value: value,
@@ -7093,7 +7777,7 @@ module SyntaxTree
7093
7777
 
7094
7778
  alias deconstruct child_nodes
7095
7779
 
7096
- def deconstruct_keys(keys)
7780
+ def deconstruct_keys(_keys)
7097
7781
  { name: name, location: location, comments: comments }
7098
7782
  end
7099
7783
 
@@ -7130,7 +7814,7 @@ module SyntaxTree
7130
7814
 
7131
7815
  alias deconstruct child_nodes
7132
7816
 
7133
- def deconstruct_keys(keys)
7817
+ def deconstruct_keys(_keys)
7134
7818
  { value: value, location: location, comments: comments }
7135
7819
  end
7136
7820
 
@@ -7166,7 +7850,7 @@ module SyntaxTree
7166
7850
 
7167
7851
  alias deconstruct child_nodes
7168
7852
 
7169
- def deconstruct_keys(keys)
7853
+ def deconstruct_keys(_keys)
7170
7854
  { arguments: arguments, location: location, comments: comments }
7171
7855
  end
7172
7856
 
@@ -7202,7 +7886,7 @@ module SyntaxTree
7202
7886
 
7203
7887
  alias deconstruct child_nodes
7204
7888
 
7205
- def deconstruct_keys(keys)
7889
+ def deconstruct_keys(_keys)
7206
7890
  { value: value, location: location, comments: comments }
7207
7891
  end
7208
7892
 
@@ -7220,7 +7904,7 @@ module SyntaxTree
7220
7904
  @value = value
7221
7905
  @location = location
7222
7906
  end
7223
-
7907
+
7224
7908
  def accept(visitor)
7225
7909
  visitor.visit_rparen(self)
7226
7910
  end
@@ -7230,8 +7914,8 @@ module SyntaxTree
7230
7914
  end
7231
7915
 
7232
7916
  alias deconstruct child_nodes
7233
-
7234
- def deconstruct_keys(keys)
7917
+
7918
+ def deconstruct_keys(_keys)
7235
7919
  { value: value, location: location }
7236
7920
  end
7237
7921
  end
@@ -7270,7 +7954,7 @@ module SyntaxTree
7270
7954
 
7271
7955
  alias deconstruct child_nodes
7272
7956
 
7273
- def deconstruct_keys(keys)
7957
+ def deconstruct_keys(_keys)
7274
7958
  {
7275
7959
  target: target,
7276
7960
  bodystmt: bodystmt,
@@ -7372,7 +8056,7 @@ module SyntaxTree
7372
8056
 
7373
8057
  alias deconstruct child_nodes
7374
8058
 
7375
- def deconstruct_keys(keys)
8059
+ def deconstruct_keys(_keys)
7376
8060
  { parser: parser, body: body, location: location, comments: comments }
7377
8061
  end
7378
8062
 
@@ -7444,8 +8128,6 @@ module SyntaxTree
7444
8128
 
7445
8129
  if !comment.inline? && (start_char <= location.start_char) &&
7446
8130
  (end_char >= location.end_char) && !comment.ignore?
7447
- parser_comments.delete_at(comment_index)
7448
-
7449
8131
  while (node = body[body_index]) &&
7450
8132
  (
7451
8133
  node.is_a?(VoidStmt) ||
@@ -7454,7 +8136,17 @@ module SyntaxTree
7454
8136
  body_index += 1
7455
8137
  end
7456
8138
 
7457
- body.insert(body_index, comment)
8139
+ if body_index != 0 &&
8140
+ body[body_index - 1].location.start_char < location.start_char &&
8141
+ body[body_index - 1].location.end_char > location.start_char
8142
+ # The previous node entirely encapsules the comment, so we don't
8143
+ # want to attach it here since it will get attached normally. This
8144
+ # is mostly in the case of hash and array literals.
8145
+ comment_index += 1
8146
+ else
8147
+ parser_comments.delete_at(comment_index)
8148
+ body.insert(body_index, comment)
8149
+ end
7458
8150
  else
7459
8151
  comment_index += 1
7460
8152
  end
@@ -7485,8 +8177,8 @@ module SyntaxTree
7485
8177
  end
7486
8178
 
7487
8179
  alias deconstruct child_nodes
7488
-
7489
- def deconstruct_keys(keys)
8180
+
8181
+ def deconstruct_keys(_keys)
7490
8182
  { parts: parts, location: location }
7491
8183
  end
7492
8184
  end
@@ -7524,14 +8216,14 @@ module SyntaxTree
7524
8216
 
7525
8217
  alias deconstruct child_nodes
7526
8218
 
7527
- def deconstruct_keys(keys)
8219
+ def deconstruct_keys(_keys)
7528
8220
  { left: left, right: right, location: location, comments: comments }
7529
8221
  end
7530
8222
 
7531
8223
  def format(q)
7532
8224
  q.group do
7533
8225
  q.format(left)
7534
- q.text(' \\')
8226
+ q.text(" \\")
7535
8227
  q.indent do
7536
8228
  q.breakable(force: true)
7537
8229
  q.format(right)
@@ -7569,7 +8261,7 @@ module SyntaxTree
7569
8261
 
7570
8262
  alias deconstruct child_nodes
7571
8263
 
7572
- def deconstruct_keys(keys)
8264
+ def deconstruct_keys(_keys)
7573
8265
  { variable: variable, location: location, comments: comments }
7574
8266
  end
7575
8267
 
@@ -7609,7 +8301,7 @@ module SyntaxTree
7609
8301
 
7610
8302
  alias deconstruct child_nodes
7611
8303
 
7612
- def deconstruct_keys(keys)
8304
+ def deconstruct_keys(_keys)
7613
8305
  { statements: statements, location: location, comments: comments }
7614
8306
  end
7615
8307
 
@@ -7667,7 +8359,7 @@ module SyntaxTree
7667
8359
 
7668
8360
  alias deconstruct child_nodes
7669
8361
 
7670
- def deconstruct_keys(keys)
8362
+ def deconstruct_keys(_keys)
7671
8363
  { parts: parts, quote: quote, location: location, comments: comments }
7672
8364
  end
7673
8365
 
@@ -7730,7 +8422,7 @@ module SyntaxTree
7730
8422
 
7731
8423
  alias deconstruct child_nodes
7732
8424
 
7733
- def deconstruct_keys(keys)
8425
+ def deconstruct_keys(_keys)
7734
8426
  { arguments: arguments, location: location, comments: comments }
7735
8427
  end
7736
8428
 
@@ -7782,8 +8474,8 @@ module SyntaxTree
7782
8474
  end
7783
8475
 
7784
8476
  alias deconstruct child_nodes
7785
-
7786
- def deconstruct_keys(keys)
8477
+
8478
+ def deconstruct_keys(_keys)
7787
8479
  { value: value, location: location }
7788
8480
  end
7789
8481
  end
@@ -7812,8 +8504,8 @@ module SyntaxTree
7812
8504
  end
7813
8505
 
7814
8506
  alias deconstruct child_nodes
7815
-
7816
- def deconstruct_keys(keys)
8507
+
8508
+ def deconstruct_keys(_keys)
7817
8509
  { value: value, location: location }
7818
8510
  end
7819
8511
  end
@@ -7847,7 +8539,7 @@ module SyntaxTree
7847
8539
 
7848
8540
  alias deconstruct child_nodes
7849
8541
 
7850
- def deconstruct_keys(keys)
8542
+ def deconstruct_keys(_keys)
7851
8543
  { value: value, location: location, comments: comments }
7852
8544
  end
7853
8545
 
@@ -7888,7 +8580,7 @@ module SyntaxTree
7888
8580
 
7889
8581
  alias deconstruct child_nodes
7890
8582
 
7891
- def deconstruct_keys(keys)
8583
+ def deconstruct_keys(_keys)
7892
8584
  {
7893
8585
  beginning: beginning,
7894
8586
  elements: elements,
@@ -7943,8 +8635,8 @@ module SyntaxTree
7943
8635
  end
7944
8636
 
7945
8637
  alias deconstruct child_nodes
7946
-
7947
- def deconstruct_keys(keys)
8638
+
8639
+ def deconstruct_keys(_keys)
7948
8640
  { value: value, location: location }
7949
8641
  end
7950
8642
  end
@@ -7972,8 +8664,8 @@ module SyntaxTree
7972
8664
  end
7973
8665
 
7974
8666
  alias deconstruct child_nodes
7975
-
7976
- def deconstruct_keys(keys)
8667
+
8668
+ def deconstruct_keys(_keys)
7977
8669
  { value: value, location: location }
7978
8670
  end
7979
8671
  end
@@ -8002,8 +8694,8 @@ module SyntaxTree
8002
8694
  end
8003
8695
 
8004
8696
  alias deconstruct child_nodes
8005
-
8006
- def deconstruct_keys(keys)
8697
+
8698
+ def deconstruct_keys(_keys)
8007
8699
  { value: value, location: location }
8008
8700
  end
8009
8701
  end
@@ -8037,7 +8729,7 @@ module SyntaxTree
8037
8729
 
8038
8730
  alias deconstruct child_nodes
8039
8731
 
8040
- def deconstruct_keys(keys)
8732
+ def deconstruct_keys(_keys)
8041
8733
  { constant: constant, location: location, comments: comments }
8042
8734
  end
8043
8735
 
@@ -8075,7 +8767,7 @@ module SyntaxTree
8075
8767
 
8076
8768
  alias deconstruct child_nodes
8077
8769
 
8078
- def deconstruct_keys(keys)
8770
+ def deconstruct_keys(_keys)
8079
8771
  { constant: constant, location: location, comments: comments }
8080
8772
  end
8081
8773
 
@@ -8113,8 +8805,8 @@ module SyntaxTree
8113
8805
  end
8114
8806
 
8115
8807
  alias deconstruct child_nodes
8116
-
8117
- def deconstruct_keys(keys)
8808
+
8809
+ def deconstruct_keys(_keys)
8118
8810
  { value: value, location: location }
8119
8811
  end
8120
8812
  end
@@ -8154,7 +8846,7 @@ module SyntaxTree
8154
8846
 
8155
8847
  alias deconstruct child_nodes
8156
8848
 
8157
- def deconstruct_keys(keys)
8849
+ def deconstruct_keys(_keys)
8158
8850
  { value: value, location: location, comments: comments }
8159
8851
  end
8160
8852
 
@@ -8191,8 +8883,8 @@ module SyntaxTree
8191
8883
  end
8192
8884
 
8193
8885
  alias deconstruct child_nodes
8194
-
8195
- def deconstruct_keys(keys)
8886
+
8887
+ def deconstruct_keys(_keys)
8196
8888
  { value: value, location: location }
8197
8889
  end
8198
8890
  end
@@ -8228,7 +8920,7 @@ module SyntaxTree
8228
8920
 
8229
8921
  alias deconstruct child_nodes
8230
8922
 
8231
- def deconstruct_keys(keys)
8923
+ def deconstruct_keys(_keys)
8232
8924
  {
8233
8925
  statement: statement,
8234
8926
  parentheses: parentheses,
@@ -8238,9 +8930,28 @@ module SyntaxTree
8238
8930
  end
8239
8931
 
8240
8932
  def format(q)
8241
- q.text(parentheses ? "not(" : "not ")
8933
+ parent = q.parents.take(2)[1]
8934
+ ternary =
8935
+ (parent.is_a?(If) || parent.is_a?(Unless)) &&
8936
+ Ternaryable.call(q, parent)
8937
+
8938
+ q.text("not")
8939
+
8940
+ if parentheses
8941
+ q.text("(")
8942
+ elsif ternary
8943
+ q.if_break { q.text(" ") }.if_flat { q.text("(") }
8944
+ else
8945
+ q.text(" ")
8946
+ end
8947
+
8242
8948
  q.format(statement) if statement
8243
- q.text(")") if parentheses
8949
+
8950
+ if parentheses
8951
+ q.text(")")
8952
+ elsif ternary
8953
+ q.if_flat { q.text(")") }
8954
+ end
8244
8955
  end
8245
8956
  end
8246
8957
 
@@ -8276,7 +8987,7 @@ module SyntaxTree
8276
8987
 
8277
8988
  alias deconstruct child_nodes
8278
8989
 
8279
- def deconstruct_keys(keys)
8990
+ def deconstruct_keys(_keys)
8280
8991
  {
8281
8992
  operator: operator,
8282
8993
  statement: statement,
@@ -8296,6 +9007,9 @@ module SyntaxTree
8296
9007
  # undef method
8297
9008
  #
8298
9009
  class Undef < Node
9010
+ # Undef accepts a variable number of arguments that can be either DynaSymbol
9011
+ # or SymbolLiteral objects. For SymbolLiteral objects we descend directly
9012
+ # into the value in order to have it come out as bare words.
8299
9013
  class UndefArgumentFormatter
8300
9014
  # [DynaSymbol | SymbolLiteral] the symbol to undefine
8301
9015
  attr_reader :node
@@ -8339,7 +9053,7 @@ module SyntaxTree
8339
9053
 
8340
9054
  alias deconstruct child_nodes
8341
9055
 
8342
- def deconstruct_keys(keys)
9056
+ def deconstruct_keys(_keys)
8343
9057
  { symbols: symbols, location: location, comments: comments }
8344
9058
  end
8345
9059
 
@@ -8398,7 +9112,7 @@ module SyntaxTree
8398
9112
 
8399
9113
  alias deconstruct child_nodes
8400
9114
 
8401
- def deconstruct_keys(keys)
9115
+ def deconstruct_keys(_keys)
8402
9116
  {
8403
9117
  predicate: predicate,
8404
9118
  statements: statements,
@@ -8444,7 +9158,7 @@ module SyntaxTree
8444
9158
 
8445
9159
  alias deconstruct child_nodes
8446
9160
 
8447
- def deconstruct_keys(keys)
9161
+ def deconstruct_keys(_keys)
8448
9162
  {
8449
9163
  statement: statement,
8450
9164
  predicate: predicate,
@@ -8483,13 +9197,15 @@ module SyntaxTree
8483
9197
  end
8484
9198
 
8485
9199
  q.group do
8486
- q.if_break { format_break(q) }.if_flat do
8487
- Parentheses.flat(q) do
8488
- q.format(statements)
8489
- q.text(" #{keyword} ")
8490
- q.format(node.predicate)
9200
+ q
9201
+ .if_break { format_break(q) }
9202
+ .if_flat do
9203
+ Parentheses.flat(q) do
9204
+ q.format(statements)
9205
+ q.text(" #{keyword} ")
9206
+ q.format(node.predicate)
9207
+ end
8491
9208
  end
8492
- end
8493
9209
  end
8494
9210
  end
8495
9211
 
@@ -8539,7 +9255,7 @@ module SyntaxTree
8539
9255
 
8540
9256
  alias deconstruct child_nodes
8541
9257
 
8542
- def deconstruct_keys(keys)
9258
+ def deconstruct_keys(_keys)
8543
9259
  {
8544
9260
  predicate: predicate,
8545
9261
  statements: statements,
@@ -8595,7 +9311,7 @@ module SyntaxTree
8595
9311
 
8596
9312
  alias deconstruct child_nodes
8597
9313
 
8598
- def deconstruct_keys(keys)
9314
+ def deconstruct_keys(_keys)
8599
9315
  {
8600
9316
  statement: statement,
8601
9317
  predicate: predicate,
@@ -8661,7 +9377,7 @@ module SyntaxTree
8661
9377
 
8662
9378
  alias deconstruct child_nodes
8663
9379
 
8664
- def deconstruct_keys(keys)
9380
+ def deconstruct_keys(_keys)
8665
9381
  { left: left, right: right, location: location, comments: comments }
8666
9382
  end
8667
9383
 
@@ -8704,7 +9420,7 @@ module SyntaxTree
8704
9420
 
8705
9421
  alias deconstruct child_nodes
8706
9422
 
8707
- def deconstruct_keys(keys)
9423
+ def deconstruct_keys(_keys)
8708
9424
  { value: value, location: location, comments: comments }
8709
9425
  end
8710
9426
 
@@ -8748,7 +9464,7 @@ module SyntaxTree
8748
9464
 
8749
9465
  alias deconstruct child_nodes
8750
9466
 
8751
- def deconstruct_keys(keys)
9467
+ def deconstruct_keys(_keys)
8752
9468
  { value: value, location: location, comments: comments }
8753
9469
  end
8754
9470
 
@@ -8789,7 +9505,7 @@ module SyntaxTree
8789
9505
 
8790
9506
  alias deconstruct child_nodes
8791
9507
 
8792
- def deconstruct_keys(keys)
9508
+ def deconstruct_keys(_keys)
8793
9509
  { value: value, location: location, comments: comments }
8794
9510
  end
8795
9511
 
@@ -8829,7 +9545,7 @@ module SyntaxTree
8829
9545
 
8830
9546
  alias deconstruct child_nodes
8831
9547
 
8832
- def deconstruct_keys(keys)
9548
+ def deconstruct_keys(_keys)
8833
9549
  { value: value, location: location, comments: comments }
8834
9550
  end
8835
9551
 
@@ -8864,7 +9580,7 @@ module SyntaxTree
8864
9580
 
8865
9581
  alias deconstruct child_nodes
8866
9582
 
8867
- def deconstruct_keys(keys)
9583
+ def deconstruct_keys(_keys)
8868
9584
  { location: location, comments: comments }
8869
9585
  end
8870
9586
 
@@ -8915,7 +9631,7 @@ module SyntaxTree
8915
9631
 
8916
9632
  alias deconstruct child_nodes
8917
9633
 
8918
- def deconstruct_keys(keys)
9634
+ def deconstruct_keys(_keys)
8919
9635
  {
8920
9636
  arguments: arguments,
8921
9637
  statements: statements,
@@ -8996,7 +9712,7 @@ module SyntaxTree
8996
9712
 
8997
9713
  alias deconstruct child_nodes
8998
9714
 
8999
- def deconstruct_keys(keys)
9715
+ def deconstruct_keys(_keys)
9000
9716
  {
9001
9717
  predicate: predicate,
9002
9718
  statements: statements,
@@ -9052,7 +9768,7 @@ module SyntaxTree
9052
9768
 
9053
9769
  alias deconstruct child_nodes
9054
9770
 
9055
- def deconstruct_keys(keys)
9771
+ def deconstruct_keys(_keys)
9056
9772
  {
9057
9773
  statement: statement,
9058
9774
  predicate: predicate,
@@ -9121,7 +9837,7 @@ module SyntaxTree
9121
9837
 
9122
9838
  alias deconstruct child_nodes
9123
9839
 
9124
- def deconstruct_keys(keys)
9840
+ def deconstruct_keys(_keys)
9125
9841
  { parts: parts, location: location, comments: comments }
9126
9842
  end
9127
9843
 
@@ -9161,7 +9877,7 @@ module SyntaxTree
9161
9877
 
9162
9878
  alias deconstruct child_nodes
9163
9879
 
9164
- def deconstruct_keys(keys)
9880
+ def deconstruct_keys(_keys)
9165
9881
  {
9166
9882
  beginning: beginning,
9167
9883
  elements: elements,
@@ -9216,8 +9932,8 @@ module SyntaxTree
9216
9932
  end
9217
9933
 
9218
9934
  alias deconstruct child_nodes
9219
-
9220
- def deconstruct_keys(keys)
9935
+
9936
+ def deconstruct_keys(_keys)
9221
9937
  { value: value, location: location }
9222
9938
  end
9223
9939
  end
@@ -9245,8 +9961,8 @@ module SyntaxTree
9245
9961
  end
9246
9962
 
9247
9963
  alias deconstruct child_nodes
9248
-
9249
- def deconstruct_keys(keys)
9964
+
9965
+ def deconstruct_keys(_keys)
9250
9966
  { parts: parts, location: location }
9251
9967
  end
9252
9968
  end
@@ -9279,7 +9995,7 @@ module SyntaxTree
9279
9995
 
9280
9996
  alias deconstruct child_nodes
9281
9997
 
9282
- def deconstruct_keys(keys)
9998
+ def deconstruct_keys(_keys)
9283
9999
  { parts: parts, location: location, comments: comments }
9284
10000
  end
9285
10001
 
@@ -9317,7 +10033,7 @@ module SyntaxTree
9317
10033
 
9318
10034
  alias deconstruct child_nodes
9319
10035
 
9320
- def deconstruct_keys(keys)
10036
+ def deconstruct_keys(_keys)
9321
10037
  { arguments: arguments, location: location, comments: comments }
9322
10038
  end
9323
10039
 
@@ -9367,7 +10083,7 @@ module SyntaxTree
9367
10083
 
9368
10084
  alias deconstruct child_nodes
9369
10085
 
9370
- def deconstruct_keys(keys)
10086
+ def deconstruct_keys(_keys)
9371
10087
  { value: value, location: location, comments: comments }
9372
10088
  end
9373
10089
 
@@ -9403,7 +10119,7 @@ module SyntaxTree
9403
10119
 
9404
10120
  alias deconstruct child_nodes
9405
10121
 
9406
- def deconstruct_keys(keys)
10122
+ def deconstruct_keys(_keys)
9407
10123
  { value: value, location: location, comments: comments }
9408
10124
  end
9409
10125