webgen 1.0.0.beta1 → 1.0.0.beta2

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.
Files changed (62) hide show
  1. data/API.rdoc +64 -11
  2. data/ChangeLog +391 -0
  3. data/README.md +2 -2
  4. data/VERSION +1 -1
  5. data/data/webgen/passive_sources/templates/tag.template +1 -1
  6. data/data/webgen/passive_sources/templates/tikz.template +14 -0
  7. data/lib/webgen/bundle/built-in/init.rb +9 -7
  8. data/lib/webgen/bundle_loader.rb +1 -1
  9. data/lib/webgen/cli/show_command.rb +2 -0
  10. data/lib/webgen/cli/show_config_command.rb +0 -1
  11. data/lib/webgen/cli/show_dependencies_command.rb +6 -63
  12. data/lib/webgen/cli/show_tree_command.rb +85 -0
  13. data/lib/webgen/content_processor/erb.rb +1 -1
  14. data/lib/webgen/content_processor/{rdoc.rb → r_doc.rb} +0 -0
  15. data/lib/webgen/content_processor/{redcloth.rb → red_cloth.rb} +0 -0
  16. data/lib/webgen/content_processor/ruby.rb +3 -0
  17. data/lib/webgen/content_processor/sass.rb +10 -6
  18. data/lib/webgen/content_processor/tikz.rb +10 -20
  19. data/lib/webgen/context/html_head.rb +7 -0
  20. data/lib/webgen/item_tracker.rb +42 -15
  21. data/lib/webgen/item_tracker/file.rb +7 -3
  22. data/lib/webgen/item_tracker/missing_node.rb +17 -5
  23. data/lib/webgen/item_tracker/node_content.rb +7 -3
  24. data/lib/webgen/item_tracker/node_meta_info.rb +8 -3
  25. data/lib/webgen/item_tracker/nodes.rb +10 -3
  26. data/lib/webgen/node.rb +4 -29
  27. data/lib/webgen/node_finder.rb +25 -10
  28. data/lib/webgen/path.rb +2 -2
  29. data/lib/webgen/path_handler/base.rb +20 -9
  30. data/lib/webgen/path_handler/feed.rb +29 -22
  31. data/lib/webgen/path_handler/page.rb +1 -3
  32. data/lib/webgen/path_handler/page_utils.rb +114 -33
  33. data/lib/webgen/path_handler/sitemap.rb +13 -6
  34. data/lib/webgen/path_handler/template.rb +0 -70
  35. data/lib/webgen/path_handler/virtual.rb +10 -2
  36. data/lib/webgen/tag.rb +13 -13
  37. data/lib/webgen/tag/tikz.rb +2 -1
  38. data/lib/webgen/test_helper.rb +2 -11
  39. data/lib/webgen/version.rb +1 -1
  40. data/test/webgen/content_processor/test_erb.rb +4 -0
  41. data/test/webgen/content_processor/{test_rdoc.rb → test_r_doc.rb} +1 -1
  42. data/test/webgen/content_processor/{test_redcloth.rb → test_red_cloth.rb} +1 -1
  43. data/test/webgen/content_processor/test_sass.rb +2 -2
  44. data/test/webgen/content_processor/test_tikz.rb +10 -3
  45. data/test/webgen/item_tracker/test_file.rb +5 -5
  46. data/test/webgen/item_tracker/test_missing_node.rb +8 -9
  47. data/test/webgen/item_tracker/test_node_content.rb +5 -6
  48. data/test/webgen/item_tracker/test_node_meta_info.rb +6 -7
  49. data/test/webgen/item_tracker/test_nodes.rb +7 -9
  50. data/test/webgen/path_handler/test_base.rb +4 -5
  51. data/test/webgen/path_handler/test_page.rb +1 -1
  52. data/test/webgen/path_handler/test_page_utils.rb +39 -11
  53. data/test/webgen/path_handler/test_template.rb +5 -45
  54. data/test/webgen/path_handler/test_virtual.rb +21 -0
  55. data/test/webgen/tag/test_link.rb +1 -1
  56. data/test/webgen/tag/test_tikz.rb +2 -2
  57. data/test/webgen/test_context.rb +10 -0
  58. data/test/webgen/test_item_tracker.rb +7 -4
  59. data/test/webgen/test_node.rb +3 -16
  60. data/test/webgen/test_node_finder.rb +10 -6
  61. data/test/webgen/test_tag.rb +4 -4
  62. metadata +218 -216
@@ -32,7 +32,7 @@ module Webgen
32
32
  # [item_data(*item)]
33
33
  # Return the data for the item so that it can be correctly checked later if it has changed.
34
34
  #
35
- # [changed?(item_id, old_data)]
35
+ # [item_changed?(item_id, old_data)]
36
36
  # Return +true+ if the item identified by its unique ID has changed. The parameter +old_data+
37
37
  # contains the last known data of the item.
38
38
  #
@@ -40,6 +40,11 @@ module Webgen
40
40
  # Return +true+ if the node identified by +node_alcn+ is referenced in the old data identified
41
41
  # by the unique ID.
42
42
  #
43
+ # [item_description(item_id, data)]
44
+ # Return a string or an array of strings which describe the item (identified by its unique ID)
45
+ # and the given item data. This is used for display purposes and should therefore include a
46
+ # nice, human readable interpretation of the item.
47
+ #
43
48
  # The parameter +item+ for the methods +item_id+ and +item_data+ contains the information needed
44
49
  # to identify the item and is depdendent on the specific item tracker extension class. Therefore
45
50
  # you need to look at the documentation for an item tracker extension to see what it expects as
@@ -67,7 +72,7 @@ module Webgen
67
72
  # @website.config[config_key]
68
73
  # end
69
74
  #
70
- # def changed?(config_key, old_val)
75
+ # def item_changed?(config_key, old_val)
71
76
  # @website.config[config_key] != old_val
72
77
  # end
73
78
  #
@@ -75,6 +80,10 @@ module Webgen
75
80
  # false
76
81
  # end
77
82
  #
83
+ # def item_description(config_key, old_val)
84
+ # "The website configuration option '#{config_key}'"
85
+ # end
86
+ #
78
87
  # end
79
88
  #
80
89
  # website.ext.item_tracker.register ConfigTracker, name: :config
@@ -134,10 +143,11 @@ module Webgen
134
143
 
135
144
  @website.blackboard.add_listener(:website_generated, self) do
136
145
  @cached[:node_dependencies].reject! {|alcn, data| !@website.tree[alcn]}
146
+
147
+ used_uids = @cached[:node_dependencies].each_with_object(Set.new) {|(_, uids), obj| obj.merge(uids)}
137
148
  @cached[:item_data].merge!(@item_data)
138
- @cached[:item_data].reject! do |uid, _|
139
- !@cached[:node_dependencies].find {|alcn, data| data.include?(uid)}
140
- end
149
+ @cached[:item_data].reject! {|uid, _| !used_uids.include?(uid)}
150
+
141
151
  @website.cache[:item_tracker_data] = @cached
142
152
  end
143
153
  end
@@ -187,17 +197,16 @@ module Webgen
187
197
 
188
198
  # Return +true+ if the given node has been referenced by any item tracker extension.
189
199
  def node_referenced?(node)
190
- node_alcn = node.alcn
191
- checked_uids = Set.new
192
- @cached[:node_dependencies].each do |alcn, uids|
193
- next if alcn == node_alcn
194
- uids.each do |uid|
195
- next if checked_uids.include?(uid)
196
- checked_uids << uid
197
- return true if item_tracker(uid.first).node_referenced?(uid.last, @cached[:item_data][uid], node_alcn)
200
+ if (cached = @website.cache.volatile[:item_tracker_referenced_nodes]).nil?
201
+ cached = @website.cache.volatile[:item_tracker_referenced_nodes] = Set.new
202
+ @cached[:node_dependencies].each do |alcn, uids|
203
+ uids.each do |uid|
204
+ cached.merge(item_tracker(uid.first).referenced_nodes(uid.last, @cached[:item_data][uid]) - [alcn])
205
+ end
198
206
  end
199
207
  end
200
- false
208
+
209
+ cached.include?(node.alcn)
201
210
  end
202
211
 
203
212
  # Return +true+ if the given item that is handled by the item tracker extension +name+ has
@@ -206,6 +215,24 @@ module Webgen
206
215
  item_changed_by_uid?(unique_id(name, item))
207
216
  end
208
217
 
218
+ # Return a hash with mappings from node ALCNs to their used items (items are converted to
219
+ # a human readable representation by using the #item_description method).
220
+ #
221
+ # If the parameter +include_default+ is set to +false+, the default items added to each node so
222
+ # that it is possible to correctly detect changes, are not included.
223
+ #
224
+ # The cached data, not the current data, is used. So this information is only useful after a
225
+ # website has been generated.
226
+ def cached_items(include_default=true)
227
+ @cached[:node_dependencies].each_with_object({}) do |(alcn, uids), h|
228
+ h[alcn] = uids.sort {|a,b| a.first <=> b.first }.map do |uid|
229
+ next if !include_default && ((uid.first == :node_meta_info && uid.last.first == alcn )||
230
+ (uid.first == :node_content && uid.last == alcn))
231
+ item_tracker(uid.first).item_description(uid.last, @cached[:item_data][uid])
232
+ end.compact
233
+ end
234
+ end
235
+
209
236
  #######
210
237
  private
211
238
  #######
@@ -217,7 +244,7 @@ module Webgen
217
244
  @item_changed[uid] = if !@cached[:item_data].has_key?(uid)
218
245
  true
219
246
  else
220
- item_tracker(uid.first).changed?(uid.last, @cached[:item_data][uid])
247
+ item_tracker(uid.first).item_changed?(uid.last, @cached[:item_data][uid])
221
248
  end
222
249
  end
223
250
 
@@ -25,12 +25,16 @@ module Webgen
25
25
  ::File.mtime(filename)
26
26
  end
27
27
 
28
- def changed?(filename, old_mtime) #:nodoc:
28
+ def item_changed?(filename, old_mtime) #:nodoc:
29
29
  ::File.mtime(filename) > old_mtime
30
30
  end
31
31
 
32
- def node_referenced?(filename, mtime, node_alcn) #:nodoc:
33
- false
32
+ def referenced_nodes(filename, mtime) #:nodoc:
33
+ []
34
+ end
35
+
36
+ def item_description(filename, data) #:nodoc:
37
+ "Content from file '#{filename}'"
34
38
  end
35
39
 
36
40
  end
@@ -1,5 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require 'set'
3
4
  require 'webgen/item_tracker'
4
5
 
5
6
  module Webgen
@@ -20,9 +21,13 @@ module Webgen
20
21
  @website = website
21
22
  @at_least_one_node_created = true
22
23
  @stop_reporting = false
24
+ @nodes_to_ignore = Set.new
23
25
 
24
- @website.blackboard.add_listener(:after_node_created, self) do
25
- @at_least_one_node_created = true
26
+ @website.blackboard.add_listener(:reused_existing_node, self) do |node, path|
27
+ @nodes_to_ignore << node
28
+ end
29
+ @website.blackboard.add_listener(:after_node_created, self) do |node|
30
+ @at_least_one_node_created = true unless @nodes_to_ignore.include?(node)
26
31
  end
27
32
  @website.blackboard.add_listener(:after_all_nodes_written, self) do
28
33
  if @at_least_one_node_created
@@ -30,10 +35,12 @@ module Webgen
30
35
  else
31
36
  @stop_reporting = true
32
37
  end
38
+ @nodes_to_ignore = Set.new
33
39
  end
34
40
  @website.blackboard.add_listener(:website_generated, self) do
35
41
  @at_least_one_node_created = true
36
42
  @stop_reporting = false
43
+ @nodes_to_ignore = Set.new
37
44
  end
38
45
  end
39
46
 
@@ -45,14 +52,19 @@ module Webgen
45
52
  @website.tree.resolve_node(path, lang).nil?
46
53
  end
47
54
 
48
- def changed?(iid, old_data) #:nodoc:
55
+ def item_changed?(iid, old_data) #:nodoc:
49
56
  return false if @stop_reporting
50
57
  missing = item_data(*iid)
51
58
  missing || missing != old_data
52
59
  end
53
60
 
54
- def node_referenced?(iid, missing, node_alcn) #:nodoc:
55
- iid.first == node_alcn
61
+ def referenced_nodes(iid, missing) #:nodoc:
62
+ [iid.first]
63
+ end
64
+
65
+ def item_description(iid, data) #:nodoc:
66
+ path, lang = *iid.last
67
+ "Missing acn, alcn or dest path <#{path}>" << (lang.nil? ? '' : " in language '#{lang}'")
56
68
  end
57
69
 
58
70
  end
@@ -26,12 +26,16 @@ module Webgen
26
26
  nil
27
27
  end
28
28
 
29
- def changed?(alcn, old_data) #:nodoc:
29
+ def item_changed?(alcn, old_data) #:nodoc:
30
30
  @website.tree[alcn].nil? || @website.ext.item_tracker.node_changed?(@website.tree[alcn])
31
31
  end
32
32
 
33
- def node_referenced?(alcn, nothing, node_alcn) #:nodoc:
34
- alcn == node_alcn
33
+ def referenced_nodes(alcn, nothing) #:nodoc:
34
+ [alcn]
35
+ end
36
+
37
+ def item_description(alcn, data) #:nodoc:
38
+ "Content from node <#{alcn}>"
35
39
  end
36
40
 
37
41
  end
@@ -38,13 +38,18 @@ module Webgen
38
38
  key.nil? ? (mi = mi.dup; mi.delete(CONTENT_MODIFICATION_KEY); mi) : mi[key].dup
39
39
  end
40
40
 
41
- def changed?(iid, old_data) #:nodoc:
41
+ def item_changed?(iid, old_data) #:nodoc:
42
42
  alcn, key = *iid
43
43
  @website.tree[alcn].nil? || item_data(alcn, key) != old_data
44
44
  end
45
45
 
46
- def node_referenced?(iid, mi, node_alcn) #:nodoc:
47
- iid.first == node_alcn
46
+ def referenced_nodes(iid, mi) #:nodoc:
47
+ [iid.first]
48
+ end
49
+
50
+ def item_description(iid, data) #:nodoc:
51
+ alcn, key = *iid
52
+ (key.nil? ? "Any meta info from <#{alcn}>" : "Meta info key '#{key}' from <#{alcn}>")
48
53
  end
49
54
 
50
55
  end
@@ -47,15 +47,22 @@ module Webgen
47
47
  nodes_to_alcn(node_list(method_name, options))
48
48
  end
49
49
 
50
- def changed?(iid, old_data) #:nodoc:
50
+ def item_changed?(iid, old_data) #:nodoc:
51
51
  method_name, options, type = *iid
52
52
  nodes = node_list(method_name, options)
53
53
  old_data != nodes_to_alcn(nodes) ||
54
54
  nodes.flatten.any? {|n| type == :content ? @website.ext.item_tracker.node_changed?(n) : @website.ext.item_tracker.item_changed?(:node_meta_info, n.alcn)}
55
55
  end
56
56
 
57
- def node_referenced?(iid, alcn_list, node_alcn) #:nodoc:
58
- alcn_list.flatten.any? {|alcn| alcn == node_alcn}
57
+ def referenced_nodes(iid, alcn_list) #:nodoc:
58
+ alcn_list.flatten
59
+ end
60
+
61
+ def item_description(iid, data) #:nodoc:
62
+ method, _, type = *iid
63
+ str = (type == :content ? "Content" : "Meta info") << " from these nodes"
64
+ str << " (result of #{[method].flatten.join('.')}):"
65
+ [str] + data.flatten
59
66
  end
60
67
 
61
68
  # Use Webgen::NodeFinder to generate a (nested) list of nodes. The options hash has to contain
data/lib/webgen/node.rb CHANGED
@@ -200,16 +200,14 @@ module Webgen
200
200
  # You can optionally specify additional attributes for the HTML element in the +attr+ Hash.
201
201
  # Also, the meta information +link_attrs+ of the given +node+ is used, if available, to set
202
202
  # attributes. However, the +attr+ parameter takes precedence over the +link_attrs+ meta
203
- # information. Be aware that all key-value pairs with Symbol keys are removed before the
204
- # attributes are written. Therefore you always need to specify general attributes with strings!
203
+ # information.
205
204
  #
206
- # If the special value :link_text is present in the attributes, it will be used as the link
205
+ # If the special value 'link_text' is present in the attributes, it will be used as the link
207
206
  # text; otherwise the title of the +node+ will be used.
208
207
  def link_to(node, lang = @lang, attr = {})
209
- attr = node['link_attrs'].merge(attr) if node['link_attrs'].kind_of?(Hash)
210
208
  rnode = node.proxy_node(lang)
211
- link_text = attr[:link_text] || (rnode != node && rnode['routed_title']) || node['title']
212
- attr.delete_if {|k,v| k.kind_of?(Symbol)}
209
+ attr = (rnode['link_attrs'].kind_of?(Hash) ? rnode['link_attrs'] : {}).merge(attr)
210
+ link_text = attr.delete('link_text') || (rnode != node && rnode['routed_title']) || node['title']
213
211
 
214
212
  attr['href'] = self.route_to(node, lang)
215
213
  attr['hreflang'] = rnode.lang.to_s if rnode.lang
@@ -223,29 +221,6 @@ module Webgen
223
221
  each_with_object({}) {|(k, v), h| h[v['version']] = v}
224
222
  end
225
223
 
226
-
227
- #######
228
- private
229
- #######
230
-
231
- # Delegate missing methods to the associated path handler. The current node is placed into the
232
- # argument array as the first argument before the method +name+ is invoked on the path handler.
233
- def method_missing(name, *args, &block)
234
- if node_info[:path_handler]
235
- node_info[:path_handler].send(name, *([self] + args), &block)
236
- else
237
- super
238
- end
239
- end
240
-
241
- def respond_to_missing?(symbol, include_private) #:nodoc:
242
- if node_info[:path_handler]
243
- node_info[:path_handler].send(:respond_to?, symbol, include_private)
244
- else
245
- super
246
- end
247
- end
248
-
249
224
  end
250
225
 
251
226
  end
@@ -38,6 +38,13 @@ module Webgen
38
38
  # Value: an integer. Specifies how many nodes from the front of the list should *not* be
39
39
  # returned. Implies 'flatten = true'.
40
40
  #
41
+ # [:levels]
42
+ # Value: one integer (is used as start and end level) or an array with two integers (the start
43
+ # and end levels). All nodes whose hierarchy level in the returned node hierarchy is greater
44
+ # than or equal to the start level and lower than or equal to the end level are used.
45
+ #
46
+ # Only used when the node hierarchy is not flattened.
47
+ #
41
48
  # [:flatten]
42
49
  # Value: anything except +nil+ or +false+. A flat list of nodes is returned if this option is
43
50
  # set, otherwise the nodes are returned in their correct hierarchical order using nested lists.
@@ -85,10 +92,10 @@ module Webgen
85
92
  # Value: a finder option set or an array of finder options sets (specifying option set names is
86
93
  # also possible). Only nodes that do not appear in any specified option set are used.
87
94
  #
88
- # [:levels]
95
+ # [:absolute_levels]
89
96
  # Value: one integer (is used as start and end level) or an array with two integers (the start
90
- # and end levels). All nodes whose hierarchy levels are greater than or equal to the start level
91
- # and lower than or equal to the end level are used.
97
+ # and end levels). All nodes whose hierarchy level in the node tree are greater than or equal to
98
+ # the start level and lower than or equal to the end level are used.
92
99
  #
93
100
  # [:ancestors]
94
101
  # Value: +true+ or +false+/+nil+. If this filter option is set to +true+, only nodes that are
@@ -131,7 +138,7 @@ module Webgen
131
138
  def initialize(website)
132
139
  @website = website
133
140
  @mapping = {
134
- :alcn => :filter_alcn, :levels => :filter_levels, :lang => :filter_lang,
141
+ :alcn => :filter_alcn, :absolute_levels => :filter_absolute_levels, :lang => :filter_lang,
135
142
  :and => :filter_and, :or => :filter_or, :not => :filter_not,
136
143
  :ancestors => :filter_ancestors, :descendants => :filter_descendants,
137
144
  :siblings => :filter_siblings,
@@ -170,8 +177,9 @@ module Webgen
170
177
  end
171
178
  opts = prepare_options_hash(opts_or_name)
172
179
 
173
- limit, offset, flatten, sort = remove_non_filter_options(opts)
180
+ limit, offset, flatten, sort, levels = remove_non_filter_options(opts)
174
181
  flatten = true if limit || offset
182
+ levels = [levels || [1, 1_000_000]].flatten.map {|i| i.to_i}
175
183
 
176
184
  nodes = filter_nodes(opts, ref_node)
177
185
 
@@ -189,10 +197,17 @@ module Webgen
189
197
  hierarchy_nodes.inject(result) {|memo, hn| memo[hn] ||= {}}
190
198
  end
191
199
 
192
- reducer = lambda do |h|
193
- h.map {|k,v| v.empty? ? k : [k, reducer.call(v)]}
200
+ reducer = lambda do |h, level|
201
+ if level < levels.first
202
+ temp = h.map {|k,v| v.empty? ? nil : reducer.call(v, level + 1)}.compact
203
+ temp.length == 1 && temp.first.kind_of?(Array) ? temp.first : temp
204
+ elsif level < levels.last
205
+ h.map {|k,v| v.empty? ? k : [k, reducer.call(v, level + 1)]}
206
+ else
207
+ h.map {|k,v| k}
208
+ end
194
209
  end
195
- nodes = reducer.call(result)
210
+ nodes = reducer.call(result, 1)
196
211
  sort_nodes(nodes, sort, false)
197
212
  end
198
213
 
@@ -222,7 +237,7 @@ module Webgen
222
237
  end
223
238
 
224
239
  def remove_non_filter_options(opts)
225
- [opts.delete(:limit), opts.delete(:offset), opts.delete(:flatten), opts.delete(:sort)]
240
+ [opts.delete(:limit), opts.delete(:offset), opts.delete(:flatten), opts.delete(:sort), opts.delete(:levels)]
226
241
  end
227
242
 
228
243
  def filter_nodes(opts, ref_node)
@@ -297,7 +312,7 @@ module Webgen
297
312
  nodes.keep_if {|n| alcn.any? {|a| n =~ a}}
298
313
  end
299
314
 
300
- def filter_levels(nodes, ref_node, range)
315
+ def filter_absolute_levels(nodes, ref_node, range)
301
316
  range = [range].flatten.map {|i| i.to_i}
302
317
  nodes.keep_if {|n| n.level >= range.first && n.level <= range.last}
303
318
  end
data/lib/webgen/path.rb CHANGED
@@ -314,9 +314,9 @@ module Webgen
314
314
  @basename = match_data[1]
315
315
  @ext = match_data[2]
316
316
  else
317
- @meta_info['sort_info'] ||= (match_data[1].nil? ? nil : match_data[1].to_i)
317
+ @meta_info['sort_info'] ||= match_data[1].to_i unless match_data[1].nil?
318
318
  @basename = match_data[2]
319
- @meta_info['lang'] ||= Webgen::LanguageManager.language_for_code(match_data[3])
319
+ @meta_info['lang'] ||= Webgen::LanguageManager.language_for_code(match_data[3]) if match_data[3]
320
320
  @ext = (@meta_info['lang'].nil? && !match_data[3].nil? ? match_data[3].to_s + '.' : '') + match_data[4].to_s
321
321
  end
322
322
  end
@@ -27,17 +27,24 @@ module Webgen
27
27
  #
28
28
  module Base
29
29
 
30
+ # This is the base Node sub class used by the Base#create_node method if a path handler class
31
+ # does not specify another Node class.
32
+ class Node < Webgen::Node
33
+
34
+ # Return the result of the #content method on the associated path handler or +nil+ if the
35
+ # associated path handler does not have a #content method.
36
+ def content
37
+ (@node_info[:path_handler].respond_to?(:content) ? @node_info[:path_handler].content(self) : nil)
38
+ end
39
+
40
+ end
41
+
42
+
30
43
  # Initialize the path handler with the given Website object.
31
44
  def initialize(website)
32
45
  @website = website
33
46
  end
34
47
 
35
- # Return +nil+ as content of the given +node+.
36
- #
37
- # Should probably be over-written by path handler classes using this module!
38
- def content(node)
39
- end
40
-
41
48
  # Update +path.meta_info+ with meta information found in the content of the path.
42
49
  #
43
50
  # This default +parse_meta_info!+ method does nothing and should be overridden in path
@@ -50,9 +57,12 @@ module Webgen
50
57
  []
51
58
  end
52
59
 
53
- # Create a node from +path+, if possible, yield the full initialized node if a block is given
60
+ # Create a node from +path+, if possible, yield the fully initialized node if a block is given
54
61
  # and return it.
55
62
  #
63
+ # The node class to be used for the created node can be specified via the +node_klass+
64
+ # parameter.
65
+ #
56
66
  # If no node can be created (e.g. when 'path.meta_info['draft']' is set), +nil+ is returned.
57
67
  #
58
68
  # The parent node under which the new node should be created can optionally be specified via
@@ -61,7 +71,7 @@ module Webgen
61
71
  #
62
72
  # On the created node, the node information +:path+ is set to the given path and
63
73
  # +:path_handler+ to the path handler instance.
64
- def create_node(path)
74
+ def create_node(path, node_klass = Node)
65
75
  return nil if path.meta_info['draft']
66
76
  parent = parent_node(path)
67
77
  dest_path = self.dest_path(parent, path)
@@ -71,6 +81,7 @@ module Webgen
71
81
  if node_path != path
72
82
  raise Webgen::NodeCreationError.new("Another node <#{node}> with the same alcn or destination path already exists")
73
83
  elsif node_path.meta_info == path.meta_info
84
+ @website.blackboard.dispatch_msg(:reused_existing_node, node)
74
85
  return node
75
86
  else
76
87
  node.tree.delete_node(node)
@@ -84,7 +95,7 @@ module Webgen
84
95
  path.meta_info['modified_at'] = Time.now
85
96
  end
86
97
 
87
- node = Webgen::Node.new(parent, path.cn, dest_path, path.meta_info)
98
+ node = node_klass.new(parent, path.cn, dest_path, path.meta_info.dup)
88
99
  node.node_info[:path] = path
89
100
  node.node_info[:path_handler] = self
90
101