Class: Markbridge::Parsers::BBCode::PeekableEnumerator

Inherits:
Object
  • Object
show all
Defined in:
lib/markbridge/parsers/bbcode/peekable_enumerator.rb

Overview

Wrapper around a scanner that allows peeking at upcoming tokens without consuming them.

This class buffers tokens pulled from a scanner (which must implement ‘next_token`) so callers can:

  • inspect the next token with #peek without advancing the scanner

  • inspect several upcoming tokens with #peek_ahead

  • consume tokens with #next

The enumerator is lazy: tokens are only requested from the scanner when needed. Once the underlying scanner returns ‘nil`, the enumerator is marked finished and further peeks return `nil` (for single peeks) or an empty array (for multi-peeks).

Examples:

Basic usage

scanner = YourScanner.new("...") # responds to `next_token`
enum = PeekableEnumerator.new(scanner)
enum.peek        # => next token (no consume)
enum.peek_ahead(3) # => array of up to 3 upcoming tokens
enum.next        # => consumes and returns next token

See Also:

Instance Method Summary collapse

Constructor Details

#initialize(scanner) ⇒ PeekableEnumerator

Initialize a new PeekableEnumerator.

Parameters:

  • scanner (Object)

    the scanner object that responds to ‘next_token`



32
33
34
35
36
# File 'lib/markbridge/parsers/bbcode/peekable_enumerator.rb', line 32

def initialize(scanner)
  @scanner = scanner
  @peeked = []
  @finished = false
end

Instance Method Details

#has_next?Boolean

Return whether more tokens are available.

This will attempt to fetch one token from the scanner if necessary to determine whether more tokens remain.

Returns:

  • (Boolean)

    ‘true` if at least one token is available



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/markbridge/parsers/bbcode/peekable_enumerator.rb', line 60

def has_next?
  return true if @peeked.any?
  return false if @finished

  value = @scanner.next_token
  if value.nil?
    @finished = true
    false
  else
    @peeked << value
    true
  end
end

#nextObject? Also known as: next_token

Consume and return the next token.

If there are tokens in the internal buffer (from prior peeks) the buffered token is returned. Otherwise, the next token is requested from the underlying scanner via ‘next_token`.

Returns:

  • (Object, nil)

    next token or ‘nil` when exhausted



45
46
47
48
49
50
51
52
# File 'lib/markbridge/parsers/bbcode/peekable_enumerator.rb', line 45

def next
  return @peeked.shift if @peeked.any?
  return nil if @finished

  value = @scanner.next_token
  @finished = true if value.nil?
  value
end

#peekObject?

Peek at the next single token without consuming it.

If the enumerator has been exhausted this returns ‘nil`.

Returns:

  • (Object, nil)

    the next token or ‘nil` when exhausted



79
80
81
82
83
84
85
# File 'lib/markbridge/parsers/bbcode/peekable_enumerator.rb', line 79

def peek
  return @peeked.first if @peeked.any?
  return nil if @finished

  ensure_peeked(1)
  @peeked.first
end

#peek_ahead(count) ⇒ Array<Object>

Peek ahead at up to ‘count` upcoming tokens without consuming them.

The method will return an array with at most ‘count` elements. If fewer tokens remain, a shorter array is returned. When the enumerator is exhausted an empty array is returned.

Parameters:

  • count (Integer)

    number of tokens to peek ahead (non-negative)

Returns:

  • (Array<Object>)

    array of upcoming tokens (possibly empty)



95
96
97
98
99
100
# File 'lib/markbridge/parsers/bbcode/peekable_enumerator.rb', line 95

def peek_ahead(count)
  return [] if count <= 0

  ensure_peeked(count)
  @peeked.take(count)
end