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.
- data/API.rdoc +143 -0
- data/AUTHORS +0 -1
- data/COPYING +17 -8
- data/ChangeLog +4456 -0
- data/GPL +623 -289
- data/README.md +71 -0
- data/Rakefile +87 -99
- data/VERSION +1 -1
- data/bin/webgen +1 -7
- data/data/webgen/basic_website_template/ext/init.rb +15 -0
- data/data/webgen/basic_website_template/webgen.config +18 -0
- data/data/webgen/bundle_template_files/README.md.erb +24 -0
- data/data/webgen/bundle_template_files/Rakefile.erb +36 -0
- data/data/webgen/bundle_template_files/info.yaml.erb +16 -0
- data/data/webgen/bundle_template_files/init.rb.erb +1 -0
- data/data/webgen/passive_sources/default.metainfo +32 -0
- data/data/webgen/passive_sources/stylesheets/coderay-default.css +109 -118
- data/data/webgen/passive_sources/templates/feed.template +62 -0
- data/data/webgen/passive_sources/templates/sitemap.template +3 -6
- data/data/webgen/passive_sources/templates/tag.template +42 -0
- data/data/webgen/website_bundles/default/README +2 -2
- data/lib/webgen/blackboard.rb +15 -51
- data/lib/webgen/bundle/built-in-show-changes/init.rb +54 -0
- data/lib/webgen/bundle/built-in/init.rb +366 -0
- data/lib/webgen/bundle_loader.rb +126 -0
- data/lib/webgen/cache.rb +9 -18
- data/lib/webgen/cli.rb +131 -58
- data/lib/webgen/cli/bundle_command.rb +30 -0
- data/lib/webgen/cli/create_bundle_command.rb +46 -0
- data/lib/webgen/cli/create_command.rb +48 -60
- data/lib/webgen/cli/generate_command.rb +25 -0
- data/lib/webgen/cli/install_bundle_command.rb +34 -0
- data/lib/webgen/cli/list_bundle_command.rb +108 -0
- data/lib/webgen/cli/logger.rb +45 -0
- data/lib/webgen/cli/show_command.rb +30 -0
- data/lib/webgen/cli/show_config_command.rb +63 -0
- data/lib/webgen/cli/show_dependencies_command.rb +103 -0
- data/lib/webgen/cli/show_extensions_command.rb +74 -0
- data/lib/webgen/cli/utils.rb +68 -95
- data/lib/webgen/configuration.rb +143 -105
- data/lib/webgen/content_processor.rb +160 -0
- data/lib/webgen/content_processor/blocks.rb +96 -0
- data/lib/webgen/content_processor/builder.rb +25 -0
- data/lib/webgen/content_processor/erb.rb +25 -0
- data/lib/webgen/content_processor/erubis.rb +31 -0
- data/lib/webgen/content_processor/fragments.rb +82 -0
- data/lib/webgen/content_processor/haml.rb +25 -0
- data/lib/webgen/content_processor/html_head.rb +157 -0
- data/lib/webgen/content_processor/kramdown.rb +49 -0
- data/lib/webgen/content_processor/maruku.rb +39 -0
- data/lib/webgen/content_processor/r_discount.rb +21 -0
- data/lib/webgen/content_processor/rdoc.rb +22 -0
- data/lib/webgen/content_processor/redcloth.rb +23 -0
- data/lib/webgen/content_processor/ruby.rb +20 -0
- data/lib/webgen/content_processor/sass.rb +145 -0
- data/lib/webgen/content_processor/scss.rb +23 -0
- data/lib/webgen/content_processor/tags.rb +30 -0
- data/lib/webgen/content_processor/tidy.rb +32 -0
- data/lib/webgen/content_processor/tikz.rb +116 -0
- data/lib/webgen/content_processor/xmllint.rb +31 -0
- data/lib/webgen/context.rb +57 -29
- data/lib/webgen/context/html_head.rb +60 -0
- data/lib/webgen/context/nodes.rb +32 -27
- data/lib/webgen/context/rendering.rb +39 -0
- data/lib/webgen/context/webgen_tags.rb +25 -0
- data/lib/webgen/core_ext.rb +25 -0
- data/lib/webgen/destination.rb +151 -0
- data/lib/webgen/destination/file_system.rb +62 -0
- data/lib/webgen/error.rb +59 -49
- data/lib/webgen/extension_manager.rb +121 -0
- data/lib/webgen/item_tracker.rb +237 -0
- data/lib/webgen/item_tracker/file.rb +39 -0
- data/lib/webgen/item_tracker/missing_node.rb +61 -0
- data/lib/webgen/item_tracker/node_content.rb +40 -0
- data/lib/webgen/item_tracker/node_meta_info.rb +53 -0
- data/lib/webgen/item_tracker/nodes.rb +92 -0
- data/lib/webgen/logger.rb +26 -82
- data/lib/webgen/node.rb +122 -367
- data/lib/webgen/node_finder.rb +336 -0
- data/lib/webgen/page.rb +48 -85
- data/lib/webgen/path.rb +218 -156
- data/lib/webgen/path_handler.rb +400 -0
- data/lib/webgen/path_handler/base.rb +220 -0
- data/lib/webgen/path_handler/copy.rb +78 -0
- data/lib/webgen/path_handler/directory.rb +21 -0
- data/lib/webgen/path_handler/feed.rb +82 -0
- data/lib/webgen/path_handler/meta_info.rb +84 -0
- data/lib/webgen/path_handler/page.rb +38 -0
- data/lib/webgen/path_handler/page_utils.rb +79 -0
- data/lib/webgen/path_handler/sitemap.rb +52 -0
- data/lib/webgen/path_handler/template.rb +96 -0
- data/lib/webgen/path_handler/virtual.rb +85 -0
- data/lib/webgen/{webgentask.rb → rake_task.rb} +31 -27
- data/lib/webgen/source.rb +106 -24
- data/lib/webgen/source/file_system.rb +41 -0
- data/lib/webgen/source/stacked.rb +49 -53
- data/lib/webgen/source/tar_archive.rb +59 -0
- data/lib/webgen/tag.rb +250 -19
- data/lib/webgen/tag/breadcrumb_trail.rb +65 -0
- data/lib/webgen/tag/coderay.rb +32 -35
- data/lib/webgen/tag/date.rb +9 -9
- data/lib/webgen/tag/execute_command.rb +31 -0
- data/lib/webgen/tag/include_file.rb +32 -0
- data/lib/webgen/tag/langbar.rb +31 -47
- data/lib/webgen/tag/link.rb +17 -18
- data/lib/webgen/tag/menu.rb +27 -189
- data/lib/webgen/tag/meta_info.rb +31 -0
- data/lib/webgen/tag/relocatable.rb +48 -39
- data/lib/webgen/tag/tikz.rb +24 -100
- data/lib/webgen/task.rb +99 -0
- data/lib/webgen/task/create_bundle.rb +73 -0
- data/lib/webgen/task/create_website.rb +94 -0
- data/lib/webgen/task/generate_website.rb +47 -0
- data/lib/webgen/test_helper.rb +183 -0
- data/lib/webgen/tree.rb +95 -46
- data/lib/webgen/utils.rb +39 -0
- data/lib/webgen/utils/external_command.rb +27 -0
- data/lib/webgen/utils/tag_parser.rb +124 -0
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/website.rb +134 -296
- data/setup.rb +1 -1
- data/test/test_documentation.rb +43 -0
- data/test/webgen/cli/test_logger.rb +41 -0
- data/test/{test_contentprocessor_blocks.rb → webgen/content_processor/test_blocks.rb} +30 -28
- data/test/webgen/content_processor/test_builder.rb +25 -0
- data/test/webgen/content_processor/test_erb.rb +21 -0
- data/test/webgen/content_processor/test_erubis.rb +33 -0
- data/test/webgen/content_processor/test_fragments.rb +96 -0
- data/test/webgen/content_processor/test_haml.rb +24 -0
- data/test/webgen/content_processor/test_html_head.rb +78 -0
- data/test/webgen/content_processor/test_kramdown.rb +49 -0
- data/test/webgen/content_processor/test_maruku.rb +30 -0
- data/test/webgen/content_processor/test_r_discount.rb +18 -0
- data/test/webgen/content_processor/test_rdoc.rb +18 -0
- data/test/webgen/content_processor/test_redcloth.rb +23 -0
- data/test/webgen/content_processor/test_ruby.rb +24 -0
- data/test/webgen/content_processor/test_sass.rb +44 -0
- data/test/webgen/content_processor/test_scss.rb +23 -0
- data/test/webgen/content_processor/test_tags.rb +44 -0
- data/test/webgen/content_processor/test_tidy.rb +31 -0
- data/test/webgen/content_processor/test_tikz.rb +33 -0
- data/test/webgen/content_processor/test_xmllint.rb +32 -0
- data/test/webgen/destination/test_file_system.rb +54 -0
- data/test/webgen/item_tracker/test_file.rb +31 -0
- data/test/webgen/item_tracker/test_missing_node.rb +70 -0
- data/test/webgen/item_tracker/test_node_content.rb +42 -0
- data/test/webgen/item_tracker/test_node_meta_info.rb +44 -0
- data/test/webgen/item_tracker/test_nodes.rb +61 -0
- data/test/webgen/path_handler/test_base.rb +153 -0
- data/test/webgen/path_handler/test_copy.rb +56 -0
- data/test/webgen/path_handler/test_feed.rb +85 -0
- data/test/webgen/path_handler/test_meta_info.rb +98 -0
- data/test/webgen/path_handler/test_page.rb +25 -0
- data/test/webgen/path_handler/test_page_utils.rb +59 -0
- data/test/webgen/path_handler/test_sitemap.rb +95 -0
- data/test/webgen/path_handler/test_template.rb +64 -0
- data/test/webgen/path_handler/test_virtual.rb +87 -0
- data/test/webgen/source/test_file_system.rb +51 -0
- data/test/webgen/source/test_stacked.rb +35 -0
- data/test/{test_source_tararchive.rb → webgen/source/test_tar_archive.rb} +10 -25
- data/test/webgen/tag/test_breadcrumb_trail.rb +66 -0
- data/test/webgen/tag/test_coderay.rb +34 -0
- data/test/webgen/tag/test_date.rb +18 -0
- data/test/webgen/tag/test_execute_command.rb +36 -0
- data/test/webgen/tag/test_include_file.rb +35 -0
- data/test/webgen/tag/test_langbar.rb +50 -0
- data/test/webgen/tag/test_link.rb +40 -0
- data/test/webgen/tag/test_menu.rb +61 -0
- data/test/webgen/tag/test_meta_info.rb +25 -0
- data/test/webgen/tag/test_relocatable.rb +50 -0
- data/test/webgen/tag/test_tikz.rb +41 -0
- data/test/webgen/task/test_create_website.rb +46 -0
- data/test/webgen/test_blackboard.rb +31 -0
- data/test/webgen/test_bundle_loader.rb +55 -0
- data/test/{test_cache.rb → webgen/test_cache.rb} +3 -15
- data/test/webgen/test_cli.rb +41 -0
- data/test/webgen/test_configuration.rb +131 -0
- data/test/webgen/test_content_processor.rb +86 -0
- data/test/webgen/test_context.rb +73 -0
- data/test/webgen/test_core_ext.rb +20 -0
- data/test/webgen/test_destination.rb +48 -0
- data/test/webgen/test_error.rb +121 -0
- data/test/webgen/test_extension_manager.rb +70 -0
- data/test/webgen/test_item_tracker.rb +106 -0
- data/test/{test_languages.rb → webgen/test_languages.rb} +4 -4
- data/test/webgen/test_logger.rb +46 -0
- data/test/webgen/test_node.rb +178 -0
- data/test/webgen/test_node_finder.rb +127 -0
- data/test/{test_page.rb → webgen/test_page.rb} +44 -48
- data/test/webgen/test_path.rb +271 -0
- data/test/{test_webgentask.rb → webgen/test_rake_task.rb} +4 -4
- data/test/webgen/test_source.rb +59 -0
- data/test/webgen/test_tag.rb +137 -0
- data/test/webgen/test_task.rb +40 -0
- data/test/webgen/test_tree.rb +147 -0
- data/test/webgen/test_utils.rb +16 -0
- data/test/webgen/test_website.rb +45 -0
- data/test/webgen/utils/test_tag_parser.rb +99 -0
- metadata +292 -344
- data/data/webgen/passive_sources/templates/atom_feed.template +0 -39
- data/data/webgen/passive_sources/templates/rss_feed.template +0 -28
- data/data/webgen/resources.yaml +0 -4
- data/data/webgen/webgui/app.rb +0 -11
- data/data/webgen/webgui/controller/main.rb +0 -135
- data/data/webgen/webgui/layout/default.xhtml +0 -40
- data/data/webgen/webgui/overrides/win32console.rb +0 -0
- data/data/webgen/webgui/public/css/jquery.autocomplete.css +0 -50
- data/data/webgen/webgui/public/css/ramaze_error.css +0 -90
- data/data/webgen/webgui/public/css/style.css +0 -55
- data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
- data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
- data/data/webgen/webgui/public/js/jquery.autocomplete.js +0 -15
- data/data/webgen/webgui/public/js/jquery.js +0 -32
- data/data/webgen/webgui/start.rb +0 -9
- data/data/webgen/webgui/view/create_website.xhtml +0 -14
- data/data/webgen/webgui/view/error.xhtml +0 -64
- data/data/webgen/webgui/view/index.xhtml +0 -22
- data/data/webgen/webgui/view/manage_website.xhtml +0 -18
- data/data/webgen/website_skeleton/README +0 -10
- data/data/webgen/website_skeleton/Rakefile +0 -69
- data/data/webgen/website_skeleton/config.yaml +0 -35
- data/data/webgen/website_skeleton/ext/init.rb +0 -10
- data/doc/contentprocessor.template +0 -11
- data/doc/contentprocessor/blocks.page +0 -129
- data/doc/contentprocessor/builder.page +0 -79
- data/doc/contentprocessor/erb.page +0 -60
- data/doc/contentprocessor/erubis.page +0 -46
- data/doc/contentprocessor/fragments.page +0 -26
- data/doc/contentprocessor/haml.page +0 -46
- data/doc/contentprocessor/head.page +0 -31
- data/doc/contentprocessor/kramdown.page +0 -49
- data/doc/contentprocessor/less.page +0 -34
- data/doc/contentprocessor/maruku.page +0 -44
- data/doc/contentprocessor/rdiscount.page +0 -37
- data/doc/contentprocessor/rdoc.page +0 -36
- data/doc/contentprocessor/redcloth.page +0 -41
- data/doc/contentprocessor/sass.page +0 -31
- data/doc/contentprocessor/scss.page +0 -39
- data/doc/contentprocessor/tags.page +0 -73
- data/doc/contentprocessor/tidy.page +0 -14
- data/doc/contentprocessor/xmllint.page +0 -14
- data/doc/extensions.metainfo +0 -29
- data/doc/extensions.page +0 -15
- data/doc/extensions.template +0 -17
- data/doc/faq.page +0 -222
- data/doc/getting_started.page +0 -135
- data/doc/index.page +0 -71
- data/doc/manual.page +0 -727
- data/doc/reference_configuration.page +0 -1254
- data/doc/reference_metainfo.page +0 -265
- data/doc/reference_website_styles.page +0 -32
- data/doc/source/filesystem.page +0 -41
- data/doc/source/tararchive.page +0 -40
- data/doc/sourcehandler.template +0 -23
- data/doc/sourcehandler/copy.page +0 -19
- data/doc/sourcehandler/directory.page +0 -27
- data/doc/sourcehandler/feed.page +0 -102
- data/doc/sourcehandler/metainfo.page +0 -48
- data/doc/sourcehandler/page.page +0 -14
- data/doc/sourcehandler/sitemap.page +0 -46
- data/doc/sourcehandler/template.page +0 -45
- data/doc/sourcehandler/virtual.page +0 -49
- data/doc/tag.template +0 -25
- data/doc/tag/breadcrumbtrail.page +0 -40
- data/doc/tag/coderay.page +0 -53
- data/doc/tag/date.page +0 -31
- data/doc/tag/executecommand.page +0 -26
- data/doc/tag/includefile.page +0 -32
- data/doc/tag/langbar.page +0 -47
- data/doc/tag/link.page +0 -44
- data/doc/tag/menu.page +0 -109
- data/doc/tag/metainfo.page +0 -29
- data/doc/tag/relocatable.page +0 -38
- data/doc/tag/sitemap.page +0 -31
- data/doc/tag/tikz.page +0 -159
- data/doc/upgrading.page +0 -138
- data/doc/webgen_page_format.page +0 -129
- data/doc/website_styles.metainfo +0 -8
- data/lib/webgen/cli/apply_command.rb +0 -66
- data/lib/webgen/cli/run_command.rb +0 -22
- data/lib/webgen/cli/webgui_command.rb +0 -68
- data/lib/webgen/common.rb +0 -27
- data/lib/webgen/common/sitemap.rb +0 -83
- data/lib/webgen/contentprocessor.rb +0 -117
- data/lib/webgen/contentprocessor/blocks.rb +0 -92
- data/lib/webgen/contentprocessor/builder.rb +0 -29
- data/lib/webgen/contentprocessor/erb.rb +0 -26
- data/lib/webgen/contentprocessor/erubis.rb +0 -39
- data/lib/webgen/contentprocessor/fragments.rb +0 -25
- data/lib/webgen/contentprocessor/haml.rb +0 -34
- data/lib/webgen/contentprocessor/head.rb +0 -128
- data/lib/webgen/contentprocessor/kramdown.rb +0 -27
- data/lib/webgen/contentprocessor/kramdown/html.rb +0 -36
- data/lib/webgen/contentprocessor/less.rb +0 -35
- data/lib/webgen/contentprocessor/maruku.rb +0 -36
- data/lib/webgen/contentprocessor/rdiscount.rb +0 -19
- data/lib/webgen/contentprocessor/rdoc.rb +0 -20
- data/lib/webgen/contentprocessor/redcloth.rb +0 -21
- data/lib/webgen/contentprocessor/sass.rb +0 -22
- data/lib/webgen/contentprocessor/scss.rb +0 -22
- data/lib/webgen/contentprocessor/tags.rb +0 -170
- data/lib/webgen/contentprocessor/tidy.rb +0 -38
- data/lib/webgen/contentprocessor/xmllint.rb +0 -37
- data/lib/webgen/context/render.rb +0 -32
- data/lib/webgen/context/tags.rb +0 -20
- data/lib/webgen/coreext.rb +0 -13
- data/lib/webgen/default_config.rb +0 -240
- data/lib/webgen/loggable.rb +0 -25
- data/lib/webgen/output.rb +0 -86
- data/lib/webgen/output/filesystem.rb +0 -69
- data/lib/webgen/source/filesystem.rb +0 -61
- data/lib/webgen/source/resource.rb +0 -45
- data/lib/webgen/source/tararchive.rb +0 -78
- data/lib/webgen/sourcehandler.rb +0 -275
- data/lib/webgen/sourcehandler/base.rb +0 -281
- data/lib/webgen/sourcehandler/copy.rb +0 -44
- data/lib/webgen/sourcehandler/directory.rb +0 -30
- data/lib/webgen/sourcehandler/feed.rb +0 -92
- data/lib/webgen/sourcehandler/fragment.rb +0 -70
- data/lib/webgen/sourcehandler/memory.rb +0 -42
- data/lib/webgen/sourcehandler/metainfo.rb +0 -128
- data/lib/webgen/sourcehandler/page.rb +0 -64
- data/lib/webgen/sourcehandler/sitemap.rb +0 -60
- data/lib/webgen/sourcehandler/template.rb +0 -66
- data/lib/webgen/sourcehandler/virtual.rb +0 -117
- data/lib/webgen/tag/base.rb +0 -170
- data/lib/webgen/tag/breadcrumbtrail.rb +0 -70
- data/lib/webgen/tag/executecommand.rb +0 -31
- data/lib/webgen/tag/includefile.rb +0 -42
- data/lib/webgen/tag/metainfo.rb +0 -27
- data/lib/webgen/tag/sitemap.rb +0 -41
- data/lib/webgen/websiteaccess.rb +0 -31
- data/lib/webgen/websitemanager.rb +0 -125
- data/misc/default.css +0 -403
- data/misc/default.template +0 -76
- data/misc/htmldoc.metainfo +0 -26
- data/misc/htmldoc.virtual +0 -17
- data/misc/images/arrow.gif +0 -0
- data/misc/images/error.png +0 -0
- data/misc/images/headerbg.jpg +0 -0
- data/misc/images/important.png +0 -0
- data/misc/images/information.png +0 -0
- data/misc/images/quote.gif +0 -0
- data/misc/images/warning.png +0 -0
- data/misc/logo.svg +0 -313
- data/misc/style.page +0 -33
- data/test/helper.rb +0 -61
- data/test/test_blackboard.rb +0 -60
- data/test/test_cli.rb +0 -119
- data/test/test_common_sitemap.rb +0 -58
- data/test/test_configuration.rb +0 -68
- data/test/test_contentprocessor.rb +0 -39
- data/test/test_contentprocessor_builder.rb +0 -41
- data/test/test_contentprocessor_erb.rb +0 -33
- data/test/test_contentprocessor_erubis.rb +0 -62
- data/test/test_contentprocessor_fragments.rb +0 -43
- data/test/test_contentprocessor_haml.rb +0 -39
- data/test/test_contentprocessor_head.rb +0 -96
- data/test/test_contentprocessor_kramdown.rb +0 -56
- data/test/test_contentprocessor_less.rb +0 -40
- data/test/test_contentprocessor_maruku.rb +0 -33
- data/test/test_contentprocessor_rdiscount.rb +0 -21
- data/test/test_contentprocessor_rdoc.rb +0 -22
- data/test/test_contentprocessor_redcloth.rb +0 -26
- data/test/test_contentprocessor_sass.rb +0 -28
- data/test/test_contentprocessor_scss.rb +0 -28
- data/test/test_contentprocessor_tags.rb +0 -122
- data/test/test_contentprocessor_tidy.rb +0 -34
- data/test/test_contentprocessor_xmllint.rb +0 -38
- data/test/test_context.rb +0 -81
- data/test/test_error.rb +0 -93
- data/test/test_loggable.rb +0 -32
- data/test/test_logger.rb +0 -94
- data/test/test_node.rb +0 -469
- data/test/test_output_filesystem.rb +0 -60
- data/test/test_path.rb +0 -241
- data/test/test_source_filesystem.rb +0 -76
- data/test/test_source_resource.rb +0 -28
- data/test/test_source_stacked.rb +0 -49
- data/test/test_sourcehandler_base.rb +0 -136
- data/test/test_sourcehandler_copy.rb +0 -47
- data/test/test_sourcehandler_directory.rb +0 -38
- data/test/test_sourcehandler_feed.rb +0 -88
- data/test/test_sourcehandler_fragment.rb +0 -70
- data/test/test_sourcehandler_main.rb +0 -39
- data/test/test_sourcehandler_memory.rb +0 -44
- data/test/test_sourcehandler_metainfo.rb +0 -127
- data/test/test_sourcehandler_page.rb +0 -73
- data/test/test_sourcehandler_sitemap.rb +0 -68
- data/test/test_sourcehandler_template.rb +0 -68
- data/test/test_sourcehandler_virtual.rb +0 -106
- data/test/test_tag_base.rb +0 -62
- data/test/test_tag_breadcrumbtrail.rb +0 -91
- data/test/test_tag_coderay.rb +0 -45
- data/test/test_tag_date.rb +0 -18
- data/test/test_tag_executecommand.rb +0 -41
- data/test/test_tag_includefile.rb +0 -50
- data/test/test_tag_langbar.rb +0 -71
- data/test/test_tag_link.rb +0 -70
- data/test/test_tag_menu.rb +0 -207
- data/test/test_tag_metainfo.rb +0 -26
- data/test/test_tag_relocatable.rb +0 -60
- data/test/test_tag_sitemap.rb +0 -47
- data/test/test_tag_tikz.rb +0 -69
- data/test/test_tree.rb +0 -70
- data/test/test_website.rb +0 -130
- data/test/test_websiteaccess.rb +0 -25
- 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
|