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.
- checksums.yaml +7 -0
- data/COPYING +23 -1
- data/Rakefile +16 -77
- data/VERSION +1 -1
- data/bin/webgen +0 -0
- data/data/webgen/basic_website_template/ext/init.rb +3 -1
- data/data/webgen/basic_website_template/src/.gitignore +0 -0
- data/data/webgen/basic_website_template/webgen.config +1 -1
- data/data/webgen/bundle_template_files/info.yaml.erb +14 -2
- data/data/webgen/passive_sources/default.metainfo +10 -0
- data/data/webgen/passive_sources/templates/api.template +16 -2
- data/data/webgen/passive_sources/templates/feed.template +5 -5
- data/data/webgen/passive_sources/templates/sitemap.template +1 -1
- data/data/webgen/passive_sources/templates/tag.template +8 -4
- data/lib/webgen/blackboard.rb +21 -5
- data/lib/webgen/bundle/built-in-show-changes/info.yaml +17 -0
- data/lib/webgen/bundle/built-in-show-changes/init.rb +4 -5
- data/lib/webgen/bundle/built-in/info.yaml +1064 -0
- data/lib/webgen/bundle/built-in/init.rb +103 -136
- data/lib/webgen/bundle_loader.rb +82 -9
- data/lib/webgen/cli.rb +12 -8
- data/lib/webgen/cli/commands/create.rb +27 -0
- data/lib/webgen/cli/{create_bundle_command.rb → commands/create_bundle.rb} +2 -2
- data/lib/webgen/cli/{create_command.rb → commands/create_website.rb} +2 -2
- data/lib/webgen/cli/commands/generate.rb +66 -0
- data/lib/webgen/cli/{install_bundle_command.rb → commands/install.rb} +1 -1
- data/lib/webgen/cli/{show_command.rb → commands/show.rb} +6 -4
- data/lib/webgen/cli/{list_bundle_command.rb → commands/show_bundles.rb} +12 -15
- data/lib/webgen/cli/{show_config_command.rb → commands/show_config.rb} +34 -6
- data/lib/webgen/cli/{show_dependencies_command.rb → commands/show_dependencies.rb} +0 -0
- data/lib/webgen/cli/{show_extensions_command.rb → commands/show_extensions.rb} +1 -13
- data/lib/webgen/cli/{show_tree_command.rb → commands/show_tree.rb} +3 -0
- data/lib/webgen/cli/utils.rb +1 -1
- data/lib/webgen/configuration.rb +9 -11
- data/lib/webgen/content_processor/html_head.rb +3 -4
- data/lib/webgen/content_processor/rainpress.rb +21 -0
- data/lib/webgen/content_processor/sass.rb +8 -8
- data/lib/webgen/content_processor/tikz.rb +59 -16
- data/lib/webgen/item_tracker.rb +33 -12
- data/lib/webgen/item_tracker/missing_node.rb +5 -5
- data/lib/webgen/item_tracker/template_chain.rb +52 -0
- data/lib/webgen/misc/dummy_index.rb +78 -0
- data/lib/webgen/node.rb +1 -1
- data/lib/webgen/node_finder.rb +86 -141
- data/lib/webgen/page.rb +5 -5
- data/lib/webgen/path.rb +4 -1
- data/lib/webgen/path_handler.rb +25 -21
- data/lib/webgen/path_handler/api.rb +36 -3
- data/lib/webgen/path_handler/base.rb +20 -4
- data/lib/webgen/path_handler/feed.rb +6 -2
- data/lib/webgen/path_handler/meta_info.rb +4 -2
- data/lib/webgen/path_handler/page.rb +5 -7
- data/lib/webgen/path_handler/sitemap.rb +6 -1
- data/lib/webgen/path_handler/virtual.rb +6 -8
- data/lib/webgen/source/file_system.rb +2 -2
- data/lib/webgen/tag.rb +22 -18
- data/lib/webgen/tag/menu.rb +5 -5
- data/lib/webgen/test_helper.rb +18 -18
- data/lib/webgen/utils/external_command.rb +1 -1
- data/lib/webgen/utils/tag_parser.rb +1 -1
- data/lib/webgen/vendor/rainpress.rb +168 -0
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/website.rb +10 -10
- data/man/man1/webgen.1 +54 -23
- data/test/test_documentation.rb +27 -4
- data/test/webgen/cli/test_logger.rb +1 -1
- data/test/webgen/content_processor/test_blocks.rb +1 -1
- data/test/webgen/content_processor/test_builder.rb +3 -2
- data/test/webgen/content_processor/test_erb.rb +1 -1
- data/test/webgen/content_processor/test_erubis.rb +2 -2
- data/test/webgen/content_processor/test_fragments.rb +1 -1
- data/test/webgen/content_processor/test_haml.rb +2 -2
- data/test/webgen/content_processor/test_html_head.rb +5 -1
- data/test/webgen/content_processor/test_kramdown.rb +2 -2
- data/test/webgen/content_processor/test_maruku.rb +2 -2
- data/test/webgen/content_processor/test_r_discount.rb +2 -2
- data/test/webgen/content_processor/test_r_doc.rb +1 -1
- data/test/webgen/content_processor/test_rainpress.rb +19 -0
- data/test/webgen/content_processor/test_red_cloth.rb +2 -2
- data/test/webgen/content_processor/test_ruby.rb +1 -1
- data/test/webgen/content_processor/test_sass.rb +8 -6
- data/test/webgen/content_processor/test_scss.rb +3 -3
- data/test/webgen/content_processor/test_tags.rb +1 -1
- data/test/webgen/content_processor/test_tidy.rb +9 -1
- data/test/webgen/content_processor/test_tikz.rb +6 -3
- data/test/webgen/content_processor/test_xmllint.rb +9 -2
- data/test/webgen/destination/test_file_system.rb +4 -4
- data/test/webgen/item_tracker/test_file.rb +1 -1
- data/test/webgen/item_tracker/test_missing_node.rb +1 -1
- data/test/webgen/item_tracker/test_node_content.rb +1 -1
- data/test/webgen/item_tracker/test_node_meta_info.rb +1 -1
- data/test/webgen/item_tracker/test_nodes.rb +2 -4
- data/test/webgen/item_tracker/test_template_chain.rb +36 -0
- data/test/webgen/misc/test_dummy_index.rb +83 -0
- data/test/webgen/path_handler/test_api.rb +6 -46
- data/test/webgen/path_handler/test_base.rb +3 -2
- data/test/webgen/path_handler/test_copy.rb +1 -1
- data/test/webgen/path_handler/test_feed.rb +3 -4
- data/test/webgen/path_handler/test_meta_info.rb +1 -1
- data/test/webgen/path_handler/test_page.rb +1 -1
- data/test/webgen/path_handler/test_page_utils.rb +1 -1
- data/test/webgen/path_handler/test_sitemap.rb +3 -5
- data/test/webgen/path_handler/test_template.rb +1 -1
- data/test/webgen/path_handler/test_virtual.rb +1 -3
- data/test/webgen/source/test_file_system.rb +9 -4
- data/test/webgen/source/test_stacked.rb +1 -1
- data/test/webgen/source/test_tar_archive.rb +2 -2
- data/test/webgen/tag/test_breadcrumb_trail.rb +1 -1
- data/test/webgen/tag/test_coderay.rb +3 -2
- data/test/webgen/tag/test_date.rb +1 -1
- data/test/webgen/tag/test_execute_command.rb +1 -1
- data/test/webgen/tag/test_include_file.rb +1 -1
- data/test/webgen/tag/test_langbar.rb +1 -1
- data/test/webgen/tag/test_link.rb +1 -1
- data/test/webgen/tag/test_menu.rb +12 -30
- data/test/webgen/tag/test_meta_info.rb +1 -1
- data/test/webgen/tag/test_relocatable.rb +1 -1
- data/test/webgen/tag/test_tikz.rb +3 -2
- data/test/webgen/task/test_create_website.rb +2 -2
- data/test/webgen/test_blackboard.rb +11 -3
- data/test/webgen/test_bundle_loader.rb +26 -9
- data/test/webgen/test_cache.rb +1 -1
- data/test/webgen/test_cli.rb +2 -2
- data/test/webgen/test_configuration.rb +8 -9
- data/test/webgen/test_content_processor.rb +1 -1
- data/test/webgen/test_context.rb +1 -1
- data/test/webgen/test_core_ext.rb +1 -1
- data/test/webgen/test_destination.rb +1 -1
- data/test/webgen/test_error.rb +5 -5
- data/test/webgen/test_extension_manager.rb +1 -1
- data/test/webgen/test_item_tracker.rb +26 -5
- data/test/webgen/test_languages.rb +1 -1
- data/test/webgen/test_logger.rb +1 -1
- data/test/webgen/test_node.rb +1 -1
- data/test/webgen/test_node_finder.rb +2 -2
- data/test/webgen/test_page.rb +5 -5
- data/test/webgen/test_path.rb +8 -8
- data/test/webgen/test_rake_task.rb +1 -1
- data/test/webgen/test_source.rb +1 -1
- data/test/webgen/test_tag.rb +16 -24
- data/test/webgen/test_task.rb +1 -1
- data/test/webgen/test_tree.rb +1 -1
- data/test/webgen/test_utils.rb +1 -1
- data/test/webgen/test_website.rb +1 -1
- data/test/webgen/utils/test_tag_parser.rb +1 -1
- metadata +85 -105
- data/lib/webgen/cli/bundle_command.rb +0 -30
- 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}", '
|
|
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[:
|
|
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['
|
|
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
|
|
70
|
-
#
|
|
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']`.
|
|
74
|
-
#
|
|
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
|
-
|
|
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[
|
|
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,
|
|
23
|
-
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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[
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
+
@website.ext.path_handler.create_secondary_nodes(entry_path)
|
|
52
51
|
end
|
|
53
52
|
end
|
|
54
|
-
|
|
55
|
-
|
|
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)}
|
data/lib/webgen/tag.rb
CHANGED
|
@@ -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]
|
|
22
|
-
#
|
|
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]
|
|
24
|
+
# [body] Holds the body value for the tag if any.
|
|
25
25
|
#
|
|
26
|
-
# [context]
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
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
|
-
|
|
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,
|
|
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
|
|
160
|
+
context = context.clone(:config => create_config(tag, params, tdata, context))
|
|
160
161
|
result, process_output = tdata.object.call(tag, body, context)
|
|
161
|
-
|
|
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
|
|
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 +
|
|
225
|
-
def
|
|
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 '#{
|
|
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 =>
|
|
237
|
+
{tdata.mandatory.first => value}
|
|
234
238
|
end
|
|
235
239
|
end
|
|
236
240
|
|
data/lib/webgen/tag/menu.rb
CHANGED
|
@@ -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 = ['
|
|
32
|
-
styles << '
|
|
33
|
-
styles << '
|
|
34
|
-
styles << '
|
|
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)
|
data/lib/webgen/test_helper.rb
CHANGED
|
@@ -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 =
|
|
132
|
+
def setup_default_nodes(tree, klass = Webgen::Node)
|
|
133
|
+
root = klass.new(tree.dummy_root, '/', '/')
|
|
134
134
|
|
|
135
|
-
file_en =
|
|
136
|
-
frag_en =
|
|
137
|
-
|
|
138
|
-
file_de =
|
|
139
|
-
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
|
|
144
|
+
klass.new(root, 'german.html', '/german.other.html', {'title' => 'german', 'lang' => 'de'})
|
|
145
145
|
|
|
146
|
-
dir =
|
|
147
|
-
dir_file =
|
|
148
|
-
|
|
149
|
-
dir_dir =
|
|
150
|
-
|
|
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 =
|
|
153
|
-
|
|
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
|
-
|
|
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
|