@@ -2298,10 +2298,15 @@ def format_arguments(q, opening, closing)
22982298
22992299 def skip_parens? ( node )
23002300 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
23042302 true
2303+ when VarRef
2304+ case node . value
2305+ when Const , CVar , GVar , IVar , Kw
2306+ true
2307+ else
2308+ false
2309+ end
23052310 else
23062311 false
23072312 end
@@ -2364,8 +2369,14 @@ def comments
23642369
23652370 def format ( q )
23662371 case operator
2367- in :"::" | Op [ value : "::" ]
2372+ when :"::"
23682373 q . text ( "." )
2374+ when Op
2375+ if operator . value == "::"
2376+ q . text ( "." )
2377+ else
2378+ operator . format ( q )
2379+ end
23692380 else
23702381 operator . format ( q )
23712382 end
@@ -2401,13 +2412,18 @@ def format(q)
24012412 # First, walk down the chain until we get to the point where we're not
24022413 # longer at a chainable node.
24032414 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
24112427 else
24122428 break
24132429 end
@@ -2426,10 +2442,8 @@ def format(q)
24262442 # nodes.
24272443 parent = parents [ 3 ] if parent . is_a? ( DoBlock )
24282444
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"
24312446 threshold = 2
2432- else
24332447 end
24342448 end
24352449
@@ -2472,20 +2486,17 @@ def format_chain(q, children)
24722486 skip_operator = false
24732487
24742488 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
24892500 end
24902501
24912502 format_child (
@@ -2498,9 +2509,9 @@ def format_chain(q, children)
24982509
24992510 # If the parent call node has a comment on the message then we need
25002511 # 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 ) )
25042515 skip_operator = true
25052516 else
25062517 skip_operator = false
@@ -2515,18 +2526,22 @@ def format_chain(q, children)
25152526
25162527 if empty_except_last
25172528 case node
2518- in Call
2529+ when Call
25192530 node . format_arguments ( q )
2520- in MethodAddBlock [ block : ]
2521- q . format ( block )
2531+ when MethodAddBlock
2532+ q . format ( node . block )
25222533 end
25232534 end
25242535 end
25252536
25262537 def self . chained? ( node )
2538+ return false if ENV [ "STREE_FAST_FORMAT" ]
2539+
25272540 case node
2528- in Call | MethodAddBlock [ call : Call ]
2541+ when Call
25292542 true
2543+ when MethodAddBlock
2544+ node . call . is_a? ( Call )
25302545 else
25312546 false
25322547 end
@@ -2538,9 +2553,12 @@ def self.chained?(node)
25382553 # want to indent the first call. So we'll pop off the first children and
25392554 # format it separately here.
25402555 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
25442562 end
25452563
25462564 def format_child (
@@ -2552,15 +2570,15 @@ def format_child(
25522570 )
25532571 # First, format the actual contents of the child.
25542572 case child
2555- in Call
2573+ when Call
25562574 q . group do
25572575 unless skip_operator
25582576 q . format ( CallOperatorFormatter . new ( child . operator ) )
25592577 end
25602578 q . format ( child . message ) if child . message != :call
25612579 child . format_arguments ( q ) unless skip_attached
25622580 end
2563- in MethodAddBlock
2581+ when MethodAddBlock
25642582 q . format ( child . block ) unless skip_attached
25652583 end
25662584
@@ -2643,9 +2661,7 @@ def format(q)
26432661 # If we're at the top of a call chain, then we're going to do some
26442662 # specialized printing in case we can print it nicely. We _only_ do this
26452663 # 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 )
26492665 q . group do
26502666 q
26512667 . if_break { CallChainFormatter . new ( self ) . format ( q ) }
@@ -2658,9 +2674,9 @@ def format(q)
26582674
26592675 def format_arguments ( q )
26602676 case arguments
2661- in ArgParen
2677+ when ArgParen
26622678 q . format ( arguments )
2663- in Args
2679+ when Args
26642680 q . text ( " " )
26652681 q . format ( arguments )
26662682 else
@@ -2821,7 +2837,7 @@ def format(q)
28212837 q . format ( operator )
28222838
28232839 case pattern
2824- in AryPtn | FndPtn | HshPtn
2840+ when AryPtn , FndPtn , HshPtn
28252841 q . text ( " " )
28262842 q . format ( pattern )
28272843 else
@@ -5286,28 +5302,35 @@ def self.call(parent)
52865302 module Ternaryable
52875303 class << self
52885304 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?
53105324 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 )
53115334 end
53125335
53135336 private
@@ -5316,24 +5339,23 @@ def call(q, node)
53165339 # parentheses around them. In this case we say they cannot be ternaried
53175340 # and default instead to breaking them into multiple lines.
53185341 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 ,
53235344 Lambda , MAssign , Next , OpAssign , RescueMod , Return , Return0 , Super ,
53245345 Undef , Unless , UnlessMod , Until , UntilMod , VarAlias , VoidStmt , While ,
53255346 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
53375359 end
53385360 end
53395361 end
@@ -5453,8 +5475,11 @@ def format_ternary(q)
54535475 end
54545476
54555477 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
54585483 true
54595484 else
54605485 false
@@ -6410,9 +6435,7 @@ def format(q)
64106435 # If we're at the top of a call chain, then we're going to do some
64116436 # specialized printing in case we can print it nicely. We _only_ do this
64126437 # 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 )
64166439 q . group do
64176440 q
64186441 . if_break { CallChainFormatter . new ( self ) . format ( q ) }
@@ -9122,6 +9145,7 @@ class Not < Node
91229145
91239146 # [boolean] whether or not parentheses were used
91249147 attr_reader :parentheses
9148+ alias parentheses? parentheses
91259149
91269150 # [Array[ Comment | EmbDoc ]] the comments attached to this node
91279151 attr_reader :comments
@@ -9160,10 +9184,10 @@ def format(q)
91609184 q . format ( statement ) if statement
91619185 q . text ( ")" )
91629186 else
9163- parent = q . parents . take ( 2 ) [ 1 ]
9187+ grandparent = q . grandparent
91649188 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 )
91679191
91689192 if ternary
91699193 q . if_break { q . text ( " " ) } . if_flat { q . text ( "(" ) }
0 commit comments