PageTemplate 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.txt +85 -0
  2. data/TC_PageTemplate.rb +856 -0
  3. 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)
@@ -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: []