webgen 0.5.8 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/COPYING +4 -0
  2. data/ChangeLog +1037 -0
  3. data/Rakefile +5 -6
  4. data/THANKS +1 -0
  5. data/VERSION +1 -1
  6. data/bin/webgen +1 -1
  7. data/data/webgen/passive_sources/images/generated_by_webgen.png +0 -0
  8. data/data/webgen/passive_sources/images/webgen_logo.png +0 -0
  9. data/data/webgen/passive_sources/stylesheets/coderay-default.css +129 -0
  10. data/data/webgen/passive_sources/templates/atom_feed.template +38 -0
  11. data/data/webgen/passive_sources/templates/rss_feed.template +28 -0
  12. data/data/webgen/passive_sources/templates/sitemap.template +21 -0
  13. data/data/webgen/resources.yaml +2 -1
  14. data/data/webgen/website_skeleton/Rakefile +5 -1
  15. data/doc/contentprocessor/builder.page +2 -2
  16. data/doc/contentprocessor/erb.page +5 -2
  17. data/doc/contentprocessor/erubis.page +2 -2
  18. data/doc/contentprocessor/head.page +21 -0
  19. data/doc/contentprocessor/tidy.page +14 -0
  20. data/doc/extensions.page +1 -1
  21. data/doc/faq.page +2 -2
  22. data/doc/manual.page +108 -43
  23. data/doc/reference_configuration.page +83 -5
  24. data/doc/reference_metainfo.page +24 -4
  25. data/doc/reference_website_styles.page +2 -2
  26. data/doc/sourcehandler/feed.page +11 -13
  27. data/doc/sourcehandler/metainfo.page +10 -3
  28. data/doc/sourcehandler/page.page +4 -4
  29. data/doc/sourcehandler/sitemap.page +8 -7
  30. data/doc/tag/coderay.page +6 -2
  31. data/doc/tag/includefile.page +1 -1
  32. data/doc/tag/menu.page +3 -0
  33. data/lib/webgen/cli/apply_command.rb +1 -1
  34. data/lib/webgen/cli/utils.rb +2 -2
  35. data/lib/webgen/common.rb +0 -9
  36. data/lib/webgen/contentprocessor.rb +18 -3
  37. data/lib/webgen/contentprocessor/blocks.rb +67 -36
  38. data/lib/webgen/contentprocessor/builder.rb +5 -2
  39. data/lib/webgen/contentprocessor/erb.rb +4 -2
  40. data/lib/webgen/contentprocessor/erubis.rb +5 -2
  41. data/lib/webgen/contentprocessor/haml.rb +6 -2
  42. data/lib/webgen/contentprocessor/head.rb +64 -0
  43. data/lib/webgen/contentprocessor/maruku.rb +3 -1
  44. data/lib/webgen/contentprocessor/rdiscount.rb +2 -0
  45. data/lib/webgen/contentprocessor/rdoc.rb +2 -0
  46. data/lib/webgen/contentprocessor/redcloth.rb +2 -0
  47. data/lib/webgen/contentprocessor/sass.rb +5 -3
  48. data/lib/webgen/contentprocessor/tags.rb +40 -24
  49. data/lib/webgen/contentprocessor/tidy.rb +38 -0
  50. data/lib/webgen/context.rb +13 -4
  51. data/lib/webgen/context/render.rb +32 -0
  52. data/lib/webgen/context/tags.rb +20 -0
  53. data/lib/webgen/default_config.rb +15 -4
  54. data/lib/webgen/deprecated.rb +38 -4
  55. data/lib/webgen/error.rb +135 -0
  56. data/lib/webgen/node.rb +48 -40
  57. data/lib/webgen/output.rb +5 -3
  58. data/lib/webgen/output/filesystem.rb +4 -4
  59. data/lib/webgen/page.rb +4 -4
  60. data/lib/webgen/path.rb +161 -58
  61. data/lib/webgen/source.rb +9 -6
  62. data/lib/webgen/source/filesystem.rb +1 -1
  63. data/lib/webgen/source/stacked.rb +13 -5
  64. data/lib/webgen/source/tararchive.rb +6 -2
  65. data/lib/webgen/sourcehandler.rb +100 -54
  66. data/lib/webgen/sourcehandler/base.rb +58 -24
  67. data/lib/webgen/sourcehandler/copy.rb +6 -5
  68. data/lib/webgen/sourcehandler/directory.rb +3 -9
  69. data/lib/webgen/sourcehandler/feed.rb +25 -50
  70. data/lib/webgen/sourcehandler/fragment.rb +10 -8
  71. data/lib/webgen/sourcehandler/memory.rb +9 -10
  72. data/lib/webgen/sourcehandler/metainfo.rb +9 -9
  73. data/lib/webgen/sourcehandler/page.rb +6 -5
  74. data/lib/webgen/sourcehandler/sitemap.rb +22 -22
  75. data/lib/webgen/sourcehandler/template.rb +6 -6
  76. data/lib/webgen/sourcehandler/virtual.rb +19 -17
  77. data/lib/webgen/tag/base.rb +27 -27
  78. data/lib/webgen/tag/breadcrumbtrail.rb +3 -3
  79. data/lib/webgen/tag/coderay.rb +19 -8
  80. data/lib/webgen/tag/executecommand.rb +4 -3
  81. data/lib/webgen/tag/langbar.rb +2 -2
  82. data/lib/webgen/tag/link.rb +8 -7
  83. data/lib/webgen/tag/menu.rb +2 -2
  84. data/lib/webgen/tag/metainfo.rb +1 -1
  85. data/lib/webgen/tag/relocatable.rb +17 -21
  86. data/lib/webgen/tag/tikz.rb +7 -10
  87. data/lib/webgen/tree.rb +7 -7
  88. data/lib/webgen/version.rb +1 -1
  89. data/lib/webgen/website.rb +32 -2
  90. data/misc/default.css +8 -2
  91. data/misc/default.template +2 -2
  92. data/misc/logo.svg +313 -0
  93. data/misc/style.page +1 -1
  94. data/test/helper.rb +18 -2
  95. data/test/test_cli.rb +104 -0
  96. data/test/test_common_sitemap.rb +1 -1
  97. data/test/test_contentprocessor.rb +8 -2
  98. data/test/test_contentprocessor_blocks.rb +17 -8
  99. data/test/test_contentprocessor_builder.rb +13 -2
  100. data/test/test_contentprocessor_erb.rb +9 -3
  101. data/test/test_contentprocessor_erubis.rb +9 -3
  102. data/test/test_contentprocessor_fragments.rb +12 -11
  103. data/test/test_contentprocessor_haml.rb +11 -2
  104. data/test/test_contentprocessor_head.rb +44 -0
  105. data/test/test_contentprocessor_maruku.rb +5 -1
  106. data/test/test_contentprocessor_rdiscount.rb +4 -0
  107. data/test/test_contentprocessor_rdoc.rb +4 -0
  108. data/test/test_contentprocessor_redcloth.rb +5 -1
  109. data/test/test_contentprocessor_sass.rb +8 -2
  110. data/test/test_contentprocessor_tags.rb +22 -7
  111. data/test/test_contentprocessor_tidy.rb +34 -0
  112. data/test/test_context.rb +39 -0
  113. data/test/test_error.rb +85 -0
  114. data/test/test_node.rb +57 -21
  115. data/test/test_page.rb +23 -5
  116. data/test/test_path.rb +120 -64
  117. data/test/test_source_filesystem.rb +1 -1
  118. data/test/test_source_stacked.rb +19 -6
  119. data/test/test_sourcehandler_base.rb +63 -50
  120. data/test/test_sourcehandler_copy.rb +6 -6
  121. data/test/test_sourcehandler_directory.rb +8 -12
  122. data/test/test_sourcehandler_feed.rb +15 -7
  123. data/test/test_sourcehandler_fragment.rb +6 -5
  124. data/test/test_sourcehandler_main.rb +39 -0
  125. data/test/test_sourcehandler_memory.rb +4 -4
  126. data/test/test_sourcehandler_metainfo.rb +20 -11
  127. data/test/test_sourcehandler_page.rb +10 -10
  128. data/test/test_sourcehandler_sitemap.rb +24 -5
  129. data/test/test_sourcehandler_template.rb +18 -15
  130. data/test/test_sourcehandler_virtual.rb +9 -5
  131. data/test/test_tag_base.rb +6 -29
  132. data/test/test_tag_coderay.rb +16 -3
  133. data/test/test_tag_executecommand.rb +2 -2
  134. data/test/test_tag_link.rb +5 -4
  135. data/test/test_tag_menu.rb +15 -15
  136. data/test/test_tag_metainfo.rb +1 -0
  137. data/test/test_tag_relocatable.rb +3 -2
  138. data/test/test_tag_tikz.rb +5 -5
  139. data/test/test_tree.rb +8 -8
  140. data/test/test_website.rb +15 -0
  141. metadata +21 -14
  142. data/test/test_common.rb +0 -18
@@ -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 objects.
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
- def initialize(map = {})
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 directoriy (ie. starting with a slash) and a
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|
@@ -5,7 +5,11 @@ require 'webgen/websiteaccess'
5
5
  require 'webgen/path'
6
6
  require 'open-uri'
7
7
  require 'zlib'
8
- require 'archive/tar/minitar'
8
+ begin
9
+ require 'archive/tar/minitar'
10
+ rescue LoadError
11
+ raise Webgen::LoadError.new('archive/tar/minitar', self.class.name, context.dest_node.alcn, 'archive-tar-minitar')
12
+ end
9
13
 
10
14
  module Webgen
11
15
 
@@ -24,7 +28,7 @@ module Webgen
24
28
 
25
29
  # Create a new tar archive path object for the entry +entry+.
26
30
  def initialize(path, data, mtime, uri)
27
- super(path) { StringIO.new(data.to_s) }
31
+ super(path) {|mode| StringIO.new(data.to_s, mode) }
28
32
  @uri = uri
29
33
  @mtime = mtime
30
34
  WebsiteAccess.website.cache[[:tararchive_path, @uri, path]] = @mtime if WebsiteAccess.website
@@ -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,88 +36,121 @@ 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 nodes provided in the +tree+. Before the actual rendering is done, the sources
43
- # are checked (nodes for deleted sources are deleted, nodes for new and changed sources).
44
- def render(tree)
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(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(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
74
+ rescue Webgen::Error
75
+ raise
76
+ rescue Exception => e
77
+ raise Webgen::Error.new(e)
67
78
  end
68
79
 
69
80
  #######
70
81
  private
71
82
  #######
72
83
 
73
- # Update the +tree+ by creating/reinitializing all needed nodes.
74
- def update_tree(tree)
84
+ # Update the <tt>website.tree</tt> by creating/reinitializing all needed nodes.
85
+ def update_tree
75
86
  unused_paths = Set.new
87
+ referenced_nodes = Set.new
88
+ all_but_passive_paths = Set.new(find_all_source_paths.select {|name, path| !path.passive?}.collect {|name, path| name})
76
89
  begin
77
- used_paths = Set.new(find_all_source_paths.keys) - unused_paths
90
+ used_paths = all_but_passive_paths - unused_paths
78
91
  paths_to_use = Set.new
79
92
  nodes_to_delete = Set.new
93
+ passive_nodes = Set.new
94
+
95
+ website.tree.node_access[:alcn].each do |alcn, node|
96
+ next if node == website.tree.dummy_root
97
+
98
+ begin
99
+ used_paths.delete(node.node_info[:src])
80
100
 
81
- tree.node_access[:alcn].each do |alcn, node|
82
- next if node == tree.dummy_root
83
- used_paths.delete(node.node_info[:src])
84
-
85
- deleted = !find_all_source_paths.include?(node.node_info[:src])
86
- if deleted
87
- nodes_to_delete << node
88
- #TODO: delete output path
89
- elsif (!node.flagged?(:created) && find_all_source_paths[node.node_info[:src]].changed?) || node.meta_info_changed?
90
- node.flag(:reinit)
91
- paths_to_use << node.node_info[:src]
92
- elsif node.changed?
93
- # nothing to be done here
101
+ src_path = find_all_source_paths[node.node_info[:src]]
102
+ if !src_path
103
+ nodes_to_delete << node
104
+ elsif (!node.flagged?(:created) && src_path.changed?) || node.meta_info_changed?
105
+ node.flag(:reinit)
106
+ paths_to_use << node.node_info[:src]
107
+ elsif node.changed?
108
+ # nothing to be done here but method node.changed? has to be called
109
+ end
110
+
111
+ if src_path && src_path.passive?
112
+ passive_nodes << node
113
+ elsif src_path
114
+ referenced_nodes += node.node_info[:used_meta_info_nodes] + node.node_info[:used_nodes]
115
+ end
116
+ rescue Webgen::Error => e
117
+ e.alcn = node.alcn unless e.alcn
118
+ raise
119
+ rescue Exception => e
120
+ raise Webgen::Error.new(e, nil, node.alcn)
94
121
  end
95
122
  end
96
123
 
97
- nodes_to_delete.each {|node| tree.delete_node(node)}
124
+ # add unused passive nodes to node_to_delete set
125
+ unreferenced_passive_nodes, other_passive_nodes = passive_nodes.partition do |pnode|
126
+ !referenced_nodes.include?(pnode.alcn)
127
+ end
128
+ refs = other_passive_nodes.collect {|n| (n.node_info[:used_meta_info_nodes] + n.node_info[:used_nodes]).to_a}.flatten
129
+ unreferenced_passive_nodes.each {|n| nodes_to_delete << n if !refs.include?(n.alcn)}
130
+
131
+ nodes_to_delete.each {|node| website.tree.delete_node(node)}
98
132
  used_paths.merge(paths_to_use)
99
- paths = create_nodes_from_paths(tree, used_paths.to_a.sort)
133
+ paths = create_nodes_from_paths(used_paths.to_a.sort)
100
134
  unused_paths.merge(used_paths - paths)
101
- tree.node_access[:alcn].each {|name, node| tree.delete_node(node) if node.flagged?(:reinit)}
135
+ website.tree.node_access[:alcn].each {|name, node| website.tree.delete_node(node) if node.flagged?(:reinit)}
102
136
  website.cache.reset_volatile_cache
103
137
  end until used_paths.empty?
104
138
  end
105
139
 
106
- # Write out all changed nodes of the +tree+.
107
- def write_tree(tree)
140
+ # Write out all changed nodes of the <tt>website.tree</tt>.
141
+ def write_tree
108
142
  output = website.blackboard.invoke(:output_instance)
109
143
 
110
- tree.node_access[:alcn].select do |name, node|
111
- use_node = (node != tree.dummy_root && node.flagged?(:dirty))
144
+ website.tree.node_access[:alcn].select do |name, node|
145
+ use_node = (node != website.tree.dummy_root && node.flagged?(:dirty))
112
146
  node.unflag(:dirty_meta_info)
113
147
  node.unflag(:created)
114
148
  node.unflag(:dirty)
115
149
  use_node
116
150
  end.sort.each do |name, node|
117
- next if node['no_output'] || !(content = node.content)
118
-
119
151
  begin
152
+ next if node['no_output'] || !(content = node.content)
153
+
120
154
  puts " "*4 + name, :verbose
121
155
  type = if node.is_directory?
122
156
  :directory
@@ -126,8 +160,11 @@ module Webgen
126
160
  :file
127
161
  end
128
162
  output.write(node.path, content, type)
129
- rescue
130
- raise RuntimeError, "Error while processing <#{node.absolute_lcn}>: #{$!.message}", $!.backtrace
163
+ rescue Webgen::Error => e
164
+ e.alcn = node.alcn unless e.alcn
165
+ raise
166
+ rescue Exception => e
167
+ raise Webgen::RenderError.new(e, nil, node.alcn)
131
168
  end
132
169
  end
133
170
  end
@@ -135,9 +172,15 @@ module Webgen
135
172
  # Return a hash with all source paths.
136
173
  def find_all_source_paths
137
174
  if !defined?(@paths)
138
- source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args|
139
- [mp, constant(name).new(*args)]
140
- end)
175
+ active_source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args|
176
+ [mp, constant(name).new(*args)]
177
+ end)
178
+ passive_source = Webgen::Source::Stacked.new(website.config['passive_sources'].collect do |mp, name, *args|
179
+ [mp, constant(name).new(*args)]
180
+ end, true)
181
+ passive_source.paths.each {|path| path.passive = true }
182
+ source = Webgen::Source::Stacked.new([['/', active_source], ['/', passive_source]])
183
+
141
184
  @paths = {}
142
185
  source.paths.each do |path|
143
186
  if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)})
@@ -155,13 +198,13 @@ module Webgen
155
198
 
156
199
  options = (website.config['sourcehandler.casefold'] ? File::FNM_CASEFOLD : 0) |
157
200
  (website.config['sourcehandler.use_hidden_files'] ? File::FNM_DOTMATCH : 0)
158
- find_all_source_paths.values_at(*paths).select do |path|
201
+ find_all_source_paths.values_at(*paths).compact.select do |path|
159
202
  patterns.any? {|pat| File.fnmatch(pat, path, options)}
160
203
  end
161
204
  end
162
205
 
163
- # Use the source handlers to create nodes for the +paths+ in the +tree+.
164
- def create_nodes_from_paths(tree, paths)
206
+ # Use the source handlers to create nodes for the +paths+ in the <tt>website.tree</tt>.
207
+ def create_nodes_from_paths(paths)
165
208
  used_paths = Set.new
166
209
  website.config['sourcehandler.invoke'].sort.each do |priority, shns|
167
210
  shns.each do |shn|
@@ -169,36 +212,39 @@ module Webgen
169
212
  handler_paths = paths_for_handler(shn, paths)
170
213
  used_paths.merge(handler_paths)
171
214
  handler_paths.sort {|a,b| a.path.length <=> b.path.length}.each do |path|
172
- parent_dir = path.directory.split('/').collect {|p| Path.new(p).cn}.join('/')
173
- parent_dir += '/' if path != '/' && parent_dir == ''
174
- create_nodes(tree, parent_dir, path, sh)
215
+ if !website.tree[path.parent_path]
216
+ used_paths.merge(create_nodes_from_paths([path.parent_path]))
217
+ end
218
+ create_nodes(path, sh)
175
219
  end
176
220
  end
177
221
  end
178
222
  used_paths
179
223
  end
180
224
 
181
- # Prepare everything to create nodes under the absolute lcn path +parent_path_name+ in the
182
- # +tree from the +path+ using the +source_handler+. If a block is given, the actual creation
183
- # of the nodes is deferred to it. After the nodes are created, it is also checked if they have
184
- # all needed properties.
185
- def create_nodes(tree, parent_path_name, path, source_handler) #:yields: parent, path
186
- if !(parent = tree[parent_path_name])
187
- raise "The specified parent path <#{parent_path_name}> does not exist"
188
- end
225
+ # Prepare everything to create from the +path+ using the +source_handler+. If a block is
226
+ # given, the actual creation of the nodes is deferred to it. Otherwise the #create_node method
227
+ # of the +source_handler+ is used. After the nodes are created, it is also checked if they
228
+ # have all needed properties.
229
+ def create_nodes(path, source_handler) #:yields: path
189
230
  path = path.dup
190
231
  path.meta_info = default_meta_info(path, source_handler.class.name)
191
232
  (website.cache[:sourcehandler_path_mi] ||= {})[[path.path, source_handler.class.name]] = path.meta_info.dup
192
- website.blackboard.dispatch_msg(:before_node_created, parent, path)
233
+ website.blackboard.dispatch_msg(:before_node_created, path)
193
234
  *nodes = if block_given?
194
- yield(parent, path)
235
+ yield(path)
195
236
  else
196
- source_handler.create_node(parent, path)
237
+ source_handler.create_node(path)
197
238
  end
198
239
  nodes.flatten.compact.each do |node|
199
240
  website.blackboard.dispatch_msg(:after_node_created, node)
200
241
  end
201
242
  nodes
243
+ rescue Webgen::Error => e
244
+ e.alcn = path unless e.alcn
245
+ raise
246
+ rescue Exception => e
247
+ raise Webgen::NodeCreationError.new(e, source_handler.class.name, path)
202
248
  end
203
249
 
204
250
  # Return the default meta info for the pair of +path+ and +sh_name+.
@@ -19,7 +19,7 @@ module Webgen::SourceHandler
19
19
  #
20
20
  # The paths that are handled by a source handler are specified via path patterns (see
21
21
  # below). During a webgen run the #create_node method for each source paths that matches a
22
- # specified path pattern is called. And when it is time to write out the node, the the #content
22
+ # specified path pattern is called. And when it is time to write out the node, the #content
23
23
  # method is called to retrieve the rendered content.
24
24
  #
25
25
  # A source handler must not take any parameters on initialization and when this module is not
@@ -35,6 +35,7 @@ module Webgen::SourceHandler
35
35
  # It also provides other utility methods:
36
36
  # * #page_from_path
37
37
  # * #content
38
+ # * #parent_node
38
39
  #
39
40
  # == Nodes Created for Paths
40
41
  #
@@ -109,10 +110,11 @@ module Webgen::SourceHandler
109
110
  # class SimpleCopy
110
111
  #
111
112
  # include Webgen::SourceHandler::Base
113
+ # include Webgen::WebsiteAccess
112
114
  #
113
- # def create_node(parent, path)
115
+ # def create_node(path)
114
116
  # path.ext += '.copied'
115
- # super(parent, path)
117
+ # super(path)
116
118
  # end
117
119
  #
118
120
  # def content(node)
@@ -151,7 +153,8 @@ module Webgen::SourceHandler
151
153
  when :year, :month, :day
152
154
  ctime = path.meta_info['created_at']
153
155
  if !ctime.kind_of?(Time)
154
- raise "Invalid meta info 'created_at' for #{path}, needed because of used output path style"
156
+ raise Webgen::NodeCreationError.new("Invalid meta info 'created_at', needed because of used output path style",
157
+ self.class.name, path)
155
158
  end
156
159
  ctime.send(part).to_s.rjust(2, '0')
157
160
  when Symbol then path.send(part)
@@ -181,36 +184,49 @@ module Webgen::SourceHandler
181
184
  if OutputPathHelpers.public_instance_methods(false).map(&:to_s).include?(method)
182
185
  name = send(method, parent, path, use_lang_part)
183
186
  name += '/' if path.path =~ /\/$/ && name !~ /\/$/
184
- if (node = node_exists?(parent, path, name)) && node.lang == path.meta_info['lang']
185
- name = node.path
186
- elsif node
187
+ if (node = node_exists?(path, name)) && node.lang != path.meta_info['lang']
187
188
  name = send(method, parent, path, (path.meta_info['lang'].nil? ? false : true))
188
189
  name += '/' if path.path =~ /\/$/ && name !~ /\/$/
189
190
  end
190
191
  name
191
192
  else
192
- raise "Unknown method for creating output path: #{method}"
193
+ raise Webgen::NodeCreationError.new("Unknown method for creating output path: #{path.meta_info['output_path']}",
194
+ self.class.name, path)
193
195
  end
194
196
  end
195
197
 
196
- # Check if the node alcn and output path which would be created by #create_node exists. The
198
+ # Check if the node alcn and output path which would be created by #create_node exist. The
197
199
  # +output_path+ to check for can individually be set.
198
- def node_exists?(parent, path, output_path = self.output_path(parent, path))
199
- parent.tree[Webgen::Node.absolute_name(parent, path.lcn, :alcn)] || (!path.meta_info['no_output'] && parent.tree[output_path, :path])
200
+ def node_exists?(path, output_path = self.output_path(parent_node(path), path))
201
+ Webgen::WebsiteAccess.website.tree[path.alcn] || (!path.meta_info['no_output'] && Webgen::WebsiteAccess.website.tree[output_path, :path])
200
202
  end
201
203
 
202
- # Create a node under +parent+ from +path+ if it does not already exists or needs to be
203
- # re-initialized. The found node or the newly created node is returned afterwards. +nil+ is
204
- # returned if no node can be created (e.g. when <tt>path.meta_info['draft']</tt> is set). Some
205
- # additional node information like <tt>:src</tt> and <tt>:processor</tt> is set and the meta
206
- # information is checked for validness. The created/re-initialized node is yielded if a block is
207
- # given.
208
- def create_node(parent, path, output_path = self.output_path(parent, path))
204
+ # Create a node from +path+ if it does not already exists or re-initalize an already existing
205
+ # node. The found node or the newly created node is returned afterwards. +nil+ is returned if no
206
+ # node can be created (e.g. when <tt>path.meta_info['draft']</tt> is set).
207
+ #
208
+ # The +options+ parameter can be used for providing the optional parameters:
209
+ #
210
+ # [<tt>:parent</tt>] The parent node under which the new node should be created. If this is not
211
+ # specified (the usual case), the parent node is determined by the
212
+ # #parent_node method.
213
+ #
214
+ # [<tt>:output_path</tt>] The output path that should be used for the node. If this is not
215
+ # specified (the usual case), the output path is determined via the
216
+ # #output_path method.
217
+ #
218
+ # Some additional node information like <tt>:src</tt> and <tt>:processor</tt> is set and the
219
+ # meta information is checked for validness. The created/re-initialized node is yielded if a
220
+ # block is given.
221
+ def create_node(path, options = {})
209
222
  return nil if path.meta_info['draft']
210
- node = node_exists?(parent, path, output_path)
223
+ parent = options[:parent] || parent_node(path)
224
+ output_path = options[:output_path] || self.output_path(parent, path)
225
+ node = node_exists?(path, output_path)
226
+
211
227
  if node && (node.node_info[:src] != path.source_path || node.node_info[:processor] != self.class.name)
212
- log(:warn) { "Node already exists: source = #{path.source_path} | path = #{node.path} | alcn = #{node.absolute_lcn}"}
213
- return node
228
+ log(:warn) { "Node already exists: source = #{path.source_path} | path = #{node.path} | alcn = #{node.alcn}"}
229
+ return node #TODO: think! should nil be returned?
214
230
  elsif !node
215
231
  node = Webgen::Node.new(parent, output_path, path.cn, path.meta_info)
216
232
  elsif node.flagged?(:reinit)
@@ -218,7 +234,11 @@ module Webgen::SourceHandler
218
234
  else
219
235
  return node
220
236
  end
221
- node['modified_at'] = Time.now unless node['modified_at'].kind_of?(Time)
237
+
238
+ if !node['modified_at'].kind_of?(Time)
239
+ log(:warn) { "Meta information 'modified_at' set to current time in <#{node.alcn}> since its value '#{node['modified_at']}' was of type #{node['modified_at'].class}" } unless node['modified_at'].nil?
240
+ node['modified_at'] = Time.now
241
+ end
222
242
  node.node_info[:src] = path.source_path
223
243
  node.node_info[:creation_path] = path.path
224
244
  node.node_info[:processor] = self.class.name
@@ -226,7 +246,10 @@ module Webgen::SourceHandler
226
246
  node
227
247
  end
228
248
 
229
- # Return the content of the given +node+. This default +content+ method just returns +nil+.
249
+ # Return the content of the given +node+. If the return value is not +nil+ then the node gets
250
+ # written, otherwise it is ignored.
251
+ #
252
+ # This default +content+ method just returns +nil+.
230
253
  def content(node)
231
254
  nil
232
255
  end
@@ -237,12 +260,23 @@ module Webgen::SourceHandler
237
260
  begin
238
261
  page = Webgen::Page.from_data(path.io.data, path.meta_info)
239
262
  rescue Webgen::Page::FormatError => e
240
- raise "Error reading source path <#{path}>: #{e.message}"
263
+ raise Webgen::NodeCreationError.new("Error reading source path: #{e.message}",
264
+ self.class.name, path)
241
265
  end
242
266
  path.meta_info = page.meta_info
243
267
  page
244
268
  end
245
269
 
270
+ # Return the parent node for the given +path+.
271
+ def parent_node(path)
272
+ parent_dir = (path.parent_path == '' ? '' : Webgen::Path.new(path.parent_path).alcn)
273
+ if !(parent = Webgen::WebsiteAccess.website.tree[parent_dir])
274
+ raise Webgen::NodeCreationError.new("The needed parent path <#{parent_dir}> does not exist",
275
+ self.class.name, path)
276
+ end
277
+ parent
278
+ end
279
+
246
280
  end
247
281
 
248
282
  end