Class: TaskJuggler::TextParser::Scanner::StreamHandle

Inherits:
Object
  • Object
show all
Defined in:
lib/taskjuggler/TextParser/Scanner.rb

Overview

This class is used to handle the low-level input operations. It knows whether it deals with a text buffer or a file and abstracts this to the Scanner. For each nested file the scanner puts a StreamHandle on the stack while the file is scanned. With this stack the scanner can resume the processing of the enclosing file once the included files have been completely processed.

Direct Known Subclasses

BufferStreamHandle, FileStreamHandle

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(log, textScanner) ⇒ StreamHandle

Returns a new instance of StreamHandle.



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 55

def initialize(log, textScanner)
  @log = log
  @textScanner = textScanner
  @fileName = nil
  @stream = nil
  @line = nil
  @endPos = 1
  @scanner = nil
  @wrapped = false
  @macroStack = []
  @nextMacroEnd = nil
end

Instance Attribute Details

#fileNameObject (readonly)

Returns the value of attribute fileName.



53
54
55
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 53

def fileName
  @fileName
end

#macroStackObject (readonly)

Returns the value of attribute macroStack.



53
54
55
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 53

def macroStack
  @macroStack
end

Instance Method Details

#cleanupMacroStackObject



125
126
127
128
129
130
131
132
133
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 125

def cleanupMacroStack
  if @nextMacroEnd
    pos = @scanner.pos
    while @nextMacroEnd && @nextMacroEnd < pos
      @macroStack.pop
      @nextMacroEnd = @macroStack.empty? ? nil : @macroStack.last.endPos
    end
  end
end

#closeObject



72
73
74
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 72

def close
  @stream = nil
end

#dirnameObject



143
144
145
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 143

def dirname
  @fileName ? File.dirname(@fileName) : ''
end

#eof?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 139

def eof?
  @stream.eof? && @scanner.eos?
end

#error(id, message) ⇒ Object



68
69
70
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 68

def error(id, message)
  @textScanner.error(id, message)
end

#injectMacro(macro, args, text, callLength) ⇒ Object



92
93
94
95
96
97
98
99
100
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 92

def injectMacro(macro, args, text, callLength)
  injectText(text, callLength)

  # Simple detection for recursive macro calls.
  return false if @macroStack.length > 20

  @macroStack << MacroStackEntry.new(macro, args, text, @nextMacroEnd)
  true
end

#injectText(text, callLength) ⇒ Object

Inject the String text into the input stream at the current cursor position.



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 78

def injectText(text, callLength)
  # Remove the macro call from the end of the already parsed input.
  preCall = @scanner.pre_match[0..-(callLength + 1)]
  # Store the end position of the inserted macro in bytes.
  @nextMacroEnd = preCall.bytesize + text.bytesize
  # Compose the new @line from the cleaned input, the injected text and
  # the remainer of the old @line.
  @line = preCall + text + @scanner.post_match
  # Start the StringScanner again at the first character of the injected
  # text.
  @scanner.string = @line
  @scanner.pos = preCall.bytesize
end

#lineObject

Return the already processed part of the current line.



158
159
160
161
162
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 158

def line
  return '' unless @line

  (@scanner.pre_match || '') + (@scanner.matched || '')
end

#lineNoObject

Return the number of the currently processed line.



148
149
150
151
152
153
154
155
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 148

def lineNo
  # The IO object counts the lines for us by counting the gets() calls.
  currentLine = @stream && @scanner ? @stream.lineno : 1
  # If we've just read the LF, we have to add 1. The LF can only be the
  # last character of the line.
  currentLine += 1 if @wrapped && @line && @scanner && @scanner.eos?
  currentLine
end

#peek(n) ⇒ Object



135
136
137
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 135

def peek(n)
  @scanner ? @scanner.peek(n) : nil
end

#readyNextLineObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 102

def readyNextLine
  # We read the file line by line with gets(). If we don't have a line
  # yet or we've reached the end of a line, we get the next one.
  if @scanner.nil? || @scanner.eos?
    if (@line = @stream.gets)
      # Update activity meter about every 1024 lines.
      @log.activity if (@stream.lineno & 0x3FF) == 0
    else
      # We've reached the end of the current file.
      @scanner = nil
      return false
    end
    @scanner = StringScanner.new(@line)
    @wrapped = @line[-1] == ?\n
  end

  true
end

#scan(re) ⇒ Object



121
122
123
# File 'lib/taskjuggler/TextParser/Scanner.rb', line 121

def scan(re)
  @scanner.scan(re)
end