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
@@ -30,26 +30,31 @@ is_integer = lambda do |val|
30
30
  val
31
31
  end
32
32
 
33
+ symbolic_hash = lambda do |val|
34
+ raise 'The value has to be a hash' unless val.kind_of?(Hash)
35
+ val.each_with_object({}) {|(k,v), h| h[k.to_sym] = v}
36
+ end
37
+
33
38
  ########################################################################
34
39
  # General configuration parameters
35
40
 
36
- option('website.tmpdir', 'tmp',
37
- 'Storage location relative to website directory for cache and temporary files created when webgen is run', &is_string)
38
- option('website.cache', [:file, 'webgen.cache'],
39
- 'The file name relative to website.tmpdir (or a string) from/to which the cache is read/written') do |val|
41
+ option('website.tmpdir', 'tmp', &is_string)
42
+ option('website.cache', ['file', 'webgen.cache']) do |val|
40
43
  raise "The value has to be an array with two values" unless val.kind_of?(Array) && val.length == 2
41
- raise "The first value has to be :file or :string" unless val[0] == :file || val[0] == :string
44
+ val.map! {|v| v.to_s}
45
+ raise "The first value has to be 'file' or 'string'" unless val[0] == 'file' || val[0] == 'string'
42
46
  val
43
47
  end
44
- option('website.dry_run', false,
45
- "Perform a dry run, don't actually write files", &true_or_false)
48
+ option('website.dry_run', false, &true_or_false)
46
49
 
47
- option('website.lang', 'en', 'The default language used for the website') do |val|
50
+ option('website.lang', 'en') do |val|
48
51
  lang = LanguageManager.language_for_code(val)
49
52
  raise "Unknown language code '#{val}'" if lang.nil?
50
53
  lang
51
54
  end
52
55
 
56
+ option('website.base_url', '', &is_string)
57
+
53
58
 
54
59
  ########################################################################
55
60
  # Everything related to the content processor extension
@@ -59,67 +64,56 @@ website.ext.content_processor = content_processor = Webgen::ContentProcessor.new
59
64
  content_processor.register('Blocks')
60
65
  content_processor.register('Builder')
61
66
  content_processor.register('Erb')
62
- option('content_processor.erb.trim_mode', '',
63
- "Specifies the ERB trim mode, can contain any combination of '%', '<' and '<>'", &is_string)
67
+ option('content_processor.erb.trim_mode', '', &is_string)
64
68
 
65
69
  content_processor.register('Erubis')
66
- option('content_processor.erubis.use_pi', false,
67
- 'Specifies whether processing instructions should be used', &true_or_false)
68
- option('content_processor.erubis.options', {},
69
- 'A hash of additional, erubis specific options')
70
+ option('content_processor.erubis.use_pi', false, &true_or_false)
71
+ option('content_processor.erubis.options', {}, &symbolic_hash)
70
72
 
71
73
  content_processor.register('Fragments')
72
74
  content_processor.register('Haml', :ext_map => {'haml' => 'html'})
73
75
  content_processor.register('HtmlHead')
74
76
 
75
77
  content_processor.register('Kramdown')
76
- option('content_processor.kramdown.options', {:auto_ids => true},
77
- 'The options hash for the kramdown processor')
78
- option('content_processor.kramdown.handle_links', true,
79
- 'Whether all links in a kramdown document should be processed by webgen', &true_or_false)
80
- option('content_processor.kramdown.ignore_unknown_fragments', false,
81
- 'Specifies whether unknown, non-resolvable fragment parts should be ignored when handling links', &true_or_false)
78
+ option('content_processor.kramdown.options', {:auto_ids => true}, &symbolic_hash)
79
+ option('content_processor.kramdown.handle_links', true, &true_or_false)
80
+ option('content_processor.kramdown.ignore_unknown_fragments', false, &true_or_false)
82
81
 
83
82
  content_processor.register('Maruku')
83
+
84
+ content_processor.register('Rainpress')
85
+ option('content_processor.rainpress.options', {}, &is_hash)
86
+
84
87
  content_processor.register('RDiscount', :name => 'rdiscount')
85
88
  content_processor.register('RDoc', :name => 'rdoc', :ext_map => {'rdoc' => 'html'})
86
89
 
87
90
  content_processor.register('RedCloth', :name => 'redcloth', :ext_map => {'textile' => 'html'})
88
- option('content_processor.redcloth.hard_breaks', false,
89
- 'Specifies whether new lines are turned into hard breaks', &true_or_false)
91
+ option('content_processor.redcloth.hard_breaks', false, &true_or_false)
90
92
 
91
93
  content_processor.register('Ruby')
92
94
 
93
95
  content_processor.register('Sass', :ext_map => {'sass' => 'css'})
94
96
  content_processor.register('Scss', :ext_map => {'scss' => 'css'})
95
- option('content_processor.sass.options', {},
96
- 'Additional Sass options (also used by the scss processor)', &is_hash)
97
+ option('content_processor.sass.options', {}, &symbolic_hash)
97
98
  website.ext.sass_load_paths = []
98
99
 
99
100
  content_processor.register('Tags')
100
101
 
101
102
  content_processor.register('Tidy')
102
- option('content_processor.tidy.options', "-raw",
103
- "Additional options passed to the tidy command (-q and -f are always used)", &is_string)
103
+ option('content_processor.tidy.options', "-raw", &is_string)
104
104
 
105
105
  content_processor.register('Tikz', :ext_map => {'tikz' => 'png'})
106
- option('content_processor.tikz.libraries', [],
107
- 'An array of additional TikZ library names', &is_array)
108
- option('content_processor.tikz.opts', '',
109
- 'A string with global options for the tikzpicture environment', &is_string)
110
- option('content_processor.tikz.resolution', '72 72',
111
- 'A string specifying the render and output resolutions, separated by whitespace') do |val|
106
+ option('content_processor.tikz.libraries', [], &is_array)
107
+ option('content_processor.tikz.opts', '', &is_string)
108
+ option('content_processor.tikz.resolution', '72 72',) do |val|
112
109
  raise "The value has to be a string in the format 'RENDER_RES OUTPUT_RES'" unless val.kind_of?(String) && val =~ /^\d+\s+\d+$/
113
110
  val
114
111
  end
115
- option('content_processor.tikz.transparent', false,
116
- 'Specifies whether the generated image should be transparent (only if the extension is png)', &true_or_false)
117
- option('content_processor.tikz.template', '/templates/tikz.template',
118
- 'Specifies the template with the LaTeX framework that should be used for rendering', &is_string)
112
+ option('content_processor.tikz.transparent', false, &true_or_false)
113
+ option('content_processor.tikz.template', '/templates/tikz.template', &is_string)
119
114
 
120
115
  content_processor.register('Xmllint')
121
- option('content_processor.xmllint.options', "--catalogs --noout --valid",
122
- 'Options passed to the xmllint command', &is_string)
116
+ option('content_processor.xmllint.options', "--catalogs --noout --valid", &is_string)
123
117
 
124
118
 
125
119
  ########################################################################
@@ -131,8 +125,7 @@ website.ext.context_modules = []
131
125
  # Everything related to the destination extension
132
126
  require 'webgen/destination'
133
127
 
134
- option('destination', [:file_system, 'out'],
135
- 'The destination extension which is used to output the generated paths.') do |val|
128
+ option('destination', ['file_system', 'out']) do |val|
136
129
  raise "The value needs to be an array with at least one value (the destination extension name)" unless val.kind_of?(Array) && val.length >=1
137
130
  val
138
131
  end
@@ -152,7 +145,7 @@ website.ext.item_tracker = item_tracker = Webgen::ItemTracker.new(website)
152
145
  item_tracker.register('NodeContent')
153
146
 
154
147
  item_tracker.register('NodeMetaInfo')
155
- website.blackboard.add_listener(:after_node_created) do |node|
148
+ website.blackboard.add_listener(:after_node_created, 'item_tracker.node_meta_info') do |node|
156
149
  item_tracker.add(node, :node_meta_info, node)
157
150
  item_tracker.add(node, :node_meta_info, node, Webgen::ItemTracker::NodeMetaInfo::CONTENT_MODIFICATION_KEY)
158
151
  end
@@ -160,55 +153,63 @@ end
160
153
  item_tracker.register('Nodes')
161
154
  item_tracker.register('File')
162
155
  item_tracker.register('MissingNode')
163
- website.blackboard.add_listener(:node_resolution_failed) do |path, lang|
164
- website.ext.item_tracker.add(website.ext.path_handler.current_dest_node, :missing_node, path, lang)
165
- website.logger.error do
166
- ["Could not resolve '#{path}' in language '#{lang}' in <#{website.ext.path_handler.current_dest_node}>",
167
- "webgen will automatically try to resolve this error by rendering this path again later.",
168
- "If the error persists, the content of the path in question needs to be edited to correct the error."]
156
+ website.blackboard.add_listener(:node_resolution_failed, 'item_tracker.missing_node') do |path, lang|
157
+ if website.ext.path_handler.current_dest_node
158
+ website.ext.item_tracker.add(website.ext.path_handler.current_dest_node, :missing_node, path, lang)
159
+ website.logger.error do
160
+ ["Could not resolve '#{path}' in language '#{lang}' in <#{website.ext.path_handler.current_dest_node}>",
161
+ "webgen will automatically try to resolve this error by rendering this path again later.",
162
+ "If the error persists, the content of the path in question needs to be edited to correct the error."]
163
+ end
169
164
  end
170
165
  end
171
166
 
167
+ item_tracker.register('TemplateChain')
168
+
172
169
  ########################################################################
173
170
  # The link definitions extension
174
171
  website.ext.link_definitions = {}
175
172
 
176
173
 
174
+ ########################################################################
175
+ # Miscellaneous extensions
176
+ website.ext.misc = OpenStruct.new
177
+
178
+ require 'webgen/misc/dummy_index'
179
+ website.ext.misc.dummy_index = Webgen::Misc::DummyIndex.new(website)
180
+ option('misc.dummy_index.enabled', true, &true_or_false)
181
+ option('misc.dummy_index.directory_indexes', ['index.html'])
182
+
183
+
177
184
  ########################################################################
178
185
  # Everything related to the node finder extension
179
186
  require 'webgen/node_finder'
180
187
 
181
188
  website.ext.node_finder = Webgen::NodeFinder.new(website)
182
- option('node_finder.option_sets', {},
183
- 'Node finder option sets that can be referenced by name')
189
+ option('node_finder.option_sets', {})
184
190
 
185
191
 
186
192
  ########################################################################
187
193
  # Everything related to the path handler extension
188
194
  require 'webgen/path_handler'
189
195
 
190
- option('path_handler.patterns.case_sensitive', false,
191
- 'Specifies whether patterns are considered to be case sensitive', &true_or_false)
192
- option('path_handler.patterns.match_leading_dot', false,
193
- 'Specifies whether paths parts starting with a dot are matched', &true_or_false)
194
- option('path_handler.lang_code_in_dest_path', 'except_default',
195
- 'Specifies whether destination paths should use the language part in their name') do |val|
196
+ option('path_handler.patterns.case_sensitive', false, &true_or_false)
197
+ option('path_handler.patterns.match_leading_dot', false, &true_or_false)
198
+ option('path_handler.lang_code_in_dest_path', 'except_default') do |val|
196
199
  if val == true || val == false || val == 'except_default'
197
200
  val
198
201
  else
199
202
  raise "The value has to be 'true', 'false' or 'except_default'"
200
203
  end
201
204
  end
202
- option('path_handler.version_in_dest_path', 'except_default',
203
- 'Specifies whether destination paths should use the version name in their name') do |val|
205
+ option('path_handler.version_in_dest_path', 'except_default') do |val|
204
206
  if val == true || val == false || val == 'except_default'
205
207
  val
206
208
  else
207
209
  raise "The value has to be 'true', 'false' or 'except_default'"
208
210
  end
209
211
  end
210
- option('path_handler.default_template', 'default.template',
211
- 'The name of the default template file')
212
+ option('path_handler.default_template', 'default.template')
212
213
 
213
214
  website.ext.path_handler = path_handler = Webgen::PathHandler.new(website)
214
215
 
@@ -234,10 +235,8 @@ sources_validator = lambda do |val|
234
235
  val
235
236
  end
236
237
 
237
- option('sources', [['/', :file_system, 'src']],
238
- 'One or more sources from which paths are read', &sources_validator)
239
- option('sources.ignore_paths', ['**/*~', '**/.svn/**'],
240
- 'Patterns for paths that should be ignored') do |val|
238
+ option('sources', [['/', :file_system, 'src']], &sources_validator)
239
+ option('sources.ignore_paths', ['**/*~', '**/.svn/**', '**/.gitignore']) do |val|
241
240
  raise "The value has to be an array of patterns" unless val.kind_of?(Array) && val.all? {|item| item.kind_of?(String)}
242
241
  val
243
242
  end
@@ -256,112 +255,80 @@ require 'webgen/tag'
256
255
 
257
256
  website.ext.tag = tag = Webgen::Tag.new(website)
258
257
 
259
- option('tag.prefix', '',
260
- 'The prefix used for tag names to avoid name clashes when another content processor uses similar markup.',
261
- &is_string)
258
+ option('tag.prefix', '', &is_string)
262
259
 
263
260
  tag.register('Date')
264
- option('tag.date.format', '%Y-%m-%d %H:%M:%S',
265
- 'The format of the date (same options as Ruby\'s Time#strftime)', &is_string)
261
+ option('tag.date.format', '%Y-%m-%d %H:%M:%S', &is_string)
266
262
 
267
263
  tag.register('MetaInfo', :names => ['meta_info', :default])
268
- option('tag.meta_info.escape_html', true,
269
- 'Special HTML characters in the output will be escaped if true', &true_or_false)
270
- option('tag.meta_info.mi', nil,
271
- 'The name of the meta information that should be output', &is_string)
264
+ option('tag.meta_info.escape_html', true, &true_or_false)
265
+ option('tag.meta_info.mi', nil, &is_string)
272
266
 
273
267
  tag.register('Relocatable', :names => ['relocatable', 'r'], :mandatory => ['path'])
274
- option('tag.relocatable.path', nil,
275
- 'The path which should be made relocatable', &is_string)
276
- option('tag.relocatable.ignore_unknown_fragment', false,
277
- 'Specifies whether an unknown, non-resolvable fragment part should be ignored', &true_or_false)
268
+ option('tag.relocatable.path', nil, &is_string)
269
+ option('tag.relocatable.ignore_unknown_fragment', false, &true_or_false)
278
270
 
279
271
  tag.register('Link', :mandatory => ['path'])
280
- option('tag.link.path', nil,
281
- 'The (A)LCN path to which a link should be generated', &is_string)
282
- option('tag.link.attr', {},
283
- 'A hash of additional HTML attributes that should be set on the link', &is_hash)
272
+ option('tag.link.path', nil, &is_string)
273
+ option('tag.link.attr', {}, &is_hash)
284
274
 
285
275
  tag.register('ExecuteCommand', :mandatory => ['command'])
286
- option('tag.execute_command.command', nil,
287
- 'The command which should be executed', &is_string)
288
- option('tag.execute_command.process_output', true,
289
- 'The output of the command will be scanned for tags if true', &true_or_false)
290
- option('tag.execute_command.escape_html', true,
291
- 'Special HTML characters in the output will be escaped if true', &true_or_false)
276
+ option('tag.execute_command.command', nil, &is_string)
277
+ option('tag.execute_command.process_output', true, &true_or_false)
278
+ option('tag.execute_command.escape_html', true, &true_or_false)
292
279
 
293
280
  tag.register('IncludeFile', :mandatory => ['filename'])
294
- option('tag.include_file.filename', nil,
295
- 'The name of the file which should be included (relative to the website).', &is_string)
296
- option('tag.include_file.process_output', true,
297
- 'The file content will be scanned for tags if true.', &true_or_false)
298
- option('tag.include_file.escape_html', true,
299
- 'Special HTML characters in the file content will be escaped if true.', &true_or_false)
281
+ option('tag.include_file.filename', nil, &is_string)
282
+ option('tag.include_file.process_output', true, &true_or_false)
283
+ option('tag.include_file.escape_html', true, &true_or_false)
300
284
 
301
285
  tag.register('Coderay', :mandatory => ['lang'])
302
- option('tag.coderay.lang', 'ruby',
303
- 'The language used for highlighting')
304
- option('tag.coderay.process_body', true,
305
- 'The tag body will be scanned for tags before highlighting if true', &true_or_false)
306
- option('tag.coderay.wrap', :div,
307
- "Specifies how the code should be wrapped, either 'div' or 'span'") do |val|
286
+ option('tag.coderay.lang', 'ruby')
287
+ option('tag.coderay.process_body', true &true_or_false)
288
+ option('tag.coderay.wrap', 'div') do |val|
308
289
  val = val.to_s.intern
309
290
  raise "The value has to be either div or span" unless val == :div || val == :span
310
291
  val
311
292
  end
312
- option('tag.coderay.css', 'style',
313
- 'Specifies how the highlighted code should be styled') do |val|
293
+ option('tag.coderay.css', 'style') do |val|
314
294
  val = val.to_s
315
295
  raise "The value has to be class, style or other" unless %w[class style other].include?(val)
316
296
  val
317
297
  end
318
- option('tag.coderay.line_numbers', true,
319
- 'Show line numbers', &true_or_false)
320
- option('tag.coderay.line_number_start', 1,
321
- 'Line number of first line', &is_integer)
322
- option('tag.coderay.bold_every', 10,
323
- 'The interval at which the line number appears bold', &is_integer)
324
- option('tag.coderay.tab_width', 8,
325
- 'Number of spaces used for a tabulator', &is_integer)
298
+ option('tag.coderay.line_numbers', true, &true_or_false)
299
+ option('tag.coderay.line_number_start', 1, &is_integer)
300
+ option('tag.coderay.bold_every', 10, &is_integer)
301
+ option('tag.coderay.tab_width', 8, &is_integer)
326
302
 
327
303
  tag.register('Tikz', :mandatory => ['path'])
328
- option('tag.tikz.path', nil,
329
- 'The path for the created image', &is_string)
330
- option('tag.tikz.img_attr', {},
331
- 'A hash of additional HTML attributes for the created img tag', &is_hash)
304
+ option('tag.tikz.path', nil, &is_string)
305
+ option('tag.tikz.img_attr', {}, &is_hash)
332
306
 
333
307
  tag.register('Langbar')
334
- option('tag.langbar.show_single_lang', true,
335
- 'Should the link be shown although the page is only available in one language?', &true_or_false)
336
- option('tag.langbar.show_own_lang', true,
337
- 'Should the link to the currently displayed language page be shown?', &true_or_false)
338
- option('tag.langbar.template', '/templates/tag.template',
339
- 'The block \'tag.langbar\' in this template file is used for rendering')
340
- option('tag.langbar.separator', ' | ',
341
- 'Specifies the string that should be used as separator between the individual language parts.')
308
+ option('tag.langbar.show_single_lang', true, &true_or_false)
309
+ option('tag.langbar.show_own_lang', true, &true_or_false)
310
+ option('tag.langbar.template', '/templates/tag.template')
311
+ option('tag.langbar.separator', ' | ')
342
312
 
343
313
  tag.register('BreadcrumbTrail')
344
- option('tag.breadcrumb_trail.omit_dir_index', false,
345
- 'Omit the last path component if it is an index path', &true_or_false)
346
- option('tag.breadcrumb_trail.start_level', 0,
347
- 'The level at which the breadcrumb trail starts (starting at 0)', &is_integer)
348
- option('tag.breadcrumb_trail.end_level', -1,
349
- 'The level at which the breadcrumb trail ends (starting at 0)', &is_integer)
350
- option('tag.breadcrumb_trail.separator', ' / ',
351
- 'The separator string which appears between the breadcrumb links', &is_string)
352
- option('tag.breadcrumb_trail.template', '/templates/tag.template',
353
- 'The block \'tag.breadcrumb_trail\' in this template file is used for rendering')
314
+ option('tag.breadcrumb_trail.omit_dir_index', false &true_or_false)
315
+ option('tag.breadcrumb_trail.start_level', 0, &is_integer)
316
+ option('tag.breadcrumb_trail.end_level', -1, &is_integer)
317
+ option('tag.breadcrumb_trail.separator', ' / ', &is_string)
318
+ option('tag.breadcrumb_trail.template', '/templates/tag.template',)
354
319
 
355
320
  tag.register('Menu')
356
- option('tag.menu.style', 'nested',
357
- 'The menu rendering style to be used, either nested or flat') do |val|
321
+ option('tag.menu.style', 'nested') do |val|
358
322
  raise "The value has to be 'nested' or 'flat'" unless %w[nested flat].include?(val.to_s)
359
323
  val.to_s
360
324
  end
361
- option('tag.menu.options', {},
362
- 'Node finder options that specify which nodes the menu should use')
363
- option('tag.menu.template', '/templates/tag.template',
364
- 'The block \'tag.menu\' in this template file is used for rendering')
325
+ option('tag.menu.options', {})
326
+ option('tag.menu.template', '/templates/tag.template')
327
+ option('tag.menu.css_class', nil)
328
+ option('tag.menu.item_level_class', 'webgen-menu-level')
329
+ option('tag.menu.item_submenu_class', 'webgen-menu-submenu')
330
+ option('tag.menu.item_submenu_inhierarchy_class', 'webgen-menu-submenu-inhierarchy')
331
+ option('tag.menu.item_selected_class', 'webgen-menu-item-selected')
365
332
 
366
333
 
367
334
  ########################################################################
@@ -14,10 +14,74 @@ module Webgen
14
14
  # 'webgen-BUNDLE_NAME-bundle'.
15
15
  class BundleLoader
16
16
 
17
+ # Exposes information about bundles like author, license, bundle homepage as well as extension
18
+ # and configuration option documentation.
19
+ class BundleInformation
20
+
21
+ def initialize #:nodoc:
22
+ @bundles = {}
23
+ @infos = nil
24
+ end
25
+
26
+ # Add the bundle +name+ with the given information file to the list of available bundles.
27
+ def add_bundle(name, info_file)
28
+ raise "Bundle information already registered for #{name}" if @bundles.has_key?(name)
29
+ @bundles[name] = info_file
30
+ load_bundle_information unless @infos.nil?
31
+ end
32
+
33
+ # Return a hash with information about bundles.
34
+ def bundles
35
+ infos[:bundles]
36
+ end
37
+
38
+ # Return a hash with information about extensions.
39
+ def extensions
40
+ infos[:extensions]
41
+ end
42
+
43
+ # Return a hash with information about options.
44
+ def options
45
+ infos[:options]
46
+ end
47
+
48
+ def infos #:nodoc:
49
+ load_bundle_information if @infos.nil?
50
+ @infos
51
+ end
52
+ private :infos
53
+
54
+ def load_bundle_information #:nodoc:
55
+ @infos = {:bundles => {}, :extensions => {}, :options => {}}
56
+
57
+ @bundles.each do |bundle, info_file|
58
+ if info_file.nil?
59
+ @infos[:bundles][bundle] = {}
60
+ else
61
+ infos = YAML.load(File.read(info_file))
62
+ [:extensions, :options].each do |type|
63
+ if data = infos.delete(type.to_s)
64
+ data.each do |name, hash|
65
+ hash['bundle'] = bundle
66
+ hash['author'] ||= infos['author']
67
+ end
68
+ @infos[type].update(data)
69
+ end
70
+ end
71
+ @infos[:bundles][bundle] = infos
72
+ end
73
+ end
74
+
75
+ @infos
76
+ end
77
+ private :load_bundle_information
78
+
79
+ end
80
+
17
81
  # Create a new BundleLoader object belonging to the website object +website+.
18
82
  def initialize(website, ext_dir)
19
83
  @website = website
20
- @website.ext.bundles = {}
84
+ @website.ext.bundle_infos = BundleInformation.new
21
85
  @ext_dir = ext_dir
22
86
  @loaded = []
23
87
  @stack = []
@@ -30,18 +94,27 @@ module Webgen
30
94
  file = File.expand_path(file)
31
95
  return if @loaded.include?(file)
32
96
 
33
- @loaded.push(file)
34
- @stack.push(file)
35
- self.instance_eval(File.read(file), file)
36
- @stack.pop
97
+ load!(file)
37
98
 
38
99
  if file != File.expand_path(File.join(@ext_dir, 'init.rb'))
39
100
  name = File.basename(File.dirname(file))
40
101
  info_file = File.join(File.dirname(file), 'info.yaml')
41
- @website.ext.bundles[name] = (File.file?(info_file) ? info_file : nil)
102
+ @website.ext.bundle_infos.add_bundle(name, File.file?(info_file) ? info_file : nil)
42
103
  end
43
104
  end
44
105
 
106
+ # Force-loads the given file and does just that (i.e. no checking if file exists and no bundle
107
+ # registration).
108
+ #
109
+ # **Note**: This method should normally not be called in an extension bundle, use the #load
110
+ # method instead.
111
+ def load!(file)
112
+ @loaded.push(file)
113
+ @stack.push(file)
114
+ self.instance_eval(File.read(file), file)
115
+ @stack.pop
116
+ end
117
+
45
118
  # Loads all bundles that are marked for auto-loading.
46
119
  def load_autoload_bundles
47
120
  bundles = Gem::Specification.map {|s| s.name }.uniq.map do |gem_name|
@@ -104,8 +177,8 @@ module Webgen
104
177
  # Define a configuration option.
105
178
  #
106
179
  # See Webgen::Configuration#define_option for more information.
107
- def option(name, default, description, &validator)
108
- @website.config.define_option(name, default, description, &validator)
180
+ def option(name, default, &validator)
181
+ @website.config.define_option(name, default, &validator)
109
182
  end
110
183
 
111
184
  # Return the website object.
@@ -117,7 +190,7 @@ module Webgen
117
190
  # source.
118
191
  #
119
192
  # See Webgen::Source for more information.
120
- def mount_passive(dir, mount_point = '/', glob = '**/*')
193
+ def mount_passive(dir, mount_point = '/', glob = '{*,**/*}')
121
194
  @website.ext.source.passive_sources.unshift([mount_point, :file_system, absolute_path(dir), glob])
122
195
  end
123
196