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,336 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/path'
4
+
5
+ module Webgen
6
+
7
+ # Used for finding nodes that match certain criterias.
8
+ #
9
+ # == About
10
+ #
11
+ # This extension class is used for finding nodes that match certain criterias (all nodes are used
12
+ # if no filter options are specified) when calling the #find method. There are some built-in
13
+ # filters but one can also provide custom filters via #add_filter_module.
14
+ #
15
+ # The found nodes are either returned in a flat list or hierarchical in nested lists (if a node
16
+ # has no child nodes, only the node itself is used; otherwise a two element array containing the
17
+ # node and child nodes is used). Sorting, limiting the number of returned nodes and using an
18
+ # offset are also possible.
19
+ #
20
+ # *Note* that results are cached in the volatile cache of the Cache instance!
21
+ #
22
+ # == Finder options
23
+ #
24
+ # Following is the list of all finder options. Note that there may also be other 3rd party node
25
+ # filters available if you are using extension bundles!
26
+ #
27
+ # === Non-filter options
28
+ #
29
+ # These options are not used for filtering out nodes but provide additional functionality.
30
+ #
31
+ # [:limit]
32
+ # Value: an integer. Specifies the maximum number of nodes that should be returned. Implies
33
+ # 'flatten = true'.
34
+ #
35
+ # Note that fewer nodes may be returned if fewer nodes match the filter criterias.
36
+ #
37
+ # [:offset]
38
+ # Value: an integer. Specifies how many nodes from the front of the list should *not* be
39
+ # returned. Implies 'flatten = true'.
40
+ #
41
+ # [:flatten]
42
+ # Value: anything except +nil+ or +false+. A flat list of nodes is returned if this option is
43
+ # set, otherwise the nodes are returned in their correct hierarchical order using nested lists.
44
+ #
45
+ # Note that any missing nodes in the hierarchy are automatically added so that traversing the
46
+ # hierarchy is always possible. For example, if we have the tree '/a/b/c' and only nodes +a+ and
47
+ # +c+ are found, node +b+ is automatically added.
48
+ #
49
+ # [:sort]
50
+ # Value: +nil+/+false+, +true+ or a meta information key. If +nil+ or +false+ is specified, no
51
+ # sorting is performed. If +true+ is specified, the meta information +sort_info+ (or if absent,
52
+ # the meta information +title+) is used for sorting. If the compared values are both integers, a
53
+ # numeric comparison is done, else a string comparison. If a meta information key is specified,
54
+ # the value of this meta information is used for comparison of nodes (again, if both compared
55
+ # values are integers, a numeric comparison is done, else a string comparison).
56
+ #
57
+ # === Filter options
58
+ #
59
+ # These options are used for filtering the nodes. All nodes are used by default if no filter
60
+ # options are specified.
61
+ #
62
+ # [:alcn]
63
+ # Value: an alcn pattern or an array of alcn patterns. Nodes that match any of the patterns are
64
+ # used.
65
+ #
66
+ # [:lang]
67
+ # Value: a language code/+nil+/the special value :+node+ or an array of these values. Nodes that
68
+ # have one of the specified language codes, are language independent (in case of the value
69
+ # +nil+) or have the same language as the reference node (in case of the value :+node+) are
70
+ # used.
71
+ #
72
+ # [:mi]
73
+ # Value: a hash with meta information key to value mappings. Only nodes that have the same
74
+ # values for all meta information keys are used.
75
+ #
76
+ # [:or]
77
+ # Value: a finder option set or an array of finder options sets (specifying option set names is
78
+ # also possible). Nodes that appear in any specified option set are additionally used.
79
+ #
80
+ # [:and]
81
+ # Value: a finder option set or an array of finder options sets (specifying option set names is
82
+ # also possible). Only nodes that appear in all specified option sets are used.
83
+ #
84
+ # [:not]
85
+ # Value: a finder option set or an array of finder options sets (specifying option set names is
86
+ # also possible). Only nodes that do not appear in any specified option set are used.
87
+ #
88
+ # [:levels]
89
+ # Value: one integer (is used as start and end level) or an array with two integers (the start
90
+ # and end levels). All nodes whose hierarchy levels are greater than or equal to the start level
91
+ # and lower than or equal to the end level are used.
92
+ #
93
+ # [:ancestors]
94
+ # Value: +true+ or +false+/+nil+. If this filter option is set to +true+, only nodes that are
95
+ # ancestors of the reference node are used. The reference node itself is used as well.
96
+ #
97
+ # [:descendants]
98
+ # Value: +true+ or +false+/+nil+. If this filter option is set to +true+, only nodes that are
99
+ # descendants of the reference node are used. The reference node itself is used as well.
100
+ #
101
+ # [:siblings]
102
+ # Value: +true+ or +false+/+nil+. If this filter option is set to +true+, only nodes that are
103
+ # siblings of the reference are node used. The reference node itself is used as well.
104
+ #
105
+ # == Implementing a filter module
106
+ #
107
+ # Implementing a filter module is very easy. Just create a module that contains your filter
108
+ # methods and tell the NodeFinder object about it using the #add_filter_module method. A filter
109
+ # method needs to take three arguments: an array of nodes, the reference node and the filter
110
+ # value.
111
+ #
112
+ # Here is a sample filter module which provides the ability to filter nodes based on the meta
113
+ # information key +category+. The +category+ key contains an array with one or more categories.
114
+ # The value for this category filter is one or more strings and the filter returns those nodes
115
+ # that contain at least one specified category.
116
+ #
117
+ # module CategoryFilter
118
+ #
119
+ # def filter_on_category(nodes, ref_node, categories)
120
+ # categories = [categories].flatten # needed in case categories is a string
121
+ # nodes.select {|n| categories.any? {|c| n['category'].include?(c)}}
122
+ # end
123
+ #
124
+ # end
125
+ #
126
+ # website.ext.node_finder.add_filter_module(CategoryFilter, category: 'filter_on_category')
127
+ #
128
+ class NodeFinder
129
+
130
+ # Create a new NodeFinder object for the given website.
131
+ def initialize(website)
132
+ @website = website
133
+ @mapping = {
134
+ :alcn => :filter_alcn, :levels => :filter_levels, :lang => :filter_lang,
135
+ :and => :filter_and, :or => :filter_or, :not => :filter_not,
136
+ :ancestors => :filter_ancestors, :descendants => :filter_descendants,
137
+ :siblings => :filter_siblings,
138
+ :mi => :filter_meta_info
139
+ }
140
+ end
141
+
142
+ # Add a module with filter methods.
143
+ #
144
+ # The parameter +mapping+ needs to be a hash associating unique names with the methods of the
145
+ # given module that can be used as finder methods.
146
+ #
147
+ # === Examples:
148
+ #
149
+ # node_finder.add_filter_module(MyModule, blog: 'filter_on_blog')
150
+ #
151
+ def add_filter_module(mod, mapping)
152
+ public_methods = mod.public_instance_methods.map {|c| c.to_s}
153
+ mapping.each do |name, method|
154
+ if !public_methods.include?(method.to_s)
155
+ raise ArgumentError, "Finder method '#{method}' not found in module #{mod}"
156
+ end
157
+ @mapping[name.intern] = method
158
+ end
159
+ extend(mod)
160
+ end
161
+
162
+ # Return all nodes that match certain criterias.
163
+ #
164
+ # The parameter +opts_or_name+ can either be a hash with finder options or the name of a finder
165
+ # option set defined using the configuration option 'node_finder.options_sets'. The node
166
+ # +ref_node+ is used as reference node.
167
+ def find(opts_or_name, ref_node)
168
+ if result = cached_result(opts_or_name, ref_node)
169
+ return result
170
+ end
171
+ opts = prepare_options_hash(opts_or_name)
172
+
173
+ limit, offset, flatten, sort = remove_non_filter_options(opts)
174
+ flatten = true if limit || offset
175
+
176
+ nodes = filter_nodes(opts, ref_node)
177
+
178
+ if flatten
179
+ sort_nodes(nodes, sort)
180
+ nodes = nodes[(offset.to_s.to_i)..(limit ? offset.to_s.to_i + limit.to_s.to_i - 1 : -1)] if limit || offset
181
+ else
182
+ result = {}
183
+ min_level = 1_000_000
184
+ nodes.each {|n| min_level = n.level if n.level < min_level}
185
+
186
+ nodes.each do |n|
187
+ hierarchy_nodes = []
188
+ (hierarchy_nodes.unshift(n); n = n.parent) while n.level >= min_level
189
+ hierarchy_nodes.inject(result) {|memo, hn| memo[hn] ||= {}}
190
+ end
191
+
192
+ reducer = lambda do |h|
193
+ h.map {|k,v| v.empty? ? k : [k, reducer.call(v)]}
194
+ end
195
+ nodes = reducer.call(result)
196
+ sort_nodes(nodes, sort, false)
197
+ end
198
+
199
+ cache_result(opts_or_name, ref_node, nodes)
200
+ end
201
+
202
+ #######
203
+ private
204
+ #######
205
+
206
+ def cached_result(opts, ref_node)
207
+ (@website.cache.volatile[:node_finder] ||= {})[[opts, ref_node.alcn]]
208
+ end
209
+
210
+ def cache_result(opts, ref_node, result)
211
+ (@website.cache.volatile[:node_finder] ||= {})[[opts, ref_node.alcn]] = result
212
+ end
213
+
214
+ def prepare_options_hash(opts_or_name)
215
+ if Hash === opts_or_name
216
+ opts_or_name.symbolize_keys
217
+ elsif @website.config['node_finder.option_sets'].has_key?(opts_or_name)
218
+ @website.config['node_finder.option_sets'][opts_or_name].symbolize_keys
219
+ else
220
+ raise ArgumentError, "Invalid argument supplied, expected Hash or name of search definition, not #{opts_or_name}"
221
+ end
222
+ end
223
+
224
+ def remove_non_filter_options(opts)
225
+ [opts.delete(:limit), opts.delete(:offset), opts.delete(:flatten), opts.delete(:sort)]
226
+ end
227
+
228
+ def filter_nodes(opts, ref_node)
229
+ nodes = @website.tree.node_access[:alcn].values
230
+ nodes.delete(@website.tree.dummy_root)
231
+
232
+ opts.each do |filter, value|
233
+ if @mapping.has_key?(filter)
234
+ nodes = send(@mapping[filter], nodes, ref_node, value)
235
+ else
236
+ @website.logger.warn { "Ignoring unknown node finder filter '#{filter}'" }
237
+ end
238
+ end
239
+
240
+ nodes
241
+ end
242
+
243
+ def sort_nodes(nodes, sort, flat_mode = true)
244
+ return unless sort
245
+ if sort == true
246
+ nodes.sort! do |(a,_),(b,_)|
247
+ a = (a['sort_info'] && a['sort_info'].to_s) || a['title'].to_s || ''
248
+ b = (b['sort_info'] && b['sort_info'].to_s) || b['title'].to_s || ''
249
+ (a = a.to_i; b = b.to_i) if a !~ /\D/ && b !~ /\D/
250
+ a <=> b
251
+ end
252
+ else
253
+ nodes.sort! do |(a,_),(b,_)|
254
+ a, b = a[sort].to_s, b[sort].to_s
255
+ a, b = a.to_i, b.to_i if a !~ /\D/ && b !~ /\D/
256
+ a <=> b
257
+ end
258
+ end
259
+ nodes.each {|n, children| sort_nodes(children, sort, flat_mode) if children } unless flat_mode
260
+ end
261
+
262
+ # :section: Filter methods
263
+
264
+ def filter_and(nodes, ref_node, opts)
265
+ [opts].flatten.each do |cur_opts|
266
+ cur_opts = prepare_options_hash(cur_opts)
267
+ remove_non_filter_options(cur_opts)
268
+ nodes &= filter_nodes(cur_opts, ref_node)
269
+ end
270
+ nodes
271
+ end
272
+
273
+ def filter_or(nodes, ref_node, opts)
274
+ [opts].flatten.each do |cur_opts|
275
+ cur_opts = prepare_options_hash(cur_opts)
276
+ remove_non_filter_options(cur_opts)
277
+ nodes |= filter_nodes(cur_opts, ref_node)
278
+ end
279
+ nodes
280
+ end
281
+
282
+ def filter_not(nodes, ref_node, opts)
283
+ [opts].flatten.each do |cur_opts|
284
+ cur_opts = prepare_options_hash(cur_opts)
285
+ remove_non_filter_options(cur_opts)
286
+ nodes -= filter_nodes(cur_opts, ref_node)
287
+ end
288
+ nodes
289
+ end
290
+
291
+ def filter_meta_info(nodes, ref_node, mi)
292
+ nodes.keep_if {|n| mi.all? {|key, val| n[key] == val}}
293
+ end
294
+
295
+ def filter_alcn(nodes, ref_node, alcn)
296
+ alcn = [alcn].flatten.map {|a| Webgen::Path.append(ref_node.alcn, a.to_s)}
297
+ nodes.keep_if {|n| alcn.any? {|a| n =~ a}}
298
+ end
299
+
300
+ def filter_levels(nodes, ref_node, range)
301
+ range = [range].flatten.map {|i| i.to_i}
302
+ nodes.keep_if {|n| n.level >= range.first && n.level <= range.last}
303
+ end
304
+
305
+ def filter_lang(nodes, ref_node, langs)
306
+ langs = [langs].flatten.map {|l| l == :node ? ref_node.lang : l}.uniq
307
+ nodes.keep_if {|n| langs.any? {|l| n.lang == l}}
308
+ end
309
+
310
+ def filter_ancestors(nodes, ref_node, enabled)
311
+ return nodes unless enabled
312
+ nodes = []
313
+ node = ref_node
314
+ until node == node.tree.dummy_root
315
+ nodes.unshift(node)
316
+ node = node.parent
317
+ end
318
+ nodes
319
+ end
320
+
321
+ def filter_descendants(nodes, ref_node, enabled)
322
+ return nodes unless enabled
323
+ nodes.keep_if do |n|
324
+ n = n.parent while n != n.tree.dummy_root && n != ref_node
325
+ n == ref_node
326
+ end
327
+ end
328
+
329
+ def filter_siblings(nodes, ref_node, enabled)
330
+ return nodes unless enabled
331
+ nodes.keep_if { |n| n.parent == ref_node.parent}
332
+ end
333
+
334
+ end
335
+
336
+ end
data/lib/webgen/page.rb CHANGED
@@ -1,95 +1,49 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'yaml'
4
+ require 'webgen/error'
4
5
 
5
6
  module Webgen
6
7
 
7
- # A Page object wraps a meta information hash and an array of Block objects. It is normally
8
- # generated from a file or string in Webgen Page Format using the provided class methods.
8
+ # A Page object wraps a meta information hash and a hash of {block name => block content}
9
+ # associations.
10
+ #
11
+ # It is normally generated from a file or string in Webgen Page Format using the provided class
12
+ # methods.
9
13
  class Page
10
14
 
11
- # A single block within a Page object. The content of the block can be rendered using the #render method.
12
- class Block
13
-
14
- # The name of the block.
15
- attr_reader :name
16
-
17
- # The content of the block.
18
- attr_reader :content
19
-
20
- # The options set specifically for this block.
21
- attr_reader :options
22
-
23
- # Create a new block with the name +name+ and the given +content+ and +options+.
24
- def initialize(name, content, options)
25
- @name, @content, @options = name, content, options
26
- end
27
-
28
- # Render the block using the provided context object.
29
- #
30
- # The context object needs to respond to <tt>#[]</tt> and <tt>#[]=</tt> (e.g. a Hash is a valid
31
- # context object) and the key <tt>:processors</tt> needs to contain a Hash which maps processor
32
- # names to processor objects that respond to <tt>#call</tt>.
33
- #
34
- # Uses the content processors specified in the +pipeline+ key of the +options+ attribute to do
35
- # the actual rendering.
36
- #
37
- # Returns the given context with the rendered content.
38
- def render(context)
39
- context[:content] = @content.dup
40
- context[:block] = self
41
- @options['pipeline'].to_s.split(/,/).each do |processor|
42
- raise "No such content processor available: #{processor}" unless context[:processors].has_key?(processor)
43
- context[:processors][processor].call(context)
44
- end
45
- context
46
- end
47
-
48
- end
49
-
50
-
51
15
  # Raised during parsing of data in Webgen Page Format if the data is invalid.
52
- class FormatError < StandardError; end
16
+ class FormatError < Error; end
53
17
 
54
18
 
55
19
  # :stopdoc:
56
- RE_META_INFO_START = /\A---\s*(?:\n|\r|\r\n)/m
57
- RE_META_INFO = /\A---\s*(?:\n|\r|\r\n).*?(?:\n|\r|\r\n)(?=---.*?(?:\n|\r|\r\n)|\Z)/m
58
- RE_BLOCKS_OPTIONS = /^--- *?(?: *((?:\w+:[^\s]* *)*))?$|^$/
59
- RE_BLOCKS_START = /^--- .*?$|^--- *$/
60
- RE_BLOCKS = /(?:(#{RE_BLOCKS_START})|\A)\n?(.*?)(?:(?=#{RE_BLOCKS_START})|\z)/m
20
+ RE_NEWLINE = /\r?\n/
21
+ RE_META_INFO_START = /\A---\s*#{RE_NEWLINE}/
22
+ RE_META_INFO = /#{RE_META_INFO_START}.*?#{RE_NEWLINE}(?=---.*?#{RE_NEWLINE}|\Z)/m
23
+ RE_BLOCKS_START_SIMPLE = /^--- (\w+)(?:\s*| -+\s*)$|^$/
24
+ RE_BLOCKS_START_COMPLEX = /^--- *?(?: *((?:\w+:[^\s]* *)*))?-*\s*$|^$/
25
+ RE_BLOCKS_START = /^---(?: .*?|)(?=#{RE_NEWLINE})/
26
+ RE_BLOCKS = /(?:(#{RE_BLOCKS_START})|\A)#{RE_NEWLINE}?(.*?)(?:(?=#{RE_BLOCKS_START})|\z)/m
27
+ RE_PAGE = /(#{RE_META_INFO})?(.*)/m
61
28
  # :startdoc:
62
29
 
63
30
  class << self
64
31
 
65
- # Parse the given string +data+ in Webgen Page Format and initialize a new Page object with
66
- # the information. The +meta_info+ parameter can be used to provide default meta information.
67
- def from_data(data, meta_info = {})
68
- md = /(#{RE_META_INFO})?(.*)/m.match(normalize_eol(data))
69
- meta_info = meta_info.merge(parse_meta_info(md[1], data))
32
+ # Parse the given string +data+ in Webgen Page Format.
33
+ #
34
+ # This method returns a Page object containing the hash with the meta information and the
35
+ # parsed blocks.
36
+ def from_data(data)
37
+ md = RE_PAGE.match(data)
38
+ meta_info = parse_meta_info(md[1], data =~ RE_META_INFO_START)
70
39
  blocks = parse_blocks(md[2] || '', meta_info)
71
40
  new(meta_info, blocks)
72
41
  end
73
42
 
74
- # Parse the given string +data+ in Webgen Page Format and return the found meta information.
75
- def meta_info_from_data(data)
76
- md = /(#{RE_META_INFO})?/m.match(normalize_eol(data))
77
- parse_meta_info(md[1], data)
78
- end
79
-
80
- #######
81
- private
82
- #######
83
-
84
- # Normalize the end-of-line encodings to Unix style.
85
- def normalize_eol(data)
86
- data.gsub(/\r\n?/, "\n")
87
- end
88
-
89
43
  # Parse the meta info string in +mi_data+ and return the hash with the meta information. The
90
44
  # original +data+ is used for checking the validness of the meta information block.
91
- def parse_meta_info(mi_data, data)
92
- if mi_data.nil? && data =~ RE_META_INFO_START
45
+ def parse_meta_info(mi_data, has_mi_start)
46
+ if mi_data.nil? && has_mi_start
93
47
  raise FormatError, 'Found start line for meta information block but no valid meta information block'
94
48
  elsif mi_data.nil?
95
49
  {}
@@ -99,39 +53,48 @@ module Webgen
99
53
  unless meta_info.kind_of?(Hash)
100
54
  raise FormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
101
55
  end
102
- rescue ArgumentError => e
56
+ rescue ArgumentError, SyntaxError => e
103
57
  raise FormatError, "Invalid YAML syntax in meta information block: #{e.message}"
104
58
  end
105
59
  meta_info
106
60
  end
107
61
  end
62
+ private :parse_meta_info
108
63
 
109
- # Parse all blocks in +data+ and return them. Meta information can be provided in +meta_info+
110
- # which is used for setting the block names and options.
64
+ # Parse all blocks in +data+ and return them.
65
+ #
66
+ # The key 'blocks' of the meta information hash is updated with information found on block
67
+ # starting lines.
111
68
  def parse_blocks(data, meta_info)
112
69
  scanned = data.scan(RE_BLOCKS)
113
70
  raise(FormatError, 'No content blocks specified') if scanned.length == 0
114
71
 
115
72
  blocks = {}
116
73
  scanned.each_with_index do |block_data, index|
74
+ index += 1
117
75
  options, content = *block_data
118
- md = RE_BLOCKS_OPTIONS.match(options.to_s)
119
- raise(FormatError, "Found invalid blocks starting line for block #{index+1}: #{options}") if content =~ /\A---/ || md.nil?
120
- options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, (v == '' ? nil : YAML::load(v))]}.flatten]
121
- options = (meta_info['blocks']['default'] || {} rescue {}).
122
- merge((meta_info['blocks'][index+1] || {} rescue {})).
123
- merge(options)
124
-
125
- name = options.delete('name') || (index == 0 ? 'content' : 'block' + (index + 1).to_s)
126
- raise(FormatError, "Previously used name '#{name}' also used for block #{index+1}") if blocks.has_key?(name)
76
+ if md = RE_BLOCKS_START_SIMPLE.match(options.to_s)
77
+ options = {'name' => md[1]}
78
+ else
79
+ md = RE_BLOCKS_START_COMPLEX.match(options.to_s)
80
+ raise(FormatError, "Found invalid blocks starting line for block #{index}: #{options}") if content =~ /\A---/ || md.nil?
81
+ options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, (v == '' ? nil : YAML::load(v))]}.flatten]
82
+ end
83
+
84
+ name = options.delete('name') || (index == 1 ? 'content' : 'block' + (index).to_s)
85
+ raise(FormatError, "Previously used name '#{name}' also used for block #{index}") if blocks.has_key?(name)
127
86
  content ||= ''
128
87
  content.gsub!(/^(\\+)(---.*?)$/) {|m| "\\" * ($1.length / 2) + $2}
129
- content.chomp!("\n") unless index + 1 == scanned.length
130
- blocks[name] = blocks[index+1] = Block.new(name, content, options)
88
+ content.chomp! unless index == scanned.length
89
+
90
+ blocks[name] = content
91
+ ((meta_info['blocks'] ||= {})[name] ||= {}).merge!(options) unless options.empty?
131
92
  end
132
- meta_info.delete('blocks')
93
+ meta_info['blocks'].delete_if {|k,v| v.empty?} if meta_info.has_key?('blocks')
94
+ meta_info.delete('blocks') if meta_info.has_key?('blocks') && meta_info['blocks'].empty?
133
95
  blocks
134
96
  end
97
+ private :parse_blocks
135
98
 
136
99
  end
137
100