zenweb 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
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