Class: TRuby::CodeEmitter::Ruby31

Inherits:
Base
  • Object
show all
Defined in:
lib/t_ruby/code_emitter.rb

Overview

Ruby 3.1+ emitter - supports anonymous block forwarding

Direct Known Subclasses

Ruby34

Instance Attribute Summary

Attributes inherited from Base

#version

Instance Method Summary collapse

Methods inherited from Base

#initialize, #numbered_params_error?, #supports_it?, #transform, #transform_numbered_params

Constructor Details

This class inherits a constructor from TRuby::CodeEmitter::Base

Instance Method Details

#transform_block_forwarding(source) ⇒ Object

Transform ‘def foo(&block) … bar(&block)` to `def foo(&) … bar(&)`

Only transforms when the block parameter is ONLY used for forwarding, not when it’s called directly (e.g., block.call)



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/t_ruby/code_emitter.rb', line 91

def transform_block_forwarding(source)
  result = source.dup

  # Find method definitions with block parameters
  # Pattern: def method_name(&block_name)
  result.gsub!(/def\s+(\w+[?!=]?)\s*\(([^)]*?)&(\w+)\s*\)/) do |_match|
    method_name = ::Regexp.last_match(1)
    other_params = ::Regexp.last_match(2)
    block_name = ::Regexp.last_match(3)

    # Find the method body to check block usage
    method_start = ::Regexp.last_match.begin(0)
    remaining = result[method_start..]

    # Check if block is only used for forwarding (not called directly)
    if block_only_forwarded?(remaining, block_name)
      "def #{method_name}(#{other_params}&)"
    else
      "def #{method_name}(#{other_params}&#{block_name})"
    end
  end

  # Replace block forwarding calls with anonymous forwarding
  # This is a simplified approach - in practice we'd need proper scope tracking
  result.gsub!(/(\w+)\s*\(\s*&(\w+)\s*\)/) do |match|
    call_name = ::Regexp.last_match(1)
    ::Regexp.last_match(2)

    # Check if this block name was converted to anonymous
    if result.include?("def ") && result.include?("(&)")
      "#{call_name}(&)"
    else
      match
    end
  end

  result
end