webgen 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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?