syntax_tree 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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