webgen 1.0.0.beta3 → 1.0.0

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 (148) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +23 -1
  3. data/Rakefile +16 -77
  4. data/VERSION +1 -1
  5. data/bin/webgen +0 -0
  6. data/data/webgen/basic_website_template/ext/init.rb +3 -1
  7. data/data/webgen/basic_website_template/src/.gitignore +0 -0
  8. data/data/webgen/basic_website_template/webgen.config +1 -1
  9. data/data/webgen/bundle_template_files/info.yaml.erb +14 -2
  10. data/data/webgen/passive_sources/default.metainfo +10 -0
  11. data/data/webgen/passive_sources/templates/api.template +16 -2
  12. data/data/webgen/passive_sources/templates/feed.template +5 -5
  13. data/data/webgen/passive_sources/templates/sitemap.template +1 -1
  14. data/data/webgen/passive_sources/templates/tag.template +8 -4
  15. data/lib/webgen/blackboard.rb +21 -5
  16. data/lib/webgen/bundle/built-in-show-changes/info.yaml +17 -0
  17. data/lib/webgen/bundle/built-in-show-changes/init.rb +4 -5
  18. data/lib/webgen/bundle/built-in/info.yaml +1064 -0
  19. data/lib/webgen/bundle/built-in/init.rb +103 -136
  20. data/lib/webgen/bundle_loader.rb +82 -9
  21. data/lib/webgen/cli.rb +12 -8
  22. data/lib/webgen/cli/commands/create.rb +27 -0
  23. data/lib/webgen/cli/{create_bundle_command.rb → commands/create_bundle.rb} +2 -2
  24. data/lib/webgen/cli/{create_command.rb → commands/create_website.rb} +2 -2
  25. data/lib/webgen/cli/commands/generate.rb +66 -0
  26. data/lib/webgen/cli/{install_bundle_command.rb → commands/install.rb} +1 -1
  27. data/lib/webgen/cli/{show_command.rb → commands/show.rb} +6 -4
  28. data/lib/webgen/cli/{list_bundle_command.rb → commands/show_bundles.rb} +12 -15
  29. data/lib/webgen/cli/{show_config_command.rb → commands/show_config.rb} +34 -6
  30. data/lib/webgen/cli/{show_dependencies_command.rb → commands/show_dependencies.rb} +0 -0
  31. data/lib/webgen/cli/{show_extensions_command.rb → commands/show_extensions.rb} +1 -13
  32. data/lib/webgen/cli/{show_tree_command.rb → commands/show_tree.rb} +3 -0
  33. data/lib/webgen/cli/utils.rb +1 -1
  34. data/lib/webgen/configuration.rb +9 -11
  35. data/lib/webgen/content_processor/html_head.rb +3 -4
  36. data/lib/webgen/content_processor/rainpress.rb +21 -0
  37. data/lib/webgen/content_processor/sass.rb +8 -8
  38. data/lib/webgen/content_processor/tikz.rb +59 -16
  39. data/lib/webgen/item_tracker.rb +33 -12
  40. data/lib/webgen/item_tracker/missing_node.rb +5 -5
  41. data/lib/webgen/item_tracker/template_chain.rb +52 -0
  42. data/lib/webgen/misc/dummy_index.rb +78 -0
  43. data/lib/webgen/node.rb +1 -1
  44. data/lib/webgen/node_finder.rb +86 -141
  45. data/lib/webgen/page.rb +5 -5
  46. data/lib/webgen/path.rb +4 -1
  47. data/lib/webgen/path_handler.rb +25 -21
  48. data/lib/webgen/path_handler/api.rb +36 -3
  49. data/lib/webgen/path_handler/base.rb +20 -4
  50. data/lib/webgen/path_handler/feed.rb +6 -2
  51. data/lib/webgen/path_handler/meta_info.rb +4 -2
  52. data/lib/webgen/path_handler/page.rb +5 -7
  53. data/lib/webgen/path_handler/sitemap.rb +6 -1
  54. data/lib/webgen/path_handler/virtual.rb +6 -8
  55. data/lib/webgen/source/file_system.rb +2 -2
  56. data/lib/webgen/tag.rb +22 -18
  57. data/lib/webgen/tag/menu.rb +5 -5
  58. data/lib/webgen/test_helper.rb +18 -18
  59. data/lib/webgen/utils/external_command.rb +1 -1
  60. data/lib/webgen/utils/tag_parser.rb +1 -1
  61. data/lib/webgen/vendor/rainpress.rb +168 -0
  62. data/lib/webgen/version.rb +1 -1
  63. data/lib/webgen/website.rb +10 -10
  64. data/man/man1/webgen.1 +54 -23
  65. data/test/test_documentation.rb +27 -4
  66. data/test/webgen/cli/test_logger.rb +1 -1
  67. data/test/webgen/content_processor/test_blocks.rb +1 -1
  68. data/test/webgen/content_processor/test_builder.rb +3 -2
  69. data/test/webgen/content_processor/test_erb.rb +1 -1
  70. data/test/webgen/content_processor/test_erubis.rb +2 -2
  71. data/test/webgen/content_processor/test_fragments.rb +1 -1
  72. data/test/webgen/content_processor/test_haml.rb +2 -2
  73. data/test/webgen/content_processor/test_html_head.rb +5 -1
  74. data/test/webgen/content_processor/test_kramdown.rb +2 -2
  75. data/test/webgen/content_processor/test_maruku.rb +2 -2
  76. data/test/webgen/content_processor/test_r_discount.rb +2 -2
  77. data/test/webgen/content_processor/test_r_doc.rb +1 -1
  78. data/test/webgen/content_processor/test_rainpress.rb +19 -0
  79. data/test/webgen/content_processor/test_red_cloth.rb +2 -2
  80. data/test/webgen/content_processor/test_ruby.rb +1 -1
  81. data/test/webgen/content_processor/test_sass.rb +8 -6
  82. data/test/webgen/content_processor/test_scss.rb +3 -3
  83. data/test/webgen/content_processor/test_tags.rb +1 -1
  84. data/test/webgen/content_processor/test_tidy.rb +9 -1
  85. data/test/webgen/content_processor/test_tikz.rb +6 -3
  86. data/test/webgen/content_processor/test_xmllint.rb +9 -2
  87. data/test/webgen/destination/test_file_system.rb +4 -4
  88. data/test/webgen/item_tracker/test_file.rb +1 -1
  89. data/test/webgen/item_tracker/test_missing_node.rb +1 -1
  90. data/test/webgen/item_tracker/test_node_content.rb +1 -1
  91. data/test/webgen/item_tracker/test_node_meta_info.rb +1 -1
  92. data/test/webgen/item_tracker/test_nodes.rb +2 -4
  93. data/test/webgen/item_tracker/test_template_chain.rb +36 -0
  94. data/test/webgen/misc/test_dummy_index.rb +83 -0
  95. data/test/webgen/path_handler/test_api.rb +6 -46
  96. data/test/webgen/path_handler/test_base.rb +3 -2
  97. data/test/webgen/path_handler/test_copy.rb +1 -1
  98. data/test/webgen/path_handler/test_feed.rb +3 -4
  99. data/test/webgen/path_handler/test_meta_info.rb +1 -1
  100. data/test/webgen/path_handler/test_page.rb +1 -1
  101. data/test/webgen/path_handler/test_page_utils.rb +1 -1
  102. data/test/webgen/path_handler/test_sitemap.rb +3 -5
  103. data/test/webgen/path_handler/test_template.rb +1 -1
  104. data/test/webgen/path_handler/test_virtual.rb +1 -3
  105. data/test/webgen/source/test_file_system.rb +9 -4
  106. data/test/webgen/source/test_stacked.rb +1 -1
  107. data/test/webgen/source/test_tar_archive.rb +2 -2
  108. data/test/webgen/tag/test_breadcrumb_trail.rb +1 -1
  109. data/test/webgen/tag/test_coderay.rb +3 -2
  110. data/test/webgen/tag/test_date.rb +1 -1
  111. data/test/webgen/tag/test_execute_command.rb +1 -1
  112. data/test/webgen/tag/test_include_file.rb +1 -1
  113. data/test/webgen/tag/test_langbar.rb +1 -1
  114. data/test/webgen/tag/test_link.rb +1 -1
  115. data/test/webgen/tag/test_menu.rb +12 -30
  116. data/test/webgen/tag/test_meta_info.rb +1 -1
  117. data/test/webgen/tag/test_relocatable.rb +1 -1
  118. data/test/webgen/tag/test_tikz.rb +3 -2
  119. data/test/webgen/task/test_create_website.rb +2 -2
  120. data/test/webgen/test_blackboard.rb +11 -3
  121. data/test/webgen/test_bundle_loader.rb +26 -9
  122. data/test/webgen/test_cache.rb +1 -1
  123. data/test/webgen/test_cli.rb +2 -2
  124. data/test/webgen/test_configuration.rb +8 -9
  125. data/test/webgen/test_content_processor.rb +1 -1
  126. data/test/webgen/test_context.rb +1 -1
  127. data/test/webgen/test_core_ext.rb +1 -1
  128. data/test/webgen/test_destination.rb +1 -1
  129. data/test/webgen/test_error.rb +5 -5
  130. data/test/webgen/test_extension_manager.rb +1 -1
  131. data/test/webgen/test_item_tracker.rb +26 -5
  132. data/test/webgen/test_languages.rb +1 -1
  133. data/test/webgen/test_logger.rb +1 -1
  134. data/test/webgen/test_node.rb +1 -1
  135. data/test/webgen/test_node_finder.rb +2 -2
  136. data/test/webgen/test_page.rb +5 -5
  137. data/test/webgen/test_path.rb +8 -8
  138. data/test/webgen/test_rake_task.rb +1 -1
  139. data/test/webgen/test_source.rb +1 -1
  140. data/test/webgen/test_tag.rb +16 -24
  141. data/test/webgen/test_task.rb +1 -1
  142. data/test/webgen/test_tree.rb +1 -1
  143. data/test/webgen/test_utils.rb +1 -1
  144. data/test/webgen/test_website.rb +1 -1
  145. data/test/webgen/utils/test_tag_parser.rb +1 -1
  146. metadata +85 -105
  147. data/lib/webgen/cli/bundle_command.rb +0 -30
  148. data/lib/webgen/cli/generate_command.rb +0 -25
@@ -1,6 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'time'
4
+ require 'ostruct'
4
5
  require 'shellwords'
5
6
  require 'webgen/path_handler/base'
6
7
  require 'webgen/path_handler/page_utils'
@@ -36,11 +37,25 @@ module Webgen
36
37
 
37
38
  dir_node = create_directory(path, Webgen::Path.new(path.parent_path + path['dir_name'] + '/'), false)
38
39
 
40
+ api = OpenStruct.new
41
+ api.directory = dir_node
42
+ api.class_nodes = {}
43
+ api.file_nodes = {}
44
+
39
45
  rdoc.store.all_classes_and_modules.sort.each do |klass|
40
46
  klass_node = create_page_node_for_class(path, dir_node, klass, output_flag_file)
47
+ api.class_nodes[klass.full_name] = klass_node
48
+ klass_node.node_info[:api] = api
41
49
  klass.each_method {|method| create_fragment_node_for_method(path, klass_node, method)}
42
50
  end
43
51
 
52
+ rdoc.store.all_files.sort.each do |file|
53
+ next unless file.text?
54
+ file_node = create_page_node_for_file(path, dir_node, file, output_flag_file)
55
+ api.file_nodes[file.full_name] = file_node
56
+ file_node.node_info[:api] = api
57
+ end
58
+
44
59
  nil
45
60
  end
46
61
 
@@ -131,11 +146,11 @@ module Webgen
131
146
  create_directory(api_path, Webgen::Path.new(File.dirname(klass_path_str) + '/'))
132
147
 
133
148
  path = Webgen::Path.new(klass_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
134
- 'title' => "#{klass.type} #{klass.full_name}", 'api_class' => klass.full_name,
149
+ 'title' => "#{klass.type} #{klass.full_name}", 'api_class_name' => klass.full_name,
135
150
  'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
136
151
  node = @website.ext.path_handler.create_secondary_nodes(path).first
137
152
 
138
- node.node_info[:api_class_object] = klass
153
+ node.node_info[:rdoc_object] = klass
139
154
  @website.ext.item_tracker.add(node, :file, output_flag_file)
140
155
  add_link_definition(api_path, klass.full_name, node.alcn, klass.full_name)
141
156
 
@@ -156,9 +171,27 @@ module Webgen
156
171
  end
157
172
  protected :create_fragment_node_for_method
158
173
 
174
+ # Create a page node for the given file and return it.
175
+ def create_page_node_for_file(api_path, dir_node, file, output_flag_file)
176
+ file_path_str = file.http_url(dir_node.alcn)
177
+
178
+ create_directory(api_path, Webgen::Path.new(File.dirname(file_path_str) + '/'))
179
+
180
+ path = Webgen::Path.new(file_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
181
+ 'title' => "File #{file.full_name}", 'api_file_name' => file.full_name,
182
+ 'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
183
+ node = @website.ext.path_handler.create_secondary_nodes(path).first
184
+
185
+ node.node_info[:rdoc_object] = file
186
+ @website.ext.item_tracker.add(node, :file, output_flag_file)
187
+
188
+ node
189
+ end
190
+ protected :create_page_node_for_file
191
+
159
192
  # Add a link definition for the given node.
160
193
  def add_link_definition(api_path, link_name, url, title)
161
- link = if api_path['prefix_for_link_defs']
194
+ link = if api_path['prefix_link_defs']
162
195
  "#{api_path['api_name']}:#{link_name}"
163
196
  else
164
197
  link_name
@@ -32,6 +32,15 @@ module Webgen
32
32
  # not specify another Node class.
33
33
  class Node < Webgen::Node
34
34
 
35
+ # Return the absolute URL of this node.
36
+ #
37
+ # This method uses the configuration option 'website.base_url' for constructing the absolute
38
+ # URL.
39
+ def url
40
+ node_url = Webgen::Path.url(dest_path, false)
41
+ node_url.absolute? ? node_url : File.join(tree.website.config['website.base_url'], dest_path)
42
+ end
43
+
35
44
  # Does exactly the same as Node#route_to but also automatically adds the necessary item
36
45
  # tracking information.
37
46
  def route_to(node, lang = @lang)
@@ -66,12 +75,19 @@ module Webgen
66
75
  []
67
76
  end
68
77
 
69
- # Create a node from +path+, if possible, yield the fully initialized node if a block is given
70
- # and return it.
78
+ # Create a node from +path+, if possible, and yield the fully initialized node if a block is
79
+ # given as well as return it.
80
+ #
81
+ # Note that the block should be used when the newly created node need to be modified because
82
+ # the returned node can also be a reused node (in case the information in the supplied path
83
+ # applies uniquely to an already existing node)!
71
84
  #
72
85
  # The node class to be used for the to-be-created node can be specified via
73
- # `path.meta_info['node_class']`. If this node processing information is not set, the
74
- # Base::Node class is used.
86
+ # `path.meta_info['node_class']`. This is normally used by specific path handlers to provide
87
+ # custom node classes.
88
+ #
89
+ # The default base node class can be changed by setting `path.meta_info['base_node_class']`.
90
+ # Note that the `node_class` key takes precedence over this key!
75
91
  #
76
92
  # The parent node under which the new node should be created can optionally be specified via
77
93
  # 'path.meta_info['parent_alcn']'. This node processing information has to be set to the alcn
@@ -34,7 +34,7 @@ module Webgen
34
34
 
35
35
  # Return the feed link URL for this feed node.
36
36
  def feed_link
37
- Webgen::Path.url(File.join(self['site_url'], tree[self['link']].dest_path), false)
37
+ tree[self['link']].url
38
38
  end
39
39
 
40
40
  # Return the content of an +entry+ (a Node object) of this feed node.
@@ -52,7 +52,7 @@ module Webgen
52
52
 
53
53
 
54
54
  # The mandatory keys that need to be set in a feed file.
55
- MANDATORY_INFOS = %W[site_url author entries]
55
+ MANDATORY_INFOS = %W[author entries]
56
56
 
57
57
  # Create the feed nodes.
58
58
  def create_nodes(path, blocks)
@@ -60,6 +60,10 @@ module Webgen
60
60
  raise Webgen::NodeCreationError.new("At least one of #{MANDATORY_INFOS.join('/')} is missing",
61
61
  "path_handler.feed", path)
62
62
  end
63
+ if @website.config['website.base_url'].empty?
64
+ raise Webgen::NodeCreationError.new("The configuration option 'website.base_url' needs to be set",
65
+ "path_handler.feed", path)
66
+ end
63
67
  if !['atom', 'rss'].include?(path['version'])
64
68
  raise Webgen::NodeCreationError.new("Invalid version '#{path['version']}' for feed path specified, only atom and rss allowed",
65
69
  "path_handler.feed", path)
@@ -19,8 +19,10 @@ module Webgen
19
19
  # :after_node_created hooks so that it can apply the meta information.
20
20
  def initialize(website)
21
21
  super
22
- @website.blackboard.add_listener(:apply_meta_info_to_path, &method(:apply_meta_info_to_path))
23
- @website.blackboard.add_listener(:after_node_created, &method(:after_node_created))
22
+ @website.blackboard.add_listener(:apply_meta_info_to_path, 'path_handler.meta_info',
23
+ &method(:apply_meta_info_to_path))
24
+ @website.blackboard.add_listener(:after_node_created, 'path_handler.meta_info',
25
+ :before => 'item_tracker.node_meta_info', &method(:after_node_created))
24
26
  @paths = []
25
27
  @alcns = []
26
28
  end
@@ -21,13 +21,11 @@ module Webgen
21
21
  end
22
22
  end
23
23
 
24
- # Render the block +block_name+ of the given +node+.
25
- #
26
- # If the parameter +chain+ (an array of template nodes) is not set, the default template chain
27
- # for the given +node+ is used.
28
- def content(node, block_name = 'content', chain = node.template_chain)
29
- chain << node
30
- chain.first.render_block(block_name, Webgen::Context.new(@website, :chain => chain)).content
24
+ # Render the content of the given page +node+.
25
+ def content(node)
26
+ @website.ext.item_tracker.add(node, :template_chain, node)
27
+ chain = node.template_chain << node
28
+ chain.first.render_block('content', Webgen::Context.new(@website, :chain => chain)).content
31
29
  end
32
30
 
33
31
  end
@@ -28,7 +28,7 @@ module Webgen
28
28
 
29
29
 
30
30
  # The mandatory keys that need to be set in a sitemap file.
31
- MANDATORY_INFOS = %W[site_url entries]
31
+ MANDATORY_INFOS = %W[entries]
32
32
 
33
33
  # Create an XML sitemap from +path+.
34
34
  def create_nodes(path, blocks)
@@ -37,6 +37,11 @@ module Webgen
37
37
  "path_handler.sitemap", path)
38
38
  end
39
39
 
40
+ if @website.config['website.base_url'].empty?
41
+ raise Webgen::NodeCreationError.new("The configuration option 'website.base_url' needs to be set",
42
+ "path_handler.sitemap", path)
43
+ end
44
+
40
45
  path.ext = 'xml'
41
46
  path['node_class'] = Node.to_s
42
47
  create_node(path) do |node|
@@ -20,9 +20,8 @@ module Webgen
20
20
 
21
21
  # Create all virtual nodes which are specified in +path+.
22
22
  def create_nodes(path, blocks)
23
- nodes = []
24
23
  if path.meta_info.delete(:virtual)
25
- nodes << create_node(path)
24
+ create_node(path)
26
25
  else
27
26
  read_entries(blocks) do |key, meta_info|
28
27
  meta_info['modified_at'] = path.meta_info['modified_at']
@@ -44,16 +43,15 @@ module Webgen
44
43
 
45
44
  if key =~ /\/$/
46
45
  entry_path['handler'] = 'directory'
47
- nodes << @website.ext.path_handler.create_secondary_nodes(entry_path)
46
+ @website.ext.path_handler.create_secondary_nodes(entry_path)
48
47
  else
49
48
  entry_path[:virtual] = true
50
49
  entry_path['handler'] = 'virtual'
51
- nodes << @website.ext.path_handler.create_secondary_nodes(entry_path)
50
+ @website.ext.path_handler.create_secondary_nodes(entry_path)
52
51
  end
53
52
  end
54
- end
55
- nodes.flatten.compact.each do |node|
56
- node.node_info[:path] = path
53
+
54
+ nil
57
55
  end
58
56
  end
59
57
 
@@ -67,7 +65,7 @@ module Webgen
67
65
  blocks.each do |name, content|
68
66
  begin
69
67
  data = YAML::load(content)
70
- rescue RuntimeError, ArgumentError, SyntaxError => e
68
+ rescue RuntimeError, ArgumentError, SyntaxError, YAML::SyntaxError => e
71
69
  raise RuntimeError, "Problem parsing block '#{name}' (it needs to contain a YAML hash): #{e.message}", e.backtrace
72
70
  end
73
71
  raise "Structure of block '#{name}' is invalid, it has to be a Hash" unless data.kind_of?(Hash)
@@ -20,7 +20,7 @@ module Webgen
20
20
 
21
21
  # Create a new file system source for the root path +root+ using the provided +glob+. If
22
22
  # +root+ is not an absolute path, the website directory will be prepended.
23
- def initialize(website, root, glob = '**/*')
23
+ def initialize(website, root, glob = '{*,**/*}')
24
24
  @root = File.absolute_path(root, website.directory)
25
25
  @glob = glob
26
26
  end
@@ -28,7 +28,7 @@ module Webgen
28
28
  # Return all paths under the root path which match the glob.
29
29
  def paths
30
30
  @paths ||= Dir.glob(File.join(@root, @glob), File::FNM_DOTMATCH|File::FNM_CASEFOLD).collect do |f|
31
- next unless File.exists?(f) # handle invalid links
31
+ next unless File.exists?(f) && f !~ /\/\.\.$/ # handle invalid links
32
32
  temp = Pathname.new(f.sub(/^#{Regexp.escape(@root)}\/?/, '/')).cleanpath.to_s
33
33
  temp += '/' if File.directory?(f) && temp[-1] != ?/
34
34
  Path.new(temp, 'modified_at' => File.mtime(f)) {|mode| File.open(f, mode)}
@@ -18,16 +18,16 @@ module Webgen
18
18
  #
19
19
  # A tag object only needs to respond to the method +call+ which needs to accept three parameters:
20
20
  #
21
- # [tag]: The name of the tag which should be processed (useful for tag objects which can process
22
- # different tags).
21
+ # [tag] The name of the tag which should be processed (useful for tag objects which can process
22
+ # different tags).
23
23
  #
24
- # [body]: Holds the body value for the tag if any.
24
+ # [body] Holds the body value for the tag if any.
25
25
  #
26
- # [context]: Holds all relevant information for processing -- have a look at the Webgen::Context
27
- # class to see what is available. The special key :config is set to an
28
- # Webgen::Configuration object that should be used to retrieve configuration option
29
- # values because the values might be changed due to options set directly via the tag
30
- # syntax.
26
+ # [context] Holds all relevant information for processing -- have a look at the Webgen::Context
27
+ # class to see what is available. The special key :config is set to an
28
+ # Webgen::Configuration object that should be used to retrieve configuration option
29
+ # values because the values might be changed due to options set directly via the tag
30
+ # syntax.
31
31
  #
32
32
  # The method has to return the result of the processing and, optionally, a boolean value
33
33
  # specifying if the result should further be processed (ie. webgen tags replaced).
@@ -76,11 +76,12 @@ module Webgen
76
76
  # If the template node cannot be found, an empty string is returned.
77
77
  def self.render_tag_template(context, tag)
78
78
  path = context[:config]["tag.#{tag}.template"]
79
- template_node = context.ref_node.resolve(path, context.dest_node.lang, true)
80
- if template_node
79
+ if path && template_node = context.ref_node.resolve(path, context.dest_node.lang, true)
80
+ context.website.ext.item_tracker.add(context.dest_node, :template_chain, template_node)
81
81
  context.render_block(:name => "tag.#{tag}", :node => 'first',
82
82
  :chain => [*template_node.template_chain, template_node, context.content_node])
83
83
  else
84
+ context.website.logger.warn { "Template node '#{path}' for tag '#{tag}' not found" }
84
85
  ''
85
86
  end
86
87
  end
@@ -88,7 +89,7 @@ module Webgen
88
89
 
89
90
  def initialize(website) # :nodoc:
90
91
  super()
91
- website.blackboard.add_listener(:website_initialized, self) do
92
+ website.blackboard.add_listener(:website_initialized, 'tag') do
92
93
  @parser = Webgen::Utils::TagParser.new(website.config['tag.prefix'])
93
94
  end
94
95
  end
@@ -156,9 +157,12 @@ module Webgen
156
157
  result = ''
157
158
  tdata = tag_data(tag, context)
158
159
  if !tdata.nil?
159
- context[:config] = create_config(tag, params, tdata, context)
160
+ context = context.clone(:config => create_config(tag, params, tdata, context))
160
161
  result, process_output = tdata.object.call(tag, body, context)
161
- result = context.website.ext.content_processor.call('tags', context.clone(:content => result)).content if process_output
162
+ if process_output
163
+ context.content = result
164
+ result = context.website.ext.content_processor.call('tags', context).content
165
+ end
162
166
  else
163
167
  raise Webgen::RenderError.new("No tag processor for '#{tag}' found", 'tag',
164
168
  context.dest_node, context.ref_node)
@@ -186,7 +190,7 @@ module Webgen
186
190
  def create_config(tag, params, tdata, context)
187
191
  values = case params
188
192
  when Hash then values_from_hash(tag, params, tdata, context)
189
- when String then values_from_string(tag, params, tdata, context)
193
+ when String, Array then values_for_default_mandatory(tag, params, tdata, context)
190
194
  when NilClass then {}
191
195
  else
192
196
  raise Webgen::RenderError.new("Invalid parameter type (#{params.class})",
@@ -221,16 +225,16 @@ module Webgen
221
225
  end
222
226
 
223
227
  # Return a hash containing valid configuration options by setting the default mandatory
224
- # parameter for +tag+ to +str+.
225
- def values_from_string(tag, str, tdata, context)
228
+ # parameter for +tag+ to +value+.
229
+ def values_for_default_mandatory(tag, value, tdata, context)
226
230
  if tdata.mandatory.first.nil?
227
231
  context.website.logger.error do
228
232
  ["No default mandatory option specified for tag '#{tag}' but set in <#{context.ref_node}>",
229
- "Use the {key: value} syntax for assigning the value '#{str}' to the intended tag option!"]
233
+ "Use the {key: value} syntax for assigning the value '#{value}' to the intended tag option!"]
230
234
  end
231
235
  {}
232
236
  else
233
- {tdata.mandatory.first => str}
237
+ {tdata.mandatory.first => value}
234
238
  end
235
239
  end
236
240
 
@@ -27,11 +27,11 @@ module Webgen
27
27
  # Return style information (node is selected, ...) and a link from +dest_node+ to +node+.
28
28
  #
29
29
  # This method can be used in a menu template.
30
- def self.menu_item_details(dest_node, node, lang, level, has_submenu)
31
- styles = ['webgen-menu-level' + level.to_s]
32
- styles << 'webgen-menu-submenu' if has_submenu
33
- styles << 'webgen-menu-submenu-inhierarchy' if node.is_ancestor_of?(dest_node)
34
- styles << 'webgen-menu-item-selected' if node == dest_node
30
+ def self.menu_item_details(dest_node, node, lang, level, has_submenu, config)
31
+ styles = [config['tag.menu.item_level_class'] + level.to_s]
32
+ styles << config['tag.menu.item_submenu_class'] if has_submenu
33
+ styles << config['tag.menu.item_submenu_inhierarchy_class'] if node.is_ancestor_of?(dest_node)
34
+ styles << config['tag.menu.item_selected_class'] if node == dest_node
35
35
  style = "class=\"#{styles.join(' ')}\"" if styles.length > 0
36
36
 
37
37
  link = dest_node.link_to(node, lang)
@@ -129,30 +129,30 @@ module Webgen
129
129
  # /dir2/ 'dir2' proxy_path='index.html'
130
130
  # /dir2/index.en.html 'index en' routed_title='routed en' link_attrs={'class' => 'help'}
131
131
  # /dir2/index.de.html 'index de' routed_title='routed de'
132
- def setup_default_nodes(tree)
133
- root = Webgen::Node.new(tree.dummy_root, '/', '/')
132
+ def setup_default_nodes(tree, klass = Webgen::Node)
133
+ root = klass.new(tree.dummy_root, '/', '/')
134
134
 
135
- file_en = Webgen::Node.new(root, 'file.html', '/file.en.html', {'lang' => 'en', 'title' => 'file en', 'sort_info' => 3})
136
- frag_en = Webgen::Node.new(file_en, '#frag', '/file.en.html#frag', {'title' => 'frag'})
137
- Webgen::Node.new(frag_en, '#nested', '/file.en.html#nested', {'title' => 'fragnested', 'routing_path' => '/routed.html'})
138
- file_de = Webgen::Node.new(root, 'file.html', '/file.de.html', {'lang' => 'de', 'title' => 'file de', 'sort_info' => 5})
139
- Webgen::Node.new(file_de, '#frag', '/file.de.html#frag', {'title' => 'frag'})
135
+ file_en = klass.new(root, 'file.html', '/file.en.html', {'lang' => 'en', 'title' => 'file en', 'sort_info' => 3})
136
+ frag_en = klass.new(file_en, '#frag', '/file.en.html#frag', {'title' => 'frag'})
137
+ klass.new(frag_en, '#nested', '/file.en.html#nested', {'title' => 'fragnested', 'routing_path' => '/routed.html'})
138
+ file_de = klass.new(root, 'file.html', '/file.de.html', {'lang' => 'de', 'title' => 'file de', 'sort_info' => 5})
139
+ klass.new(file_de, '#frag', '/file.de.html#frag', {'title' => 'frag'})
140
140
 
141
- Webgen::Node.new(root, 'other.html', '/other.html', {'title' => 'other'})
142
- Webgen::Node.new(root, 'other.html', '/other.en.html', {'lang' => 'en', 'title' => 'other en'})
141
+ klass.new(root, 'other.html', '/other.html', {'title' => 'other'})
142
+ klass.new(root, 'other.html', '/other.en.html', {'lang' => 'en', 'title' => 'other en'})
143
143
 
144
- Webgen::Node.new(root, 'german.html', '/german.other.html', {'title' => 'german', 'lang' => 'de'})
144
+ klass.new(root, 'german.html', '/german.other.html', {'title' => 'german', 'lang' => 'de'})
145
145
 
146
- dir = Webgen::Node.new(root, 'dir/', '/dir/', {'title' => 'dir'})
147
- dir_file = Webgen::Node.new(dir, 'subfile.html', '/dir/subfile.html', {'title' => 'subfile'})
148
- Webgen::Node.new(dir_file, '#frag', '/dir/subfile.html#frag', {'title' => 'frag'})
149
- dir_dir = Webgen::Node.new(dir, 'dir/' , '/dir/dir/', {'title' => 'dir'})
150
- Webgen::Node.new(dir_dir, 'file.html', '/dir/dir/file.html', {'title' => 'file'})
146
+ dir = klass.new(root, 'dir/', '/dir/', {'title' => 'dir'})
147
+ dir_file = klass.new(dir, 'subfile.html', '/dir/subfile.html', {'title' => 'subfile'})
148
+ klass.new(dir_file, '#frag', '/dir/subfile.html#frag', {'title' => 'frag'})
149
+ dir_dir = klass.new(dir, 'dir/' , '/dir/dir/', {'title' => 'dir'})
150
+ klass.new(dir_dir, 'file.html', '/dir/dir/file.html', {'title' => 'file'})
151
151
 
152
- dir2 = Webgen::Node.new(root, 'dir2/', '/dir2/', {'proxy_path' => 'index.html', 'title' => 'dir2'})
153
- Webgen::Node.new(dir2, 'index.html', '/dir2/index.en.html',
152
+ dir2 = klass.new(root, 'dir2/', '/dir2/', {'proxy_path' => 'index.html', 'title' => 'dir2'})
153
+ klass.new(dir2, 'index.html', '/dir2/index.en.html',
154
154
  {'lang' => 'en', 'routed_title' => 'routed', 'title' => 'index en', 'link_attrs' => {'class'=>'help'}})
155
- Webgen::Node.new(dir2, 'index.html', '/dir2/index.de.html',
155
+ klass.new(dir2, 'index.html', '/dir2/index.de.html',
156
156
  {'lang' => 'de', 'routed_title' => 'routed de', 'title' => 'index de'})
157
157
  end
158
158
 
@@ -13,7 +13,7 @@ module Webgen
13
13
  #
14
14
  # This just checks if the exit status is zero.
15
15
  def self.ensure_available!(cmd, *args)
16
- status = systemu([cmd, *args], 'stdout' => '')
16
+ status = systemu([cmd, *args], 'stdout' => '', 'stdin' => '')
17
17
  raise Webgen::CommandNotFoundError.new(cmd) if status.exitstatus != 0
18
18
  end
19
19
 
@@ -114,7 +114,7 @@ module Webgen
114
114
  # Parse the parameter string and return the result.
115
115
  def parse_params(param_string, tag)
116
116
  YAML::load("--- #{param_string}")
117
- rescue ArgumentError, SyntaxError => e
117
+ rescue ArgumentError, SyntaxError, YAML::SyntaxError => e
118
118
  raise Error.new("Could not parse parameter string '#{param_string}' for tag '#{tag}': #{e.message}")
119
119
  end
120
120
 
@@ -0,0 +1,168 @@
1
+ # == Information
2
+ #
3
+ # This is the main class of Rainpress, create an instance of it to compress
4
+ # your CSS-styles.
5
+ #
6
+ # Author:: Uwe L. Korn <uwelk@xhochy.org>
7
+ #
8
+ # <b>Options:</b>
9
+ #
10
+ # * <tt>:comments</tt> - if set to false, comments will not be removed
11
+ # * <tt>:newlines</tt> - if set to false, newlines will not be removed
12
+ # * <tt>:spaces</tt> - if set to false, spaces will not be removed
13
+ # * <tt>:colors</tt> - if set to false, colors will not be modified
14
+ # * <tt>:misc</tt> - if set to false, miscellaneous compression parts will be skipped
15
+ class Rainpress
16
+ # Quick-compress the styles.
17
+ # This eliminates the need to create an instance of the class
18
+ def self.compress(style, options = {})
19
+ self.new(style, options).compress!
20
+ end
21
+
22
+ def initialize(style, opts = {})
23
+ @style = style
24
+ @opts = {
25
+ :comments => true,
26
+ :newlines => true,
27
+ :spaces => true,
28
+ :colors => true,
29
+ :misc => true
30
+ }
31
+ @opts.merge! opts
32
+ end
33
+
34
+ # Run the compressions and return the newly compressed text
35
+ def compress!
36
+ remove_comments! if @opts[:comments]
37
+ remove_newlines! if @opts[:newlines]
38
+ remove_spaces! if @opts[:spaces]
39
+ shorten_colors! if @opts[:colors]
40
+ do_misc! if @opts[:misc]
41
+ @style
42
+ end
43
+
44
+ # Remove all comments out of the CSS-Document
45
+ #
46
+ # Only /* text */ comments are supported.
47
+ # Attention: If you are doing css hacks for IE using the comment tricks,
48
+ # they will be removed using this function. Please consider for IE css style
49
+ # corrections the usage of conditionals comments in your (X)HTML document.
50
+ def remove_comments!
51
+ input = @style
52
+ @style = ''
53
+
54
+ while input.length > 0 do
55
+ pos = input.index("/*");
56
+
57
+ # No more comments
58
+ if pos == nil
59
+ @style += input
60
+ input = '';
61
+ else # Comment beginning at pos
62
+ @style += input[0..(pos-1)] if pos > 0 # only append text if there is some
63
+ input = input[(pos+2)..-1]
64
+ # Comment ending at pos
65
+ pos = input.index("*/")
66
+ input = input[(pos+2)..-1]
67
+ end
68
+ end
69
+ end
70
+
71
+ # Remove all newline characters
72
+ #
73
+ # We take care of Windows(\r\n), Unix(\n) and Mac(\r) newlines.
74
+ def remove_newlines!
75
+ @style.gsub! /\n|\r/, ''
76
+ end
77
+
78
+ # Remove unneeded spaces
79
+ #
80
+ # 1. Turn mutiple spaces into a single
81
+ # 2. Remove spaces around ;:{},
82
+ # 3. Remove tabs
83
+ def remove_spaces!
84
+ @style.gsub! /\s*(\s|;|:|\}|\{|,)\s*/, '\1'
85
+ @style.gsub! "\t", ''
86
+ end
87
+
88
+ # Replace color values with their shorter equivalent
89
+ #
90
+ # 1. Turn rgb(,,)-colors into #-values
91
+ # 2. Shorten #AABBCC down to #ABC
92
+ # 3. Replace names with their shorter hex-equivalent
93
+ # * white -> #fff
94
+ # * black -> #000
95
+ # 4. Replace #-values with their shorter name
96
+ # * #f00 -> red
97
+ def shorten_colors!
98
+ # rgb(50,101,152) to #326598
99
+ @style.gsub! /rgb\s*\(\s*([0-9,\s]+)\s*\)/ do |match|
100
+ out = '#'
101
+ $1.split(',').each do |num|
102
+ out += '0' if num.to_i < 16
103
+ out += num.to_i.to_s(16) # convert to hex
104
+ end
105
+ out
106
+ end
107
+ # Convert #AABBCC to #ABC, keep if preceed by a '='
108
+ @style.gsub! /([^\"'=\s])(\s*)#([\da-f])\3([\da-f])\4([\da-f])\5/i, '\1#\3\4\5'
109
+
110
+ # At the moment we assume that colours only appear before ';' or '}' and
111
+ # after a ':', if there could be an occurence of a color before or after
112
+ # an other character, submit either a bug report or, better, a patch that
113
+ # enables Rainpress to take care of this.
114
+
115
+ # shorten several names to numbers
116
+ ## shorten white -> #fff
117
+ @style.gsub! /:\s*white\s*(;|\})/, ':#fff\1'
118
+
119
+ ## shorten black -> #000
120
+ @style.gsub! /:\s*black\s*(;|\})/, ':#000\1'
121
+
122
+ # shotern several numbers to names
123
+ ## shorten #f00 or #ff0000 -> red
124
+ @style.gsub! /:\s*#f{1,2}0{2,4}(;|\})/i, ':red\1'
125
+ end
126
+
127
+ # Do miscellaneous compression methods on the style.
128
+ def do_misc!
129
+ # Replace 0(pt,px,em,%) with 0 but only when preceded by : or a white-space
130
+ @style.gsub! /([\s:]+)(0)(px|em|%|in|cm|mm|pc|pt|ex)/i, '\1\2'
131
+
132
+ # Replace :0 0 0 0(;|}) with :0(;|})
133
+ @style.gsub! /:0 0 0 0(;|\})/, ':0\1'
134
+
135
+ # Replace :0 0 0(;|}) with :0(;|})
136
+ @style.gsub! /:0 0 0(;|\})/, ':0\1'
137
+
138
+ # Replace :0 0(;|}) with :0(;|})
139
+ @style.gsub! /:0 0(;|\})/, ':0\1'
140
+
141
+ # Replace background-position:0; with background-position:0 0;
142
+ @style.gsub! 'background-position:0;', 'background-position:0 0;'
143
+
144
+ # Replace 0.6 to .6, but only when preceded by : or a white-space
145
+ @style.gsub! /[:\s]0+\.(\d+)/ do |match|
146
+ match.sub '0', '' # only first '0' !!
147
+ end
148
+
149
+ # Replace multiple ';' with a single ';'
150
+ @style.gsub! /[;]+/, ';'
151
+
152
+ # Replace ;} with }
153
+ @style.gsub! ';}', '}'
154
+
155
+ # Replace font-weight:normal; with 400
156
+ @style.gsub! /font-weight[\s]*:[\s]*normal[\s]*(;|\})/i,'font-weight:400\1'
157
+ @style.gsub! /font[\s]*:[\s]*normal[\s;\}]*/ do |match|
158
+ match.sub 'normal', '400'
159
+ end
160
+
161
+ # Replace font-weight:bold; with 700
162
+ @style.gsub! /font-weight[\s]*:[\s]*bold[\s]*(;|\})/,'font-weight:700\1'
163
+ @style.gsub! /font[\s]*:[\s]*bold[\s;\}]*/ do |match|
164
+ match.sub 'bold', '700'
165
+ end
166
+ end
167
+
168
+ end