gettalong-webgen 0.5.8.20090507 → 0.5.9.20090620

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/Rakefile +5 -6
  2. data/data/webgen/passive_sources/images/generated_by_webgen.png +0 -0
  3. data/data/webgen/passive_sources/images/webgen_logo.png +0 -0
  4. data/data/webgen/passive_sources/templates/atom_feed.template +38 -0
  5. data/data/webgen/passive_sources/templates/rss_feed.template +28 -0
  6. data/data/webgen/resources.yaml +2 -1
  7. data/doc/contentprocessor/builder.page +1 -1
  8. data/doc/contentprocessor/erb.page +5 -2
  9. data/doc/contentprocessor/erubis.page +2 -2
  10. data/doc/extensions.page +1 -1
  11. data/doc/manual.page +56 -26
  12. data/doc/reference_configuration.page +36 -1
  13. data/doc/reference_website_styles.page +1 -1
  14. data/doc/sourcehandler/feed.page +6 -11
  15. data/doc/tag/includefile.page +1 -1
  16. data/lib/webgen/cli/apply_command.rb +1 -1
  17. data/lib/webgen/cli/utils.rb +2 -2
  18. data/lib/webgen/common.rb +0 -9
  19. data/lib/webgen/contentprocessor/blocks.rb +60 -36
  20. data/lib/webgen/contentprocessor/builder.rb +2 -2
  21. data/lib/webgen/contentprocessor/erb.rb +3 -2
  22. data/lib/webgen/contentprocessor/erubis.rb +2 -2
  23. data/lib/webgen/contentprocessor/haml.rb +2 -2
  24. data/lib/webgen/contentprocessor/maruku.rb +1 -1
  25. data/lib/webgen/contentprocessor/sass.rb +2 -2
  26. data/lib/webgen/contentprocessor/tags.rb +25 -11
  27. data/lib/webgen/context.rb +4 -1
  28. data/lib/webgen/context/render.rb +32 -0
  29. data/lib/webgen/context/tags.rb +20 -0
  30. data/lib/webgen/default_config.rb +4 -1
  31. data/lib/webgen/deprecated.rb +37 -4
  32. data/lib/webgen/node.rb +37 -38
  33. data/lib/webgen/path.rb +151 -54
  34. data/lib/webgen/source.rb +6 -6
  35. data/lib/webgen/source/stacked.rb +13 -5
  36. data/lib/webgen/sourcehandler.rb +71 -45
  37. data/lib/webgen/sourcehandler/base.rb +51 -21
  38. data/lib/webgen/sourcehandler/copy.rb +4 -4
  39. data/lib/webgen/sourcehandler/directory.rb +3 -9
  40. data/lib/webgen/sourcehandler/feed.rb +23 -49
  41. data/lib/webgen/sourcehandler/fragment.rb +10 -8
  42. data/lib/webgen/sourcehandler/memory.rb +9 -10
  43. data/lib/webgen/sourcehandler/metainfo.rb +9 -9
  44. data/lib/webgen/sourcehandler/page.rb +5 -5
  45. data/lib/webgen/sourcehandler/sitemap.rb +3 -3
  46. data/lib/webgen/sourcehandler/template.rb +6 -6
  47. data/lib/webgen/sourcehandler/virtual.rb +19 -17
  48. data/lib/webgen/tag/base.rb +34 -26
  49. data/lib/webgen/tag/breadcrumbtrail.rb +3 -3
  50. data/lib/webgen/tag/executecommand.rb +3 -3
  51. data/lib/webgen/tag/langbar.rb +2 -2
  52. data/lib/webgen/tag/link.rb +3 -3
  53. data/lib/webgen/tag/menu.rb +2 -2
  54. data/lib/webgen/tag/metainfo.rb +1 -1
  55. data/lib/webgen/tag/relocatable.rb +17 -21
  56. data/lib/webgen/tag/tikz.rb +5 -6
  57. data/lib/webgen/tree.rb +7 -7
  58. data/lib/webgen/version.rb +1 -1
  59. data/lib/webgen/website.rb +4 -2
  60. data/misc/default.css +8 -2
  61. data/misc/default.template +2 -2
  62. data/misc/logo.svg +313 -0
  63. data/misc/style.page +1 -1
  64. data/test/helper.rb +2 -2
  65. data/test/test_common_sitemap.rb +1 -1
  66. data/test/test_contentprocessor_blocks.rb +12 -4
  67. data/test/test_contentprocessor_builder.rb +2 -1
  68. data/test/test_contentprocessor_erb.rb +2 -1
  69. data/test/test_contentprocessor_erubis.rb +1 -1
  70. data/test/test_contentprocessor_fragments.rb +12 -11
  71. data/test/test_contentprocessor_haml.rb +2 -1
  72. data/test/test_contentprocessor_maruku.rb +1 -0
  73. data/test/test_contentprocessor_rdiscount.rb +1 -0
  74. data/test/test_contentprocessor_rdoc.rb +1 -0
  75. data/test/test_contentprocessor_sass.rb +1 -0
  76. data/test/test_contentprocessor_tags.rb +13 -0
  77. data/test/test_context.rb +28 -0
  78. data/test/test_node.rb +40 -20
  79. data/test/test_path.rb +106 -65
  80. data/test/test_source_filesystem.rb +1 -1
  81. data/test/test_source_stacked.rb +19 -6
  82. data/test/test_sourcehandler_base.rb +53 -47
  83. data/test/test_sourcehandler_copy.rb +6 -6
  84. data/test/test_sourcehandler_directory.rb +8 -12
  85. data/test/test_sourcehandler_feed.rb +10 -6
  86. data/test/test_sourcehandler_fragment.rb +6 -5
  87. data/test/test_sourcehandler_main.rb +39 -0
  88. data/test/test_sourcehandler_memory.rb +4 -4
  89. data/test/test_sourcehandler_metainfo.rb +10 -10
  90. data/test/test_sourcehandler_page.rb +9 -9
  91. data/test/test_sourcehandler_sitemap.rb +4 -4
  92. data/test/test_sourcehandler_template.rb +14 -14
  93. data/test/test_sourcehandler_virtual.rb +9 -5
  94. data/test/test_tag_base.rb +2 -2
  95. data/test/test_tag_executecommand.rb +1 -1
  96. data/test/test_tag_link.rb +4 -3
  97. data/test/test_tag_menu.rb +15 -15
  98. data/test/test_tag_metainfo.rb +1 -0
  99. data/test/test_tag_relocatable.rb +2 -1
  100. data/test/test_tag_tikz.rb +3 -3
  101. data/test/test_tree.rb +8 -8
  102. data/test/test_website.rb +15 -0
  103. metadata +14 -14
  104. data/test/test_common.rb +0 -18
@@ -19,11 +19,11 @@ module Webgen::ContentProcessor
19
19
  dest_node = deprecate('dest_node', 'context.dest_node', context.dest_node)
20
20
 
21
21
  xml = ::Builder::XmlMarkup.new(:indent => 2)
22
- eval(context.content, binding, context.ref_node.absolute_lcn)
22
+ eval(context.content, binding, context.ref_node.alcn)
23
23
  context.content = xml.target!
24
24
  context
25
25
  rescue Exception => e
26
- raise RuntimeError, "Error using Builder in <#{context.ref_node.absolute_lcn}> to generate XML: #{e.message}", e.backtrace
26
+ raise RuntimeError, "Error using Builder in <#{context.ref_node.alcn}> to generate XML: #{e.message}", e.backtrace
27
27
  end
28
28
 
29
29
  end
@@ -10,6 +10,7 @@ module Webgen::ContentProcessor
10
10
  # Process the Ruby statements embedded in the content of +context+.
11
11
  def call(context)
12
12
  require 'erb'
13
+ extend(ERB::Util)
13
14
 
14
15
  website = deprecate('website', 'context.website', context.website)
15
16
  node = deprecate('node', 'context.node', context.content_node)
@@ -17,11 +18,11 @@ module Webgen::ContentProcessor
17
18
  dest_node = deprecate('dest_node', 'context.dest_node', context.dest_node)
18
19
 
19
20
  erb = ERB.new(context.content)
20
- erb.filename = context.ref_node.absolute_lcn
21
+ erb.filename = context.ref_node.alcn
21
22
  context.content = erb.result(binding)
22
23
  context
23
24
  rescue Exception => e
24
- raise RuntimeError, "Erb processing failed in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
25
+ raise RuntimeError, "Erb processing failed in <#{context.ref_node.alcn}>: #{e.message}", e.backtrace
25
26
  end
26
27
 
27
28
  end
@@ -29,11 +29,11 @@ module Webgen::ContentProcessor
29
29
  else
30
30
  ::Erubis::Eruby.new(context.content, options)
31
31
  end
32
- erubis.filename = context.ref_node.absolute_lcn
32
+ erubis.filename = context.ref_node.alcn
33
33
  context.content = erubis.result(binding)
34
34
  context
35
35
  rescue Exception => e
36
- raise RuntimeError, "Erubis processing failed in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
36
+ raise RuntimeError, "Erubis processing failed in <#{context.ref_node.alcn}>: #{e.message}", e.backtrace
37
37
  end
38
38
 
39
39
  end
@@ -18,11 +18,11 @@ module Webgen::ContentProcessor
18
18
  :ref_node => deprecate('ref_node', 'context.ref_node', context.ref_node),
19
19
  :dest_node => deprecate('dest_node', 'context.dest_node', context.dest_node)
20
20
  }
21
- context.content = ::Haml::Engine.new(context.content, :filename => context.ref_node.absolute_lcn).
21
+ context.content = ::Haml::Engine.new(context.content, :filename => context.ref_node.alcn).
22
22
  render(Object.new, locals)
23
23
  context
24
24
  rescue Exception => e
25
- raise RuntimeError, "Error converting Haml markup to HTML in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
25
+ raise RuntimeError, "Error converting Haml markup to HTML in <#{context.ref_node.alcn}>: #{e.message}", e.backtrace
26
26
  end
27
27
 
28
28
  end
@@ -12,7 +12,7 @@ module Webgen::ContentProcessor
12
12
  context.content = ::Maruku.new(context.content, :on_error => :raise).to_html
13
13
  context
14
14
  rescue Exception => e
15
- raise RuntimeError, "Maruku to HTML conversion failed for <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
15
+ raise RuntimeError, "Maruku to HTML conversion failed for <#{context.ref_node.alcn}>: #{e.message}", e.backtrace
16
16
  end
17
17
 
18
18
  end
@@ -9,10 +9,10 @@ module Webgen::ContentProcessor
9
9
  def call(context)
10
10
  require 'sass'
11
11
 
12
- context.content = ::Sass::Engine.new(context.content, :filename => context.ref_node.absolute_lcn).render
12
+ context.content = ::Sass::Engine.new(context.content, :filename => context.ref_node.alcn).render
13
13
  context
14
14
  rescue Exception => e
15
- raise RuntimeError, "Error converting Sass markup to CSS in <#{context.ref_node.absolute_lcn}>: #{e.message}", e.backtrace
15
+ raise RuntimeError, "Error converting Sass markup to CSS in <#{context.ref_node.alcn}>: #{e.message}", e.backtrace
16
16
  end
17
17
 
18
18
  end
@@ -23,23 +23,37 @@ module Webgen::ContentProcessor
23
23
  # Replace all webgen tags in the content of +context+ with the rendered content.
24
24
  def call(context)
25
25
  replace_tags(context.content, context.ref_node) do |tag, param_string, body|
26
- log(:debug) { "Replacing tag #{tag} with data '#{param_string}' and body '#{body}' in <#{context.ref_node.absolute_lcn}>" }
26
+ log(:debug) { "Replacing tag #{tag} with data '#{param_string}' and body '#{body}' in <#{context.ref_node.alcn}>" }
27
+ process_tag(tag, param_string, body, context)
28
+ end
29
+ context
30
+ end
27
31
 
28
- result = ''
29
- processor = processor_for_tag(tag)
30
- if !processor.nil?
31
- processor.set_params(processor.create_tag_params(param_string, context.ref_node))
32
+ # Process the +tag+ and return the result. The parameter +params+ needs to be a Hash holding all
33
+ # needed and optional parameters for the tag or a parameter String in YAML format and +body+ is
34
+ # the optional body for the tag. +context+ needs to be a valid Webgen::Context object.
35
+ def process_tag(tag, params, body, context)
36
+ result = ''
37
+ processor = processor_for_tag(tag)
38
+ if !processor.nil?
39
+ params, mandatory_missing = if params.kind_of?(String)
40
+ processor.create_tag_params(params, context.ref_node)
41
+ else
42
+ processor.create_params_hash(params, context.ref_node)
43
+ end
44
+ if mandatory_missing
45
+ context.dest_node.flag(:dirty)
46
+ else
47
+ processor.set_params(params)
32
48
  result, process_output = processor.call(tag, body, context)
33
49
  processor.set_params(nil)
34
-
35
50
  result = call(context.clone(:content => result)).content if process_output
36
51
  end
37
-
38
- result
39
52
  end
40
- context
53
+ result
41
54
  end
42
55
 
56
+
43
57
  #######
44
58
  private
45
59
  #######
@@ -72,7 +86,7 @@ module Webgen::ContentProcessor
72
86
  when :in_start_tag
73
87
  data.brackets += (scanner[1] == '{' ? 1 : -1) while data.brackets != 0 && scanner.skip_until(BRACKETS_RE)
74
88
  if data.brackets != 0
75
- log(:error) { "Unbalanced curly brackets in <#{node.absolute_lcn}>!" }
89
+ log(:error) { "Unbalanced curly brackets in <#{node.alcn}>!" }
76
90
  data.state = :done
77
91
  else
78
92
  data.params_end_pos = data.body_end_pos = data.end_pos = scanner.pos - 1
@@ -106,7 +120,7 @@ module Webgen::ContentProcessor
106
120
  data.end_pos = scanner.pos - 1
107
121
  data.body_end_pos = scanner.pos - scanner.matched.length + scanner[1].length / 2
108
122
  else
109
- log(:error) { "Invalid body part in <#{node.absolute_lcn}>!" }
123
+ log(:error) { "Invalid body part in <#{node.alcn}>!" }
110
124
  data.state = :done
111
125
  end
112
126
 
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require 'webgen/context/nodes'
3
+ require 'webgen/context/tags'
4
+ require 'webgen/context/render'
3
5
 
4
6
  module Webgen
5
7
 
@@ -13,7 +15,8 @@ module Webgen
13
15
  # The content string that should be processed.
14
16
  #
15
17
  # [<tt>:processors</tt>]
16
- # Normally an AccessHash object providing access to all available content processors.
18
+ # Normally an ContentProcessor::AccessHash object providing access to all available content
19
+ # processors.
17
20
  #
18
21
  # [<tt>:chain</tt>]
19
22
  # The chain of nodes that is processed. There are some utiltity methods for getting
@@ -0,0 +1,32 @@
1
+ module Webgen
2
+
3
+ class Context
4
+
5
+ # Render the named block and return the result.
6
+ #
7
+ # call-seq:
8
+ # context.render_block(block_name)<br />
9
+ # context.render_block(:name => block_name, :option => value, ...)
10
+ #
11
+ # This method uses the functionality of the content processor +blocks+ for doing the actual
12
+ # work, so you may also want to look at Webgen::ContentProcessor::Blocks#render_block. You can
13
+ # call this method in two ways:
14
+ #
15
+ # [<tt>#render_block(block_name)</tt>]
16
+ # Renders the block named +block_name+ of the next node in the current node chain. This is the
17
+ # version that most want to use since it is equivalent to the use of <tt><webgen:block
18
+ # name="block_name" /></tt>. It is equivalent to <tt>#render_block(:name =>
19
+ # block_name)</tt>.
20
+ #
21
+ # [<tt>#render_block(opts_hash)</tt>]
22
+ # This version allows the same level of control over the output as the blocks content
23
+ # processor. For a list of valid options have a look at the documentation of the
24
+ # Webgen::ContentProcessor::Blocks#render_block method!
25
+ def render_block(name_or_hash)
26
+ name_or_hash = {:name => name_or_hash} if name_or_hash.kind_of?(String)
27
+ website.cache.instance('Webgen::ContentProcessor::Blocks').render_block(self, name_or_hash)
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,20 @@
1
+ module Webgen
2
+
3
+ class Context
4
+
5
+ # Returns the result of evaluating the webgen tag +name+ with the tag parameters +params+ and
6
+ # the +body+ in the current context.
7
+ #
8
+ # Have a look at Webgen::Tag::Base for more information about webgen tags!
9
+ #
10
+ # This method is useful when you want to have the functionality of webgen tags available but you
11
+ # don't want to use the content processor for them. Or, for example, if the used markup language
12
+ # uses a similar markup as webgen tags do and therefore you can't use the normal webgen tags
13
+ # content processor.
14
+ def tag(name, params = {}, body = '')
15
+ website.cache.instance('Webgen::ContentProcessor::Tags').process_tag(name, params, body, self)
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -43,6 +43,7 @@ end
43
43
 
44
44
  # All things regarding sources
45
45
  config.sources [['/', "Webgen::Source::FileSystem", 'src']], :doc => 'One or more sources from which files are read, relative to website directory'
46
+ config.passive_sources([['/', "Webgen::Source::Resource", "webgen-passive-sources"]], :doc => 'One or more sources for delayed node creation on node resolution')
46
47
 
47
48
  # All things regarding source handler
48
49
  config.sourcehandler.patterns({
@@ -70,7 +71,7 @@ config.sourcehandler.default_lang_in_output_path(false, :doc => 'Specifies wheth
70
71
  config.sourcehandler.default_meta_info({
71
72
  :all => {
72
73
  'output_path' => 'standard',
73
- 'output_path_style' => [:parent, :cnbase, ['.', :lang], :ext]
74
+ 'output_path_style' => [:parent, :basename, ['.', :lang], :ext]
74
75
  },
75
76
  'Webgen::SourceHandler::Copy' => {
76
77
  'kind' => 'asset'
@@ -114,6 +115,8 @@ website.autoload_service(:parse_html_headers, 'Webgen::SourceHandler::Fragment')
114
115
 
115
116
  # All things regarding output
116
117
  config.output ["Webgen::Output::FileSystem", 'out'], :doc => 'The class which is used to output the generated paths.'
118
+ config.output.do_deletion(false, :doc => 'Specifies whether the generated output paths should be deleted once the sources are deleted')
119
+
117
120
 
118
121
  Webgen::WebsiteAccess.website.blackboard.add_service(:output_instance, Webgen::Output.method(:instance))
119
122
 
@@ -3,18 +3,42 @@ module Webgen
3
3
  class Node
4
4
 
5
5
  def flagged(key)
6
- warn("Deprecation warning: this method will be removed in one of the next releases - use Node#flagged? instead!")
6
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Node#flagged? instead!")
7
7
  flagged?(key)
8
8
  end
9
9
 
10
+ def absolute_cn
11
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Node#acn instead!")
12
+ acn
13
+ end
14
+
15
+ def absolute_lcn
16
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Node#alcn instead!")
17
+ alcn
18
+ end
19
+
20
+ end
21
+
22
+ class Path
23
+
24
+ def cnbase
25
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Path#basename instead!")
26
+ @basename
27
+ end
28
+
29
+ def cnbase=(value)
30
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Path#basename= instead!")
31
+ basename = value
32
+ end
33
+
10
34
  end
11
35
 
12
36
  def self.const_missing(const)
13
37
  if const.to_s == 'Block'
14
- warn("Deprecation warning: Webgen::Block name will be removed in one of the next releases - use Webgen::Page::Block instead!")
38
+ warn("Deprecation warning (~ #{caller.first}): Webgen::Block name will be removed in one of the next releases - use Webgen::Page::Block instead!")
15
39
  Webgen::Page::Block
16
40
  elsif const.to_s == "WebgenPageFormatError"
17
- warn("Deprecation warning: Webgen::WebgenPageFormatError name will be removed in one of the next releases - use Webgen::Page::FormatError instead!")
41
+ warn("Deprecation warning (~ #{caller.first}): Webgen::WebgenPageFormatError name will be removed in one of the next releases - use Webgen::Page::FormatError instead!")
18
42
  Webgen::Page::FormatError
19
43
  else
20
44
  super
@@ -25,7 +49,7 @@ module Webgen
25
49
 
26
50
  def self.const_missing(const)
27
51
  if const.to_s == 'Context'
28
- warn("Deprecation warning: Webgen::ContentProcessor::Context is now named Webgen::Context! This alias will be removed in one of the next releases.")
52
+ warn("Deprecation warning (~ #{caller.first}): Webgen::ContentProcessor::Context is now named Webgen::Context! This alias will be removed in one of the next releases.")
29
53
  Webgen::Context
30
54
  else
31
55
  super
@@ -50,4 +74,13 @@ module Webgen
50
74
 
51
75
  end
52
76
 
77
+ module Common
78
+
79
+ def self.absolute_path(path, base)
80
+ warn("Deprecation warning (~ #{caller.first}): this method will be removed in one of the next releases - use Webgen::Path.make_absolute(base, path) instead!")
81
+ Path.make_absolute(base, path)
82
+ end
83
+
84
+ end
85
+
53
86
  end
data/lib/webgen/node.rb CHANGED
@@ -22,10 +22,11 @@ module Webgen
22
22
  include WebsiteAccess
23
23
  include Loggable
24
24
 
25
- # The parent node.
25
+ # The parent node. This is in all but one case a Node object. The one exception is that the
26
+ # parent of the Tree#dummy_node is a Tree object.
26
27
  attr_reader :parent
27
28
 
28
- # The children of this node.
29
+ # The child nodes of this node.
29
30
  attr_reader :children
30
31
 
31
32
  # The full output path of this node.
@@ -38,13 +39,13 @@ module Webgen
38
39
  attr_reader :cn
39
40
 
40
41
  # The absolute canonical name of this node.
41
- attr_reader :absolute_cn
42
+ attr_reader :acn
42
43
 
43
44
  # The localized canonical name of this node.
44
45
  attr_reader :lcn
45
46
 
46
47
  # The absolute localized canonical name of this node.
47
- attr_reader :absolute_lcn
48
+ attr_reader :alcn
48
49
 
49
50
  # The level of the node. The level specifies how deep the node is in the hierarchy.
50
51
  attr_reader :level
@@ -76,7 +77,7 @@ module Webgen
76
77
  # found, the node is language neutral.
77
78
  def initialize(parent, path, cn, meta_info = {})
78
79
  @parent = parent
79
- @cn = cn.chomp('/').freeze
80
+ @cn = cn.freeze
80
81
  @children = []
81
82
  reinit(path, meta_info)
82
83
  init_rest
@@ -111,7 +112,7 @@ module Webgen
111
112
 
112
113
  # Return the node information hash which contains information for processing the node.
113
114
  def node_info
114
- tree.node_info[@absolute_lcn] ||= {}
115
+ tree.node_info[@alcn] ||= {}
115
116
  end
116
117
 
117
118
  # Check if the node is a directory.
@@ -161,8 +162,8 @@ module Webgen
161
162
  def changed?
162
163
  if_not_checked(:node) do
163
164
  flag(:dirty) if meta_info_changed? ||
164
- node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)} ||
165
- node_info[:used_meta_info_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].meta_info_changed?)}
165
+ node_info[:used_nodes].any? {|n| n != @alcn && (!tree[n] || tree[n].changed?)} ||
166
+ node_info[:used_meta_info_nodes].any? {|n| n != @alcn && (!tree[n] || tree[n].meta_info_changed?)}
166
167
  website.blackboard.dispatch_msg(:node_changed?, self) unless flagged?(:dirty)
167
168
  end
168
169
  flagged?(:dirty)
@@ -183,12 +184,12 @@ module Webgen
183
184
 
184
185
  # Return an informative representation of the node.
185
186
  def inspect
186
- "<##{self.class.name}: alcn=#{@absolute_lcn}>"
187
+ "<##{self.class.name}: alcn=#{@alcn}>"
187
188
  end
188
189
 
189
190
  # Return +true+ if the alcn matches the pattern. See File.fnmatch for useable patterns.
190
191
  def =~(pattern)
191
- File.fnmatch(pattern, @absolute_lcn, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
192
+ File.fnmatch(pattern, @alcn, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
192
193
  end
193
194
 
194
195
  # Sort nodes by using the meta info +sort_info+ (or +title+ if +sort_info+ is not set) of both
@@ -203,22 +204,16 @@ module Webgen
203
204
  self_so <=> other_so
204
205
  end
205
206
 
206
- # Construct the absolute (localized) canonical name by using the +parent+ node and +name+ (which
207
- # can be a cn or an lcn). The +type+ can be either <tt>:alcn</tt> or <tt>:acn</tt>.
208
- def self.absolute_name(parent, name, type)
209
- if parent.kind_of?(Tree)
210
- ''
211
- else
212
- parent = parent.parent while parent.is_fragment? # Handle fragment nodes specially in case they are nested
213
- parent_name = (type == :alcn ? parent.absolute_lcn : parent.absolute_cn)
214
- parent_name + (parent_name !~ /\/$/ && (parent.is_directory? || parent == parent.tree.dummy_root) ? '/' : '') + name
215
- end
216
- end
207
+ # This pattern is the the same as URI::UNSAFE except that the hash character (#) is also
208
+ # not escaped. This is needed sothat paths with fragments work correctly.
209
+ URL_UNSAFE_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}#{URI::PATTERN::RESERVED}#]") # :nodoc:
217
210
 
218
- # Construct an internal URL for the given +name+ which can be a acn/alcn/path.
219
- def self.url(name)
220
- url = URI::parse(name)
221
- url = URI::parse('webgen://webgen.localhost/') + url unless url.absolute?
211
+ # Construct an internal URL for the given +name+ which can be an acn/alcn/path. If the parameter
212
+ # +make_absolute+ is +true+, then a relative URL will be made absolute by prepending the special
213
+ # URL <tt>webgen:://webgen.localhost/</tt>.
214
+ def self.url(name, make_absolute = true)
215
+ url = URI::parse(URI::escape(name, URL_UNSAFE_PATTERN))
216
+ url = URI::parse('webgen://webgen.localhost/') + url unless url.absolute? || !make_absolute
222
217
  url
223
218
  end
224
219
 
@@ -235,7 +230,7 @@ module Webgen
235
230
  # exists, an unlocalized version of the node. If no such node is found either, +nil+ is
236
231
  # returned.
237
232
  def in_lang(lang)
238
- avail = @tree.node_access[:acn][@absolute_cn]
233
+ avail = @tree.node_access[:acn][@acn]
239
234
  avail.find do |n|
240
235
  n = n.parent while n.is_fragment?
241
236
  n.lang == lang
@@ -252,19 +247,23 @@ module Webgen
252
247
  # If the +path+ is an alcn and a node is found, it is returned. If the +path+ is an acn, the
253
248
  # correct localized node according to +lang+ is returned or if no such node exists but an
254
249
  # unlocalized version does, the unlocalized node is returned.
255
- def resolve(path, lang = nil)
256
- url = self.class.url(self.is_directory? ? File.join(@absolute_lcn, '/') : @absolute_lcn) + path
250
+ def resolve(path, lang = nil, use_passive_sources = true)
251
+ orig_path = path
252
+ url = self.class.url(@alcn) + self.class.url(path, false)
257
253
 
258
254
  path = url.path + (url.fragment.nil? ? '' : '#' + url.fragment)
259
- path.chomp!('/') unless path == '/'
260
255
  return nil if path =~ /^\/\.\./
261
256
 
262
257
  node = @tree[path, :alcn]
263
- if node && node.absolute_cn != path
264
- node
265
- else
266
- (node = @tree[path, :acn]) && node.in_lang(lang)
258
+ if !node || node.acn == path
259
+ (node = (@tree[path, :acn] || @tree[path + '/', :acn])) && (node = node.in_lang(lang))
260
+ end
261
+ if !node && use_passive_sources && !website.config['passive_sources'].empty?
262
+ nodes = website.blackboard.invoke(:create_nodes_from_paths, [path])
263
+ node = resolve(orig_path, lang, false)
264
+ node.node_info[:used_meta_info_nodes] += nodes.collect {|n| n.alcn} if node
267
265
  end
266
+ node
268
267
  end
269
268
 
270
269
  # Return the relative path to the given path +other+. The parameter +other+ can be a Node or a
@@ -295,7 +294,7 @@ module Webgen
295
294
  if !is_directory?
296
295
  self
297
296
  else
298
- key = [absolute_lcn, :index_node, lang]
297
+ key = [alcn, :index_node, lang]
299
298
  vcache = website.cache.volatile
300
299
  return vcache[key] if vcache.has_key?(key)
301
300
 
@@ -306,10 +305,10 @@ module Webgen
306
305
  index_node = resolve(index_path, lang)
307
306
  if index_node
308
307
  vcache[key] = index_node
309
- log(:info) { "Directory index path for <#{absolute_lcn}> => <#{index_node.absolute_lcn}>" }
308
+ log(:info) { "Directory index path for <#{alcn}> => <#{index_node.alcn}>" }
310
309
  elsif log_warning
311
310
  vcache[key] = self
312
- log(:warn) { "No directory index path found for directory <#{absolute_lcn}>" }
311
+ log(:warn) { "No directory index path found for directory <#{alcn}>" }
313
312
  end
314
313
  end
315
314
  vcache[key] || self
@@ -351,8 +350,8 @@ module Webgen
351
350
  # Do the rest of the initialization.
352
351
  def init_rest
353
352
  @lcn = Path.lcn(@cn, @lang)
354
- @absolute_cn = self.class.absolute_name(@parent, @cn, :acn)
355
- @absolute_lcn = self.class.absolute_name(@parent, @lcn, :alcn)
353
+ @acn = (@parent.kind_of?(Tree) ? '' : @parent.acn.sub(/#.*$/, '') + @cn)
354
+ @alcn = (@parent.kind_of?(Tree) ? '' : @parent.alcn.sub(/#.*$/, '') + @lcn)
356
355
 
357
356
  @level = -1
358
357
  @tree = @parent