webgen 0.5.2 → 0.5.3

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 (85) hide show
  1. data/Rakefile +15 -4
  2. data/VERSION +1 -1
  3. data/data/webgen/webgui/controller/main.rb +1 -1
  4. data/data/webgen/website_skeleton/ext/init.rb +6 -0
  5. data/data/webgen/website_styles/1024px/src/default.css +188 -188
  6. data/data/webgen/website_styles/1024px/src/default.template +51 -51
  7. data/data/webgen/website_styles/andreas00/src/default.template +1 -1
  8. data/data/webgen/website_styles/andreas01/src/default.css +8 -8
  9. data/data/webgen/website_styles/andreas01/src/default.template +1 -1
  10. data/data/webgen/website_styles/andreas03/src/default.css +3 -3
  11. data/data/webgen/website_styles/andreas03/src/default.template +2 -2
  12. data/data/webgen/website_styles/andreas04/src/default.css +1 -1
  13. data/data/webgen/website_styles/andreas05/src/default.css +3 -3
  14. data/data/webgen/website_styles/andreas05/src/default.template +26 -26
  15. data/data/webgen/website_styles/andreas06/src/default.css +6 -6
  16. data/data/webgen/website_styles/andreas06/src/default.template +1 -1
  17. data/data/webgen/website_styles/andreas07/src/default.css +6 -6
  18. data/data/webgen/website_styles/andreas08/src/default.css +7 -7
  19. data/data/webgen/website_styles/andreas08/src/default.template +2 -2
  20. data/data/webgen/website_styles/andreas09/src/default.css +3 -3
  21. data/data/webgen/website_styles/andreas09/src/default.template +1 -1
  22. data/data/webgen/website_styles/simple/src/default.css +84 -84
  23. data/data/webgen/website_styles/simple/src/default.template +1 -1
  24. data/doc/index.page +27 -12
  25. data/doc/manual.page +52 -10
  26. data/doc/reference_configuration.page +108 -52
  27. data/doc/reference_metainfo.page +77 -2
  28. data/doc/sourcehandler/feed.page +82 -0
  29. data/doc/sourcehandler/metainfo.page +3 -2
  30. data/doc/sourcehandler/sitemap.page +46 -0
  31. data/doc/tag.template +2 -3
  32. data/doc/tag/breadcrumbtrail.page +11 -3
  33. data/doc/tag/menu.page +6 -4
  34. data/doc/tag/sitemap.page +31 -0
  35. data/doc/upgrading.page +67 -0
  36. data/lib/webgen/cli/utils.rb +4 -4
  37. data/lib/webgen/cli/webgui_command.rb +2 -1
  38. data/lib/webgen/common.rb +10 -0
  39. data/lib/webgen/common/sitemap.rb +76 -0
  40. data/lib/webgen/configuration.rb +64 -1
  41. data/lib/webgen/contentprocessor.rb +1 -1
  42. data/lib/webgen/contentprocessor/builder.rb +1 -1
  43. data/lib/webgen/contentprocessor/erb.rb +1 -1
  44. data/lib/webgen/contentprocessor/haml.rb +1 -1
  45. data/lib/webgen/contentprocessor/maruku.rb +1 -1
  46. data/lib/webgen/contentprocessor/sass.rb +1 -1
  47. data/lib/webgen/coreext.rb +10 -0
  48. data/lib/webgen/default_config.rb +35 -4
  49. data/lib/webgen/node.rb +12 -6
  50. data/lib/webgen/page.rb +1 -1
  51. data/lib/webgen/path.rb +1 -1
  52. data/lib/webgen/sourcehandler.rb +11 -6
  53. data/lib/webgen/sourcehandler/base.rb +5 -2
  54. data/lib/webgen/sourcehandler/feed.rb +121 -0
  55. data/lib/webgen/sourcehandler/metainfo.rb +22 -13
  56. data/lib/webgen/sourcehandler/page.rb +5 -3
  57. data/lib/webgen/sourcehandler/sitemap.rb +60 -0
  58. data/lib/webgen/sourcehandler/template.rb +5 -1
  59. data/lib/webgen/sourcehandler/virtual.rb +1 -0
  60. data/lib/webgen/tag.rb +1 -0
  61. data/lib/webgen/tag/breadcrumbtrail.rb +42 -10
  62. data/lib/webgen/tag/langbar.rb +1 -1
  63. data/lib/webgen/tag/menu.rb +10 -14
  64. data/lib/webgen/tag/sitemap.rb +42 -0
  65. data/lib/webgen/tree.rb +1 -1
  66. data/lib/webgen/version.rb +1 -1
  67. data/lib/webgen/website.rb +5 -6
  68. data/misc/default.css +6 -2
  69. data/test/helper.rb +13 -0
  70. data/test/test_common_sitemap.rb +56 -0
  71. data/test/test_configuration.rb +24 -0
  72. data/test/test_contentprocessor_maruku.rb +4 -1
  73. data/test/test_node.rb +4 -1
  74. data/test/test_page.rb +11 -5
  75. data/test/test_path.rb +10 -10
  76. data/test/test_sourcehandler_feed.rb +74 -0
  77. data/test/test_sourcehandler_metainfo.rb +26 -12
  78. data/test/test_sourcehandler_page.rb +1 -0
  79. data/test/test_sourcehandler_sitemap.rb +47 -0
  80. data/test/test_sourcehandler_template.rb +3 -0
  81. data/test/test_sourcehandler_virtual.rb +4 -1
  82. data/test/test_tag_breadcrumbtrail.rb +33 -23
  83. data/test/test_tag_menu.rb +24 -25
  84. data/test/test_tag_sitemap.rb +44 -0
  85. metadata +37 -4
@@ -20,7 +20,8 @@ module Webgen::CLI
20
20
  $:.shift
21
21
  require 'ramaze'
22
22
  Ramaze::Log.loggers = []
23
- def Ramaze.shutdown; end
23
+ def Ramaze.shutdown; # :nodoc:
24
+ end
24
25
 
25
26
  acquire Webgen.data_dir/:webgui/:controller/'*'
26
27
  Ramaze::Global.setup do |g|
@@ -0,0 +1,10 @@
1
+ module Webgen
2
+
3
+ # Namespace for classes that provide common functionality.
4
+ module Common
5
+
6
+ autoload :Sitemap, 'webgen/common/sitemap'
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,76 @@
1
+ require 'webgen/tag/menu'
2
+ require 'webgen/websiteaccess'
3
+
4
+ module Webgen::Common
5
+
6
+ # This class provides functionality for creating sitemaps and checking if a sitemap has changed.
7
+ class Sitemap
8
+
9
+ include Webgen::WebsiteAccess
10
+
11
+ def initialize #:nodoc:
12
+ website.blackboard.add_listener(:node_changed?, method(:node_changed?))
13
+ end
14
+
15
+ # Return the sitemap tree as Webgen::Tag::Menu::MenuNode created for the +node+ in the language
16
+ # +lang+ using the provided +options+ which can be any configuration option starting with
17
+ # <tt>common.sitemap</tt>.
18
+ def create_sitemap(node, lang, options)
19
+ @options = options
20
+ tree = recursive_create(nil, node.tree.root, lang).sort!
21
+ @options = nil
22
+ (node.node_info[:common_sitemap] ||= {})[[options.to_a.sort, lang]] = tree.to_lcn_list
23
+ tree
24
+ end
25
+
26
+ #######
27
+ private
28
+ #######
29
+
30
+ # Recursively create the sitemap.
31
+ def recursive_create(parent, node, lang, in_sitemap = true)
32
+ mnode = Webgen::Tag::Menu::MenuNode.new(parent, node)
33
+ node.children.map do |n|
34
+ sub_in_sitemap = ((option('common.sitemap.used_kinds').empty? || option('common.sitemap.used_kinds').include?(n['kind'])) &&
35
+ (option('common.sitemap.any_lang') || n.lang.nil? || n.lang == lang) &&
36
+ (!option('common.sitemap.honor_in_menu') || n['in_menu']) &&
37
+ (parent.nil? || node.routing_node(lang) != n))
38
+ [(!n.children.empty? || sub_in_sitemap ? n : nil), sub_in_sitemap]
39
+ end.each do |n, sub_in_sitemap|
40
+ next if n.nil?
41
+ sub_node = recursive_create(mnode, n, lang, sub_in_sitemap)
42
+ mnode.children << sub_node unless sub_node.nil?
43
+ end
44
+ (mnode.children.empty? && !in_sitemap ? nil : mnode)
45
+ end
46
+
47
+ # Retrieve the configuration option value for +name+. The value is taken from the current
48
+ # configuration options hash if +name+ is specified there or from the website configuration
49
+ # otherwise.
50
+ def option(name)
51
+ (@options && @options.has_key?(name) ? @options[name] : website.config[name])
52
+ end
53
+
54
+ # Check if the sitemaps for +node+ have changed.
55
+ def node_changed?(node)
56
+ return if !node.node_info[:common_sitemap]
57
+
58
+ node.node_info[:common_sitemap].each do |(options, lang), cached_tree|
59
+ @options = options.to_hash
60
+ tree = recursive_create(nil, node.tree.root, lang).sort!.to_lcn_list
61
+ @options = nil
62
+
63
+ if (tree != cached_tree) ||
64
+ (tree.flatten.any? do |alcn|
65
+ (n = node.tree[alcn]) && (r = n.routing_node(lang)) && r.meta_info_changed?
66
+ end)
67
+ node.dirty = true
68
+ break
69
+ end
70
+ end
71
+ end
72
+
73
+
74
+ end
75
+
76
+ end
@@ -6,7 +6,9 @@ module Webgen
6
6
  #
7
7
  # config.my.new.config 'value', :doc => 'some', :meta => 'info'
8
8
  #
9
- # and later accessed or set using the accessor methods #[] and #[]=.
9
+ # and later accessed or set using the accessor methods #[] and #[]= or a configuration
10
+ # helper. These helpers are defined in the Helpers module and provide easier access to complex
11
+ # configuration options.
10
12
  class Configuration
11
13
 
12
14
  # Helper class for providing an easy method to define configuration options.
@@ -32,6 +34,67 @@ module Webgen
32
34
 
33
35
  end
34
36
 
37
+ # This module provides methods for setting more complex configuration options. It is mixed into
38
+ # Webgen::Configuration so that it methods can be used. Detailed information on the use of the
39
+ # methods can be found in the "User Manual" in the "Configuration File" section.
40
+ #
41
+ # All public methods defined in this module are available for direct use in the
42
+ # configuration file, e.g. the method named +default_meta_info+ can be used like this:
43
+ #
44
+ # default_meta_info:
45
+ # Webgen::SourceHandler::Page:
46
+ # in_menu : true
47
+ # :action : replace
48
+ #
49
+ # All methods have to take exactly one argument, a Hash.
50
+ #
51
+ # The special key <tt>:action</tt> should be used for specifying how the configuration option
52
+ # should be set:
53
+ #
54
+ # replace:: Replace the configuration option with the new values.
55
+ # modify:: Replace old values with new values and add missing ones (useful for hashes and
56
+ # normally the default value)
57
+ module Helpers
58
+
59
+ # Set the default meta information for source handlers.
60
+ def default_meta_info(args)
61
+ args.each do |sh_name, mi|
62
+ raise ArgumentError, 'Invalid argument for configuration helper default_meta_info' unless mi.kind_of?(Hash)
63
+ action = mi.delete(:action) || 'modify'
64
+ mi_hash = (self['sourcehandler.default_meta_info'][complete_source_handler_name(sh_name)] ||= {})
65
+ case action
66
+ when 'replace' then mi_hash.replace(mi)
67
+ else mi_hash.update(mi)
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ # Set the path patterns used by source handlers.
74
+ def patterns(args)
75
+ args.each do |sh_name, data|
76
+ pattern_arr = (self['sourcehandler.patterns'][complete_source_handler_name(sh_name)] ||= [])
77
+ case data
78
+ when Array then pattern_arr.replace(data)
79
+ when Hash
80
+ (data['del'] || []).each {|pat| pattern_arr.delete(pat)}
81
+ (data['add'] || []).each {|pat| pattern_arr << pat}
82
+ else
83
+ raise ArgumentError, 'Invalid argument for configuration helper patterns'
84
+ end
85
+ end
86
+ end
87
+
88
+ # Complete +sh_name+ by checking if a source handler called
89
+ # <tt>Webgen::SourceHandler::SH_NAME</tt> exists.
90
+ def complete_source_handler_name(sh_name)
91
+ (Webgen::SourceHandler.constants.include?(sh_name) ? 'Webgen::SourceHandler::' + sh_name : sh_name)
92
+ end
93
+ private :complete_source_handler_name
94
+ end
95
+
96
+ include Helpers
97
+
35
98
  # The hash which stores the meta info for the configuration options.
36
99
  attr_reader :meta_info
37
100
 
@@ -36,7 +36,7 @@ module Webgen
36
36
  # context.content.gsub!(/#{context.content_node['replace_key']}:([\w\/.]+)/ ) do |match|
37
37
  # link_node = context.ref_node.resolve($1, context.content_node.lang)
38
38
  # if link_node
39
- # context.dest_node.link_to(link_node)
39
+ # context.dest_node.link_to(link_node, :lang => context.content_node.lang)
40
40
  # else
41
41
  # match
42
42
  # end
@@ -18,7 +18,7 @@ module Webgen::ContentProcessor
18
18
  context.content = xml.target!
19
19
  context
20
20
  rescue Exception => e
21
- raise RuntimeError, "Error using Builder to generate XML: #{e.message}", e.backtrace
21
+ raise RuntimeError, "Error using Builder in <#{context.ref_node.absolute_lcn}> to generate XML: #{e.message}", e.backtrace
22
22
  end
23
23
 
24
24
  end
@@ -16,7 +16,7 @@ module Webgen::ContentProcessor
16
16
  context.content = erb.result(binding)
17
17
  context
18
18
  rescue Exception => e
19
- raise RuntimeError, "Erb processing failed: #{e.message}", e.backtrace
19
+ raise RuntimeError, "Erb processing failed in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
20
20
  end
21
21
 
22
22
  end
@@ -17,7 +17,7 @@ module Webgen::ContentProcessor
17
17
  render(Object.new, locals)
18
18
  context
19
19
  rescue Exception => e
20
- raise RuntimeError, "Error converting Haml markup to HTML: #{e.message}", e.backtrace
20
+ raise RuntimeError, "Error converting Haml markup to HTML in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
21
21
  end
22
22
 
23
23
  end
@@ -10,7 +10,7 @@ module Webgen::ContentProcessor
10
10
  context.content = ::Maruku.new(context.content, :on_error => :raise).to_html
11
11
  context
12
12
  rescue Exception => e
13
- raise RuntimeError, "Maruku to HTML conversion failed: #{e.message}", e.backtrace
13
+ raise RuntimeError, "Maruku to HTML conversion failed for <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
14
14
  end
15
15
 
16
16
  end
@@ -10,7 +10,7 @@ module Webgen::ContentProcessor
10
10
  context.content = ::Sass::Engine.new(context.content, :filename => context.ref_node.absolute_lcn).render
11
11
  context
12
12
  rescue Exception => e
13
- raise RuntimeError, "Error converting Sass markup to CSS: #{e.message}", e.backtrace
13
+ raise RuntimeError, "Error converting Sass markup to CSS in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
14
14
  end
15
15
 
16
16
  end
@@ -0,0 +1,10 @@
1
+ # :nodoc:
2
+ class Array
3
+
4
+ def to_hash # :nodoc:
5
+ h = {}
6
+ self.each {|k,v| h[k] = v}
7
+ h
8
+ end
9
+
10
+ end
@@ -49,11 +49,15 @@ config.sourcehandler.patterns({
49
49
  'Webgen::SourceHandler::Metainfo' => ['**/metainfo', '**/*.metainfo'],
50
50
  'Webgen::SourceHandler::Template' => ['**/*.template'],
51
51
  'Webgen::SourceHandler::Page' => ['**/*.page'],
52
- 'Webgen::SourceHandler::Virtual' => ['**/virtual', '**/*.virtual']
52
+ 'Webgen::SourceHandler::Virtual' => ['**/virtual', '**/*.virtual'],
53
+ 'Webgen::SourceHandler::Feed' => ['**/*.feed'],
54
+ 'Webgen::SourceHandler::Sitemap' => ['**/*.sitemap']
53
55
  }, :doc => 'Source handler to path pattern map')
54
56
  config.sourcehandler.invoke({
55
57
  1 => ['Webgen::SourceHandler::Directory', 'Webgen::SourceHandler::Metainfo', 'Webgen::SourceHandler::Directory'],
56
- 5 => ['Webgen::SourceHandler::Copy', 'Webgen::SourceHandler::Template', 'Webgen::SourceHandler::Page'],
58
+ 5 => ['Webgen::SourceHandler::Copy', 'Webgen::SourceHandler::Template',
59
+ 'Webgen::SourceHandler::Page', 'Webgen::SourceHandler::Feed',
60
+ 'Webgen::SourceHandler::Sitemap'],
57
61
  9 => ['Webgen::SourceHandler::Virtual']
58
62
  }, :doc => 'All source handlers listed here are used by webgen and invoked according to their priority setting')
59
63
  config.sourcehandler.casefold(true, :doc => 'Specifies whether path are considered to be case-sensitive')
@@ -65,18 +69,35 @@ config.sourcehandler.default_meta_info({
65
69
  :all => {
66
70
  'output_path_style' => [:parent, :cnbase, ['.', :lang], :ext]
67
71
  },
72
+ 'Webgen::SourceHandler::Copy' => {
73
+ 'kind' => 'asset'
74
+ },
68
75
  'Webgen::SourceHandler::Directory' => {
69
- 'index_path' => 'index.html'
76
+ 'index_path' => 'index.html',
77
+ 'kind' => 'directory'
70
78
  },
71
79
  'Webgen::SourceHandler::Page' => {
80
+ 'kind' => 'page',
72
81
  'fragments_in_menu' => true,
73
82
  'blocks' => {'default' => {'pipeline' => 'erb,tags,maruku,blocks'}}
74
83
  },
84
+ 'Webgen::SourceHandler::Fragment' => {
85
+ 'kind' => 'fragment'
86
+ },
75
87
  'Webgen::SourceHandler::Template' => {
76
88
  'blocks' => {'default' => {'pipeline' => 'erb,tags,blocks'}}
77
89
  },
78
90
  'Webgen::SourceHandler::Metainfo' => {
79
91
  'blocks' => {1 => {'name' => 'paths'}, 2 => {'name' => 'alcn'}}
92
+ },
93
+ 'Webgen::SourceHandler::Feed' => {
94
+ 'rss' => true,
95
+ 'atom' => true
96
+ },
97
+ 'Webgen::SourceHandler::Sitemap' => {
98
+ 'default_priority' => 0.5,
99
+ 'default_change_freq' => 'weekly',
100
+ 'common.sitemap.any_lang' => true
80
101
  }
81
102
  }, :doc => "Default meta information for all nodes and for nodes belonging to a specific source handler")
82
103
 
@@ -121,6 +142,7 @@ config.contentprocessor.tags.map({
121
142
  'execute_cmd' => 'Webgen::Tag::ExecuteCommand',
122
143
  'coderay' => 'Webgen::Tag::Coderay',
123
144
  'date' => 'Webgen::Tag::Date',
145
+ 'sitemap' => 'Webgen::Tag::Sitemap',
124
146
  :default => 'Webgen::Tag::Metainfo'
125
147
  }, :doc => 'Tag processor name to class map')
126
148
 
@@ -133,8 +155,9 @@ config.tag.menu.show_current_subtree_only(true, :doc => 'Specifies whether only
133
155
  config.tag.menu.used_nodes('all', :doc => 'Specifies the kind of nodes that should be used: all, files, or fragments')
134
156
 
135
157
  config.tag.breadcrumbtrail.separator(' / ', :doc => 'Separates the hierachy entries from each other.')
136
- config.tag.breadcrumbtrail.omit_last(false, :doc => 'Omits the last path component.')
137
158
  config.tag.breadcrumbtrail.omit_index_path(false, :doc => 'Omits the last path component if it is an index path.')
159
+ config.tag.breadcrumbtrail.start_level(0, :doc => 'The level at which the breadcrumb trail starts.')
160
+ config.tag.breadcrumbtrail.end_level(-1, :doc => 'The level at which the breadcrumb trail ends.')
138
161
 
139
162
  config.tag.langbar.separator(' | ', :doc => 'Separates the languages from each other.')
140
163
  config.tag.langbar.show_single_lang(true, :doc => 'Should the link be shown although the page is only available in one language?')
@@ -157,3 +180,11 @@ config.tag.coderay.bold_every(10, :doc => 'The interval at which the line number
157
180
  config.tag.coderay.tab_width(8, :doc => 'Number of spaces used for a tabulator')
158
181
 
159
182
  config.tag.date.format('%Y-%m-%d %H:%M:%S', :doc => 'The format of the date (same options as Ruby\'s Time#strftime)')
183
+
184
+
185
+ # All things regarding common functionality
186
+ website.autoload_service(:create_sitemap, 'Webgen::Common::Sitemap')
187
+
188
+ config.common.sitemap.honor_in_menu(false, :doc => 'Only include pages that are also in the menu if true')
189
+ config.common.sitemap.any_lang(false, :doc => 'Use nodes in any language if true')
190
+ config.common.sitemap.used_kinds(['page'], :doc => 'Array of node kinds that is used for the sitemap')
@@ -119,6 +119,7 @@ module Webgen
119
119
  # Return +true+ if the node has changed since the last webgen run. If it has changed, +dirty+ is
120
120
  # set to +true+.
121
121
  def changed?
122
+ @dirty = @dirty || meta_info_changed?
122
123
  @dirty = node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)} unless @dirty
123
124
  website.blackboard.dispatch_msg(:node_changed?, self) unless @dirty
124
125
  @dirty
@@ -274,18 +275,23 @@ module Webgen
274
275
  # You can optionally specify additional attributes for the HTML element in the +attr+ Hash.
275
276
  # Also, the meta information +link_attrs+ of the given +node+ is used, if available, to set
276
277
  # attributes. However, the +attr+ parameter takes precedence over the +link_attrs+ meta
277
- # information. If the special value <tt>:link_text</tt> is present in the attributes, it will be
278
- # used as the link text; otherwise the title of the +node+ will be used. Be aware that all
279
- # key-value pairs with Symbol keys are removed before the attributes are written. Therefore you
280
- # always need to specify general attributes with Strings!
278
+ # information. Be aware that all key-value pairs with Symbol keys are removed before the
279
+ # attributes are written. Therefore you always need to specify general attributes with Strings!
280
+ #
281
+ # If the special value <tt>:link_text</tt> is present in the attributes, it will be used as the
282
+ # link text; otherwise the title of the +node+ will be used.
283
+ #
284
+ # If the special value <tt>:lang</tt> is present in the attributes, it will be used as parameter
285
+ # to the <tt>node.routing_node</tt> call for getting the linked-to node instead of this node's
286
+ # +lang+ attribute. Note: this is only useful when linking to a directory.
281
287
  def link_to(node, attr = {})
282
288
  attr = node['link_attrs'].merge(attr) if node['link_attrs'].kind_of?(Hash)
283
- rnode = node.routing_node(@lang)
289
+ rnode = node.routing_node(attr[:lang] || @lang)
284
290
  link_text = attr[:link_text] || (rnode != node && rnode['routed_title']) || node['title']
285
291
  attr.delete_if {|k,v| k.kind_of?(Symbol)}
286
292
 
287
293
  use_link = (rnode != self || website.config['website.link_to_current_page'])
288
- attr['href'] = self.route_to(node) if use_link
294
+ attr['href'] = self.route_to(rnode) if use_link
289
295
  attrs = attr.collect {|name,value| "#{name.to_s}=\"#{value}\"" }.sort.unshift('').join(' ')
290
296
  (use_link ? "<a#{attrs}>#{link_text}</a>" : "<span#{attrs}>#{link_text}</span>")
291
297
  end
@@ -44,7 +44,7 @@ module Webgen
44
44
  class Page
45
45
 
46
46
  RE_META_INFO_START = /\A---\s*(?:\n|\r|\r\n)/m
47
- RE_META_INFO = /\A---\s*(?:\n|\r|\r\n).*?(?:\n|\r|\r\n)(?=---.*?(?:\n|\r|\r\n))/m
47
+ RE_META_INFO = /\A---\s*(?:\n|\r|\r\n).*?(?:\n|\r|\r\n)(?=---.*?(?:\n|\r|\r\n)|\Z)/m
48
48
  RE_BLOCKS_OPTIONS = /^--- *?(?: *((?:\w+:[^\s]* *)*))?$|^$/
49
49
  RE_BLOCKS_START = /^--- .*?$|^--- *$/
50
50
  RE_BLOCKS = /(?:(#{RE_BLOCKS_START})|\A)(.*?)(?:(?=#{RE_BLOCKS_START})|\Z)/m
@@ -169,7 +169,7 @@ module Webgen
169
169
  @directory = File.join(File.dirname(path), '/')
170
170
  matchData = FILENAME_RE.match(@basename)
171
171
 
172
- @meta_info['sort_info'] = matchData[1].to_i
172
+ @meta_info['sort_info'] = (matchData[1].nil? ? nil : matchData[1].to_i)
173
173
  @cnbase = matchData[2]
174
174
  @meta_info['lang'] = Webgen::LanguageManager.language_for_code(matchData[3])
175
175
  @ext = (@meta_info['lang'].nil? && !matchData[3].nil? ? matchData[3].to_s + '.' : '') + matchData[4].to_s
@@ -17,6 +17,8 @@ module Webgen
17
17
  autoload :Page, 'webgen/sourcehandler/page'
18
18
  autoload :Fragment, 'webgen/sourcehandler/fragment'
19
19
  autoload :Virtual, 'webgen/sourcehandler/virtual'
20
+ autoload :Feed, 'webgen/sourcehandler/feed'
21
+ autoload :Sitemap, 'webgen/sourcehandler/sitemap'
20
22
 
21
23
  # This class is used by Website to do the actual rendering of the website. It
22
24
  #
@@ -142,7 +144,7 @@ module Webgen
142
144
  else
143
145
  source_handler.create_node(parent, path.dup)
144
146
  end
145
- nodes.compact.each do |node|
147
+ nodes.flatten.compact.each do |node|
146
148
  website.blackboard.dispatch_msg(:after_node_created, node)
147
149
  end
148
150
  nodes
@@ -154,13 +156,16 @@ module Webgen
154
156
  merge(website.config['sourcehandler.default_meta_info'][sh_name] || {})
155
157
  end
156
158
 
157
- # Check if the default meta information for +node+ has changed since the last run.
159
+ # Check if the default meta information for +node+ has changed since the last run. But don't
160
+ # take the node's path's +modified_at+ meta information into account since that changes on
161
+ # every path change.
158
162
  def meta_info_changed?(node)
159
163
  path = node.node_info[:src]
160
- cached_mi = website.cache[:sourcehandler_path_mi][[path, node.node_info[:processor]]]
161
- if !cached_mi || cached_mi != default_meta_info(@paths[path], node.node_info[:processor])
162
- node.dirty_meta_info = true
163
- end
164
+ old_mi = website.cache[:sourcehandler_path_mi][[path, node.node_info[:processor]]]
165
+ old_mi.delete('modified_at')
166
+ new_mi = default_meta_info(@paths[path], node.node_info[:processor])
167
+ new_mi.delete('modified_at')
168
+ node.dirty_meta_info = true if !old_mi || old_mi != new_mi
164
169
  end
165
170
 
166
171
  # Clean the +tree+ by deleting nodes which have changed or which don't have an associated
@@ -152,11 +152,14 @@ module Webgen::SourceHandler
152
152
  parent.tree[Webgen::Node.absolute_name(parent, path.lcn, :alcn)] || (!path.meta_info['no_output'] && parent.tree[output_path, :path])
153
153
  end
154
154
 
155
- # Create and return a node under +parent+ from +path+ if it does not already exists. The created
156
- # node is yielded if a block is given.
155
+ # Create and return a node under +parent+ from +path+ if it does not already exists. Some
156
+ # additional node information like <tt>:src</tt> and <tt>:processor</tt> is set and the meta
157
+ # information is checked for validness. The created node is yielded if a block is given.
157
158
  def create_node(parent, path, output_path = self.output_path(parent, path))
159
+ return if path.meta_info['draft']
158
160
  if !node_exists?(parent, path, output_path)
159
161
  node = Webgen::Node.new(parent, output_path, path.cn, path.meta_info)
162
+ node['modified_at'] = Time.now unless node['modified_at'].kind_of?(Time)
160
163
  node.node_info[:src] = path.path
161
164
  node.node_info[:processor] = self.class.name
162
165
  yield(node) if block_given?