zenweb 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +426 -0
  3. data/Manifest.txt +54 -0
  4. data/README.txt +63 -0
  5. data/Rakefile +22 -0
  6. data/bin/zenweb +27 -0
  7. data/bin/zenwebpage +66 -0
  8. data/bin/zenwebsite +39 -0
  9. data/design/REQUIREMENTS.txt +52 -0
  10. data/design/ZENWEB_2.txt +69 -0
  11. data/design/heirarchy.png +0 -0
  12. data/design/heirarchy.tgif +311 -0
  13. data/docs/Customizing +76 -0
  14. data/docs/FAQ +12 -0
  15. data/docs/Features +128 -0
  16. data/docs/Presentation +88 -0
  17. data/docs/QuickStart +32 -0
  18. data/docs/Renderers +85 -0
  19. data/docs/SiteMap +13 -0
  20. data/docs/YourOwnWebsite +32 -0
  21. data/docs/index +14 -0
  22. data/docs/metadata.txt +10 -0
  23. data/lib/ZenWeb.rb +850 -0
  24. data/lib/ZenWeb/CalendarRenderer.rb +162 -0
  25. data/lib/ZenWeb/CompactRenderer.rb +45 -0
  26. data/lib/ZenWeb/CompositeRenderer.rb +63 -0
  27. data/lib/ZenWeb/FileAttachmentRenderer.rb +57 -0
  28. data/lib/ZenWeb/FooterRenderer.rb +38 -0
  29. data/lib/ZenWeb/GenericRenderer.rb +143 -0
  30. data/lib/ZenWeb/HeaderRenderer.rb +52 -0
  31. data/lib/ZenWeb/HtmlRenderer.rb +81 -0
  32. data/lib/ZenWeb/HtmlTableRenderer.rb +94 -0
  33. data/lib/ZenWeb/HtmlTemplateRenderer.rb +173 -0
  34. data/lib/ZenWeb/MetadataRenderer.rb +83 -0
  35. data/lib/ZenWeb/RelativeRenderer.rb +98 -0
  36. data/lib/ZenWeb/RubyCodeRenderer.rb +56 -0
  37. data/lib/ZenWeb/SitemapRenderer.rb +56 -0
  38. data/lib/ZenWeb/StandardRenderer.rb +40 -0
  39. data/lib/ZenWeb/StupidRenderer.rb +88 -0
  40. data/lib/ZenWeb/SubpageRenderer.rb +45 -0
  41. data/lib/ZenWeb/TextToHtmlRenderer.rb +219 -0
  42. data/lib/ZenWeb/TocRenderer.rb +61 -0
  43. data/lib/ZenWeb/XXXRenderer.rb +32 -0
  44. data/test/SiteMap +14 -0
  45. data/test/Something +4 -0
  46. data/test/include.txt +3 -0
  47. data/test/index +8 -0
  48. data/test/metadata.txt +10 -0
  49. data/test/ryand/SiteMap +10 -0
  50. data/test/ryand/blah +4 -0
  51. data/test/ryand/blah-blah +4 -0
  52. data/test/ryand/index +52 -0
  53. data/test/ryand/metadata.txt +2 -0
  54. data/test/ryand/stuff/index +4 -0
  55. data/test/test_zenweb.rb +1624 -0
  56. metadata +161 -0
  57. metadata.gz.sig +0 -0
@@ -0,0 +1,162 @@
1
+ # this is a simple template. Globally replace Calendar with the name of
2
+ # your renderer and then go fill in YYY with the appropriate content.
3
+
4
+ require 'ZenWeb/GenericRenderer'
5
+ require 'date' # which requires rational
6
+ require 'time'
7
+
8
+ # class Integer
9
+ # alias :slowgcd :gcd
10
+ # def gcd(n)
11
+ # m = abs
12
+ # while n != 0
13
+ # m %= n
14
+ # tmp = m; m = n; n = tmp
15
+ # end
16
+ # m.abs
17
+ # end
18
+ # end
19
+
20
+ # require 'tally'
21
+ # class Integer
22
+ # tally :gcd, true
23
+ # end
24
+
25
+ =begin
26
+
27
+ = Class CalendarRenderer
28
+
29
+ DOC
30
+
31
+ === Methods
32
+
33
+ =end
34
+
35
+ class CalendarRenderer < GenericRenderer
36
+
37
+ DAYS_IN_MONTH = [
38
+ [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
39
+ [nil, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
40
+ ]
41
+
42
+ =begin
43
+
44
+ --- CalendarRenderer#render(content)
45
+
46
+ DOC
47
+
48
+ =end
49
+
50
+ def render(content)
51
+ events = Hash.new { |h,k| h[k] = [] }
52
+ reverse = false
53
+ self.scan_region(content, /<cal/i, /<\/cal>/i) do |line, context|
54
+ case context
55
+ when :START then
56
+ reverse = true if line =~ /<cal\s+reverse\s*>/i
57
+ when :END then
58
+ self.generate_calendars(events, reverse)
59
+ else
60
+ if line =~ /(\d\d\d\d-\d\d-\d\d):\s*(.*)/ then
61
+ description = $2
62
+ time = Time.parse($1) # NOT Date! hellishly slow!
63
+ events[$1] << description
64
+ end
65
+ end
66
+ end
67
+
68
+ return self.result
69
+ end
70
+
71
+ def generate_calendar(year, month, events)
72
+
73
+ current_events = []
74
+
75
+ which_year = Date.leap?(year) ? 1 : 0
76
+ date_start = Date.civil(year, month, 1)
77
+ last_day = DAYS_IN_MONTH[which_year][month]
78
+ date_end = Date.civil(year, month, -1)
79
+
80
+ push "<table class=\"calendar\">"
81
+ push "<tr>"
82
+ push "<td valign=\"top\">" # calendar
83
+
84
+ m2 = "%02d" % month
85
+ push "<table class=\"view y#{year} m#{m2}\">\n"
86
+
87
+ long_month_name = Date::MONTHNAMES[month]
88
+ month_name = Date::ABBR_MONTHNAMES[month].downcase
89
+
90
+ push "<tr class=\"title\">\n"
91
+ push "<th colspan=7>#{long_month_name} #{year}</th>\n"
92
+ push "</tr>\n"
93
+
94
+ push "<tr class=\"weektitle\"\n"
95
+ push Date::ABBR_DAYNAMES.map { |d| "<th class=\"#{d.downcase}\">#{d}</th>" }.join("\n")
96
+ push "</tr>\n"
97
+
98
+ dow_start = date_start.wday
99
+ push "<tr class=\"days firstweek\">\n"
100
+ push "<td colspan=#{dow_start}>&nbsp;</td>\n" unless dow_start == 0
101
+
102
+ last_sunday = date_end.day - date_end.wday + 1
103
+
104
+ week = 1
105
+ wday = dow_start
106
+
107
+ day_last = date_end.day
108
+
109
+ 1.upto(day_last) do |day|
110
+
111
+ event=""
112
+ cal = Time.local(year, month, day).strftime("%Y-%m-%d")
113
+ if events.has_key? cal then
114
+ current_events << "<li>#{cal}:\n<ul>\n"
115
+ events[cal].each do |description|
116
+ current_events << "<li>#{description}\n"
117
+ end
118
+ current_events << "</ul>\n"
119
+ event=" event"
120
+ end
121
+
122
+ dow = Date::ABBR_DAYNAMES[(day + dow_start - 1) % 7].downcase
123
+ d2 = "%02d" % day
124
+ push "<td class=\"d#{d2} #{dow}#{event}\">#{day}</td>\n"
125
+
126
+ if day != day_last and wday == 6 then
127
+ push "</tr>\n"
128
+ unless day == last_sunday then
129
+ push "<tr class=\"days\">\n"
130
+ else
131
+ push "<tr class=\"days lastweek\">\n"
132
+ end
133
+ week += 1
134
+ end
135
+
136
+ wday += 1
137
+ wday = 0 if wday >= 7 # remember 0..6
138
+ end
139
+
140
+ day_count = 7-date_end.wday-1
141
+ push "<td colspan=#{day_count}>&nbsp;</td>\n" unless day_count == 0
142
+ push "</tr>\n"
143
+ push "</table>\n"
144
+ push "</td>\n" # /calendar
145
+ push "<td class=\"eventlist\">\n" # events
146
+ push "<ul>\n"
147
+ push current_events.join('')
148
+ push "</ul>\n"
149
+ push "</td>\n" # /events
150
+ push "</tr>\n"
151
+ push "</table>\n"
152
+ end
153
+
154
+ def generate_calendars(events, should_reverse=false)
155
+ active_months = events.keys.map { |d| d[0..6] }.sort.uniq
156
+ active_months = active_months.reverse if should_reverse
157
+ active_months.each do |ym|
158
+ year, month = ym.split(/-/).map { |n| n.to_i }
159
+ self.generate_calendar(year, month, events)
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,45 @@
1
+ #
2
+ #
3
+
4
+ require 'ZenWeb/GenericRenderer'
5
+
6
+ =begin
7
+
8
+ = Class CompactRenderer
9
+
10
+ CompactRenderer compacts HTML whitespace and comments to minimize how much text gets served.
11
+
12
+ === Methods
13
+
14
+ =end
15
+
16
+ class CompactRenderer < GenericRenderer
17
+
18
+ =begin
19
+
20
+ --- CompactRenderer#render(content)
21
+
22
+ Compacts HTML blah blah DOC
23
+
24
+ =end
25
+
26
+ def render(content)
27
+
28
+ # protect pre blocks
29
+ content = content.gsub(/(<pre>)([\s\S]*?)(<\/pre>)/i) do
30
+ p1 = $1
31
+ body = $2
32
+ p2 = $3
33
+ body = body.gsub(/\n/, 1.chr).gsub(/ /, 2.chr)
34
+ p1 + body + p2
35
+ end
36
+
37
+ content = content.gsub(/\n\r/, '').gsub(/\s+/, ' ').gsub(/> </, '><').strip
38
+ content = content.gsub(1.chr, "\n").gsub(2.chr, " ")
39
+
40
+ push(content)
41
+
42
+ return self.result
43
+ end
44
+
45
+ end
@@ -0,0 +1,63 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ =begin
4
+
5
+ = Class CompositeRenderer
6
+
7
+ Allows multiple renderers to be plugged into a single renderer.
8
+
9
+ === Methods
10
+
11
+ =end
12
+
13
+ class CompositeRenderer < GenericRenderer
14
+
15
+ attr_reader :renderers
16
+
17
+ =begin
18
+
19
+ --- CompositeRenderer#new(document)
20
+
21
+ Creates a new CompositeRenderer.
22
+
23
+ =end
24
+
25
+ def initialize(document)
26
+ super(document)
27
+ @renderers = []
28
+ end
29
+
30
+ =begin
31
+
32
+ --- CompositeRenderer#render(content)
33
+
34
+ Renders by running all of the renderers in sequence.
35
+
36
+ =end
37
+
38
+ def render(content)
39
+ @renderers.each { | renderer |
40
+ content = renderer.render(content)
41
+ }
42
+ return content
43
+ end
44
+
45
+ =begin
46
+
47
+ --- CompositeRenderer#addRenderer(renderer)
48
+
49
+ Adds renderer to the list of renderers used by this composite.
50
+
51
+ =end
52
+
53
+ def addRenderer(renderer)
54
+
55
+ if (renderer.nil? or ! renderer.kind_of? GenericRenderer) then
56
+ raise ArgumentError, "You may only add an instance of GenericRenderer"
57
+ end
58
+
59
+ @renderers.push(renderer)
60
+ end
61
+
62
+ end
63
+
@@ -0,0 +1,57 @@
1
+ # this is a simple template. Globally replace FileAttachment with the name of
2
+ # your renderer and then go fill in YYY with the appropriate content.
3
+
4
+ require 'ZenWeb/GenericRenderer'
5
+
6
+ =begin
7
+
8
+ = Class FileAttachmentRenderer
9
+
10
+ Finds content between <file name="name">...</file> tags. Writes the
11
+ content to a file of the given name and includes a link to the file.
12
+
13
+ === Methods
14
+
15
+ =end
16
+
17
+ class FileAttachmentRenderer < GenericRenderer
18
+
19
+ =begin
20
+
21
+ --- FileAttachmentRenderer#render(content)
22
+
23
+ YYY
24
+
25
+ =end
26
+
27
+ def render(content)
28
+
29
+ start_re = /<file\s+name\s*=\s*\"([\w\.-]+)\"\s*>/i
30
+ end_re = /<\/file>/i
31
+
32
+ file_content = []
33
+ name = nil
34
+ self.scan_region(content, start_re, end_re) do |line, context|
35
+ case context
36
+ when :START then
37
+ name = $1 if line =~ /name\s*=\s*\"([\w\.-]+)\"/i
38
+ when :END then
39
+ raise "name is undefined, add name= attribute" if name.nil?
40
+ dir = File.dirname @document.htmlpath
41
+ path = File.join(dir, name)
42
+ push "\n"
43
+ push "<A HREF=\"#{name}\">Download #{name}</A>\n"
44
+ File.open(path, "w") do |file|
45
+ file.print file_content.join('')
46
+ end
47
+ file_content = []
48
+ else
49
+ file_content.push line
50
+ push " " + line
51
+ end
52
+ end
53
+
54
+ return self.result.strip
55
+ end
56
+
57
+ end
@@ -0,0 +1,38 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ =begin
4
+
5
+ = Class FooterRenderer
6
+
7
+ Inserts a footer based on metadata.
8
+
9
+ === Methods
10
+
11
+ =end
12
+
13
+ class FooterRenderer < GenericRenderer
14
+
15
+ =begin
16
+
17
+ --- FooterRenderer#render(content)
18
+
19
+ Adds a footer if the ((|footer|)) metadata item exists. If the
20
+ document contains a BODY close HTML tag, then the footer
21
+ immediately precedes it, otherwise it is simply at the bottom.
22
+
23
+ =end
24
+
25
+ def render(content)
26
+
27
+ footer = @document['footer'] || nil
28
+
29
+ if footer then
30
+ content.sub!(/(<\/BODY>|\z)/i) {
31
+ footer + $1
32
+ }
33
+ end
34
+
35
+ return content
36
+ end
37
+ end
38
+
@@ -0,0 +1,143 @@
1
+ $TESTING = FALSE unless defined? $TESTING
2
+
3
+ =begin
4
+
5
+ = Class GenericRenderer
6
+
7
+ A GenericRenderer provides an interface for all renderers. It renders
8
+ nothing itself.
9
+
10
+ === Methods
11
+
12
+ =end
13
+
14
+ class GenericRenderer
15
+
16
+ =begin
17
+
18
+ --- GenericRenderer.new(document)
19
+
20
+ Instantiates a generic renderer with a reference to
21
+ ((|document|)), it\'s website and sitemap.
22
+
23
+ =end
24
+
25
+ # REFACTOR: do not take a document at all
26
+ def initialize(document)
27
+ @document = document
28
+ @website = @document.website
29
+ @sitemap = @website.sitemap
30
+ @result = []
31
+ end
32
+
33
+ =begin
34
+
35
+ --- GenericRenderer#push(obj)
36
+
37
+ Pushes a string representation of ((|obj|)) onto the result
38
+ array. If ((|obj|)) is an array, it iterates each item and pushes
39
+ them (recursively). If it is not an array, it pushes (({obj.to_s})).
40
+
41
+ =end
42
+
43
+ def push(obj)
44
+ if obj.is_a?(Array) then
45
+ stuff = obj.flatten
46
+ @result.push(*stuff) unless stuff.empty?
47
+ else
48
+ if false then
49
+ @result.push(obj.to_s)
50
+ else
51
+ @result.push(obj)
52
+ end
53
+ end
54
+ end
55
+
56
+ =begin
57
+
58
+ --- GenericRenderer#unshift(obj)
59
+
60
+ Same as ((<GenericRenderer#push>)) but prepends instead of appends.
61
+
62
+ =end
63
+
64
+ def unshift(obj)
65
+ if obj.is_a?(Array) then
66
+ obj.reverse.each { | item |
67
+ self.unshift(item)
68
+ }
69
+ else
70
+ @result.unshift(obj.to_s)
71
+ end
72
+
73
+ end
74
+
75
+ # DOC GenericRenderer#result
76
+ def result(clear=true)
77
+ result = @result.join('')
78
+ @result = [] if clear
79
+ return result
80
+ end
81
+
82
+ =begin
83
+
84
+ --- GenericRenderer#render(content)
85
+
86
+ Renders the content. Does nothing in GenericRenderer, but is
87
+ expected to be overridden by subclasses. ((|content|)) is an array
88
+ of strings and render must return an array of strings.
89
+
90
+ NEW: the argument and result are now a single string!
91
+
92
+ =end
93
+
94
+ # REFACTOR: pass in content and document to render
95
+ def render(content)
96
+ return content
97
+ end
98
+
99
+ def each_paragraph(content)
100
+ content.scan(/.+?(?:#{$/}#{$/}+|\Z)/m) do |block|
101
+ $stderr.puts "BLOCK = #{block.inspect}" if $DEBUG
102
+ yield(block)
103
+ end
104
+ end
105
+
106
+ def each_paragraph_matching(content, pattern)
107
+ $stderr.puts "CONTENT = #{content.inspect}" if $DEBUG
108
+ self.each_paragraph(content) do |block|
109
+ $stderr.puts "PARAGRAPH = #{block.inspect}" if $DEBUG
110
+ if block =~ pattern then
111
+ yield(block)
112
+ else
113
+ push block
114
+ end
115
+ end
116
+ end
117
+
118
+ def scan_region(content, region_start, region_end)
119
+ matching = false
120
+ content.scan(/.*#{$/}?/) do |l|
121
+ # TODO: detect region_end w/o start and freak
122
+ # TODO: detect nesting and freak
123
+ if l =~ region_start then
124
+ matching = true
125
+ $stderr.puts :START, l.inspect if $DEBUG
126
+ yield(l, :START)
127
+ matching = false if l =~ region_end
128
+ elsif l =~ region_end then
129
+ matching = false
130
+ $stderr.puts :END, l.inspect if $DEBUG
131
+ yield(l, :END)
132
+ elsif matching then
133
+ $stderr.puts :MIDDLE, l.inspect if $DEBUG
134
+ yield(l, :MIDDLE)
135
+ else
136
+ $stderr.puts :IGNORED, l.inspect if $DEBUG
137
+ push l
138
+ end
139
+ end
140
+ end
141
+
142
+ end
143
+