PageTemplate 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes +24 -0
- data/MANIFEST +0 -1
- data/README.txt +10 -8
- data/Rakefile +30 -9
- data/lib/PageTemplate/case.rb +72 -0
- data/lib/PageTemplate/commands.rb +500 -0
- data/lib/PageTemplate/parser.rb +373 -0
- data/lib/PageTemplate.rb +47 -991
- data/setup-usage.txt +129 -0
- data/setup.rb +1360 -0
- data/tdata/dummy.txt +2 -0
- data/test.rb +616 -0
- metadata +13 -169
- data/CVS/Entries +0 -10
- data/CVS/Repository +0 -1
- data/CVS/Root +0 -1
- data/Changes~ +0 -7
- data/InstalledFiles +0 -7
- data/Rakefile~ +0 -54
- data/TC_PageTemplate.rb +0 -974
- data/TC_PageTemplate.rb~ +0 -965
- data/config.save +0 -12
- data/doc/classes/BlockCommand.html +0 -229
- data/doc/classes/BlockCommand.src/M000004.html +0 -18
- data/doc/classes/BlockCommand.src/M000005.html +0 -25
- data/doc/classes/BlockCommand.src/M000006.html +0 -18
- data/doc/classes/BlockCommand.src/M000007.html +0 -23
- data/doc/classes/BlockCommand.src/M000008.html +0 -24
- data/doc/classes/Command.html +0 -167
- data/doc/classes/Command.src/M000032.html +0 -19
- data/doc/classes/Command.src/M000033.html +0 -18
- data/doc/classes/CommentCommand.html +0 -146
- data/doc/classes/CommentCommand.src/M000009.html +0 -18
- data/doc/classes/IfCommand.html +0 -193
- data/doc/classes/IfCommand.src/M000042.html +0 -19
- data/doc/classes/IfCommand.src/M000043.html +0 -20
- data/doc/classes/IfCommand.src/M000044.html +0 -20
- data/doc/classes/IfElseCommand.html +0 -189
- data/doc/classes/IfElseCommand.src/M000025.html +0 -19
- data/doc/classes/IfElseCommand.src/M000026.html +0 -23
- data/doc/classes/IfElseCommand.src/M000027.html +0 -20
- data/doc/classes/IncludeCommand.html +0 -171
- data/doc/classes/IncludeCommand.src/M000019.html +0 -26
- data/doc/classes/IncludeCommand.src/M000020.html +0 -28
- data/doc/classes/IncludeCommand.src/M000021.html +0 -18
- data/doc/classes/IncludeCommandError.html +0 -118
- data/doc/classes/LoopCommand.html +0 -197
- data/doc/classes/LoopCommand.src/M000001.html +0 -19
- data/doc/classes/LoopCommand.src/M000002.html +0 -42
- data/doc/classes/LoopCommand.src/M000003.html +0 -20
- data/doc/classes/LoopElseCommand.html +0 -190
- data/doc/classes/LoopElseCommand.src/M000022.html +0 -19
- data/doc/classes/LoopElseCommand.src/M000023.html +0 -23
- data/doc/classes/LoopElseCommand.src/M000024.html +0 -20
- data/doc/classes/Namespace.html +0 -297
- data/doc/classes/Namespace.src/M000034.html +0 -19
- data/doc/classes/Namespace.src/M000035.html +0 -18
- data/doc/classes/Namespace.src/M000036.html +0 -18
- data/doc/classes/Namespace.src/M000037.html +0 -19
- data/doc/classes/Namespace.src/M000038.html +0 -36
- data/doc/classes/Namespace.src/M000039.html +0 -21
- data/doc/classes/Namespace.src/M000040.html +0 -18
- data/doc/classes/Namespace.src/M000041.html +0 -18
- data/doc/classes/PageTemplate.html +0 -380
- data/doc/classes/PageTemplate.src/M000010.html +0 -49
- data/doc/classes/PageTemplate.src/M000011.html +0 -18
- data/doc/classes/PageTemplate.src/M000012.html +0 -29
- data/doc/classes/PageTemplate.src/M000013.html +0 -18
- data/doc/classes/PageTemplate.src/M000014.html +0 -18
- data/doc/classes/PageTemplate.src/M000015.html +0 -18
- data/doc/classes/PageTemplate.src/M000016.html +0 -18
- data/doc/classes/PageTemplate.src/M000017.html +0 -18
- data/doc/classes/PageTemplate.src/M000018.html +0 -19
- data/doc/classes/Syntax/CachedParser.html +0 -163
- data/doc/classes/Syntax/CachedParser.src/M000048.html +0 -19
- data/doc/classes/Syntax/CachedParser.src/M000049.html +0 -53
- data/doc/classes/Syntax/Glossary.html +0 -251
- data/doc/classes/Syntax/Glossary.src/M000050.html +0 -20
- data/doc/classes/Syntax/Glossary.src/M000051.html +0 -29
- data/doc/classes/Syntax/Parser.html +0 -261
- data/doc/classes/Syntax/Parser.src/M000052.html +0 -22
- data/doc/classes/Syntax/Parser.src/M000053.html +0 -36
- data/doc/classes/Syntax/Parser.src/M000054.html +0 -18
- data/doc/classes/Syntax/Parser.src/M000055.html +0 -21
- data/doc/classes/Syntax/Parser.src/M000056.html +0 -53
- data/doc/classes/Syntax/Parser.src/M000057.html +0 -111
- data/doc/classes/Syntax.html +0 -139
- data/doc/classes/TextCommand.html +0 -185
- data/doc/classes/TextCommand.src/M000045.html +0 -18
- data/doc/classes/TextCommand.src/M000046.html +0 -18
- data/doc/classes/TextCommand.src/M000047.html +0 -18
- data/doc/classes/UnlessCommand.html +0 -151
- data/doc/classes/UnlessCommand.src/M000028.html +0 -20
- data/doc/classes/ValueCommand.html +0 -186
- data/doc/classes/ValueCommand.src/M000029.html +0 -18
- data/doc/classes/ValueCommand.src/M000030.html +0 -18
- data/doc/classes/ValueCommand.src/M000031.html +0 -20
- data/doc/created.rid +0 -1
- data/doc/files/README_txt.html +0 -224
- data/doc/files/lib/PageTemplate_rb.html +0 -119
- data/doc/fr_class_index.html +0 -44
- data/doc/fr_file_index.html +0 -28
- data/doc/fr_method_index.html +0 -83
- data/doc/index.html +0 -24
- data/doc/rdoc-style.css +0 -208
- data/install.rb +0 -1015
- data/lib/CVS/Entries +0 -2
- data/lib/CVS/Repository +0 -1
- data/lib/CVS/Root +0 -1
- data/lib/PageTemplate.rb~ +0 -1004
- data/pkg/PageTemplate-1.2.0.gem +0 -0
- data/tdata/CVS/Entries +0 -28
- data/tdata/CVS/Repository +0 -1
- data/tdata/CVS/Root +0 -1
- data/tdata/cm.txt +0 -3
- data/tdata/complex.txt +0 -116
- data/tdata/i1.txt +0 -1
- data/tdata/i2.txt +0 -7
- data/tdata/ib1.txt +0 -7
- data/tdata/ib2.txt +0 -13
- data/tdata/ie1.txt +0 -4
- data/tdata/ie2.txt +0 -15
- data/tdata/include.1.txt +0 -1
- data/tdata/include.2.txt +0 -1
- data/tdata/include.3.txt +0 -1
- data/tdata/include.4.nf.out.txt +0 -2
- data/tdata/include.4.out.txt +0 -3
- data/tdata/include.4.txt +0 -2
- data/tdata/include.4a.txt +0 -1
- data/tdata/include.4b.txt +0 -2
- data/tdata/include.5.txt +0 -2
- data/tdata/l1.txt +0 -5
- data/tdata/l2.txt +0 -7
- data/tdata/metadata.1.txt +0 -5
- data/tdata/metadata.2.txt +0 -5
- data/tdata/metadata.3.txt +0 -5
- data/tdata/metadata.4.txt +0 -5
- data/tdata/nm.txt +0 -4
- data/tdata/p/CVS/Entries +0 -5
- data/tdata/p/CVS/Repository +0 -1
- data/tdata/p/CVS/Root +0 -1
- data/tdata/p/CVS/b2.txt,t +0 -0
- data/tdata/p/_b1.txt +0 -0
- data/tdata/p/b1.txt +0 -4
- data/tdata/p/b2.txt +0 -4
- data/tdata/p/b2.txt~ +0 -4
- data/tdata/p/cb1.txt +0 -4
- data/tdata/t.txt +0 -2
- data/tdata/v1.txt +0 -11
- data/tdata/v2.txt +0 -11
@@ -0,0 +1,373 @@
|
|
1
|
+
# parser.rb
|
2
|
+
#
|
3
|
+
# This contains the guts of the engines that make PageTemplate work.
|
4
|
+
#
|
5
|
+
|
6
|
+
############################################################
|
7
|
+
|
8
|
+
class PageTemplate
|
9
|
+
|
10
|
+
# A Namespace object consists of three things:
|
11
|
+
#
|
12
|
+
# parent: A parent object to get a value from if the namespace
|
13
|
+
# does not 'know' a value.
|
14
|
+
#
|
15
|
+
# object: An object is a hash or list that contains the values that
|
16
|
+
# this namespace will refer to. It may also be an object, in which
|
17
|
+
# case, its methods are treated as a hash, with respond_to? and
|
18
|
+
# send()
|
19
|
+
#
|
20
|
+
# Cache: A cache ensures that a method on an object will only be
|
21
|
+
# called once.
|
22
|
+
class Namespace
|
23
|
+
attr_accessor :parent, :object
|
24
|
+
def initialize(parent=nil,object=nil)
|
25
|
+
@values = Hash.new
|
26
|
+
@parent = parent
|
27
|
+
@object = object
|
28
|
+
end
|
29
|
+
|
30
|
+
# Clears the cache
|
31
|
+
def clear_cache
|
32
|
+
@values = Hash.new
|
33
|
+
end
|
34
|
+
|
35
|
+
# Saves a variable +key+ as the string +value+ in the global
|
36
|
+
# namespace.
|
37
|
+
def set(key, value)
|
38
|
+
@values[key] = value
|
39
|
+
end
|
40
|
+
alias_method :[]=, :set
|
41
|
+
|
42
|
+
# Returns the first value found for +key+ in the nested namespaces.
|
43
|
+
# Returns nil if no value is found.
|
44
|
+
#
|
45
|
+
# Values are checked for in this order through each level of namespace:
|
46
|
+
#
|
47
|
+
# * level.key
|
48
|
+
# * level.key()
|
49
|
+
# * level[key]
|
50
|
+
#
|
51
|
+
# If a value is not found in any of the nested namespaces, get()
|
52
|
+
# searches for the key in the global namespace.
|
53
|
+
#
|
54
|
+
# If +val+ is a dot-separated list of words, then 'key' is the
|
55
|
+
# first part of it. The remainder of the words are sent to key
|
56
|
+
# (and further results) to premit accessing attributes of objects.
|
57
|
+
def get(val)
|
58
|
+
# Is it ours, or is it cached?
|
59
|
+
key, rest = val.split(/\./,2)
|
60
|
+
value = case
|
61
|
+
when @values.has_key?(key)
|
62
|
+
@values[key]
|
63
|
+
when @object.respond_to?(:has_key?) && @object.has_key?(key)
|
64
|
+
@values[key] = @object[key]
|
65
|
+
when @object && @object.respond_to?(key.to_sym)
|
66
|
+
# This sets the cache and returns the value, too!
|
67
|
+
@values[key] = @object.send(key)
|
68
|
+
when @object && key == '__ITEM__'
|
69
|
+
@object
|
70
|
+
when @parent
|
71
|
+
@parent.get(key)
|
72
|
+
else
|
73
|
+
# We're the global namespace
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
if rest
|
78
|
+
rest.split(/\./).each do |i|
|
79
|
+
begin
|
80
|
+
value = value.send(i)
|
81
|
+
rescue NoMethodError => er
|
82
|
+
return nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
value
|
87
|
+
end
|
88
|
+
alias_method :[], :get
|
89
|
+
|
90
|
+
# A convenience method to test whether a variable has a true
|
91
|
+
# value. Returns nil if +flag+ is not found in the namespace,
|
92
|
+
# or +flag+ has a nil value attached to it.
|
93
|
+
def true?(flag)
|
94
|
+
get(flag) ? true : false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# A Source is a source from which templates are drawn.
|
99
|
+
#
|
100
|
+
# Source#get(name) must return the body of the template that is to
|
101
|
+
# be parsed, or nil if it doesn't exist.
|
102
|
+
class Source
|
103
|
+
def initialize(args = {})
|
104
|
+
@args = args
|
105
|
+
end
|
106
|
+
def get(name)
|
107
|
+
name
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# FileSource provides access to files within the 'include_paths'
|
112
|
+
# argument.
|
113
|
+
#
|
114
|
+
# It attempts to be secure by not allowing any access outside of
|
115
|
+
# The directories detailed within include_paths
|
116
|
+
class FileSource < Source
|
117
|
+
attr_reader :paths
|
118
|
+
|
119
|
+
def initialize(args = {})
|
120
|
+
@args = args
|
121
|
+
@paths = @args['include_paths']
|
122
|
+
@paths ||= [@args['include_path']].compact
|
123
|
+
@paths = [Dir.getwd] if @paths.empty?
|
124
|
+
end
|
125
|
+
|
126
|
+
# Return the contents of the file +name+, which must be within the
|
127
|
+
# include_paths.
|
128
|
+
def get(name)
|
129
|
+
begin
|
130
|
+
fn = get_filename(name)
|
131
|
+
if fn
|
132
|
+
return IO.read(fn)
|
133
|
+
else
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
rescue Exception => er
|
137
|
+
return "[ Unable to open file #{fn} ]"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
def get_filename(file)
|
141
|
+
file = file.gsub(/\.\.\//,'')
|
142
|
+
file.untaint
|
143
|
+
@paths.each do |path|
|
144
|
+
fn = File.join(path,file)
|
145
|
+
return fn if File.exists?(fn)
|
146
|
+
end
|
147
|
+
return nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# This is the dictionary of commands and the directive that Parser
|
152
|
+
# uses to compile a template into a tree of commands.
|
153
|
+
#
|
154
|
+
# directive is the general format of a PageTemplate command.
|
155
|
+
# Default: /\[%(.+?)%\]/m
|
156
|
+
#
|
157
|
+
# @glossary is a hash table of regexp->Command objects. These
|
158
|
+
# regexps should not contain PageTemplate command text. i.e:
|
159
|
+
# /var \w+/i should be used instead of /[% var %]/
|
160
|
+
class SyntaxGlossary
|
161
|
+
attr_accessor :directive
|
162
|
+
|
163
|
+
def initialize(directive, glossary)
|
164
|
+
@directive = directive
|
165
|
+
@glossary = glossary
|
166
|
+
end
|
167
|
+
|
168
|
+
# Look up +text+ to see if it matches a command within the lookup
|
169
|
+
# table, returning the command for it, or UnknownCommand if none
|
170
|
+
# match.
|
171
|
+
def lookup(text)
|
172
|
+
@glossary.each do |key,val|
|
173
|
+
if m = key.match(text)
|
174
|
+
return val
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
return UnknownCommand
|
179
|
+
end
|
180
|
+
|
181
|
+
# Define a regexp -> Command mapping.
|
182
|
+
# +rx+ is inserted in the lookup table as a key for +command+
|
183
|
+
def define(rx,command)
|
184
|
+
raise ArgumentError, 'First argument to define must be a Regexp' unless rx.is_a?(Regexp)
|
185
|
+
@glossary[rx] = command
|
186
|
+
end
|
187
|
+
# This is shorthand for define(+key+,Valuecommand), and also
|
188
|
+
# allows +key+ to be a string, converting it to a regexp before
|
189
|
+
# adding it to the dictionary.
|
190
|
+
def define_global_var(key)
|
191
|
+
rx = key
|
192
|
+
rx = /^#{key.to_s}(?:\.\w+\??)*(?:\s:(\w+))?$/ unless key.is_a?(Regexp)
|
193
|
+
@glossary[rx] = ValueCommand
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# This is the regexp we tried using for grabbing an entire line
|
198
|
+
# Good for everything but ValueCommand :-/.
|
199
|
+
# /(?:^\s*\[%([^\]]+?)%\]\s*$\r?\n?|\[%(.+?)%\])/m,
|
200
|
+
DEFAULTGLOSSARY = SyntaxGlossary.new(
|
201
|
+
/\[%(.+?)%\]/m,
|
202
|
+
|
203
|
+
/^var ((\w+)(\.\w+\??)*)(\s+:\w+)?$/i => ValueCommand,
|
204
|
+
/^--/i => CommentCommand,
|
205
|
+
/^(if|unless) ((\w+)(\.\w+\??)*)$/i => IfCommand,
|
206
|
+
/^(in|loop) ((\w+)(\.\w+\??)*)(:\s+\w+)?$/i => LoopCommand,
|
207
|
+
/^(include) ((\w+)(\.\w+\??)*)$/i => IncludeCommand
|
208
|
+
)
|
209
|
+
|
210
|
+
# Preprocessor is a parent class for preprocessors.
|
211
|
+
# A preprocessor is used to process or otherwise prepare output for
|
212
|
+
# printing by Valuecommand
|
213
|
+
#
|
214
|
+
# Preprocessors must be singletons, and take a string to convert in
|
215
|
+
# some form.
|
216
|
+
class Preprocessor
|
217
|
+
end
|
218
|
+
|
219
|
+
# DefaultPreprocessor is a preprocessor with simple processors.
|
220
|
+
class DefaultPreprocessor < Preprocessor
|
221
|
+
# Just the string itself.
|
222
|
+
def DefaultPreprocessor.process(str)
|
223
|
+
str
|
224
|
+
end
|
225
|
+
# Reverse the string. (Just to demonstrate preprocessor)
|
226
|
+
def DefaultPreprocessor.reverse(str)
|
227
|
+
str.reverse
|
228
|
+
end
|
229
|
+
# HTML's escapeURI
|
230
|
+
def DefaultPreprocessor.escapeURI(string)
|
231
|
+
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
|
232
|
+
'%' + $1.unpack('H2' * $1.size).join('%').upcase
|
233
|
+
end.tr(' ','+')
|
234
|
+
end
|
235
|
+
# escape HTML.
|
236
|
+
def DefaultPreprocessor.escapeHTML(string)
|
237
|
+
str = string.gsub(/&/n, '&')
|
238
|
+
str.gsub!(/\"/n, '"')
|
239
|
+
str.gsub!(/>/n, '>')
|
240
|
+
str.gsub!(/</n, '<')
|
241
|
+
str
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# The big ass parser that does all the dirty work of turning
|
246
|
+
# templates into compiled commands.
|
247
|
+
#
|
248
|
+
# Parser.new() accepts a hash as an argument, and looks for these
|
249
|
+
# keys: (with defaults)
|
250
|
+
#
|
251
|
+
# 'namespace' => A namespace object. (A new namespace)
|
252
|
+
# 'glossary' => A SyntaxGlossary object. (a dup of DEFAULTGLOSSARY)
|
253
|
+
# 'preprocessor' => The preprocessor. (DefaultPreprocessor)
|
254
|
+
# 'default_processor' => The processor. (:process)
|
255
|
+
# 'source' => The Source for templates. (FileSource)
|
256
|
+
#
|
257
|
+
# Once the parser is created, it can compile and parse any number of
|
258
|
+
# templates.
|
259
|
+
#
|
260
|
+
# It can be treated as a one-template item by using
|
261
|
+
# Parser#load(template), and calling Parser.output
|
262
|
+
#
|
263
|
+
# To create separate generated templates from the same engine, use
|
264
|
+
# Parser#parse, or Parser#load. (It will still keep the most recent
|
265
|
+
# one it's #load'd, but that will not affect previously parsed or
|
266
|
+
# loaded)
|
267
|
+
class Parser
|
268
|
+
attr_reader :preprocessor, :default_processor
|
269
|
+
attr_reader :glossary, :namespace, :source
|
270
|
+
attr_reader :args, :commands
|
271
|
+
# Parser.new() accepts a hash as an argument, and looks for these
|
272
|
+
# keys: (with defaults)
|
273
|
+
#
|
274
|
+
# 'namespace' => A namespace object. (A new namespace)
|
275
|
+
# 'glossary' => A SyntaxGlossary object. (a dup of DEFAULTGLOSSARY)
|
276
|
+
# 'preprocessor' => The preprocessor. (DefaultPreprocessor)
|
277
|
+
# 'default_processor' => The processor. (:process)
|
278
|
+
# 'source' => The Source for templates. (FileSource)
|
279
|
+
def initialize(args = {})
|
280
|
+
@args = args # For sub-commands
|
281
|
+
@namespace = args['namespace'] || Namespace.new
|
282
|
+
@glossary = args['glossary'] || DEFAULTGLOSSARY.dup
|
283
|
+
@preprocessor = args['preprocessor'] || DefaultPreprocessor
|
284
|
+
@default_processor = args['default_processor'] || :process
|
285
|
+
@source = (args['source'] || FileSource).new(@args)
|
286
|
+
@commands = nil
|
287
|
+
end
|
288
|
+
# Load +name+ from a template, and save it to allow this parser to
|
289
|
+
# use it for output.
|
290
|
+
def load(name)
|
291
|
+
@commands = compile(name)
|
292
|
+
end
|
293
|
+
# Load +name+ from a template, but do not save it.
|
294
|
+
def compile(name)
|
295
|
+
body = @source.get(name)
|
296
|
+
if body
|
297
|
+
parse(body)
|
298
|
+
else
|
299
|
+
TextCommand.new("[ Template '#{name}' not found ]")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
# Compile a Template (BlockCommand) from a string. Does not save
|
303
|
+
# the commands.
|
304
|
+
def parse(body)
|
305
|
+
rx = @glossary.directive
|
306
|
+
stack = [Template.new(self)]
|
307
|
+
while (m = rx.match(body))
|
308
|
+
pre = m.pre_match
|
309
|
+
command = m[1].strip.gsub(/\s+/,' ')
|
310
|
+
body = m.post_match
|
311
|
+
|
312
|
+
# Convert all pre-text to a TextCommand
|
313
|
+
if (pre && pre.length > 0)
|
314
|
+
stack.last.add TextCommand.new(pre)
|
315
|
+
end
|
316
|
+
|
317
|
+
# If the command at the top of the stack is a 'Stacker',
|
318
|
+
# Does this command modify it? If so, just skip back.
|
319
|
+
next if stack.last.modifies?(command)
|
320
|
+
|
321
|
+
# If it closes, we're done changing this. Pop it off the
|
322
|
+
# Stack and add it to the one above it.
|
323
|
+
if stack.last.closes?(command)
|
324
|
+
cmd = stack.pop
|
325
|
+
stack.last.add(cmd)
|
326
|
+
next
|
327
|
+
end
|
328
|
+
|
329
|
+
# Find what command it is.
|
330
|
+
cmd = @glossary.lookup(command)
|
331
|
+
|
332
|
+
# If the command takes it, pass the parser.
|
333
|
+
block = if (cmd.instance_method(:initialize).arity == 2)
|
334
|
+
cmd.new(command,self)
|
335
|
+
else
|
336
|
+
cmd.new(command)
|
337
|
+
end
|
338
|
+
|
339
|
+
# If it's a stacking command, push it on the stack
|
340
|
+
if block.is_a?(StackableCommand)
|
341
|
+
stack.push block
|
342
|
+
else
|
343
|
+
stack.last.add block
|
344
|
+
end
|
345
|
+
end
|
346
|
+
stack.last.add TextCommand.new(body) if body && body.length > 0
|
347
|
+
if (stack.length > 1)
|
348
|
+
raise ArgumentError, 'Mismatched command closures in template'
|
349
|
+
end
|
350
|
+
stack[0]
|
351
|
+
end
|
352
|
+
# Not really of any point, but clears the saved commands.
|
353
|
+
def clearCommands
|
354
|
+
@commands = nil
|
355
|
+
end
|
356
|
+
# Sets this parser's namespace values.
|
357
|
+
def []=(key,val)
|
358
|
+
@namespace[key] = val
|
359
|
+
end
|
360
|
+
# Gets this parser's namespace values.
|
361
|
+
def [](key)
|
362
|
+
@namespace[key]
|
363
|
+
end
|
364
|
+
# If any commands are loaded and saved, return a string of it.
|
365
|
+
def output(namespace=nil)
|
366
|
+
return '' unless @commands
|
367
|
+
@namespace.parent = namespace if namespace
|
368
|
+
str = @commands.output(@namespace)
|
369
|
+
@namespace.parent = nil
|
370
|
+
str
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|