PageTemplate 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +85 -0
- data/TC_PageTemplate.rb +856 -0
- metadata +39 -0
data/README.txt
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
= PageTemplate.rb README
|
2
|
+
|
3
|
+
Use PageTemplate.rb to create output based on template pages and
|
4
|
+
the code of your program. This package is inspired by, but not
|
5
|
+
quite like, Perl's HTML::Template package. Its main intent is to
|
6
|
+
separate design and code for CGI programs, but it could be useful
|
7
|
+
in other contexts as well (Ex: site generation packages).
|
8
|
+
|
9
|
+
PageTemplate.rb is distributed under the MIT License, which is included
|
10
|
+
within this document in the License section.
|
11
|
+
|
12
|
+
As a side note: if you are using PageTemplate in your projects, or
|
13
|
+
add features to your copy, I'd love to hear about it. If you feel like
|
14
|
+
it.
|
15
|
+
|
16
|
+
Brian Wisti (brian@coolnamehere.com)
|
17
|
+
http://www.coolnamehere.com/products/pagetemplate/
|
18
|
+
|
19
|
+
== Features
|
20
|
+
|
21
|
+
* Variable substitution
|
22
|
+
* If and If/Else structures
|
23
|
+
* Loops and Loop/Else structures
|
24
|
+
* Customizable Syntax
|
25
|
+
* Include content from external files (new in 1.1)
|
26
|
+
|
27
|
+
== Requirements
|
28
|
+
|
29
|
+
* ruby 1.8
|
30
|
+
|
31
|
+
== Install
|
32
|
+
|
33
|
+
=== Generic Install
|
34
|
+
|
35
|
+
De-Compress archive and enter its top directory.
|
36
|
+
Then type:
|
37
|
+
|
38
|
+
$ ruby install.rb config
|
39
|
+
$ ruby install.rb setup
|
40
|
+
($ su)
|
41
|
+
# ruby install.rb install
|
42
|
+
|
43
|
+
You can also install files into your favorite directory
|
44
|
+
by supplying install.rb some options. Try "ruby install.rb --help".
|
45
|
+
|
46
|
+
=== Install With Rake
|
47
|
+
|
48
|
+
$ rake
|
49
|
+
$ sudo rake install
|
50
|
+
|
51
|
+
=== Install With RubyGems
|
52
|
+
|
53
|
+
Download the gem file from the
|
54
|
+
[PageTemplate RubyForge page]:http://rubyforge.org/projects/pagetemplate/
|
55
|
+
|
56
|
+
Then, use the gem command to install it:
|
57
|
+
|
58
|
+
$ sudo gem install -l PageTemplate-1.1.1.gem
|
59
|
+
|
60
|
+
I think that's all there is to it. I'm new to gems, though, so let me
|
61
|
+
know if I missed something.
|
62
|
+
|
63
|
+
== Usage
|
64
|
+
|
65
|
+
PageTemplate.rb is a class library, and has no command line or
|
66
|
+
interactive capabilities. See PageTemplate for a
|
67
|
+
reference to the classes and methods contained in this package.
|
68
|
+
There is a tutorial and user guide available online, at
|
69
|
+
http://coolnamehere.com/products/pagetemplate/
|
70
|
+
|
71
|
+
== License
|
72
|
+
|
73
|
+
The MIT License
|
74
|
+
|
75
|
+
Copyright (c) 2002-2005 Brian Wisti
|
76
|
+
|
77
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
78
|
+
|
79
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
80
|
+
|
81
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
Brian Wisti (brian@coolnamehere.com)
|
data/TC_PageTemplate.rb
ADDED
@@ -0,0 +1,856 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require './lib/PageTemplate.rb'
|
5
|
+
|
6
|
+
require "date"
|
7
|
+
|
8
|
+
class TC_Namespace < Test::Unit::TestCase
|
9
|
+
@@namespace = Namespace.new()
|
10
|
+
|
11
|
+
def testNamespaceSet
|
12
|
+
assert(@@namespace.set("name", "Frank"))
|
13
|
+
end
|
14
|
+
|
15
|
+
def testNamespaceGet
|
16
|
+
@@namespace.set("name", "Frank")
|
17
|
+
assert_equal("Frank", @@namespace.get("name"))
|
18
|
+
end
|
19
|
+
|
20
|
+
def testTrue
|
21
|
+
assert_not_nil(@@namespace.true?("name"))
|
22
|
+
assert_nil(@@namespace.true?("null"))
|
23
|
+
@@namespace.set("falseFlag", false)
|
24
|
+
assert_nil(@@namespace.true?("falseFlag"))
|
25
|
+
end
|
26
|
+
|
27
|
+
def testNamespacePush
|
28
|
+
assert_equal("Frank", @@namespace.get("name"))
|
29
|
+
names = { 'name' => "Eddie Baby" }
|
30
|
+
|
31
|
+
# Pushing a hash (and nested namespace)
|
32
|
+
assert(@@namespace.push(names))
|
33
|
+
assert_equal("Eddie Baby", @@namespace.get("name"))
|
34
|
+
|
35
|
+
# Pushing an object
|
36
|
+
date = Date.today()
|
37
|
+
date2 = Date.today()
|
38
|
+
|
39
|
+
@@namespace.push(date)
|
40
|
+
assert_equal(date2.year, @@namespace.get("year"))
|
41
|
+
end
|
42
|
+
|
43
|
+
def testNamespacePop
|
44
|
+
names = { 'name' => "Eddie Baby" }
|
45
|
+
@@namespace.push(names)
|
46
|
+
assert_equal("Eddie Baby", @@namespace.get("name"))
|
47
|
+
assert(@@namespace.pop())
|
48
|
+
assert_equal("Frank", @@namespace.get("name"))
|
49
|
+
assert_nil(@@namespace.pop())
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class TC_Command < Test::Unit::TestCase
|
55
|
+
@@command = Command.new()
|
56
|
+
|
57
|
+
def testCommandOutput
|
58
|
+
assert_raises(NotImplementedError) { @@command.output() }
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class TC_BlockCommand < Test::Unit::TestCase
|
64
|
+
@@command = BlockCommand.new()
|
65
|
+
|
66
|
+
def testAddCommand
|
67
|
+
aCommand = TextCommand.new("Hello")
|
68
|
+
assert(@@command.add(aCommand))
|
69
|
+
|
70
|
+
assert_raises(TypeError) { @@command.add("Hello") }
|
71
|
+
end
|
72
|
+
|
73
|
+
def testOutput
|
74
|
+
bCommand = TextCommand.new(", ")
|
75
|
+
cCommand = TextCommand.new("World")
|
76
|
+
|
77
|
+
@@command.add(bCommand)
|
78
|
+
@@command.add(cCommand)
|
79
|
+
|
80
|
+
assert_equal("Hello, World", @@command.output)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class TC_TextCommand < Test::Unit::TestCase
|
85
|
+
@@command = TextCommand.new("Just testing")
|
86
|
+
|
87
|
+
def testCommandOutput
|
88
|
+
assert_equal("Just testing", @@command.output)
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class TC_ValueCommand < Test::Unit::TestCase
|
94
|
+
@@valueCommand = ValueCommand.new("name")
|
95
|
+
|
96
|
+
def testOutput
|
97
|
+
ns = Namespace.new()
|
98
|
+
ns.set("name", "Frank")
|
99
|
+
assert_equal(ns.get("name"), @@valueCommand.output(ns))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class TC_IfCommand < Test::Unit::TestCase
|
104
|
+
|
105
|
+
def testOutput
|
106
|
+
aCommand = TextCommand.new("Programming ")
|
107
|
+
bCommand = TextCommand.new("Ruby")
|
108
|
+
commandBlock = BlockCommand.new()
|
109
|
+
commandBlock.add(aCommand)
|
110
|
+
commandBlock.add(bCommand)
|
111
|
+
|
112
|
+
ns = Namespace.new()
|
113
|
+
ns.set("testing", 1)
|
114
|
+
|
115
|
+
# First test for output with true condition
|
116
|
+
ifCommand = IfCommand.new("testing", commandBlock)
|
117
|
+
assert_equal("Programming Ruby", ifCommand.output(ns))
|
118
|
+
|
119
|
+
# Test for nil output with false condition
|
120
|
+
ifCommand = IfCommand.new("production", commandBlock)
|
121
|
+
assert_nil(ifCommand.output(ns))
|
122
|
+
|
123
|
+
ns.set("production", false)
|
124
|
+
assert_nil(ifCommand.output(ns))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class TC_IfElseCommand < Test::Unit::TestCase
|
129
|
+
|
130
|
+
def testOutput
|
131
|
+
aCommand = TextCommand.new("This is ")
|
132
|
+
bCommand = TextCommand.new("True")
|
133
|
+
cCommand = TextCommand.new("False")
|
134
|
+
ifBlock = BlockCommand.new()
|
135
|
+
ifBlock.add(aCommand)
|
136
|
+
ifBlock.add(bCommand)
|
137
|
+
elseBlock = BlockCommand.new()
|
138
|
+
elseBlock.add(aCommand)
|
139
|
+
elseBlock.add(cCommand)
|
140
|
+
|
141
|
+
ns = Namespace.new()
|
142
|
+
ns.set("testing", 1)
|
143
|
+
|
144
|
+
# First test for output with true condition
|
145
|
+
ifElseCommand = IfElseCommand.new("testing", ifBlock, elseBlock)
|
146
|
+
assert_equal("This is True", ifElseCommand.output(ns))
|
147
|
+
|
148
|
+
# Test for output with false condition
|
149
|
+
ifElseCommand = IfElseCommand.new("live", ifBlock, elseBlock)
|
150
|
+
assert_equal("This is False", ifElseCommand.output(ns))
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
class TC_LoopCommand < Test::Unit::TestCase
|
156
|
+
|
157
|
+
def testOutput
|
158
|
+
# Build a list of hashes for the namespace
|
159
|
+
loopItems = [
|
160
|
+
{ 'x'=> '1 ', 'y'=> '2 ', 'z'=> '3' },
|
161
|
+
{ 'x'=> 'a ', 'y'=> 'b ', 'z'=> 'c' },
|
162
|
+
]
|
163
|
+
ns = Namespace.new()
|
164
|
+
ns.set('list', loopItems)
|
165
|
+
|
166
|
+
# Build a command list
|
167
|
+
xCommand = ValueCommand.new('x')
|
168
|
+
yCommand = ValueCommand.new('y')
|
169
|
+
zCommand = ValueCommand.new('z')
|
170
|
+
commandBlock = BlockCommand.new()
|
171
|
+
commandBlock.add(xCommand)
|
172
|
+
commandBlock.add(yCommand)
|
173
|
+
commandBlock.add(zCommand)
|
174
|
+
|
175
|
+
loopCommand = LoopCommand.new('list', commandBlock)
|
176
|
+
assert_equal("1 2 3a b c", loopCommand.output(ns))
|
177
|
+
loopCommand = LoopCommand.new('noshow', commandBlock)
|
178
|
+
assert_nil(loopCommand.output(ns))
|
179
|
+
ns.set("string", "hello")
|
180
|
+
loopCommand = LoopCommand.new("string", commandBlock)
|
181
|
+
assert_raises(TypeError) { loopCommand.output(ns) }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class TC_LoopElseCommand < Test::Unit::TestCase
|
186
|
+
|
187
|
+
def testOutput
|
188
|
+
# Build a list of hashes for the namespace
|
189
|
+
loopItems = [
|
190
|
+
{ 'x'=> '1 ', 'y'=> '2 ', 'z'=> '3' },
|
191
|
+
{ 'x'=> 'a ', 'y'=> 'b ', 'z'=> 'c' },
|
192
|
+
]
|
193
|
+
ns = Namespace.new()
|
194
|
+
ns.set('list', loopItems)
|
195
|
+
|
196
|
+
# Build a command list
|
197
|
+
xCommand = ValueCommand.new('x')
|
198
|
+
yCommand = ValueCommand.new('y')
|
199
|
+
zCommand = ValueCommand.new('z')
|
200
|
+
commandBlock = BlockCommand.new()
|
201
|
+
commandBlock.add(xCommand)
|
202
|
+
commandBlock.add(yCommand)
|
203
|
+
commandBlock.add(zCommand)
|
204
|
+
|
205
|
+
# Build a command list for the else block
|
206
|
+
aCommand = TextCommand.new("In the else block")
|
207
|
+
elseCommands = BlockCommand.new()
|
208
|
+
elseCommands.add(aCommand)
|
209
|
+
|
210
|
+
# Build the LoopCommand
|
211
|
+
loopCommand =
|
212
|
+
LoopElseCommand.new('list', commandBlock, elseCommands)
|
213
|
+
|
214
|
+
# Test for output when loop variable is true
|
215
|
+
assert_equal("1 2 3a b c", loopCommand.output(ns))
|
216
|
+
|
217
|
+
# Test for nil when loop variable is false
|
218
|
+
loopCommand =
|
219
|
+
LoopElseCommand.new('noshow', commandBlock, elseCommands)
|
220
|
+
assert_equal("In the else block", loopCommand.output(ns))
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
class TC_NestedCommands < Test::Unit::TestCase
|
227
|
+
|
228
|
+
def testNestedIfs
|
229
|
+
ns = Namespace.new()
|
230
|
+
|
231
|
+
innerBlock = BlockCommand.new()
|
232
|
+
innerBlock.add(TextCommand.new("Inner"))
|
233
|
+
innerIf = IfCommand.new("inner", innerBlock)
|
234
|
+
|
235
|
+
outerBlock = BlockCommand.new()
|
236
|
+
outerBlock.add(TextCommand.new("Outer"))
|
237
|
+
outerBlock.add(innerIf)
|
238
|
+
outerIf = IfCommand.new("outer", outerBlock)
|
239
|
+
|
240
|
+
mainBlock = BlockCommand.new()
|
241
|
+
mainBlock.add(outerIf)
|
242
|
+
|
243
|
+
# True in a true should yield result of both command lists
|
244
|
+
ns.set("outer", 1)
|
245
|
+
ns.set("inner", 1)
|
246
|
+
assert_equal("OuterInner", mainBlock.output(ns))
|
247
|
+
|
248
|
+
# False in a true should yield result of outside list
|
249
|
+
ns.set("inner", false)
|
250
|
+
assert_equal("Outer", mainBlock.output(ns))
|
251
|
+
|
252
|
+
# False in a false should yield nil
|
253
|
+
ns.set("outer", false)
|
254
|
+
assert_nil(mainBlock.output(ns))
|
255
|
+
|
256
|
+
# True in a false should yield nil
|
257
|
+
ns.set("inner", 1)
|
258
|
+
ns.set("outer", false)
|
259
|
+
assert_nil(mainBlock.output(ns))
|
260
|
+
end
|
261
|
+
|
262
|
+
def testNestedLoops
|
263
|
+
loop1 = [
|
264
|
+
{ 'a' => 'o1 ', 'b' => 'o2 ', 'c' => [
|
265
|
+
{ 'x' => 'i1 ', 'y' => 'i2 ', 'z' => 'i3 ' },
|
266
|
+
{ 'x' => 'i4 ', 'y' => 'i5 ', 'z' => 'i6 ' } ]
|
267
|
+
},
|
268
|
+
{ 'a' => 'o3 ', 'b' => 'o4 ', 'c' => [
|
269
|
+
{ 'x' => 'j1 ', 'y' => 'j2 ', 'z' => 'j3 ' },
|
270
|
+
{ 'x' => 'j4 ', 'y' => 'j5 ', 'z' => 'j6 ' } ]
|
271
|
+
}
|
272
|
+
]
|
273
|
+
ns = Namespace.new()
|
274
|
+
ns.set("loop", loop1)
|
275
|
+
|
276
|
+
aCommand = ValueCommand.new('a')
|
277
|
+
bCommand = ValueCommand.new('b')
|
278
|
+
xCommand = ValueCommand.new('x')
|
279
|
+
yCommand = ValueCommand.new('y')
|
280
|
+
zCommand = ValueCommand.new('z')
|
281
|
+
innerBlock = BlockCommand.new()
|
282
|
+
innerBlock.add(xCommand)
|
283
|
+
innerBlock.add(yCommand)
|
284
|
+
innerBlock.add(zCommand)
|
285
|
+
cCommand = LoopCommand.new('c', innerBlock)
|
286
|
+
outerBlock = BlockCommand.new()
|
287
|
+
outerBlock.add(aCommand)
|
288
|
+
outerBlock.add(bCommand)
|
289
|
+
outerBlock.add(cCommand)
|
290
|
+
loopCommand = LoopCommand.new('loop', outerBlock)
|
291
|
+
|
292
|
+
# Loop in a loop should yield lots of text ;-)
|
293
|
+
# 'o1 o2 i1 i2 i3 i4 i5 i6 o3 o4 j1 j2 j3 j4 j5 j6 '
|
294
|
+
assert_equal('o1 o2 i1 i2 i3 i4 i5 i6 o3 o4 j1 j2 j3 j4 j5 j6 ',
|
295
|
+
loopCommand.output(ns))
|
296
|
+
|
297
|
+
# False in a loop should yield outside loop
|
298
|
+
# 'o1 o2 o3 o4 '
|
299
|
+
loop1.each { |item| item['c'] = [] }
|
300
|
+
assert_equal('o1 o2 o3 o4 ', loopCommand.output(ns))
|
301
|
+
end
|
302
|
+
|
303
|
+
def testMixedNesting
|
304
|
+
# Loop in If
|
305
|
+
loop1 = [
|
306
|
+
{ 'a' => '1 ', 'b' => '2 ', 'c' => '3 ' },
|
307
|
+
{ 'a' => 'x ', 'b' => 'y ', 'c' => 'z ' }
|
308
|
+
]
|
309
|
+
|
310
|
+
aCommand = ValueCommand.new('a')
|
311
|
+
bCommand = ValueCommand.new('b')
|
312
|
+
cCommand = ValueCommand.new('c')
|
313
|
+
loopBlock = BlockCommand.new()
|
314
|
+
loopBlock.add(aCommand)
|
315
|
+
loopBlock.add(bCommand)
|
316
|
+
loopBlock.add(cCommand)
|
317
|
+
loopCommand = LoopCommand.new("loop", loopBlock)
|
318
|
+
ifBlock = BlockCommand.new()
|
319
|
+
ifBlock.add(loopCommand)
|
320
|
+
ifCommand = IfCommand.new("flag", ifBlock)
|
321
|
+
|
322
|
+
ns = Namespace.new()
|
323
|
+
ns.set("loop", loop1)
|
324
|
+
ns.set("flag", 1)
|
325
|
+
assert_equal("1 2 3 x y z ", ifCommand.output(ns))
|
326
|
+
ns.set("flag", false)
|
327
|
+
assert_nil(ifCommand.output(ns))
|
328
|
+
|
329
|
+
# If in Loop
|
330
|
+
|
331
|
+
dCommand = TextCommand.new("(true)")
|
332
|
+
ifBlock = BlockCommand.new()
|
333
|
+
ifBlock.add(dCommand)
|
334
|
+
ifCommand = IfCommand.new("flag", ifBlock)
|
335
|
+
loopBlock = BlockCommand.new()
|
336
|
+
loopBlock.add(aCommand)
|
337
|
+
loopBlock.add(bCommand)
|
338
|
+
loopBlock.add(cCommand)
|
339
|
+
loopBlock.add(ifCommand)
|
340
|
+
loopCommand = LoopCommand.new("loop", loopBlock)
|
341
|
+
|
342
|
+
loop1[-1]['flag'] = 1
|
343
|
+
assert_equal("1 2 3 x y z (true)", loopCommand.output(ns))
|
344
|
+
loop1[-1]['flag'] = false
|
345
|
+
assert_equal("1 2 3 x y z ", loopCommand.output(ns))
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
class TC_SyntaxGlossary < Test::Unit::TestCase
|
351
|
+
@@syntax = Syntax::Glossary.new( /\[%(.+?)%\]/,
|
352
|
+
'value' => /var (\w+)/,
|
353
|
+
'ifopen' => /if (\w+)/,
|
354
|
+
'ifclose' => /endif/,
|
355
|
+
'ifbranch' => /else/,
|
356
|
+
'loopopen' => /in (\w+)/,
|
357
|
+
'loopclose' => /endin/,
|
358
|
+
'loopbranch' => /no/,
|
359
|
+
'include' => /include (\w+)/
|
360
|
+
)
|
361
|
+
|
362
|
+
def testGlossary
|
363
|
+
assert_equal(/\[%(.+?)%\]/, @@syntax.directive)
|
364
|
+
assert_equal(/in (\w+)/, @@syntax.glossary['loopopen'])
|
365
|
+
|
366
|
+
badSyntax = {
|
367
|
+
'flargle' => /flargle/
|
368
|
+
}
|
369
|
+
assert_raises(ArgumentError) {
|
370
|
+
Syntax::Glossary.new(/%(.+?)%/, badSyntax)
|
371
|
+
}
|
372
|
+
end
|
373
|
+
|
374
|
+
def testLookup
|
375
|
+
assert_equal(["value", "name"], @@syntax.lookup("var name"))
|
376
|
+
assert_equal(["ifopen", "name"], @@syntax.lookup("if name"))
|
377
|
+
assert_equal(["ifclose", nil], @@syntax.lookup("endif"))
|
378
|
+
assert_equal(["ifbranch", nil], @@syntax.lookup("else"))
|
379
|
+
assert_equal(["loopopen", "x"], @@syntax.lookup("in x"))
|
380
|
+
assert_equal(["loopclose", nil], @@syntax.lookup("endin"))
|
381
|
+
assert_equal(["loopbranch", nil], @@syntax.lookup("no"))
|
382
|
+
assert_equal(["include", "foo"], @@syntax.lookup("include foo"))
|
383
|
+
assert_nil(@@syntax.lookup("foo"))
|
384
|
+
assert_nil(@@syntax.lookup("foo bar"))
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
class TC_SyntaxParser < Test::Unit::TestCase
|
390
|
+
@@parser = Syntax::Parser.new(Syntax::DEFAULT)
|
391
|
+
|
392
|
+
def testParse
|
393
|
+
assert_equal([[1, ""]], @@parser.parse([""]))
|
394
|
+
assert_equal([
|
395
|
+
[1, "Hello "],
|
396
|
+
[1, ["value", "world"]],
|
397
|
+
[1, ""]
|
398
|
+
], @@parser.parse(["Hello [%var world%]"])
|
399
|
+
)
|
400
|
+
|
401
|
+
assert_equal([
|
402
|
+
[1, ""],
|
403
|
+
[1, ["value", "articleno"]],
|
404
|
+
[1, ""]
|
405
|
+
], @@parser.parse(["[%var articleno%]"]))
|
406
|
+
assert_equal([
|
407
|
+
[1, ""],
|
408
|
+
[1, ["value", "articleno"]],
|
409
|
+
[1, ""]
|
410
|
+
], @@parser.parse(["[% var articleno %\]"]))
|
411
|
+
|
412
|
+
multiline = [
|
413
|
+
"Hello [%var world%\]",
|
414
|
+
"[%if return%]",
|
415
|
+
"Welcome Back!",
|
416
|
+
"[%endif%]"
|
417
|
+
]
|
418
|
+
|
419
|
+
mResult = [
|
420
|
+
[1, "Hello "],
|
421
|
+
[1, ["value", "world"]],
|
422
|
+
[1, ""],
|
423
|
+
[2, ""],
|
424
|
+
[2, ["ifopen", "return"]],
|
425
|
+
[2, ""],
|
426
|
+
[3, "Welcome Back!"],
|
427
|
+
[4, ""],
|
428
|
+
[4, ["ifclose", nil]],
|
429
|
+
[4, ""]
|
430
|
+
]
|
431
|
+
|
432
|
+
assert_equal(mResult, @@parser.parse(multiline))
|
433
|
+
end
|
434
|
+
|
435
|
+
def testCompile
|
436
|
+
directives = [
|
437
|
+
"Hello [%var world%]",
|
438
|
+
"[%if return%]",
|
439
|
+
"Welcome Back!",
|
440
|
+
"[%endif%]"
|
441
|
+
]
|
442
|
+
assert(@@parser.compile(@@parser.parse(directives)))
|
443
|
+
end
|
444
|
+
|
445
|
+
def testBuild
|
446
|
+
assert(@@parser.build("tdata/p/b1.txt"))
|
447
|
+
# Make sure nothing panics if we ask for the commands again.
|
448
|
+
assert(@@parser.build("tdata/p/b1.txt"))
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
class TC_SyntaxCachedParser < Test::Unit::TestCase
|
453
|
+
@@parser = Syntax::CachedParser.new(Syntax::DEFAULT)
|
454
|
+
|
455
|
+
def testBuild
|
456
|
+
assert(@@parser.build("tdata/p/b1.txt"))
|
457
|
+
assert(File.exists?("tdata/p/_b1.txt"))
|
458
|
+
|
459
|
+
ns = Namespace.new()
|
460
|
+
ns["world"] = "World"
|
461
|
+
assert(@@parser.output(ns))
|
462
|
+
end
|
463
|
+
|
464
|
+
def testCachedBuild
|
465
|
+
assert(@@parser.build("tdata/p/cb1.txt"))
|
466
|
+
assert(File.exists?("tdata/p/_cb1.txt"))
|
467
|
+
assert(@@parser.reset)
|
468
|
+
assert(@@parser.build("tdata/p/cb1.txt"))
|
469
|
+
end
|
470
|
+
|
471
|
+
def testCachedRebuild
|
472
|
+
# Create a new parser and build with the cached information.
|
473
|
+
p2 = Syntax::CachedParser.new(Syntax::DEFAULT)
|
474
|
+
assert(p2.build("tdata/p/cb1.txt"))
|
475
|
+
|
476
|
+
# Clean up after ourselves.
|
477
|
+
system("rm -f tdata/p/_cb1.txt")
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
class TC_PageTemplate < Test::Unit::TestCase
|
482
|
+
@@template = PageTemplate.new( 'syntax' => Syntax::DEFAULT )
|
483
|
+
|
484
|
+
def testLoadFile
|
485
|
+
assert(@@template.load("tdata/t.txt"))
|
486
|
+
assert_equal("tdata/t.txt", @@template.file)
|
487
|
+
assert_raises(ArgumentError) { @@template.load("tdata/null") }
|
488
|
+
end
|
489
|
+
|
490
|
+
def testInitializeTemplate
|
491
|
+
assert(PageTemplate.new())
|
492
|
+
assert(PageTemplate.new("filename" => "tdata/t.txt"))
|
493
|
+
assert_raises(ArgumentError) { PageTemplate.new("filename" => "tdata/null") }
|
494
|
+
end
|
495
|
+
|
496
|
+
def testSetParameter
|
497
|
+
assert(@@template.setParameter("name", "PageTemplate"))
|
498
|
+
end
|
499
|
+
|
500
|
+
def testGetParameter
|
501
|
+
@@template.setParameter("name", "PageTemplate")
|
502
|
+
assert_equal("PageTemplate", @@template.getParameter("name"))
|
503
|
+
assert_nil(@@template.getParameter("null"))
|
504
|
+
end
|
505
|
+
|
506
|
+
def testHashAccess
|
507
|
+
@@template['hash'] = 'test'
|
508
|
+
assert_equal('test', @@template['hash'])
|
509
|
+
end
|
510
|
+
|
511
|
+
def testOutputNoMarkup
|
512
|
+
@@template.load("tdata/nm.txt")
|
513
|
+
cmpFile = File.open("tdata/nm.txt").read()
|
514
|
+
assert_equal(cmpFile, @@template.output())
|
515
|
+
end
|
516
|
+
|
517
|
+
def testOutputValueMarkup
|
518
|
+
|
519
|
+
# Valid markup, value exists.
|
520
|
+
@@template['title'] = "ValueMarkup"
|
521
|
+
@@template.load("tdata/v1.txt")
|
522
|
+
assert(@@template.output =~ /<h1>ValueMarkup<\/h1>/)
|
523
|
+
|
524
|
+
# Valid markup, value does not exist.
|
525
|
+
@@template['title'] = ""
|
526
|
+
assert(@@template.output =~ /<h1><\/h1>/)
|
527
|
+
|
528
|
+
# Invalid markup.
|
529
|
+
@@template.load("tdata/v2.txt")
|
530
|
+
assert(@@template.output =~ /<h1>title%\]<\/h1>/)
|
531
|
+
end
|
532
|
+
|
533
|
+
def testOutputIfMarkup
|
534
|
+
@@template['flag'] = true
|
535
|
+
@@template.load("tdata/i1.txt")
|
536
|
+
assert(@@template.output =~ /It's all true!/)
|
537
|
+
|
538
|
+
@@template['flag'] = false
|
539
|
+
assert(@@template.output !~ /It's all true!/)
|
540
|
+
|
541
|
+
# Nested if expressions
|
542
|
+
@@template.load("tdata/i2.txt")
|
543
|
+
|
544
|
+
# 1. Both true.
|
545
|
+
@@template['outer'] = true
|
546
|
+
@@template['inner'] = true
|
547
|
+
assert(@@template.output =~ /This is outer text/)
|
548
|
+
assert(@@template.output =~ /This is inner text/)
|
549
|
+
|
550
|
+
# 2. Outer true, inner false.
|
551
|
+
@@template['outer'] = true
|
552
|
+
@@template['inner'] = false
|
553
|
+
assert(@@template.output =~ /This is outer text/)
|
554
|
+
assert(@@template.output !~ /This is inner text/)
|
555
|
+
|
556
|
+
# 3. Inner true, outer false.
|
557
|
+
@@template['outer'] = false
|
558
|
+
@@template['inner'] = true
|
559
|
+
assert(@@template.output !~ /This is outer text/)
|
560
|
+
assert(@@template.output !~ /This is inner text/)
|
561
|
+
end
|
562
|
+
|
563
|
+
def testOutputIfBranchMarkup
|
564
|
+
@@template.load("tdata/ie1.txt")
|
565
|
+
|
566
|
+
# True: if block executes, not else block
|
567
|
+
@@template["flag"] = true
|
568
|
+
assert(@@template.output =~ /It's all true!/)
|
569
|
+
assert(@@template.output !~ /Nothing is true/)
|
570
|
+
|
571
|
+
# False: else block executes, not if block
|
572
|
+
@@template["flag"] = false
|
573
|
+
assert(@@template.output =~ /Nothing is true/)
|
574
|
+
assert(@@template.output !~ /It's all true!/)
|
575
|
+
end
|
576
|
+
|
577
|
+
def testOutputNestedIfBranchMarkup
|
578
|
+
@@template.load("tdata/ie2.txt")
|
579
|
+
|
580
|
+
# Outer true, inner true
|
581
|
+
@@template['outer'] = true
|
582
|
+
@@template['inner'] = true
|
583
|
+
assert(@@template.output =~ /Outer is true/)
|
584
|
+
assert(@@template.output =~ /Inner is true/)
|
585
|
+
|
586
|
+
# Outer true, inner false
|
587
|
+
@@template['outer'] = true
|
588
|
+
@@template['inner'] = false
|
589
|
+
assert(@@template.output =~ /Outer is true/)
|
590
|
+
assert(@@template.output =~ /Inner is false/)
|
591
|
+
|
592
|
+
# Outer false, inner true
|
593
|
+
@@template['outer'] = false
|
594
|
+
@@template['inner'] = true
|
595
|
+
assert(@@template.output =~ /Outer is false/)
|
596
|
+
assert(@@template.output =~ /Inner is true/)
|
597
|
+
|
598
|
+
# Outer false, inner false
|
599
|
+
@@template['outer'] = false
|
600
|
+
@@template['inner'] = false
|
601
|
+
assert(@@template.output =~ /Outer is false/)
|
602
|
+
assert(@@template.output =~ /Inner is false/)
|
603
|
+
end
|
604
|
+
|
605
|
+
def testOutputLoopMarkup
|
606
|
+
@@template.load("tdata/l1.txt")
|
607
|
+
|
608
|
+
# Loop Exists
|
609
|
+
myLoop = []
|
610
|
+
1.upto(5) { |v| myLoop << {'value' => v} }
|
611
|
+
|
612
|
+
@@template['loop'] = myLoop
|
613
|
+
assert(@@template.output =~ /<li>3<\/li>/)
|
614
|
+
|
615
|
+
# Loop Doesn't Exist
|
616
|
+
@@template['loop'] = false
|
617
|
+
assert(@@template.output !~ /<li>3<\/li>/)
|
618
|
+
|
619
|
+
# Loop Is Empty List
|
620
|
+
@@template['loop'] = []
|
621
|
+
assert(@@template.output !~ /<li>.*?<\/li>/)
|
622
|
+
end
|
623
|
+
|
624
|
+
def testOutputNestedLoopMarkup
|
625
|
+
@@template.load("tdata/l2.txt")
|
626
|
+
|
627
|
+
# Outer Loop Exists, Inner Loop Exists
|
628
|
+
innerLoop = []
|
629
|
+
'a'.upto('f') { |v| innerLoop << { 'value' => v } }
|
630
|
+
outerLoop = []
|
631
|
+
1.upto(5) do |v|
|
632
|
+
outerLoop << {'value' => v, 'inner' => innerLoop}
|
633
|
+
end
|
634
|
+
@@template['loop'] = outerLoop
|
635
|
+
assert(@@template.output =~ /<li>\d/)
|
636
|
+
assert(@@template.output =~ /<li>[a-f]<\/li>/)
|
637
|
+
|
638
|
+
# Outer Loop Exists, Inner Loop Empty
|
639
|
+
outerLoop.each { |x| x['inner'] = [] }
|
640
|
+
assert(@@template.output !~ /<li>[a-f]<\/li>/)
|
641
|
+
|
642
|
+
# Outer Loop Exists, Alternate Inner Loops Empty
|
643
|
+
outerLoop.each_with_index do |x, i|
|
644
|
+
x['inner'] = innerLoop if i % 2 == 0
|
645
|
+
end
|
646
|
+
assert(@@template.output =~ /<li>4\s+?<ul><\/ul>/m)
|
647
|
+
assert(@@template.output =~ /<li>3\s+?<ul><li>a/m)
|
648
|
+
|
649
|
+
# Outer Loop Empty
|
650
|
+
@@template['loop'] = false
|
651
|
+
assert(@@template.output !~ /<li>/)
|
652
|
+
end
|
653
|
+
|
654
|
+
def testOutputLoopBranchMarkup
|
655
|
+
@@template.load("tdata/ib1.txt")
|
656
|
+
|
657
|
+
# Loop exists
|
658
|
+
myLoop = []
|
659
|
+
1.upto(5) { |v| myLoop << {'value' => v} }
|
660
|
+
@@template['loop'] = myLoop
|
661
|
+
assert(@@template.output =~ /<li>\d<\/li>/)
|
662
|
+
assert(@@template.output !~ /No values/)
|
663
|
+
|
664
|
+
# No loop
|
665
|
+
@@template['loop'] = []
|
666
|
+
assert(@@template.output !~ /<li>\d<\/li>/)
|
667
|
+
assert(@@template.output =~ /No values/)
|
668
|
+
end
|
669
|
+
|
670
|
+
def testOutputNestedLoopBranchMarkup
|
671
|
+
@@template.load("tdata/ib2.txt")
|
672
|
+
# Outer Loop Exists, Inner Loop Exists
|
673
|
+
innerLoop = []
|
674
|
+
'a'.upto('f') { |v| innerLoop << { 'value' => v } }
|
675
|
+
outerLoop = []
|
676
|
+
1.upto(5) do |v|
|
677
|
+
outerLoop << {'value' => v, 'inner' => innerLoop}
|
678
|
+
end
|
679
|
+
@@template['loop'] = outerLoop
|
680
|
+
assert(@@template.output =~ /<li>\d/)
|
681
|
+
assert(@@template.output =~ /<li>[a-f]<\/li>/)
|
682
|
+
|
683
|
+
# Outer Loop Exists, Inner Loop Empty
|
684
|
+
outerLoop.each { |x| x['inner'] = [] }
|
685
|
+
assert(@@template.output =~ /No inner values/)
|
686
|
+
|
687
|
+
# Outer Loop Exists, Alternate Inner Loops Empty
|
688
|
+
outerLoop.each_with_index do |x, i|
|
689
|
+
x['inner'] = innerLoop if i % 2 == 0
|
690
|
+
end
|
691
|
+
assert(@@template.output =~ /<li>4\s+?<ul>.+?No inner values/m)
|
692
|
+
assert(@@template.output =~ /<li>3\s+?<ul>.+?<li>a/m)
|
693
|
+
|
694
|
+
# Outer Loop Empty
|
695
|
+
@@template['loop'] = false
|
696
|
+
assert(@@template.output =~ /No values/)
|
697
|
+
end
|
698
|
+
|
699
|
+
def testOutputComplexMarkup
|
700
|
+
title = "Testing"
|
701
|
+
reverse = true
|
702
|
+
|
703
|
+
languages = [
|
704
|
+
{ 'name'=> 'C', 'author'=> 'Dennis Ritchie' },
|
705
|
+
{ 'name'=> 'C++', 'author'=> 'Bjarne Stroustrup' },
|
706
|
+
{ 'name'=> 'Perl', 'author'=> 'Larry Wall',
|
707
|
+
'guideline'=> 'TMTOWTDI - There\'s More Than One Way To Do It'},
|
708
|
+
{ 'name'=> 'Python', 'author'=> 'Guido van Rossum',
|
709
|
+
'guideline'=> 'There Should Be One Obvious Way To Do It' },
|
710
|
+
{ 'name'=> 'Ruby', 'author'=> 'Yukihiro Matsumoto',
|
711
|
+
'guideline'=> 'TPOL - The Principle Of Least Surprise'}
|
712
|
+
]
|
713
|
+
|
714
|
+
favorites = [
|
715
|
+
{ 'topic'=> 'Interesting Comic Books',
|
716
|
+
'items'=> [
|
717
|
+
{'title'=> 'Dropsie Avenue',
|
718
|
+
'creator'=> 'Will Eisner'},
|
719
|
+
{'title'=> 'Cerebus',
|
720
|
+
'creator'=> 'Dave Sim'},
|
721
|
+
{'title'=> 'Jar Of Fools',
|
722
|
+
'creator'=> 'Jason Lutes'}]},
|
723
|
+
{ 'topic'=> 'Favorite Albums',
|
724
|
+
'items'=> [
|
725
|
+
{'title'=> 'Amnesiac',
|
726
|
+
'creator'=> 'Radiohead'},
|
727
|
+
{'title'=> 'The Moon and Antarctica',
|
728
|
+
'creator'=> 'Modest Mouse'},
|
729
|
+
{'title'=> 'Dirt Track Date',
|
730
|
+
'creator'=> 'Southern Culture On The Skids'},
|
731
|
+
{'title'=> 'My Motor',
|
732
|
+
'creator'=> 'Dorkweed'},
|
733
|
+
{'title'=> 'Swordfishtrombones',
|
734
|
+
'creator'=> 'Tom Waits'}]}
|
735
|
+
]
|
736
|
+
|
737
|
+
page = PageTemplate.new(
|
738
|
+
'filename' => "tdata/complex.txt"
|
739
|
+
)
|
740
|
+
page.setParameter("title", title)
|
741
|
+
page.setParameter("ifTest", 1)
|
742
|
+
page.setParameter("languages", languages)
|
743
|
+
page.setParameter("favorites", favorites)
|
744
|
+
if reverse == 1
|
745
|
+
page.setParameter("reverse", 1)
|
746
|
+
end
|
747
|
+
|
748
|
+
assert(page.output)
|
749
|
+
end
|
750
|
+
|
751
|
+
def testCachedTemplate
|
752
|
+
assert(ct = PageTemplate.new(
|
753
|
+
'filename' => "tdata/complex.txt",
|
754
|
+
'use_cache' => true
|
755
|
+
))
|
756
|
+
|
757
|
+
languages = [
|
758
|
+
{ 'name'=> 'C', 'author'=> 'Dennis Ritchie' },
|
759
|
+
{ 'name'=> 'C++', 'author'=> 'Bjarne Stroustrup' },
|
760
|
+
{ 'name'=> 'Perl', 'author'=> 'Larry Wall',
|
761
|
+
'guideline'=> 'TMTOWTDI - There\'s More Than One Way To Do It'},
|
762
|
+
{ 'name'=> 'Python', 'author'=> 'Guido van Rossum',
|
763
|
+
'guideline'=> 'There Should Be One Obvious Way To Do It' },
|
764
|
+
{ 'name'=> 'Ruby', 'author'=> 'Yukihiro Matsumoto',
|
765
|
+
'guideline'=> 'TPOL - The Principle Of Least Surprise'}
|
766
|
+
]
|
767
|
+
|
768
|
+
favorites = [
|
769
|
+
{ 'topic'=> 'Interesting Comic Books',
|
770
|
+
'items'=> [
|
771
|
+
{'title'=> 'Dropsie Avenue',
|
772
|
+
'creator'=> 'Will Eisner'},
|
773
|
+
{'title'=> 'Cerebus',
|
774
|
+
'creator'=> 'Dave Sim'},
|
775
|
+
{'title'=> 'Jar Of Fools',
|
776
|
+
'creator'=> 'Jason Lutes'}]},
|
777
|
+
{ 'topic'=> 'Favorite Albums',
|
778
|
+
'items'=> [
|
779
|
+
{'title'=> 'Amnesiac',
|
780
|
+
'creator'=> 'Radiohead'},
|
781
|
+
{'title'=> 'The Moon and Antarctica',
|
782
|
+
'creator'=> 'Modest Mouse'},
|
783
|
+
{'title'=> 'Dirt Track Date',
|
784
|
+
'creator'=> 'Southern Culture On The Skids'},
|
785
|
+
{'title'=> 'My Motor',
|
786
|
+
'creator'=> 'Dorkweed'},
|
787
|
+
{'title'=> 'Swordfishtrombones',
|
788
|
+
'creator'=> 'Tom Waits'}]}
|
789
|
+
]
|
790
|
+
ct["languages"] = languages
|
791
|
+
ct["favorites"] = favorites
|
792
|
+
assert(ct.output)
|
793
|
+
assert(File.exists?("tdata/_complex.txt"))
|
794
|
+
system("rm -f tdata/_complex.txt")
|
795
|
+
|
796
|
+
end
|
797
|
+
|
798
|
+
def testClearFile
|
799
|
+
assert(@@template.clearFile)
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
class TC_Include < Test::Unit::TestCase
|
804
|
+
def testIncludeCommand()
|
805
|
+
ns = Namespace.new()
|
806
|
+
|
807
|
+
|
808
|
+
incCommand = IncludeCommand.new("tdata/include.1.txt")
|
809
|
+
text = File.open("tdata/include.1.txt").read()
|
810
|
+
assert_equal(text, incCommand.output(ns),
|
811
|
+
"IncludeCommands can be initialized with relative filenames")
|
812
|
+
|
813
|
+
text = File.open("tdata/include.2.txt").read()
|
814
|
+
incCommand = IncludeCommand.new("tdata/include.2.txt")
|
815
|
+
assert_equal(text, incCommand.output(ns))
|
816
|
+
|
817
|
+
# Including text with template markup.
|
818
|
+
ns["x"] = "Dude!"
|
819
|
+
pt = PageTemplate.new()
|
820
|
+
pt.load("tdata/include.3.txt")
|
821
|
+
pt["x"] = "Dude!"
|
822
|
+
incCommand = IncludeCommand.new("tdata/include.3.txt")
|
823
|
+
assert_equal(pt.output(), incCommand.output(ns),
|
824
|
+
"Include Commands can parse standard Template markup")
|
825
|
+
|
826
|
+
end
|
827
|
+
|
828
|
+
def testIncludePath
|
829
|
+
incCommand = IncludeCommand.new("include.4.txt", "tdata")
|
830
|
+
text = File.open("tdata/include.4.out.txt").read()
|
831
|
+
assert_equal(text, incCommand.output,
|
832
|
+
"IncludeCommand accepts an include path as a second arg")
|
833
|
+
|
834
|
+
pt = PageTemplate.new('include_path' => "tdata")
|
835
|
+
pt.load("tdata/include.4.txt")
|
836
|
+
pt["file"] = "include.4b.txt"
|
837
|
+
text = File.open("tdata/include.4.out.txt").read()
|
838
|
+
assert_equal(text, pt.output,
|
839
|
+
"Include Commands can be given a variable name as an argument")
|
840
|
+
|
841
|
+
end
|
842
|
+
|
843
|
+
def testIncludeSyntax
|
844
|
+
text = File.open("tdata/include.4.out.txt").read()
|
845
|
+
pt = PageTemplate.new("include_path" => "tdata")
|
846
|
+
pt.load("include.4.txt")
|
847
|
+
assert_equal(text, pt.output(),
|
848
|
+
"PageTemplate supports 'include' syntax")
|
849
|
+
pt = PageTemplate.new('include_path' => "tdata")
|
850
|
+
pt.load("include.5.txt")
|
851
|
+
assert_equal(text, pt.output(),
|
852
|
+
"PageTemplate supports 'include' syntax")
|
853
|
+
|
854
|
+
end
|
855
|
+
|
856
|
+
end
|
metadata
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.4
|
3
|
+
specification_version: 1
|
4
|
+
name: PageTemplate
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.1.1
|
7
|
+
date: 2005-02-16
|
8
|
+
summary: A simple templating system for Web sites.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: brian@coolnamehere.com
|
12
|
+
homepage: http://coolnamehere.com/products/pagetemplate
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: PageTemplate
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Brian Wisti
|
29
|
+
files:
|
30
|
+
- README.txt
|
31
|
+
test_files:
|
32
|
+
- TC_PageTemplate.rb
|
33
|
+
rdoc_options: []
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README.txt
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
requirements: []
|
39
|
+
dependencies: []
|