Class: Parser::AST::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/synvert/core/node_ext.rb

Overview

Extend Parser::AST::Node. https://github.com/whitequark/parser/blob/master/lib/parser/ast/node.rb

Rules

Synvert compares ast nodes with key / value pairs, each ast node has multiple attributes, e.g. receiver, message and arguments, it matches only when all of key / value pairs match.

type: ‘send’, message: :include, arguments: [‘FactoryGirl::Syntax::Methods’]

Synvert does comparison based on the value type

  1. if value is a symbol, then compares ast node value as symbol, e.g. message: :include

  2. if value is a string, then compares ast node original source code, e.g. name: ‘Synvert::Application’

  3. if value is a regexp, then compares ast node original source code, e.g. message: /find_all_by_/

  4. if value is an array, then compares each ast node, e.g. arguments: [‘FactoryGirl::Syntax::Methods’]

  5. if value is nil, then check if ast node is nil, e.g. arguments: [nil]

  6. if value is true or false, then check if ast node is :true or :false, e.g. arguments: [false]

  7. if value is ast, then compare ast node directly, e.g. to_ast: Parser::CurrentRuby.parse(“self.class.serialized_attributes”)

It can also compare nested key / value pairs, like

type: ‘send’, receiver: { type: ‘send’, receiver: { type: ‘send’, message: ‘config’ }, message: ‘active_record’ }, message: ‘identity_map=’

Source Code to Ast Node https://synvert-playground.xinminlabs.com/ruby

Instance Method Summary collapse

Instance Method Details

#columnInteger

Get the column of node.

Returns:

  • (Integer)

    column.



42
43
44
# File 'lib/synvert/core/node_ext.rb', line 42

def column
  loc.expression.column
end

#filenameString

Get the file name of node.

Returns:

  • (String)

    file name.



35
36
37
# File 'lib/synvert/core/node_ext.rb', line 35

def filename
  loc.expression&.source_buffer.name
end

#lineInteger

Get the line of node.

Returns:

  • (Integer)

    line.



49
50
51
# File 'lib/synvert/core/node_ext.rb', line 49

def line
  loc.expression.line
end

#match?(rules) ⇒ Boolean

Match node with rules. It provides some additional keywords to match rules, any, contain, not, in, not_in, gt, gte, lt, lte.

Examples:

type: 'send', arguments: { any: 'Lifo::ShowExceptions' }
type: { in: ['send', 'csend'] }
type: :send, arguments: { length: { gt: 2 } }

Parameters:

  • rules (Hash)

    rules to match.

Returns:

  • (Boolean)

    true if matches.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/synvert/core/node_ext.rb', line 61

def match?(rules)
  keywords = %i[any contain not in not_in gt gte lt lte]
  flat_hash(rules).keys.all? do |multi_keys|
    last_key = multi_keys.last
    actual = keywords.include?(last_key) ? actual_value(multi_keys[0...-1]) : actual_value(multi_keys)
    expected = expected_value(rules, multi_keys)
    case last_key
    when :any, :contain
      actual.any? { |actual_value| match_value?(actual_value, expected) }
    when :not
      !match_value?(actual, expected)
    when :in
      expected.any? { |expected_value| match_value?(actual, expected_value) }
    when :not_in
      expected.all? { |expected_value| !match_value?(actual, expected_value) }
    when :gt
      actual > expected
    when :gte
      actual >= expected
    when :lt
      actual < expected
    when :lte
      actual <= expected
    else
      match_value?(actual, expected)
    end
  end
end

#strip_curly_bracesString

Strip curly braces for hash.

Examples:

node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
node.strip_curly_braces # "foo: 'bar'"

Returns:

  • (String)


95
96
97
98
99
# File 'lib/synvert/core/node_ext.rb', line 95

def strip_curly_braces
  return to_source unless type == :hash

  to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip }
end

#to_hashObject

Convert node to a hash, so that it can be converted to a json.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/synvert/core/node_ext.rb', line 166

def to_hash
  result = { type: type }
  if TYPE_CHILDREN[type]
    TYPE_CHILDREN[type].each do |key|
      value = send(key)
      result[key] =
        case value
        when Array
          value.map { |v| v.respond_to?(:to_hash) ? v.to_hash : v }
        when Parser::AST::Node
          value.to_hash
        else
          value
        end
    end
  else
    result[:children] = children.map { |c| c.respond_to?(:to_hash) ? c.to_hash : c }
  end
  result
end

#to_lambda_literalString

Convert lambda {} to -> {}

Examples:

node # s(:block, s(:send, nil, :lambda), s(:args), s(:send, nil, :foobar))
node.to_lambda_literal # "-> { foobar }"

Returns:

  • (String)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/synvert/core/node_ext.rb', line 150

def to_lambda_literal
  if type == :block && caller.type == :send && caller.receiver.nil? && caller.message == :lambda
    new_source = to_source
    if arguments.size > 1
      new_source = new_source[0...arguments.first.loc.expression.begin_pos - 2] + new_source[arguments.last.loc.expression.end_pos + 1..-1]
      new_source = new_source.sub('lambda', "->(#{arguments.map(&:to_source).join(', ')})")
    else
      new_source = new_source.sub('lambda', '->')
    end
    new_source
  else
    to_source
  end
end

#to_single_quoteString

Get single quote string.

Examples:

node # s(:str, "foobar")
node.to_single_quote # "'foobar'"

Returns:

  • (String)


117
118
119
120
121
# File 'lib/synvert/core/node_ext.rb', line 117

def to_single_quote
  return to_source unless type == :str

  "'#{to_value}'"
end

#to_stringString

Convert symbol to string.

Examples:

node # s(:sym, :foobar)
node.to_string # "foobar"

Returns:

  • (String)


139
140
141
142
143
# File 'lib/synvert/core/node_ext.rb', line 139

def to_string
  return to_source unless type == :sym

  to_value.to_s
end

#to_symbolString

Convert string to symbol.

Examples:

node # s(:str, "foobar")
node.to_symbol # ":foobar"

Returns:

  • (String)


128
129
130
131
132
# File 'lib/synvert/core/node_ext.rb', line 128

def to_symbol
  return to_source unless type == :str

  ":#{to_value}"
end

#wrap_curly_bracesString

Wrap curly braces for hash.

Examples:

node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
node.wrap_curly_braces # "{ foo: 'bar' }"

Returns:

  • (String)


106
107
108
109
110
# File 'lib/synvert/core/node_ext.rb', line 106

def wrap_curly_braces
  return to_source unless type == :hash

  "{ #{to_source} }"
end