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,98 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ $Uri_Implemented = true
4
+ if RUBY_VERSION =~ /1.6.(\d+)/ then
5
+ $Uri_Implemented = $1.to_i >= 7
6
+ end
7
+
8
+ if $Uri_Implemented then
9
+ require 'uri'
10
+ else
11
+ if $TESTING then
12
+ $stderr.puts "WARNING: RelativeRenderer can not be implemented in ruby versions < 1.6.7."
13
+ $stderr.puts "Some unit tests will fail as a result"
14
+ end
15
+ end
16
+
17
+ =begin
18
+
19
+ = Class RelativeRenderer
20
+
21
+ Converts urls to relative urls if possible...
22
+
23
+ === Methods
24
+
25
+ =end
26
+
27
+ class RelativeRenderer < GenericRenderer
28
+
29
+ =begin
30
+
31
+ --- RelativeRenderer.new(document)
32
+
33
+ Instantiates RelativeRenderer.
34
+
35
+ =end
36
+
37
+ def initialize(document)
38
+ super(document)
39
+
40
+ if $Uri_Implemented then
41
+ # fake, since we don't know the domain (or care), but necessary for URI#-
42
+ # it bombs otherwise... fun.
43
+ @base = URI.parse("http://www.domain.com/")
44
+
45
+ # @base + url will == url if url is not relative...
46
+ @docurl = @base + URI.parse(@document.url)
47
+ end
48
+ end
49
+
50
+ =begin
51
+
52
+ --- RelativeRenderer#render(content)
53
+
54
+ Converts urls that look like they can be made relative to be so...
55
+
56
+ =end
57
+
58
+ def render(content)
59
+ if $Uri_Implemented then
60
+ content.each { | line |
61
+
62
+ line.gsub!(%r%(href=\")([^\"]+)(\")%i) { |url|
63
+ front = $1
64
+ oldurl = $2
65
+ back = $3
66
+ newurl = convert(oldurl)
67
+
68
+ front + newurl + back
69
+ }
70
+
71
+ push(line)
72
+ }
73
+
74
+ return self.result
75
+ else
76
+ return content
77
+ end
78
+ end
79
+
80
+ def convert(u)
81
+
82
+ if $Uri_Implemented and (u[0].chr != '#') then
83
+ oldurl = URI.parse(u)
84
+
85
+ if oldurl.relative? then
86
+ oldurl = @base + oldurl
87
+ scheme = oldurl.scheme
88
+ newurl = oldurl - @docurl
89
+ else
90
+ newurl = u
91
+ end
92
+ return newurl.to_s
93
+ else
94
+ return u
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,56 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ =begin
4
+
5
+ = Class RubyCodeRenderer
6
+
7
+ Finds paragraphs prefixed with "!" and evaluates them with xmp
8
+
9
+ === Methods
10
+
11
+ =end
12
+
13
+ class RubyCodeRenderer < GenericRenderer
14
+
15
+ =begin
16
+
17
+ --- RubyCodeRenderer#render(content)
18
+
19
+ Finds paragraphs prefixed with "!" and evaluates them with xmp
20
+
21
+ =end
22
+
23
+ def render(content)
24
+
25
+ text = content.split($PARAGRAPH_RE)
26
+
27
+ text.each do | p |
28
+
29
+ if p =~ /^\s*\!/m then
30
+ p.gsub!(/^\s*\!\s*/, '')
31
+
32
+ begin
33
+ cmd = "irb --prompt xmp --noreadline 2>/dev/null"
34
+ puts "Running irb for code:\n#{p}" unless $TESTING
35
+ IO.popen(cmd, "r+") do |xmp|
36
+ xmp.puts(p + "\nexit")
37
+ result = xmp.read
38
+ result.gsub!(/\s+>> exit\s*\Z/, '')
39
+ result.gsub!(/=>(.*)\Z/m, '=><EM>\1</EM>')
40
+ push result
41
+ end
42
+ rescue Exception => something
43
+ $stderr.puts "xmp: #{something}\nTrace =\n" + $@.join("\n") + "\n"
44
+ end
45
+ else
46
+ push p
47
+ end
48
+ push ''
49
+ end
50
+
51
+ # put it back into line-by-line format
52
+ @result = @result.join("\n").scan(/^.*[\n\r]+/)
53
+
54
+ return self.result
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ =begin
4
+
5
+ = Class SitemapRenderer
6
+
7
+ Converts a sitemap file into output suitable for
8
+ ((<Class TextToHtmlRenderer>)).
9
+
10
+ === Methods
11
+
12
+ =end
13
+
14
+ class SitemapRenderer < GenericRenderer
15
+
16
+ =begin
17
+
18
+ --- SitemapRenderer#render(content)
19
+
20
+ Converts a sitemap file into output suitable for ((<Class TextToHtmlRenderer>)).
21
+
22
+ =end
23
+
24
+ def render(content)
25
+
26
+ # used for /~user/blah.html pages
27
+ # basically, we need to strip off whatever the base of the sitemap is to
28
+ # make sure we indent everything to the right level.
29
+ base = @sitemap.url
30
+ base = base.sub(%r%/[^/]*$%, '/')
31
+
32
+ urls = @sitemap.doc_order.clone
33
+
34
+ @document['subtitle'] ||= "There are #{urls.size} pages in this website."
35
+ urls.each { | url |
36
+
37
+ indent = url.sub(/\.html$/, "")
38
+ indent.sub!(/#{base}/, "")
39
+ indent.sub!(/\/index$/, "")
40
+ indent.sub!(/^\//, "")
41
+ indent.gsub!(/[^\/]+\//, "\t")
42
+
43
+ if indent =~ /^(\t*).*/ then
44
+ indent = $1
45
+ end
46
+
47
+ doc = @website[url]
48
+ title = doc.fulltitle
49
+
50
+ push("#{indent}+ <A HREF=\"#{url}\">#{title}</A>\n")
51
+ }
52
+
53
+ return self.result
54
+ end
55
+ end
56
+
@@ -0,0 +1,40 @@
1
+ require 'ZenWeb/CompositeRenderer'
2
+ require 'ZenWeb/SubpageRenderer'
3
+ require 'ZenWeb/MetadataRenderer'
4
+ require 'ZenWeb/TextToHtmlRenderer'
5
+ require 'ZenWeb/HtmlTemplateRenderer'
6
+ require 'ZenWeb/FooterRenderer'
7
+
8
+ =begin
9
+
10
+ = Class StandardRenderer
11
+
12
+ Creates a fairly standard webpage using several different renderers.
13
+
14
+ === Methods
15
+
16
+ =end
17
+
18
+ class StandardRenderer < CompositeRenderer
19
+
20
+ =begin
21
+
22
+ --- StandardRenderer#new(document)
23
+
24
+ Creates a new StandardRenderer.
25
+
26
+ =end
27
+
28
+ def initialize(document)
29
+ super(document)
30
+
31
+ # TODO: make this a metadata variable
32
+ self.addRenderer(SubpageRenderer.new(document))
33
+ self.addRenderer(MetadataRenderer.new(document))
34
+ self.addRenderer(TextToHtmlRenderer.new(document))
35
+ self.addRenderer(HtmlTemplateRenderer.new(document))
36
+ self.addRenderer(FooterRenderer.new(document))
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,88 @@
1
+ # this is a simple template. Globally replace Stupid 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 StupidRenderer
9
+
10
+ Maniplates the text as a whole, in really stupid ways. Currently, as
11
+ a fun demo of metadata, we have it using the variable 'stupidmethod'
12
+ to determine what it does. There are two actions possible:
13
+
14
+ + strip - strips vowels from the text. Good compression! :)
15
+ + leet - does a horrid job of making the text 7337. Scary.
16
+
17
+ === Methods
18
+
19
+ =end
20
+
21
+ $Transcode = {
22
+ 'a' => '4', 'b' => '|3', 'c' => '<', 'd' => '|)', 'e' => '3',
23
+ 'f' => 'F', 'g' => 'G', 'h' => ']-[', 'i' => '|', 'j' => 'J',
24
+ 'k' => ']<', 'l' => 'L', 'm' => '/\/\\', 'n' => '/\/', 'o' => '0',
25
+ 'p' => 'P', 'q' => 'Q', 'r' => '/~', 's' => '$', 't' => '+',
26
+ 'u' => '|_|', 'v' => '\/', 'w' => '\/\/', 'x' => '><', 'y' => '`/',
27
+ 'z' => 'Z',
28
+ }
29
+
30
+ class StupidRenderer < GenericRenderer
31
+
32
+ =begin
33
+
34
+ --- StupidRenderer#render(content)
35
+
36
+ Strips vowells
37
+
38
+ =end
39
+
40
+ def render(content)
41
+
42
+ methodname = @document['stupidmethod'] || nil
43
+ if methodname then
44
+ method = self.method(methodname)
45
+
46
+ content.each { |line|
47
+ line = method.call(line)
48
+ push(line)
49
+ }
50
+ else
51
+ @result = content.to_a
52
+ end
53
+
54
+
55
+ return self.result
56
+ end
57
+
58
+ def strip(s)
59
+ s = s.gsub(/[aeiou]/i, '')
60
+ return s
61
+ end
62
+
63
+ def leet(s)
64
+
65
+ # this is a lot more complicated than it needs to be. Basically,
66
+ # we didn't want variable interpolation chunks (eg #{blah}) to
67
+ # become 7337, so we split on #{}s, work on the other parts, and
68
+ # then fit it all back together. This should probably be moved up
69
+ # to render.
70
+
71
+ result = []
72
+ new_s = s.clone
73
+ re = /(\#\{[^\}]+\})/
74
+ new_s.split(re).each { |chunk|
75
+ if (chunk =~ re) then
76
+ result.push(chunk)
77
+ else
78
+ chunk.gsub!(/./) { |char|
79
+ $Transcode[char.downcase] || char
80
+ }
81
+ result.push(chunk)
82
+ end
83
+ }
84
+
85
+ return result.join('')
86
+ end
87
+
88
+ end
@@ -0,0 +1,45 @@
1
+ require 'ZenWeb/GenericRenderer'
2
+
3
+ =begin
4
+
5
+ = Class SubpageRenderer
6
+
7
+ Generates a list of known subpages in a format compatible with
8
+ TextToHtmlRenderer.
9
+
10
+ === Methods
11
+
12
+ =end
13
+
14
+ class SubpageRenderer < GenericRenderer
15
+
16
+ =begin
17
+
18
+ --- SubpageRenderer#render(content)
19
+
20
+ Renders a list of known subpages in a format compatible with
21
+ TextToHtmlRenderer. Adds the list to the end of the content.
22
+
23
+ =end
24
+
25
+ def render(content)
26
+ skip = @document['skipsubpages'] || (@document['includesubpages'] || '') =~ /false/
27
+
28
+ subpages = @document.subpages.clone
29
+ if (not skip and subpages.length > 0) then
30
+ push("\n\n")
31
+ push("** Subpages:\n\n")
32
+ subpages.each_index { | index |
33
+ url = subpages[index]
34
+ doc = @website[url]
35
+ title = doc.fulltitle
36
+
37
+ push("+ <A HREF=\"#{url}\">#{title}</A>\n")
38
+ }
39
+ push("\n")
40
+ end
41
+
42
+ return content + self.result
43
+ end
44
+ end
45
+
@@ -0,0 +1,219 @@
1
+ require 'ZenWeb/HtmlRenderer'
2
+
3
+ =begin
4
+
5
+ = Class TextToHtmlRenderer
6
+
7
+ Converts a fairly plain text format into styled HTML.
8
+
9
+ === Methods
10
+
11
+ =end
12
+
13
+ class TextToHtmlRenderer < HtmlRenderer
14
+
15
+ =begin
16
+
17
+ --- TextToHtmlRenderer#render(content)
18
+
19
+ Converts a simple plaintext format into formatted HTML. Includes
20
+ paragraphing, embedded variables, lists, rules, preformatted
21
+ blocks, and embedded HTML. See the demo pages for a complete
22
+ description on how to use this.
23
+
24
+ =end
25
+
26
+ def render(content)
27
+
28
+ text = content.split($PARAGRAPH_RE)
29
+
30
+ table = div = false
31
+
32
+ text.each { | p |
33
+
34
+ # massage a little
35
+ p = p.sub($PARAGRAPH_END_RE, '')
36
+ p.chomp!
37
+
38
+ p.gsub!(/\\&/, "&amp;")
39
+ p.gsub!(/\\</, "&lt;")
40
+ p.gsub!(/\\>/, "&gt;")
41
+ p.gsub!(/\\\"/, "&quot;")
42
+
43
+ p.gsub!(/\\\{/, "{")
44
+ p.gsub!(/\\:/, "&#58;")
45
+
46
+ # WARN Not sure if I want to do this or not... thinking about it.
47
+ # p.gsub!(/\\(.)/) { | c | sprintf("&#%04X#;", $1[0]) }
48
+
49
+ # url substitutions
50
+ p.gsub!(/([^=\"])((http|ftp|mailto):(\S+))/) {
51
+ pre = $1
52
+ url = $2
53
+ txt = $4
54
+
55
+ txt.gsub!(/\//, " ")
56
+ txt.strip!
57
+ txt.gsub!(/ /, " /")
58
+
59
+ "#{pre}<A HREF=\"#{url}\">#{txt}</A>"
60
+ }
61
+
62
+ case p
63
+ when /^(\*\*+)\s*(.*)$/ then
64
+ level = $1.length
65
+ push("<H#{level}>#{$2}</H#{level}>\n\n")
66
+ when /^---+$/ then
67
+ push("<HR>\n\n")
68
+ when /^===+$/ then
69
+ push("<HR CLASS=\"thick\">\n\n")
70
+ when /^%%%\s*(.*)/ then # TODO: I'm not fond of this
71
+ rest = $1
72
+ close = (rest.empty? or (rest.downcase == "end"))
73
+ push "</div></div>\n" if div
74
+ push "\n" if div unless table
75
+ push "</td><td>\n" if table and div
76
+
77
+ push "<div #{rest}><div>\n\n" unless close
78
+ div = ! close
79
+ when /^%%\s*$/ then
80
+ if div then
81
+ push "</div></div>\n"
82
+ div = false
83
+ end
84
+ if table then
85
+ push "</td></tr></table>\n\n"
86
+ else
87
+ push "<table><tr><td>\n\n"
88
+ end
89
+ table = ! table
90
+ when /^%[=-]/ then
91
+ hash, order = self.createHash(p)
92
+ push(self.hash2html(hash, order) + "\n") if hash
93
+ when /^\t*([\+=])/ then
94
+ ordered = $1 == "="
95
+ list = self.createList(p)
96
+ push(self.array2html(list, ordered)) if list
97
+ when /^\ \ / then # and p !~ /^[^\ ]/ then
98
+ p.gsub!(/^\ \ /, '')
99
+ push("<PRE>" + p + "</PRE>\n\n")
100
+ when /^\s*<\//, /^\s*<(?:DIV|FORM|P|TABLE|BLOCKQUOTE|H[1-7])\b/i then
101
+ push p
102
+ push "\n\n"
103
+ else
104
+ push("<P>" + p + "</P>")
105
+ push "\n\n"
106
+ end
107
+ }
108
+
109
+ # TODO: need to extend: ordered lists
110
+
111
+ # FIX: xmp makes this slow
112
+ # put it back into line-by-line format
113
+ # I use scan instead of split so I can keep the EOLs.
114
+ # @result = @result.join("\n").scan(/^.*[\n\r]+/)
115
+
116
+ return self.result
117
+
118
+ end
119
+
120
+ =begin
121
+
122
+ --- ZenDocument#createList
123
+
124
+ Convert a string composed of lines prefixed by plus signs into an
125
+ array of those strings, sans plus signs. If a line is indented
126
+ with tabs, then the lines at that indention level will become an
127
+ array of their own, to be added to the encompassing array.
128
+
129
+ =end
130
+
131
+ def createList(data)
132
+
133
+ if (data.is_a?(String)) then
134
+ # TODO: at some time we'll want to support different types of lists
135
+ data = data.gsub(/^(\t*)([\+=])\s*(.*)$/) { type=$2; $1 + $3 }
136
+ data = data.split($/)
137
+ end
138
+
139
+ min = -1
140
+ i = 0
141
+ len = data.size
142
+
143
+ while (i < len)
144
+ if (min == -1) then
145
+
146
+ # looking for initial match:
147
+ if (data[i] =~ /^\t(\t*.*)/) then
148
+
149
+ # replace w/ one less tab, and record that we have a match
150
+ data[i] = $1
151
+ min = i
152
+ end
153
+ else
154
+
155
+ # found match, looking for mismatch
156
+ if (data[i] !~ /^\t(\t*.*)/ or i == len) then
157
+
158
+ # found mismatch, replacing w/ sublist
159
+ data[min..i-1] = [ createList(data[min..i-1]) ]
160
+ # resetting appropriate values
161
+ len = data.size
162
+ i = min
163
+ min = -1
164
+ else
165
+ data[i] = $1
166
+ end
167
+ end
168
+ i += 1
169
+ end
170
+
171
+ if (i >= len - 1 and min != -1) then
172
+ data[min..i-1] = [ createList(data[min..i-1]) ]
173
+ end
174
+
175
+ return data
176
+ end
177
+
178
+ =begin
179
+
180
+ --- ZenDocument#createHash
181
+
182
+ Convert a string composed of lines prefixed one of two delimiters
183
+ into a hash. If the delimiter is "%-", then that string is used
184
+ as the key to the hash. If the delimiter is "%=", then that
185
+ string is used as the value to the hash.
186
+
187
+ =end
188
+
189
+ def createHash(data)
190
+
191
+ result = {}
192
+ order = []
193
+
194
+ if (data.is_a?(String)) then
195
+ data = data.split($/)
196
+ end
197
+
198
+ key = nil
199
+ data.each { |line|
200
+ if (line =~ /^\s*%-\s*(.*)/) then
201
+ key = $1
202
+ elsif (line =~ /^\s*%=\s*(.*)/) then
203
+ val = $1
204
+
205
+ if (key) then
206
+ # WARN: maybe do something if already defined?
207
+ result[key] = val
208
+ order << key
209
+ end
210
+
211
+ else
212
+ # nothing
213
+ end
214
+ }
215
+
216
+ return result, order
217
+ end
218
+
219
+ end