@@ -2298,10 +2298,15 @@ def format_arguments(q, opening, closing)
2298
2298
2299
2299
def skip_parens? ( node )
2300
2300
case node
2301
- in FloatLiteral | Imaginary | Int | RationalLiteral
2302
- true
2303
- in VarRef [ value : Const | CVar | GVar | IVar | Kw ]
2301
+ when FloatLiteral , Imaginary , Int , RationalLiteral
2304
2302
true
2303
+ when VarRef
2304
+ case node . value
2305
+ when Const , CVar , GVar , IVar , Kw
2306
+ true
2307
+ else
2308
+ false
2309
+ end
2305
2310
else
2306
2311
false
2307
2312
end
@@ -2364,8 +2369,14 @@ def comments
2364
2369
2365
2370
def format ( q )
2366
2371
case operator
2367
- in :"::" | Op [ value : "::" ]
2372
+ when :"::"
2368
2373
q . text ( "." )
2374
+ when Op
2375
+ if operator . value == "::"
2376
+ q . text ( "." )
2377
+ else
2378
+ operator . format ( q )
2379
+ end
2369
2380
else
2370
2381
operator . format ( q )
2371
2382
end
@@ -2401,13 +2412,18 @@ def format(q)
2401
2412
# First, walk down the chain until we get to the point where we're not
2402
2413
# longer at a chainable node.
2403
2414
loop do
2404
- case children . last
2405
- in Call [ receiver : Call ]
2406
- children << children . last . receiver
2407
- in Call [ receiver : MethodAddBlock [ call : Call ] ]
2408
- children << children . last . receiver
2409
- in MethodAddBlock [ call : Call ]
2410
- children << children . last . call
2415
+ case ( child = children . last )
2416
+ when Call
2417
+ case ( receiver = child . receiver )
2418
+ when Call
2419
+ children << receiver
2420
+ when MethodAddBlock
2421
+ receiver . call . is_a? ( Call ) ? children << receiver : break
2422
+ else
2423
+ break
2424
+ end
2425
+ when MethodAddBlock
2426
+ child . call . is_a? ( Call ) ? children << child . call : break
2411
2427
else
2412
2428
break
2413
2429
end
@@ -2426,10 +2442,8 @@ def format(q)
2426
2442
# nodes.
2427
2443
parent = parents [ 3 ] if parent . is_a? ( DoBlock )
2428
2444
2429
- case parent
2430
- in MethodAddBlock [ call : FCall [ value : { value : "sig" } ] ]
2445
+ if parent . is_a? ( MethodAddBlock ) && parent . call . is_a? ( FCall ) && parent . call . value . value == "sig"
2431
2446
threshold = 2
2432
- else
2433
2447
end
2434
2448
end
2435
2449
@@ -2472,20 +2486,17 @@ def format_chain(q, children)
2472
2486
skip_operator = false
2473
2487
2474
2488
while ( child = children . pop )
2475
- case child
2476
- in Call [
2477
- receiver : Call [ message : { value : "where" } ] ,
2478
- message : { value : "not" }
2479
- ]
2480
- # This is very specialized behavior wherein we group
2481
- # .where.not calls together because it looks better. For more
2482
- # information, see
2483
- # https://github.com/prettier/plugin-ruby/issues/862.
2484
- in Call
2485
- # If we're at a Call node and not a MethodAddBlock node in the
2486
- # chain then we're going to add a newline so it indents properly.
2487
- q . breakable_empty
2488
- else
2489
+ if child . is_a? ( Call )
2490
+ if child . receiver . is_a? ( Call ) && child . receiver . message . value == "where" && child . message . value == "not"
2491
+ # This is very specialized behavior wherein we group
2492
+ # .where.not calls together because it looks better. For more
2493
+ # information, see
2494
+ # https://github.com/prettier/plugin-ruby/issues/862.
2495
+ else
2496
+ # If we're at a Call node and not a MethodAddBlock node in the
2497
+ # chain then we're going to add a newline so it indents properly.
2498
+ q . breakable_empty
2499
+ end
2489
2500
end
2490
2501
2491
2502
format_child (
@@ -2498,9 +2509,9 @@ def format_chain(q, children)
2498
2509
2499
2510
# If the parent call node has a comment on the message then we need
2500
2511
# to print the operator trailing in order to keep it working.
2501
- case children . last
2502
- in Call [ message : { comments : [ _ , * ] } , operator : ]
2503
- q . format ( CallOperatorFormatter . new ( operator ) )
2512
+ last_child = children . last
2513
+ if last_child . is_a? ( Call ) && last_child . message . comments . any?
2514
+ q . format ( CallOperatorFormatter . new ( last_child . operator ) )
2504
2515
skip_operator = true
2505
2516
else
2506
2517
skip_operator = false
@@ -2515,18 +2526,22 @@ def format_chain(q, children)
2515
2526
2516
2527
if empty_except_last
2517
2528
case node
2518
- in Call
2529
+ when Call
2519
2530
node . format_arguments ( q )
2520
- in MethodAddBlock [ block : ]
2521
- q . format ( block )
2531
+ when MethodAddBlock
2532
+ q . format ( node . block )
2522
2533
end
2523
2534
end
2524
2535
end
2525
2536
2526
2537
def self . chained? ( node )
2538
+ return false if ENV [ "STREE_FAST_FORMAT" ]
2539
+
2527
2540
case node
2528
- in Call | MethodAddBlock [ call : Call ]
2541
+ when Call
2529
2542
true
2543
+ when MethodAddBlock
2544
+ node . call . is_a? ( Call )
2530
2545
else
2531
2546
false
2532
2547
end
@@ -2538,9 +2553,12 @@ def self.chained?(node)
2538
2553
# want to indent the first call. So we'll pop off the first children and
2539
2554
# format it separately here.
2540
2555
def attach_directly? ( node )
2541
- [ ArrayLiteral , HashLiteral , Heredoc , If , Unless , XStringLiteral ] . include? (
2542
- node . receiver . class
2543
- )
2556
+ case node . receiver
2557
+ when ArrayLiteral , HashLiteral , Heredoc , If , Unless , XStringLiteral
2558
+ true
2559
+ else
2560
+ false
2561
+ end
2544
2562
end
2545
2563
2546
2564
def format_child (
@@ -2552,15 +2570,15 @@ def format_child(
2552
2570
)
2553
2571
# First, format the actual contents of the child.
2554
2572
case child
2555
- in Call
2573
+ when Call
2556
2574
q . group do
2557
2575
unless skip_operator
2558
2576
q . format ( CallOperatorFormatter . new ( child . operator ) )
2559
2577
end
2560
2578
q . format ( child . message ) if child . message != :call
2561
2579
child . format_arguments ( q ) unless skip_attached
2562
2580
end
2563
- in MethodAddBlock
2581
+ when MethodAddBlock
2564
2582
q . format ( child . block ) unless skip_attached
2565
2583
end
2566
2584
@@ -2643,9 +2661,7 @@ def format(q)
2643
2661
# If we're at the top of a call chain, then we're going to do some
2644
2662
# specialized printing in case we can print it nicely. We _only_ do this
2645
2663
# at the top of the chain to avoid weird recursion issues.
2646
- if !ENV [ "STREE_SKIP_CALL_CHAIN" ] &&
2647
- !CallChainFormatter . chained? ( q . parent ) &&
2648
- CallChainFormatter . chained? ( receiver )
2664
+ if CallChainFormatter . chained? ( receiver ) && !CallChainFormatter . chained? ( q . parent )
2649
2665
q . group do
2650
2666
q
2651
2667
. if_break { CallChainFormatter . new ( self ) . format ( q ) }
@@ -2658,9 +2674,9 @@ def format(q)
2658
2674
2659
2675
def format_arguments ( q )
2660
2676
case arguments
2661
- in ArgParen
2677
+ when ArgParen
2662
2678
q . format ( arguments )
2663
- in Args
2679
+ when Args
2664
2680
q . text ( " " )
2665
2681
q . format ( arguments )
2666
2682
else
@@ -2821,7 +2837,7 @@ def format(q)
2821
2837
q . format ( operator )
2822
2838
2823
2839
case pattern
2824
- in AryPtn | FndPtn | HshPtn
2840
+ when AryPtn , FndPtn , HshPtn
2825
2841
q . text ( " " )
2826
2842
q . format ( pattern )
2827
2843
else
@@ -5286,28 +5302,35 @@ def self.call(parent)
5286
5302
module Ternaryable
5287
5303
class << self
5288
5304
def call ( q , node )
5289
- case q . parents . take ( 2 ) [ 1 ]
5290
- in Paren [ contents : Statements [ body : [ node ] ] ]
5291
- # If this is a conditional inside of a parentheses as the only
5292
- # content, then we don't want to transform it into a ternary.
5293
- # Presumably the user wanted it to be an explicit conditional because
5294
- # there are parentheses around it. So we'll just leave it in place.
5295
- false
5296
- else
5297
- # Otherwise, we're going to check the conditional for certain cases.
5298
- case node
5299
- in predicate : Assign | Command | CommandCall | MAssign | OpAssign
5300
- false
5301
- in predicate : Not [ parentheses : false ]
5302
- false
5303
- in {
5304
- statements : { body : [ truthy ] } ,
5305
- consequent : Else [ statements : { body : [ falsy ] } ] }
5306
- ternaryable? ( truthy ) && ternaryable? ( falsy )
5307
- else
5308
- false
5309
- end
5305
+ return false if ENV [ "STREE_FAST_FORMAT" ]
5306
+
5307
+ # If this is a conditional inside of a parentheses as the only content,
5308
+ # then we don't want to transform it into a ternary. Presumably the user
5309
+ # wanted it to be an explicit conditional because there are parentheses
5310
+ # around it. So we'll just leave it in place.
5311
+ grandparent = q . grandparent
5312
+ if grandparent . is_a? ( Paren ) && ( body = grandparent . contents . body ) && body . length == 1 && body . first == node
5313
+ return false
5314
+ end
5315
+
5316
+ # Otherwise, we'll check the type of predicate. For certain nodes we
5317
+ # want to force it to not be a ternary, like if the predicate is an
5318
+ # assignment because it's hard to read.
5319
+ case node . predicate
5320
+ when Assign , Command , CommandCall , MAssign , OpAssign
5321
+ return false
5322
+ when Not
5323
+ return false unless node . predicate . parentheses?
5310
5324
end
5325
+
5326
+ # If there's no Else, then this can't be represented as a ternary.
5327
+ return false unless node . consequent . is_a? ( Else )
5328
+
5329
+ truthy_body = node . statements . body
5330
+ falsy_body = node . consequent . statements . body
5331
+
5332
+ ( truthy_body . length == 1 ) && ternaryable? ( truthy_body . first ) &&
5333
+ ( falsy_body . length == 1 ) && ternaryable? ( falsy_body . first )
5311
5334
end
5312
5335
5313
5336
private
@@ -5316,24 +5339,23 @@ def call(q, node)
5316
5339
# parentheses around them. In this case we say they cannot be ternaried
5317
5340
# and default instead to breaking them into multiple lines.
5318
5341
def ternaryable? ( statement )
5319
- # This is a list of nodes that should not be allowed to be a part of a
5320
- # ternary clause.
5321
- no_ternary = [
5322
- Alias , Assign , Break , Command , CommandCall , Heredoc , If , IfMod , IfOp ,
5342
+ case statement
5343
+ when Alias , Assign , Break , Command , CommandCall , Heredoc , If , IfMod , IfOp ,
5323
5344
Lambda , MAssign , Next , OpAssign , RescueMod , Return , Return0 , Super ,
5324
5345
Undef , Unless , UnlessMod , Until , UntilMod , VarAlias , VoidStmt , While ,
5325
5346
WhileMod , Yield , Yield0 , ZSuper
5326
- ]
5327
-
5328
- # Here we're going to check that the only statement inside the
5329
- # statements node is no a part of our denied list of nodes that can be
5330
- # ternaries.
5331
- #
5332
- # If the user is using one of the lower precedence "and" or "or"
5333
- # operators, then we can't use a ternary expression as it would break
5334
- # the flow control.
5335
- !no_ternary . include? ( statement . class ) &&
5336
- !( statement . is_a? ( Binary ) && %i[ and or ] . include? ( statement . operator ) )
5347
+ # This is a list of nodes that should not be allowed to be a part of a
5348
+ # ternary clause.
5349
+ false
5350
+ when Binary
5351
+ # If the user is using one of the lower precedence "and" or "or"
5352
+ # operators, then we can't use a ternary expression as it would break
5353
+ # the flow control.
5354
+ operator = statement . operator
5355
+ operator != "and" && operator != "or"
5356
+ else
5357
+ true
5358
+ end
5337
5359
end
5338
5360
end
5339
5361
end
@@ -5453,8 +5475,11 @@ def format_ternary(q)
5453
5475
end
5454
5476
5455
5477
def contains_conditional?
5456
- case node
5457
- in statements : { body : [ If | IfMod | IfOp | Unless | UnlessMod ] }
5478
+ statements = node . statements . body
5479
+ return false if statements . length != 1
5480
+
5481
+ case statements . first
5482
+ when If , IfMod , IfOp , Unless , UnlessMod
5458
5483
true
5459
5484
else
5460
5485
false
@@ -6410,9 +6435,7 @@ def format(q)
6410
6435
# If we're at the top of a call chain, then we're going to do some
6411
6436
# specialized printing in case we can print it nicely. We _only_ do this
6412
6437
# at the top of the chain to avoid weird recursion issues.
6413
- if !ENV [ "STREE_SKIP_CALL_CHAIN" ] &&
6414
- !CallChainFormatter . chained? ( q . parent ) &&
6415
- CallChainFormatter . chained? ( call )
6438
+ if CallChainFormatter . chained? ( call ) && !CallChainFormatter . chained? ( q . parent )
6416
6439
q . group do
6417
6440
q
6418
6441
. if_break { CallChainFormatter . new ( self ) . format ( q ) }
@@ -9122,6 +9145,7 @@ class Not < Node
9122
9145
9123
9146
# [boolean] whether or not parentheses were used
9124
9147
attr_reader :parentheses
9148
+ alias parentheses? parentheses
9125
9149
9126
9150
# [Array[ Comment | EmbDoc ]] the comments attached to this node
9127
9151
attr_reader :comments
@@ -9160,10 +9184,10 @@ def format(q)
9160
9184
q . format ( statement ) if statement
9161
9185
q . text ( ")" )
9162
9186
else
9163
- parent = q . parents . take ( 2 ) [ 1 ]
9187
+ grandparent = q . grandparent
9164
9188
ternary =
9165
- ( parent . is_a? ( If ) || parent . is_a? ( Unless ) ) &&
9166
- Ternaryable . call ( q , parent )
9189
+ ( grandparent . is_a? ( If ) || grandparent . is_a? ( Unless ) ) &&
9190
+ Ternaryable . call ( q , grandparent )
9167
9191
9168
9192
if ternary
9169
9193
q . if_break { q . text ( " " ) } . if_flat { q . text ( "(" ) }
0 commit comments