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,47 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
require 'webgen/task'
|
|
5
|
+
|
|
6
|
+
module Webgen
|
|
7
|
+
class Task
|
|
8
|
+
|
|
9
|
+
# Generates the website.
|
|
10
|
+
#
|
|
11
|
+
# This can be called the main task of webgen.
|
|
12
|
+
module GenerateWebsite
|
|
13
|
+
|
|
14
|
+
# Main webgen task: Generate the website.
|
|
15
|
+
#
|
|
16
|
+
# Returns +true+ if the website has been successfully generated.
|
|
17
|
+
def self.call(website)
|
|
18
|
+
successful = true
|
|
19
|
+
website.logger.info { "Generating website..." }
|
|
20
|
+
time = Benchmark.measure do
|
|
21
|
+
website.ext.path_handler.populate_tree
|
|
22
|
+
if website.tree.root && !website.tree.root['passive']
|
|
23
|
+
passes = website.ext.path_handler.write_tree
|
|
24
|
+
if passes == 0
|
|
25
|
+
website.logger.info { "Nothing has changed since the last invocation!" }
|
|
26
|
+
else
|
|
27
|
+
website.logger.vinfo do
|
|
28
|
+
"Needed #{passes} pass#{passes == 1 ? '' : 'es'} to generate the website"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
successful = false
|
|
33
|
+
website.logger.info do
|
|
34
|
+
['No active source paths found - maybe not a webgen website?',
|
|
35
|
+
'Change to a website directory and run the command again.']
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
website.logger.info { "... done in " << ('%2.2f' % time.real) << ' seconds' }
|
|
40
|
+
website.save_cache if successful
|
|
41
|
+
successful
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'ostruct'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
require 'webgen/logger'
|
|
8
|
+
|
|
9
|
+
require 'webgen/blackboard'
|
|
10
|
+
require 'webgen/cache'
|
|
11
|
+
require 'webgen/context'
|
|
12
|
+
require 'webgen/page'
|
|
13
|
+
require 'webgen/error'
|
|
14
|
+
require 'webgen/tree'
|
|
15
|
+
require 'webgen/node'
|
|
16
|
+
require 'webgen/path_handler/page_utils'
|
|
17
|
+
require 'webgen/utils'
|
|
18
|
+
|
|
19
|
+
module Webgen
|
|
20
|
+
|
|
21
|
+
module TestHelper
|
|
22
|
+
|
|
23
|
+
# A special subclass of Webgen::Node that is used in testing when a "renderable" node is needed,
|
|
24
|
+
# ie. one that has the necessary info set to be processed via Webgen::PathHandler::PageUtils.
|
|
25
|
+
class RenderNode < Webgen::Node
|
|
26
|
+
|
|
27
|
+
include Webgen::PathHandler::PageUtils
|
|
28
|
+
|
|
29
|
+
def initialize(page_data, parent, cn, dest_path, meta_info = {})
|
|
30
|
+
super(parent, cn, dest_path, meta_info)
|
|
31
|
+
page = Webgen::Page.from_data(page_data)
|
|
32
|
+
self.node_info[:blocks] = page.blocks
|
|
33
|
+
self.meta_info.update(page.meta_info)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def blocks
|
|
37
|
+
super(self)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def render_block(name, context)
|
|
41
|
+
super(self, name, context)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def template_chain
|
|
45
|
+
[self]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Fails if the given block does not raise error_class and the error is not on the line.
|
|
52
|
+
def assert_error_on_line(error_class, line)
|
|
53
|
+
begin
|
|
54
|
+
yield
|
|
55
|
+
rescue error_class => e
|
|
56
|
+
assert_equal(line, (e.respond_to?(:line) ? e.line : Webgen::Error.error_line(e)))
|
|
57
|
+
else
|
|
58
|
+
fail "No exception raised though #{error_class} expected"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Fails if the log string is not empty.
|
|
63
|
+
#
|
|
64
|
+
# Uses the StringIO @logio if no other StringIO is given.
|
|
65
|
+
def assert_nothing_logged(io = @logio)
|
|
66
|
+
assert_equal('', io.string)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Fails if the log string does not match the regular expression.
|
|
70
|
+
#
|
|
71
|
+
# Uses the StringIO @logio if no other StringIO is given and resets the log string after the
|
|
72
|
+
# check.
|
|
73
|
+
def assert_log_match(reg, io = @logio)
|
|
74
|
+
assert_match(reg, io.string)
|
|
75
|
+
@logio.string = ''
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Creates a basic mock website that is accessible via @website with the following methods:
|
|
79
|
+
#
|
|
80
|
+
# [@website.config]
|
|
81
|
+
# The given config object or {} if none specified
|
|
82
|
+
#
|
|
83
|
+
# [@website.directory]
|
|
84
|
+
# Set to a non-existent temporary directory
|
|
85
|
+
#
|
|
86
|
+
# [@website.tmpdir]
|
|
87
|
+
# Set to @website.directory/tmp
|
|
88
|
+
#
|
|
89
|
+
# [@website.ext]
|
|
90
|
+
# OpenStruct instance. The accessor +item_tracker+ is set to an object that responds to +add+.
|
|
91
|
+
#
|
|
92
|
+
# [@website.blackboard]
|
|
93
|
+
# A Webgen::Blackboard instance
|
|
94
|
+
#
|
|
95
|
+
# [@website.logger]
|
|
96
|
+
# Webgen::Logger instance with a StringIO as target. The StringIO target is also available
|
|
97
|
+
# via @logio.
|
|
98
|
+
#
|
|
99
|
+
# [@website.tree]
|
|
100
|
+
# Webgen::Tree instance
|
|
101
|
+
def setup_website(config = {})
|
|
102
|
+
@website = MiniTest::Mock.new
|
|
103
|
+
@website.expect(:config, config)
|
|
104
|
+
directory = Dir::Tmpname.create("test-webgen-website") {|path| raise Errno::EEXIST if File.directory?(path)}
|
|
105
|
+
@website.expect(:directory, directory)
|
|
106
|
+
def (@website).tmpdir(path=''); File.join(self.directory, 'tmp', path); end
|
|
107
|
+
@website.expect(:ext, OpenStruct.new)
|
|
108
|
+
@website.expect(:blackboard, Webgen::Blackboard.new)
|
|
109
|
+
@website.expect(:cache, Webgen::Cache.new)
|
|
110
|
+
@logio = StringIO.new
|
|
111
|
+
@website.expect(:logger, Webgen::Logger.new(@logio))
|
|
112
|
+
@website.expect(:tree, Webgen::Tree.new(@website))
|
|
113
|
+
@website.ext.item_tracker = Object.new
|
|
114
|
+
def (@website.ext.item_tracker).add(*args); end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Adds the following nodes (showing alcn=dest_path, title, other meta info) to the tree which
|
|
118
|
+
# has to be empty:
|
|
119
|
+
#
|
|
120
|
+
# /
|
|
121
|
+
# /file.en.html 'file en' sort_info=3
|
|
122
|
+
# /file.en.html#frag 'frag'
|
|
123
|
+
# /file.en.html#nested 'fragnested'
|
|
124
|
+
# /file.de.html 'file de' sort_info=5
|
|
125
|
+
# /file.de.html#frag 'frag'
|
|
126
|
+
# /other.html 'other'
|
|
127
|
+
# /other.en.html 'other en'
|
|
128
|
+
# /german.de.html 'german' dest_path='/german.other.html'
|
|
129
|
+
# /dir/ 'dir'
|
|
130
|
+
# /dir/subfile.html 'subfile'
|
|
131
|
+
# /dir/subfile.html#frag 'frag'
|
|
132
|
+
# /dir/dir/ 'dir'
|
|
133
|
+
# /dir/dir/file.html 'file'
|
|
134
|
+
# /dir2/ 'dir2' proxy_path='index.html'
|
|
135
|
+
# /dir2/index.en.html 'index en' routed_title='routed en' link_attrs={'class' => 'help'}
|
|
136
|
+
# /dir2/index.de.html 'index de' routed_title='routed de'
|
|
137
|
+
def setup_default_nodes(tree)
|
|
138
|
+
root = Webgen::Node.new(tree.dummy_root, '/', '/')
|
|
139
|
+
|
|
140
|
+
file_en = Webgen::Node.new(root, 'file.html', '/file.en.html', {'lang' => 'en', 'title' => 'file en', 'sort_info' => 3})
|
|
141
|
+
frag_en = Webgen::Node.new(file_en, '#frag', '/file.en.html#frag', {'title' => 'frag'})
|
|
142
|
+
Webgen::Node.new(frag_en, '#nested', '/file.en.html#nested', {'title' => 'fragnested'})
|
|
143
|
+
file_de = Webgen::Node.new(root, 'file.html', '/file.de.html', {'lang' => 'de', 'title' => 'file de', 'sort_info' => 5})
|
|
144
|
+
Webgen::Node.new(file_de, '#frag', '/file.de.html#frag', {'title' => 'frag'})
|
|
145
|
+
|
|
146
|
+
Webgen::Node.new(root, 'other.html', '/other.html', {'title' => 'other'})
|
|
147
|
+
Webgen::Node.new(root, 'other.html', '/other.en.html', {'lang' => 'en', 'title' => 'other en'})
|
|
148
|
+
|
|
149
|
+
Webgen::Node.new(root, 'german.html', '/german.other.html', {'title' => 'german', 'lang' => 'de'})
|
|
150
|
+
|
|
151
|
+
dir = Webgen::Node.new(root, 'dir/', '/dir/', {'title' => 'dir'})
|
|
152
|
+
dir_file = Webgen::Node.new(dir, 'subfile.html', '/dir/subfile.html', {'title' => 'subfile'})
|
|
153
|
+
Webgen::Node.new(dir_file, '#frag', '/dir/subfile.html#frag', {'title' => 'frag'})
|
|
154
|
+
dir_dir = Webgen::Node.new(dir, 'dir/' , '/dir/dir/', {'title' => 'dir'})
|
|
155
|
+
Webgen::Node.new(dir_dir, 'file.html', '/dir/dir/file.html', {'title' => 'file'})
|
|
156
|
+
|
|
157
|
+
dir2 = Webgen::Node.new(root, 'dir2/', '/dir2/', {'proxy_path' => 'index.html', 'title' => 'dir2'})
|
|
158
|
+
Webgen::Node.new(dir2, 'index.html', '/dir2/index.en.html',
|
|
159
|
+
{'lang' => 'en', 'routed_title' => 'routed', 'title' => 'index en', 'link_attrs' => {'class'=>'help'}})
|
|
160
|
+
Webgen::Node.new(dir2, 'index.html', '/dir2/index.de.html',
|
|
161
|
+
{'lang' => 'de', 'routed_title' => 'routed de', 'title' => 'index de'})
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Creates a Webgen::Context object that is returned and accessible via @context.
|
|
165
|
+
#
|
|
166
|
+
# The needed website object is created using #setup_website and the :chain is set to a mock
|
|
167
|
+
# node that responds to :alcn with '/test'.
|
|
168
|
+
def setup_context
|
|
169
|
+
setup_website
|
|
170
|
+
node = MiniTest::Mock.new
|
|
171
|
+
node.expect(:alcn, '/test')
|
|
172
|
+
@context = Webgen::Context.new(@website, :chain => [node], :doit => 'hallo')
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Creates and returns a RenderNode /tag.template using the default tag template.
|
|
176
|
+
def setup_tag_template(root)
|
|
177
|
+
template_data = File.read(File.join(Webgen::Utils.data_dir, 'passive_sources', 'templates', 'tag.template'))
|
|
178
|
+
RenderNode.new(template_data, root, 'tag.template', '/tag.template')
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end
|
data/lib/webgen/tree.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
require 'webgen/websiteaccess'
|
|
4
3
|
require 'webgen/node'
|
|
5
4
|
|
|
6
5
|
module Webgen
|
|
@@ -8,25 +7,26 @@ module Webgen
|
|
|
8
7
|
# Represents a tree of nodes.
|
|
9
8
|
class Tree
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
10
|
+
# The dummy root.
|
|
11
|
+
#
|
|
12
|
+
# This is the default node that gets created when the Tree is created so that the real root node
|
|
13
|
+
# can be treated like any other node. It has only one child, namely the real root node of the
|
|
14
|
+
# tree.
|
|
16
15
|
attr_reader :dummy_root
|
|
17
16
|
|
|
18
|
-
# Direct access to the hashes for node resolving.
|
|
19
|
-
#
|
|
17
|
+
# Direct access to the hashes for node resolving.
|
|
18
|
+
#
|
|
19
|
+
# Only use this for reading purposes! If you just want to get a specific node for an
|
|
20
|
+
# alcn/acn/destination path, use #node instead.
|
|
20
21
|
attr_reader :node_access
|
|
21
22
|
|
|
22
|
-
# The
|
|
23
|
-
|
|
24
|
-
attr_reader :node_info
|
|
23
|
+
# The website to which the Tree object belongs.
|
|
24
|
+
attr_reader :website
|
|
25
25
|
|
|
26
|
-
# Create a new Tree object.
|
|
27
|
-
def initialize
|
|
28
|
-
@
|
|
29
|
-
@
|
|
26
|
+
# Create a new Tree object for the website.
|
|
27
|
+
def initialize(website)
|
|
28
|
+
@website = website
|
|
29
|
+
@node_access = {:alcn => {}, :acn => {}, :dest_path => {}, :translation_key => {}}
|
|
30
30
|
@dummy_root = Node.new(self, '', '')
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -35,54 +35,103 @@ module Webgen
|
|
|
35
35
|
@dummy_root.children.first
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
# Access a node via a +path+ of a specific +type+.
|
|
39
|
-
#
|
|
40
|
-
#
|
|
38
|
+
# Access a node via a +path+ of a specific +type+.
|
|
39
|
+
#
|
|
40
|
+
# If type is +:alcn+ (default) then +path+ has to be an absolute localized canonical name, if
|
|
41
|
+
# type is +acn+ then +path+ has to be an absolute canonical name and if type is +:dest_path+
|
|
42
|
+
# then +path+ needs to be a destination path.
|
|
41
43
|
#
|
|
42
44
|
# Returns the requested Node or +nil+ if such a node does not exist.
|
|
43
45
|
def node(path, type = :alcn)
|
|
44
|
-
|
|
46
|
+
case type
|
|
47
|
+
when :alcn then @node_access[type][path]
|
|
48
|
+
when :acn then @node_access[type][path] && @node_access[type][path].first
|
|
49
|
+
when :dest_path then @node_access[type][path]
|
|
50
|
+
else
|
|
51
|
+
raise ArgumentError, "Unknown type '#{type}' for resolving path <#{path}>"
|
|
52
|
+
end
|
|
45
53
|
end
|
|
46
54
|
alias_method :[], :node
|
|
47
55
|
|
|
48
|
-
#
|
|
56
|
+
# Return the node representing the given +path+ which can be an alcn/acn/destination path (name
|
|
57
|
+
# resolution is done in the specified order). The path has to be absolute, i.e. starting with a
|
|
58
|
+
# slash.
|
|
59
|
+
#
|
|
60
|
+
# If the +path+ is an alcn and a node is found, it is returned. If the +path+ is an acn, the
|
|
61
|
+
# correct localized node according to +lang+ is returned or if no such node exists but an
|
|
62
|
+
# unlocalized version does, the unlocalized node is returned. If the +path+ is a destination
|
|
63
|
+
# path, the node with this destination path is returned.
|
|
64
|
+
#
|
|
65
|
+
# If no node is found for the given path or if the path is invalid, +nil+ is returned and, if
|
|
66
|
+
# +msg_on_failure+ is +true+, the message :node_resolution_failed (with parameters +path+ and
|
|
67
|
+
# +lang+) is dispatched.
|
|
68
|
+
def resolve_node(path, lang, msg_on_failure = false)
|
|
69
|
+
node = self.node(path, :alcn)
|
|
70
|
+
if !node || node.acn == path
|
|
71
|
+
(node = (self.node(path, :acn) || self.node(path + '/', :acn))) && (node = translate_node(node, lang))
|
|
72
|
+
end
|
|
73
|
+
node = self.node(path, :dest_path) if !node
|
|
74
|
+
@website.blackboard.dispatch_msg(:node_resolution_failed, path, lang) if !node && msg_on_failure
|
|
75
|
+
node
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Return the translation of the node to the language +lang+ or, if no such node exists, an
|
|
79
|
+
# unlocalized version of the node. If no such node is found either, +nil+ is returned.
|
|
80
|
+
def translate_node(node, lang)
|
|
81
|
+
avail = @node_access[:translation_key][translation_key(node)]
|
|
82
|
+
avail.find do |n|
|
|
83
|
+
n = n.parent while n.is_fragment?
|
|
84
|
+
n.lang == lang
|
|
85
|
+
end || avail.find do |n|
|
|
86
|
+
n = n.parent while n.is_fragment?
|
|
87
|
+
n.lang.nil?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Return all translations of the node.
|
|
92
|
+
def translations(node)
|
|
93
|
+
@node_access[:translation_key][translation_key(node)].dup
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Utility method called by Node#initialize. This method should not be used directly!
|
|
49
97
|
def register_node(node)
|
|
50
98
|
if @node_access[:alcn].has_key?(node.alcn)
|
|
51
|
-
raise "Can't have two nodes with same
|
|
99
|
+
raise "Can't have two nodes with same alcn: #{node}"
|
|
52
100
|
else
|
|
53
101
|
@node_access[:alcn][node.alcn] = node
|
|
54
102
|
end
|
|
55
103
|
(@node_access[:acn][node.acn] ||= []) << node
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return if node['no_output']
|
|
62
|
-
if @node_access[:path].has_key?(node.path)
|
|
63
|
-
raise "Can't have two nodes with same output path: #{node.path}"
|
|
104
|
+
(@node_access[:translation_key][translation_key(node)] ||= []) << node
|
|
105
|
+
if node.meta_info['no_output']
|
|
106
|
+
# ignore node dest path
|
|
107
|
+
elsif @node_access[:dest_path].has_key?(node.dest_path)
|
|
108
|
+
raise "Can't have two nodes with same destination path: #{node.dest_path}"
|
|
64
109
|
else
|
|
65
|
-
@node_access[:
|
|
110
|
+
@node_access[:dest_path][node.dest_path] = node
|
|
66
111
|
end
|
|
67
112
|
end
|
|
68
113
|
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
n = node_or_alcn.kind_of?(Node) ? node_or_alcn : @node_access[:alcn][node_or_alcn]
|
|
75
|
-
return if n.nil? || n == @dummy_root
|
|
76
|
-
|
|
77
|
-
n.children.dup.each {|child| delete_node(child)}
|
|
78
|
-
|
|
79
|
-
website.blackboard.dispatch_msg(:before_node_deleted, n)
|
|
80
|
-
n.parent.children.delete(n)
|
|
81
|
-
@node_access[:alcn].delete(n.alcn)
|
|
82
|
-
@node_access[:acn][n.acn].delete(n)
|
|
83
|
-
@node_access[:path].delete(n.path)
|
|
114
|
+
# Return the translation key for the node.
|
|
115
|
+
def translation_key(node)
|
|
116
|
+
node.meta_info['translation_key'] || node.acn
|
|
117
|
+
end
|
|
118
|
+
private :translation_key
|
|
84
119
|
|
|
85
|
-
|
|
120
|
+
# Delete the node and all of its children from the tree.
|
|
121
|
+
#
|
|
122
|
+
# The message +:before_node_deleted+ is sent with the to-be-deleted node before the node is
|
|
123
|
+
# actually deleted from the tree.
|
|
124
|
+
def delete_node(node)
|
|
125
|
+
return if node.nil? || !node.kind_of?(Node) || node == @dummy_root
|
|
126
|
+
|
|
127
|
+
node.children.dup.each {|child| delete_node(child)}
|
|
128
|
+
|
|
129
|
+
@website.blackboard.dispatch_msg(:before_node_deleted, node)
|
|
130
|
+
node.parent.children.delete(node)
|
|
131
|
+
@node_access[:alcn].delete(node.alcn)
|
|
132
|
+
@node_access[:acn][node.acn].delete(node)
|
|
133
|
+
@node_access[:translation_key][translation_key(node)].delete(node)
|
|
134
|
+
@node_access[:dest_path].delete(node.dest_path) unless node.meta_info['no_output']
|
|
86
135
|
end
|
|
87
136
|
|
|
88
137
|
end
|
data/lib/webgen/utils.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'rbconfig'
|
|
4
|
+
require 'webgen/core_ext'
|
|
5
|
+
|
|
6
|
+
module Webgen
|
|
7
|
+
|
|
8
|
+
# Namespace for classes and methods that provide common functionality.
|
|
9
|
+
module Utils
|
|
10
|
+
|
|
11
|
+
# Return the data directory for webgen.
|
|
12
|
+
def self.data_dir
|
|
13
|
+
unless defined?(@@data_dir)
|
|
14
|
+
require 'rbconfig'
|
|
15
|
+
@@data_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'webgen'))
|
|
16
|
+
@@data_dir = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "webgen")) if !File.exists?(@@data_dir)
|
|
17
|
+
raise "Could not find webgen data directory! This is a bug, report it please!" unless File.directory?(@@data_dir)
|
|
18
|
+
end
|
|
19
|
+
@@data_dir
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Return the object for the given absolute constant +name+.
|
|
23
|
+
def self.const_for_name(name)
|
|
24
|
+
name.split('::').inject(Object) {|b,n| b.const_get(n)}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Transform the string in Module::CamelCase format into module/camel_case format.
|
|
28
|
+
def self.snake_case(str)
|
|
29
|
+
str = str.dup
|
|
30
|
+
str.gsub!(/::/, '/')
|
|
31
|
+
str.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
|
32
|
+
str.gsub!(/([a-z])([A-Z])/,'\1_\2')
|
|
33
|
+
str.downcase!
|
|
34
|
+
str
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|