webgen 0.5.17 → 1.0.0.beta1

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 (408) hide show
  1. data/API.rdoc +143 -0
  2. data/AUTHORS +0 -1
  3. data/COPYING +17 -8
  4. data/ChangeLog +4456 -0
  5. data/GPL +623 -289
  6. data/README.md +71 -0
  7. data/Rakefile +87 -99
  8. data/VERSION +1 -1
  9. data/bin/webgen +1 -7
  10. data/data/webgen/basic_website_template/ext/init.rb +15 -0
  11. data/data/webgen/basic_website_template/webgen.config +18 -0
  12. data/data/webgen/bundle_template_files/README.md.erb +24 -0
  13. data/data/webgen/bundle_template_files/Rakefile.erb +36 -0
  14. data/data/webgen/bundle_template_files/info.yaml.erb +16 -0
  15. data/data/webgen/bundle_template_files/init.rb.erb +1 -0
  16. data/data/webgen/passive_sources/default.metainfo +32 -0
  17. data/data/webgen/passive_sources/stylesheets/coderay-default.css +109 -118
  18. data/data/webgen/passive_sources/templates/feed.template +62 -0
  19. data/data/webgen/passive_sources/templates/sitemap.template +3 -6
  20. data/data/webgen/passive_sources/templates/tag.template +42 -0
  21. data/data/webgen/website_bundles/default/README +2 -2
  22. data/lib/webgen/blackboard.rb +15 -51
  23. data/lib/webgen/bundle/built-in-show-changes/init.rb +54 -0
  24. data/lib/webgen/bundle/built-in/init.rb +366 -0
  25. data/lib/webgen/bundle_loader.rb +126 -0
  26. data/lib/webgen/cache.rb +9 -18
  27. data/lib/webgen/cli.rb +131 -58
  28. data/lib/webgen/cli/bundle_command.rb +30 -0
  29. data/lib/webgen/cli/create_bundle_command.rb +46 -0
  30. data/lib/webgen/cli/create_command.rb +48 -60
  31. data/lib/webgen/cli/generate_command.rb +25 -0
  32. data/lib/webgen/cli/install_bundle_command.rb +34 -0
  33. data/lib/webgen/cli/list_bundle_command.rb +108 -0
  34. data/lib/webgen/cli/logger.rb +45 -0
  35. data/lib/webgen/cli/show_command.rb +30 -0
  36. data/lib/webgen/cli/show_config_command.rb +63 -0
  37. data/lib/webgen/cli/show_dependencies_command.rb +103 -0
  38. data/lib/webgen/cli/show_extensions_command.rb +74 -0
  39. data/lib/webgen/cli/utils.rb +68 -95
  40. data/lib/webgen/configuration.rb +143 -105
  41. data/lib/webgen/content_processor.rb +160 -0
  42. data/lib/webgen/content_processor/blocks.rb +96 -0
  43. data/lib/webgen/content_processor/builder.rb +25 -0
  44. data/lib/webgen/content_processor/erb.rb +25 -0
  45. data/lib/webgen/content_processor/erubis.rb +31 -0
  46. data/lib/webgen/content_processor/fragments.rb +82 -0
  47. data/lib/webgen/content_processor/haml.rb +25 -0
  48. data/lib/webgen/content_processor/html_head.rb +157 -0
  49. data/lib/webgen/content_processor/kramdown.rb +49 -0
  50. data/lib/webgen/content_processor/maruku.rb +39 -0
  51. data/lib/webgen/content_processor/r_discount.rb +21 -0
  52. data/lib/webgen/content_processor/rdoc.rb +22 -0
  53. data/lib/webgen/content_processor/redcloth.rb +23 -0
  54. data/lib/webgen/content_processor/ruby.rb +20 -0
  55. data/lib/webgen/content_processor/sass.rb +145 -0
  56. data/lib/webgen/content_processor/scss.rb +23 -0
  57. data/lib/webgen/content_processor/tags.rb +30 -0
  58. data/lib/webgen/content_processor/tidy.rb +32 -0
  59. data/lib/webgen/content_processor/tikz.rb +116 -0
  60. data/lib/webgen/content_processor/xmllint.rb +31 -0
  61. data/lib/webgen/context.rb +57 -29
  62. data/lib/webgen/context/html_head.rb +60 -0
  63. data/lib/webgen/context/nodes.rb +32 -27
  64. data/lib/webgen/context/rendering.rb +39 -0
  65. data/lib/webgen/context/webgen_tags.rb +25 -0
  66. data/lib/webgen/core_ext.rb +25 -0
  67. data/lib/webgen/destination.rb +151 -0
  68. data/lib/webgen/destination/file_system.rb +62 -0
  69. data/lib/webgen/error.rb +59 -49
  70. data/lib/webgen/extension_manager.rb +121 -0
  71. data/lib/webgen/item_tracker.rb +237 -0
  72. data/lib/webgen/item_tracker/file.rb +39 -0
  73. data/lib/webgen/item_tracker/missing_node.rb +61 -0
  74. data/lib/webgen/item_tracker/node_content.rb +40 -0
  75. data/lib/webgen/item_tracker/node_meta_info.rb +53 -0
  76. data/lib/webgen/item_tracker/nodes.rb +92 -0
  77. data/lib/webgen/logger.rb +26 -82
  78. data/lib/webgen/node.rb +122 -367
  79. data/lib/webgen/node_finder.rb +336 -0
  80. data/lib/webgen/page.rb +48 -85
  81. data/lib/webgen/path.rb +218 -156
  82. data/lib/webgen/path_handler.rb +400 -0
  83. data/lib/webgen/path_handler/base.rb +220 -0
  84. data/lib/webgen/path_handler/copy.rb +78 -0
  85. data/lib/webgen/path_handler/directory.rb +21 -0
  86. data/lib/webgen/path_handler/feed.rb +82 -0
  87. data/lib/webgen/path_handler/meta_info.rb +84 -0
  88. data/lib/webgen/path_handler/page.rb +38 -0
  89. data/lib/webgen/path_handler/page_utils.rb +79 -0
  90. data/lib/webgen/path_handler/sitemap.rb +52 -0
  91. data/lib/webgen/path_handler/template.rb +96 -0
  92. data/lib/webgen/path_handler/virtual.rb +85 -0
  93. data/lib/webgen/{webgentask.rb → rake_task.rb} +31 -27
  94. data/lib/webgen/source.rb +106 -24
  95. data/lib/webgen/source/file_system.rb +41 -0
  96. data/lib/webgen/source/stacked.rb +49 -53
  97. data/lib/webgen/source/tar_archive.rb +59 -0
  98. data/lib/webgen/tag.rb +250 -19
  99. data/lib/webgen/tag/breadcrumb_trail.rb +65 -0
  100. data/lib/webgen/tag/coderay.rb +32 -35
  101. data/lib/webgen/tag/date.rb +9 -9
  102. data/lib/webgen/tag/execute_command.rb +31 -0
  103. data/lib/webgen/tag/include_file.rb +32 -0
  104. data/lib/webgen/tag/langbar.rb +31 -47
  105. data/lib/webgen/tag/link.rb +17 -18
  106. data/lib/webgen/tag/menu.rb +27 -189
  107. data/lib/webgen/tag/meta_info.rb +31 -0
  108. data/lib/webgen/tag/relocatable.rb +48 -39
  109. data/lib/webgen/tag/tikz.rb +24 -100
  110. data/lib/webgen/task.rb +99 -0
  111. data/lib/webgen/task/create_bundle.rb +73 -0
  112. data/lib/webgen/task/create_website.rb +94 -0
  113. data/lib/webgen/task/generate_website.rb +47 -0
  114. data/lib/webgen/test_helper.rb +183 -0
  115. data/lib/webgen/tree.rb +95 -46
  116. data/lib/webgen/utils.rb +39 -0
  117. data/lib/webgen/utils/external_command.rb +27 -0
  118. data/lib/webgen/utils/tag_parser.rb +124 -0
  119. data/lib/webgen/version.rb +1 -1
  120. data/lib/webgen/website.rb +134 -296
  121. data/setup.rb +1 -1
  122. data/test/test_documentation.rb +43 -0
  123. data/test/webgen/cli/test_logger.rb +41 -0
  124. data/test/{test_contentprocessor_blocks.rb → webgen/content_processor/test_blocks.rb} +30 -28
  125. data/test/webgen/content_processor/test_builder.rb +25 -0
  126. data/test/webgen/content_processor/test_erb.rb +21 -0
  127. data/test/webgen/content_processor/test_erubis.rb +33 -0
  128. data/test/webgen/content_processor/test_fragments.rb +96 -0
  129. data/test/webgen/content_processor/test_haml.rb +24 -0
  130. data/test/webgen/content_processor/test_html_head.rb +78 -0
  131. data/test/webgen/content_processor/test_kramdown.rb +49 -0
  132. data/test/webgen/content_processor/test_maruku.rb +30 -0
  133. data/test/webgen/content_processor/test_r_discount.rb +18 -0
  134. data/test/webgen/content_processor/test_rdoc.rb +18 -0
  135. data/test/webgen/content_processor/test_redcloth.rb +23 -0
  136. data/test/webgen/content_processor/test_ruby.rb +24 -0
  137. data/test/webgen/content_processor/test_sass.rb +44 -0
  138. data/test/webgen/content_processor/test_scss.rb +23 -0
  139. data/test/webgen/content_processor/test_tags.rb +44 -0
  140. data/test/webgen/content_processor/test_tidy.rb +31 -0
  141. data/test/webgen/content_processor/test_tikz.rb +33 -0
  142. data/test/webgen/content_processor/test_xmllint.rb +32 -0
  143. data/test/webgen/destination/test_file_system.rb +54 -0
  144. data/test/webgen/item_tracker/test_file.rb +31 -0
  145. data/test/webgen/item_tracker/test_missing_node.rb +70 -0
  146. data/test/webgen/item_tracker/test_node_content.rb +42 -0
  147. data/test/webgen/item_tracker/test_node_meta_info.rb +44 -0
  148. data/test/webgen/item_tracker/test_nodes.rb +61 -0
  149. data/test/webgen/path_handler/test_base.rb +153 -0
  150. data/test/webgen/path_handler/test_copy.rb +56 -0
  151. data/test/webgen/path_handler/test_feed.rb +85 -0
  152. data/test/webgen/path_handler/test_meta_info.rb +98 -0
  153. data/test/webgen/path_handler/test_page.rb +25 -0
  154. data/test/webgen/path_handler/test_page_utils.rb +59 -0
  155. data/test/webgen/path_handler/test_sitemap.rb +95 -0
  156. data/test/webgen/path_handler/test_template.rb +64 -0
  157. data/test/webgen/path_handler/test_virtual.rb +87 -0
  158. data/test/webgen/source/test_file_system.rb +51 -0
  159. data/test/webgen/source/test_stacked.rb +35 -0
  160. data/test/{test_source_tararchive.rb → webgen/source/test_tar_archive.rb} +10 -25
  161. data/test/webgen/tag/test_breadcrumb_trail.rb +66 -0
  162. data/test/webgen/tag/test_coderay.rb +34 -0
  163. data/test/webgen/tag/test_date.rb +18 -0
  164. data/test/webgen/tag/test_execute_command.rb +36 -0
  165. data/test/webgen/tag/test_include_file.rb +35 -0
  166. data/test/webgen/tag/test_langbar.rb +50 -0
  167. data/test/webgen/tag/test_link.rb +40 -0
  168. data/test/webgen/tag/test_menu.rb +61 -0
  169. data/test/webgen/tag/test_meta_info.rb +25 -0
  170. data/test/webgen/tag/test_relocatable.rb +50 -0
  171. data/test/webgen/tag/test_tikz.rb +41 -0
  172. data/test/webgen/task/test_create_website.rb +46 -0
  173. data/test/webgen/test_blackboard.rb +31 -0
  174. data/test/webgen/test_bundle_loader.rb +55 -0
  175. data/test/{test_cache.rb → webgen/test_cache.rb} +3 -15
  176. data/test/webgen/test_cli.rb +41 -0
  177. data/test/webgen/test_configuration.rb +131 -0
  178. data/test/webgen/test_content_processor.rb +86 -0
  179. data/test/webgen/test_context.rb +73 -0
  180. data/test/webgen/test_core_ext.rb +20 -0
  181. data/test/webgen/test_destination.rb +48 -0
  182. data/test/webgen/test_error.rb +121 -0
  183. data/test/webgen/test_extension_manager.rb +70 -0
  184. data/test/webgen/test_item_tracker.rb +106 -0
  185. data/test/{test_languages.rb → webgen/test_languages.rb} +4 -4
  186. data/test/webgen/test_logger.rb +46 -0
  187. data/test/webgen/test_node.rb +178 -0
  188. data/test/webgen/test_node_finder.rb +127 -0
  189. data/test/{test_page.rb → webgen/test_page.rb} +44 -48
  190. data/test/webgen/test_path.rb +271 -0
  191. data/test/{test_webgentask.rb → webgen/test_rake_task.rb} +4 -4
  192. data/test/webgen/test_source.rb +59 -0
  193. data/test/webgen/test_tag.rb +137 -0
  194. data/test/webgen/test_task.rb +40 -0
  195. data/test/webgen/test_tree.rb +147 -0
  196. data/test/webgen/test_utils.rb +16 -0
  197. data/test/webgen/test_website.rb +45 -0
  198. data/test/webgen/utils/test_tag_parser.rb +99 -0
  199. metadata +292 -344
  200. data/data/webgen/passive_sources/templates/atom_feed.template +0 -39
  201. data/data/webgen/passive_sources/templates/rss_feed.template +0 -28
  202. data/data/webgen/resources.yaml +0 -4
  203. data/data/webgen/webgui/app.rb +0 -11
  204. data/data/webgen/webgui/controller/main.rb +0 -135
  205. data/data/webgen/webgui/layout/default.xhtml +0 -40
  206. data/data/webgen/webgui/overrides/win32console.rb +0 -0
  207. data/data/webgen/webgui/public/css/jquery.autocomplete.css +0 -50
  208. data/data/webgen/webgui/public/css/ramaze_error.css +0 -90
  209. data/data/webgen/webgui/public/css/style.css +0 -55
  210. data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
  211. data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
  212. data/data/webgen/webgui/public/js/jquery.autocomplete.js +0 -15
  213. data/data/webgen/webgui/public/js/jquery.js +0 -32
  214. data/data/webgen/webgui/start.rb +0 -9
  215. data/data/webgen/webgui/view/create_website.xhtml +0 -14
  216. data/data/webgen/webgui/view/error.xhtml +0 -64
  217. data/data/webgen/webgui/view/index.xhtml +0 -22
  218. data/data/webgen/webgui/view/manage_website.xhtml +0 -18
  219. data/data/webgen/website_skeleton/README +0 -10
  220. data/data/webgen/website_skeleton/Rakefile +0 -69
  221. data/data/webgen/website_skeleton/config.yaml +0 -35
  222. data/data/webgen/website_skeleton/ext/init.rb +0 -10
  223. data/doc/contentprocessor.template +0 -11
  224. data/doc/contentprocessor/blocks.page +0 -129
  225. data/doc/contentprocessor/builder.page +0 -79
  226. data/doc/contentprocessor/erb.page +0 -60
  227. data/doc/contentprocessor/erubis.page +0 -46
  228. data/doc/contentprocessor/fragments.page +0 -26
  229. data/doc/contentprocessor/haml.page +0 -46
  230. data/doc/contentprocessor/head.page +0 -31
  231. data/doc/contentprocessor/kramdown.page +0 -49
  232. data/doc/contentprocessor/less.page +0 -34
  233. data/doc/contentprocessor/maruku.page +0 -44
  234. data/doc/contentprocessor/rdiscount.page +0 -37
  235. data/doc/contentprocessor/rdoc.page +0 -36
  236. data/doc/contentprocessor/redcloth.page +0 -41
  237. data/doc/contentprocessor/sass.page +0 -31
  238. data/doc/contentprocessor/scss.page +0 -39
  239. data/doc/contentprocessor/tags.page +0 -73
  240. data/doc/contentprocessor/tidy.page +0 -14
  241. data/doc/contentprocessor/xmllint.page +0 -14
  242. data/doc/extensions.metainfo +0 -29
  243. data/doc/extensions.page +0 -15
  244. data/doc/extensions.template +0 -17
  245. data/doc/faq.page +0 -222
  246. data/doc/getting_started.page +0 -135
  247. data/doc/index.page +0 -71
  248. data/doc/manual.page +0 -727
  249. data/doc/reference_configuration.page +0 -1254
  250. data/doc/reference_metainfo.page +0 -265
  251. data/doc/reference_website_styles.page +0 -32
  252. data/doc/source/filesystem.page +0 -41
  253. data/doc/source/tararchive.page +0 -40
  254. data/doc/sourcehandler.template +0 -23
  255. data/doc/sourcehandler/copy.page +0 -19
  256. data/doc/sourcehandler/directory.page +0 -27
  257. data/doc/sourcehandler/feed.page +0 -102
  258. data/doc/sourcehandler/metainfo.page +0 -48
  259. data/doc/sourcehandler/page.page +0 -14
  260. data/doc/sourcehandler/sitemap.page +0 -46
  261. data/doc/sourcehandler/template.page +0 -45
  262. data/doc/sourcehandler/virtual.page +0 -49
  263. data/doc/tag.template +0 -25
  264. data/doc/tag/breadcrumbtrail.page +0 -40
  265. data/doc/tag/coderay.page +0 -53
  266. data/doc/tag/date.page +0 -31
  267. data/doc/tag/executecommand.page +0 -26
  268. data/doc/tag/includefile.page +0 -32
  269. data/doc/tag/langbar.page +0 -47
  270. data/doc/tag/link.page +0 -44
  271. data/doc/tag/menu.page +0 -109
  272. data/doc/tag/metainfo.page +0 -29
  273. data/doc/tag/relocatable.page +0 -38
  274. data/doc/tag/sitemap.page +0 -31
  275. data/doc/tag/tikz.page +0 -159
  276. data/doc/upgrading.page +0 -138
  277. data/doc/webgen_page_format.page +0 -129
  278. data/doc/website_styles.metainfo +0 -8
  279. data/lib/webgen/cli/apply_command.rb +0 -66
  280. data/lib/webgen/cli/run_command.rb +0 -22
  281. data/lib/webgen/cli/webgui_command.rb +0 -68
  282. data/lib/webgen/common.rb +0 -27
  283. data/lib/webgen/common/sitemap.rb +0 -83
  284. data/lib/webgen/contentprocessor.rb +0 -117
  285. data/lib/webgen/contentprocessor/blocks.rb +0 -92
  286. data/lib/webgen/contentprocessor/builder.rb +0 -29
  287. data/lib/webgen/contentprocessor/erb.rb +0 -26
  288. data/lib/webgen/contentprocessor/erubis.rb +0 -39
  289. data/lib/webgen/contentprocessor/fragments.rb +0 -25
  290. data/lib/webgen/contentprocessor/haml.rb +0 -34
  291. data/lib/webgen/contentprocessor/head.rb +0 -128
  292. data/lib/webgen/contentprocessor/kramdown.rb +0 -27
  293. data/lib/webgen/contentprocessor/kramdown/html.rb +0 -36
  294. data/lib/webgen/contentprocessor/less.rb +0 -35
  295. data/lib/webgen/contentprocessor/maruku.rb +0 -36
  296. data/lib/webgen/contentprocessor/rdiscount.rb +0 -19
  297. data/lib/webgen/contentprocessor/rdoc.rb +0 -20
  298. data/lib/webgen/contentprocessor/redcloth.rb +0 -21
  299. data/lib/webgen/contentprocessor/sass.rb +0 -22
  300. data/lib/webgen/contentprocessor/scss.rb +0 -22
  301. data/lib/webgen/contentprocessor/tags.rb +0 -170
  302. data/lib/webgen/contentprocessor/tidy.rb +0 -38
  303. data/lib/webgen/contentprocessor/xmllint.rb +0 -37
  304. data/lib/webgen/context/render.rb +0 -32
  305. data/lib/webgen/context/tags.rb +0 -20
  306. data/lib/webgen/coreext.rb +0 -13
  307. data/lib/webgen/default_config.rb +0 -240
  308. data/lib/webgen/loggable.rb +0 -25
  309. data/lib/webgen/output.rb +0 -86
  310. data/lib/webgen/output/filesystem.rb +0 -69
  311. data/lib/webgen/source/filesystem.rb +0 -61
  312. data/lib/webgen/source/resource.rb +0 -45
  313. data/lib/webgen/source/tararchive.rb +0 -78
  314. data/lib/webgen/sourcehandler.rb +0 -275
  315. data/lib/webgen/sourcehandler/base.rb +0 -281
  316. data/lib/webgen/sourcehandler/copy.rb +0 -44
  317. data/lib/webgen/sourcehandler/directory.rb +0 -30
  318. data/lib/webgen/sourcehandler/feed.rb +0 -92
  319. data/lib/webgen/sourcehandler/fragment.rb +0 -70
  320. data/lib/webgen/sourcehandler/memory.rb +0 -42
  321. data/lib/webgen/sourcehandler/metainfo.rb +0 -128
  322. data/lib/webgen/sourcehandler/page.rb +0 -64
  323. data/lib/webgen/sourcehandler/sitemap.rb +0 -60
  324. data/lib/webgen/sourcehandler/template.rb +0 -66
  325. data/lib/webgen/sourcehandler/virtual.rb +0 -117
  326. data/lib/webgen/tag/base.rb +0 -170
  327. data/lib/webgen/tag/breadcrumbtrail.rb +0 -70
  328. data/lib/webgen/tag/executecommand.rb +0 -31
  329. data/lib/webgen/tag/includefile.rb +0 -42
  330. data/lib/webgen/tag/metainfo.rb +0 -27
  331. data/lib/webgen/tag/sitemap.rb +0 -41
  332. data/lib/webgen/websiteaccess.rb +0 -31
  333. data/lib/webgen/websitemanager.rb +0 -125
  334. data/misc/default.css +0 -403
  335. data/misc/default.template +0 -76
  336. data/misc/htmldoc.metainfo +0 -26
  337. data/misc/htmldoc.virtual +0 -17
  338. data/misc/images/arrow.gif +0 -0
  339. data/misc/images/error.png +0 -0
  340. data/misc/images/headerbg.jpg +0 -0
  341. data/misc/images/important.png +0 -0
  342. data/misc/images/information.png +0 -0
  343. data/misc/images/quote.gif +0 -0
  344. data/misc/images/warning.png +0 -0
  345. data/misc/logo.svg +0 -313
  346. data/misc/style.page +0 -33
  347. data/test/helper.rb +0 -61
  348. data/test/test_blackboard.rb +0 -60
  349. data/test/test_cli.rb +0 -119
  350. data/test/test_common_sitemap.rb +0 -58
  351. data/test/test_configuration.rb +0 -68
  352. data/test/test_contentprocessor.rb +0 -39
  353. data/test/test_contentprocessor_builder.rb +0 -41
  354. data/test/test_contentprocessor_erb.rb +0 -33
  355. data/test/test_contentprocessor_erubis.rb +0 -62
  356. data/test/test_contentprocessor_fragments.rb +0 -43
  357. data/test/test_contentprocessor_haml.rb +0 -39
  358. data/test/test_contentprocessor_head.rb +0 -96
  359. data/test/test_contentprocessor_kramdown.rb +0 -56
  360. data/test/test_contentprocessor_less.rb +0 -40
  361. data/test/test_contentprocessor_maruku.rb +0 -33
  362. data/test/test_contentprocessor_rdiscount.rb +0 -21
  363. data/test/test_contentprocessor_rdoc.rb +0 -22
  364. data/test/test_contentprocessor_redcloth.rb +0 -26
  365. data/test/test_contentprocessor_sass.rb +0 -28
  366. data/test/test_contentprocessor_scss.rb +0 -28
  367. data/test/test_contentprocessor_tags.rb +0 -122
  368. data/test/test_contentprocessor_tidy.rb +0 -34
  369. data/test/test_contentprocessor_xmllint.rb +0 -38
  370. data/test/test_context.rb +0 -81
  371. data/test/test_error.rb +0 -93
  372. data/test/test_loggable.rb +0 -32
  373. data/test/test_logger.rb +0 -94
  374. data/test/test_node.rb +0 -469
  375. data/test/test_output_filesystem.rb +0 -60
  376. data/test/test_path.rb +0 -241
  377. data/test/test_source_filesystem.rb +0 -76
  378. data/test/test_source_resource.rb +0 -28
  379. data/test/test_source_stacked.rb +0 -49
  380. data/test/test_sourcehandler_base.rb +0 -136
  381. data/test/test_sourcehandler_copy.rb +0 -47
  382. data/test/test_sourcehandler_directory.rb +0 -38
  383. data/test/test_sourcehandler_feed.rb +0 -88
  384. data/test/test_sourcehandler_fragment.rb +0 -70
  385. data/test/test_sourcehandler_main.rb +0 -39
  386. data/test/test_sourcehandler_memory.rb +0 -44
  387. data/test/test_sourcehandler_metainfo.rb +0 -127
  388. data/test/test_sourcehandler_page.rb +0 -73
  389. data/test/test_sourcehandler_sitemap.rb +0 -68
  390. data/test/test_sourcehandler_template.rb +0 -68
  391. data/test/test_sourcehandler_virtual.rb +0 -106
  392. data/test/test_tag_base.rb +0 -62
  393. data/test/test_tag_breadcrumbtrail.rb +0 -91
  394. data/test/test_tag_coderay.rb +0 -45
  395. data/test/test_tag_date.rb +0 -18
  396. data/test/test_tag_executecommand.rb +0 -41
  397. data/test/test_tag_includefile.rb +0 -50
  398. data/test/test_tag_langbar.rb +0 -71
  399. data/test/test_tag_link.rb +0 -70
  400. data/test/test_tag_menu.rb +0 -207
  401. data/test/test_tag_metainfo.rb +0 -26
  402. data/test/test_tag_relocatable.rb +0 -60
  403. data/test/test_tag_sitemap.rb +0 -47
  404. data/test/test_tag_tikz.rb +0 -69
  405. data/test/test_tree.rb +0 -70
  406. data/test/test_website.rb +0 -130
  407. data/test/test_websiteaccess.rb +0 -25
  408. data/test/test_websitemanager.rb +0 -65
@@ -0,0 +1,400 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/extension_manager'
4
+ require 'stringio'
5
+ require 'set'
6
+ require 'benchmark'
7
+
8
+ module Webgen
9
+
10
+ # Namespace for all path handlers.
11
+ #
12
+ # == About
13
+ #
14
+ # A path handler is a webgen extension that uses source Path objects to create Node objects and
15
+ # that provides methods for rendering these nodes. The nodes are stored in a hierarchy, the root
16
+ # of which is a Tree object. Path handlers can do simple things, like copying a path from the
17
+ # source to the destination, or a complex things, like generating a whole set of nodes from one
18
+ # input path (e.g. generating a whole image gallery)!
19
+ #
20
+ # The paths that are handled by a path handler are specified via path patterns (see below). The
21
+ # #create_nodes method of a path handler is called for each source path that matches a specified
22
+ # path pattern. And when it is time to write out a node, the #content method on the associated
23
+ # path handler is called to retrieve the rendered content of the node.
24
+ #
25
+ # Also note that any method invoked on a Node object that is not defined in the Node class itself
26
+ # is forwarded to the associated path handler, adding the node as first parameter to the parameter
27
+ # list.
28
+ #
29
+ # === Tree creation
30
+ #
31
+ # The method #populate_tree is used for creating the initial node tree, the internal
32
+ # representation of all paths. It is only the initial tree because it is possible that additional,
33
+ # secondary nodes are created during the rendering phase by using the #create_secondary_nodes
34
+ # method.
35
+ #
36
+ # Tree creation works like this:
37
+ #
38
+ # 1. All path handlers on the invocation list are used in turn. The order is important; it allows
39
+ # avoiding unnecessary write phases and it makes sure that, for example, directory nodes are
40
+ # created before their file nodes.
41
+ #
42
+ # 2. When a path handler is used for creating nodes, all source paths (retrieved by using
43
+ # Webgen::Source#paths method) that match one of the associated patterns are used.
44
+ #
45
+ # 3. The meta information of a used source path is then updated with the meta information from the
46
+ # 'path_handler.default_meta_info' configuration option key.
47
+ #
48
+ # After that the source path is given to the #parse_meta_info! method of the path handler so
49
+ # that meta information of the path can be updated with meta information stored in the content
50
+ # of the path itself.
51
+ #
52
+ # Then the meta information 'versions' is used to determine if multiple version of the path
53
+ # should be used for creating nodes and each path version is then given to the #create_nodes
54
+ # method of the path handler so that it can create one or more nodes.
55
+ #
56
+ # 4. Nodes returned by the #creates_nodes of a path handler are assumed to have the Node#node_info
57
+ # keys :path and :path_handler and the meta info key 'modified_at' correctly set (this is
58
+ # automatically done if the Webgen::PathHandler::Base#create_node method is used).
59
+ #
60
+ # === Path Patterns and Invocation order
61
+ #
62
+ # Path patterns define which paths are handled by a specific path handler. These patterns are
63
+ # specified when a path handler is registered using #register method. The patterns need to have a
64
+ # format that Dir.glob can handle.
65
+ #
66
+ # In addition to specifying the patterns a path handler uses, one can also specify the place in
67
+ # the invocation list which the path handler should use. The invocation list is used from the
68
+ # front to the back when the Tree is created.
69
+ #
70
+ # == Implementing a path handler
71
+ #
72
+ # A path handler must take the website as the only parameter on initialization and needs to define
73
+ # the following methods:
74
+ #
75
+ # [parse_meta_info!(path)]
76
+ #
77
+ # Update +path.meta_info+ with meta information found in the content of the path. The return
78
+ # values of this method are given to the #create_nodes method as additional parameters!
79
+ #
80
+ # This allows one to use a single pass for reading the meta information and the normal content
81
+ # of the path.
82
+ #
83
+ # [#create_nodes(path, ...)]
84
+ #
85
+ # Create one or more nodes from the path and return them. If #parse_meta_info! returns one or
86
+ # more values, these values are provided as additional parameters to this method.
87
+ #
88
+ # It is a good idead to use the helper method Webgen::PathHandler::Base#create_node for actually
89
+ # creating a node.
90
+ #
91
+ # [#content(node)]
92
+ #
93
+ # Return the content of the given node. This method is only called for nodes that have been
94
+ # created by the path handler.
95
+ #
96
+ # Also note that a path handler does not need to reside under the Webgen::PathHandler namespace
97
+ # but all built-in ones do so that auto-loading of the path handlers works.
98
+ #
99
+ # The Webgen::PathHandler::Base module provides default implementations of the needed methods
100
+ # (except for #create_nodes) and should be used by all path handlers! If a path handler processes
101
+ # paths in Webgen Page Format, it should probably also use Webgen::PathHandler::PageUtils.
102
+ #
103
+ # Information that is used by a path handler only for processing purposes should be stored in the
104
+ # #node_info hash of a node as the #meta_info hash is reserved for user provided node meta
105
+ # information.
106
+ #
107
+ # Following is a simple path handler class example which copies paths from the source to the
108
+ # destination and modifies the extension in the process:
109
+ #
110
+ # class SimpleCopy
111
+ #
112
+ # include Webgen::PathHandler::Base
113
+ #
114
+ # def create_nodes(path)
115
+ # path.ext += '.copied'
116
+ # create_node(path)
117
+ # end
118
+ #
119
+ # def content(node)
120
+ # node.node_info[:path]
121
+ # end
122
+ #
123
+ # end
124
+ #
125
+ # website.ext.path_handler.register(SimpleCopy, patterns: ['**/*.jpg', '**/*.png'])
126
+ #
127
+ class PathHandler
128
+
129
+ include Webgen::ExtensionManager
130
+
131
+ # The destination node if one is currently written (only during the invocation of #write_tree)
132
+ # or +nil+ otherwise.
133
+ attr_reader :current_dest_node
134
+
135
+ # Create a new path handler object for the given website.
136
+ def initialize(website)
137
+ super()
138
+ @website = website
139
+ @current_dest_node = nil
140
+ @invocation_order = []
141
+ @instances = {}
142
+ @secondary_nodes = {}
143
+
144
+ @website.blackboard.add_listener(:website_generated, self) do
145
+ @website.cache[:path_handler_secondary_nodes] = @secondary_nodes
146
+ end
147
+
148
+ used_secondary_paths = {}
149
+ @website.blackboard.add_listener(:before_secondary_nodes_created, self) do |path, source_alcn|
150
+ (used_secondary_paths[source_alcn] ||= Set.new) << path if source_alcn
151
+ end
152
+ @website.blackboard.add_listener(:before_node_written, self) do |node|
153
+ used_secondary_paths = {}
154
+ end
155
+ @website.blackboard.add_listener(:after_node_written, self) do |node|
156
+ @secondary_nodes.select do |path, data|
157
+ data[1] == node.alcn && used_secondary_paths[node.alcn] &&
158
+ !used_secondary_paths[node.alcn].include?(path)
159
+ end.each do |path, data|
160
+ @secondary_nodes.delete(path)
161
+ data[2].each {|alcn| @website.tree.delete_node(@website.tree[alcn])}
162
+ end
163
+ end
164
+ end
165
+
166
+ # Register a path handler.
167
+ #
168
+ # The parameter +klass+ has to contain the name of the path handler class or the class object
169
+ # itself. If the class is located under this namespace, only the class name without the
170
+ # hierarchy part is needed, otherwise the full class name including parent module/class names is
171
+ # needed.
172
+ #
173
+ # === Options:
174
+ #
175
+ # [:name] The name for the path handler. If not set, it defaults to the snake-case version of
176
+ # the class name (without the hierarchy part). It should only contain letters.
177
+ #
178
+ # [:patterns] A list of path patterns for which the path handler should be used. If not
179
+ # specified, defaults to an empty list.
180
+ #
181
+ # [:insert_at] Specifies the position in the invocation list. If not specified or if :end is
182
+ # specified, the handler is added to the end of the list. If :front is specified,
183
+ # it is added to the beginning of the list. Otherwise the value is expected to be a
184
+ # position number and the path handler is added at the specified position in the
185
+ # list.
186
+ #
187
+ # === Examples:
188
+ #
189
+ # path_handler.register('Template') # registers Webgen::PathHandler::Template
190
+ #
191
+ # path_handler.register('::Template') # registers Template !!!
192
+ #
193
+ # path_handler.register('MyModule::Doit', name: 'template', patterns: ['**/*.template'])
194
+ #
195
+ def register(klass, options={}, &block)
196
+ name = do_register(klass, options, false, &block)
197
+ ext_data(name).patterns = options[:patterns] || []
198
+ pos = if options[:insert_at].nil? || options[:insert_at] == :end
199
+ -1
200
+ elsif options[:insert_at] == :front
201
+ 0
202
+ else
203
+ options[:insert_at].to_i
204
+ end
205
+ @invocation_order.delete(name)
206
+ @invocation_order.insert(pos, name)
207
+ end
208
+
209
+ # Return the instance of the path handler class with the given name.
210
+ def instance(handler)
211
+ @instances[handler] ||= extension(handler).new(@website)
212
+ end
213
+
214
+
215
+ # Populate the website tree with nodes.
216
+ #
217
+ # Can only be called once because the tree can only be populated once!
218
+ def populate_tree
219
+ raise Webgen::NodeCreationError.new("Can't populate tree twice", self.class.name) if @website.tree.root
220
+
221
+ time = Benchmark.measure do
222
+ meta_info, rest = @website.ext.source.paths.partition {|path| path.path =~ /[\/.]metainfo$/}
223
+ create_nodes(meta_info, [:meta_info])
224
+ create_nodes(rest)
225
+
226
+ used_paths = @website.tree.node_access[:alcn].values.map {|n| n.node_info[:path]}
227
+ unused_paths = rest - used_paths
228
+ @website.logger.vinfo do
229
+ "The following source paths have not been used: #{unused_paths.join(', ')}"
230
+ end if unused_paths.length > 0
231
+
232
+ (@website.cache[:path_handler_secondary_nodes] || {}).each do |path, (content, source_alcn, _)|
233
+ next if !@website.tree[source_alcn]
234
+ create_secondary_nodes(path, content, source_alcn)
235
+ end
236
+ end
237
+ @website.logger.vinfo do
238
+ "Populating node tree took " << ('%2.2f' % time.real) << ' seconds'
239
+ end
240
+
241
+ @website.blackboard.dispatch_msg(:after_tree_populated)
242
+ end
243
+
244
+ # Write all changed nodes of the website tree to their respective destination using the
245
+ # Destination object at +website.ext.destination+.
246
+ #
247
+ # Returns the number of passes needed for correctly writing out all paths.
248
+ def write_tree
249
+ passes = 0
250
+ content = nil
251
+
252
+ begin
253
+ at_least_one_node_written = false
254
+ @website.cache.reset_volatile_cache
255
+ @website.blackboard.dispatch_msg(:before_all_nodes_written)
256
+ @website.tree.node_access[:alcn].sort.each do |name, node|
257
+ begin
258
+ next if node == @website.tree.dummy_root ||
259
+ (node['passive'] && !node['no_output'] && !@website.ext.item_tracker.node_referenced?(node)) ||
260
+ ((@website.config['website.dry_run'] || @website.ext.destination.exists?(node.dest_path)) &&
261
+ !@website.ext.item_tracker.node_changed?(node))
262
+
263
+ @website.blackboard.dispatch_msg(:before_node_written, node)
264
+ if !node['no_output']
265
+ content = write_node(node)
266
+ at_least_one_node_written = true
267
+ end
268
+ @website.blackboard.dispatch_msg(:after_node_written, node, content)
269
+ rescue Webgen::Error => e
270
+ e.path = node.alcn if e.path.to_s.empty?
271
+ raise
272
+ rescue Exception => e
273
+ raise Webgen::RenderError.new(e, nil, node)
274
+ end
275
+ end
276
+ @website.blackboard.dispatch_msg(:after_all_nodes_written)
277
+ passes += 1 if at_least_one_node_written
278
+ end while at_least_one_node_written
279
+
280
+ @website.blackboard.dispatch_msg(:website_generated)
281
+ passes
282
+ end
283
+
284
+ # Write the given node to the destination.
285
+ def write_node(node)
286
+ @current_dest_node = node
287
+ @website.logger.info do
288
+ "[#{(@website.ext.destination.exists?(node.dest_path) ? 'update' : 'create')}] <#{node.dest_path}>"
289
+ end
290
+ content = nil
291
+ time = Benchmark.measure { content = node.content }
292
+ @website.ext.destination.write(node.dest_path, content)
293
+ @website.logger.vinfo do
294
+ "[timing] <#{node.dest_path}> rendered in " << ('%2.2f' % time.real) << ' seconds'
295
+ end
296
+ content
297
+ ensure
298
+ @current_dest_node = nil
299
+ end
300
+ private :write_node
301
+
302
+ # Use the registered path handlers to create nodes which are all returned.
303
+ def create_nodes(paths, handlers = @invocation_order)
304
+ nodes = []
305
+ paths.each {|path| @website.blackboard.dispatch_msg(:apply_meta_info_to_path, path)}
306
+ handlers.each do |name|
307
+ paths_for_handler(name.to_s, paths).each do |path|
308
+ nodes += create_nodes_with_path_handler(path, name)
309
+ end
310
+ end
311
+ nodes
312
+ end
313
+ private :create_nodes
314
+
315
+ # Create nodes for the given +path+ (a Path object which must not be a source path).
316
+ #
317
+ # The content of the path also needs to be specified. Note that if an IO block is associated
318
+ # with the path, it is discarded!
319
+ #
320
+ # If the parameter +handler+ is present, nodes from the given path are only created with the
321
+ # specified handler.
322
+ #
323
+ # If the secondary nodes are created during the rendering phase (and not during node creation,
324
+ # ie. in a #create_nodes method of a path handler), the +source_alcn+ has to be set to the node
325
+ # alcn from which these nodes are created!
326
+ def create_secondary_nodes(path, content = '', source_alcn = nil)
327
+ if (sn = @secondary_nodes[path]) && sn[1] != source_alcn
328
+ raise Webgen::NodeCreationError.new("Duplicate secondary path name <#{path}>", self.class.name, path)
329
+ end
330
+ @website.blackboard.dispatch_msg(:before_secondary_nodes_created, path, source_alcn)
331
+
332
+ path['modified_at'] ||= @website.tree[source_alcn]['modified_at'] if source_alcn
333
+ path.set_io { StringIO.new(content) }
334
+
335
+ nodes = if path['handler']
336
+ @website.blackboard.dispatch_msg(:apply_meta_info_to_path, path)
337
+ create_nodes_with_path_handler(path, path['handler'])
338
+ else
339
+ create_nodes([path])
340
+ end
341
+ @website.blackboard.dispatch_msg(:after_secondary_nodes_created, path, nodes)
342
+
343
+ if source_alcn
344
+ path.set_io(&nil)
345
+ _, _, stored_alcns = @secondary_nodes.delete(path)
346
+ cur_alcns = nodes.map {|n| n.alcn}
347
+ (stored_alcns - cur_alcns).each {|n| @website.tree.delete_node(@website.tree[n])} if stored_alcns
348
+ @secondary_nodes[path.dup] = [content, source_alcn, cur_alcns]
349
+ end
350
+
351
+ nodes
352
+ end
353
+
354
+ # Return the paths which are handled by the path handler +name+ (where +name+ is a String).
355
+ def paths_for_handler(name, paths)
356
+ patterns = ext_data(name).patterns || []
357
+
358
+ options = (@website.config['path_handler.patterns.case_sensitive'] ? 0 : File::FNM_CASEFOLD) |
359
+ (@website.config['path_handler.patterns.match_leading_dot'] ? File::FNM_DOTMATCH : 0) |
360
+ File::FNM_PATHNAME
361
+
362
+ paths.select do |path|
363
+ path.meta_info['handler'] == name ||
364
+ patterns.any? {|pat| Webgen::Path.matches_pattern?(path, pat, options)}
365
+ end.sort {|a,b| a.path <=> b.path}
366
+ end
367
+ private :paths_for_handler
368
+
369
+ # Prepare everything to create nodes from the path using the given handler. After the nodes are
370
+ # created, it is checked if they have all needed properties.
371
+ #
372
+ # Returns an array with all created nodes.
373
+ def create_nodes_with_path_handler(path, handler) #:yields: path
374
+ *data = instance(handler).parse_meta_info!(path)
375
+
376
+ (path.meta_info.delete('versions') || {'default' => {}}).map do |name, mi|
377
+ vpath = path.dup
378
+ (mi ||= {})['version'] ||= name
379
+ vpath.meta_info.merge!(mi)
380
+ vpath.meta_info['dest_path'] ||= '<parent><basename>(-<version>)(.<lang>)<ext>'
381
+ @website.logger.debug do
382
+ "Creating node version '#{vpath['version']}' from path <#{vpath}> with #{handler} handler"
383
+ end
384
+ @website.blackboard.dispatch_msg(:before_node_created, vpath)
385
+ instance(handler).create_nodes(vpath, *data)
386
+ end.flatten.compact.each do |node|
387
+ @website.blackboard.dispatch_msg(:after_node_created, node)
388
+ end
389
+ rescue Webgen::Error => e
390
+ e.path = path.to_s if e.path.to_s.empty?
391
+ e.location = instance(handler).class.name unless e.location
392
+ raise
393
+ rescue Exception => e
394
+ raise Webgen::NodeCreationError.new(e, instance(handler).class.name, path)
395
+ end
396
+ private :create_nodes_with_path_handler
397
+
398
+ end
399
+
400
+ end
@@ -0,0 +1,220 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/path_handler'
4
+ require 'webgen/error'
5
+ require 'webgen/node'
6
+ require 'webgen/path'
7
+
8
+ module Webgen
9
+ class PathHandler
10
+
11
+ # This module provides the helper methods needed by most, if not all, path handlers.
12
+ #
13
+ # == About
14
+ #
15
+ # It provides default implementations of all methods expected by Webgen::PathHandler except
16
+ # #create_nodes, namely #initialize, #parse_meta_info! and #content.
17
+ #
18
+ # The most important method used when implementing a path handler is probably #create_node which
19
+ # should be used in #create_nodes to create an actual Webgen::Node object from a Webgen::Path
20
+ # object.
21
+ #
22
+ # The following utility methods are also provided:
23
+ #
24
+ # * #parent_node
25
+ # * #dest_path
26
+ # * #node_exists?
27
+ #
28
+ module Base
29
+
30
+ # Initialize the path handler with the given Website object.
31
+ def initialize(website)
32
+ @website = website
33
+ end
34
+
35
+ # Return +nil+ as content of the given +node+.
36
+ #
37
+ # Should probably be over-written by path handler classes using this module!
38
+ def content(node)
39
+ end
40
+
41
+ # Update +path.meta_info+ with meta information found in the content of the path.
42
+ #
43
+ # This default +parse_meta_info!+ method does nothing and should be overridden in path
44
+ # handlers that know that additional meta information can be found in the content of the path
45
+ # itself.
46
+ #
47
+ # Note that the return values of this method are given as extra parameters to the
48
+ # #create_nodes method. If you don't handle extra parameters, return an empty array.
49
+ def parse_meta_info!(path)
50
+ []
51
+ end
52
+
53
+ # Create a node from +path+, if possible, yield the full initialized node if a block is given
54
+ # and return it.
55
+ #
56
+ # If no node can be created (e.g. when 'path.meta_info['draft']' is set), +nil+ is returned.
57
+ #
58
+ # The parent node under which the new node should be created can optionally be specified via
59
+ # 'path.meta_info['parent_alcn']'. This meta information has to be set to an alcn of an
60
+ # existing node.
61
+ #
62
+ # On the created node, the node information +:path+ is set to the given path and
63
+ # +:path_handler+ to the path handler instance.
64
+ def create_node(path)
65
+ return nil if path.meta_info['draft']
66
+ parent = parent_node(path)
67
+ dest_path = self.dest_path(parent, path)
68
+
69
+ if node = node_exists?(path, dest_path)
70
+ node_path = node.node_info[:path]
71
+ if node_path != path
72
+ raise Webgen::NodeCreationError.new("Another node <#{node}> with the same alcn or destination path already exists")
73
+ elsif node_path.meta_info == path.meta_info
74
+ return node
75
+ else
76
+ node.tree.delete_node(node)
77
+ end
78
+ end
79
+
80
+ if !path.meta_info['modified_at'].kind_of?(Time)
81
+ @website.logger.debug do
82
+ "Meta information 'modified_at' set to current time in <#{path}> since its value #{path.meta_info['modified_at'].inspect} was of type #{path.meta_info['modified_at'].class}"
83
+ end
84
+ path.meta_info['modified_at'] = Time.now
85
+ end
86
+
87
+ node = Webgen::Node.new(parent, path.cn, dest_path, path.meta_info)
88
+ node.node_info[:path] = path
89
+ node.node_info[:path_handler] = self
90
+
91
+ yield(node) if block_given?
92
+ node
93
+ end
94
+ protected :create_node
95
+
96
+ # Return the parent node for the given +path+.
97
+ def parent_node(path)
98
+ parent_alcn = path.meta_info['parent_alcn'] ||
99
+ (path.parent_path == '' ? '' : Webgen::Path.new(path.parent_path).alcn)
100
+ if !(parent = @website.tree[parent_alcn])
101
+ raise Webgen::NodeCreationError.new("The needed parent node <#{parent_alcn}> does not exist")
102
+ end
103
+ parent
104
+ end
105
+ protected :parent_node
106
+
107
+ # Construct the destination path for the given +path+ and +parent+ node.
108
+ #
109
+ # See the user documentation for how a destination path is constructed and which configuration
110
+ # options are used!
111
+ #
112
+ # First it is checked if a node with the constructed destination path already exists. If it
113
+ # exists, the language part is forced to be in the destination path and the resulting
114
+ # destination path is returned.
115
+ def dest_path(parent, path)
116
+ dpath = construct_dest_path(parent, path, false)
117
+ if (node = node_exists?(path, dpath)) && node.lang != path.meta_info['lang']
118
+ dpath = construct_dest_path(parent, path, true)
119
+ end
120
+ dpath
121
+ end
122
+ protected :dest_path
123
+
124
+ DEST_PATH_SEGMENTS = /<.*?>|\(.*?\)/ # :nodoc:
125
+ DEST_PATH_PARENT_SEGMENTS = /<parent(-?\d+)(?:..(-?\d+))?>/
126
+
127
+ # Construct the destination path from the parent node and the path.
128
+ def construct_dest_path(parent, path, force_lang_part)
129
+ unless path.meta_info['dest_path'].kind_of?(String)
130
+ raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', must be a string")
131
+ end
132
+ dest_path = path.meta_info['dest_path'].dup
133
+
134
+ if dest_path.start_with?('webgen:')
135
+ dest_path.gsub!(/^webgen:/, '')
136
+ elsif dest_path !~ /^[\w+.-]+:/
137
+ parent = parent.parent while parent.is_fragment?
138
+ parent_segments = parent.dest_path.split('/')[1..-1] || []
139
+ use_lang_part = if path.meta_info['lang'].nil? # unlocalized files never get a lang in the filename!
140
+ false
141
+ elsif force_lang_part
142
+ true
143
+ elsif @website.config['path_handler.lang_code_in_dest_path'] == 'except_default'
144
+ @website.config['website.lang'] != path.meta_info['lang']
145
+ else
146
+ @website.config['path_handler.lang_code_in_dest_path']
147
+ end
148
+ use_version_part = if @website.config['path_handler.version_in_dest_path'] == 'except_default'
149
+ path.meta_info['version'] != 'default'
150
+ else
151
+ @website.config['path_handler.version_in_dest_path']
152
+ end
153
+
154
+ replace_segment = lambda do |match|
155
+ case match
156
+ when DEST_PATH_PARENT_SEGMENTS
157
+ nr1 = adjust_index($1.to_i)
158
+ (nr2 = adjust_index($2.to_i)) if $2
159
+ [parent_segments[nr2 ? nr1..nr2 : nr1]].flatten.compact.join('/')
160
+ when "<parent>"
161
+ parent.dest_path
162
+ when "<basename>"
163
+ path.basename
164
+ when "<ext>"
165
+ path.ext.empty? ? '' : '.' << path.ext
166
+ when "<lang>"
167
+ use_lang_part ? path.meta_info['lang'] : ''
168
+ when "<version>"
169
+ use_version_part ? path.meta_info['version'] : ''
170
+ when /<(year|month|day)>/
171
+ ctime = path.meta_info['created_at']
172
+ if !ctime.kind_of?(Time)
173
+ raise Webgen::NodeCreationError.new("Invalid meta info 'created_at', needed for destination path creation")
174
+ end
175
+ ctime.send($1).to_s.rjust(2, '0')
176
+ when /\((.*)\)/
177
+ inner = $1
178
+ replaced = inner.gsub(DEST_PATH_SEGMENTS, &replace_segment)
179
+ removed = inner.gsub(DEST_PATH_SEGMENTS, "")
180
+ replaced == removed ? '' : replaced
181
+ else
182
+ raise Webgen::NodeCreationError.new("Unknown destination path segment name: #{match}")
183
+ end
184
+ end
185
+ dest_path.gsub!(DEST_PATH_SEGMENTS, &replace_segment)
186
+ dest_path += '/' if path.path =~ /\/$/
187
+ dest_path.gsub!(/\/\/+/, '/')
188
+ end
189
+
190
+ dest_path
191
+ end
192
+ private :construct_dest_path
193
+
194
+ # Consider the number +index+ to be 1-based and convert it to a 0-based index needed for Ruby
195
+ # arrays.
196
+ #
197
+ # An error is raised if the index is equal to 0.
198
+ def adjust_index(index)
199
+ if index > 0
200
+ index - 1
201
+ elsif index == 0
202
+ raise Webgen::NodeCreationError.new("Invalid meta info 'dest_path', index into parent segments must not be 0")
203
+ else
204
+ index
205
+ end
206
+ end
207
+ private :adjust_index
208
+
209
+ # Check if the node alcn or the destination path, which would be created by #create_node for
210
+ # the given paths, exists.
211
+ def node_exists?(path, dest_path)
212
+ @website.tree[path.alcn] || (!path.meta_info['no_output'] && @website.tree[dest_path, :dest_path])
213
+ end
214
+ protected :node_exists?
215
+
216
+ end
217
+
218
+ end
219
+
220
+ end