def determine_end_offset(block, tokens, source, expected_matcher)
      lines = source.lines
      last_line_number = lines.length
      end_offset = nil
      tokens.reverse_each do |token|
        # Break once we're through with the last line.
        break if token[0][0] != last_line_number

        # Look for expected match to block opener
        next if token[1] != expected_matcher
        next if token[1] == :on_kw && token[2] != END_STR

        # Raise if we've already found something that looks like a block end.
        raise AmbiguousSourceError.from_proc(block) if end_offset
        # Ending offset is the position of the ending token, plus the length of
        # that token.
        end_offset = token[0][1] + token[2].length
      end
      raise AmbiguousSourceError.from_proc(block) unless end_offset
      determine_end_offset_relative_to_source(end_offset, lines.last.length)
    end
def determine_end_offset(block, tokens, source, expected_matcher)
      lines = source.lines
      last_line_number = lines.length
      end_offset = nil
      tokens.reverse_each do |token|
        # Break once we're through with the last line.
        break if token[0][0] != last_line_number

        # Look for expected match to block opener
        next if token[1] != expected_matcher
        next if token[1] == :on_kw && token[2] != END_STR

        # Raise if we've already found something that looks like a block end.
        raise AmbiguousSourceError.from_proc(block) if end_offset
        # Ending offset is the position of the ending token, plus the length of
        # that token.
        end_offset = token[0][1] + token[2].length
      end
      raise AmbiguousSourceError.from_proc(block) unless end_offset
      determine_end_offset_relative_to_source(end_offset, lines.last.length)
    end
Encapsulates the logic required to determine the offset of the end of the
 block. The end of the block is characterized by a matching curly brace
 (`}`) or the `end` keyword.