module SyntaxTree::Ternaryable
def call(q, node)
def call(q, node) return false if ENV["STREE_FAST_FORMAT"] || q.disable_auto_ternary? # If this is a conditional inside of a parentheses as the only content, # then we don't want to transform it into a ternary. Presumably the user # wanted it to be an explicit conditional because there are parentheses # around it. So we'll just leave it in place. grandparent = q.grandparent if grandparent.is_a?(Paren) && (body = grandparent.contents.body) && body.length == 1 && body.first == node return false end # Otherwise, we'll check the type of predicate. For certain nodes we # want to force it to not be a ternary, like if the predicate is an # assignment because it's hard to read. case node.predicate when Assign, Binary, Command, CommandCall, MAssign, OpAssign return false when Not return false unless node.predicate.parentheses? end # If there's no Else, then this can't be represented as a ternary. return false unless node.consequent.is_a?(Else) truthy_body = node.statements.body falsy_body = node.consequent.statements.body (truthy_body.length == 1) && ternaryable?(truthy_body.first) && (falsy_body.length == 1) && ternaryable?(falsy_body.first) end
def ternaryable?(statement)
parentheses around them. In this case we say they cannot be ternaried
Certain expressions cannot be reduced to a ternary without adding
def ternaryable?(statement) case statement when AliasNode, Assign, Break, Command, CommandCall, Defined, Heredoc, IfNode, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, ReturnNode, Super, Undef, UnlessNode, UntilNode, VoidStmt, WhileNode, YieldNode, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false when Binary # If the user is using one of the lower precedence "and" or "or" # operators, then we can't use a ternary expression as it would break # the flow control. operator = statement.operator operator != :and && operator != :or else true end end