webgen 0.5.17 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|