zenweb 2.18.1 → 3.0.0.b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +18 -0
  3. data/.gemtest +0 -0
  4. data/History.txt +6 -0
  5. data/Manifest.txt +52 -50
  6. data/README.txt +27 -22
  7. data/Rakefile +8 -9
  8. data/example-site/.isolate.rb +8 -0
  9. data/example-site/Rakefile +32 -0
  10. data/example-site/_config.yml +3 -0
  11. data/example-site/_includes/analytics.html.erb +11 -0
  12. data/example-site/_includes/header.html.erb +3 -0
  13. data/example-site/_includes/page_list_item.html +5 -0
  14. data/example-site/_includes/post_list_item.html +5 -0
  15. data/example-site/_layouts/post.erb +13 -0
  16. data/example-site/_layouts/project.erb +39 -0
  17. data/example-site/_layouts/site.erb +62 -0
  18. data/example-site/about/index.html.md +8 -0
  19. data/example-site/atom.xml.erb +43 -0
  20. data/example-site/blog/2012-01-02-page1.html.md +5 -0
  21. data/example-site/blog/2012-01-03-page2.html.md +5 -0
  22. data/example-site/blog/2012-01-04-page3.html.md +5 -0
  23. data/example-site/blog/_config.yml +1 -0
  24. data/example-site/blog/index.html.erb +19 -0
  25. data/example-site/config.ru +33 -0
  26. data/example-site/css/colors.css.less +71 -0
  27. data/example-site/css/styles.css +223 -0
  28. data/example-site/css/syntax.css +171 -0
  29. data/example-site/img/bg.png +0 -0
  30. data/example-site/index.html.erb +27 -0
  31. data/example-site/js/jquery.js +154 -0
  32. data/example-site/js/site.js +37 -0
  33. data/example-site/pages/index.html.erb +17 -0
  34. data/example-site/pages/nonblogpage.html.md +8 -0
  35. data/example-site/projects/index.html.erb +18 -0
  36. data/example-site/projects/zenweb.html.erb +9 -0
  37. data/example-site/sitemap.xml.erb +24 -0
  38. data/lib/zenweb.rb +12 -0
  39. data/lib/zenweb/config.rb +126 -0
  40. data/lib/zenweb/extensions.rb +51 -0
  41. data/lib/zenweb/page.rb +409 -0
  42. data/lib/zenweb/plugins/disqus.rb +18 -0
  43. data/lib/zenweb/plugins/erb.rb +43 -0
  44. data/lib/zenweb/plugins/google.rb +20 -0
  45. data/lib/zenweb/plugins/less.rb +10 -0
  46. data/lib/zenweb/plugins/markdown.rb +121 -0
  47. data/lib/zenweb/site.rb +237 -0
  48. data/lib/zenweb/tasks.rake +165 -0
  49. data/test/helper.rb +53 -0
  50. data/test/test_zenweb_config.rb +90 -0
  51. data/test/test_zenweb_extensions.rb +33 -0
  52. data/test/test_zenweb_page.rb +381 -0
  53. data/test/test_zenweb_plugins_disqus.rb +41 -0
  54. data/test/test_zenweb_plugins_erb.rb +60 -0
  55. data/test/test_zenweb_plugins_google.rb +38 -0
  56. data/test/test_zenweb_plugins_less.rb +33 -0
  57. data/test/test_zenweb_plugins_markdown.rb +227 -0
  58. data/test/test_zenweb_site.rb +294 -0
  59. metadata +230 -86
  60. metadata.gz.sig +0 -0
  61. data/bin/zenweb +0 -27
  62. data/bin/zenwebpage +0 -66
  63. data/bin/zenwebsite +0 -39
  64. data/design/REQUIREMENTS.txt +0 -52
  65. data/design/ZENWEB_2.txt +0 -69
  66. data/design/heirarchy.png +0 -0
  67. data/design/heirarchy.tgif +0 -311
  68. data/docs/Customizing +0 -76
  69. data/docs/FAQ +0 -12
  70. data/docs/Features +0 -128
  71. data/docs/Presentation +0 -88
  72. data/docs/QuickStart +0 -32
  73. data/docs/Renderers +0 -85
  74. data/docs/SiteMap +0 -13
  75. data/docs/YourOwnWebsite +0 -32
  76. data/docs/index +0 -14
  77. data/docs/metadata.txt +0 -10
  78. data/lib/ZenWeb.rb +0 -850
  79. data/lib/ZenWeb/CalendarRenderer.rb +0 -162
  80. data/lib/ZenWeb/CompactRenderer.rb +0 -45
  81. data/lib/ZenWeb/CompositeRenderer.rb +0 -63
  82. data/lib/ZenWeb/FileAttachmentRenderer.rb +0 -57
  83. data/lib/ZenWeb/FooterRenderer.rb +0 -38
  84. data/lib/ZenWeb/GenericRenderer.rb +0 -143
  85. data/lib/ZenWeb/HeaderRenderer.rb +0 -52
  86. data/lib/ZenWeb/HtmlRenderer.rb +0 -81
  87. data/lib/ZenWeb/HtmlTableRenderer.rb +0 -94
  88. data/lib/ZenWeb/HtmlTemplateRenderer.rb +0 -173
  89. data/lib/ZenWeb/MetadataRenderer.rb +0 -83
  90. data/lib/ZenWeb/RelativeRenderer.rb +0 -97
  91. data/lib/ZenWeb/RubyCodeRenderer.rb +0 -56
  92. data/lib/ZenWeb/SitemapRenderer.rb +0 -56
  93. data/lib/ZenWeb/StandardRenderer.rb +0 -40
  94. data/lib/ZenWeb/StupidRenderer.rb +0 -91
  95. data/lib/ZenWeb/SubpageRenderer.rb +0 -45
  96. data/lib/ZenWeb/TextToHtmlRenderer.rb +0 -219
  97. data/lib/ZenWeb/TocRenderer.rb +0 -60
  98. data/lib/ZenWeb/XXXRenderer.rb +0 -32
  99. data/test/SiteMap +0 -14
  100. data/test/Something +0 -4
  101. data/test/include.txt +0 -3
  102. data/test/index +0 -8
  103. data/test/metadata.txt +0 -10
  104. data/test/ryand/SiteMap +0 -10
  105. data/test/ryand/blah +0 -4
  106. data/test/ryand/blah-blah +0 -4
  107. data/test/ryand/index +0 -52
  108. data/test/ryand/metadata.txt +0 -2
  109. data/test/ryand/stuff/index +0 -4
  110. data/test/test_zenweb.rb +0 -1619
data/docs/index DELETED
@@ -1,14 +0,0 @@
1
- # "title" = "ZenWeb"
2
- # "subtitle" = "Demo and Instructions"
3
- # "description" = "Demo of ZenWeb"
4
- # "keywords" = "ZenWeb, Stuff"
5
-
6
- Welcome to ZenWeb. If you are viewing the plain-text version of this
7
- document, I urge you to run 'make' and view the HTML version
8
- instead. It at the very least helps demonstrate some of the
9
- capabilities of ZenWeb. After that, you might want to start with
10
- #{QuickStart}.
11
-
12
- Eventually, visit all of the subpages below to learn how to use
13
- ZenWeb. If I am missing anything or you'd like to make suggestions,
14
- email #{support}.
data/docs/metadata.txt DELETED
@@ -1,10 +0,0 @@
1
-
2
- 'renderers' = ['TocRenderer', 'HtmlTableRenderer', 'StandardRenderer', 'RelativeRenderer' ]
3
-
4
- 'QuickStart' = '<A HREF="QuickStart.html">QuickStart</A>'
5
- 'customizing' = '<A HREF="Customizing.html">customizing</A>'
6
- 'Features' = '<A HREF="Features.html">features</A>'
7
- 'TextToHTML' = '<A HREF="Features.html">Text-To-HTML</A>'
8
- 'Your Own Website' = '<A HREF="YourOwnWebsite.html">Your Own Website</A>'
9
- 'raa' = '<A HREF="http://www.ruby-lang.org/en/raa.html">Ruby Application Archive</A>'
10
- 'support' = '<A HREF="mailto:support-zenweb@ZenSpider.com">support</A>'
data/lib/ZenWeb.rb DELETED
@@ -1,850 +0,0 @@
1
- #!/usr/local/bin/ruby -w
2
-
3
- require 'fileutils'
4
-
5
- $TESTING = FALSE unless defined? $TESTING
6
-
7
- # this is due to a stupid bug across 1.6.4, 1.6.7, and 1.7.2.
8
- $PARAGRAPH_RE = Regexp.new( $/ * 2 + "+")
9
- $PARAGRAPH_END_RE = Regexp.new( "^" + $/ + "+")
10
-
11
- =begin
12
- = ZenWeb
13
-
14
- A set of classes for organizing and formating a collection of related
15
- documents.
16
-
17
- = SYNOPSIS
18
-
19
- ZenWeb.rb directory
20
-
21
- = DESCRIPTION
22
-
23
- A ZenWebsite is a collection of documents in one or more directories,
24
- organized by a sitemap. The sitemap references every document in the
25
- collection and maintains their order and hierarchy.
26
-
27
- Each directory may contain a metadata file of key/value pairs that can
28
- be used by ZenWeb and by the documents themselves. Each metadata file
29
- can override values from the metadata file in the parent
30
- directory. Each document can also define metadata, which will also
31
- override any values from the metadata files.
32
-
33
- ZenWeb processes the sitemap and in turn all related documents. ZenWeb
34
- uses a series of renderers (determined by metadata) to process the
35
- documents and writes the end result to disk.
36
-
37
- There are 5 major classes:
38
-
39
- * ((<Class ZenWebsite>))
40
- * ((<Class ZenDocument>))
41
- * ((<Class ZenSitemap>))
42
- * ((<Class Metadata>))
43
- * ((<Class GenericRenderer>))
44
-
45
- And many renderer classes, now located separately in the ZenWeb
46
- sub-directory. For example:
47
-
48
- * ((<Class SitemapRenderer>))
49
- * ((<Class HtmlRenderer>))
50
- * ((<Class HtmlTemplateRenderer>))
51
- * ((<Class TextToHtmlRenderer>))
52
- * ((<Class HeaderRenderer>))
53
- * ((<Class FooterRenderer>))
54
-
55
- =end
56
-
57
- =begin
58
-
59
- = Class ZenWebsite
60
-
61
- ZenWebsite is the top level class. It is responsible for driving the
62
- process.
63
-
64
- === Methods
65
-
66
- =end
67
-
68
- class ZenWebsite
69
-
70
- VERSION = '2.18.1'
71
-
72
- attr_reader :datadir, :htmldir, :sitemap
73
- attr_reader :documents if $TESTING
74
- attr_reader :doc_order if $TESTING
75
-
76
- =begin
77
-
78
- --- ZenWebsite.new(sitemapURL, datadir, htmldir)
79
-
80
- Creates a new ZenWebsite instance and preprocesses the sitemap and
81
- all referenced documents.
82
-
83
- =end
84
-
85
- def initialize(sitemapUrl, datadir, htmldir)
86
-
87
- unless (test(?d, datadir)) then
88
- raise ArgumentError, "datadir must be a valid directory"
89
- end
90
-
91
- @datadir = datadir
92
- @htmldir = htmldir
93
- @sitemap = ZenSitemap.new(sitemapUrl, self)
94
- @documents = @sitemap.documents
95
- @doc_order = @sitemap.doc_order
96
-
97
- # Tell each document to notify it's parent about itself.
98
- @doc_order.each { | url |
99
- doc = self[url]
100
- parentURL = doc.parentURL
101
- parentDoc = self[parentURL]
102
- if (parentDoc and parentURL != url) then
103
- parentDoc.addSubpage(doc.url)
104
- end
105
- }
106
-
107
- end
108
-
109
- =begin
110
-
111
- --- ZenWebsite#renderSite
112
-
113
- Iterates over all of the documents and asks them to
114
- ((<render|ZenDocument#render>)).
115
-
116
- =end
117
-
118
- def renderSite()
119
-
120
- puts "Generating website..." unless $TESTING
121
- force = false
122
- unless (test(?d, self.htmldir)) then
123
- FileUtils.mkdir_p self.htmldir
124
- else
125
- # NOTE: It would be better to know what was changed and only
126
- # rerender them and their previous and current immediate
127
- # relatives.
128
-
129
- # HACK: found a bug at the last minute. Looks minor, but I'm
130
- # disabling this in case it's too annoying.
131
- # force = self.sitemap.newerThanTarget
132
- end
133
-
134
- if force then
135
- puts "Sitemap modified, regenerating entire website." unless $TESTING
136
- end
137
-
138
- @doc_order.each { | url |
139
- doc = @documents[url]
140
-
141
- doc.render(force)
142
- }
143
-
144
- self
145
- end
146
-
147
- ############################################################
148
- # Accessors:
149
-
150
- =begin
151
-
152
- --- ZenWebsite#[](url)
153
-
154
- Accesses a document by url.
155
-
156
- =end
157
-
158
- def [](url)
159
- return @documents[url] || nil
160
- end
161
-
162
- =begin
163
-
164
- --- ZenWebsite.banner()
165
-
166
- Returns a string containing the ZenWeb banner including the version.
167
-
168
- =end
169
-
170
- def ZenWebsite.banner()
171
- return "ZenWeb v. #{ZenWebsite::VERSION} http://www.zenspider.com/ZSS/Products/ZenWeb/"
172
- end
173
-
174
- def top
175
- self[@doc_order.first]
176
- end
177
-
178
- end
179
-
180
- =begin
181
-
182
- = Class ZenDocument
183
- A ZenDocument is an object representing a unit of input data,
184
- typically a file. It may correspond to multiple output data (one
185
- document could create several HTML pages).
186
- === Methods
187
-
188
- =end
189
-
190
- class ZenDocument
191
-
192
- # 1.8 has a bug in it that causes MASSIVE slowdown with cyclic
193
- # object graphs. The fix has been submitted, but won't be released
194
- # until 1.8.2 or above. This is a hacky workaround that makes
195
- # running tolerable. I should come up with a better solution to deal
196
- # with debugging, but I haven't actually needed to debug in a while.
197
- # Basically, avoid ever showing the website or sitemap in an inspect.
198
-
199
- if false and VERSION =~ /^1\.8/ then
200
- def inspect
201
- return "<#{self.class}\@#{self.object_id}: #{self.url}>"
202
- end
203
- end
204
-
205
- # These are done manually:
206
- # attr_reader :datapath, :htmlpath, :metadata
207
- attr_reader :url, :subpages, :website, :content
208
- attr_writer :content if $TESTING
209
-
210
- =begin
211
-
212
- --- ZenDocument.new(url, website)
213
-
214
- Creates a new ZenDocument instance and preprocesses the metadata.
215
-
216
- =end
217
-
218
- def initialize(url, website)
219
-
220
- raise ArgumentError, "url was nil" if url.nil?
221
- raise ArgumentError, "web was nil" if website.nil?
222
-
223
- @url = url
224
- @website = website
225
- @datapath = nil
226
- @htmlpath = nil
227
- @subpages = []
228
- @content = ""
229
-
230
- unless (test(?f, self.datapath)) then
231
- raise ArgumentError, "url #{url} doesn't exist in #{self.datadir} (#{self.datapath})"
232
- end
233
-
234
- @metadata = nil
235
-
236
- end
237
-
238
- =begin
239
-
240
- --- ZenDocument#parseMetadata
241
-
242
- Opens the datafile and preparses the content for metadata. In a
243
- document, metadata has the basic form of "# key = val" where key
244
- and val are both proper ruby representations of the values in
245
- question. Eval is used to convert them from textual representation
246
- to an actual ruby object.
247
-
248
- =end
249
-
250
- def parseMetadata
251
- # 1) Open file
252
- # 2) Parse w/ generic parser for metadata, stripping it out.
253
- count = 0
254
-
255
- page = []
256
-
257
- IO.foreach(self.datapath) { | line |
258
- count += 1
259
- # REFACTOR: class Metadata also has this.
260
- if (line =~ /^\#\s*(\"(?:\\.|[^\"]+)\"|[^=]+)\s*=\s*(.*?)\s*$/) then
261
- begin
262
- key = $1
263
- val = $2
264
-
265
- key = eval(key)
266
- val = eval(val)
267
- rescue Exception
268
- $stderr.puts "#{self.datapath}:#{count}: eval failed: #{line}"
269
- else
270
- self[key] = val
271
- end
272
- else
273
- page.push(line)
274
- end
275
- }
276
-
277
- @content = page.join('')
278
- end
279
-
280
- =begin
281
-
282
- --- ZenDocument#renderContent
283
-
284
- Renders the content of the document by passing the content to a
285
- series of renderers. The renderers are specified by metadata as an
286
- array of strings and each one must implement the GenericRenderer
287
- interface.
288
-
289
- =end
290
-
291
- def renderContent()
292
-
293
- # FIX this is mainly here to force the rendering of the metadata,
294
- # which also forces the population of @content.
295
- title = self['title']
296
-
297
- # contents already preparsed for metadata
298
- result = self.content
299
-
300
- # 3) Use metadata to determine the rest of the renderers.
301
- renderers = self['renderers'] || [ 'GenericRenderer' ]
302
-
303
- # 4) For each renderer in list:
304
-
305
- renderers.each { | rendererName |
306
-
307
- # 4.1) Invoke a renderer by that name
308
-
309
- renderer = nil
310
- begin
311
-
312
- # try to find ZenWeb/blah.rb first, then just blah.rb.
313
- begin
314
- require "ZenWeb/#{rendererName}"
315
- rescue LoadError => loaderr
316
- require "#{rendererName}" # FIX: ruby requires the quotes?!?!
317
- end
318
-
319
- theClass = Module.const_get(rendererName)
320
- renderer = theClass.send("new", self)
321
- rescue LoadError, NameError => err
322
- raise NotImplementedError, "Renderer #{rendererName} is not implemented or loaded (#{err})"
323
- end
324
-
325
- # 4.2) Pass entire file contents to renderer and replace w/ result.
326
- newresult = renderer.render(result)
327
- result = newresult
328
- }
329
-
330
- return result
331
- end
332
-
333
- =begin
334
-
335
- --- ZenDocument#render(force)
336
-
337
- Gets the rendered content from ((<ZenDocument#renderContent>)) and
338
- writes it to disk if it decides to or is told to force the
339
- rendering. Returns true if it rendered the document.
340
-
341
- =end
342
-
343
- def render(force=false)
344
- if force or self['force'] or self.newerThanTarget then
345
-
346
- puts url unless $TESTING
347
-
348
- path = self.htmlpath
349
- dir = File.dirname(path)
350
-
351
- unless (test(?d, dir)) then
352
- FileUtils.mkdir_p dir
353
- end
354
-
355
- content = self.renderContent
356
- out = File.new(self.htmlpath, "w")
357
- out.print(content)
358
- out.close
359
- return true
360
- else
361
- return false
362
- end
363
- end
364
-
365
- =begin
366
-
367
- --- ZenDocument#newerThanTarget
368
-
369
- Returns true if the sourcefile is newer than the targetfile.
370
-
371
- =end
372
-
373
- def newerThanTarget()
374
- data = self.datapath
375
- html = self.htmlpath
376
-
377
- if test(?f, html) then
378
- return test(?>, data, html)
379
- else
380
- return true
381
- end
382
- end
383
-
384
- =begin
385
-
386
- --- ZenDocument#parentURL
387
-
388
- Returns the parent url of this document. That is either the
389
- index.html document of the current directory, or the parent
390
- directory.
391
-
392
- =end
393
-
394
- def parentURL()
395
- self.url.sub(/\/[^\/]+\/index.html$/, "/index.html").sub(/\/[^\/]+$/, "/index.html")
396
- end
397
-
398
- =begin
399
-
400
- --- ZenDocument#addSubpage
401
-
402
- Adds a url to the list of subpages of this document.
403
-
404
- =end
405
-
406
- def addSubpage(url)
407
- raise ArgumentError, "url must be a string" unless url.instance_of? String
408
- if (url != self.url) then
409
- self.subpages.push(url)
410
- end
411
- end
412
-
413
- ############################################################
414
- # Accessors:
415
-
416
- =begin
417
-
418
- --- ZenDocument#parent
419
-
420
- Returns the document object corresponding to the parentURL or
421
- itself if it IS the top.
422
-
423
- =end
424
-
425
- def parent
426
- parentURL = self.parentURL
427
- parent = (parentURL != self.url ? self.website[parentURL] : self)
428
- parent = self if parent.nil?
429
-
430
- return parent
431
- end
432
-
433
- =begin
434
-
435
- --- ZenDocument#dir
436
-
437
- Returns the path of the directory for this url.
438
-
439
- =end
440
-
441
- def dir()
442
- return File.dirname(self.datapath)
443
- end
444
-
445
- =begin
446
-
447
- --- ZenDocument#datapath
448
-
449
- Returns the full path to the data document.
450
-
451
- =end
452
-
453
- def datapath()
454
-
455
- if (@datapath.nil?) then
456
- datapath = "#{self.datadir}#{@url}"
457
- datapath.sub!(/\.html$/, "")
458
- datapath.sub!(/~/, "")
459
- @datapath = datapath
460
- end
461
-
462
- return @datapath
463
- end
464
-
465
- =begin
466
-
467
- --- ZenDocument#htmlpath
468
-
469
- Returns the full path to the rendered document.
470
-
471
- =end
472
-
473
- def htmlpath()
474
-
475
- if (@htmlpath.nil?) then
476
- htmlpath = "#{self.htmldir}#{@url}"
477
- htmlpath.sub!(/~/, "")
478
- @htmlpath = htmlpath
479
- end
480
-
481
- return @htmlpath
482
- end
483
-
484
- =begin
485
-
486
- --- ZenDocument#fulltitle
487
-
488
- Returns the concatination of the title and subtitle, if any.
489
-
490
- =end
491
-
492
- def fulltitle
493
- title = self.title
494
- subtitle = self['subtitle'] || nil
495
-
496
- return title + (subtitle ? ": " + subtitle : '')
497
- end
498
-
499
- def title
500
- self['title'] || "Unknown"
501
- end
502
-
503
- =begin
504
-
505
- --- ZenDocument#[](key)
506
-
507
- Returns the metadata corresponding to ((|key|)), or nil.
508
-
509
- =end
510
-
511
- def [](key)
512
- return self.metadata[key]
513
- end
514
-
515
- =begin
516
-
517
- --- ZenDocument#[]=(key, val)
518
-
519
- Sets the metadata value at ((|key|)) to ((|val|)).
520
-
521
- =end
522
-
523
- def []=(key, val)
524
- self.metadata[key] = val
525
- end
526
-
527
- =begin
528
-
529
- --- ZenDocument#metadata
530
-
531
- DOC
532
-
533
- =end
534
-
535
- def metadata
536
- if @metadata.nil? then
537
- @metadata = Metadata.new(self.dir, self.datadir)
538
- self.parseMetadata
539
- end
540
-
541
- return @metadata
542
- end
543
-
544
- =begin
545
-
546
- --- ZenDocument#datadir
547
-
548
- Returns the directory that all documents are read from.
549
-
550
- =end
551
-
552
- def datadir
553
- return self.website.datadir
554
- end
555
-
556
- =begin
557
-
558
- --- ZenDocument#htmldir
559
-
560
- Returns the directory that all rendered documents are written to.
561
-
562
- =end
563
-
564
- def htmldir
565
- return self.website.htmldir
566
- end
567
-
568
- end
569
-
570
- =begin
571
-
572
- = Class ZenSitemap
573
-
574
- A ZenSitemap is a type of ZenDocument represents a file that consists
575
- of lines of urls. Each of those urls will correspond to a file in the
576
- ((<datadir|ZenWebsite#datadir>)).
577
-
578
- A ZenSitemap is a ZenDocument that knows about the order and hierarchy
579
- of all of the other pages in the website.
580
-
581
- === Methods
582
-
583
- =end
584
-
585
- class ZenSitemap < ZenDocument
586
-
587
- attr_reader :documents, :doc_order
588
-
589
- =begin
590
-
591
- --- ZenSitemap.new(url, website)
592
-
593
- Creates a new ZenSitemap instance and processes the sitemap
594
- content instantiating a ZenDocument for every referenced document
595
- in the sitemap.
596
-
597
- =end
598
-
599
- def initialize(url, website)
600
- super(url, website)
601
-
602
- @documents = {}
603
- @doc_order = []
604
-
605
- self['title'] ||= "SiteMap"
606
- self['description'] ||= "This page links to every page in the website."
607
- self['keywords'] ||= "sitemap, website"
608
-
609
- count = 0
610
-
611
- IO.foreach(self.datapath) { |f|
612
- count += 1
613
- f.chomp!
614
-
615
- f.gsub!(/\s*\#.*/, '')
616
- f.strip!
617
-
618
- next if f == ""
619
-
620
- if f =~ /^\s*([\/-_~\.\w]+)$/
621
- url = $1
622
-
623
- if (url == self.url) then
624
- doc = self
625
- else
626
- doc = ZenDocument.new(url, @website)
627
- end
628
-
629
- self.documents[url] = doc
630
- self.doc_order.push(url)
631
- else
632
- $stderr.puts "WARNING on line #{count}: syntax error: '#{f}'"
633
- end
634
- }
635
-
636
- end # initialize
637
-
638
- end
639
-
640
- =begin
641
-
642
- = Class Metadata
643
-
644
- Metadata provides a hash whose content comes from a file whose name is
645
- fixed. Metadata will also be provided by metadata files in parent
646
- directories, up to a specified directory, or "/" by default.
647
-
648
- === Methods
649
-
650
- =end
651
-
652
- class Metadata < Hash
653
-
654
- RESERVED_WORDS=Regexp.new("\`|" + %w(^img ^link author banner bgcolor charset copyright description dtd email footer force head_extra header icbm(_title)? include keywords naked_page rating skipsubpages style stylesheet subtitle title).join("|"))
655
-
656
- @@metadata = {}
657
- @@count = {}
658
- @@count.default = 0
659
-
660
- =begin
661
-
662
- --- Metadata#displayBadMetadata
663
-
664
- Reports both unused metadata (only really good if you render the
665
- entire site) and metadata accessed but not defined (sometimes gets
666
- confused by legit ruby code).
667
-
668
- =end
669
-
670
- def self.displayBadMetadata
671
-
672
- good_key = {}
673
-
674
- puts
675
- puts "Unused metadata entries:"
676
- puts
677
- @@metadata.each do |file, metadata|
678
- puts "File = #{file}"
679
- metadata.each_key do |key|
680
- count = @@count[key]
681
- good_key[key] = true
682
- puts " #{key}" unless count > 0
683
- end
684
- end
685
-
686
- puts
687
- puts "Bad accesses:"
688
- puts
689
- @@count.each do |key, count|
690
- puts " #{key}: #{count}" unless good_key[key] or key =~ RESERVED_WORDS
691
- end
692
- end
693
-
694
- def [](key)
695
- @@count[key] += 1
696
- $stderr.puts " WARNING: metadata '#{key}' does not exist" unless $TESTING or key?(key) or key =~ RESERVED_WORDS
697
- super
698
- end
699
-
700
- @@path = {}
701
-
702
- =begin
703
-
704
- --- Metadata.new(directory, toplevel = "/")
705
-
706
- Instantiates a new metadata object and loads the data from
707
- ((|directory|)) up to the ((|toplevel|)) directory.
708
-
709
- =end
710
-
711
- def initialize(directory, toplevel = "/")
712
- super()
713
-
714
- self.default = nil
715
-
716
- unless (test(?e, directory)) then
717
- raise ArgumentError, "directory #{directory} does not exist"
718
- end
719
-
720
- unless (test(?d, toplevel)) then
721
- raise ArgumentError, "toplevel directory #{toplevel} does not exist"
722
- end
723
-
724
- # Check that toplevel is ABOVE directory, not below. Can be equal.
725
- unless @@path.include? directory then
726
- abs_dir = File.expand_path(directory)
727
- @@path[directory] = abs_dir
728
- else
729
- abs_dir = @@path[directory]
730
- end
731
-
732
- unless @@path.include? toplevel then
733
- abs_top = File.expand_path(toplevel)
734
- @@path[toplevel] = abs_top
735
- else
736
- abs_top = @@path[toplevel]
737
- end
738
-
739
- if (abs_top.length > abs_dir.length || abs_dir.index(abs_top) != 0) then
740
- raise ArgumentError, "toplevel is not a parent dir to directory"
741
- end
742
-
743
- if (test(?f, directory)) then
744
- directory = File.dirname(directory)
745
- end
746
-
747
- self.loadFromDirectory(directory, toplevel)
748
- end
749
-
750
- =begin
751
-
752
- --- Metadata#loadFromDirectory(directory, toplevel, count=1)
753
-
754
- Loads a series of metadata files from the directory ((|toplevel|))
755
- down to ((|directory|)). Each load in turn may override previous
756
- values.
757
-
758
- =end
759
-
760
- def loadFromDirectory(directory, toplevel, count = 1)
761
-
762
- raise "too many recursions" if (count > 20)
763
-
764
- if (directory != toplevel && directory != "/" && directory != ".") then
765
- # Recurse to parent directory. Increment count for basic loop protection.
766
- self.loadFromDirectory(File.dirname(directory), toplevel, count + 1)
767
- end
768
-
769
- file = directory + "/" + "metadata.txt"
770
- if (test(?f, file)) then
771
- self.load(file)
772
- end
773
-
774
- end
775
-
776
- =begin
777
-
778
- --- Metadata#load(file)
779
-
780
- Loads a specific file ((|file|)). If any keys already exist that
781
- are specifed in the file, then they are overridden.
782
-
783
- =end
784
-
785
- def load(file)
786
-
787
- count = 0
788
-
789
- unless (@@metadata[file]) then
790
- hash = {}
791
-
792
- IO.foreach(file) { | line |
793
- count += 1
794
- if (line =~ /^\s*(\"(?:\\.|[^\"]+)\"|[^=]+)\s*=\s*(.*?)\s*$/) then
795
-
796
- # REFACTEE: this is duplicated from above
797
- begin
798
- key = $1
799
- val = $2
800
-
801
- key = eval(key)
802
- val = eval(val)
803
- rescue Exception
804
- $stderr.puts "WARNING on line #{count}: eval failed: #{line}: #{$!}"
805
- else
806
- hash[key] = val
807
- end
808
- elsif (line =~ /^\s*$/) then
809
- # ignore
810
- elsif (line =~ /^\#.*$/) then
811
- # ignore
812
- else
813
- $stderr.puts "WARNING on line #{count}: cannot parse: #{line}"
814
- end
815
- }
816
- @@metadata[file] = hash
817
- end
818
-
819
- self.update(@@metadata[file])
820
-
821
- end
822
-
823
- end
824
-
825
- ############################################################
826
- # Object methods - shortcuts for users
827
-
828
- =begin
829
-
830
- --- link(url, title)
831
-
832
- Returns a string with an anchor with the appropriate data.
833
-
834
- =end
835
-
836
- def link(url, title)
837
- return "<A HREF=\"#{url}\">#{title}</A>"
838
- end
839
-
840
- =begin
841
-
842
- --- img(url, alt, height=0, width=0, border=0)
843
-
844
- Returns a string with an image tag with the appropriate data.
845
-
846
- =end
847
-
848
- def img(url, alt, height=nil, width=nil, border=0)
849
- return "<IMG SRC=\"#{url}\" ALT=\"#{alt}\""+(height ? " HEIGHT=#{height}" : '')+(width ? " WIDTH=#{width}" : '')+">"
850
- end