Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8932ff8

Browse files
committed
Even better chained calls
1 parent 2d9d555 commit 8932ff8

File tree

1 file changed

+90
-9
lines changed

1 file changed

+90
-9
lines changed

lib/syntax_tree/node.rb

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,68 @@ def format(q)
22052205
end
22062206
end
22072207

2208+
class CallChainFormatter
2209+
# [Call] the top of the call chain
2210+
attr_reader :node
2211+
2212+
def initialize(node)
2213+
@node = node
2214+
end
2215+
2216+
def format(q)
2217+
children = [node]
2218+
children << children.last.receiver while children.last.receiver.is_a?(Call)
2219+
q.format(children.last.receiver)
2220+
2221+
q.group do
2222+
format_child(q, children.pop) if attach_directly?(children.last)
2223+
2224+
q.indent do
2225+
children.reverse_each do |child|
2226+
case child
2227+
in { receiver: Call[message: { value: "where" }], message: { value: "not" } }
2228+
# This is very specialized behavior wherein we group
2229+
# .where.not calls together because it looks better. For more
2230+
# information, see
2231+
# https://github.com/prettier/plugin-ruby/issues/862.
2232+
else
2233+
q.breakable("")
2234+
end
2235+
2236+
format_child(q, child)
2237+
end
2238+
end
2239+
end
2240+
end
2241+
2242+
private
2243+
2244+
# For certain nodes, we want to attach directly to the end and don't
2245+
# want to indent the first call. So we'll pop off the first children and
2246+
# format it separately here.
2247+
def attach_directly?(child)
2248+
[ArrayLiteral, HashLiteral, Heredoc, If, Unless, XStringLiteral]
2249+
.include?(child.receiver.class)
2250+
end
2251+
2252+
def format_child(q, child)
2253+
q.format(CallOperatorFormatter.new(child.operator))
2254+
q.format(child.message) if child.message != :call
2255+
child.format_arguments(q)
2256+
2257+
# If there are any comments on this node then we need to explicitly print
2258+
# them out here since we're bypassing the normal comment printing.
2259+
if child.comments.any?
2260+
child.comments.each do |comment|
2261+
comment.inline? ? q.text(" ") : q.breakable
2262+
comment.format(q)
2263+
end
2264+
2265+
q.break_parent
2266+
end
2267+
end
2268+
end
2269+
22082270
# Call represents a method call.
22092271
#
22102272
# receiver.message
@@ -2270,6 +2332,33 @@ def deconstruct_keys(keys)
22702332
def format(q)
22712333
call_operator = CallOperatorFormatter.new(operator)
22722334

2335+
# If we're at the top of a call chain, then we're going to do some
2336+
# specialized printing in case we can print it nicely. We _only_ do this
2337+
# at the top of the chain to avoid weird recursion issues.
2338+
if !q.parent.is_a?(Call) && receiver.is_a?(Call)
2339+
q.group { q.if_break { CallChainFormatter.new(self).format(q) }.if_flat { format_contents(q) } }
2340+
else
2341+
format_contents(q)
2342+
end
2343+
end
2344+
2345+
def format_arguments(q)
2346+
case arguments
2347+
in ArgParen
2348+
q.format(arguments)
2349+
in Args
2350+
q.text(" ")
2351+
q.format(arguments)
2352+
else
2353+
# Do nothing if there are no arguments.
2354+
end
2355+
end
2356+
2357+
private
2358+
2359+
def format_contents(q)
2360+
call_operator = CallOperatorFormatter.new(operator)
2361+
22732362
q.group do
22742363
q.format(receiver)
22752364

@@ -2290,15 +2379,7 @@ def format(q)
22902379
q.format(message) if message != :call
22912380
end
22922381

2293-
case arguments
2294-
in ArgParen
2295-
q.format(arguments)
2296-
in Args
2297-
q.text(" ")
2298-
q.format(arguments)
2299-
else
2300-
# Do nothing if there are no arguments.
2301-
end
2382+
format_arguments(q)
23022383
end
23032384
end
23042385
end

0 commit comments

Comments
 (0)