thorero 0.9.4.4 → 0.9.4.5
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/LICENSE +1 -1
- data/README +21 -0
- data/Rakefile +275 -108
- data/TODO +0 -0
- data/bin/merb +12 -0
- data/bin/merb-specs +5 -0
- data/docs/bootloading.dox +58 -0
- data/docs/documentation_standards +40 -0
- data/docs/merb-core-call-stack-diagram.mmap +0 -0
- data/docs/merb-core-call-stack-diagram.pdf +0 -0
- data/docs/merb-core-call-stack-diagram.png +0 -0
- data/docs/new_render_api +51 -0
- data/lib/merb-core.rb +603 -0
- data/lib/merb-core/autoload.rb +32 -0
- data/lib/merb-core/bootloader.rb +708 -0
- data/lib/merb-core/config.rb +303 -0
- data/lib/merb-core/constants.rb +43 -0
- data/lib/merb-core/controller/abstract_controller.rb +578 -0
- data/lib/merb-core/controller/exceptions.rb +302 -0
- data/lib/merb-core/controller/merb_controller.rb +256 -0
- data/lib/merb-core/controller/mime.rb +106 -0
- data/lib/merb-core/controller/mixins/authentication.rb +87 -0
- data/lib/merb-core/controller/mixins/controller.rb +290 -0
- data/lib/merb-core/controller/mixins/render.rb +481 -0
- data/lib/merb-core/controller/mixins/responder.rb +472 -0
- data/lib/merb-core/controller/template.rb +254 -0
- data/lib/merb-core/core_ext.rb +8 -0
- data/lib/merb-core/core_ext/kernel.rb +319 -0
- data/lib/merb-core/dispatch/cookies.rb +91 -0
- data/lib/merb-core/dispatch/dispatcher.rb +278 -0
- data/lib/merb-core/dispatch/exceptions.html.erb +303 -0
- data/lib/merb-core/dispatch/request.rb +603 -0
- data/lib/merb-core/dispatch/router.rb +179 -0
- data/lib/merb-core/dispatch/router/behavior.rb +867 -0
- data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
- data/lib/merb-core/dispatch/router/route.rb +321 -0
- data/lib/merb-core/dispatch/session.rb +78 -0
- data/lib/merb-core/dispatch/session/cookie.rb +168 -0
- data/lib/merb-core/dispatch/session/memcached.rb +184 -0
- data/lib/merb-core/dispatch/session/memory.rb +241 -0
- data/lib/merb-core/dispatch/worker.rb +28 -0
- data/lib/merb-core/gem_ext/erubis.rb +77 -0
- data/lib/{extlib → merb-core}/logger.rb +2 -2
- data/lib/merb-core/plugins.rb +59 -0
- data/lib/merb-core/rack.rb +21 -0
- data/lib/merb-core/rack/adapter.rb +44 -0
- data/lib/merb-core/rack/adapter/ebb.rb +25 -0
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
- data/lib/merb-core/rack/adapter/irb.rb +118 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/runner.rb +28 -0
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/thin.rb +39 -0
- data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
- data/lib/merb-core/rack/adapter/webrick.rb +36 -0
- data/lib/merb-core/rack/application.rb +18 -0
- data/lib/merb-core/rack/handler/mongrel.rb +97 -0
- data/lib/merb-core/rack/middleware.rb +26 -0
- data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
- data/lib/merb-core/rack/middleware/profiler.rb +19 -0
- data/lib/merb-core/rack/middleware/static.rb +45 -0
- data/lib/merb-core/server.rb +252 -0
- data/lib/merb-core/tasks/audit.rake +68 -0
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -0
- data/lib/merb-core/test.rb +11 -0
- data/lib/merb-core/test/helpers.rb +9 -0
- data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
- data/lib/merb-core/test/helpers/request_helper.rb +344 -0
- data/lib/merb-core/test/helpers/route_helper.rb +33 -0
- data/lib/merb-core/test/helpers/view_helper.rb +121 -0
- data/lib/merb-core/test/matchers.rb +9 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +319 -0
- data/lib/merb-core/test/matchers/route_matchers.rb +136 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +335 -0
- data/lib/merb-core/test/run_specs.rb +47 -0
- data/lib/merb-core/test/tasks/spectasks.rb +68 -0
- data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
- data/lib/merb-core/test/test_ext/object.rb +14 -0
- data/lib/merb-core/test/test_ext/string.rb +14 -0
- data/lib/merb-core/vendor/facets.rb +2 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
- data/lib/merb-core/vendor/facets/inflect.rb +345 -0
- data/lib/merb-core/version.rb +11 -0
- data/spec/private/config/adapter_spec.rb +32 -0
- data/spec/private/config/config_spec.rb +202 -0
- data/spec/private/config/environment_spec.rb +13 -0
- data/spec/private/config/spec_helper.rb +1 -0
- data/spec/private/core_ext/kernel_spec.rb +169 -0
- data/spec/private/dispatch/bootloader_spec.rb +24 -0
- data/spec/private/dispatch/cookies_spec.rb +107 -0
- data/spec/private/dispatch/dispatch_spec.rb +35 -0
- data/spec/private/dispatch/fixture/app/controllers/application.rb +4 -0
- data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +27 -0
- data/spec/private/dispatch/fixture/app/controllers/foo.rb +21 -0
- data/spec/private/dispatch/fixture/app/helpers/global_helpers.rb +8 -0
- data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +37 -0
- data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +216 -0
- data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +38 -0
- data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +40 -0
- data/spec/private/dispatch/fixture/app/views/foo/bar.html.erb +0 -0
- data/spec/private/dispatch/fixture/app/views/layout/application.html.erb +11 -0
- data/spec/private/dispatch/fixture/config/black_hole.rb +12 -0
- data/spec/private/dispatch/fixture/config/environments/development.rb +6 -0
- data/spec/private/dispatch/fixture/config/environments/production.rb +5 -0
- data/spec/private/dispatch/fixture/config/environments/test.rb +6 -0
- data/spec/private/dispatch/fixture/config/init.rb +45 -0
- data/spec/private/dispatch/fixture/config/rack.rb +11 -0
- data/spec/private/dispatch/fixture/config/router.rb +35 -0
- data/spec/private/dispatch/fixture/log/merb_test.log +1874 -0
- data/spec/private/dispatch/fixture/public/images/merb.jpg +0 -0
- data/spec/private/dispatch/fixture/public/merb.fcgi +4 -0
- data/spec/private/dispatch/fixture/public/stylesheets/master.css +119 -0
- data/spec/private/dispatch/route_params_spec.rb +24 -0
- data/spec/private/dispatch/session_mixin_spec.rb +47 -0
- data/spec/private/dispatch/spec_helper.rb +1 -0
- data/spec/private/plugins/plugin_spec.rb +166 -0
- data/spec/private/rack/application_spec.rb +49 -0
- data/spec/private/router/behavior_spec.rb +60 -0
- data/spec/private/router/fixture/log/merb_test.log +139 -0
- data/spec/private/router/route_spec.rb +414 -0
- data/spec/private/router/router_spec.rb +175 -0
- data/spec/private/vendor/facets/plural_spec.rb +564 -0
- data/spec/private/vendor/facets/singular_spec.rb +489 -0
- data/spec/public/DEFINITIONS +11 -0
- data/spec/public/abstract_controller/controllers/alt_views/layout/application.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_string_controller_layout.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_template_controller_layout.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/show.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/partial/basic_partial_with_multiple_roots/_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_and_custom_location/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_inherited/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/cousins.rb +41 -0
- data/spec/public/abstract_controller/controllers/display.rb +54 -0
- data/spec/public/abstract_controller/controllers/filters.rb +193 -0
- data/spec/public/abstract_controller/controllers/helpers.rb +41 -0
- data/spec/public/abstract_controller/controllers/partial.rb +121 -0
- data/spec/public/abstract_controller/controllers/render.rb +113 -0
- data/spec/public/abstract_controller/controllers/views/helpers/capture/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/helpers/capture_eq/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/helpers/capture_with_args/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/helpers/concat/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/layout/alt.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/layout/custom.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object_with_action/new.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_app_layout/index.erb +0 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_custom_layout/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/show.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_two_throw_contents/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/another_directory/_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/basic_partial/_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/basic_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/basic_partial_with_multiple_roots/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_first.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_second.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/nested_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_in_another_directory/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/_collection.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/_collection.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/_collection.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/_collection.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/_variables.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/_both.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/_with_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/_with_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_partial/_with_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_partial/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/test_display/foo.html.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/test_render/foo.html.erb +0 -0
- data/spec/public/abstract_controller/controllers/views/wonderful/index.erb +1 -0
- data/spec/public/abstract_controller/display_spec.rb +33 -0
- data/spec/public/abstract_controller/filter_spec.rb +106 -0
- data/spec/public/abstract_controller/helper_spec.rb +21 -0
- data/spec/public/abstract_controller/partial_spec.rb +61 -0
- data/spec/public/abstract_controller/render_spec.rb +90 -0
- data/spec/public/abstract_controller/spec_helper.rb +31 -0
- data/spec/public/boot_loader/boot_loader_spec.rb +33 -0
- data/spec/public/boot_loader/spec_helper.rb +1 -0
- data/spec/public/controller/authentication_spec.rb +103 -0
- data/spec/public/controller/base_spec.rb +36 -0
- data/spec/public/controller/controllers/authentication.rb +45 -0
- data/spec/public/controller/controllers/base.rb +36 -0
- data/spec/public/controller/controllers/display.rb +118 -0
- data/spec/public/controller/controllers/redirect.rb +30 -0
- data/spec/public/controller/controllers/responder.rb +93 -0
- data/spec/public/controller/controllers/url.rb +7 -0
- data/spec/public/controller/controllers/views/layout/custom.html.erb +1 -0
- data/spec/public/controller/controllers/views/layout/custom_arg.html.erb +1 -0
- data/spec/public/controller/controllers/views/layout/custom_arg.json.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.xml.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.xml.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/no_layout.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template_argument/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/html_default/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/layout/custom.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.xml.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.js.erb +1 -0
- data/spec/public/controller/display_spec.rb +84 -0
- data/spec/public/controller/redirect_spec.rb +27 -0
- data/spec/public/controller/responder_spec.rb +163 -0
- data/spec/public/controller/spec_helper.rb +11 -0
- data/spec/public/controller/url_spec.rb +180 -0
- data/spec/public/core/merb_core_spec.rb +45 -0
- data/spec/public/core_ext/class_spec.rb +91 -0
- data/spec/public/core_ext/fixtures/core_ext_dependency.rb +2 -0
- data/spec/public/core_ext/kernel_spec.rb +9 -0
- data/spec/public/core_ext/spec_helper.rb +1 -0
- data/spec/public/directory_structure/directory/app/controllers/application.rb +3 -0
- data/spec/public/directory_structure/directory/app/controllers/base.rb +13 -0
- data/spec/public/directory_structure/directory/app/controllers/custom.rb +19 -0
- data/spec/public/directory_structure/directory/app/views/base/template.html.erb +1 -0
- data/spec/public/directory_structure/directory/app/views/wonderful/template.erb +1 -0
- data/spec/public/directory_structure/directory/config/router.rb +3 -0
- data/spec/public/directory_structure/directory/log/merb_test.log +562 -0
- data/spec/public/directory_structure/directory_spec.rb +44 -0
- data/spec/public/logger/logger_spec.rb +181 -0
- data/spec/public/logger/spec_helper.rb +1 -0
- data/spec/public/reloading/directory/app/controllers/application.rb +3 -0
- data/spec/public/reloading/directory/app/controllers/reload.rb +6 -0
- data/spec/public/reloading/directory/config/init.rb +2 -0
- data/spec/public/reloading/directory/log/merb_test.log +138 -0
- data/spec/public/reloading/reload_spec.rb +103 -0
- data/spec/public/request/multipart_spec.rb +41 -0
- data/spec/public/request/request_spec.rb +228 -0
- data/spec/public/router/default_spec.rb +21 -0
- data/spec/public/router/deferred_spec.rb +22 -0
- data/spec/public/router/fixation_spec.rb +27 -0
- data/spec/public/router/fixture/log/merb_test.log +1556 -0
- data/spec/public/router/namespace_spec.rb +113 -0
- data/spec/public/router/nested_matches_spec.rb +97 -0
- data/spec/public/router/nested_resources_spec.rb +41 -0
- data/spec/public/router/resource_spec.rb +37 -0
- data/spec/public/router/resources_spec.rb +82 -0
- data/spec/public/router/spec_helper.rb +90 -0
- data/spec/public/router/special_spec.rb +61 -0
- data/spec/public/router/string_spec.rb +61 -0
- data/spec/public/template/template_spec.rb +104 -0
- data/spec/public/template/templates/error.html.erb +2 -0
- data/spec/public/template/templates/template.html.erb +1 -0
- data/spec/public/template/templates/template.html.myt +1 -0
- data/spec/public/test/controller_matchers_spec.rb +402 -0
- data/spec/public/test/controllers/controller_assertion_mock.rb +7 -0
- data/spec/public/test/controllers/dispatch_controller.rb +11 -0
- data/spec/public/test/controllers/spec_helper_controller.rb +38 -0
- data/spec/public/test/multipart_request_helper_spec.rb +159 -0
- data/spec/public/test/multipart_upload_text_file.txt +1 -0
- data/spec/public/test/request_helper_spec.rb +221 -0
- data/spec/public/test/route_helper_spec.rb +71 -0
- data/spec/public/test/route_matchers_spec.rb +162 -0
- data/spec/public/test/view_helper_spec.rb +96 -0
- data/spec/public/test/view_matchers_spec.rb +183 -0
- data/spec/spec_helper.rb +68 -0
- metadata +493 -41
- data/README.txt +0 -3
- data/lib/extlib.rb +0 -32
- data/lib/extlib/assertions.rb +0 -8
- data/lib/extlib/blank.rb +0 -42
- data/lib/extlib/class.rb +0 -175
- data/lib/extlib/hash.rb +0 -410
- data/lib/extlib/hook.rb +0 -366
- data/lib/extlib/inflection.rb +0 -141
- data/lib/extlib/lazy_array.rb +0 -106
- data/lib/extlib/mash.rb +0 -143
- data/lib/extlib/module.rb +0 -37
- data/lib/extlib/object.rb +0 -165
- data/lib/extlib/object_space.rb +0 -13
- data/lib/extlib/pathname.rb +0 -5
- data/lib/extlib/pooling.rb +0 -233
- data/lib/extlib/rubygems.rb +0 -38
- data/lib/extlib/simple_set.rb +0 -39
- data/lib/extlib/string.rb +0 -132
- data/lib/extlib/struct.rb +0 -8
- data/lib/extlib/tasks/release.rb +0 -9
- data/lib/extlib/time.rb +0 -12
- data/lib/extlib/version.rb +0 -3
- data/lib/extlib/virtual_file.rb +0 -10
@@ -0,0 +1,603 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
|
5
|
+
class Request
|
6
|
+
# def env def session def route_params
|
7
|
+
attr_accessor :env, :session, :route_params
|
8
|
+
|
9
|
+
# by setting these to false, auto-parsing is disabled; this way you can
|
10
|
+
# do your own parsing instead
|
11
|
+
cattr_accessor :parse_multipart_params, :parse_json_params,
|
12
|
+
:parse_xml_params
|
13
|
+
self.parse_multipart_params = true
|
14
|
+
self.parse_json_params = true
|
15
|
+
self.parse_xml_params = true
|
16
|
+
|
17
|
+
# Flash, and some older browsers can't use arbitrary
|
18
|
+
# request methods -- i.e., are limited to GET/POST.
|
19
|
+
# These user-agents can make POST requests in combination
|
20
|
+
# with these overrides to participate fully in REST
|
21
|
+
# Common examples are _method or fb_sig_request_method
|
22
|
+
# in the params, or an X-HTTP-Method-Override header
|
23
|
+
cattr_accessor :http_method_overrides
|
24
|
+
self.http_method_overrides = []
|
25
|
+
|
26
|
+
# Initial the request object.
|
27
|
+
#
|
28
|
+
# ==== Parameters
|
29
|
+
# http_request<~params:~[], ~body:IO>::
|
30
|
+
# An object like an HTTP Request.
|
31
|
+
def initialize(rack_env)
|
32
|
+
@env = rack_env
|
33
|
+
@body = rack_env['rack.input']
|
34
|
+
@route_params = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
METHODS = %w{get post put delete head options}
|
38
|
+
|
39
|
+
# ==== Returns
|
40
|
+
# Symbol:: The name of the request method, e.g. :get.
|
41
|
+
#
|
42
|
+
# ==== Notes
|
43
|
+
# If the method is post, then the blocks specified in
|
44
|
+
# http_method_overrides will be checked for the masquerading method.
|
45
|
+
# The block will get the controller yielded to it. The first matching workaround wins.
|
46
|
+
# To disable this behavior, set http_method_overrides = []
|
47
|
+
def method
|
48
|
+
@method ||= begin
|
49
|
+
request_method = @env['REQUEST_METHOD'].downcase.to_sym
|
50
|
+
case request_method
|
51
|
+
when :get, :head, :put, :delete, :options
|
52
|
+
request_method
|
53
|
+
when :post
|
54
|
+
m = nil
|
55
|
+
self.class.http_method_overrides.each do |o|
|
56
|
+
m ||= o.call(self); break if m
|
57
|
+
end
|
58
|
+
m.downcase! if m
|
59
|
+
METHODS.include?(m) ? m.to_sym : :post
|
60
|
+
else
|
61
|
+
raise "Unknown REQUEST_METHOD: #{@env['REQUEST_METHOD']}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# create predicate methods for querying the REQUEST_METHOD
|
67
|
+
# get? post? head? put? etc
|
68
|
+
METHODS.each do |m|
|
69
|
+
class_eval "def #{m}?() method == :#{m} end"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# ==== Returns
|
75
|
+
# Hash:: Parameters passed from the URL like ?blah=hello.
|
76
|
+
def query_params
|
77
|
+
@query_params ||= self.class.query_parse(query_string || '')
|
78
|
+
end
|
79
|
+
|
80
|
+
# Parameters passed in the body of the request. Ajax calls from
|
81
|
+
# prototype.js and other libraries pass content this way.
|
82
|
+
#
|
83
|
+
# ==== Returns
|
84
|
+
# Hash:: The parameters passed in the body.
|
85
|
+
def body_params
|
86
|
+
@body_params ||= begin
|
87
|
+
if content_type && content_type.match(Merb::Const::FORM_URL_ENCODED_REGEXP) # or content_type.nil?
|
88
|
+
self.class.query_parse(raw_post)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# ==== Returns
|
94
|
+
# Hash::
|
95
|
+
# The parameters gathered from the query string and the request body,
|
96
|
+
# with parameters in the body taking precedence.
|
97
|
+
def body_and_query_params
|
98
|
+
# ^-- FIXME a better name for this method
|
99
|
+
@body_and_query_params ||= begin
|
100
|
+
h = query_params
|
101
|
+
h.merge!(body_params) if body_params
|
102
|
+
h.to_mash
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# ==== Raises
|
107
|
+
# ControllerExceptions::MultiPartParseError::
|
108
|
+
# Unable to parse the multipart form data.
|
109
|
+
#
|
110
|
+
# ==== Returns
|
111
|
+
# Hash:: The parsed multipart parameters.
|
112
|
+
def multipart_params
|
113
|
+
@multipart_params ||=
|
114
|
+
begin
|
115
|
+
# if the content-type is multipart
|
116
|
+
# parse the multipart. Otherwise return {}
|
117
|
+
if (Merb::Const::MULTIPART_REGEXP =~ content_type)
|
118
|
+
self.class.parse_multipart(@body, $1, content_length)
|
119
|
+
else
|
120
|
+
{}
|
121
|
+
end
|
122
|
+
rescue ControllerExceptions::MultiPartParseError => e
|
123
|
+
@multipart_params = {}
|
124
|
+
raise e
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# ==== Returns
|
129
|
+
# Hash:: Parameters from body if this is a JSON request.
|
130
|
+
#
|
131
|
+
# ==== Notes
|
132
|
+
# If the JSON object parses as a Hash, it will be merged with the
|
133
|
+
# parameters hash. If it parses to anything else (such as an Array, or
|
134
|
+
# if it inflates to an Object) it will be accessible via the inflated_object
|
135
|
+
# parameter.
|
136
|
+
def json_params
|
137
|
+
@json_params ||= begin
|
138
|
+
if Merb::Const::JSON_MIME_TYPE_REGEXP.match(content_type)
|
139
|
+
jobj = JSON.parse(raw_post) rescue Mash.new
|
140
|
+
jobj.kind_of?(Hash) ? jobj : { :inflated_object => jobj }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# ==== Returns
|
146
|
+
# Hash:: Parameters from body if this is an XML request.
|
147
|
+
def xml_params
|
148
|
+
@xml_params ||= begin
|
149
|
+
if Merb::Const::XML_MIME_TYPE_REGEXP.match(content_type)
|
150
|
+
Hash.from_xml(raw_post) rescue Mash.new
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
public
|
156
|
+
# ==== Returns
|
157
|
+
# Hash:: All request parameters.
|
158
|
+
#
|
159
|
+
# ==== Notes
|
160
|
+
# The order of precedence for the params is XML, JSON, multipart, body and
|
161
|
+
# request string.
|
162
|
+
def params
|
163
|
+
@params ||= begin
|
164
|
+
h = body_and_query_params.merge(route_params)
|
165
|
+
h.merge!(multipart_params) if self.class.parse_multipart_params && multipart_params
|
166
|
+
h.merge!(json_params) if self.class.parse_json_params && json_params
|
167
|
+
h.merge!(xml_params) if self.class.parse_xml_params && xml_params
|
168
|
+
h
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def message
|
173
|
+
return {} unless params[:_message]
|
174
|
+
begin
|
175
|
+
Marshal.load(Merb::Request.unescape(params[:_message]).unpack("m").first)
|
176
|
+
rescue ArgumentError
|
177
|
+
{}
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Resets the params to a nil value.
|
182
|
+
def reset_params!
|
183
|
+
@params = nil
|
184
|
+
end
|
185
|
+
|
186
|
+
# ==== Returns
|
187
|
+
# Hash:: The cookies for this request.
|
188
|
+
def cookies
|
189
|
+
@cookies ||= self.class.query_parse(@env[Merb::Const::HTTP_COOKIE], ';,')
|
190
|
+
end
|
191
|
+
|
192
|
+
# ==== Returns
|
193
|
+
# String:: The raw post.
|
194
|
+
def raw_post
|
195
|
+
@body.rewind if @body.respond_to?(:rewind)
|
196
|
+
@raw_post ||= @body.read
|
197
|
+
end
|
198
|
+
|
199
|
+
# ==== Returns
|
200
|
+
# Boolean:: If the request is an XML HTTP request.
|
201
|
+
def xml_http_request?
|
202
|
+
not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
|
203
|
+
end
|
204
|
+
alias xhr? :xml_http_request?
|
205
|
+
alias ajax? :xml_http_request?
|
206
|
+
|
207
|
+
# ==== Returns
|
208
|
+
# String:: The remote IP address.
|
209
|
+
def remote_ip
|
210
|
+
return @env['HTTP_CLIENT_IP'] if @env.include?('HTTP_CLIENT_IP')
|
211
|
+
|
212
|
+
if @env.include?(Merb::Const::HTTP_X_FORWARDED_FOR) then
|
213
|
+
remote_ips = @env[Merb::Const::HTTP_X_FORWARDED_FOR].split(',').reject do |ip|
|
214
|
+
ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
|
215
|
+
end
|
216
|
+
|
217
|
+
return remote_ips.first.strip unless remote_ips.empty?
|
218
|
+
end
|
219
|
+
|
220
|
+
return @env[Merb::Const::REMOTE_ADDR]
|
221
|
+
end
|
222
|
+
|
223
|
+
# ==== Returns
|
224
|
+
# String::
|
225
|
+
# The protocol, i.e. either "https://" or "http://" depending on the
|
226
|
+
# HTTPS header.
|
227
|
+
def protocol
|
228
|
+
ssl? ? 'https://' : 'http://'
|
229
|
+
end
|
230
|
+
|
231
|
+
# ==== Returns
|
232
|
+
# Boolean::: True if the request is an SSL request.
|
233
|
+
def ssl?
|
234
|
+
@env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
|
235
|
+
end
|
236
|
+
|
237
|
+
# ==== Returns
|
238
|
+
# String:: The HTTP referer.
|
239
|
+
def referer
|
240
|
+
@env['HTTP_REFERER']
|
241
|
+
end
|
242
|
+
|
243
|
+
# ==== Returns
|
244
|
+
# String:: The full URI, including protocol and host
|
245
|
+
def full_uri
|
246
|
+
protocol + host + uri
|
247
|
+
end
|
248
|
+
|
249
|
+
# ==== Returns
|
250
|
+
# String:: The request URI.
|
251
|
+
def uri
|
252
|
+
@env['REQUEST_PATH'] || @env['REQUEST_URI']
|
253
|
+
end
|
254
|
+
|
255
|
+
# ==== Returns
|
256
|
+
# String:: The HTTP user agent.
|
257
|
+
def user_agent
|
258
|
+
@env['HTTP_USER_AGENT']
|
259
|
+
end
|
260
|
+
|
261
|
+
# ==== Returns
|
262
|
+
# String:: The server name.
|
263
|
+
def server_name
|
264
|
+
@env['SERVER_NAME']
|
265
|
+
end
|
266
|
+
|
267
|
+
# ==== Returns
|
268
|
+
# String:: The accepted encodings.
|
269
|
+
def accept_encoding
|
270
|
+
@env['HTTP_ACCEPT_ENCODING']
|
271
|
+
end
|
272
|
+
|
273
|
+
# ==== Returns
|
274
|
+
# String:: The script name.
|
275
|
+
def script_name
|
276
|
+
@env['SCRIPT_NAME']
|
277
|
+
end
|
278
|
+
|
279
|
+
# ==== Returns
|
280
|
+
# String:: HTTP cache control.
|
281
|
+
def cache_control
|
282
|
+
@env['HTTP_CACHE_CONTROL']
|
283
|
+
end
|
284
|
+
|
285
|
+
# ==== Returns
|
286
|
+
# String:: The accepted language.
|
287
|
+
def accept_language
|
288
|
+
@env['HTTP_ACCEPT_LANGUAGE']
|
289
|
+
end
|
290
|
+
|
291
|
+
# ==== Returns
|
292
|
+
# String:: The server software.
|
293
|
+
def server_software
|
294
|
+
@env['SERVER_SOFTWARE']
|
295
|
+
end
|
296
|
+
|
297
|
+
# ==== Returns
|
298
|
+
# String:: Value of HTTP_KEEP_ALIVE.
|
299
|
+
def keep_alive
|
300
|
+
@env['HTTP_KEEP_ALIVE']
|
301
|
+
end
|
302
|
+
|
303
|
+
# ==== Returns
|
304
|
+
# String:: The accepted character sets.
|
305
|
+
def accept_charset
|
306
|
+
@env['HTTP_ACCEPT_CHARSET']
|
307
|
+
end
|
308
|
+
|
309
|
+
# ==== Returns
|
310
|
+
# String:: The HTTP version
|
311
|
+
def version
|
312
|
+
@env['HTTP_VERSION']
|
313
|
+
end
|
314
|
+
|
315
|
+
# ==== Returns
|
316
|
+
# String:: The gateway.
|
317
|
+
def gateway
|
318
|
+
@env['GATEWAY_INTERFACE']
|
319
|
+
end
|
320
|
+
|
321
|
+
# ==== Returns
|
322
|
+
# String:: The accepted response types. Defaults to "*/*".
|
323
|
+
def accept
|
324
|
+
@env['HTTP_ACCEPT'].blank? ? "*/*" : @env['HTTP_ACCEPT']
|
325
|
+
end
|
326
|
+
|
327
|
+
# ==== Returns
|
328
|
+
# String:: The HTTP connection.
|
329
|
+
def connection
|
330
|
+
@env['HTTP_CONNECTION']
|
331
|
+
end
|
332
|
+
|
333
|
+
# ==== Returns
|
334
|
+
# String:: The query string.
|
335
|
+
def query_string
|
336
|
+
@env['QUERY_STRING']
|
337
|
+
end
|
338
|
+
|
339
|
+
# ==== Returns
|
340
|
+
# String:: The request content type.
|
341
|
+
def content_type
|
342
|
+
@env['CONTENT_TYPE']
|
343
|
+
end
|
344
|
+
|
345
|
+
# ==== Returns
|
346
|
+
# Fixnum:: The request content length.
|
347
|
+
def content_length
|
348
|
+
@content_length ||= @env[Merb::Const::CONTENT_LENGTH].to_i
|
349
|
+
end
|
350
|
+
|
351
|
+
# ==== Returns
|
352
|
+
# String::
|
353
|
+
# The URI without the query string. Strips trailing "/" and reduces
|
354
|
+
# duplicate "/" to a single "/".
|
355
|
+
def path
|
356
|
+
path = (uri.empty? ? '/' : uri.split('?').first).squeeze("/")
|
357
|
+
path = path[0..-2] if (path[-1] == ?/) && path.size > 1
|
358
|
+
path
|
359
|
+
end
|
360
|
+
|
361
|
+
# ==== Returns
|
362
|
+
# String:: The path info.
|
363
|
+
def path_info
|
364
|
+
@path_info ||= self.class.unescape(@env['PATH_INFO'])
|
365
|
+
end
|
366
|
+
|
367
|
+
# ==== Returns
|
368
|
+
# Fixnum:: The server port.
|
369
|
+
def port
|
370
|
+
@env['SERVER_PORT'].to_i
|
371
|
+
end
|
372
|
+
|
373
|
+
# ==== Returns
|
374
|
+
# String:: The full hostname including the port.
|
375
|
+
def host
|
376
|
+
@env['HTTP_X_FORWARDED_HOST'] || @env['HTTP_HOST']
|
377
|
+
end
|
378
|
+
|
379
|
+
# ==== Parameters
|
380
|
+
# tld_length<Fixnum>::
|
381
|
+
# Number of domains levels to inlclude in the top level domain. Defaults
|
382
|
+
# to 1.
|
383
|
+
#
|
384
|
+
# ==== Returns
|
385
|
+
# Array:: All the subdomain parts of the host.
|
386
|
+
def subdomains(tld_length = 1)
|
387
|
+
parts = host.split('.')
|
388
|
+
parts[0..-(tld_length+2)]
|
389
|
+
end
|
390
|
+
|
391
|
+
# ==== Parameters
|
392
|
+
# tld_length<Fixnum>::
|
393
|
+
# Number of domains levels to inlclude in the top level domain. Defaults
|
394
|
+
# to 1.
|
395
|
+
#
|
396
|
+
# ==== Returns
|
397
|
+
# String:: The full domain name without the port number.
|
398
|
+
def domain(tld_length = 1)
|
399
|
+
host.split('.').last(1 + tld_length).join('.').sub(/:\d+$/,'')
|
400
|
+
end
|
401
|
+
|
402
|
+
class << self
|
403
|
+
|
404
|
+
# ==== Parameters
|
405
|
+
# value<Array, Hash, Dictionary ~to_s>:: The value for the query string.
|
406
|
+
# prefix<~to_s>:: The prefix to add to the query string keys.
|
407
|
+
#
|
408
|
+
# ==== Returns
|
409
|
+
# String:: The query string.
|
410
|
+
#
|
411
|
+
# ==== Alternatives
|
412
|
+
# If the value is a string, the prefix will be used as the key.
|
413
|
+
#
|
414
|
+
# ==== Examples
|
415
|
+
# params_to_query_string(10, "page")
|
416
|
+
# # => "page=10"
|
417
|
+
# params_to_query_string({ :page => 10, :word => "ruby" })
|
418
|
+
# # => "page=10&word=ruby"
|
419
|
+
# params_to_query_string({ :page => 10, :word => "ruby" }, "search")
|
420
|
+
# # => "search[page]=10&search[word]=ruby"
|
421
|
+
# params_to_query_string([ "ice-cream", "cake" ], "shopping_list")
|
422
|
+
# # => "shopping_list[]=ice-cream&shopping_list[]=cake"
|
423
|
+
def params_to_query_string(value, prefix = nil)
|
424
|
+
case value
|
425
|
+
when Array
|
426
|
+
value.map { |v|
|
427
|
+
params_to_query_string(v, "#{prefix}[]")
|
428
|
+
} * "&"
|
429
|
+
when Hash, Dictionary
|
430
|
+
value.map { |k, v|
|
431
|
+
params_to_query_string(v, prefix ? "#{prefix}[#{Merb::Request.escape(k)}]" : Merb::Request.escape(k))
|
432
|
+
} * "&"
|
433
|
+
else
|
434
|
+
"#{prefix}=#{Merb::Request.escape(value)}"
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
# ==== Parameters
|
439
|
+
# s<String>:: String to URL escape.
|
440
|
+
#
|
441
|
+
# ==== returns
|
442
|
+
# String:: The escaped string.
|
443
|
+
def escape(s)
|
444
|
+
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
445
|
+
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
446
|
+
}.tr(' ', '+')
|
447
|
+
end
|
448
|
+
|
449
|
+
# ==== Parameter
|
450
|
+
# s<String>:: String to URL unescape.
|
451
|
+
#
|
452
|
+
# ==== returns
|
453
|
+
# String:: The unescaped string.
|
454
|
+
def unescape(s)
|
455
|
+
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
456
|
+
[$1.delete('%')].pack('H*')
|
457
|
+
}
|
458
|
+
end
|
459
|
+
|
460
|
+
# ==== Parameters
|
461
|
+
# qs<String>:: The query string.
|
462
|
+
# d<String>:: The query string divider. Defaults to "&".
|
463
|
+
# preserve_order<Boolean>:: Preserve order of args. Defaults to false.
|
464
|
+
#
|
465
|
+
# ==== Returns
|
466
|
+
# Mash:: The parsed query string (Dictionary if preserve_order is set).
|
467
|
+
#
|
468
|
+
# ==== Examples
|
469
|
+
# query_parse("bar=nik&post[body]=heya")
|
470
|
+
# # => { :bar => "nik", :post => { :body => "heya" } }
|
471
|
+
def query_parse(qs, d = '&;', preserve_order = false)
|
472
|
+
qh = preserve_order ? Dictionary.new : {}
|
473
|
+
(qs||'').split(/[#{d}] */n).inject(qh) { |h,p|
|
474
|
+
key, value = unescape(p).split('=',2)
|
475
|
+
normalize_params(h, key, value)
|
476
|
+
}
|
477
|
+
preserve_order ? qh : qh.to_mash
|
478
|
+
end
|
479
|
+
|
480
|
+
NAME_REGEX = /Content-Disposition:.* name="?([^\";]*)"?/ni.freeze
|
481
|
+
CONTENT_TYPE_REGEX = /Content-Type: (.*)\r\n/ni.freeze
|
482
|
+
FILENAME_REGEX = /Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze
|
483
|
+
CRLF = "\r\n".freeze
|
484
|
+
EOL = CRLF
|
485
|
+
|
486
|
+
# ==== Parameters
|
487
|
+
# request<IO>:: The raw request.
|
488
|
+
# boundary<String>:: The boundary string.
|
489
|
+
# content_length<Fixnum>:: The length of the content.
|
490
|
+
#
|
491
|
+
# ==== Raises
|
492
|
+
# ControllerExceptions::MultiPartParseError:: Failed to parse request.
|
493
|
+
#
|
494
|
+
# ==== Returns
|
495
|
+
# Hash:: The parsed request.
|
496
|
+
def parse_multipart(request, boundary, content_length)
|
497
|
+
boundary = "--#{boundary}"
|
498
|
+
paramhsh = {}
|
499
|
+
buf = ""
|
500
|
+
input = request
|
501
|
+
input.binmode if defined? input.binmode
|
502
|
+
boundary_size = boundary.size + EOL.size
|
503
|
+
bufsize = 16384
|
504
|
+
content_length -= boundary_size
|
505
|
+
status = input.read(boundary_size)
|
506
|
+
return {} if status == nil || status.empty?
|
507
|
+
raise ControllerExceptions::MultiPartParseError, "bad content body:\n'#{status}' should == '#{boundary + EOL}'" unless status == boundary + EOL
|
508
|
+
rx = /(?:#{EOL})?#{Regexp.quote(boundary,'n')}(#{EOL}|--)/
|
509
|
+
loop {
|
510
|
+
head = nil
|
511
|
+
body = ''
|
512
|
+
filename = content_type = name = nil
|
513
|
+
read_size = 0
|
514
|
+
until head && buf =~ rx
|
515
|
+
i = buf.index("\r\n\r\n")
|
516
|
+
if( i == nil && read_size == 0 && content_length == 0 )
|
517
|
+
content_length = -1
|
518
|
+
break
|
519
|
+
end
|
520
|
+
if !head && i
|
521
|
+
head = buf.slice!(0, i+2) # First \r\n
|
522
|
+
buf.slice!(0, 2) # Second \r\n
|
523
|
+
filename = head[FILENAME_REGEX, 1]
|
524
|
+
content_type = head[CONTENT_TYPE_REGEX, 1]
|
525
|
+
name = head[NAME_REGEX, 1]
|
526
|
+
|
527
|
+
if filename && !filename.empty?
|
528
|
+
body = Tempfile.new(:Merb)
|
529
|
+
body.binmode if defined? body.binmode
|
530
|
+
end
|
531
|
+
next
|
532
|
+
end
|
533
|
+
|
534
|
+
# Save the read body part.
|
535
|
+
if head && (boundary_size+4 < buf.size)
|
536
|
+
body << buf.slice!(0, buf.size - (boundary_size+4))
|
537
|
+
end
|
538
|
+
|
539
|
+
read_size = bufsize < content_length ? bufsize : content_length
|
540
|
+
if( read_size > 0 )
|
541
|
+
c = input.read(read_size)
|
542
|
+
raise ControllerExceptions::MultiPartParseError, "bad content body" if c.nil? || c.empty?
|
543
|
+
buf << c
|
544
|
+
content_length -= c.size
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
# Save the rest.
|
549
|
+
if i = buf.index(rx)
|
550
|
+
body << buf.slice!(0, i)
|
551
|
+
buf.slice!(0, boundary_size+2)
|
552
|
+
|
553
|
+
content_length = -1 if $1 == "--"
|
554
|
+
end
|
555
|
+
|
556
|
+
if filename && !filename.empty?
|
557
|
+
body.rewind
|
558
|
+
data = {
|
559
|
+
:filename => File.basename(filename),
|
560
|
+
:content_type => content_type,
|
561
|
+
:tempfile => body,
|
562
|
+
:size => File.size(body.path)
|
563
|
+
}
|
564
|
+
else
|
565
|
+
data = body
|
566
|
+
end
|
567
|
+
paramhsh = normalize_params(paramhsh,name,data)
|
568
|
+
break if buf.empty? || content_length == -1
|
569
|
+
}
|
570
|
+
paramhsh
|
571
|
+
end
|
572
|
+
|
573
|
+
# Converts a query string snippet to a hash and adds it to existing
|
574
|
+
# parameters.
|
575
|
+
#
|
576
|
+
# ==== Parameters
|
577
|
+
# parms<Hash>:: Parameters to add the normalized parameters to.
|
578
|
+
# name<String>:: The key of the parameter to normalize.
|
579
|
+
# val<String>:: The value of the parameter.
|
580
|
+
#
|
581
|
+
# ==== Returns
|
582
|
+
# Hash:: Normalized parameters
|
583
|
+
def normalize_params(parms, name, val=nil)
|
584
|
+
name =~ %r([\[\]]*([^\[\]]+)\]*)
|
585
|
+
key = $1 || ''
|
586
|
+
after = $' || ''
|
587
|
+
|
588
|
+
if after == ""
|
589
|
+
parms[key] = val
|
590
|
+
elsif after == "[]"
|
591
|
+
(parms[key] ||= []) << val
|
592
|
+
elsif after =~ %r(^\[\])
|
593
|
+
parms[key] ||= []
|
594
|
+
parms[key] << normalize_params({}, after, val)
|
595
|
+
else
|
596
|
+
parms[key] ||= {}
|
597
|
+
parms[key] = normalize_params(parms[key], after, val)
|
598
|
+
end
|
599
|
+
parms
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|