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,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/cli/utils'
4
+
5
+ module Webgen
6
+ module CLI
7
+
8
+ # The CLI command for showing all available options.
9
+ class ShowConfigCommand < CmdParse::Command
10
+
11
+ def initialize # :nodoc:
12
+ super('config', false, false, true)
13
+ self.short_desc = 'Show available configuration options'
14
+ self.description = Utils.format_command_desc(<<DESC)
15
+ Shows all available configuration options. The option name and default value as
16
+ well as the currently used value are displayed.
17
+
18
+ If the global verbosity option is set, option descriptions are additionally
19
+ displayed.
20
+
21
+ If an argument is given, only those options that have the argument in their name
22
+ are displayed.
23
+
24
+ Hint: A debug message will appear at the top of the output if this command is run
25
+ in the context of a website, there are unknown configuration options in the
26
+ configuration file and the log level is set to debug.
27
+ DESC
28
+ self.options = CmdParse::OptionParserWrapper.new do |opts|
29
+ opts.separator "Options:"
30
+ opts.on("-m", "--modified",
31
+ *Utils.format_option_desc("Show modified configuration options only")) do |v|
32
+ @modified = true
33
+ end
34
+ end
35
+ @modified = false
36
+ @unknown = true
37
+ end
38
+
39
+ def execute(args) # :nodoc:
40
+ config = commandparser.website.config
41
+ selector = args.first.to_s
42
+ config.options.select do |n, d|
43
+ n.include?(selector) && (!@modified || config[n] != d.default)
44
+ end.sort.each do |name, data|
45
+ format_config_option(name, data, config[name])
46
+ end
47
+ end
48
+
49
+ def format_config_option(name, data, cur_val)
50
+ print("#{Utils.light(Utils.blue(name))}: ")
51
+ if cur_val != data.default
52
+ puts(Utils.green(cur_val.to_s) + " (default: #{data.default})")
53
+ else
54
+ puts(cur_val.inspect)
55
+ end
56
+ puts(Utils.format(data.description, 78, 2, true).join("\n") + "\n\n") if commandparser.verbose
57
+ end
58
+ private :format_config_option
59
+
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,103 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/cli/utils'
4
+
5
+ module Webgen
6
+ module CLI
7
+
8
+ # The CLI command for showing dependencies (tracked items) of paths.
9
+ class ShowDependenciesCommand < CmdParse::Command
10
+
11
+ def initialize # :nodoc:
12
+ super('deps', false, false, true)
13
+ self.short_desc = 'Show dependencies for all paths'
14
+ self.description = Utils.format_command_desc(<<DESC)
15
+ Shows the dependencies (i.e. tracked items) for each path. This is only useful
16
+ after webgen has generated the website at least once so that this information
17
+ is available.
18
+
19
+ If an argument is given, only those paths that have the argument in their name
20
+ are displayed with their dependencies.
21
+
22
+ Hint: The global verbosity option enables additional output.
23
+ DESC
24
+ end
25
+
26
+ def execute(args) # :nodoc:
27
+ cache = commandparser.website.cache[:item_tracker_data]
28
+ if cache.nil?
29
+ puts "No data available, you need to generate the website first!"
30
+ return
31
+ end
32
+ arg = args.shift
33
+
34
+ data = cache[:node_dependencies]
35
+ data = data.select {|alcn, _| alcn.include?(arg) } if arg
36
+ data.sort.each do |alcn, deps|
37
+ deps = deps.sort {|a,b| a.first <=> b.first }.map do |uid|
38
+ method = "format_#{uid.first}"
39
+ if respond_to?(method, true)
40
+ send(method, alcn, uid, cache[:item_data][uid])
41
+ else
42
+ unknown_uid(uid)
43
+ end
44
+ end.compact
45
+
46
+ if deps.length > 0 || commandparser.verbose
47
+ puts("#{Utils.light(Utils.blue(alcn))}: ")
48
+ deps.each {|d| puts(" #{[d].flatten.join("\n ")}")}
49
+ end
50
+ end
51
+ end
52
+
53
+ def unknown_uid(uid)
54
+ uid.first.to_s
55
+ end
56
+ private :unknown_uid
57
+
58
+ def format_node_meta_info(alcn, uid, data)
59
+ dep_alcn, key = *uid.last
60
+ return if alcn == dep_alcn && !commandparser.verbose
61
+
62
+ if key.nil?
63
+ "Any meta info from <#{dep_alcn}>"
64
+ else
65
+ "Meta info key '#{key}' from <#{dep_alcn}>"
66
+ end
67
+ end
68
+ private :format_node_meta_info
69
+
70
+ def format_node_content(alcn, uid, data)
71
+ dep_alcn = uid.last
72
+ return if alcn == dep_alcn && !commandparser.verbose
73
+
74
+ "Content from node <#{dep_alcn}>"
75
+ end
76
+ private :format_node_content
77
+
78
+ def format_file(alcn, uid, data)
79
+ "Content from file '#{uid.last}'"
80
+ end
81
+ private :format_file
82
+
83
+ def format_missing_node(alcn, uid, data)
84
+ path, lang = *uid.last
85
+
86
+ "Missing acn, alcn or dest path <#{path}>" << (lang.nil? ? '' : " in language '#{lang}'")
87
+ end
88
+ private :format_missing_node
89
+
90
+ def format_nodes(alcn, uid, data)
91
+ method, _, type = *uid.last
92
+
93
+ res = [(type == :content ? "Content" : "Meta info") + " from these nodes"]
94
+ res.first << " (result of #{[method].flatten.join('.')})" if commandparser.verbose
95
+ res.first << ":"
96
+ res += data.flatten
97
+ end
98
+ private :format_nodes
99
+
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,74 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/cli/utils'
4
+
5
+ module Webgen
6
+ module CLI
7
+
8
+ # The CLI command for showing available extension.
9
+ class ShowExtensionsCommand < CmdParse::Command
10
+
11
+ def initialize # :nodoc:
12
+ super('extensions', false, false, true)
13
+ self.short_desc = 'Show available extensions'
14
+ self.description = Utils.format_command_desc(<<DESC)
15
+ Shows all available extensions and additional information about them, e.g. a
16
+ short summary of the functionality or the extension bundle it is defined in.
17
+
18
+ If an argument is given, only those extensions that have the argument in their
19
+ name are displayed.
20
+
21
+ Hint: The global verbosity option enables additional output.
22
+ DESC
23
+ self.options = CmdParse::OptionParserWrapper.new do |opts|
24
+ opts.separator "Options:"
25
+ opts.on("-b NAME", "--bundle NAME", String,
26
+ *Utils.format_option_desc("Only show extensions of this bundle")) do |bundle|
27
+ @bundle = bundle
28
+ end
29
+ end
30
+ @bundle = nil
31
+ end
32
+
33
+ def execute(args) # :nodoc:
34
+ exts = {}
35
+ commandparser.website.ext.bundles.each do |bundle, info_file|
36
+ next if info_file.nil? || (@bundle && @bundle != bundle)
37
+ infos = YAML.load(File.read(info_file))
38
+ next unless infos['extensions']
39
+ infos['extensions'].each do |n, d|
40
+ d['bundle'] = bundle
41
+ d['author'] ||= infos['author']
42
+ end
43
+ exts.update(infos['extensions'])
44
+ end
45
+
46
+ selector = args.first.to_s
47
+ exts.select {|n, d| n.include?(selector)}.sort.each do |name, data|
48
+ format_extension_info(name, data, !selector.empty?)
49
+ end
50
+ end
51
+
52
+ def format_extension_info(name, data, has_selector)
53
+ author = (!data['author'] || data['author'].empty? ? 'unknown' : data['author'])
54
+
55
+ indentation = (has_selector ? 0 : name.count('.')*2)
56
+ puts(" "*indentation + Utils.light(Utils.blue(name)))
57
+ if commandparser.verbose
58
+ print(" "*(indentation + 2) + "Bundle: ")
59
+ puts(Utils.format(data['bundle'], 78, indentation + 11, false))
60
+ print(" "*(indentation + 2) + "Author: ")
61
+ puts(Utils.format(author, 78, indentation + 11, false))
62
+ print(" "*(indentation + 2) + "Summary: ")
63
+ puts(Utils.format(data['summary'], 78, indentation + 11, false))
64
+ else
65
+ puts(Utils.format(data['summary'], 78, indentation + 2, true).join("\n"))
66
+ end
67
+ puts
68
+ end
69
+ private :format_extension_info
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -2,119 +2,92 @@
2
2
 
3
3
  require 'rbconfig'
4
4
 
5
- module Webgen::CLI
5
+ module Webgen
6
6
 
7
- # Provides methods for other CLI classes for formatting text in a consistent manner.
8
- class Utils
7
+ module CLI
9
8
 
10
- USE_ANSI_COLORS = Config::CONFIG['host_os'] !~ /mswin|mingw/
11
- DEFAULT_WIDTH = if Config::CONFIG['host_os'] =~ /mswin|mingw/
12
- 72
13
- else
14
- ((size = %x{stty size 2>/dev/null}).length > 0 && (size = size.split.last.to_i) > 0 ? size : 72) rescue 72
15
- end
9
+ # Provides methods for CLI classes for formatting text in a consistent manner.
10
+ module Utils
16
11
 
17
- module Color
12
+ class << self; attr_accessor :use_colors; end
13
+ @use_colors = $stdout.tty? && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/
18
14
 
19
- @@colors = {:bold => [0, 1], :green => [0, 32], :lred => [1, 31], :reset => [0, 0]}
15
+ DEFAULT_WIDTH = 80
20
16
 
21
- @@colors.each do |color, values|
22
- module_eval <<-EOF
23
- def Color.#{color.to_s}(text = nil)
24
- "\e[#{values[0]};#{values[1]}m" + (text.nil? ? '' : text + self.reset)
25
- end
26
- EOF
27
- end
17
+ module Color # :nodoc:
28
18
 
29
- end
19
+ @@colors = {:bold => [1], :light => [1], :green => [32], :yellow => [33], :red => [31], :blue => [34], :reset => [0]}
30
20
 
21
+ @@colors.each do |color, values|
22
+ module_eval("def Color.#{color.to_s}(text = nil);" <<
23
+ "'\e[#{values.join(';')}m' << (text.nil? ? '' : text + self.reset); end")
24
+ end
31
25
 
32
- # Used for dynamically formatting the text (setting color, bold face, ...).
33
- def self.method_missing(id, text = nil)
34
- if USE_ANSI_COLORS && Color.respond_to?(id)
35
- Color.send(id, text.to_s)
36
- else
37
- text.to_s
38
26
  end
39
- end
40
27
 
41
- # Return an array of lines which represents the text in +content+ formatted sothat no line is
42
- # longer than +width+ characters. The +indent+ parameter specifies the amount of spaces
43
- # prepended to each line. If +first_line_indented+ is +true+, then the first line is indented.
44
- def self.format(content, indent = 0, first_line_indented = false, width = DEFAULT_WIDTH)
45
- content = (content || '').dup
46
- length = width - indent
47
-
48
- paragraphs = content.split(/\n\n/)
49
- if (0..1) === paragraphs.length
50
- pattern = /^(.{0,#{length}})[ \n]/m
51
- lines = []
52
- while content.length > length
53
- if content =~ pattern
54
- str = $1
55
- len = $&.length
56
- else
57
- str = content[0, length]
58
- len = length
59
- end
60
- lines << (lines.empty? && !first_line_indented ? '' : ' '*indent) + str.gsub(/\n/, ' ')
61
- content.slice!(0, len)
28
+
29
+ # Used for dynamically formatting the text (setting color, bold face, ...).
30
+ #
31
+ # The +id+ (method name) can be one of the following: bold, light, green, yellow, red, blue,
32
+ # reset.
33
+ def self.method_missing(id, text = nil)
34
+ if self.use_colors && Color.respond_to?(id)
35
+ Color.send(id, text)
36
+ else
37
+ text.to_s
62
38
  end
63
- lines << (lines.empty? && !first_line_indented ? '' : ' '*indent) + content.gsub(/\n/, ' ') unless content.strip.empty?
64
- lines
65
- else
66
- ((format(paragraphs.shift, indent, first_line_indented, width) << '') +
67
- paragraphs.collect {|p| format(p, indent, true, width) << '' }).flatten[0..-2]
68
39
  end
69
- end
70
40
 
71
- # Return a headline with the given +text+ and amount of +indent+.
72
- def self.headline(text, indent = 2)
73
- ' '*indent + "#{bold(text)}"
74
- end
75
-
76
- # Return a section header with the given +text+ formatted in the given +color+ and indented
77
- # according to +indent+. The whole text is also left justified to the column specified with
78
- # +ljustlength+.
79
- def self.section(text, ljustlength = 0, indent = 4, color = :green)
80
- ' '*indent + "#{send(color, text)}".ljust(ljustlength - indent + send(color).length)
81
- end
82
-
83
- # Creates a listing of the key-value pairs of +hash+ under a section called +name+.
84
- def self.hash_output(name, hash)
85
- ljust = 20
86
- puts section('Name', ljust) + "#{lred(name)}"
41
+ # Format the command description.
42
+ #
43
+ # Returns an array of Strings.
44
+ #
45
+ # See Utils.format for more information.
46
+ def self.format_command_desc(desc)
47
+ format(desc, 76)
48
+ end
87
49
 
88
- hash.sort_by {|k,v| k.to_s }.each do |name, value|
89
- next unless value.respond_to?(:to_str)
90
- desc = format(value.to_str, ljust)
91
- puts section(name.to_s.capitalize, ljust) + desc.shift
92
- desc.each {|line| puts line}
50
+ # Format the option description.
51
+ #
52
+ # Returns an array of Strings.
53
+ #
54
+ # See Utils.format for more information.
55
+ def self.format_option_desc(desc)
56
+ format(desc, 48)
93
57
  end
94
- puts
95
- end
96
58
 
97
- # Tries to match +name+ to a unique bundle name of the WebsiteManager +wm+. If this can not be
98
- # done, it is checked whether +name+ is actually a valid bundle URL and if so, the URL source is
99
- # added to the bundles of +wm+.
100
- #
101
- # Returns the correct bundle name or raises an error.
102
- def self.match_bundle_name(wm, name)
103
- matches = wm.bundles.keys.select {|k| k =~ /#{Regexp.escape(name)}/}
104
- if matches.size > 1
105
- raise ArgumentError.new("#{name} matches more than one bundle: #{matches.join(", ")}")
106
- elsif matches.size == 0
107
- begin
108
- source = Webgen::Source::TarArchive.new(name)
109
- wm.add_source(source, 'custom-URL-source')
110
- name = 'custom-URL-source'
111
- rescue
112
- raise ArgumentError.new("#{name} is neither a valid bundle name nor a valid URL")
59
+ # Return an array of lines which represents the text in +content+ formatted so that no line is
60
+ # longer than +width+ characters.
61
+ #
62
+ # The +indent+ parameter specifies the amount of spaces prepended to each line. If
63
+ # +first_line_indented+ is +true+, then the first line is indented.
64
+ def self.format(content, width = DEFAULT_WIDTH, indent = 0, first_line_indented = false)
65
+ content = (content || '').dup
66
+ length = width - indent
67
+
68
+ paragraphs = content.split(/\n\n/)
69
+ if (0..1) === paragraphs.length
70
+ pattern = /^(.{0,#{length}})[ \n]/m
71
+ lines = []
72
+ while content.length > length
73
+ if content =~ pattern
74
+ str = $1
75
+ len = $&.length
76
+ else
77
+ str = content[0, length]
78
+ len = length
79
+ end
80
+ lines << (lines.empty? && !first_line_indented ? '' : ' '*indent) + str.gsub(/\n/, ' ')
81
+ content.slice!(0, len)
82
+ end
83
+ lines << (lines.empty? && !first_line_indented ? '' : ' '*indent) + content.gsub(/\n/, ' ') unless content.strip.empty?
84
+ lines
85
+ else
86
+ ((format(paragraphs.shift, width, indent, first_line_indented) << '') +
87
+ paragraphs.collect {|p| format(p, width, indent, true) << '' }).flatten[0..-2]
113
88
  end
114
- else
115
- name = matches.first
116
89
  end
117
- name
90
+
118
91
  end
119
92
 
120
93
  end
@@ -1,149 +1,187 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require 'yaml'
4
+ require 'webgen/error'
5
+
3
6
  module Webgen
4
7
 
5
8
  # Stores the configuration for a webgen website.
6
9
  #
7
- # Configuration options should be created like this:
10
+ # Configuration options can be created by using the define_option method:
11
+ #
12
+ # config.define_option "my.new.option", 'default value', 'description'
13
+ #
14
+ # and later accessed or set using the accessor methods #[] and #[]=. A validation block can also
15
+ # be specified when defining an option. This validation block is called when a new value should be
16
+ # set and it should return the (possibly changed) value to be set:
8
17
  #
9
- # config.my.new.config 'value', :doc => 'some', :meta => 'info'
18
+ # config.define_option "my.new.option", 'default value', 'description' do |val|
19
+ # raise "Option must be a string" unless val.kind_of?(String)
20
+ # val.upcase
21
+ # end
10
22
  #
11
- # and later accessed or set using the accessor methods #[] and #[]= or a configuration helper.
12
- # These helpers are defined in the Helpers module and provide easier access to complex
13
- # configuration options. Also see the {webgen
14
- # manual}[http://webgen.rubyforge.org/documentation/manual.html#website-configfile] for
15
- # information about the configuration helpers.
23
+ # **Note**: When a Configuration object is dumped (via Marshal), the option validator procs are
24
+ # not dumped and can therefore not be restored.
16
25
  class Configuration
17
26
 
18
- # Helper class for providing an easy method to define configuration options.
19
- class MethodChain
27
+ # Raised by the Webgen::Configuration class.
28
+ class Error < Webgen::Error; end
20
29
 
21
- def initialize(config) #:nodoc:
22
- @config = config
23
- @name = ''
30
+ # Struct class for storing a configuration option.
31
+ Option = Struct.new(:default, :description, :validator) do
32
+ def dupped_default #:nodoc:
33
+ default.dup rescue default
24
34
  end
25
35
 
26
- def method_missing(id, *args) #:nodoc:
27
- @name += (@name.empty? ? '' : '.') + id.id2name.sub(/(!|=)$/,'')
28
- if args.length > 0
29
- value = args.shift
30
- @config.data[@name] = value unless @config.data.has_key?(@name) # value is set only the first time
31
- @config.meta_info[@name] ||= {}
32
- @config.meta_info[@name].update(*args) if args.length > 0
33
- nil
34
- else
35
- self
36
- end
36
+ def ==(other) #:nodoc:
37
+ self.default == other.default
37
38
  end
38
39
 
39
- end
40
-
41
- # This module provides methods for setting more complex configuration options. It is mixed into
42
- # Webgen::Configuration so that its methods can be used. Detailed information on the use of the
43
- # methods can be found in the "User Manual" in the "Configuration File" section.
44
- #
45
- # All public methods defined in this module are available for direct use in the
46
- # configuration file, e.g. the method named +default_meta_info+ can be used like this:
47
- #
48
- # default_meta_info:
49
- # Webgen::SourceHandler::Page:
50
- # in_menu : true
51
- # :action : replace
52
- #
53
- # All methods have to take exactly one argument, a Hash.
54
- #
55
- # The special key <tt>:action</tt> should be used for specifying how the configuration option
56
- # should be set:
57
- #
58
- # [replace] Replace the configuration option with the new values.
59
- # [modify] Replace old values with new values and add missing ones (useful for hashes and
60
- # normally the default value)
61
- module Helpers
62
-
63
- # Set the default meta information for source handlers.
64
- def default_meta_info(args)
65
- args.each do |sh_name, mi|
66
- raise ArgumentError, 'Invalid argument for configuration helper default_meta_info' unless mi.kind_of?(Hash)
67
- action = mi.delete(:action) || 'modify'
68
- mi_hash = (self['sourcehandler.default_meta_info'][complete_source_handler_name(sh_name)] ||= {})
69
- case action
70
- when 'replace' then mi_hash.replace(mi)
71
- else mi_hash.update(mi)
72
- end
73
- end
40
+ def marshal_dump #:nodoc:
41
+ [self.default, self.description]
74
42
  end
75
43
 
76
-
77
- # Set the path patterns used by source handlers.
78
- def patterns(args)
79
- args.each do |sh_name, data|
80
- pattern_arr = (self['sourcehandler.patterns'][complete_source_handler_name(sh_name)] ||= [])
81
- case data
82
- when Array then pattern_arr.replace(data)
83
- when Hash
84
- (data['del'] || []).each {|pat| pattern_arr.delete(pat)}
85
- (data['add'] || []).each {|pat| pattern_arr << pat}
86
- else
87
- raise ArgumentError, 'Invalid argument for configuration helper patterns'
88
- end
89
- end
44
+ def marshal_load(data) #:nodoc:
45
+ self.default = data[0]
46
+ self.description = data[1]
90
47
  end
91
48
 
49
+ end
92
50
 
93
- # Set the default processing pipeline for a source handler.
94
- def default_processing_pipeline(args)
95
- args.each do |sh_name, pipeline|
96
- raise ArgumentError, 'Invalid argument for configuration helper pipeline' unless pipeline.kind_of?(String)
97
- mi_hash = (self['sourcehandler.default_meta_info'][complete_source_handler_name(sh_name)] ||= {})
98
- ((mi_hash['blocks'] ||= {})['default'] ||= {})['pipeline'] = pipeline
99
- end
100
- end
101
51
 
52
+ # Contains all the defined configuration options.
53
+ attr_reader :options
102
54
 
103
- # Complete +sh_name+ by checking if a source handler called
104
- # <tt>Webgen::SourceHandler::SH_NAME</tt> exists.
105
- def complete_source_handler_name(sh_name)
106
- (Webgen::SourceHandler.constants.map {|c| c.to_s}.include?(sh_name) ? 'Webgen::SourceHandler::' + sh_name : sh_name)
107
- end
108
- private :complete_source_handler_name
55
+ # Create a new Configuration object.
56
+ def initialize
57
+ @options = {}
58
+ @values = {}
59
+ end
109
60
 
61
+ def initialize_copy(orig) #:nodoc:
62
+ super
63
+ @options = orig.options.dup
64
+ @values = {}
65
+ orig.instance_eval { @values }.each {|k,v| @values[k] = v.dup rescue v}
110
66
  end
111
67
 
68
+ def clone #:nodoc:
69
+ super
70
+ freeze if frozen?
71
+ end
112
72
 
113
- include Helpers
73
+ def freeze #:nodoc:
74
+ super
75
+ @options.freeze
76
+ @values.each_value {|v| v.freeze}
77
+ @values.freeze
78
+ self
79
+ end
114
80
 
115
- # The hash which stores the meta info for the configuration options.
116
- attr_reader :meta_info
81
+ def ==(other) #:nodoc:
82
+ @options == other.options && @values == other.instance_variable_get(:@values)
83
+ end
117
84
 
118
- # The configuration options hash.
119
- attr_reader :data
85
+ # Define a new option +name+ with a default value of +default+ and the description.
86
+ #
87
+ # If a validation block is provided, it is called with the new value when one is set and should
88
+ # return a (possibly altered) value to be set.
89
+ def define_option(name, default, description, &validator)
90
+ if @options.has_key?(name)
91
+ raise ArgumentError, "Configuration option '#{name}' has already be defined"
92
+ else
93
+ @options[name] = Option.new
94
+ @options[name].default = default.freeze
95
+ @options[name].description = description.freeze
96
+ @options[name].validator = validator.freeze
97
+ @options[name].freeze
98
+ end
99
+ end
120
100
 
121
- # Create a new Configuration object.
122
- def initialize
123
- @data = {}
124
- @meta_info = {}
101
+ # Return +true+ if the given option exists.
102
+ def option?(name)
103
+ @options.has_key?(name)
125
104
  end
126
105
 
127
- # Return the configuration option +name+.
106
+ # Return the value for the configuration option +name+.
128
107
  def [](name)
129
- if @data.has_key?(name)
130
- @data[name]
108
+ if @options.has_key?(name)
109
+ if frozen?
110
+ @values.has_key?(name) ? @values[name] : @options[name].dupped_default
111
+ else
112
+ @values[name] = @options[name].dupped_default unless @values.has_key?(name)
113
+ @values[name]
114
+ end
131
115
  else
132
- raise ArgumentError, "No such configuration option: #{name}"
116
+ raise Error, "Configuration option '#{name}' does not exist"
133
117
  end
134
118
  end
135
119
 
136
- # Set the configuration option +name+ to the provided +value+.
120
+ # Use +value+ as value for the configuration option +name+.
137
121
  def []=(name, value)
138
- if @data.has_key?(name)
139
- @data[name] = value
122
+ if @options.has_key?(name)
123
+ begin
124
+ @values[name] = (@options[name].validator ? @options[name].validator.call(value) : value)
125
+ rescue
126
+ raise Error, "Problem setting configuration option '#{name}': #{$!.message}", $!.backtrace
127
+ end
140
128
  else
141
- raise ArgumentError, "No such configuration option: #{name}"
129
+ raise Error, "Configuration option '#{name}' does not exist"
142
130
  end
143
131
  end
144
132
 
145
- def method_missing(id, *args) #:nodoc:
146
- MethodChain.new(self).method_missing(id, *args)
133
+ # Set the configuration values from the Hash +values+.
134
+ #
135
+ # The hash can either contain full configuration option names or namespaced option names, ie. in
136
+ # YAML format:
137
+ #
138
+ # my.option: value
139
+ #
140
+ # website:
141
+ # lang: en
142
+ # url: my_url
143
+ #
144
+ # The above hash will set the option 'my.option' to +value+, 'website.lang' to +en+ and
145
+ # 'website.url' to +my_url+.
146
+ #
147
+ # Returns an array with all unknown configuration options.
148
+ def set_values(values)
149
+ unknown_options = []
150
+ process = proc do |name, value|
151
+ if @options.has_key?(name)
152
+ self[name] = value
153
+ elsif value.kind_of?(Hash)
154
+ value.each {|k,v| process.call("#{name}.#{k}", v)}
155
+ else
156
+ unknown_options << name
157
+ end
158
+ end
159
+ values.each(&process)
160
+ unknown_options
161
+ end
162
+
163
+ # Load the configuration values.
164
+ #
165
+ # If +filename+ is a String, it is treated as the name of the configuration file from which the
166
+ # values should be loaded. If +filename+ responds to \#read, it is treated as an IO object from
167
+ # which the values should be loaded.
168
+ #
169
+ # The configuration needs to be in YAML format. More specifically, it needs to contain a YAML
170
+ # hash which is further processed by #set_values.
171
+ #
172
+ # Returns an array with all unknown configuration options.
173
+ def load_from_file(filename)
174
+ data = if String === filename || filename.respond_to?(:read)
175
+ begin
176
+ YAML::load(String === filename ? File.read(filename) : filename.read) || {}
177
+ rescue RuntimeError, ArgumentError, SyntaxError => e
178
+ raise Error, "Problem parsing configuration data (it needs to contain a YAML hash): #{e.message}", e.backtrace
179
+ end
180
+ else
181
+ raise ArgumentError, "Need a String or IO object, not a #{filename.class}"
182
+ end
183
+ raise Error, 'Structure of configuration file is invalid, it has to be a Hash' unless data.kind_of?(Hash)
184
+ set_values(data)
147
185
  end
148
186
 
149
187
  end