gettalong-webgen 0.5.8.20090507 → 0.5.9.20090620
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/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)
|