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.
- data.tar.gz.sig +0 -0
- data/History.txt +426 -0
- data/Manifest.txt +54 -0
- data/README.txt +63 -0
- data/Rakefile +22 -0
- data/bin/zenweb +27 -0
- data/bin/zenwebpage +66 -0
- data/bin/zenwebsite +39 -0
- data/design/REQUIREMENTS.txt +52 -0
- data/design/ZENWEB_2.txt +69 -0
- data/design/heirarchy.png +0 -0
- data/design/heirarchy.tgif +311 -0
- data/docs/Customizing +76 -0
- data/docs/FAQ +12 -0
- data/docs/Features +128 -0
- data/docs/Presentation +88 -0
- data/docs/QuickStart +32 -0
- data/docs/Renderers +85 -0
- data/docs/SiteMap +13 -0
- data/docs/YourOwnWebsite +32 -0
- data/docs/index +14 -0
- data/docs/metadata.txt +10 -0
- data/lib/ZenWeb.rb +850 -0
- data/lib/ZenWeb/CalendarRenderer.rb +162 -0
- data/lib/ZenWeb/CompactRenderer.rb +45 -0
- data/lib/ZenWeb/CompositeRenderer.rb +63 -0
- data/lib/ZenWeb/FileAttachmentRenderer.rb +57 -0
- data/lib/ZenWeb/FooterRenderer.rb +38 -0
- data/lib/ZenWeb/GenericRenderer.rb +143 -0
- data/lib/ZenWeb/HeaderRenderer.rb +52 -0
- data/lib/ZenWeb/HtmlRenderer.rb +81 -0
- data/lib/ZenWeb/HtmlTableRenderer.rb +94 -0
- data/lib/ZenWeb/HtmlTemplateRenderer.rb +173 -0
- data/lib/ZenWeb/MetadataRenderer.rb +83 -0
- data/lib/ZenWeb/RelativeRenderer.rb +98 -0
- data/lib/ZenWeb/RubyCodeRenderer.rb +56 -0
- data/lib/ZenWeb/SitemapRenderer.rb +56 -0
- data/lib/ZenWeb/StandardRenderer.rb +40 -0
- data/lib/ZenWeb/StupidRenderer.rb +88 -0
- data/lib/ZenWeb/SubpageRenderer.rb +45 -0
- data/lib/ZenWeb/TextToHtmlRenderer.rb +219 -0
- data/lib/ZenWeb/TocRenderer.rb +61 -0
- data/lib/ZenWeb/XXXRenderer.rb +32 -0
- data/test/SiteMap +14 -0
- data/test/Something +4 -0
- data/test/include.txt +3 -0
- data/test/index +8 -0
- data/test/metadata.txt +10 -0
- data/test/ryand/SiteMap +10 -0
- data/test/ryand/blah +4 -0
- data/test/ryand/blah-blah +4 -0
- data/test/ryand/index +52 -0
- data/test/ryand/metadata.txt +2 -0
- data/test/ryand/stuff/index +4 -0
- data/test/test_zenweb.rb +1624 -0
- metadata +161 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
= Class HeaderRenderer
|
|
6
|
+
|
|
7
|
+
Inserts a header based on metadata.
|
|
8
|
+
|
|
9
|
+
=== Methods
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
class HeaderRenderer < GenericRenderer
|
|
14
|
+
|
|
15
|
+
=begin
|
|
16
|
+
|
|
17
|
+
--- HeaderRenderer#render(content)
|
|
18
|
+
|
|
19
|
+
Adds a header if the ((|header|)) metadata item exists. If the
|
|
20
|
+
document contains a BODY HTML tag, then the header immediately
|
|
21
|
+
follows it, otherwise it is simply at the top.
|
|
22
|
+
|
|
23
|
+
=end
|
|
24
|
+
|
|
25
|
+
def render(content)
|
|
26
|
+
|
|
27
|
+
header = @document['header'] || nil
|
|
28
|
+
|
|
29
|
+
if header then
|
|
30
|
+
placed = false
|
|
31
|
+
|
|
32
|
+
content.each { | line |
|
|
33
|
+
|
|
34
|
+
push(line)
|
|
35
|
+
|
|
36
|
+
if (line =~ /<BODY/i) then
|
|
37
|
+
push(header)
|
|
38
|
+
placed = true
|
|
39
|
+
end
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
unless placed then
|
|
43
|
+
unshift(header) unless placed
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
push(content)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return self.result
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
= Class HtmlRenderer
|
|
6
|
+
|
|
7
|
+
Abstract superclass that provides common functionality for those
|
|
8
|
+
renderers that produce HTML.
|
|
9
|
+
|
|
10
|
+
=== Methods
|
|
11
|
+
|
|
12
|
+
=end
|
|
13
|
+
|
|
14
|
+
class HtmlRenderer < GenericRenderer
|
|
15
|
+
|
|
16
|
+
=begin
|
|
17
|
+
|
|
18
|
+
--- HtmlRenderer#render(content)
|
|
19
|
+
|
|
20
|
+
Raises an exception. This is subclass responsibility as this is an
|
|
21
|
+
abstract class.
|
|
22
|
+
|
|
23
|
+
=end
|
|
24
|
+
|
|
25
|
+
def render(content)
|
|
26
|
+
raise "Subclass Responsibility"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
=begin
|
|
30
|
+
|
|
31
|
+
--- HtmlRenderer#array2html
|
|
32
|
+
|
|
33
|
+
Converts an array (of arrays, potentially) into an unordered list.
|
|
34
|
+
|
|
35
|
+
=end
|
|
36
|
+
|
|
37
|
+
def array2html(list, ordered=false, indent=0)
|
|
38
|
+
result = []
|
|
39
|
+
|
|
40
|
+
indent1 = " " * indent
|
|
41
|
+
indent2 = " " * (indent + 1)
|
|
42
|
+
|
|
43
|
+
tag = ordered ? "OL" : "UL"
|
|
44
|
+
|
|
45
|
+
result << "#{indent1}<#{tag}>\n"
|
|
46
|
+
list.each { | l |
|
|
47
|
+
if (l.is_a?(Array)) then
|
|
48
|
+
x = result.pop
|
|
49
|
+
result.push "\n"
|
|
50
|
+
result.push self.array2html(l, ordered, indent+2)
|
|
51
|
+
result.push indent2 unless x =~ /^\s+/
|
|
52
|
+
result.push x
|
|
53
|
+
else
|
|
54
|
+
result.push(indent2, "<LI>", l.to_s, "</LI>\n")
|
|
55
|
+
end
|
|
56
|
+
}
|
|
57
|
+
result << "#{indent1}</#{tag}>\n"
|
|
58
|
+
|
|
59
|
+
return result.join
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def hash2html(hash, order)
|
|
63
|
+
result = ""
|
|
64
|
+
|
|
65
|
+
if (hash) then
|
|
66
|
+
result += "<DL>\n"
|
|
67
|
+
order.each { | key |
|
|
68
|
+
val = hash[key] or raise "Key '#{key}' is missing!"
|
|
69
|
+
result += " <DT>#{key}</DT>\n"
|
|
70
|
+
result += " <DD>#{val}</DD>\n\n"
|
|
71
|
+
}
|
|
72
|
+
result += "</DL>\n"
|
|
73
|
+
else
|
|
74
|
+
result = "not a hash"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
return result
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
|
2
|
+
|
|
3
|
+
class Hash
|
|
4
|
+
def %(style)
|
|
5
|
+
style.gsub(/%([-\d]*)\(([^\)]+)\)/) do |match|
|
|
6
|
+
result = ''
|
|
7
|
+
key = $2.intern
|
|
8
|
+
if self.has_key?(key) then
|
|
9
|
+
result = $1 ? sprintf("%*s", $1.to_i, self[key]) : self[key]
|
|
10
|
+
else
|
|
11
|
+
$stderr.puts " WARNING: missing data for '#{key}' in #{self.inspect}" unless $TESTING
|
|
12
|
+
end
|
|
13
|
+
result
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
=begin
|
|
19
|
+
|
|
20
|
+
= Class HtmlTableRenderer
|
|
21
|
+
|
|
22
|
+
Converts tab delimited data (tagged with <tabs>) into HTML tables
|
|
23
|
+
|
|
24
|
+
=== Methods
|
|
25
|
+
|
|
26
|
+
=end
|
|
27
|
+
|
|
28
|
+
class HtmlTableRenderer < GenericRenderer
|
|
29
|
+
|
|
30
|
+
=begin
|
|
31
|
+
|
|
32
|
+
--- HtmlTableRenderer#render(content)
|
|
33
|
+
|
|
34
|
+
Converts tab delimited data (tagged with <tabs>) into HTML tables
|
|
35
|
+
|
|
36
|
+
=end
|
|
37
|
+
|
|
38
|
+
def render(content)
|
|
39
|
+
|
|
40
|
+
first=true
|
|
41
|
+
pre_style = post_style = head_style = body_style = column_titles = nil
|
|
42
|
+
|
|
43
|
+
self.scan_region(content, /^<tabs/i, /^<\/tabs>/i) do |line, context|
|
|
44
|
+
line.chomp!
|
|
45
|
+
case context
|
|
46
|
+
when :START then
|
|
47
|
+
first = true
|
|
48
|
+
if line =~ /style\s*=\s*\"?([\w\.-]+)\"?/i then
|
|
49
|
+
pre_style = @document["style_#{$1}_pre"] || ''
|
|
50
|
+
post_style = @document["style_#{$1}_post"] || ''
|
|
51
|
+
head_style = @document["style_#{$1}_head"] || ''
|
|
52
|
+
body_style = @document["style_#{$1}"] or
|
|
53
|
+
raise "You must specify a metadata entry for 'style_#{$1}'"
|
|
54
|
+
else
|
|
55
|
+
pre_style = "<table border=\"0\">\n"
|
|
56
|
+
post_style = "</table>\n"
|
|
57
|
+
head_style = nil
|
|
58
|
+
body_style = nil
|
|
59
|
+
column_titles = nil
|
|
60
|
+
end
|
|
61
|
+
line = pre_style
|
|
62
|
+
when :END then
|
|
63
|
+
line = post_style
|
|
64
|
+
else
|
|
65
|
+
columns = line.split(/\t+/)
|
|
66
|
+
|
|
67
|
+
if body_style then
|
|
68
|
+
if first then
|
|
69
|
+
line = head_style
|
|
70
|
+
# map the first row of data to column title positions
|
|
71
|
+
column_titles = columns.map {|x| x.intern}
|
|
72
|
+
else
|
|
73
|
+
data = {}
|
|
74
|
+
# use the column title positions to extract the data from the table
|
|
75
|
+
column_titles.each_with_index do |title, index|
|
|
76
|
+
data[title] = columns[index]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# use our extension to hash (see above) to format the data
|
|
80
|
+
line = data % body_style
|
|
81
|
+
end
|
|
82
|
+
else
|
|
83
|
+
type = first ? "th" : "td"
|
|
84
|
+
line = "<tr><#{type}>#{columns.join "</#{type}><#{type}>"}</#{type}></tr>\n"
|
|
85
|
+
end
|
|
86
|
+
first = false if first
|
|
87
|
+
end
|
|
88
|
+
push line
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
return self.result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require 'ZenWeb/HtmlRenderer'
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
= Class HtmlTemplateRenderer
|
|
6
|
+
|
|
7
|
+
Generates a consistant HTML page header and footer, including a
|
|
8
|
+
navigation bar, title, subtitle, and appropriate META tags.
|
|
9
|
+
|
|
10
|
+
=== Methods
|
|
11
|
+
|
|
12
|
+
=end
|
|
13
|
+
|
|
14
|
+
class HtmlTemplateRenderer < HtmlRenderer
|
|
15
|
+
|
|
16
|
+
=begin
|
|
17
|
+
|
|
18
|
+
--- HtmlTemplateRenderer#render(content)
|
|
19
|
+
|
|
20
|
+
Renders a standardized HTML header and footer. This currently also
|
|
21
|
+
includes a navigation bar and a list of subpages, which will
|
|
22
|
+
probably be broken out to their own renderers soon.
|
|
23
|
+
|
|
24
|
+
Metadata variables used:
|
|
25
|
+
|
|
26
|
+
+ author
|
|
27
|
+
+ banner - graphic at the top of the page, usually a logo
|
|
28
|
+
+ bgcolor - defaults to not being defined
|
|
29
|
+
+ copyright
|
|
30
|
+
+ description
|
|
31
|
+
+ dtd (default: 'DTD HTML 4.0')
|
|
32
|
+
+ email - used in a mailto in metadata
|
|
33
|
+
+ keywords
|
|
34
|
+
+ rating (default: 'general')
|
|
35
|
+
+ stylesheet - reference to a CSS file
|
|
36
|
+
+ style - CSS code directly (for smaller snippets)
|
|
37
|
+
+ subtitle
|
|
38
|
+
+ title (default: 'Unknown Title')
|
|
39
|
+
+ icbm - longitude and latitude for geourl.org
|
|
40
|
+
+ icbm_title - defaults to the page title
|
|
41
|
+
|
|
42
|
+
=end
|
|
43
|
+
|
|
44
|
+
def render(content)
|
|
45
|
+
author = @document['author']
|
|
46
|
+
banner = @document['banner']
|
|
47
|
+
bgcolor = @document['bgcolor']
|
|
48
|
+
dtd = @document['dtd'] || 'DTD HTML 4.0'
|
|
49
|
+
copyright = @document['copyright']
|
|
50
|
+
description = @document['description']
|
|
51
|
+
email = @document['email']
|
|
52
|
+
keywords = @document['keywords']
|
|
53
|
+
rating = @document['rating'] || 'general'
|
|
54
|
+
stylesheet = @document['stylesheet']
|
|
55
|
+
subtitle = @document['subtitle']
|
|
56
|
+
title = @document['title'] || 'Unknown Title'
|
|
57
|
+
icbm = @document['icbm']
|
|
58
|
+
icbm_title = @document['icbm_title'] || @document['title']
|
|
59
|
+
charset = @document['charset']
|
|
60
|
+
style = @document['style']
|
|
61
|
+
naked_page = @document['naked_page']
|
|
62
|
+
head_extra = @document['head_extra'] || []
|
|
63
|
+
|
|
64
|
+
titletext = @document.fulltitle
|
|
65
|
+
|
|
66
|
+
# TODO: iterate over a list of metas and add them in one nicely organized block
|
|
67
|
+
|
|
68
|
+
if bgcolor then
|
|
69
|
+
style ||= ""
|
|
70
|
+
style = "body { background-color: #{bgcolor} }\n" + style
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# header
|
|
74
|
+
push([
|
|
75
|
+
"<!DOCTYPE HTML PUBLIC \"-//W3C//#{dtd}//EN\">\n",
|
|
76
|
+
"<HTML>\n",
|
|
77
|
+
"<HEAD>\n",
|
|
78
|
+
"<TITLE>#{titletext}</TITLE>\n",
|
|
79
|
+
email ? "<LINK REV=\"MADE\" HREF=\"#{email}\">\n" : [],
|
|
80
|
+
stylesheet ? "<LINK REL=\"STYLESHEET\" HREF=\"#{stylesheet}\" TYPE=\"text/css\" title=\"#{stylesheet}\">\n" : [],
|
|
81
|
+
"<META NAME=\"rating\" CONTENT=\"#{rating}\">\n",
|
|
82
|
+
"<META NAME=\"GENERATOR\" CONTENT=\"#{ZenWebsite.banner}\">\n",
|
|
83
|
+
style ? "<STYLE TYPE=\"text/css\">\n#{style}\n</STYLE>" : [],
|
|
84
|
+
author ? "<META NAME=\"author\" CONTENT=\"#{author}\">\n" : [],
|
|
85
|
+
copyright ? "<META NAME=\"copyright\" CONTENT=\"#{copyright}\">\n" : [],
|
|
86
|
+
keywords ? "<META NAME=\"keywords\" CONTENT=\"#{keywords}\">\n" : [],
|
|
87
|
+
description ? "<META NAME=\"description\" CONTENT=\"#{description}\">\n" : [],
|
|
88
|
+
charset ? "<META HTTP-EQUIV=\"content-type\" CONTENT=\"text/html; charset=#{charset}\">" : [],
|
|
89
|
+
icbm ? "<meta name=\"ICBM\" content=\"#{icbm}\">\n<meta name=\"DC.title\" content=\"#{icbm_title}\">" : [],
|
|
90
|
+
|
|
91
|
+
"<link rel=\"up\" href=\"#{@document.parentURL}\" title=\"#{@document.parent.title}\">\n",
|
|
92
|
+
"<link rel=\"contents\" href=\"#{@sitemap.url}\" title=\"#{@sitemap.title}\">\n",
|
|
93
|
+
"<link rel=\"top\" href=\"#{@website.top.url}\" title=\"#{@website.top.title}\">\n",
|
|
94
|
+
|
|
95
|
+
head_extra.join("\n"),
|
|
96
|
+
|
|
97
|
+
"</HEAD>\n",
|
|
98
|
+
"<BODY>\n",
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
unless naked_page then
|
|
102
|
+
self.navbar
|
|
103
|
+
|
|
104
|
+
if banner then
|
|
105
|
+
push("<H1><IMG SRC=\"#{banner}\" ALT=\"#{File.basename banner}\"></H1>\n")
|
|
106
|
+
unless (subtitle) then
|
|
107
|
+
push("<H2>#{title}</H2>\n")
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
push("<H1>#{title}</H1>\n")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
push([
|
|
114
|
+
subtitle ? "<H2>#{subtitle}</H2>\n" : [],
|
|
115
|
+
"<HR CLASS=\"thick\">\n\n",
|
|
116
|
+
])
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
push content
|
|
120
|
+
|
|
121
|
+
unless naked_page then
|
|
122
|
+
push([
|
|
123
|
+
"<HR CLASS=\"thick\">\n\n",
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
self.navbar
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
push("\n</BODY>\n</HTML>\n")
|
|
130
|
+
|
|
131
|
+
return self.result
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
=begin
|
|
135
|
+
|
|
136
|
+
--- HtmlTemplateRenderer#navbar
|
|
137
|
+
|
|
138
|
+
Generates a navbar that contains a link to the sitemap, search
|
|
139
|
+
page (if any), and a fake "breadcrumbs" trail which is really just
|
|
140
|
+
a list of all of the parent titles up the chain to the top.
|
|
141
|
+
|
|
142
|
+
=end
|
|
143
|
+
|
|
144
|
+
def navbar
|
|
145
|
+
|
|
146
|
+
sep = " / "
|
|
147
|
+
search = @website["/Search.html"]
|
|
148
|
+
|
|
149
|
+
push([
|
|
150
|
+
"<P class=\"navbar\">\n",
|
|
151
|
+
"<A HREF=\"#{@sitemap.url}\">Sitemap</A>",
|
|
152
|
+
search ? " | <A HREF=\"#{search.url}\"><EM>Search</EM></A>" : [],
|
|
153
|
+
" || ",
|
|
154
|
+
])
|
|
155
|
+
|
|
156
|
+
path = []
|
|
157
|
+
current = @document
|
|
158
|
+
while current and current != current.parent do
|
|
159
|
+
current = current.parent
|
|
160
|
+
path.unshift(current) if current
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
push([
|
|
164
|
+
path.map{|doc| ["<A HREF=\"#{doc.url}\">#{doc['title']}</A>\n", sep]},
|
|
165
|
+
@document['title'],
|
|
166
|
+
"</P>\n",
|
|
167
|
+
])
|
|
168
|
+
|
|
169
|
+
return []
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'ZenWeb/GenericRenderer'
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
= Class MetadataRenderer
|
|
6
|
+
|
|
7
|
+
Converts all metadata references into their values.
|
|
8
|
+
|
|
9
|
+
=== Methods
|
|
10
|
+
|
|
11
|
+
=end
|
|
12
|
+
|
|
13
|
+
class MetadataRenderer < GenericRenderer
|
|
14
|
+
|
|
15
|
+
@@cache = {}
|
|
16
|
+
|
|
17
|
+
=begin
|
|
18
|
+
|
|
19
|
+
--- MetadataRenderer#render(content)
|
|
20
|
+
|
|
21
|
+
Converts all metadata references into their values.
|
|
22
|
+
|
|
23
|
+
=end
|
|
24
|
+
|
|
25
|
+
def render(content)
|
|
26
|
+
|
|
27
|
+
content = content.gsub(/\#\{([^\}]+)\}/) {
|
|
28
|
+
key = $1
|
|
29
|
+
|
|
30
|
+
# check to see if this is a metadata entry
|
|
31
|
+
val = @document[key] || nil
|
|
32
|
+
|
|
33
|
+
# otherwise try to eval it. If that fails, just give text.
|
|
34
|
+
unless (val) then
|
|
35
|
+
begin
|
|
36
|
+
# this allows evals that fail (expensive) to be cached,
|
|
37
|
+
# and good code to be eval'd every time.
|
|
38
|
+
# I think this is a good balance.
|
|
39
|
+
if @@cache[key] then
|
|
40
|
+
val = @@cache[key]
|
|
41
|
+
else
|
|
42
|
+
val = eval(key)
|
|
43
|
+
end
|
|
44
|
+
rescue NameError => err
|
|
45
|
+
val = key
|
|
46
|
+
@@cache[key] = key
|
|
47
|
+
rescue Exception => err
|
|
48
|
+
$stderr.puts "eval failed in MetadataRenderer for #{@document.datapath}: #{err}. Code = '#{key}'"
|
|
49
|
+
val = key
|
|
50
|
+
@@cache[key] = key
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
val
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return content
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@@paths = {}
|
|
61
|
+
|
|
62
|
+
def include(path, remove_metadata=false, escape=false)
|
|
63
|
+
unless @@paths.include? path then
|
|
64
|
+
full_path = File.expand_path(File.join(File.dirname(@document.datapath), path))
|
|
65
|
+
@@paths[path] = full_path
|
|
66
|
+
else
|
|
67
|
+
full_path = @@paths[path]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
content = File.new(full_path).readlines
|
|
71
|
+
|
|
72
|
+
if remove_metadata then
|
|
73
|
+
content = content.reject { |line| line =~ /^\s*\#/ }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
content = self.render(content.join(''))
|
|
77
|
+
content.gsub!(/([<>&])/) { |x| '\\' + x } if escape
|
|
78
|
+
|
|
79
|
+
content
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|