Class: SyntaxTree::HshPtn

Inherits:
Node
  • Object
show all
Defined in:
lib/syntax_tree/node.rb

Overview

HshPtn represents matching against a hash pattern using the Ruby 2.7+ pattern matching syntax.

case value
in { key: }
end

Defined Under Namespace

Classes: KeywordFormatter, KeywordRestFormatter

Instance Attribute Summary collapse

Attributes inherited from Node

#location

Instance Method Summary collapse

Methods inherited from Node

#construct_keys, #pretty_print, #to_json

Constructor Details

#initialize(constant:, keywords:, keyword_rest:, location:, comments: []) ⇒ HshPtn

Returns a new instance of HshPtn.



5037
5038
5039
5040
5041
5042
5043
# File 'lib/syntax_tree/node.rb', line 5037

def initialize(constant:, keywords:, keyword_rest:, location:, comments: [])
  @constant = constant
  @keywords = keywords
  @keyword_rest = keyword_rest
  @location = location
  @comments = comments
end

Instance Attribute Details

#commentsObject (readonly)

Array[ Comment | EmbDoc ]

the comments attached to this node



5035
5036
5037
# File 'lib/syntax_tree/node.rb', line 5035

def comments
  @comments
end

#constantObject (readonly)

nil | untyped

the optional constant wrapper



5025
5026
5027
# File 'lib/syntax_tree/node.rb', line 5025

def constant
  @constant
end

#keyword_restObject (readonly)

nil | VarField

an optional parameter to gather up all remaining keywords



5032
5033
5034
# File 'lib/syntax_tree/node.rb', line 5032

def keyword_rest
  @keyword_rest
end

#keywordsObject (readonly)

Array[ [Label, untyped

]] the set of tuples representing the keywords

that should be matched against in the pattern



5029
5030
5031
# File 'lib/syntax_tree/node.rb', line 5029

def keywords
  @keywords
end

Instance Method Details

#accept(visitor) ⇒ Object



5045
5046
5047
# File 'lib/syntax_tree/node.rb', line 5045

def accept(visitor)
  visitor.visit_hshptn(self)
end

#child_nodesObject Also known as: deconstruct



5049
5050
5051
# File 'lib/syntax_tree/node.rb', line 5049

def child_nodes
  [constant, *keywords.flatten(1), keyword_rest]
end

#deconstruct_keys(_keys) ⇒ Object



5055
5056
5057
5058
5059
5060
5061
5062
5063
# File 'lib/syntax_tree/node.rb', line 5055

def deconstruct_keys(_keys)
  {
    constant: constant,
    keywords: keywords,
    keyword_rest: keyword_rest,
    location: location,
    comments: comments
  }
end

#format(q) ⇒ Object



5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
# File 'lib/syntax_tree/node.rb', line 5065

def format(q)
  parts = keywords.map { |(key, value)| KeywordFormatter.new(key, value) }
  parts << KeywordRestFormatter.new(keyword_rest) if keyword_rest

  nested = PATTERNS.include?(q.parent.class)
  contents = -> do
    q.group { q.seplist(parts) { |part| q.format(part, stackable: false) } }

    # If there isn't a constant, and there's a blank keyword_rest, then we
    # have an plain ** that needs to have a `then` after it in order to
    # parse correctly on the next parse.
    if !constant && keyword_rest && keyword_rest.value.nil? && !nested
      q.text(" then")
    end
  end

  # If there is a constant, we're going to format to have the constant name
  # first and then use brackets.
  if constant
    q.group do
      q.format(constant)
      q.text("[")
      q.indent do
        q.breakable("")
        contents.call
      end
      q.breakable("")
      q.text("]")
    end
    return
  end

  # If there's nothing at all, then we're going to use empty braces.
  if parts.empty?
    q.text("{}")
    return
  end

  # If there's only one pair, then we'll just print the contents provided
  # we're not inside another pattern.
  if !nested && parts.size == 1
    contents.call
    return
  end

  # Otherwise, we're going to always use braces to make it clear it's a hash
  # pattern.
  q.group do
    q.text("{")
    q.indent do
      q.breakable
      contents.call
    end

    if q.target_ruby_version < Gem::Version.new("2.7.3")
      q.text(" }")
    else
      q.breakable
      q.text("}")
    end
  end
end