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.



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

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.



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

def fileName
  @fileName
end

#macroStackObject (readonly)

Returns the value of attribute macroStack.



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

def macroStack
  @macroStack
end

Instance Method Details

#cleanupMacroStackObject



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

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

#closeObject



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

def close
  @stream = nil
end

#dirnameObject



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

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

#eof?Boolean

Returns:

  • (Boolean)


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

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

#error(id, message) ⇒ Object



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

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

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



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

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.



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

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.



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

def line
  return '' unless @line

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

#lineNoObject

Return the number of the currently processed line.



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

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



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

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

#readyNextLineObject



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

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



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

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