cyberweb 0.4.174 → 0.5.225
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.
Potentially problematic release.
This version of cyberweb might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +1782 -405
- data/bin/cyberweb_sanitize +10 -0
- data/bin/download_webpage +7 -0
- data/bin/html_to_cyberweb_converter +7 -0
- data/cyberweb.gemspec +25 -25
- data/doc/README.gen +1745 -383
- data/doc/USAGE.md +16 -16
- data/doc/{AUTHORS.md → authors.md} +0 -0
- data/doc/configuration/configuration.md +3 -1
- data/doc/deprecations.md +13 -7
- data/doc/{DOCUMENTATION_FOR_CYBERSPRAWL.md → documentation_for_cybersprawl.md} +7 -4
- data/doc/future_design_goals.md +33 -0
- data/doc/html_characters.md +7 -7
- data/doc/{JQUERY.md → jquery/jquery.md} +20 -12
- data/doc/{MOUSE.md → mouse.md} +1 -9
- data/doc/{RENDER_WEB_BASE.md → render_web_base.md} +11 -4
- data/doc/todo/todo_for_the_cyberweb_project.md +791 -0
- data/examples/advanced/animated_css_example/animated_css_example.html +47 -0
- data/examples/advanced/animated_submarine/animated_submarine.html +511 -0
- data/examples/advanced/animated_windmill/animated_windmill.html +468 -0
- data/examples/advanced/delayed_update_of_the_body_via_javascript.cgi +8 -5
- data/examples/advanced/draw_circle/draw_circle.cgi +36 -0
- data/examples/advanced/drop_shadow_examples.cgi +37 -0
- data/examples/advanced/games/snake/food.png +0 -0
- data/examples/advanced/games/snake/ground.png +0 -0
- data/examples/advanced/games/snake/snake.cgi +28 -0
- data/examples/advanced/games/tetris/tetris.cgi +7 -0
- data/examples/advanced/games/tetris/tetris.rb +17 -0
- data/examples/advanced/games/tetris/tetris.sinatra +58 -0
- data/examples/advanced/games/tic-tac-toe/tic-tac-toe.cgi +123 -0
- data/examples/advanced/get_some_coffee/get_some_coffee.html +293 -0
- data/examples/advanced/glow_on_hover_example/glow_on_hover_example.cgi +27 -0
- data/examples/advanced/hybrid_experiment.cgi +34 -12
- data/examples/advanced/images/global_css_rules_for_the_images.cgi +32 -0
- data/examples/advanced/larger_image_on_mouse_over_example.cgi +2 -2
- data/examples/advanced/no_right_click.cgi +4 -3
- data/examples/advanced/{objectified_html_tags.cgi → objectified_html_tags/objectified_html_tags.cgi} +12 -3
- data/examples/advanced/objectified_html_tags/testing_objectified_html_tags_with_the_webobject.cgi +28 -0
- data/examples/advanced/random_glow_effects.cgi +34 -0
- data/examples/advanced/select_everything_example/select_everything_example.cgi +25 -0
- data/examples/advanced/simple_calculator.cgi +13 -21
- data/examples/advanced/simple_form_example.cgi +11 -11
- data/examples/advanced/traffic_light/traffic_light.html +163 -0
- data/examples/advanced/weather_animation/weather_animation.html +560 -0
- data/examples/css/animated_3D_cube_example/animated_3D_cube_example.html +265 -0
- data/examples/css/animated_bird_example/animated_bird_example.html +207 -0
- data/examples/css/animated_desk_example/animated_desk_example.html +120 -0
- data/examples/css/animated_dog_example/animated_dog_example.html +432 -0
- data/examples/css/animated_submit_button.html +190 -0
- data/examples/css/animated_text_colour_change/animated_text_colour_change.html +41 -0
- data/examples/css/blue_border.html +3 -1
- data/examples/css/border_image_example/border_image_example.html +40 -0
- data/examples/css/box_shadow/box_shadow_example.html +18 -0
- data/examples/css/christmas_snow_globe_animation.html +596 -0
- data/examples/css/css_border_spacing_example.html +5 -5
- data/examples/css/css_bubbles.html +3 -1
- data/examples/css/css_checkboxes_example/css_checkboxes_example.html +110 -0
- data/examples/css/css_drag_and_drop.html +1 -5
- data/examples/css/css_grid_feline_style/css_grid_feline_style.html +161 -0
- data/examples/css/css_neon_glow_effects.html +1 -1
- data/examples/css/css_rotate_these_words.html +83 -0
- data/examples/css/css_text_decoration_example.html +7 -7
- data/examples/css/css_thermometer/css_thermometer.html +91 -0
- data/examples/css/{css_tooltip.html → css_tooltip/css_tooltip.html} +8 -6
- data/examples/css/css_typewriter_example/css_typewriter_example.html +226 -0
- data/examples/css/cyberweb_animated_logo/cyberweb_animated_logo.html +179 -0
- data/examples/css/daily_coffee/daily_coffee.html +1110 -0
- data/examples/css/different_colour_on_selected_text/different_colour_on_selected_text.html +31 -0
- data/examples/css/differentially_glowing_text_example/differentially_glowing_text_example.html +82 -0
- data/examples/css/fade_in_and_fade_out_effect.html +2 -2
- data/examples/css/flying_birds_example/flying_birds_example.html +171 -0
- data/examples/css/folding_cards_example/folding_cards_example.html +624 -0
- data/examples/css/font_size_examples.html +7 -5
- data/examples/css/glowing_on_hover_animation/glowing_on_hover_animation.html +90 -0
- data/examples/css/grow_example.html +31 -0
- data/examples/css/happy_toaster_example/happy_toaster_example.html +830 -0
- data/examples/css/landing_on_mars_animation/landing_on_mars_animation.html +374 -0
- data/examples/css/letter_spacing_example.cgi +18 -14
- data/examples/css/lighthouse_example/lighthouse_example.html +1161 -0
- data/examples/css/{meter_example.html → meter_example/meter_example.html} +0 -0
- data/examples/css/motorcycle_on_the_go/motorcycle_on_the_go.html +227 -0
- data/examples/css/on_hover_glow_effect/on_hover_glow_effect.html +50 -0
- data/examples/css/on_mouse_button_pressed.html +6 -4
- data/examples/css/our_solar_system/our_solar_system.html +441 -0
- data/examples/css/outline/outline_versus_border_example.html +57 -0
- data/examples/css/polaroid_card_effect_example/polaroid_card_effect_example.html +130 -0
- data/examples/css/responsive_image_gallery/responsive_image_gallery.html +97 -0
- data/examples/css/rotating_DNA/rotating_DNA.html +626 -0
- data/examples/css/rotating_sphere_example/rotating_sphere_example.html +112 -0
- data/examples/css/scale_example.html +4 -5
- data/examples/css/shadow_example_in_CSS/shadow_example_in_CSS.cgi +62 -0
- data/examples/css/shaking_shapes_example.html +133 -0
- data/examples/css/simple_stars_example/simple_stars_example.html +27 -0
- data/examples/css/slide_checkbox_example/slide_checkbox_example.html +564 -0
- data/examples/css/speak_bubble_quote_example/speak_bubble_quote_example.html +109 -0
- data/examples/css/speedy_truck_example/speedy_truck_example.html +168 -0
- data/examples/css/{sticky_div_example.html → sticky_div_example/sticky_div_example.html} +0 -0
- data/examples/css/stitched_div.html +9 -0
- data/examples/css/sun_and_clouds_animation/sun_and_clouds_animation.html +292 -0
- data/examples/css/talking_candles_example/talking_candles_example.html +550 -0
- data/examples/css/text_decoration_underline_example/text_decoration_underline_example.html +62 -0
- data/examples/css/this_is_a_cat/this_is_a_cat.html +219 -0
- data/examples/css/three_dots_indicating_page_loading.html +65 -0
- data/examples/css/user_select_example/user_select_example.html +24 -0
- data/examples/css/walking_cat/walking_cat.html +128 -0
- data/examples/css/water_wave_text_animation_effect/water_wave_text_animation_effect.html +86 -0
- data/examples/csv/README.md +2 -1
- data/examples/flip_card_example/flip_card_example.html +10 -3
- data/examples/games/README.md +3 -0
- data/examples/games/snake/images/food.png +0 -0
- data/examples/games/snake/images/ground.png +0 -0
- data/examples/games/snake/snake.html +16 -0
- data/examples/games/snake/snake.js +117 -0
- data/examples/games/tetris/smaller_tetris_game.html +518 -0
- data/examples/games/tetris/tetris.html +461 -0
- data/examples/games/tic-tac-toe/index.js +125 -0
- data/examples/games/tic-tac-toe/style.css +79 -0
- data/examples/games/tic-tac-toe/tic-tac-toe.html +39 -0
- data/examples/html/MathML/001_show_a_simple_quadratic_equation.html +22 -0
- data/examples/html/MathML/002_simple_equation.html +7 -0
- data/examples/html/MathML/003_function_of_example.html +17 -0
- data/examples/html/MathML/README.md +2 -0
- data/examples/html/abbr_example.html +2 -5
- data/examples/html/accordion/README.md +1 -0
- data/examples/html/accordion/accordion.html +56 -0
- data/examples/html/base64_image_example.html +8 -5
- data/examples/html/buttons_example.html +133 -0
- data/examples/html/canvas_drawing_example.html +54 -0
- data/examples/html/colour_wheel.html +441 -442
- data/examples/html/column_width_example.html +2 -2
- data/examples/html/custom_cursor.html +8 -5
- data/examples/html/cyberweb_logo/README.md +2 -0
- data/examples/html/cyberweb_logo/cyberweb_logo.html +11 -0
- data/examples/html/draggable_paragraph.html +1 -2
- data/examples/html/email_popup_example/email_popup_example.html +175 -0
- data/examples/html/fieldset_example.html +3 -1
- data/examples/html/font_examples/README.md +1 -0
- data/examples/html/font_examples/chancery_text.html +19 -0
- data/examples/html/font_examples/fantasy_text.html +19 -0
- data/examples/html/font_examples/georgia_text.html +19 -0
- data/examples/html/font_size_example/font_size_example.html +85 -0
- data/examples/html/glyph_example.html +0 -1
- data/examples/html/grayscale_filter_example/grayscale_filter_example.html +15 -0
- data/examples/html/html_links_example.html +61 -0
- data/examples/html/html_slider/html_slider.html +39 -0
- data/examples/html/input_autofocus_example.html +11 -7
- data/examples/html/input_placeholder_example.html +15 -0
- data/examples/html/larger_image_on_mouse_over_example.html +1 -1
- data/examples/html/ordered_and_unordered_bulletsin.html +4 -2
- data/examples/html/play_video_example.html +3 -2
- data/examples/html/remote_image_example.html +8 -2
- data/examples/html/select_everything_on_mouse_click_event.html +38 -0
- data/examples/html/selected_text_appears_in_another_colour_example.html +34 -0
- data/examples/html/send_email_hyperlink/send_email_hyperlink.html +8 -0
- data/examples/html/simple_unordered_list.html +3 -0
- data/examples/html/spinner_example/spinner.html +79 -0
- data/examples/html/table_with_header_example.html +26 -13
- data/examples/html/test_mkv_codec/test_mkv_codec.html +11 -0
- data/examples/html/two_columns_flex_example.html +4 -1
- data/examples/{javascript → javascript_and_jquery}/README.md +0 -0
- data/examples/{javascript → javascript_and_jquery}/arrays/arrays_example_in_javascript.html +0 -0
- data/examples/javascript_and_jquery/autocomplete_on_an_input_field/autocomplete_on_an_input_field.html +295 -0
- data/examples/javascript_and_jquery/change_the_background_colour_dynamically/change_the_background_colour_dynamically.html +41 -0
- data/examples/{javascript → javascript_and_jquery}/delay_example/delay_example.html +0 -0
- data/examples/{javascript → javascript_and_jquery}/drag_support/drag_support.html +0 -0
- data/examples/javascript_and_jquery/jquery_bubbling_header/bubbling_header.html +109 -0
- data/examples/{javascript → javascript_and_jquery}/jquery_drag_and_drop/drag_and_drop_image_example.html +0 -0
- data/examples/javascript_and_jquery/jquery_showcase/README.md +6 -0
- data/examples/javascript_and_jquery/jquery_showcase/jquery_001.cgi +23 -0
- data/examples/javascript_and_jquery/jquery_showcase/jquery_002.cgi +34 -0
- data/examples/javascript_and_jquery/jquery_showcase/jquery_003.cgi +24 -0
- data/examples/javascript_and_jquery/jquery_showcase/jquery_004.cgi +34 -0
- data/examples/javascript_and_jquery/on_change_event/on_change_event.html +29 -0
- data/examples/javascript_and_jquery/on_click_colour_change/on_click_colour_change.html +31 -0
- data/examples/javascript_and_jquery/on_click_display_random_number/on_click_display_random_number.html +43 -0
- data/examples/{javascript → javascript_and_jquery}/on_click_event_hello_world/on_click_event_hello_world.html +0 -0
- data/examples/javascript_and_jquery/on_mouse_wheel_event/on_mouse_wheel_event.html +37 -0
- data/examples/javascript_and_jquery/read_the_content_of_a_local_file/read_the_content_of_a_local_file.html +35 -0
- data/examples/{javascript → javascript_and_jquery}/rgb_to_hex/rgb_to_hex.html +0 -0
- data/examples/{javascript → javascript_and_jquery}/screen_resolution/screen_resolution.html +2 -1
- data/examples/{javascript → javascript_and_jquery}/select_everything/select_everything.html +1 -1
- data/examples/javascript_and_jquery/vue/README.md +1 -0
- data/examples/javascript_and_jquery/vue/showcasing_vue.html +80 -0
- data/examples/{javascript → javascript_and_jquery}/write_into_a_file/write_into_a_file.html +0 -0
- data/examples/rack/example_with_html_template.rb +5 -4
- data/examples/rack/example_with_rack_and_cyberweb_showing_how_to_use_images.rb +3 -2
- data/examples/rack/hello_world_example_with_rack.rb +3 -2
- data/examples/rack/lobster.rb +7 -5
- data/examples/rack/rack_env.rb +3 -3
- data/examples/{show_greek_letters.rb → show_greek_letters/show_greek_letters.rb} +0 -0
- data/examples/simple/input_example_with_coloured_focus.cgi +32 -0
- data/examples/simple/input_type_examples.cgi +51 -0
- data/examples/simple/on_click_event_hello_world.cgi +5 -5
- data/examples/simple/rotate_these_words.cgi +90 -0
- data/examples/{example1.rb → simple/show_how_to_set_a_title.rb} +0 -0
- data/examples/simple/simple_gradient.cgi +57 -0
- data/images/cyberweb_favicon.png +0 -0
- data/images/cyberweb_logo.png +0 -0
- data/images/cyberweb_theme.png +0 -0
- data/lib/cyberweb/REST/README.md +7 -0
- data/lib/cyberweb/REST/base/accept_entry.rb +94 -0
- data/lib/cyberweb/REST/base/application.rb +37 -0
- data/lib/cyberweb/REST/base/bad_request.rb +10 -0
- data/lib/cyberweb/REST/base/base.rb +1131 -0
- data/lib/cyberweb/REST/base/common_logger.rb +35 -0
- data/lib/cyberweb/REST/base/delegator.rb +75 -0
- data/lib/cyberweb/REST/base/error.rb +8 -0
- data/lib/cyberweb/REST/base/extended_rack.rb +66 -0
- data/lib/cyberweb/REST/base/helpers/helpers.rb +473 -0
- data/lib/cyberweb/REST/base/helpers/stream.rb +75 -0
- data/lib/cyberweb/REST/base/mime_type_entry.rb +67 -0
- data/lib/cyberweb/{constants/file_constants.rb → REST/base/not_found.rb} +10 -5
- data/lib/cyberweb/REST/base/request.rb +145 -0
- data/lib/cyberweb/REST/base/response.rb +94 -0
- data/lib/cyberweb/REST/base/templates/templates.rb +208 -0
- data/lib/cyberweb/REST/base/wrapper.rb +28 -0
- data/lib/cyberweb/{constants/nl.rb → REST/constants.rb} +8 -9
- data/lib/cyberweb/REST/main.rb +109 -0
- data/lib/cyberweb/REST/show_exceptions.rb +396 -0
- data/lib/cyberweb/and_sinatra_base.rb +0 -0
- data/lib/cyberweb/autoinclude.rb +0 -0
- data/lib/cyberweb/autoinclude_webobject.rb +0 -0
- data/lib/cyberweb/base/base.rb +9 -2
- data/lib/cyberweb/base/colours.rb +8 -6
- data/lib/cyberweb/base/constants.rb +8 -0
- data/lib/cyberweb/base/misc.rb +140 -53
- data/lib/cyberweb/base/save_file.rb +3 -0
- data/lib/cyberweb/base_module/base_module.rb +79 -0
- data/lib/cyberweb/cascading_style_sheets/admonition.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/balloon.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/border.css +107 -41
- data/lib/cyberweb/cascading_style_sheets/code.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/colours.css +46 -23
- data/lib/cyberweb/cascading_style_sheets/css_reset.css +59 -0
- data/lib/cyberweb/cascading_style_sheets/cursors.css +14 -0
- data/lib/cyberweb/cascading_style_sheets/custom/animated_bike.css +199 -0
- data/lib/cyberweb/cascading_style_sheets/default.css +171 -136
- data/lib/cyberweb/cascading_style_sheets/div.css +18 -4
- data/lib/cyberweb/cascading_style_sheets/drop_shadow.css +154 -0
- data/lib/cyberweb/cascading_style_sheets/error_404_css_class.css +26 -0
- data/lib/cyberweb/cascading_style_sheets/fonts.css +60 -39
- data/lib/cyberweb/cascading_style_sheets/glow_effects.css +69 -0
- data/lib/cyberweb/cascading_style_sheets/gradient_effects.css +5 -0
- data/lib/cyberweb/cascading_style_sheets/hover.css +4212 -0
- data/lib/cyberweb/cascading_style_sheets/links.css +8 -8
- data/lib/cyberweb/cascading_style_sheets/margin.css +195 -178
- data/lib/cyberweb/cascading_style_sheets/menu.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/message_boxes.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/misc.css +51 -11
- data/lib/cyberweb/cascading_style_sheets/popup.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/rpg.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/ruby_regexes.css +12 -0
- data/lib/cyberweb/cascading_style_sheets/shapes.css +59 -0
- data/lib/cyberweb/cascading_style_sheets/template2.css +0 -0
- data/lib/cyberweb/cascading_style_sheets/text_shadow.css +21 -0
- data/lib/cyberweb/cascading_style_sheets/tooltip.css +0 -0
- data/lib/cyberweb/cgi/constants.rb +1 -2
- data/lib/cyberweb/cgi/exceptions.rb +1 -1
- data/lib/cyberweb/coloured_tags/coloured_tags.rb +1 -1
- data/lib/cyberweb/colours/colour_chart.rb +10 -56
- data/lib/cyberweb/colours/colours.rb +149 -4
- data/lib/cyberweb/commandline/commandline_interface.rb +13 -8
- data/lib/cyberweb/configuration/load_the_configuration_file.rb +1 -1
- data/lib/cyberweb/constants/constants.rb +592 -2
- data/lib/cyberweb/controller/{webobject_controller.rb → controller.rb} +1 -1
- data/lib/cyberweb/css_manager/css_manager.rb +237 -0
- data/lib/cyberweb/databases/sqlite.rb +56 -0
- data/lib/cyberweb/debug/debug.rb +1 -1
- data/lib/cyberweb/encoding/encoding.rb +11 -0
- data/lib/cyberweb/erb/test.rhtml +0 -0
- data/lib/cyberweb/erb/test_template.erb +0 -0
- data/lib/cyberweb/evaluate_from_the_same_named_file_then_serve.rb +1 -1
- data/lib/cyberweb/favicon/favicon.rb +8 -7
- data/lib/cyberweb/forum/README.md +4 -0
- data/lib/cyberweb/foto_gallery/foto_gallery.rb +158 -0
- data/lib/cyberweb/generator/README.md +2 -2
- data/lib/cyberweb/generator/cgi.rb +22 -9
- data/lib/cyberweb/generator/static_webpage.rb +22 -12
- data/lib/cyberweb/html_tags/README.md +3 -3
- data/lib/cyberweb/html_tags/button.rb +10 -2
- data/lib/cyberweb/html_tags/h2.rb +6 -4
- data/lib/cyberweb/html_tags/html_tags.rb +17 -1
- data/lib/cyberweb/html_tags/input.rb +10 -5
- data/lib/cyberweb/html_tags/legend.rb +1 -1
- data/lib/cyberweb/html_tags/span.rb +10 -2
- data/lib/cyberweb/html_tags/table.rb +30 -19
- data/lib/cyberweb/html_template/html_template.rb +248 -85
- data/lib/cyberweb/images/embed_this_image.rb +3 -1
- data/lib/cyberweb/images/images.rb +2 -2
- data/lib/cyberweb/images/is_image.rb +2 -1
- data/lib/cyberweb/images/path_to_images.rb +2 -1
- data/lib/cyberweb/images/remove_this_substring_from_all_images.rb +1 -1
- data/lib/cyberweb/images/standalone_drag_and_drop_this_image.rb +3 -3
- data/lib/cyberweb/images/string_image.rb +6 -3
- data/lib/cyberweb/images_base64_encoded/404_ERROR.png.md +1 -0
- data/lib/cyberweb/images_base64_encoded/AUSRUFUNGSZEICHEN.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/BLUEARROW.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/BUBBLE.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/CAT.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/CAUTION.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/CHEERING_PERSON.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/CURSOR.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/DOT_01.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/DUCKY.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/ELEPHANT.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/HALLOWEEN.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/HANGING_MONKEY.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/LENS.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/README.md +0 -0
- data/lib/cyberweb/images_base64_encoded/SIX_SIDED_DICE.png.md +1 -0
- data/lib/cyberweb/images_base64_encoded/TU_WIEN_LOGO.png.md +0 -0
- data/lib/cyberweb/images_base64_encoded/VOGEL.png.md +0 -0
- data/lib/cyberweb/javascript/drag_and_drop.rb +17 -14
- data/lib/cyberweb/javascript/javascript.rb +79 -34
- data/lib/cyberweb/javascript/javascript_clock.rb +50 -14
- data/lib/cyberweb/javascript/javascript_helper/javascript_helper.rb +59 -0
- data/lib/cyberweb/javascript/jquery.rb +9 -5
- data/lib/cyberweb/javascript/on_click_change_opacity.rb +5 -1
- data/lib/cyberweb/javascript/on_click_hide.rb +2 -0
- data/lib/cyberweb/javascript/popup.rb +5 -2
- data/lib/cyberweb/javascript/resize.rb +4 -1
- data/lib/cyberweb/javascript_code/README.md +1 -1
- data/lib/cyberweb/javascript_code/custom_functions.js +51 -25
- data/lib/cyberweb/javascript_code/disable_right_click.js +5 -0
- data/lib/cyberweb/javascript_code/games/snake.js +113 -0
- data/lib/cyberweb/javascript_code/games/tetris.js +491 -0
- data/lib/cyberweb/javascript_code/games/tic-tac-toe.js +125 -0
- data/lib/cyberweb/javascript_code/html_colours.js +161 -0
- data/lib/cyberweb/javascript_code/jquery/jquery-3.6.1.js +10909 -0
- data/lib/cyberweb/javascript_code/select_everything_on_mouse_click_event.js +23 -0
- data/lib/cyberweb/javascript_code/simple_calculator.js +3 -3
- data/lib/cyberweb/javascript_code/simulate_a_dice.js +20 -0
- data/lib/cyberweb/javascript_code/sleep.js +3 -0
- data/lib/cyberweb/mouse/mouse.rb +4 -1
- data/lib/cyberweb/objectified/html_tags/README.md +13 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/a.rb +17 -35
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/abbr.rb +18 -9
- data/lib/cyberweb/objectified/html_tags/base.rb +960 -0
- data/lib/cyberweb/objectified/html_tags/blockquote.rb +106 -0
- data/lib/cyberweb/{objectified_html_tags/span.rb → objectified/html_tags/body.rb} +25 -20
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/button.rb +26 -34
- data/lib/cyberweb/objectified/html_tags/canvas.rb +202 -0
- data/lib/cyberweb/objectified/html_tags/cite.rb +103 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/combobox.rb +26 -34
- data/lib/cyberweb/objectified/html_tags/div.rb +155 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/embed.rb +18 -33
- data/lib/cyberweb/objectified/html_tags/fieldset.rb +107 -0
- data/lib/cyberweb/objectified/html_tags/figure.rb +152 -0
- data/lib/cyberweb/objectified/html_tags/form.rb +155 -0
- data/lib/cyberweb/objectified/html_tags/h1.rb +176 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/h2.rb +32 -40
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/h3.rb +30 -42
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/h4.rb +30 -42
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/h5.rb +31 -40
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/h6.rb +31 -41
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/hbox.rb +12 -10
- data/lib/cyberweb/objectified/html_tags/head.rb +126 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/img.rb +47 -32
- data/lib/cyberweb/objectified/html_tags/include_objectified_html_tags.rb +49 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/input.rb +50 -51
- data/lib/cyberweb/objectified/html_tags/map.rb +107 -0
- data/lib/cyberweb/{objectified_html_tags/div.rb → objectified/html_tags/meta.rb} +36 -47
- data/lib/cyberweb/{objectified_html_tags/h1.rb → objectified/html_tags/object.rb} +34 -42
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/p.rb +17 -32
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/pre.rb +28 -34
- data/lib/cyberweb/{objectified_html_tags/table.rb → objectified/html_tags/progress.rb} +99 -94
- data/lib/cyberweb/objectified/html_tags/span.rb +103 -0
- data/lib/cyberweb/objectified/html_tags/table.rb +257 -0
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/textarea.rb +25 -36
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/title.rb +11 -17
- data/lib/cyberweb/{objectified_html_tags/form.rb → objectified/html_tags/ul.rb} +45 -42
- data/lib/cyberweb/{objectified_html_tags → objectified/html_tags}/window.rb +15 -10
- data/lib/cyberweb/objectified/mask/README.md +8 -0
- data/lib/cyberweb/objectified/mask/compatibility_to_html_tags.rb +40 -0
- data/lib/cyberweb/objectified/mask/mask.rb +490 -0
- data/lib/cyberweb/objectified/web_object/README.md +4 -0
- data/lib/cyberweb/objectified/web_object/web_object.rb +119 -0
- data/lib/cyberweb/predefined_and_freeform_methods/frage.rb +4 -2
- data/lib/cyberweb/predefined_and_freeform_methods/freeform_methods.rb +30 -19
- data/lib/cyberweb/predefined_and_freeform_methods/hash_registered_extra_tags.rb +6 -0
- data/lib/cyberweb/predefined_and_freeform_methods/header.rb +2 -0
- data/lib/cyberweb/predefined_and_freeform_methods/predefined_methods.rb +10 -175
- data/lib/cyberweb/project/project.rb +9 -4
- data/lib/cyberweb/rack/request.rb +11 -11
- data/lib/cyberweb/raw_images/404.png +0 -0
- data/lib/cyberweb/raw_images/500.png +0 -0
- data/lib/cyberweb/raw_images/README.md +2 -0
- data/lib/cyberweb/raw_images/a_dice.png +0 -0
- data/lib/cyberweb/raw_images/food.png +0 -0
- data/lib/cyberweb/raw_images/ground.png +0 -0
- data/lib/cyberweb/requires/require_generators.rb +1 -1
- data/lib/cyberweb/requires/require_html_tags_files.rb +1 -1
- data/lib/cyberweb/requires/require_javascript_files.rb +1 -1
- data/lib/cyberweb/requires/require_objectified_html_tags_files.rb +29 -3
- data/lib/cyberweb/requires/require_the_constants.rb +3 -1
- data/lib/cyberweb/requires/require_the_cyberweb_project.rb +12 -31
- data/lib/cyberweb/requires/require_the_toplevel_methods_files.rb +1 -1
- data/lib/cyberweb/requires/require_web_object_files.rb +1 -1
- data/lib/cyberweb/requires/require_yaml.rb +3 -3
- data/lib/cyberweb/rest +1 -0
- data/lib/cyberweb/route_handler/class_based_test.rb +43 -0
- data/lib/cyberweb/route_handler/module/misc.rb +108 -0
- data/lib/cyberweb/route_handler/module/route_handler_module.rb +215 -0
- data/lib/cyberweb/route_handler/module/verbs.rb +53 -0
- data/lib/cyberweb/route_handler/route_handler.rb +56 -0
- data/lib/cyberweb/route_handler/test.rb +43 -0
- data/lib/cyberweb/{constants/array_predefined_constants.rb → sinatra/base/set_use_this_port.rb} +16 -9
- data/lib/cyberweb/sinatra/base/use_this_port.rb +40 -0
- data/lib/cyberweb/sinatra/base.rb +51 -36
- data/lib/cyberweb/sinatra/custom_extensions.rb +39 -14
- data/lib/cyberweb/standalone_classes/all_css_classes.rb +1 -1
- data/lib/cyberweb/standalone_classes/calculator.rb +7 -1
- data/lib/cyberweb/standalone_classes/correct_image_entries_in_html_file.rb +12 -7
- data/lib/cyberweb/standalone_classes/turn_html_into_cyberweb.rb +13 -11
- data/lib/cyberweb/svg/standalone/README.md +2 -0
- data/lib/cyberweb/svg/standalone/amusement_park.svg +738 -0
- data/lib/cyberweb/svg/svg.cgi +2 -3
- data/lib/cyberweb/toplevel_methods/a.rb +2 -1
- data/lib/cyberweb/toplevel_methods/anmerkung.rb +3 -0
- data/lib/cyberweb/toplevel_methods/audio.rb +1 -1
- data/lib/cyberweb/toplevel_methods/bold.rb +9 -3
- data/lib/cyberweb/toplevel_methods/charsets.rb +17 -13
- data/lib/cyberweb/toplevel_methods/consider_serving_the_web_object.rb +3 -3
- data/lib/cyberweb/toplevel_methods/css.rb +719 -25
- data/lib/cyberweb/{csv → toplevel_methods}/csv.rb +5 -3
- data/lib/cyberweb/{constants/roebe.rb → toplevel_methods/custom_error_page.rb} +10 -10
- data/lib/cyberweb/toplevel_methods/{date.rb → date_and_time.rb} +23 -10
- data/lib/cyberweb/toplevel_methods/disable.rb +7 -3
- data/lib/cyberweb/toplevel_methods/dot.rb +2 -2
- data/lib/cyberweb/toplevel_methods/download_webpage.rb +41 -3
- data/lib/cyberweb/toplevel_methods/edit_configuration_file.rb +1 -1
- data/lib/cyberweb/toplevel_methods/fields.rb +2 -0
- data/lib/cyberweb/toplevel_methods/filename.rb +3 -1
- data/lib/cyberweb/toplevel_methods/frames.rb +0 -2
- data/lib/cyberweb/toplevel_methods/google.rb +52 -0
- data/lib/cyberweb/{html_codes → toplevel_methods}/greek_letters.rb +22 -1
- data/lib/cyberweb/toplevel_methods/hardware_information.rb +2 -1
- data/lib/cyberweb/{help → toplevel_methods}/help.rb +3 -2
- data/lib/cyberweb/toplevel_methods/html_comment.rb +2 -2
- data/lib/cyberweb/toplevel_methods/html_tables.rb +401 -266
- data/lib/cyberweb/toplevel_methods/internal_hash.rb +173 -0
- data/lib/cyberweb/{io → toplevel_methods}/io.rb +1 -1
- data/lib/cyberweb/toplevel_methods/javascript.rb +42 -0
- data/lib/cyberweb/toplevel_methods/jquery.rb +8 -0
- data/lib/cyberweb/toplevel_methods/last_modified.rb +4 -0
- data/lib/cyberweb/toplevel_methods/links.rb +23 -7
- data/lib/cyberweb/toplevel_methods/listing.rb +2 -1
- data/lib/cyberweb/toplevel_methods/localhost.rb +3 -0
- data/lib/cyberweb/toplevel_methods/markdown.rb +3 -2
- data/lib/cyberweb/toplevel_methods/mathml.rb +5 -3
- data/lib/cyberweb/toplevel_methods/message_boxes.rb +6 -2
- data/lib/cyberweb/toplevel_methods/misc.rb +531 -79
- data/lib/cyberweb/toplevel_methods/padlem_and_marlem.rb +3 -0
- data/lib/cyberweb/toplevel_methods/path.rb +6 -1
- data/lib/cyberweb/toplevel_methods/pdf.rb +1 -1
- data/lib/cyberweb/toplevel_methods/process_content.rb +4 -7
- data/lib/cyberweb/toplevel_methods/progress.rb +6 -2
- data/lib/cyberweb/toplevel_methods/quote.rb +7 -1
- data/lib/cyberweb/toplevel_methods/random.rb +4 -1
- data/lib/cyberweb/toplevel_methods/rds.rb +14 -6
- data/lib/cyberweb/toplevel_methods/read_and_display.rb +3 -2
- data/lib/cyberweb/toplevel_methods/return_head_start.rb +1 -1
- data/lib/cyberweb/toplevel_methods/return_html_fin.rb +6 -3
- data/lib/cyberweb/toplevel_methods/return_html_header.rb +8 -3
- data/lib/cyberweb/toplevel_methods/return_html_start.rb +7 -2
- data/lib/cyberweb/toplevel_methods/return_meta_collection.rb +15 -4
- data/lib/cyberweb/toplevel_methods/return_pwd.rb +4 -0
- data/lib/cyberweb/toplevel_methods/return_strict_doctype.rb +8 -7
- data/lib/cyberweb/toplevel_methods/roebe.rb +6 -0
- data/lib/cyberweb/toplevel_methods/s2.rb +3 -1
- data/lib/cyberweb/toplevel_methods/sanitize_url.rb +7 -5
- data/lib/cyberweb/toplevel_methods/sbr.rb +7 -7
- data/lib/cyberweb/toplevel_methods/server_base_directory.rb +7 -3
- data/lib/cyberweb/toplevel_methods/show_and_display.rb +15 -15
- data/lib/cyberweb/toplevel_methods/show_configuration.rb +2 -2
- data/lib/cyberweb/toplevel_methods/spacer.rb +5 -2
- data/lib/cyberweb/toplevel_methods/svg.rb +62 -4
- data/lib/cyberweb/toplevel_methods/tag.rb +8 -2
- data/lib/cyberweb/toplevel_methods/temp_directory.rb +2 -2
- data/lib/cyberweb/toplevel_methods/textile.rb +2 -2
- data/lib/cyberweb/toplevel_methods/title.rb +14 -2
- data/lib/cyberweb/toplevel_methods/video.rb +3 -4
- data/lib/cyberweb/toplevel_methods/write_what_into.rb +2 -0
- data/lib/cyberweb/utility_scripts/README.md +3 -4
- data/lib/cyberweb/utility_scripts/autogenerate_drop_shadow_rules/autogenerate_drop_shadow_rules.rb +71 -0
- data/lib/cyberweb/utility_scripts/create_standalone_html_page.rb +223 -0
- data/lib/cyberweb/utility_scripts/download_all_images_from_this_website.rb +143 -0
- data/lib/cyberweb/utility_scripts/download_balloon_css.rb +1 -1
- data/lib/cyberweb/utility_scripts/fix_incorrect_links_to_locally_existing_images_in_this_file.rb +142 -0
- data/lib/cyberweb/utility_scripts/html_to_cyberweb_converter.rb +235 -0
- data/lib/cyberweb/utility_scripts/images_to_html/images_to_html.rb +878 -0
- data/lib/cyberweb/utility_scripts/images_to_html/misc.rb +62 -0
- data/lib/cyberweb/utility_scripts/new_tags.rb +105 -0
- data/lib/cyberweb/utility_scripts/simple_index/README.md +9 -0
- data/lib/cyberweb/utility_scripts/simple_index/simple_index.rb +149 -0
- data/lib/cyberweb/version/version.rb +2 -2
- data/lib/cyberweb/vue/README.md +2 -0
- data/lib/cyberweb/vue/vue.rb +91 -0
- data/lib/cyberweb/web_images/array_listing_all_project_images.rb +1 -1
- data/lib/cyberweb/web_images/map_symbol_to_image_location.rb +60 -4
- data/lib/cyberweb/web_images/web_images.rb +37 -20
- data/lib/cyberweb/{constants/array_images.rb → web_object/display_output_and_report.rb} +11 -10
- data/lib/cyberweb/web_object/english.rb +55 -0
- data/lib/cyberweb/web_object/favicon.rb +103 -22
- data/lib/cyberweb/web_object/html_tags.rb +1433 -0
- data/lib/cyberweb/web_object/images.rb +428 -398
- data/lib/cyberweb/web_object/{javascript.rb → javascript_and_jquery.rb} +174 -276
- data/lib/cyberweb/web_object/{links.rb → link.rb} +185 -83
- data/lib/cyberweb/web_object/misc.rb +3934 -3928
- data/lib/cyberweb/web_object/reset.rb +153 -67
- data/lib/cyberweb/web_object/run.rb +1 -1
- data/lib/cyberweb/web_object/web_object.rb +3690 -49
- data/lib/cyberweb/web_scraper/scrape_this_url.rb +4 -2
- data/lib/cyberweb/webmin/biology_server.cgi +14 -15
- data/lib/cyberweb/webmin/calculator.cgi +2 -2
- data/lib/cyberweb/webmin/colour_chart.cgi +4 -5
- data/lib/cyberweb/webmin/comments.cgi +8 -7
- data/lib/cyberweb/webmin/comments_data +0 -0
- data/lib/cyberweb/webmin/constants.rb +1 -2
- data/lib/cyberweb/webmin/dictionary.cgi +3 -4
- data/lib/cyberweb/webmin/sys_info.cgi +1 -2
- data/lib/cyberweb/webmin/webforum.cgi +1 -2
- data/lib/cyberweb/webmin/webmin.cgi +2 -3
- data/lib/cyberweb/yaml/autogenerated_system_settings.yml +10 -10
- data/lib/cyberweb/yaml/custom_tags.yml +1 -1
- data/lib/cyberweb/yaml/html5_global_attributes.yml +5 -1
- data/lib/cyberweb/yaml/html_tag_legend.yml +2 -0
- data/lib/cyberweb/yaml/http_status_codes.yml +4 -1
- data/lib/cyberweb/yaml/load_these_yaml_files_by_default.yml +29 -0
- data/lib/cyberweb/yaml/project_configuration.yml +42 -31
- data/lib/cyberweb/yaml/video_attributes.yml +2 -0
- data/lib/cyberweb/yaml/web_images.yml +1 -1
- data/test/REST/simple.rb +7 -0
- data/test/complex_tests/simple_sinatra_example_using_cyberweb/simple.rb +1 -1
- data/test/complex_tests/sinatra_or_cyberweb/sinatra_or_cyberweb.cgi +1 -1
- data/test/complex_tests/sinatra_or_cyberweb/sinatra_or_cyberweb.rb +4 -4
- data/test/complex_tests/sinatra_or_cyberweb/sinatra_or_cyberweb.sinatra +1 -2
- data/test/complex_tests/testing_frames.cgi +3 -5
- data/test/complex_tests/testing_objectified_html_tags/testing_objectified_html_tags.html +28 -0
- data/test/complex_tests/testing_objectified_html_tags/testing_objectified_html_tags.rb +175 -0
- data/test/complex_tests/testing_style_variants/show_coloured_boxes.cgi +11 -7
- data/test/complex_tests/testing_tables.cgi +3 -3
- data/test/complex_tests/testing_the_cyberweb_shell.rb +2 -0
- data/test/complex_tests/testing_web_object.rb +5 -2
- data/test/css/README.md +4 -3
- data/test/css/return_the_content_of_these_css_classes.rb +5 -1
- data/test/css/test_hover_css/test_hover_css.cgi +59 -0
- data/test/css/test_ordered_list/test_ordered_list.cgi +31 -0
- data/test/css/testing_css_effects.cgi +3 -4
- data/test/css/testing_css_masking.cgi +3 -4
- data/test/hello_world/hello_world.cgi +6 -4
- data/test/html_template/html_template.rb +15 -0
- data/test/javascript/testing_custom_functions.js +24 -0
- data/test/javascript/testing_drag_and_drop_support.cgi +1 -1
- data/test/javascript/testing_on_click_change_opacity.cgi +4 -5
- data/test/javascript/testing_snowflakes.cgi +2 -2
- data/test/simple_tests/ad-hoc-test.cgi +5 -2
- data/test/simple_tests/cgi/hello_world_with_cyberweb.cgi +14 -0
- data/test/simple_tests/commandline_tests.rb +21 -15
- data/test/simple_tests/display_this_file.cgi +2 -2
- data/test/simple_tests/simple_html_example.cgi +2 -1
- data/test/simple_tests/simple_html_test_page/simple_html_test_page.html +20 -0
- data/test/simple_tests/simple_status_page.cgi +2 -2
- data/test/simple_tests/string_s2_test.rb +5 -0
- data/test/simple_tests/test_simple_string_as_input.rb +3 -1
- data/test/simple_tests/testing_base64_images.cgi +3 -4
- data/test/simple_tests/testing_checkboxes.cgi +22 -0
- data/test/simple_tests/testing_dragging_an_image.cgi +5 -6
- data/test/simple_tests/testing_editable_text.cgi +2 -3
- data/test/simple_tests/testing_email.cgi +6 -7
- data/test/simple_tests/testing_embedding_a_pdf_file.cgi +5 -5
- data/test/simple_tests/testing_google_charts.cgi +3 -3
- data/test/simple_tests/testing_html_forms.cgi +3 -3
- data/test/simple_tests/testing_html_template.rb +2 -0
- data/test/simple_tests/testing_popup_div.cgi +2 -3
- data/test/simple_tests/testing_return_dataset_without_any_comments.rb +3 -1
- data/test/simple_tests/testing_the_cap_box.cgi +3 -4
- data/test/simple_tests/testing_the_div_tag.cgi +3 -4
- data/test/simple_tests/testing_the_headers_tag.cgi +3 -4
- data/test/simple_tests/testing_the_html_colours.cgi +2 -3
- data/test/simple_tests/testing_the_info_box.cgi +2 -3
- data/test/simple_tests/testing_the_li_tag.cgi +2 -1
- data/test/simple_tests/testing_the_s2_method.rb +6 -1
- data/test/simple_tests/testing_the_select_tag.cgi +16 -8
- data/test/simple_tests/testing_the_span_tag.cgi +2 -3
- data/test/simple_tests/testing_web_images.rb +4 -2
- data/test/testing_html_tags/button_example.cgi +6 -7
- metadata +345 -151
- data/doc/CONVENTIONS.md +0 -7
- data/doc/CYBERWEB_TUTORIAL.cgi +0 -43
- data/doc/FUTURE_DESIGN_GOAL_CONSIDERATIONS.md +0 -13
- data/doc/todo/TODO_FOR_THE_CYBERWEB_PROJECT.md +0 -1089
- data/examples/css/shadow_example_in_CSS.cgi +0 -30
- data/lib/cyberweb/charts/README.md +0 -2
- data/lib/cyberweb/charts/google_charts.rb +0 -51
- data/lib/cyberweb/colours/random_colour.rb +0 -28
- data/lib/cyberweb/colours/sanitize_for_colours.rb +0 -95
- data/lib/cyberweb/constants/array_local_css_files.rb +0 -35
- data/lib/cyberweb/constants/configuration_file.rb +0 -33
- data/lib/cyberweb/constants/http_status_codes.rb +0 -42
- data/lib/cyberweb/constants/project_constants.rb +0 -99
- data/lib/cyberweb/constants/standalone_constants.rb +0 -309
- data/lib/cyberweb/csv/README.md +0 -2
- data/lib/cyberweb/generator/webpage_for_images.rb +0 -553
- data/lib/cyberweb/html_codes/README.md +0 -15
- data/lib/cyberweb/images/real/README.md +0 -6
- data/lib/cyberweb/io/README.md +0 -1
- data/lib/cyberweb/javascript/scroll.rb +0 -17
- data/lib/cyberweb/objectified_html_tags/README.md +0 -8
- data/lib/cyberweb/objectified_html_tags/base.rb +0 -376
- data/lib/cyberweb/predefined_and_freeform_methods/hash_css_class_to_use.rb +0 -55
- data/lib/cyberweb/requires/require_charts.rb +0 -20
- data/lib/cyberweb/web_object/css.rb +0 -627
- data/lib/cyberweb/web_object/evaluate.rb +0 -126
- data/lib/cyberweb/web_object/html_related_tags.rb +0 -320
- data/lib/cyberweb/web_object/initialize.rb +0 -51
- data/lib/cyberweb/web_object/input_related_functionality.rb +0 -414
- data/lib/cyberweb/web_object/languages.rb +0 -172
- data/lib/cyberweb/web_object/params.rb +0 -289
- data/lib/cyberweb/web_object/sinatra_related_functionality.rb +0 -30
- data/lib/cyberweb/web_object/sitemap.rb +0 -176
- data/lib/cyberweb/web_object/table.rb +0 -378
- data/test/complex_tests/testing_objectified_html_tags.rb +0 -82
- data/test/javascript/testing_cheerleader_javascript.cgi +0 -0
@@ -0,0 +1,1131 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# Encoding: UTF-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
# =========================================================================== #
|
5
|
+
# === Cyberweb::REST::Base
|
6
|
+
#
|
7
|
+
# This is the Base class for all Sinatra applications and middleware.
|
8
|
+
# =========================================================================== #
|
9
|
+
# require 'cyberweb/REST/base/base.rb'
|
10
|
+
# =========================================================================== #
|
11
|
+
module Cyberweb
|
12
|
+
|
13
|
+
module REST
|
14
|
+
|
15
|
+
class Base # === Cyberweb::REST::Base
|
16
|
+
|
17
|
+
require 'cyberweb/REST/show_exceptions.rb'
|
18
|
+
require 'cyberweb/REST/base/not_found.rb'
|
19
|
+
|
20
|
+
require 'rack/protection'
|
21
|
+
|
22
|
+
require 'rack/utils'
|
23
|
+
include Rack::Utils
|
24
|
+
|
25
|
+
require 'cyberweb/REST/base/helpers/helpers.rb'
|
26
|
+
include Helpers
|
27
|
+
|
28
|
+
require 'cyberweb/REST/base/templates/templates.rb'
|
29
|
+
include Templates
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'mustermann'
|
33
|
+
rescue LoadError; end
|
34
|
+
|
35
|
+
# ========================================================================= #
|
36
|
+
# === URI_INSTANCE
|
37
|
+
# ========================================================================= #
|
38
|
+
URI_INSTANCE = URI::Parser.new
|
39
|
+
|
40
|
+
attr_accessor :app
|
41
|
+
attr_accessor :env
|
42
|
+
attr_accessor :request
|
43
|
+
attr_accessor :response
|
44
|
+
attr_accessor :params
|
45
|
+
attr_reader :template_cache
|
46
|
+
|
47
|
+
# ========================================================================= #
|
48
|
+
# === initialize
|
49
|
+
# ========================================================================= #
|
50
|
+
def initialize(app = nil, **_kwargs)
|
51
|
+
super()
|
52
|
+
@app = app
|
53
|
+
@template_cache = Tilt::Cache.new
|
54
|
+
@pinned_response = nil # whether a before! filter pinned the content-type
|
55
|
+
yield self if block_given?
|
56
|
+
end
|
57
|
+
|
58
|
+
# ========================================================================= #
|
59
|
+
# === template_cache?
|
60
|
+
# ========================================================================= #
|
61
|
+
def template_cache?
|
62
|
+
@template_cache
|
63
|
+
end
|
64
|
+
|
65
|
+
# ========================================================================= #
|
66
|
+
# === call
|
67
|
+
#
|
68
|
+
# Rack call interface.
|
69
|
+
# ========================================================================= #
|
70
|
+
def call(env)
|
71
|
+
dup.call!(env)
|
72
|
+
end
|
73
|
+
|
74
|
+
# ========================================================================= #
|
75
|
+
# === call!
|
76
|
+
# ========================================================================= #
|
77
|
+
def call!(env)
|
78
|
+
@env = env
|
79
|
+
@params = {}
|
80
|
+
@request = ::Cyberweb::REST::Request.new(env)
|
81
|
+
@response = ::Cyberweb::REST::Response.new
|
82
|
+
@pinned_response = nil
|
83
|
+
template_cache.clear if settings.reload_templates
|
84
|
+
|
85
|
+
invoke { dispatch! }
|
86
|
+
invoke { error_block!(response.status) } unless @env['sinatra.error']
|
87
|
+
|
88
|
+
unless @response['Content-Type']
|
89
|
+
if Array === body && body[0].respond_to?(:content_type)
|
90
|
+
content_type body[0].content_type
|
91
|
+
elsif (default = settings.default_content_type)
|
92
|
+
content_type default
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@response.finish
|
96
|
+
end
|
97
|
+
|
98
|
+
# ========================================================================= #
|
99
|
+
# Access settings defined with Base.set.
|
100
|
+
# ========================================================================= #
|
101
|
+
def self.settings
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# ========================================================================= #
|
106
|
+
# === settings
|
107
|
+
#
|
108
|
+
# Access settings defined with Base.set.
|
109
|
+
# ========================================================================= #
|
110
|
+
def settings
|
111
|
+
self.class.settings
|
112
|
+
end
|
113
|
+
|
114
|
+
# ========================================================================= #
|
115
|
+
# === halt
|
116
|
+
#
|
117
|
+
# Exit the current block, halts any further processing
|
118
|
+
# of the request, and returns the specified response.
|
119
|
+
# ========================================================================= #
|
120
|
+
def halt(*response)
|
121
|
+
response = response.first if response.length == 1
|
122
|
+
throw :halt, response
|
123
|
+
end
|
124
|
+
|
125
|
+
# ========================================================================= #
|
126
|
+
# === pass
|
127
|
+
#
|
128
|
+
# Pass control to the next matching route.
|
129
|
+
#
|
130
|
+
# If there are no more matching routes, Cyberweb::REST will return
|
131
|
+
# a 404 response.
|
132
|
+
# ========================================================================= #
|
133
|
+
def pass(&block)
|
134
|
+
throw :pass, block
|
135
|
+
end
|
136
|
+
|
137
|
+
# ========================================================================= #
|
138
|
+
# === forward
|
139
|
+
#
|
140
|
+
# Forward the request to the downstream app -- middleware only.
|
141
|
+
# ========================================================================= #
|
142
|
+
def forward
|
143
|
+
raise 'downstream app not set' unless @app.respond_to? :call
|
144
|
+
status, headers, body = @app.call env
|
145
|
+
@response.status = status
|
146
|
+
@response.body = body
|
147
|
+
@response.headers.merge! headers
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
# ========================================================================= #
|
154
|
+
# Run filters defined on the class and all superclasses.
|
155
|
+
# Accepts an optional block to call after each filter is applied.
|
156
|
+
# ========================================================================= #
|
157
|
+
def filter!(type, base = settings, &block)
|
158
|
+
filter!(type, base.superclass, &block) if base.superclass.respond_to?(:filters)
|
159
|
+
base.filters[type].each do |args|
|
160
|
+
result = process_route(*args)
|
161
|
+
block.call(result) if block_given?
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# ========================================================================= #
|
166
|
+
# Run routes defined on the class and all superclasses.
|
167
|
+
# ========================================================================= #
|
168
|
+
def route!(base = settings, pass_block = nil)
|
169
|
+
routes = base.routes[@request.request_method]
|
170
|
+
|
171
|
+
routes&.each { |pattern, conditions, block|
|
172
|
+
response.delete_header('Content-Type') unless @pinned_response
|
173
|
+
returned_pass_block = process_route(pattern, conditions) { |*args|
|
174
|
+
env['sinatra.route'] = "#{@request.request_method} #{pattern}"
|
175
|
+
route_eval { block[*args] }
|
176
|
+
}
|
177
|
+
|
178
|
+
# don't wipe out pass_block in superclass
|
179
|
+
pass_block = returned_pass_block if returned_pass_block
|
180
|
+
}
|
181
|
+
|
182
|
+
# Run routes defined in superclass.
|
183
|
+
if base.superclass.respond_to?(:routes)
|
184
|
+
return route!(base.superclass, pass_block)
|
185
|
+
end
|
186
|
+
|
187
|
+
route_eval(&pass_block) if pass_block
|
188
|
+
route_missing
|
189
|
+
end
|
190
|
+
|
191
|
+
# ========================================================================= #
|
192
|
+
# === route_eval
|
193
|
+
#
|
194
|
+
# Run a route block and throw :halt with the result.
|
195
|
+
# ========================================================================= #
|
196
|
+
def route_eval
|
197
|
+
throw :halt, yield
|
198
|
+
end
|
199
|
+
|
200
|
+
# ========================================================================= #
|
201
|
+
# === process_route
|
202
|
+
#
|
203
|
+
# If the current request matches pattern and conditions, fill params
|
204
|
+
# with keys and call the given block.
|
205
|
+
# Revert params afterwards.
|
206
|
+
#
|
207
|
+
# Returns pass block.
|
208
|
+
# ========================================================================= #
|
209
|
+
def process_route(
|
210
|
+
pattern, conditions, block = nil, values = []
|
211
|
+
)
|
212
|
+
route = @request.path_info
|
213
|
+
route = '/' if route.empty? && !settings.empty_path_info?
|
214
|
+
route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/')
|
215
|
+
|
216
|
+
params = pattern.params(route)
|
217
|
+
return unless params
|
218
|
+
|
219
|
+
params.delete('ignore') # TODO: better params handling, maybe turn it into "smart" object or detect changes
|
220
|
+
force_encoding(params)
|
221
|
+
@params = @params.merge(params) { |_k, v1, v2| v2 || v1 } if params.any?
|
222
|
+
|
223
|
+
regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? { |subpattern| subpattern.is_a?(Mustermann::Regular) })
|
224
|
+
if regexp_exists
|
225
|
+
captures = pattern.match(route).captures.map { |c| URI_INSTANCE.unescape(c) if c }
|
226
|
+
values += captures
|
227
|
+
@params[:captures] = force_encoding(captures) unless captures.nil? || captures.empty?
|
228
|
+
else
|
229
|
+
values += params.values.flatten
|
230
|
+
end
|
231
|
+
|
232
|
+
catch(:pass) do
|
233
|
+
conditions.each { |c|
|
234
|
+
throw :pass if c.bind(self).call == false
|
235
|
+
}
|
236
|
+
block ? block[self, values] : yield(self, values)
|
237
|
+
end
|
238
|
+
rescue StandardError
|
239
|
+
@env['rest.error.params'] = @params
|
240
|
+
raise
|
241
|
+
ensure
|
242
|
+
params ||= {}
|
243
|
+
params.each { |k, _| @params.delete(k) } unless @env['rest.error.params']
|
244
|
+
end
|
245
|
+
|
246
|
+
# === route_missing
|
247
|
+
#
|
248
|
+
# No matching route was found or all routes passed. The default
|
249
|
+
# implementation is to forward the request downstream when running
|
250
|
+
# as middleware (@app is non-nil); when no downstream app is set, raise
|
251
|
+
# a NotFound exception. Subclasses can override this method to perform
|
252
|
+
# custom route miss logic.
|
253
|
+
def route_missing
|
254
|
+
raise NotFound unless @app
|
255
|
+
forward
|
256
|
+
end
|
257
|
+
|
258
|
+
# === static!
|
259
|
+
#
|
260
|
+
# Attempt to serve static files from public directory. Throws :halt when
|
261
|
+
# a matching file is found, returns nil otherwise.
|
262
|
+
def static!(options = {})
|
263
|
+
return if (public_dir = settings.public_folder).nil?
|
264
|
+
|
265
|
+
path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}"
|
266
|
+
return unless valid_path?(path)
|
267
|
+
|
268
|
+
path = File.expand_path(path)
|
269
|
+
return unless path.start_with?("#{File.expand_path(public_dir)}/")
|
270
|
+
|
271
|
+
return unless File.file?(path)
|
272
|
+
|
273
|
+
env['sinatra.static_file'] = path
|
274
|
+
cache_control(*settings.static_cache_control) if settings.static_cache_control?
|
275
|
+
send_file path, options.merge(disposition: nil)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Run the block with 'throw :halt' support and apply result to the response.
|
279
|
+
def invoke(&block)
|
280
|
+
res = catch(:halt, &block)
|
281
|
+
|
282
|
+
res = [res] if (Integer === res) || (String === res)
|
283
|
+
if (Array === res) && (Integer === res.first)
|
284
|
+
res = res.dup
|
285
|
+
status(res.shift)
|
286
|
+
body(res.pop)
|
287
|
+
headers(*res)
|
288
|
+
elsif res.respond_to? :each
|
289
|
+
body res
|
290
|
+
end
|
291
|
+
nil # avoid double setting the same response tuple twice
|
292
|
+
end
|
293
|
+
|
294
|
+
# === dispatch!
|
295
|
+
#
|
296
|
+
# Dispatch a request with error handling.
|
297
|
+
def dispatch!
|
298
|
+
# Avoid passing frozen string in force_encoding
|
299
|
+
@params.merge!(@request.params).each do |key, val|
|
300
|
+
next unless val.respond_to?(:force_encoding)
|
301
|
+
|
302
|
+
val = val.dup if val.frozen?
|
303
|
+
@params[key] = force_encoding(val)
|
304
|
+
end
|
305
|
+
|
306
|
+
invoke do
|
307
|
+
static! if settings.static? && (request.get? || request.head?)
|
308
|
+
filter! :before do
|
309
|
+
@pinned_response = !response['Content-Type'].nil?
|
310
|
+
end
|
311
|
+
route!
|
312
|
+
end
|
313
|
+
rescue ::Exception => e
|
314
|
+
invoke { handle_exception!(e) }
|
315
|
+
ensure
|
316
|
+
begin
|
317
|
+
filter! :after unless env['sinatra.static_file']
|
318
|
+
rescue ::Exception => e
|
319
|
+
invoke { handle_exception!(e) } unless @env['sinatra.error']
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Error handling during requests.
|
324
|
+
def handle_exception!(boom)
|
325
|
+
error_params = @env['sinatra.error.params']
|
326
|
+
|
327
|
+
@params = @params.merge(error_params) if error_params
|
328
|
+
|
329
|
+
@env['sinatra.error'] = boom
|
330
|
+
|
331
|
+
http_status = if boom.is_a? ::Cyberweb::REST::Error
|
332
|
+
if boom.respond_to? :http_status
|
333
|
+
boom.http_status
|
334
|
+
elsif settings.use_code? && boom.respond_to?(:code)
|
335
|
+
boom.code
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
http_status = 500 unless http_status&.between?(400, 599)
|
340
|
+
status(http_status)
|
341
|
+
|
342
|
+
if server_error?
|
343
|
+
dump_errors! boom if settings.dump_errors?
|
344
|
+
raise boom if settings.show_exceptions? && (settings.show_exceptions != :after_handler)
|
345
|
+
elsif not_found?
|
346
|
+
headers['X-Cascade'] = 'pass' if settings.x_cascade?
|
347
|
+
end
|
348
|
+
|
349
|
+
if (res = error_block!(boom.class, boom) || error_block!(status, boom))
|
350
|
+
return res
|
351
|
+
end
|
352
|
+
|
353
|
+
if not_found? || bad_request?
|
354
|
+
if boom.message && boom.message != boom.class.name
|
355
|
+
body Rack::Utils.escape_html(boom.message)
|
356
|
+
else
|
357
|
+
content_type 'text/html'
|
358
|
+
body "<h1>#{not_found? ? 'Not Found' : 'Bad Request'}</h1>"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
return unless server_error?
|
363
|
+
|
364
|
+
raise boom if settings.raise_errors? || settings.show_exceptions?
|
365
|
+
error_block! Exception, boom
|
366
|
+
end
|
367
|
+
|
368
|
+
# Find an custom error block for the key(s) specified.
|
369
|
+
def error_block!(key, *block_params)
|
370
|
+
base = settings
|
371
|
+
while base.respond_to?(:errors)
|
372
|
+
args_array = base.errors[key]
|
373
|
+
|
374
|
+
next base = base.superclass unless args_array
|
375
|
+
args_array.reverse_each do |args|
|
376
|
+
first = args == args_array.first
|
377
|
+
args += [block_params]
|
378
|
+
resp = process_route(*args)
|
379
|
+
return resp unless resp.nil? && !first
|
380
|
+
end
|
381
|
+
end
|
382
|
+
return false unless key.respond_to?(:superclass) && (key.superclass < Exception)
|
383
|
+
|
384
|
+
error_block!(key.superclass, *block_params)
|
385
|
+
end
|
386
|
+
|
387
|
+
# === dump_errors!
|
388
|
+
def dump_errors!(boom)
|
389
|
+
msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
|
390
|
+
@env['rack.errors'].puts(msg)
|
391
|
+
end
|
392
|
+
|
393
|
+
class << self
|
394
|
+
# === CALLERS_TO_IGNORE
|
395
|
+
CALLERS_TO_IGNORE = [
|
396
|
+
%r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all cyberweb-rest code
|
397
|
+
%r{lib/tilt.*\.rb$}, # all tilt code
|
398
|
+
/^\(.*\)$/, # generated code
|
399
|
+
%r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
|
400
|
+
/active_support/, # active_support require hacks
|
401
|
+
%r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
|
402
|
+
/<internal:/ # internal in ruby >= 1.9.2
|
403
|
+
]
|
404
|
+
|
405
|
+
attr_reader :routes
|
406
|
+
attr_reader :filters
|
407
|
+
attr_reader :templates
|
408
|
+
attr_reader :errors
|
409
|
+
|
410
|
+
# === reset!
|
411
|
+
#
|
412
|
+
# Removes all routes, filters, middleware and extension hooks from the
|
413
|
+
# current class (not routes/filters/... defined by its superclass).
|
414
|
+
def reset!
|
415
|
+
@conditions = []
|
416
|
+
@routes = {}
|
417
|
+
@filters = { before: [], after: [] }
|
418
|
+
@errors = {}
|
419
|
+
@middleware = []
|
420
|
+
@prototype = nil
|
421
|
+
@extensions = []
|
422
|
+
|
423
|
+
@templates = if superclass.respond_to?(:templates)
|
424
|
+
Hash.new { |_hash, key| superclass.templates[key] }
|
425
|
+
else
|
426
|
+
{}
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# Extension modules registered on this class and all superclasses.
|
431
|
+
def extensions
|
432
|
+
if superclass.respond_to?(:extensions)
|
433
|
+
(@extensions + superclass.extensions).uniq
|
434
|
+
else
|
435
|
+
@extensions
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
# Middleware used in this class and all superclasses.
|
440
|
+
def middleware
|
441
|
+
if superclass.respond_to?(:middleware)
|
442
|
+
superclass.middleware + @middleware
|
443
|
+
else
|
444
|
+
@middleware
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
# Sets an option to the given value. If the value is a proc,
|
449
|
+
# the proc will be called every time the option is accessed.
|
450
|
+
def set(option, value = (not_set = true), ignore_setter = false, &block)
|
451
|
+
raise ArgumentError if block && !not_set
|
452
|
+
|
453
|
+
if block
|
454
|
+
value = block
|
455
|
+
not_set = false
|
456
|
+
end
|
457
|
+
|
458
|
+
if not_set
|
459
|
+
raise ArgumentError unless option.respond_to?(:each)
|
460
|
+
|
461
|
+
option.each { |k, v| set(k, v) }
|
462
|
+
return self
|
463
|
+
end
|
464
|
+
|
465
|
+
if respond_to?("#{option}=") && !ignore_setter
|
466
|
+
return __send__("#{option}=", value)
|
467
|
+
end
|
468
|
+
|
469
|
+
setter = proc { |val| set option, val, true }
|
470
|
+
getter = proc { value }
|
471
|
+
|
472
|
+
case value
|
473
|
+
when Proc
|
474
|
+
getter = value
|
475
|
+
when Symbol, Integer, FalseClass, TrueClass, NilClass
|
476
|
+
getter = value.inspect
|
477
|
+
when Hash
|
478
|
+
setter = proc do |val|
|
479
|
+
val = value.merge val if Hash === val
|
480
|
+
set option, val, true
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
define_singleton("#{option}=", setter)
|
485
|
+
define_singleton(option, getter)
|
486
|
+
define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
|
487
|
+
self
|
488
|
+
end
|
489
|
+
|
490
|
+
# Same as calling `set :option, true` for each of the given options.
|
491
|
+
def enable(*opts)
|
492
|
+
opts.each { |key| set(key, true) }
|
493
|
+
end
|
494
|
+
|
495
|
+
# Same as calling `set :option, false` for each of the given options.
|
496
|
+
def disable(*opts)
|
497
|
+
opts.each { |key| set(key, false) }
|
498
|
+
end
|
499
|
+
|
500
|
+
# Define a custom error handler. Optionally takes either an Exception
|
501
|
+
# class, or an HTTP status code to specify which errors should be
|
502
|
+
# handled.
|
503
|
+
def error(*codes, &block)
|
504
|
+
args = compile! 'ERROR', /.*/, block
|
505
|
+
codes = codes.flat_map(&method(:Array))
|
506
|
+
codes << Exception if codes.empty?
|
507
|
+
codes << ::Cyberweb::REST::NotFound if codes.include?(404)
|
508
|
+
codes.each { |c| (@errors[c] ||= []) << args }
|
509
|
+
end
|
510
|
+
|
511
|
+
# Sugar for `error(404) { ... }`
|
512
|
+
def not_found(&block)
|
513
|
+
error(404, &block)
|
514
|
+
end
|
515
|
+
|
516
|
+
# Define a named template. The block must return the template source.
|
517
|
+
def template(name, &block)
|
518
|
+
filename, line = caller_locations.first
|
519
|
+
templates[name] = [block, filename, line.to_i]
|
520
|
+
end
|
521
|
+
|
522
|
+
# Define the layout template. The block must return the template source.
|
523
|
+
def layout(name = :layout, &block)
|
524
|
+
template name, &block
|
525
|
+
end
|
526
|
+
|
527
|
+
# Load embedded templates from the file; uses the caller's __FILE__
|
528
|
+
# when no file is specified.
|
529
|
+
def inline_templates=(file = nil)
|
530
|
+
file = (caller_files.first || File.expand_path($0)) if file.nil? || file == true
|
531
|
+
|
532
|
+
begin
|
533
|
+
io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
|
534
|
+
app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
|
535
|
+
rescue Errno::ENOENT
|
536
|
+
app, data = nil
|
537
|
+
end
|
538
|
+
|
539
|
+
return unless data
|
540
|
+
|
541
|
+
encoding = if app && app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
|
542
|
+
$2
|
543
|
+
else
|
544
|
+
settings.default_encoding
|
545
|
+
end
|
546
|
+
|
547
|
+
lines = app.count("\n") + 1
|
548
|
+
template = nil
|
549
|
+
force_encoding data, encoding
|
550
|
+
data.each_line do |line|
|
551
|
+
lines += 1
|
552
|
+
if line =~ /^@@\s*(.*\S)\s*$/
|
553
|
+
template = force_encoding(String.new, encoding)
|
554
|
+
templates[$1.to_sym] = [template, file, lines]
|
555
|
+
elsif template
|
556
|
+
template << line
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
# Lookup or register a mime type in Rack's mime registry.
|
562
|
+
def mime_type(type, value = nil)
|
563
|
+
return type if type.nil?
|
564
|
+
return type.to_s if type.to_s.include?('/')
|
565
|
+
|
566
|
+
type = ".#{type}" unless type.to_s[0] == '.'
|
567
|
+
return Rack::Mime.mime_type(type, nil) unless value
|
568
|
+
|
569
|
+
Rack::Mime::MIME_TYPES[type] = value
|
570
|
+
end
|
571
|
+
|
572
|
+
# provides all mime types matching type, including deprecated types:
|
573
|
+
# mime_types :html # => ['text/html']
|
574
|
+
# mime_types :js # => ['application/javascript', 'text/javascript']
|
575
|
+
def mime_types(type)
|
576
|
+
type = mime_type type
|
577
|
+
type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
|
578
|
+
end
|
579
|
+
|
580
|
+
# Define a before filter; runs before all requests within the same
|
581
|
+
# context as route handlers and may access/modify the request and
|
582
|
+
# response.
|
583
|
+
def before(path = /.*/, **options, &block)
|
584
|
+
add_filter(:before, path, **options, &block)
|
585
|
+
end
|
586
|
+
|
587
|
+
# Define an after filter; runs after all requests within the same
|
588
|
+
# context as route handlers and may access/modify the request and
|
589
|
+
# response.
|
590
|
+
def after(path = /.*/, **options, &block)
|
591
|
+
add_filter(:after, path, **options, &block)
|
592
|
+
end
|
593
|
+
|
594
|
+
# add a filter
|
595
|
+
def add_filter(type, path = /.*/, **options, &block)
|
596
|
+
filters[type] << compile!(type, path, block, **options)
|
597
|
+
end
|
598
|
+
|
599
|
+
# Add a route condition. The route is considered non-matching when the
|
600
|
+
# block returns false.
|
601
|
+
def condition(name = "#{caller.first[/`.*'/]} condition", &block)
|
602
|
+
@conditions << generate_method(name, &block)
|
603
|
+
end
|
604
|
+
|
605
|
+
def public=(value)
|
606
|
+
warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
|
607
|
+
set(:public_folder, value)
|
608
|
+
end
|
609
|
+
|
610
|
+
def public_dir=(value)
|
611
|
+
self.public_folder = value
|
612
|
+
end
|
613
|
+
|
614
|
+
def public_dir
|
615
|
+
public_folder
|
616
|
+
end
|
617
|
+
|
618
|
+
# Defining a `GET` handler also automatically defines
|
619
|
+
# a `HEAD` handler.
|
620
|
+
def get(path, opts = {}, &block)
|
621
|
+
conditions = @conditions.dup
|
622
|
+
route('GET', path, opts, &block)
|
623
|
+
|
624
|
+
@conditions = conditions
|
625
|
+
route('HEAD', path, opts, &block)
|
626
|
+
end
|
627
|
+
|
628
|
+
def put(path, opts = {}, &block) route 'PUT', path, opts, &block end
|
629
|
+
|
630
|
+
def post(path, opts = {}, &block) route 'POST', path, opts, &block end
|
631
|
+
|
632
|
+
def delete(path, opts = {}, &block) route 'DELETE', path, opts, &block end
|
633
|
+
|
634
|
+
def head(path, opts = {}, &block) route 'HEAD', path, opts, &block end
|
635
|
+
|
636
|
+
def options(path, opts = {}, &block) route 'OPTIONS', path, opts, &block end
|
637
|
+
|
638
|
+
def patch(path, opts = {}, &block) route 'PATCH', path, opts, &block end
|
639
|
+
|
640
|
+
def link(path, opts = {}, &block) route 'LINK', path, opts, &block end
|
641
|
+
|
642
|
+
def unlink(path, opts = {}, &block) route 'UNLINK', path, opts, &block end
|
643
|
+
|
644
|
+
# Makes the methods defined in the block and in the Modules given
|
645
|
+
# in `extensions` available to the handlers and templates
|
646
|
+
def helpers(*extensions, &block)
|
647
|
+
class_eval(&block) if block_given?
|
648
|
+
include(*extensions) if extensions.any?
|
649
|
+
end
|
650
|
+
|
651
|
+
# Register an extension. Alternatively take a block from which an
|
652
|
+
# extension will be created and registered on the fly.
|
653
|
+
def register(*extensions, &block)
|
654
|
+
extensions << Module.new(&block) if block_given?
|
655
|
+
@extensions += extensions
|
656
|
+
extensions.each do |extension|
|
657
|
+
extend extension
|
658
|
+
extension.registered(self) if extension.respond_to?(:registered)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
def development?; environment == :development end
|
663
|
+
def production?; environment == :production end
|
664
|
+
def test?; environment == :test end
|
665
|
+
|
666
|
+
# === configure
|
667
|
+
#
|
668
|
+
# Set configuration options for Sinatra and/or the app.
|
669
|
+
# Allows scoping of settings for certain environments.
|
670
|
+
def configure(*envs)
|
671
|
+
yield self if envs.empty? || envs.include?(environment.to_sym)
|
672
|
+
end
|
673
|
+
|
674
|
+
# Use the specified Rack middleware
|
675
|
+
def use(middleware, *args, &block)
|
676
|
+
@prototype = nil
|
677
|
+
@middleware << [middleware, args, block]
|
678
|
+
end
|
679
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
680
|
+
|
681
|
+
# Stop the self-hosted server if running.
|
682
|
+
def quit!
|
683
|
+
return unless running?
|
684
|
+
|
685
|
+
# Use Thin's hard #stop! if available, otherwise just #stop.
|
686
|
+
running_server.respond_to?(:stop!) ? running_server.stop! : running_server.stop
|
687
|
+
warn '== Cyberweb::REST has ended his set (crowd applauds)' unless suppress_messages?
|
688
|
+
set :running_server, nil
|
689
|
+
set :handler_name, nil
|
690
|
+
end; alias stop! quit! # === stop!
|
691
|
+
|
692
|
+
# === run
|
693
|
+
#
|
694
|
+
# Run the CyberweB::REST app as a self-hosted server using
|
695
|
+
# Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call
|
696
|
+
# with the constructed handler once we have taken the stage.
|
697
|
+
def run!(options = {}, &block)
|
698
|
+
return if running?
|
699
|
+
|
700
|
+
set options
|
701
|
+
handler = Rack::Handler.pick(server)
|
702
|
+
handler_name = handler.name.gsub(/.*::/, '')
|
703
|
+
server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
|
704
|
+
server_settings.merge!(Port: port, Host: bind)
|
705
|
+
|
706
|
+
begin
|
707
|
+
start_server(handler, server_settings, handler_name, &block)
|
708
|
+
rescue Errno::EADDRINUSE
|
709
|
+
warn "== Someone is already performing on port #{port}!"
|
710
|
+
raise
|
711
|
+
ensure
|
712
|
+
quit!
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
alias start! run!
|
717
|
+
|
718
|
+
# Check whether the self-hosted server is running or not.
|
719
|
+
def running?
|
720
|
+
running_server?
|
721
|
+
end
|
722
|
+
|
723
|
+
# The prototype instance used to process requests.
|
724
|
+
def prototype
|
725
|
+
@prototype ||= new
|
726
|
+
end
|
727
|
+
|
728
|
+
# Create a new instance without middleware in front of it.
|
729
|
+
alias new! new unless method_defined? :new!
|
730
|
+
|
731
|
+
# Create a new instance of the class fronted by its middleware
|
732
|
+
# pipeline. The object is guaranteed to respond to #call but may not be
|
733
|
+
# an instance of the class new was called on.
|
734
|
+
def new(*args, &block)
|
735
|
+
instance = new!(*args, &block)
|
736
|
+
Wrapper.new(build(instance).to_app, instance)
|
737
|
+
end
|
738
|
+
ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
|
739
|
+
|
740
|
+
# Creates a Rack::Builder instance with all the middleware set up and
|
741
|
+
# the given +app+ as end point.
|
742
|
+
def build(app)
|
743
|
+
builder = Rack::Builder.new
|
744
|
+
setup_default_middleware builder
|
745
|
+
setup_middleware builder
|
746
|
+
builder.run app
|
747
|
+
builder
|
748
|
+
end
|
749
|
+
|
750
|
+
def call(env)
|
751
|
+
synchronize { prototype.call(env) }
|
752
|
+
end
|
753
|
+
|
754
|
+
# Like Kernel#caller but excluding certain magic entries and without
|
755
|
+
# line / method information; the resulting array contains filenames only.
|
756
|
+
def caller_files
|
757
|
+
cleaned_caller(1).flatten
|
758
|
+
end
|
759
|
+
|
760
|
+
private
|
761
|
+
|
762
|
+
# === start_server
|
763
|
+
#
|
764
|
+
# Starts the server by running the Rack Handler.
|
765
|
+
def start_server(handler, server_settings, handler_name)
|
766
|
+
pp 'STARTING HIER'
|
767
|
+
# Ensure we initialize middleware before startup, to match standard Rack
|
768
|
+
# behavior, by ensuring an instance exists:
|
769
|
+
prototype
|
770
|
+
# Run the instance we created:
|
771
|
+
handler.run(self, **server_settings) do |server|
|
772
|
+
unless suppress_messages?
|
773
|
+
warn "== Cyberweb::REST has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
|
774
|
+
end
|
775
|
+
|
776
|
+
setup_traps
|
777
|
+
set :running_server, server
|
778
|
+
set :handler_name, handler_name
|
779
|
+
server.threaded = settings.threaded if server.respond_to? :threaded=
|
780
|
+
|
781
|
+
yield server if block_given?
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
def suppress_messages?
|
786
|
+
handler_name =~ /cgi/i || quiet
|
787
|
+
end
|
788
|
+
|
789
|
+
def setup_traps
|
790
|
+
return unless traps?
|
791
|
+
|
792
|
+
at_exit { quit! }
|
793
|
+
|
794
|
+
%i[INT TERM].each do |signal|
|
795
|
+
old_handler = trap(signal) do
|
796
|
+
quit!
|
797
|
+
old_handler.call if old_handler.respond_to?(:call)
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
set :traps, false
|
802
|
+
end
|
803
|
+
|
804
|
+
# Dynamically defines a method on settings.
|
805
|
+
def define_singleton(name, content = Proc.new)
|
806
|
+
singleton_class.class_eval do
|
807
|
+
undef_method(name) if method_defined? name
|
808
|
+
String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content)
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
# Condition for matching host name. Parameter might be String or Regexp.
|
813
|
+
def host_name(pattern)
|
814
|
+
condition { pattern === request.host }
|
815
|
+
end
|
816
|
+
|
817
|
+
# Condition for matching user agent. Parameter should be Regexp.
|
818
|
+
# Will set params[:agent].
|
819
|
+
def user_agent(pattern)
|
820
|
+
condition do
|
821
|
+
if request.user_agent.to_s =~ pattern
|
822
|
+
@params[:agent] = $~[1..-1]
|
823
|
+
true
|
824
|
+
else
|
825
|
+
false
|
826
|
+
end
|
827
|
+
end
|
828
|
+
end
|
829
|
+
alias agent user_agent
|
830
|
+
|
831
|
+
# Condition for matching mimetypes. Accepts file extensions.
|
832
|
+
def provides(*types)
|
833
|
+
types.map! { |t| mime_types(t) }
|
834
|
+
types.flatten!
|
835
|
+
condition do
|
836
|
+
response_content_type = response['Content-Type']
|
837
|
+
preferred_type = request.preferred_type(types)
|
838
|
+
|
839
|
+
if response_content_type
|
840
|
+
types.include?(response_content_type) || types.include?(response_content_type[/^[^;]+/])
|
841
|
+
elsif preferred_type
|
842
|
+
params = (preferred_type.respond_to?(:params) ? preferred_type.params : {})
|
843
|
+
content_type(preferred_type, params)
|
844
|
+
true
|
845
|
+
else
|
846
|
+
false
|
847
|
+
end
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
def route(verb, path, options = {}, &block)
|
852
|
+
enable :empty_path_info if path == '' && empty_path_info.nil?
|
853
|
+
signature = compile!(verb, path, block, **options)
|
854
|
+
(@routes[verb] ||= []) << signature
|
855
|
+
invoke_hook(:route_added, verb, path, block)
|
856
|
+
signature
|
857
|
+
end
|
858
|
+
|
859
|
+
def invoke_hook(name, *args)
|
860
|
+
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
861
|
+
end
|
862
|
+
|
863
|
+
def generate_method(method_name, &block)
|
864
|
+
define_method(method_name, &block)
|
865
|
+
method = instance_method method_name
|
866
|
+
remove_method method_name
|
867
|
+
method
|
868
|
+
end
|
869
|
+
|
870
|
+
def compile!(verb, path, block, **options)
|
871
|
+
# Because of self.options.host
|
872
|
+
host_name(options.delete(:host)) if options.key?(:host)
|
873
|
+
# Pass Mustermann opts to compile()
|
874
|
+
route_mustermann_opts = options.key?(:mustermann_opts) ? options.delete(:mustermann_opts) : {}
|
875
|
+
|
876
|
+
options.each_pair { |option, args| send(option, *args) }
|
877
|
+
|
878
|
+
pattern = compile(path, route_mustermann_opts)
|
879
|
+
method_name = "#{verb} #{path}"
|
880
|
+
unbound_method = generate_method(method_name, &block)
|
881
|
+
conditions = @conditions
|
882
|
+
@conditions = []
|
883
|
+
wrapper = block.arity.zero? ?
|
884
|
+
proc { |a, _p| unbound_method.bind(a).call } :
|
885
|
+
proc { |a, p| unbound_method.bind(a).call(*p) }
|
886
|
+
|
887
|
+
[pattern, conditions, wrapper]
|
888
|
+
end
|
889
|
+
|
890
|
+
# === compile
|
891
|
+
def compile(path, route_mustermann_opts = {})
|
892
|
+
Mustermann.new(path, **mustermann_opts.merge(route_mustermann_opts))
|
893
|
+
end
|
894
|
+
# === setup_default_middleware
|
895
|
+
def setup_default_middleware(builder)
|
896
|
+
builder.use ExtendedRack
|
897
|
+
builder.use ShowExceptions if show_exceptions?
|
898
|
+
builder.use Rack::MethodOverride if method_override?
|
899
|
+
builder.use Rack::Head
|
900
|
+
setup_logging builder
|
901
|
+
setup_sessions builder
|
902
|
+
setup_protection builder
|
903
|
+
end
|
904
|
+
|
905
|
+
def setup_middleware(builder)
|
906
|
+
middleware.each { |c, a, b| builder.use(c, *a, &b) }
|
907
|
+
end
|
908
|
+
|
909
|
+
def setup_logging(builder)
|
910
|
+
if logging?
|
911
|
+
setup_common_logger(builder)
|
912
|
+
setup_custom_logger(builder)
|
913
|
+
elsif logging == false
|
914
|
+
setup_null_logger(builder)
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
def setup_null_logger(builder)
|
919
|
+
builder.use Rack::NullLogger
|
920
|
+
end
|
921
|
+
# === setup_common_logger
|
922
|
+
def setup_common_logger(builder)
|
923
|
+
builder.use ::CyberweB::REST::CommonLogger
|
924
|
+
end
|
925
|
+
|
926
|
+
def setup_custom_logger(builder)
|
927
|
+
if logging.respond_to? :to_int
|
928
|
+
builder.use Rack::Logger, logging
|
929
|
+
else
|
930
|
+
builder.use Rack::Logger
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
def setup_protection(builder)
|
935
|
+
return unless protection?
|
936
|
+
|
937
|
+
options = Hash === protection ? protection.dup : {}
|
938
|
+
options = {
|
939
|
+
img_src: "'self' data:",
|
940
|
+
font_src: "'self'"
|
941
|
+
}.merge options
|
942
|
+
|
943
|
+
protect_session = options.fetch(:session) { sessions? }
|
944
|
+
options[:without_session] = !protect_session
|
945
|
+
|
946
|
+
options[:reaction] ||= :drop_session
|
947
|
+
|
948
|
+
builder.use Rack::Protection, options
|
949
|
+
end
|
950
|
+
|
951
|
+
def setup_sessions(builder)
|
952
|
+
return unless sessions?
|
953
|
+
|
954
|
+
options = {}
|
955
|
+
options[:secret] = session_secret if session_secret?
|
956
|
+
options.merge! sessions.to_hash if sessions.respond_to? :to_hash
|
957
|
+
builder.use session_store, options
|
958
|
+
end
|
959
|
+
|
960
|
+
def inherited(subclass)
|
961
|
+
subclass.reset!
|
962
|
+
subclass.set :app_file, caller_files.first unless subclass.app_file?
|
963
|
+
super
|
964
|
+
end
|
965
|
+
|
966
|
+
@@mutex = Mutex.new
|
967
|
+
def synchronize(&block)
|
968
|
+
if lock?
|
969
|
+
@@mutex.synchronize(&block)
|
970
|
+
else
|
971
|
+
yield
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
# used for deprecation warnings
|
976
|
+
def warn_for_deprecation(message)
|
977
|
+
warn message + "\n\tfrom #{cleaned_caller.first.join(':')}"
|
978
|
+
end
|
979
|
+
|
980
|
+
# Like Kernel#caller but excluding certain magic entries
|
981
|
+
def cleaned_caller(keep = 3)
|
982
|
+
caller(1)
|
983
|
+
.map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] }
|
984
|
+
.reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
# Force data to specified encoding. It defaults to settings.default_encoding
|
989
|
+
# which is UTF-8 by default
|
990
|
+
def self.force_encoding(data, encoding = default_encoding)
|
991
|
+
return if data == settings || data.is_a?(Tempfile)
|
992
|
+
if data.respond_to? :force_encoding
|
993
|
+
data.force_encoding(encoding).encode!
|
994
|
+
elsif data.respond_to? :each_value
|
995
|
+
data.each_value { |v| force_encoding(v, encoding) }
|
996
|
+
elsif data.respond_to? :each
|
997
|
+
data.each { |v| force_encoding(v, encoding) }
|
998
|
+
end
|
999
|
+
data
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
# === force_encoding
|
1003
|
+
def force_encoding(*args)
|
1004
|
+
settings.force_encoding(*args)
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
reset!
|
1008
|
+
|
1009
|
+
set :environment, (ENV['APP_ENV'] || ENV['RACK_ENV'] || :development).to_sym
|
1010
|
+
set :raise_errors, proc { test? }
|
1011
|
+
set :dump_errors, proc { !test? }
|
1012
|
+
set :show_exceptions, proc { development? }
|
1013
|
+
set :sessions, false
|
1014
|
+
set :session_store, Rack::Protection::EncryptedCookie
|
1015
|
+
set :logging, false
|
1016
|
+
set :protection, true
|
1017
|
+
set :method_override, false
|
1018
|
+
set :use_code, false
|
1019
|
+
set :default_encoding, 'utf-8'
|
1020
|
+
set :x_cascade, true
|
1021
|
+
set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
|
1022
|
+
settings.add_charset << %r{^text/}
|
1023
|
+
set :mustermann_opts, {}
|
1024
|
+
set :default_content_type, 'text/html'
|
1025
|
+
|
1026
|
+
# explicitly generating a session secret eagerly to play nice with preforking
|
1027
|
+
begin
|
1028
|
+
require 'securerandom'
|
1029
|
+
set :session_secret, SecureRandom.hex(64)
|
1030
|
+
rescue LoadError, NotImplementedError
|
1031
|
+
# SecureRandom raises a NotImplementedError if no random device is available
|
1032
|
+
set :session_secret, format('%064x', Kernel.rand((2**256) - 1))
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
class << self
|
1036
|
+
alias methodoverride? method_override?
|
1037
|
+
alias methodoverride= method_override=
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
set :run, false # start server via at-exit hook?
|
1041
|
+
set :running_server, nil
|
1042
|
+
set :handler_name, nil
|
1043
|
+
set :traps, true
|
1044
|
+
set :server, %w[HTTP webrick]
|
1045
|
+
set :bind, proc { development? ? 'localhost' : '0.0.0.0' }
|
1046
|
+
set :port, Integer(ENV['PORT'] && !ENV['PORT'].empty? ? ENV['PORT'] : 4567)
|
1047
|
+
set :quiet, false
|
1048
|
+
|
1049
|
+
ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
1050
|
+
|
1051
|
+
server.unshift 'puma'
|
1052
|
+
server.unshift 'falcon' if ruby_engine != 'jruby'
|
1053
|
+
server.unshift 'mongrel' if ruby_engine.nil?
|
1054
|
+
server.unshift 'thin' if ruby_engine != 'jruby'
|
1055
|
+
server.unshift 'trinidad' if ruby_engine == 'jruby'
|
1056
|
+
|
1057
|
+
set :absolute_redirects, true
|
1058
|
+
set :prefixed_redirects, false
|
1059
|
+
set :empty_path_info, nil
|
1060
|
+
set :strict_paths, true
|
1061
|
+
|
1062
|
+
set :app_file, nil
|
1063
|
+
set :root, proc { app_file && File.expand_path(File.dirname(app_file)) }
|
1064
|
+
set :views, proc { root && File.join(root, 'views') }
|
1065
|
+
set :reload_templates, proc { development? }
|
1066
|
+
set :lock, false
|
1067
|
+
set :threaded, true
|
1068
|
+
|
1069
|
+
set :public_folder, proc { root && File.join(root, 'public') }
|
1070
|
+
set :static, proc { public_folder && File.exist?(public_folder) }
|
1071
|
+
set :static_cache_control, false
|
1072
|
+
|
1073
|
+
error(::Exception) {
|
1074
|
+
response.status = 500
|
1075
|
+
content_type 'text/html'
|
1076
|
+
'<h1>Internal Server Error</h1>'
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
configure :development do
|
1080
|
+
get('/__sinatra__/:image.png') {
|
1081
|
+
filename = __dir__ + "/images/#{params[:image].to_i}.png"
|
1082
|
+
content_type :png
|
1083
|
+
send_file filename
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
error NotFound do
|
1087
|
+
content_type 'text/html'
|
1088
|
+
|
1089
|
+
if instance_of?(Sinatra::Application)
|
1090
|
+
code = <<-RUBY.gsub(/^ {12}/, '')
|
1091
|
+
#{request.request_method.downcase} '#{request.path_info}' do
|
1092
|
+
"Hello World"
|
1093
|
+
end
|
1094
|
+
RUBY
|
1095
|
+
else
|
1096
|
+
code = <<-RUBY.gsub(/^ {12}/, '')
|
1097
|
+
class #{self.class}
|
1098
|
+
#{request.request_method.downcase} '#{request.path_info}' do
|
1099
|
+
"Hello World"
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
RUBY
|
1103
|
+
|
1104
|
+
file = settings.app_file.to_s.sub(settings.root.to_s, '').sub(%r{^/}, '')
|
1105
|
+
code = "# in #{file}\n#{code}" unless file.empty?
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
<<-HTML.gsub(/^ {10}/, '')
|
1109
|
+
<!DOCTYPE html>
|
1110
|
+
<html>
|
1111
|
+
<head>
|
1112
|
+
<style type="text/css">
|
1113
|
+
body { text-align:center;font-family:helvetica,arial;font-size:22px;
|
1114
|
+
color:#888;margin:20px}
|
1115
|
+
#c {margin:0 auto;width:500px;text-align:left}
|
1116
|
+
</style>
|
1117
|
+
</head>
|
1118
|
+
<body>
|
1119
|
+
<h2>Sinatra doesn’t know this ditty.</h2>
|
1120
|
+
<img src='#{uri '/__sinatra__/404.png'}'>
|
1121
|
+
<div id="c">
|
1122
|
+
Try this:
|
1123
|
+
<pre>#{Rack::Utils.escape_html(code)}</pre>
|
1124
|
+
</div>
|
1125
|
+
</body>
|
1126
|
+
</html>
|
1127
|
+
HTML
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
end; end; end
|