Class: Rbs::Merge::NodeWrapper

Inherits:
Ast::Merge::NodeWrapperBase
  • Object
show all
Defined in:
lib/rbs/merge/node_wrapper.rb

Overview

Wraps RBS AST nodes with a unified interface for merging.
Supports both the RBS gem’s native AST and tree-sitter-rbs nodes.

Inherits common functionality from Ast::Merge::NodeWrapperBase:

  • Source context (lines, source, comments)
  • Line info extraction
  • Basic methods: #type, #text, #signature

Adds RBS-specific functionality:

  • Backend awareness for RBS gem/tree-sitter normalization
  • Type predicates using NodeTypeNormalizer
  • Name extraction for declarations and members

Examples:

Basic usage with RBS gem

analysis = FileAnalysis.new(source)
analysis.statements.each do |wrapper|
  puts wrapper.canonical_type  # => :class, :module, etc.
  puts wrapper.name            # => "Foo", "Bar::Baz"
end

See Also:

  • Ast::Merge::NodeWrapperBase

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#backendSymbol (readonly)

Returns The backend used for parsing (:rbs or :tree_sitter).

Returns:

  • (Symbol)

    The backend used for parsing (:rbs or :tree_sitter)



52
53
54
# File 'lib/rbs/merge/node_wrapper.rb', line 52

def backend
  @backend
end

Class Method Details

.wrap(node, lines, source: nil, leading_comments: [], inline_comment: nil, backend: :rbs) ⇒ NodeWrapper?

Wrap an RBS node, returning nil for nil input.

Parameters:

  • node (Object, nil)

    RBS node to wrap (RBS::AST::* or tree-sitter node)

  • lines (Array<String>)

    Source lines for content extraction

  • source (String, nil) (defaults to: nil)

    Original source string

  • leading_comments (Array<Hash>) (defaults to: [])

    Comments before this node

  • inline_comment (Hash, nil) (defaults to: nil)

    Inline comment on the node’s line

  • backend (Symbol) (defaults to: :rbs)

    The backend used for parsing (:rbs or :tree_sitter)

Returns:

  • (NodeWrapper, nil)

    Wrapped node or nil if node is nil



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rbs/merge/node_wrapper.rb', line 37

def wrap(node, lines, source: nil, leading_comments: [], inline_comment: nil, backend: :rbs)
  return if node.nil?

  new(
    node,
    lines: lines,
    source: source,
    leading_comments: leading_comments,
    inline_comment: inline_comment,
    backend: backend,
  )
end

Instance Method Details

#alias?Boolean

Check if this is a method alias

Returns:

  • (Boolean)


150
151
152
# File 'lib/rbs/merge/node_wrapper.rb', line 150

def alias?
  canonical_type == :alias
end

#alias_new_nameString?

Get alias new name

Returns:

  • (String, nil)


342
343
344
345
346
347
348
349
350
351
# File 'lib/rbs/merge/node_wrapper.rb', line 342

def alias_new_name
  return unless alias?

  if @backend == :rbs
    @node.respond_to?(:new_name) ? @node.new_name.to_s : nil
  else
    # For tree-sitter, find the new name child
    extract_child_text("new_name") || extract_child_text("alias_name")
  end
end

#alias_old_nameString?

Get alias old name

Returns:

  • (String, nil)


355
356
357
358
359
360
361
362
363
364
# File 'lib/rbs/merge/node_wrapper.rb', line 355

def alias_old_name
  return unless alias?

  if @backend == :rbs
    @node.respond_to?(:old_name) ? @node.old_name.to_s : nil
  else
    # For tree-sitter, find the old name child
    extract_child_text("old_name") || extract_child_text("aliased_name")
  end
end

#attr?Boolean

Check if this is any kind of attribute

Returns:

  • (Boolean)


174
175
176
# File 'lib/rbs/merge/node_wrapper.rb', line 174

def attr?
  %i[attr_reader attr_writer attr_accessor].include?(canonical_type)
end

#attr_accessor?Boolean

Check if this is an attribute accessor

Returns:

  • (Boolean)


168
169
170
# File 'lib/rbs/merge/node_wrapper.rb', line 168

def attr_accessor?
  canonical_type == :attr_accessor
end

#attr_reader?Boolean

Check if this is an attribute reader

Returns:

  • (Boolean)


156
157
158
# File 'lib/rbs/merge/node_wrapper.rb', line 156

def attr_reader?
  canonical_type == :attr_reader
end

#attr_writer?Boolean

Check if this is an attribute writer

Returns:

  • (Boolean)


162
163
164
# File 'lib/rbs/merge/node_wrapper.rb', line 162

def attr_writer?
  canonical_type == :attr_writer
end

#canonical_typeSymbol

Get the canonical (normalized) type for this node

Returns:

  • (Symbol)


74
75
76
# File 'lib/rbs/merge/node_wrapper.rb', line 74

def canonical_type
  NodeTypeNormalizer.canonical_type(type, @backend)
end

#civar?Boolean

Check if this is a class instance variable

Returns:

  • (Boolean)


204
205
206
# File 'lib/rbs/merge/node_wrapper.rb', line 204

def civar?
  canonical_type == :civar
end

#class?Boolean

Check if this is a class declaration

Returns:

  • (Boolean)


108
109
110
# File 'lib/rbs/merge/node_wrapper.rb', line 108

def class?
  canonical_type == :class
end

#commentObject?

Get the associated comment for this declaration (RBS gem only)
RBS gem associates comments with declarations via the comment attribute

Returns:

  • (Object, nil)

    The comment object or nil



99
100
101
102
103
104
# File 'lib/rbs/merge/node_wrapper.rb', line 99

def comment
  return unless @backend == :rbs
  return unless @node.respond_to?(:comment)

  @node.comment
end

#constant?Boolean

Check if this is a constant declaration

Returns:

  • (Boolean)


132
133
134
# File 'lib/rbs/merge/node_wrapper.rb', line 132

def constant?
  canonical_type == :constant
end

#container?Boolean

Check if this is a container (can have children/members)

Returns:

  • (Boolean)


228
229
230
# File 'lib/rbs/merge/node_wrapper.rb', line 228

def container?
  NodeTypeNormalizer.container_type?(canonical_type)
end

#cvar?Boolean

Check if this is a class variable

Returns:

  • (Boolean)


210
211
212
# File 'lib/rbs/merge/node_wrapper.rb', line 210

def cvar?
  canonical_type == :cvar
end

#declaration?Boolean

Check if this is a declaration (class, module, interface, etc.)

Returns:

  • (Boolean)


216
217
218
# File 'lib/rbs/merge/node_wrapper.rb', line 216

def declaration?
  NodeTypeNormalizer.declaration_type?(canonical_type)
end

#end_lineInteger?

Get the end line of this node

Returns:

  • (Integer, nil)


245
246
247
248
249
250
251
252
# File 'lib/rbs/merge/node_wrapper.rb', line 245

def end_line
  if @backend == :rbs
    @node.location&.end_line
  else
    pos = @node.end_point
    pos ? pos.row + 1 : nil
  end
end

#extend?Boolean

Check if this is an extend

Returns:

  • (Boolean)


186
187
188
# File 'lib/rbs/merge/node_wrapper.rb', line 186

def extend?
  canonical_type == :extend
end

#global?Boolean

Check if this is a global variable declaration

Returns:

  • (Boolean)


138
139
140
# File 'lib/rbs/merge/node_wrapper.rb', line 138

def global?
  canonical_type == :global
end

#include?Boolean

Check if this is an include

Returns:

  • (Boolean)


180
181
182
# File 'lib/rbs/merge/node_wrapper.rb', line 180

def include?
  canonical_type == :include
end

#interface?Boolean

Check if this is an interface declaration

Returns:

  • (Boolean)


120
121
122
# File 'lib/rbs/merge/node_wrapper.rb', line 120

def interface?
  canonical_type == :interface
end

#ivar?Boolean

Check if this is an instance variable

Returns:

  • (Boolean)


198
199
200
# File 'lib/rbs/merge/node_wrapper.rb', line 198

def ivar?
  canonical_type == :ivar
end

#member?Boolean

Check if this is a member (method, attr, include, etc.)

Returns:

  • (Boolean)


222
223
224
# File 'lib/rbs/merge/node_wrapper.rb', line 222

def member?
  NodeTypeNormalizer.member_type?(canonical_type)
end

#membersArray<NodeWrapper>

Get members of this container (for class/module/interface)

Returns:



268
269
270
271
272
273
274
275
276
# File 'lib/rbs/merge/node_wrapper.rb', line 268

def members
  return [] unless container?

  if @backend == :rbs
    extract_rbs_members
  else
    extract_tree_sitter_members
  end
end

#method?Boolean

Check if this is a method definition

Returns:

  • (Boolean)


144
145
146
# File 'lib/rbs/merge/node_wrapper.rb', line 144

def method?
  canonical_type == :method
end

#method_kindSymbol?

Get method kind (instance, singleton, singleton_instance)

Returns:

  • (Symbol, nil)


324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/rbs/merge/node_wrapper.rb', line 324

def method_kind
  return unless method?

  if @backend == :rbs
    @node.respond_to?(:kind) ? @node.kind : :instance
  else
    # For tree-sitter, check if it's a singleton method
    type_str = @node.type.to_s
    if type_str.include?("singleton")
      :singleton
    else
      :instance
    end
  end
end

#module?Boolean

Check if this is a module declaration

Returns:

  • (Boolean)


114
115
116
# File 'lib/rbs/merge/node_wrapper.rb', line 114

def module?
  canonical_type == :module
end

#nameString?

Get the name of this declaration/member

Returns:

  • (String, nil)


88
89
90
91
92
93
94
# File 'lib/rbs/merge/node_wrapper.rb', line 88

def name
  if @backend == :rbs
    extract_rbs_name
  else
    extract_tree_sitter_name
  end
end

#prepend?Boolean

Check if this is a prepend

Returns:

  • (Boolean)


192
193
194
# File 'lib/rbs/merge/node_wrapper.rb', line 192

def prepend?
  canonical_type == :prepend
end

#process_additional_options(options) ⇒ Object

Process RBS-specific options (backend)

Parameters:

  • options (Hash)

    Additional options



56
57
58
# File 'lib/rbs/merge/node_wrapper.rb', line 56

def process_additional_options(options)
  @backend = options.fetch(:backend, :rbs)
end

#signatureArray?

Generate a signature for this node

Returns:

  • (Array, nil)


280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/rbs/merge/node_wrapper.rb', line 280

def signature
  case canonical_type
  when :class
    [:class, name]
  when :module
    [:module, name]
  when :interface
    [:interface, name]
  when :type_alias
    [:type_alias, name]
  when :constant
    [:constant, name]
  when :global
    [:global, name]
  when :method
    kind = method_kind
    [:method, name, kind]
  when :alias
    [:alias, alias_new_name, alias_old_name]
  when :attr_reader
    [:attr_reader, name]
  when :attr_writer
    [:attr_writer, name]
  when :attr_accessor
    [:attr_accessor, name]
  when :include
    [:include, name]
  when :extend
    [:extend, name]
  when :prepend
    [:prepend, name]
  when :ivar
    [:ivar, name]
  when :civar
    [:civar, name]
  when :cvar
    [:cvar, name]
  else
    [:unknown, canonical_type, start_line]
  end
end

#start_lineInteger?

Get the start line of this node

Returns:

  • (Integer, nil)


234
235
236
237
238
239
240
241
# File 'lib/rbs/merge/node_wrapper.rb', line 234

def start_line
  if @backend == :rbs
    @node.location&.start_line
  else
    pos = @node.start_point
    pos ? pos.row + 1 : nil
  end
end

#textString?

Get source text for this node

Returns:

  • (String, nil)


256
257
258
259
260
261
262
263
264
# File 'lib/rbs/merge/node_wrapper.rb', line 256

def text
  return unless start_line && end_line

  if @lines && start_line > 0 && end_line <= @lines.length
    @lines[(start_line - 1)..(end_line - 1)].join("\n")
  elsif @source
    @source.lines[(start_line - 1)..(end_line - 1)]&.join
  end
end

#typeSymbol

Get the raw type from the underlying node

Returns:

  • (Symbol)


62
63
64
65
66
67
68
69
70
# File 'lib/rbs/merge/node_wrapper.rb', line 62

def type
  if @backend == :rbs
    # For RBS gem, use class name as type
    @node.class.name.to_sym
  else
    # For tree-sitter, use the node's type
    @node.type.to_sym
  end
end

#type?(type_name) ⇒ Boolean

Check if this node has a specific type (checks both raw and canonical)

Parameters:

  • type_name (Symbol, String)

    Type to check

Returns:

  • (Boolean)


81
82
83
84
# File 'lib/rbs/merge/node_wrapper.rb', line 81

def type?(type_name)
  type_sym = type_name.to_sym
  type == type_sym || canonical_type == type_sym
end

#type_alias?Boolean

Check if this is a type alias declaration

Returns:

  • (Boolean)


126
127
128
# File 'lib/rbs/merge/node_wrapper.rb', line 126

def type_alias?
  canonical_type == :type_alias
end