gettalong-webgen 0.5.8.20090507 → 0.5.9.20090620
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -6
- data/data/webgen/passive_sources/images/generated_by_webgen.png +0 -0
- data/data/webgen/passive_sources/images/webgen_logo.png +0 -0
- data/data/webgen/passive_sources/templates/atom_feed.template +38 -0
- data/data/webgen/passive_sources/templates/rss_feed.template +28 -0
- data/data/webgen/resources.yaml +2 -1
- data/doc/contentprocessor/builder.page +1 -1
- data/doc/contentprocessor/erb.page +5 -2
- data/doc/contentprocessor/erubis.page +2 -2
- data/doc/extensions.page +1 -1
- data/doc/manual.page +56 -26
- data/doc/reference_configuration.page +36 -1
- data/doc/reference_website_styles.page +1 -1
- data/doc/sourcehandler/feed.page +6 -11
- data/doc/tag/includefile.page +1 -1
- data/lib/webgen/cli/apply_command.rb +1 -1
- data/lib/webgen/cli/utils.rb +2 -2
- data/lib/webgen/common.rb +0 -9
- data/lib/webgen/contentprocessor/blocks.rb +60 -36
- data/lib/webgen/contentprocessor/builder.rb +2 -2
- data/lib/webgen/contentprocessor/erb.rb +3 -2
- data/lib/webgen/contentprocessor/erubis.rb +2 -2
- data/lib/webgen/contentprocessor/haml.rb +2 -2
- data/lib/webgen/contentprocessor/maruku.rb +1 -1
- data/lib/webgen/contentprocessor/sass.rb +2 -2
- data/lib/webgen/contentprocessor/tags.rb +25 -11
- data/lib/webgen/context.rb +4 -1
- data/lib/webgen/context/render.rb +32 -0
- data/lib/webgen/context/tags.rb +20 -0
- data/lib/webgen/default_config.rb +4 -1
- data/lib/webgen/deprecated.rb +37 -4
- data/lib/webgen/node.rb +37 -38
- data/lib/webgen/path.rb +151 -54
- data/lib/webgen/source.rb +6 -6
- data/lib/webgen/source/stacked.rb +13 -5
- data/lib/webgen/sourcehandler.rb +71 -45
- data/lib/webgen/sourcehandler/base.rb +51 -21
- data/lib/webgen/sourcehandler/copy.rb +4 -4
- data/lib/webgen/sourcehandler/directory.rb +3 -9
- data/lib/webgen/sourcehandler/feed.rb +23 -49
- data/lib/webgen/sourcehandler/fragment.rb +10 -8
- data/lib/webgen/sourcehandler/memory.rb +9 -10
- data/lib/webgen/sourcehandler/metainfo.rb +9 -9
- data/lib/webgen/sourcehandler/page.rb +5 -5
- data/lib/webgen/sourcehandler/sitemap.rb +3 -3
- data/lib/webgen/sourcehandler/template.rb +6 -6
- data/lib/webgen/sourcehandler/virtual.rb +19 -17
- data/lib/webgen/tag/base.rb +34 -26
- data/lib/webgen/tag/breadcrumbtrail.rb +3 -3
- data/lib/webgen/tag/executecommand.rb +3 -3
- data/lib/webgen/tag/langbar.rb +2 -2
- data/lib/webgen/tag/link.rb +3 -3
- data/lib/webgen/tag/menu.rb +2 -2
- data/lib/webgen/tag/metainfo.rb +1 -1
- data/lib/webgen/tag/relocatable.rb +17 -21
- data/lib/webgen/tag/tikz.rb +5 -6
- data/lib/webgen/tree.rb +7 -7
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/website.rb +4 -2
- data/misc/default.css +8 -2
- data/misc/default.template +2 -2
- data/misc/logo.svg +313 -0
- data/misc/style.page +1 -1
- data/test/helper.rb +2 -2
- data/test/test_common_sitemap.rb +1 -1
- data/test/test_contentprocessor_blocks.rb +12 -4
- data/test/test_contentprocessor_builder.rb +2 -1
- data/test/test_contentprocessor_erb.rb +2 -1
- data/test/test_contentprocessor_erubis.rb +1 -1
- data/test/test_contentprocessor_fragments.rb +12 -11
- data/test/test_contentprocessor_haml.rb +2 -1
- data/test/test_contentprocessor_maruku.rb +1 -0
- data/test/test_contentprocessor_rdiscount.rb +1 -0
- data/test/test_contentprocessor_rdoc.rb +1 -0
- data/test/test_contentprocessor_sass.rb +1 -0
- data/test/test_contentprocessor_tags.rb +13 -0
- data/test/test_context.rb +28 -0
- data/test/test_node.rb +40 -20
- data/test/test_path.rb +106 -65
- data/test/test_source_filesystem.rb +1 -1
- data/test/test_source_stacked.rb +19 -6
- data/test/test_sourcehandler_base.rb +53 -47
- data/test/test_sourcehandler_copy.rb +6 -6
- data/test/test_sourcehandler_directory.rb +8 -12
- data/test/test_sourcehandler_feed.rb +10 -6
- data/test/test_sourcehandler_fragment.rb +6 -5
- data/test/test_sourcehandler_main.rb +39 -0
- data/test/test_sourcehandler_memory.rb +4 -4
- data/test/test_sourcehandler_metainfo.rb +10 -10
- data/test/test_sourcehandler_page.rb +9 -9
- data/test/test_sourcehandler_sitemap.rb +4 -4
- data/test/test_sourcehandler_template.rb +14 -14
- data/test/test_sourcehandler_virtual.rb +9 -5
- data/test/test_tag_base.rb +2 -2
- data/test/test_tag_executecommand.rb +1 -1
- data/test/test_tag_link.rb +4 -3
- data/test/test_tag_menu.rb +15 -15
- data/test/test_tag_metainfo.rb +1 -0
- data/test/test_tag_relocatable.rb +2 -1
- data/test/test_tag_tikz.rb +3 -3
- data/test/test_tree.rb +8 -8
- data/test/test_website.rb +15 -0
- metadata +14 -14
- data/test/test_common.rb +0 -18
data/lib/webgen/path.rb
CHANGED
@@ -1,11 +1,32 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'pathname'
|
3
4
|
require 'webgen/languages'
|
4
5
|
|
5
6
|
module Webgen
|
6
7
|
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# == General Information
|
9
|
+
#
|
10
|
+
# A Path object provides information about a path that is used to create a node as well as methods
|
11
|
+
# for accessing its content. In contrast, output paths are always strings and just specify the
|
12
|
+
# location where a specific node should be written to.
|
13
|
+
#
|
14
|
+
# Note the +path+ and +source_path+ attributes of a Path object:
|
15
|
+
#
|
16
|
+
# * The +source_path+ specifies a path string that was directly created by a Source object. Each
|
17
|
+
# Path object must have such a valid source path sothat webgen can infer the Path the lead to
|
18
|
+
# the creation of a Node object later.
|
19
|
+
#
|
20
|
+
# * In contrast, the +path+ attribute specifies the path that is used to create the canonical name
|
21
|
+
# (and by default the output path) of a Node object. Normally it is the same as the
|
22
|
+
# +source_path+ but can differ (e.g. when fragment nodes are created for page file nodes).
|
23
|
+
#
|
24
|
+
# A Path object can represent one of three different things: a directory, a file or a fragment. If
|
25
|
+
# the +path+ ends with a slash character, then the path object represents a directory, if the path
|
26
|
+
# contains a hash character anywhere, then the path object represents a fragment and else it
|
27
|
+
# represents a file. Have a look at the webgen manual to see the exact format of a path!
|
28
|
+
#
|
29
|
+
# == Relation to Source classes
|
9
30
|
#
|
10
31
|
# A webgen source class needs to derive a specialized path class from this class and implement an
|
11
32
|
# approriate #changed? method that returns +true+ if the path's content has changed since the last
|
@@ -13,15 +34,21 @@ module Webgen
|
|
13
34
|
class Path
|
14
35
|
|
15
36
|
# Helper class for easy access to the content of a path.
|
37
|
+
#
|
38
|
+
# This class is used sothat the creation of the real IO object for #stream can be delayed till
|
39
|
+
# it is actually needed. This is done by not directly requiring the user of this class to supply
|
40
|
+
# the IO object, but by requiring a block that creates the real IO object.
|
16
41
|
class SourceIO
|
17
42
|
|
18
|
-
# Create a new SourceIO object. A block has to be specified that returns
|
43
|
+
# Create a new SourceIO object. A block has to be specified that returns the to-be-wrapped IO
|
44
|
+
# object.
|
19
45
|
def initialize(&block)
|
20
46
|
@block = block
|
21
|
-
raise ArgumentError, '
|
47
|
+
raise ArgumentError, 'You need to provide a block which returns an IO object' if @block.nil?
|
22
48
|
end
|
23
49
|
|
24
|
-
# Provide direct access to the wrapped IO object.
|
50
|
+
# Provide direct access to the wrapped IO object by yielding it. After the method block
|
51
|
+
# returns the IO object is automatically closed.
|
25
52
|
def stream
|
26
53
|
io = @block.call
|
27
54
|
yield(io)
|
@@ -29,7 +56,7 @@ module Webgen
|
|
29
56
|
io.close
|
30
57
|
end
|
31
58
|
|
32
|
-
# Return the content of the wrapped IO object as string.
|
59
|
+
# Return the whole content of the wrapped IO object as string.
|
33
60
|
def data
|
34
61
|
stream {|io| io.read}
|
35
62
|
end
|
@@ -37,6 +64,13 @@ module Webgen
|
|
37
64
|
end
|
38
65
|
|
39
66
|
|
67
|
+
# Make the given +path+ absolute by prepending the absolute directory path +base+ if necessary.
|
68
|
+
# Also resolves all '..' and '.' references in +path+.
|
69
|
+
def self.make_absolute(base, path)
|
70
|
+
raise(ArgumentError, 'base has to be an absolute path, ie. needs to start with a slash') unless base =~ /\//
|
71
|
+
Pathname.new(path =~ /^\// ? path : File.join(base, path)).cleanpath.to_s
|
72
|
+
end
|
73
|
+
|
40
74
|
# Return +true+ if the given +path+ matches the given +pattern+ (trailing slashes of directories
|
41
75
|
# are not respected). For information on which patterns are supported, have a look at the
|
42
76
|
# documentation of File.fnmatch.
|
@@ -49,66 +83,86 @@ module Webgen
|
|
49
83
|
|
50
84
|
include Comparable
|
51
85
|
|
52
|
-
# The full path.
|
53
|
-
|
86
|
+
# The full path for which this Path object was created.
|
87
|
+
attr_reader :path
|
54
88
|
|
55
|
-
#
|
56
|
-
|
89
|
+
# A string specifying the path that lead to the creation of this path.
|
90
|
+
attr_reader :source_path
|
57
91
|
|
58
|
-
# The
|
59
|
-
|
92
|
+
# The string specifying the parent path
|
93
|
+
attr_reader :parent_path
|
60
94
|
|
61
|
-
# The
|
62
|
-
attr_accessor :
|
63
|
-
|
64
|
-
# The canonical name without the extension.
|
65
|
-
attr_accessor :cnbase
|
95
|
+
# The canonical name of the path without the extension.
|
96
|
+
attr_accessor :basename
|
66
97
|
|
67
|
-
# The extension
|
98
|
+
# The extension of the +path+.
|
68
99
|
attr_accessor :ext
|
69
100
|
|
70
101
|
# Extracted meta information for the path.
|
71
102
|
attr_accessor :meta_info
|
72
103
|
|
104
|
+
# Specifies whether this path should be used during the "tree update" phase of a webgen run or
|
105
|
+
# only later during node resolution.
|
106
|
+
attr_writer :passive
|
107
|
+
|
108
|
+
# Is this path only used later during node resolution? Defaults to +false+, i.e. used during the
|
109
|
+
# "tree update" phase.
|
110
|
+
def passive?; @passive; end
|
111
|
+
|
112
|
+
|
73
113
|
# Create a new Path object for +path+. The optional +source_path+ parameter specifies the path
|
74
|
-
# that lead to the creation of this path. The optional block needs to return an IO object
|
75
|
-
# the content of the path.
|
114
|
+
# string that lead to the creation of this path. The optional block needs to return an IO object
|
115
|
+
# for getting the content of the path.
|
116
|
+
#
|
117
|
+
# The +path+ needs to be in a well defined format which can be looked up in the webgen manual.
|
76
118
|
def initialize(path, source_path = path, &ioblock)
|
77
119
|
@meta_info = {}
|
78
120
|
@io = block_given? ? SourceIO.new(&ioblock) : nil
|
79
121
|
@source_path = source_path
|
122
|
+
@passive = false
|
80
123
|
analyse(path)
|
81
124
|
end
|
82
125
|
|
83
|
-
# Mount this path at the mount point +mp
|
84
|
-
# the new path object.
|
126
|
+
# Mount this path at the mount point +mp+, optionally stripping +prefix+ from the parent path,
|
127
|
+
# and return the new path object.
|
128
|
+
#
|
129
|
+
# The parameters +mp+ and +prefix+ have to be absolute directory paths, ie. they have to start
|
130
|
+
# and end with a slash and must not contain any hash characters!
|
131
|
+
#
|
132
|
+
#--
|
133
|
+
# Can't use self.class.new(...) here because the semantics of the sub constructors is not know
|
134
|
+
#++
|
85
135
|
def mount_at(mp, prefix = nil)
|
136
|
+
raise(ArgumentError, "The mount point (#{mp}) must be a valid directory path") if mp =~ /^[^\/]|#|[^\/]$/
|
137
|
+
raise(ArgumentError, "The strip prefix (#{prefix}) must be a valid directory path") if !prefix.nil? && prefix =~ /^[^\/]|#|[^\/]$/
|
138
|
+
|
86
139
|
temp = dup
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
temp.
|
140
|
+
strip_re = /^#{Regexp.escape(prefix.to_s)}/
|
141
|
+
temp.instance_variable_set(:@path, temp.path.sub(strip_re, ''))
|
142
|
+
reanalyse = (@path == '/' || temp.path == '')
|
143
|
+
temp.instance_variable_set(:@path, File.join(mp, temp.path))
|
144
|
+
temp.instance_variable_set(:@source_path, temp.path) if @path == @source_path
|
91
145
|
if reanalyse
|
92
146
|
temp.send(:analyse, temp.path)
|
93
147
|
else
|
94
|
-
temp.
|
148
|
+
temp.instance_variable_set(:@parent_path, File.join(mp, temp.parent_path.sub(strip_re, '')))
|
95
149
|
end
|
96
150
|
temp
|
97
151
|
end
|
98
152
|
|
99
|
-
# Has the content of this path changed since the last webgen run? This default implementation
|
100
|
-
# always returns +true+, a specialized sub class needs to override this behaviour!
|
101
|
-
def changed?
|
102
|
-
true
|
103
|
-
end
|
104
|
-
|
105
153
|
# Duplicate the path object.
|
106
154
|
def dup
|
107
155
|
temp = super
|
108
|
-
temp.meta_info
|
156
|
+
temp.instance_variable_set(:@meta_info, @meta_info.dup)
|
109
157
|
temp
|
110
158
|
end
|
111
159
|
|
160
|
+
# Has the content of this path changed since the last webgen run? This default implementation
|
161
|
+
# always returns +true+, a specialized sub class needs to override this behaviour!
|
162
|
+
def changed?
|
163
|
+
true
|
164
|
+
end
|
165
|
+
|
112
166
|
# The SourceIO object associated with the path.
|
113
167
|
def io
|
114
168
|
if @io
|
@@ -118,26 +172,45 @@ module Webgen
|
|
118
172
|
end
|
119
173
|
end
|
120
174
|
|
121
|
-
# The canonical name created from the
|
175
|
+
# The canonical name created from the +path+ (namely from the parts +basename+ and +extension+).
|
122
176
|
def cn
|
123
|
-
@
|
177
|
+
@basename + (@ext.length > 0 ? '.' + @ext : '') + (@basename != '/' && @path =~ /.\/$/ ? '/' : '')
|
124
178
|
end
|
125
179
|
|
126
|
-
# Utility method for creating the lcn from +cn+ and the language +lang+.
|
180
|
+
# Utility method for creating the lcn from the +cn+ and the language +lang+.
|
127
181
|
def self.lcn(cn, lang)
|
128
182
|
if lang.nil?
|
129
183
|
cn
|
130
184
|
else
|
131
|
-
cn.split('.').insert(1, lang.to_s).join('.')
|
185
|
+
cn.split('.').insert((cn =~ /^\./ ? 2 : 1), lang.to_s).join('.')
|
132
186
|
end
|
133
187
|
end
|
134
188
|
|
135
|
-
# The localized canonical name created from the
|
189
|
+
# The localized canonical name created from the +path+.
|
136
190
|
def lcn
|
137
191
|
self.class.lcn(cn, @meta_info['lang'])
|
138
192
|
end
|
139
193
|
|
140
|
-
#
|
194
|
+
# The absolute canonical name of this path.
|
195
|
+
def acn
|
196
|
+
if @path =~ /#/
|
197
|
+
self.class.new(@parent_path).acn + cn
|
198
|
+
else
|
199
|
+
@parent_path + cn
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# The absolute localized canonical name of this path.
|
204
|
+
def alcn
|
205
|
+
if @path =~ /#/
|
206
|
+
self.class.new(@parent_path).alcn + lcn
|
207
|
+
else
|
208
|
+
@parent_path + lcn
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Equality -- Return +true+ if +other+ is a Path object with the same #path or if +other+ is a
|
213
|
+
# String equal to the #path. Else return +false+.
|
141
214
|
def ==(other)
|
142
215
|
if other.kind_of?(Path)
|
143
216
|
other.path == @path
|
@@ -149,13 +222,12 @@ module Webgen
|
|
149
222
|
end
|
150
223
|
alias_method(:eql?, :==)
|
151
224
|
|
152
|
-
#
|
225
|
+
# Compare the #path of this object to <tt>other.path</tt>
|
153
226
|
def <=>(other)
|
154
|
-
@path <=> other.
|
227
|
+
@path <=> other.path
|
155
228
|
end
|
156
229
|
|
157
|
-
|
158
|
-
def hash
|
230
|
+
def hash #:nodoc:
|
159
231
|
@path.hash
|
160
232
|
end
|
161
233
|
|
@@ -172,21 +244,46 @@ module Webgen
|
|
172
244
|
private
|
173
245
|
#######
|
174
246
|
|
175
|
-
FILENAME_RE = /^(?:(\d+)\.)?([^.]*?)(?:\.(\w\w\w?)(?=.))?(?:\.(.*))?$/
|
176
|
-
|
177
247
|
# Analyse the +path+ and fill the object with the extracted information.
|
178
248
|
def analyse(path)
|
179
249
|
@path = path
|
180
|
-
@
|
181
|
-
|
182
|
-
|
250
|
+
if @path =~ /#/
|
251
|
+
analyse_fragment
|
252
|
+
elsif @path =~ /\/$/
|
253
|
+
analyse_directory
|
254
|
+
else
|
255
|
+
analyse_file
|
256
|
+
end
|
257
|
+
@meta_info['title'] = @basename.tr('_-', ' ').capitalize
|
258
|
+
@ext ||= ''
|
259
|
+
raise "The basename of a path may not be empty: #{@path}" if @basename.empty? || @basename == '#'
|
260
|
+
raise "The parent path must start with a slash: #{@path}" if @path !~ /^\// && @path != '/'
|
261
|
+
end
|
183
262
|
|
184
|
-
|
185
|
-
|
186
|
-
@
|
187
|
-
@
|
263
|
+
# Analyse the path assuming it is a directory.
|
264
|
+
def analyse_directory
|
265
|
+
@parent_path = (@path == '/' ? '' : File.join(File.dirname(@path), '/'))
|
266
|
+
@basename = File.basename(@path)
|
267
|
+
end
|
268
|
+
|
269
|
+
FILENAME_RE = /^(?:(\d+)\.)?(\.?[^.]*?)(?:\.(\w\w\w?)(?=\.))?(?:\.(.*))?$/
|
270
|
+
|
271
|
+
# Analyse the path assuming it is a file.
|
272
|
+
def analyse_file
|
273
|
+
@parent_path = File.join(File.dirname(@path), '/')
|
274
|
+
match_data = FILENAME_RE.match(File.basename(@path))
|
275
|
+
|
276
|
+
@meta_info['sort_info'] = (match_data[1].nil? ? nil : match_data[1].to_i)
|
277
|
+
@basename = match_data[2]
|
278
|
+
@meta_info['lang'] = Webgen::LanguageManager.language_for_code(match_data[3])
|
279
|
+
@ext = (@meta_info['lang'].nil? && !match_data[3].nil? ? match_data[3].to_s : '') + match_data[4].to_s
|
280
|
+
end
|
188
281
|
|
189
|
-
|
282
|
+
# Analyse the path assuming it is a fragment.
|
283
|
+
def analyse_fragment
|
284
|
+
@parent_path, @basename = @path.scan(/^(.*?)(#.*?)$/).first
|
285
|
+
raise "The parent path of a fragment path must be a file path and not a directory path: #{@path}" if @parent_path =~ /\/$/
|
286
|
+
raise "A fragment path must only contain one hash character: #{path}" if @path.count("#") > 1
|
190
287
|
end
|
191
288
|
|
192
289
|
end
|
data/lib/webgen/source.rb
CHANGED
@@ -10,9 +10,10 @@ module Webgen
|
|
10
10
|
#
|
11
11
|
# A source class only needs to respond to the method +paths+ which needs to return a set of paths
|
12
12
|
# for the source. The returned paths must respond to the method <tt>changed?</tt> (has to return
|
13
|
-
# +true+ if the paths has changed since the last webgen run).
|
14
|
-
#
|
15
|
-
# singleton methods on each path
|
13
|
+
# +true+ if the paths has changed since the last webgen run). If a path represents a directory, it
|
14
|
+
# needs to have a trailing slash! The default implementation in the Path class just returns
|
15
|
+
# +true+. One can either derive a specialized path class or define singleton methods on each path
|
16
|
+
# object.
|
16
17
|
#
|
17
18
|
# == Sample Source Class
|
18
19
|
#
|
@@ -36,10 +37,9 @@ module Webgen
|
|
36
37
|
# end
|
37
38
|
#
|
38
39
|
# You can use this source class in your website (after placing the code in, for example,
|
39
|
-
# <tt>ext/init.rb</tt>) by updating the <tt>sources</tt> configuration option
|
40
|
-
# has to be placed after the definition of the +MemorySource+ class):
|
40
|
+
# <tt>ext/init.rb</tt>) by updating the <tt>sources</tt> configuration option:
|
41
41
|
#
|
42
|
-
# WebsiteAccess.website.config['sources'] << ['/', MemorySource]
|
42
|
+
# WebsiteAccess.website.config['sources'] << ['/', 'MemorySource']
|
43
43
|
#
|
44
44
|
module Source
|
45
45
|
|
@@ -17,20 +17,27 @@ module Webgen::Source
|
|
17
17
|
# source, it is discarded and not used.
|
18
18
|
class Stacked
|
19
19
|
|
20
|
-
# Return the stack of Webgen::Source
|
20
|
+
# Return the stack of mount point to Webgen::Source object maps.
|
21
21
|
attr_reader :stack
|
22
22
|
|
23
|
+
# Specifies whether the result of #paths calls should be cached (default: +false+). If caching
|
24
|
+
# is activated, new maps cannot be added to the stacked source anymore!
|
25
|
+
attr_accessor :cache_paths
|
26
|
+
|
23
27
|
# Create a new stack. The optional +map+ parameter can be used to provide initial mappings of
|
24
|
-
# mount points to source objects (see #add for details).
|
25
|
-
|
28
|
+
# mount points to source objects (see #add for details). You cannot add other maps after a call
|
29
|
+
# to #paths if +cache_paths+ is +true+
|
30
|
+
def initialize(map = {}, cache_paths = false)
|
26
31
|
@stack = []
|
32
|
+
@cache_paths = cache_paths
|
27
33
|
add(map)
|
28
34
|
end
|
29
35
|
|
30
36
|
# Add all mappings found in +maps+ to the stack. The parameter +maps+ should be an array of
|
31
|
-
# two-element arrays which contain an absolute
|
32
|
-
# source object.
|
37
|
+
# two-element arrays which contain an absolute directory (ie. starting and ending with a slash)
|
38
|
+
# and a source object.
|
33
39
|
def add(maps)
|
40
|
+
raise "Cannot add new maps since caching is activated for this source" if defined?(@paths) && @cache_paths
|
34
41
|
maps.each do |mp, source|
|
35
42
|
raise "Invalid mount point specified: #{mp}" unless mp =~ /^\//
|
36
43
|
@stack << [mp, source]
|
@@ -41,6 +48,7 @@ module Webgen::Source
|
|
41
48
|
# returned by later source objects are not used if a prior source object has returned the same
|
42
49
|
# path.
|
43
50
|
def paths
|
51
|
+
return @paths if defined?(@paths) && @cache_paths
|
44
52
|
@paths = Set.new
|
45
53
|
@stack.each do |mp, source|
|
46
54
|
source.paths.each do |path|
|
data/lib/webgen/sourcehandler.rb
CHANGED
@@ -28,6 +28,7 @@ module Webgen
|
|
28
28
|
# * collects all source paths using the source classes
|
29
29
|
# * creates nodes using the source handler classes
|
30
30
|
# * writes changed nodes out using an output class
|
31
|
+
# * deletes old nodes
|
31
32
|
class Main
|
32
33
|
|
33
34
|
include WebsiteAccess
|
@@ -35,34 +36,40 @@ module Webgen
|
|
35
36
|
|
36
37
|
def initialize #:nodoc:
|
37
38
|
website.blackboard.add_service(:create_nodes, method(:create_nodes))
|
39
|
+
website.blackboard.add_service(:create_nodes_from_paths, method(:create_nodes_from_paths))
|
38
40
|
website.blackboard.add_service(:source_paths, method(:find_all_source_paths))
|
39
41
|
website.blackboard.add_listener(:node_meta_info_changed?, method(:meta_info_changed?))
|
42
|
+
|
43
|
+
website.blackboard.add_listener(:before_node_deleted) do |node|
|
44
|
+
website.blackboard.invoke(:output_instance).delete(node.path)
|
45
|
+
end if website.config['output.do_deletion']
|
40
46
|
end
|
41
47
|
|
42
|
-
# Render the
|
43
|
-
#
|
44
|
-
|
48
|
+
# Render the current website. Before the actual rendering is done, the sources are checked for
|
49
|
+
# changes, i.e. nodes for deleted sources are deleted, nodes for new and changed sources are
|
50
|
+
# updated.
|
51
|
+
def render
|
45
52
|
begin
|
46
53
|
website.logger.mark_new_cycle if website.logger
|
47
54
|
|
48
55
|
puts "Updating tree..."
|
49
56
|
time = Benchmark.measure do
|
50
57
|
website.cache.reset_volatile_cache
|
51
|
-
update_tree
|
58
|
+
update_tree
|
52
59
|
end
|
53
60
|
puts "...done in " + ('%2.4f' % time.real) + ' seconds'
|
54
61
|
|
55
|
-
if !tree.root
|
62
|
+
if !website.tree.root
|
56
63
|
puts 'No source files found - maybe not a webgen website?'
|
57
64
|
return nil
|
58
65
|
end
|
59
66
|
|
60
67
|
puts "Writing changed nodes..."
|
61
68
|
time = Benchmark.measure do
|
62
|
-
write_tree
|
69
|
+
write_tree
|
63
70
|
end
|
64
71
|
puts "...done in " + ('%2.4f' % time.real) + ' seconds'
|
65
|
-
end while tree.node_access[:alcn].any? {|name,node| node.flagged?(:created) || node.flagged?(:reinit)}
|
72
|
+
end while website.tree.node_access[:alcn].any? {|name,node| node.flagged?(:created) || node.flagged?(:reinit)}
|
66
73
|
:success
|
67
74
|
end
|
68
75
|
|
@@ -70,45 +77,60 @@ module Webgen
|
|
70
77
|
private
|
71
78
|
#######
|
72
79
|
|
73
|
-
# Update the
|
74
|
-
def update_tree
|
80
|
+
# Update the <tt>website.tree</tt> by creating/reinitializing all needed nodes.
|
81
|
+
def update_tree
|
75
82
|
unused_paths = Set.new
|
83
|
+
referenced_nodes = Set.new
|
84
|
+
all_but_passive_paths = Set.new(find_all_source_paths.select {|name, path| !path.passive?}.collect {|name, path| name})
|
76
85
|
begin
|
77
|
-
used_paths =
|
86
|
+
used_paths = all_but_passive_paths - unused_paths
|
78
87
|
paths_to_use = Set.new
|
79
88
|
nodes_to_delete = Set.new
|
89
|
+
passive_nodes = Set.new
|
80
90
|
|
81
|
-
tree.node_access[:alcn].each do |alcn, node|
|
82
|
-
next if node == tree.dummy_root
|
91
|
+
website.tree.node_access[:alcn].each do |alcn, node|
|
92
|
+
next if node == website.tree.dummy_root
|
83
93
|
used_paths.delete(node.node_info[:src])
|
84
94
|
|
85
|
-
|
86
|
-
if
|
95
|
+
src_path = find_all_source_paths[node.node_info[:src]]
|
96
|
+
if !src_path
|
87
97
|
nodes_to_delete << node
|
88
|
-
|
89
|
-
elsif (!node.flagged?(:created) && find_all_source_paths[node.node_info[:src]].changed?) || node.meta_info_changed?
|
98
|
+
elsif (!node.flagged?(:created) && src_path.changed?) || node.meta_info_changed?
|
90
99
|
node.flag(:reinit)
|
91
100
|
paths_to_use << node.node_info[:src]
|
92
101
|
elsif node.changed?
|
93
|
-
# nothing to be done here
|
102
|
+
# nothing to be done here but method node.changed? has to be called
|
103
|
+
end
|
104
|
+
|
105
|
+
if src_path && src_path.passive?
|
106
|
+
passive_nodes << node
|
107
|
+
elsif src_path
|
108
|
+
referenced_nodes += node.node_info[:used_meta_info_nodes] + node.node_info[:used_nodes]
|
94
109
|
end
|
95
110
|
end
|
96
111
|
|
97
|
-
|
112
|
+
# add unused passive nodes to node_to_delete set
|
113
|
+
unreferenced_passive_nodes, other_passive_nodes = passive_nodes.partition do |pnode|
|
114
|
+
!referenced_nodes.include?(pnode.alcn)
|
115
|
+
end
|
116
|
+
refs = other_passive_nodes.collect {|n| (n.node_info[:used_meta_info_nodes] + n.node_info[:used_nodes]).to_a}.flatten
|
117
|
+
unreferenced_passive_nodes.each {|n| nodes_to_delete << n if !refs.include?(n.alcn)}
|
118
|
+
|
119
|
+
nodes_to_delete.each {|node| website.tree.delete_node(node)}
|
98
120
|
used_paths.merge(paths_to_use)
|
99
|
-
paths = create_nodes_from_paths(
|
121
|
+
paths = create_nodes_from_paths(used_paths.to_a.sort)
|
100
122
|
unused_paths.merge(used_paths - paths)
|
101
|
-
tree.node_access[:alcn].each {|name, node| tree.delete_node(node) if node.flagged?(:reinit)}
|
123
|
+
website.tree.node_access[:alcn].each {|name, node| website.tree.delete_node(node) if node.flagged?(:reinit)}
|
102
124
|
website.cache.reset_volatile_cache
|
103
125
|
end until used_paths.empty?
|
104
126
|
end
|
105
127
|
|
106
|
-
# Write out all changed nodes of the
|
107
|
-
def write_tree
|
128
|
+
# Write out all changed nodes of the <tt>website.tree</tt>.
|
129
|
+
def write_tree
|
108
130
|
output = website.blackboard.invoke(:output_instance)
|
109
131
|
|
110
|
-
tree.node_access[:alcn].select do |name, node|
|
111
|
-
use_node = (node != tree.dummy_root && node.flagged?(:dirty))
|
132
|
+
website.tree.node_access[:alcn].select do |name, node|
|
133
|
+
use_node = (node != website.tree.dummy_root && node.flagged?(:dirty))
|
112
134
|
node.unflag(:dirty_meta_info)
|
113
135
|
node.unflag(:created)
|
114
136
|
node.unflag(:dirty)
|
@@ -127,7 +149,7 @@ module Webgen
|
|
127
149
|
end
|
128
150
|
output.write(node.path, content, type)
|
129
151
|
rescue
|
130
|
-
raise RuntimeError, "Error while processing <#{node.
|
152
|
+
raise RuntimeError, "Error while processing <#{node.alcn}>: #{$!.message}", $!.backtrace
|
131
153
|
end
|
132
154
|
end
|
133
155
|
end
|
@@ -135,9 +157,15 @@ module Webgen
|
|
135
157
|
# Return a hash with all source paths.
|
136
158
|
def find_all_source_paths
|
137
159
|
if !defined?(@paths)
|
138
|
-
|
139
|
-
|
140
|
-
|
160
|
+
active_source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args|
|
161
|
+
[mp, constant(name).new(*args)]
|
162
|
+
end)
|
163
|
+
passive_source = Webgen::Source::Stacked.new(website.config['passive_sources'].collect do |mp, name, *args|
|
164
|
+
[mp, constant(name).new(*args)]
|
165
|
+
end, true)
|
166
|
+
passive_source.paths.each {|path| path.passive = true }
|
167
|
+
source = Webgen::Source::Stacked.new([['/', active_source], ['/', passive_source]])
|
168
|
+
|
141
169
|
@paths = {}
|
142
170
|
source.paths.each do |path|
|
143
171
|
if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)})
|
@@ -155,13 +183,13 @@ module Webgen
|
|
155
183
|
|
156
184
|
options = (website.config['sourcehandler.casefold'] ? File::FNM_CASEFOLD : 0) |
|
157
185
|
(website.config['sourcehandler.use_hidden_files'] ? File::FNM_DOTMATCH : 0)
|
158
|
-
find_all_source_paths.values_at(*paths).select do |path|
|
186
|
+
find_all_source_paths.values_at(*paths).compact.select do |path|
|
159
187
|
patterns.any? {|pat| File.fnmatch(pat, path, options)}
|
160
188
|
end
|
161
189
|
end
|
162
190
|
|
163
|
-
# Use the source handlers to create nodes for the +paths+ in the
|
164
|
-
def create_nodes_from_paths(
|
191
|
+
# Use the source handlers to create nodes for the +paths+ in the <tt>website.tree</tt>.
|
192
|
+
def create_nodes_from_paths(paths)
|
165
193
|
used_paths = Set.new
|
166
194
|
website.config['sourcehandler.invoke'].sort.each do |priority, shns|
|
167
195
|
shns.each do |shn|
|
@@ -169,31 +197,29 @@ module Webgen
|
|
169
197
|
handler_paths = paths_for_handler(shn, paths)
|
170
198
|
used_paths.merge(handler_paths)
|
171
199
|
handler_paths.sort {|a,b| a.path.length <=> b.path.length}.each do |path|
|
172
|
-
|
173
|
-
|
174
|
-
|
200
|
+
if !website.tree[path.parent_path]
|
201
|
+
used_paths.merge(create_nodes_from_paths([path.parent_path]))
|
202
|
+
end
|
203
|
+
create_nodes(path, sh)
|
175
204
|
end
|
176
205
|
end
|
177
206
|
end
|
178
207
|
used_paths
|
179
208
|
end
|
180
209
|
|
181
|
-
# Prepare everything to create
|
182
|
-
#
|
183
|
-
# of the
|
184
|
-
# all needed properties.
|
185
|
-
def create_nodes(
|
186
|
-
if !(parent = tree[parent_path_name])
|
187
|
-
raise "The specified parent path <#{parent_path_name}> does not exist"
|
188
|
-
end
|
210
|
+
# Prepare everything to create from the +path+ using the +source_handler+. If a block is
|
211
|
+
# given, the actual creation of the nodes is deferred to it. Otherwise the #create_node method
|
212
|
+
# of the +source_handler+ is used. After the nodes are created, it is also checked if they
|
213
|
+
# have all needed properties.
|
214
|
+
def create_nodes(path, source_handler) #:yields: path
|
189
215
|
path = path.dup
|
190
216
|
path.meta_info = default_meta_info(path, source_handler.class.name)
|
191
217
|
(website.cache[:sourcehandler_path_mi] ||= {})[[path.path, source_handler.class.name]] = path.meta_info.dup
|
192
|
-
website.blackboard.dispatch_msg(:before_node_created,
|
218
|
+
website.blackboard.dispatch_msg(:before_node_created, path)
|
193
219
|
*nodes = if block_given?
|
194
|
-
yield(
|
220
|
+
yield(path)
|
195
221
|
else
|
196
|
-
source_handler.create_node(
|
222
|
+
source_handler.create_node(path)
|
197
223
|
end
|
198
224
|
nodes.flatten.compact.each do |node|
|
199
225
|
website.blackboard.dispatch_msg(:after_node_created, node)
|