merb-core 0.9.2
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 +20 -0
- data/README +21 -0
- data/Rakefile +285 -0
- data/TODO +0 -0
- data/bin/merb +8 -0
- data/bin/merb-specs +5 -0
- data/docs/bootloading.dox +57 -0
- data/docs/documentation_standards +40 -0
- data/docs/new_render_api +51 -0
- data/lib/merb-core.rb +304 -0
- data/lib/merb-core/autoload.rb +29 -0
- data/lib/merb-core/bootloader.rb +601 -0
- data/lib/merb-core/config.rb +284 -0
- data/lib/merb-core/constants.rb +43 -0
- data/lib/merb-core/controller/abstract_controller.rb +531 -0
- data/lib/merb-core/controller/exceptions.rb +257 -0
- data/lib/merb-core/controller/merb_controller.rb +214 -0
- data/lib/merb-core/controller/mime.rb +88 -0
- data/lib/merb-core/controller/mixins/controller.rb +262 -0
- data/lib/merb-core/controller/mixins/render.rb +324 -0
- data/lib/merb-core/controller/mixins/responder.rb +464 -0
- data/lib/merb-core/controller/template.rb +205 -0
- data/lib/merb-core/core_ext.rb +12 -0
- data/lib/merb-core/core_ext/class.rb +192 -0
- data/lib/merb-core/core_ext/hash.rb +422 -0
- data/lib/merb-core/core_ext/kernel.rb +304 -0
- data/lib/merb-core/core_ext/mash.rb +154 -0
- data/lib/merb-core/core_ext/object.rb +136 -0
- data/lib/merb-core/core_ext/object_space.rb +14 -0
- data/lib/merb-core/core_ext/rubygems.rb +28 -0
- data/lib/merb-core/core_ext/set.rb +41 -0
- data/lib/merb-core/core_ext/string.rb +69 -0
- data/lib/merb-core/dispatch/cookies.rb +92 -0
- data/lib/merb-core/dispatch/dispatcher.rb +233 -0
- data/lib/merb-core/dispatch/exceptions.html.erb +297 -0
- data/lib/merb-core/dispatch/request.rb +560 -0
- data/lib/merb-core/dispatch/router.rb +141 -0
- data/lib/merb-core/dispatch/router/behavior.rb +777 -0
- data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
- data/lib/merb-core/dispatch/router/route.rb +212 -0
- data/lib/merb-core/dispatch/session.rb +28 -0
- data/lib/merb-core/dispatch/session/cookie.rb +166 -0
- data/lib/merb-core/dispatch/session/memcached.rb +161 -0
- data/lib/merb-core/dispatch/session/memory.rb +234 -0
- data/lib/merb-core/gem_ext/erubis.rb +19 -0
- data/lib/merb-core/logger.rb +230 -0
- data/lib/merb-core/plugins.rb +25 -0
- data/lib/merb-core/rack.rb +15 -0
- data/lib/merb-core/rack/adapter.rb +42 -0
- data/lib/merb-core/rack/adapter/ebb.rb +22 -0
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +24 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +16 -0
- data/lib/merb-core/rack/adapter/irb.rb +108 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +25 -0
- data/lib/merb-core/rack/adapter/runner.rb +27 -0
- data/lib/merb-core/rack/adapter/thin.rb +27 -0
- data/lib/merb-core/rack/adapter/webrick.rb +35 -0
- data/lib/merb-core/rack/application.rb +77 -0
- data/lib/merb-core/rack/handler/mongrel.rb +97 -0
- data/lib/merb-core/server.rb +184 -0
- data/lib/merb-core/test.rb +10 -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 +257 -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 +269 -0
- data/lib/merb-core/test/matchers/route_matchers.rb +136 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +293 -0
- data/lib/merb-core/test/run_specs.rb +38 -0
- data/lib/merb-core/test/tasks/spectasks.rb +39 -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/vendor/facets.rb +2 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
- data/lib/merb-core/vendor/facets/inflect.rb +211 -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 +139 -0
- data/spec/private/config/environment_spec.rb +13 -0
- data/spec/private/config/spec_helper.rb +1 -0
- data/spec/private/core_ext/hash_spec.rb +506 -0
- data/spec/private/core_ext/kernel_spec.rb +46 -0
- data/spec/private/core_ext/object_spec.rb +39 -0
- data/spec/private/core_ext/set_spec.rb +26 -0
- data/spec/private/core_ext/string_spec.rb +9 -0
- data/spec/private/dispatch/cookies_spec.rb +107 -0
- data/spec/private/dispatch/dispatch_spec.rb +26 -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/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 +1 -0
- data/spec/private/dispatch/fixture/config/router.rb +35 -0
- data/spec/private/dispatch/fixture/log/development.log +1 -0
- data/spec/private/dispatch/fixture/log/merb.4000.pid +1 -0
- data/spec/private/dispatch/fixture/log/merb_test.log +2040 -0
- data/spec/private/dispatch/fixture/log/production.log +1 -0
- data/spec/private/dispatch/fixture/merb.4000.pid +1 -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/spec_helper.rb +1 -0
- data/spec/private/plugins/plugin_spec.rb +81 -0
- data/spec/private/rack/application_spec.rb +43 -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/display.rb +54 -0
- data/spec/public/abstract_controller/controllers/filters.rb +167 -0
- data/spec/public/abstract_controller/controllers/helpers.rb +31 -0
- data/spec/public/abstract_controller/controllers/partial.rb +106 -0
- data/spec/public/abstract_controller/controllers/render.rb +86 -0
- data/spec/public/abstract_controller/controllers/views/helpers/capture/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/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_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_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 +80 -0
- data/spec/public/abstract_controller/helper_spec.rb +13 -0
- data/spec/public/abstract_controller/partial_spec.rb +53 -0
- data/spec/public/abstract_controller/render_spec.rb +70 -0
- data/spec/public/abstract_controller/spec_helper.rb +27 -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/base_spec.rb +31 -0
- data/spec/public/controller/controllers/base.rb +41 -0
- data/spec/public/controller/controllers/display.rb +40 -0
- data/spec/public/controller/controllers/responder.rb +67 -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/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/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 +34 -0
- data/spec/public/controller/log/merb.4000.pid +1 -0
- data/spec/public/controller/responder_spec.rb +95 -0
- data/spec/public/controller/spec_helper.rb +9 -0
- data/spec/public/controller/url_spec.rb +152 -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.4000.pid +1 -0
- data/spec/public/directory_structure/directory/log/merb_test.log +265 -0
- data/spec/public/directory_structure/directory/merb.4000.pid +1 -0
- data/spec/public/directory_structure/directory_spec.rb +44 -0
- data/spec/public/logger/logger_spec.rb +175 -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.4000.pid +1 -0
- data/spec/public/reloading/directory/log/merb_test.log +59 -0
- data/spec/public/reloading/directory/merb.4000.pid +1 -0
- data/spec/public/reloading/reload_spec.rb +80 -0
- data/spec/public/request/multipart_spec.rb +15 -0
- data/spec/public/request/request_spec.rb +207 -0
- data/spec/public/router/default_spec.rb +21 -0
- data/spec/public/router/deferred_spec.rb +22 -0
- data/spec/public/router/namespace_spec.rb +113 -0
- data/spec/public/router/nested_resources_spec.rb +34 -0
- data/spec/public/router/resource_spec.rb +45 -0
- data/spec/public/router/resources_spec.rb +57 -0
- data/spec/public/router/spec_helper.rb +72 -0
- data/spec/public/router/special_spec.rb +44 -0
- data/spec/public/router/string_spec.rb +61 -0
- data/spec/public/template/template_spec.rb +92 -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 +378 -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 +30 -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 +153 -0
- data/spec/public/test/route_helper_spec.rb +54 -0
- data/spec/public/test/route_matchers_spec.rb +133 -0
- data/spec/public/test/view_helper_spec.rb +96 -0
- data/spec/public/test/view_matchers_spec.rb +107 -0
- data/spec/spec_helper.rb +71 -0
- metadata +488 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Merb
|
|
2
|
+
class << self
|
|
3
|
+
|
|
4
|
+
# ==== Returns
|
|
5
|
+
# Hash:: The available mime types.
|
|
6
|
+
def available_mime_types
|
|
7
|
+
ResponderMixin::TYPES
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Any specific outgoing headers should be included here. These are not
|
|
11
|
+
# the content-type header but anything in addition to it.
|
|
12
|
+
# +transform_method+ should be set to a symbol of the method used to
|
|
13
|
+
# transform a resource into this mime type.
|
|
14
|
+
# For example for the :xml mime type an object might be transformed by
|
|
15
|
+
# calling :to_xml, or for the :js mime type, :to_json.
|
|
16
|
+
# If there is no transform method, use nil.
|
|
17
|
+
#
|
|
18
|
+
# ==== Autogenerated Methods
|
|
19
|
+
# Adding a mime-type adds a render_type method that sets the content
|
|
20
|
+
# type and calls render.
|
|
21
|
+
#
|
|
22
|
+
# By default this does: def render_all, def render_yaml, def render_text,
|
|
23
|
+
# def render_html, def render_xml, def render_js, and def render_yaml
|
|
24
|
+
#
|
|
25
|
+
# ==== Parameters
|
|
26
|
+
# key<Symbol>:: The name of the mime-type. This is used by the provides API
|
|
27
|
+
# transform_method<~to_s>::
|
|
28
|
+
# The associated method to call on objects to convert them to the
|
|
29
|
+
# appropriate mime-type. For instance, :json would use :to_json as its
|
|
30
|
+
# transform_method.
|
|
31
|
+
# values<Array[String]>::
|
|
32
|
+
# A list of possible values sent in the Accept header, such as text/html,
|
|
33
|
+
# that should be associated with this content-type.
|
|
34
|
+
# new_response_headers<Hash>::
|
|
35
|
+
# The response headers to set for the the mime type.
|
|
36
|
+
def add_mime_type(key, transform_method, values, new_response_headers = {})
|
|
37
|
+
enforce!(key => Symbol, values => Array)
|
|
38
|
+
ResponderMixin::TYPES.update(key =>
|
|
39
|
+
{:request_headers => values,
|
|
40
|
+
:transform_method => transform_method,
|
|
41
|
+
:response_headers => new_response_headers })
|
|
42
|
+
|
|
43
|
+
Merb::RenderMixin.class_eval <<-EOS, __FILE__, __LINE__
|
|
44
|
+
def render_#{key}(thing = nil, opts = {})
|
|
45
|
+
self.content_type = :#{key}
|
|
46
|
+
render thing, opts
|
|
47
|
+
end
|
|
48
|
+
EOS
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Removes a MIME-type from the mime-type list.
|
|
52
|
+
#
|
|
53
|
+
# ==== Parameters
|
|
54
|
+
# key<Symbol>:: The key that represents the mime-type to remove.
|
|
55
|
+
#
|
|
56
|
+
# ==== Note
|
|
57
|
+
# :all is the key for */*; It can't be removed.
|
|
58
|
+
def remove_mime_type(key)
|
|
59
|
+
return false if key == :all
|
|
60
|
+
ResponderMixin::TYPES.delete(key)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# ==== Parameters
|
|
64
|
+
# key<Symbol>:: The key that represents the mime-type.
|
|
65
|
+
#
|
|
66
|
+
# ==== Returns
|
|
67
|
+
# Symbol:: The transform method for the mime type, e.g. :to_json.
|
|
68
|
+
#
|
|
69
|
+
# ==== Raises
|
|
70
|
+
# ArgumentError:: The requested mime type is not valid.
|
|
71
|
+
def mime_transform_method(key)
|
|
72
|
+
raise ArgumentError, ":#{key} is not a valid MIME-type" unless ResponderMixin::TYPES.key?(key)
|
|
73
|
+
ResponderMixin::TYPES[key][:transform_method]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The mime-type for a particular inbound Accepts header.
|
|
77
|
+
#
|
|
78
|
+
# ==== Parameters
|
|
79
|
+
# header<String>:: The name of the header to find the mime-type for.
|
|
80
|
+
#
|
|
81
|
+
# ==== Returns
|
|
82
|
+
# Hash:: The mime type information.
|
|
83
|
+
def mime_by_request_header(header)
|
|
84
|
+
available_mime_types.find {|key,info| info[request_headers].include?(header)}.first
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
module Merb
|
|
2
|
+
# Module that is mixed in to all implemented controllers.
|
|
3
|
+
module ControllerMixin
|
|
4
|
+
# Renders the block given as a parameter using chunked encoding.
|
|
5
|
+
#
|
|
6
|
+
# ==== Parameters
|
|
7
|
+
# &blk::
|
|
8
|
+
# A block that, when called, will use send_chunks to send chunks of data
|
|
9
|
+
# down to the server. The chunking will terminate once the block returns.
|
|
10
|
+
#
|
|
11
|
+
# ==== Examples
|
|
12
|
+
# def stream
|
|
13
|
+
# prefix = '<p>'
|
|
14
|
+
# suffix = "</p>\r\n"
|
|
15
|
+
# render_chunked do
|
|
16
|
+
# IO.popen("cat /tmp/test.log") do |io|
|
|
17
|
+
# done = false
|
|
18
|
+
# until done
|
|
19
|
+
# sleep 0.3
|
|
20
|
+
# line = io.gets.chomp
|
|
21
|
+
#
|
|
22
|
+
# if line == 'EOF'
|
|
23
|
+
# done = true
|
|
24
|
+
# else
|
|
25
|
+
# send_chunk(prefix + line + suffix)
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
def render_chunked(&blk)
|
|
32
|
+
must_support_streaming!
|
|
33
|
+
headers['Transfer-Encoding'] = 'chunked'
|
|
34
|
+
Proc.new { |response|
|
|
35
|
+
@response = response
|
|
36
|
+
response.send_status_no_connection_close('')
|
|
37
|
+
response.send_header
|
|
38
|
+
blk.call
|
|
39
|
+
response.write("0\r\n\r\n")
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Writes a chunk from +render_chunked+ to the response that is sent back to
|
|
44
|
+
# the client. This should only be called within a +render_chunked+ block.
|
|
45
|
+
#
|
|
46
|
+
# ==== Parameters
|
|
47
|
+
# data<String>:: a chunk of data to return.
|
|
48
|
+
def send_chunk(data)
|
|
49
|
+
@response.write('%x' % data.size + "\r\n")
|
|
50
|
+
@response.write(data + "\r\n")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ==== Parameters
|
|
54
|
+
# &blk::
|
|
55
|
+
# A proc that should get called outside the mutex, and which will return
|
|
56
|
+
# the value to render.
|
|
57
|
+
#
|
|
58
|
+
# ==== Returns
|
|
59
|
+
# Proc::
|
|
60
|
+
# A block that Mongrel can call later, allowing Merb to release the
|
|
61
|
+
# thread lock and render another request.
|
|
62
|
+
def render_deferred(&blk)
|
|
63
|
+
must_support_streaming!
|
|
64
|
+
Proc.new {|response|
|
|
65
|
+
result = blk.call
|
|
66
|
+
response.send_status(result.length)
|
|
67
|
+
response.send_header
|
|
68
|
+
response.write(result)
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Renders the passed in string, then calls the block outside the mutex and
|
|
73
|
+
# after the string has been returned to the client.
|
|
74
|
+
#
|
|
75
|
+
# ==== Parameters
|
|
76
|
+
# str<String>:: A +String+ to return to the client.
|
|
77
|
+
# &blk:: A block that should get called once the string has been returned.
|
|
78
|
+
#
|
|
79
|
+
# ==== Returns
|
|
80
|
+
# Proc::
|
|
81
|
+
# A block that Mongrel can call after returning the string to the user.
|
|
82
|
+
def render_then_call(str, &blk)
|
|
83
|
+
must_support_streaming!
|
|
84
|
+
Proc.new {|response|
|
|
85
|
+
response.send_status(str.length)
|
|
86
|
+
response.send_header
|
|
87
|
+
response.write(str)
|
|
88
|
+
blk.call
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# ==== Parameters
|
|
93
|
+
# url<String>::
|
|
94
|
+
# URL to redirect to. It can be either a relative or fully-qualified URL.
|
|
95
|
+
#
|
|
96
|
+
# ==== Returns
|
|
97
|
+
# String:: Explanation of redirect.
|
|
98
|
+
#
|
|
99
|
+
# ==== Examples
|
|
100
|
+
# redirect("/posts/34")
|
|
101
|
+
# redirect("http://www.merbivore.com/")
|
|
102
|
+
def redirect(url)
|
|
103
|
+
Merb.logger.info("Redirecting to: #{url}")
|
|
104
|
+
self.status = 302
|
|
105
|
+
headers['Location'] = url
|
|
106
|
+
"<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Sends a file over HTTP. When given a path to a file, it will set the
|
|
110
|
+
# right headers so that the static file is served directly.
|
|
111
|
+
#
|
|
112
|
+
# ==== Parameters
|
|
113
|
+
# file<String>:: Path to file to send to the client.
|
|
114
|
+
# opts<Hash>:: Options for sending the file (see below).
|
|
115
|
+
#
|
|
116
|
+
# ==== Options (opts)
|
|
117
|
+
# :disposition<String>::
|
|
118
|
+
# The disposition of the file send. Defaults to "attachment".
|
|
119
|
+
# :filename<String>::
|
|
120
|
+
# The name to use for the file. Defaults to the filename of file.
|
|
121
|
+
# :type<String>:: The content type.
|
|
122
|
+
#
|
|
123
|
+
# ==== Returns
|
|
124
|
+
# IO:: An I/O stream for the file.
|
|
125
|
+
def send_file(file, opts={})
|
|
126
|
+
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
|
127
|
+
disposition = opts[:disposition].dup || 'attachment'
|
|
128
|
+
disposition << %(; filename="#{opts[:filename] ? opts[:filename] : File.basename(file)}")
|
|
129
|
+
headers.update(
|
|
130
|
+
'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers
|
|
131
|
+
'Content-Disposition' => disposition,
|
|
132
|
+
'Content-Transfer-Encoding' => 'binary'
|
|
133
|
+
)
|
|
134
|
+
File.open(file)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Send binary data over HTTP to the user as a file download. May set content type,
|
|
138
|
+
# apparent file name, and specify whether to show data inline or download as an attachment.
|
|
139
|
+
#
|
|
140
|
+
# ==== Parameters
|
|
141
|
+
# data<String>:: Path to file to send to the client.
|
|
142
|
+
# opts<Hash>:: Options for sending the data (see below).
|
|
143
|
+
#
|
|
144
|
+
# ==== Options (opts)
|
|
145
|
+
# :disposition<String>::
|
|
146
|
+
# The disposition of the file send. Defaults to "attachment".
|
|
147
|
+
# :filename<String>::
|
|
148
|
+
# The name to use for the file. Defaults to the filename of file.
|
|
149
|
+
# :type<String>:: The content type.
|
|
150
|
+
def send_data(data, opts={})
|
|
151
|
+
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
|
152
|
+
disposition = opts[:disposition].dup || 'attachment'
|
|
153
|
+
disposition << %(; filename="#{opts[:filename]}") if opts[:filename]
|
|
154
|
+
headers.update(
|
|
155
|
+
'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers
|
|
156
|
+
'Content-Disposition' => disposition,
|
|
157
|
+
'Content-Transfer-Encoding' => 'binary'
|
|
158
|
+
)
|
|
159
|
+
data
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Streams a file over HTTP.
|
|
163
|
+
#
|
|
164
|
+
# ==== Parameters
|
|
165
|
+
# opts<Hash>:: Options for the file streaming (see below).
|
|
166
|
+
# &stream::
|
|
167
|
+
# A block that, when called, will return an object that responds to
|
|
168
|
+
# +get_lines+ for streaming.
|
|
169
|
+
#
|
|
170
|
+
# ==== Options
|
|
171
|
+
# :disposition<String>::
|
|
172
|
+
# The disposition of the file send. Defaults to "attachment".
|
|
173
|
+
# :type<String>:: The content type.
|
|
174
|
+
# :content_length<Numeric>:: The length of the content to send.
|
|
175
|
+
# :filename<String>:: The name to use for the streamed file.
|
|
176
|
+
#
|
|
177
|
+
# ==== Examples
|
|
178
|
+
# stream_file({ :filename => file_name, :type => content_type,
|
|
179
|
+
# :content_length => content_length }) do |response|
|
|
180
|
+
# AWS::S3::S3Object.stream(user.folder_name + "-" + user_file.unique_id, bucket_name) do |chunk|
|
|
181
|
+
# response.write chunk
|
|
182
|
+
# end
|
|
183
|
+
# end
|
|
184
|
+
def stream_file(opts={}, &stream)
|
|
185
|
+
must_support_streaming!
|
|
186
|
+
opts.update(Merb::Const::DEFAULT_SEND_FILE_OPTIONS.merge(opts))
|
|
187
|
+
disposition = opts[:disposition].dup || 'attachment'
|
|
188
|
+
disposition << %(; filename="#{opts[:filename]}")
|
|
189
|
+
response.headers.update(
|
|
190
|
+
'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers
|
|
191
|
+
'Content-Disposition' => disposition,
|
|
192
|
+
'Content-Transfer-Encoding' => 'binary',
|
|
193
|
+
'CONTENT-LENGTH' => opts[:content_length]
|
|
194
|
+
)
|
|
195
|
+
response.send_status(opts[:content_length])
|
|
196
|
+
response.send_header
|
|
197
|
+
stream
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Uses the nginx specific +X-Accel-Redirect+ header to send a file directly
|
|
201
|
+
# from nginx. For more information, see the nginx wiki:
|
|
202
|
+
# http://wiki.codemongers.com/NginxXSendfile
|
|
203
|
+
#
|
|
204
|
+
# ==== Parameters
|
|
205
|
+
# file<String>:: Path to file to send to the client.
|
|
206
|
+
def nginx_send_file(file)
|
|
207
|
+
headers['X-Accel-Redirect'] = File.expand_path(file)
|
|
208
|
+
return
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Sets a cookie to be included in the response. This method is used
|
|
212
|
+
# primarily internally in Merb.
|
|
213
|
+
#
|
|
214
|
+
# If you need to set a cookie, then use the +cookies+ hash.
|
|
215
|
+
#
|
|
216
|
+
# ==== Parameters
|
|
217
|
+
# name<~to_s>:: A name for the cookie.
|
|
218
|
+
# value<~to_s>:: A value for the cookie.
|
|
219
|
+
# expires<~gmtime:~strftime>:: An expiration time for the cookie.
|
|
220
|
+
def set_cookie(name, value, expires)
|
|
221
|
+
(headers['Set-Cookie'] ||=[]) << (Merb::Const::SET_COOKIE % [
|
|
222
|
+
name.to_s,
|
|
223
|
+
::Merb::Request.escape(value.to_s),
|
|
224
|
+
# Cookie expiration time must be GMT. See RFC 2109
|
|
225
|
+
expires.gmtime.strftime(Merb::Const::COOKIE_EXPIRATION_FORMAT)
|
|
226
|
+
])
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Marks a cookie as deleted and gives it an expires stamp in the past. This
|
|
230
|
+
# method is used primarily internally in Merb.
|
|
231
|
+
#
|
|
232
|
+
# Use the +cookies+ hash to manipulate cookies instead.
|
|
233
|
+
#
|
|
234
|
+
# ==== Parameters
|
|
235
|
+
# name<~to_s>:: A name for the cookie to delete.
|
|
236
|
+
def delete_cookie(name)
|
|
237
|
+
set_cookie(name, nil, Merb::Const::COOKIE_EXPIRED_TIME)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Escapes the string representation of +obj+ and escapes it for use in XML.
|
|
241
|
+
#
|
|
242
|
+
# ==== Parameter
|
|
243
|
+
# obj<~to_s>:: The object to escape for use in XML.
|
|
244
|
+
#
|
|
245
|
+
# ==== Returns
|
|
246
|
+
# String:: The escaped object.
|
|
247
|
+
def escape_xml(obj)
|
|
248
|
+
Erubis::XmlHelper.escape_xml(obj.to_s)
|
|
249
|
+
end
|
|
250
|
+
alias h escape_xml
|
|
251
|
+
alias html_escape escape_xml
|
|
252
|
+
|
|
253
|
+
private
|
|
254
|
+
# Checks whether streaming is supported by the current Rack adapter.
|
|
255
|
+
#
|
|
256
|
+
# ==== Raises
|
|
257
|
+
# NotImplemented:: The Rack adapter doens't support streaming.
|
|
258
|
+
def must_support_streaming!
|
|
259
|
+
raise(NotImplemented, "Current Rack adapter does not support streaming") unless request.env['rack.streaming']
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
module Merb::RenderMixin
|
|
2
|
+
# So we can do raise TemplateNotFound
|
|
3
|
+
include Merb::ControllerExceptions
|
|
4
|
+
|
|
5
|
+
# ==== Parameters
|
|
6
|
+
# base<Module>:: Module that is including RenderMixin (probably a controller)
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.class_eval do
|
|
9
|
+
class_inheritable_accessor :_layout, :_cached_templates
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Render the specified item, with the specified options.
|
|
14
|
+
#
|
|
15
|
+
# ==== Parameters
|
|
16
|
+
# thing<String, Symbol, nil>::
|
|
17
|
+
# The thing to render. This will default to the current action
|
|
18
|
+
# opts<Hash>:: An options hash (see below)
|
|
19
|
+
#
|
|
20
|
+
# ==== Options (opts)
|
|
21
|
+
# :format<Symbol>:: A registered mime-type format
|
|
22
|
+
# :template<String>::
|
|
23
|
+
# The path to the template relative to the template root
|
|
24
|
+
# :status<~to_i>::
|
|
25
|
+
# The status to send to the client. Typically, this would be an integer
|
|
26
|
+
# (200), or a Merb status code (Accepted)
|
|
27
|
+
# :layout<~to_s>::
|
|
28
|
+
# A layout to use instead of the default. This should be relative to the
|
|
29
|
+
# layout root. By default, the layout will be either the controller_name or
|
|
30
|
+
# application. If you want to use an alternative content-type than the one
|
|
31
|
+
# that the base template was rendered as, you will need to do :layout =>
|
|
32
|
+
# "foo.#{content_type}" (i.e. "foo.json")
|
|
33
|
+
#
|
|
34
|
+
# ==== Returns
|
|
35
|
+
# String:: The rendered template, including layout, if appropriate.
|
|
36
|
+
#
|
|
37
|
+
# ==== Raises
|
|
38
|
+
# TemplateNotFound:: There is no template for the specified location.
|
|
39
|
+
#
|
|
40
|
+
# ==== Alternatives
|
|
41
|
+
# If you pass a Hash as the first parameter, it will be moved to opts and
|
|
42
|
+
# "thing" will be the current action
|
|
43
|
+
#---
|
|
44
|
+
# @public
|
|
45
|
+
def render(thing = nil, opts = {})
|
|
46
|
+
# render :format => :xml means render nil, :format => :xml
|
|
47
|
+
opts, thing = thing, nil if thing.is_a?(Hash)
|
|
48
|
+
|
|
49
|
+
# If you don't specify a thing to render, assume they want to render the current action
|
|
50
|
+
thing ||= action_name.to_sym
|
|
51
|
+
|
|
52
|
+
# Content negotiation
|
|
53
|
+
opts[:format] ? (self.content_type = opts[:format]) : content_type
|
|
54
|
+
|
|
55
|
+
# Handle options (:status)
|
|
56
|
+
_handle_options!(opts)
|
|
57
|
+
|
|
58
|
+
# Do we have a template to try to render?
|
|
59
|
+
if thing.is_a?(Symbol) || opts[:template]
|
|
60
|
+
|
|
61
|
+
template_method, template_location = _template_for(thing, content_type, controller_name, opts)
|
|
62
|
+
|
|
63
|
+
# Raise an error if there's no template
|
|
64
|
+
raise TemplateNotFound, "No template found at #{template_location}.*" \
|
|
65
|
+
unless template_method && self.respond_to?(template_method)
|
|
66
|
+
|
|
67
|
+
# Call the method in question and throw the content for later consumption by the layout
|
|
68
|
+
throw_content(:for_layout, self.send(template_method))
|
|
69
|
+
|
|
70
|
+
# Do we have a string to render?
|
|
71
|
+
elsif thing.is_a?(String)
|
|
72
|
+
|
|
73
|
+
# Throw it for later consumption by the layout
|
|
74
|
+
throw_content(:for_layout, thing)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# If we find a layout, use it. Otherwise, just render the content thrown for layout.
|
|
78
|
+
layout = opts[:layout] != false && _get_layout(opts[:layout])
|
|
79
|
+
layout ? send(layout) : catch_content(:for_layout)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Renders an object using to registered transform method based on the
|
|
83
|
+
# negotiated content-type, if a template does not exist. For instance, if the
|
|
84
|
+
# content-type is :json, Merb will first look for current_action.json.*.
|
|
85
|
+
# Failing that, it will run object.to_json.
|
|
86
|
+
#
|
|
87
|
+
# ==== Parameter
|
|
88
|
+
# object<Object>::
|
|
89
|
+
# An object that responds_to? the transform method registered for the
|
|
90
|
+
# negotiated mime-type.
|
|
91
|
+
# thing<String, Symbol>::
|
|
92
|
+
# The thing to attempt to render via #render before calling the transform
|
|
93
|
+
# method on the object. Defaults to nil.
|
|
94
|
+
# opts<Hash>:: An options hash that will be passed on to #render
|
|
95
|
+
#
|
|
96
|
+
# ==== Returns
|
|
97
|
+
# String::
|
|
98
|
+
# The rendered template or if no template is found, the transformed object.
|
|
99
|
+
#
|
|
100
|
+
# ==== Raises
|
|
101
|
+
# NotAcceptable::
|
|
102
|
+
# If there is no transform method for the specified mime-type or the object
|
|
103
|
+
# does not respond to the transform method.
|
|
104
|
+
#
|
|
105
|
+
# ==== Alternatives
|
|
106
|
+
# A string in the second parameter will be interpreted as a template:
|
|
107
|
+
# display @object, "path/to/foo"
|
|
108
|
+
# #=> display @object, nil, :template => "path/to/foo"
|
|
109
|
+
#
|
|
110
|
+
# A hash in the second parameters will be interpreted as opts:
|
|
111
|
+
# display @object, :layout => "zoo"
|
|
112
|
+
# #=> display @object, nil, :layout => "zoo"
|
|
113
|
+
#
|
|
114
|
+
# ==== Note
|
|
115
|
+
# The transformed object will not be used in a layout unless a :layout is
|
|
116
|
+
# explicitly passed in the opts.
|
|
117
|
+
def display(object, thing = nil, opts = {})
|
|
118
|
+
# display @object, "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
|
119
|
+
# display @object, :template => "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
|
120
|
+
opts[:template], thing = thing, nil if thing.is_a?(String) || thing.is_a?(Hash)
|
|
121
|
+
|
|
122
|
+
# Try to render without the object
|
|
123
|
+
render(thing || action_name.to_sym, opts)
|
|
124
|
+
|
|
125
|
+
# If the render fails (i.e. a template was not found)
|
|
126
|
+
rescue TemplateNotFound
|
|
127
|
+
|
|
128
|
+
# Figure out what to transform and raise NotAcceptable unless there's a transform method assigned
|
|
129
|
+
transform = Merb.mime_transform_method(content_type)
|
|
130
|
+
raise NotAcceptable unless transform && object.respond_to?(transform)
|
|
131
|
+
|
|
132
|
+
# Throw the transformed object for later consumption by the layout
|
|
133
|
+
throw_content(:for_layout, object.send(transform))
|
|
134
|
+
|
|
135
|
+
# Only use a layout if one was specified
|
|
136
|
+
if opts[:layout]
|
|
137
|
+
# Look for the layout under the default layout directly. If it's not found, reraise
|
|
138
|
+
# the TemplateNotFound error
|
|
139
|
+
template = _template_location(opts[:layout], layout.index(".") ? content_type : nil, "layout")
|
|
140
|
+
layout = _template_for(_template_root / template) ||
|
|
141
|
+
(raise TemplateNotFound, "No layout found at #{_template_root / template}.*")
|
|
142
|
+
|
|
143
|
+
# If the layout was found, call it
|
|
144
|
+
send(layout)
|
|
145
|
+
|
|
146
|
+
# Otherwise, just render the transformed object
|
|
147
|
+
else
|
|
148
|
+
catch_content(:for_layout)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Render a partial template.
|
|
153
|
+
#
|
|
154
|
+
# ==== Parameters
|
|
155
|
+
# template<~to_s>::
|
|
156
|
+
# The path to the template, relative to the current controller or the
|
|
157
|
+
# template root. If the template contains a "/", Merb will search for it
|
|
158
|
+
# relative to the template root; otherwise, Merb will search for it
|
|
159
|
+
# relative to the current controller.
|
|
160
|
+
# opts<Hash>:: A hash of options (see below)
|
|
161
|
+
#
|
|
162
|
+
# ==== Options (opts)
|
|
163
|
+
# :with<Object, Array>::
|
|
164
|
+
# An object or an array of objects that will be passed into the partial.
|
|
165
|
+
# :as<~to_sym>:: The local name of the :with Object inside of the partial.
|
|
166
|
+
# :format<Symbol>:: The mime format that you want the partial to be in (:js, :html, etc.)
|
|
167
|
+
# others::
|
|
168
|
+
# A Hash object names and values that will be the local names and values
|
|
169
|
+
# inside the partial.
|
|
170
|
+
#
|
|
171
|
+
# ==== Example
|
|
172
|
+
# partial :foo, :hello => @object
|
|
173
|
+
#
|
|
174
|
+
# The "_foo" partial will be called, relative to the current controller,
|
|
175
|
+
# with a local variable of +hello+ inside of it, assigned to @object.
|
|
176
|
+
def partial(template, opts={})
|
|
177
|
+
|
|
178
|
+
# partial :foo becomes "#{controller_name}/_foo"
|
|
179
|
+
# partial "foo/bar" becomes "foo/_bar"
|
|
180
|
+
template = template.to_s
|
|
181
|
+
kontroller = (m = template.match(/.*(?=\/)/)) ? m[0] : controller_name
|
|
182
|
+
template = "_#{File.basename(template)}"
|
|
183
|
+
|
|
184
|
+
template_method, template_location = _template_for(template, opts.delete(:format) || content_type, kontroller)
|
|
185
|
+
|
|
186
|
+
(@_old_partial_locals ||= []).push @_merb_partial_locals
|
|
187
|
+
|
|
188
|
+
if opts.key?(:with)
|
|
189
|
+
with = opts.delete(:with)
|
|
190
|
+
as = opts.delete(:as) || template_location.match(%r[.*/_([^\.]*)])[1]
|
|
191
|
+
@_merb_partial_locals = opts
|
|
192
|
+
sent_template = [with].flatten.map do |temp|
|
|
193
|
+
@_merb_partial_locals[as.to_sym] = temp
|
|
194
|
+
send(template_method)
|
|
195
|
+
end.join
|
|
196
|
+
else
|
|
197
|
+
@_merb_partial_locals = opts
|
|
198
|
+
sent_template = send(template_method)
|
|
199
|
+
end
|
|
200
|
+
@_merb_partial_locals = @_old_partial_locals.pop
|
|
201
|
+
sent_template
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Take the options hash and handle it as appropriate.
|
|
205
|
+
#
|
|
206
|
+
# ==== Parameters
|
|
207
|
+
# opts<Hash>:: The options hash that was passed into render.
|
|
208
|
+
#
|
|
209
|
+
# ==== Options
|
|
210
|
+
# :status<~to_i>::
|
|
211
|
+
# The status of the response will be set to opts[:status].to_i
|
|
212
|
+
#
|
|
213
|
+
# ==== Returns
|
|
214
|
+
# Hash:: The options hash that was passed in.
|
|
215
|
+
def _handle_options!(opts)
|
|
216
|
+
self.status = opts[:status].to_i if opts[:status]
|
|
217
|
+
opts
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Get the layout that should be used. The content-type will be appended to
|
|
221
|
+
# the layout unless the layout already contains a "." in it.
|
|
222
|
+
#
|
|
223
|
+
# If no layout was passed in, this method will look for one with the same
|
|
224
|
+
# name as the controller, and finally one in "application.#{content_type}".
|
|
225
|
+
#
|
|
226
|
+
# ==== Parameters
|
|
227
|
+
# layout<~to_s>:: A layout, relative to the layout root. Defaults to nil.
|
|
228
|
+
#
|
|
229
|
+
# ==== Returns
|
|
230
|
+
# String:: The method name that corresponds to the found layout.
|
|
231
|
+
#
|
|
232
|
+
# ==== Raises
|
|
233
|
+
# TemplateNotFound::
|
|
234
|
+
# If a layout was specified (either via layout in the class or by passing
|
|
235
|
+
# one in to this method), and not found. No error will be raised if no
|
|
236
|
+
# layout was specified, and the default layouts were not found.
|
|
237
|
+
def _get_layout(layout = nil)
|
|
238
|
+
if _layout && !layout
|
|
239
|
+
layout = _layout.instance_of?(Symbol) && self.respond_to?(_layout, true) ? send(_layout) : _layout
|
|
240
|
+
end
|
|
241
|
+
layout = layout.to_s if layout
|
|
242
|
+
|
|
243
|
+
# If a layout was provided, throw an error if it's not found
|
|
244
|
+
if layout
|
|
245
|
+
template_method, template_location = _template_for(layout, layout.index(".") ? nil : content_type, "layout")
|
|
246
|
+
raise TemplateNotFound, "No layout found at #{template_location}" unless template_method
|
|
247
|
+
template_method
|
|
248
|
+
|
|
249
|
+
# If a layout was not provided, try the default locations
|
|
250
|
+
else
|
|
251
|
+
template, location = _template_for(controller_name, content_type, "layout")
|
|
252
|
+
template, location = _template_for("application", content_type, "layout") unless template
|
|
253
|
+
template
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Iterate over the template roots in reverse order, and return the template
|
|
258
|
+
# and template location of the first match.
|
|
259
|
+
#
|
|
260
|
+
# ==== Parameters
|
|
261
|
+
# thing<Object>:: The controller action.
|
|
262
|
+
# content_type<~to_s>:: The content type. Defaults to nil.
|
|
263
|
+
# controller<~to_s>:: The name of the controller. Defaults to nil.
|
|
264
|
+
#
|
|
265
|
+
# ==== Options (opts)
|
|
266
|
+
# :template<String>::
|
|
267
|
+
# The location of the template to use. Defaults to whatever matches this
|
|
268
|
+
# thing, content_type and controller.
|
|
269
|
+
#
|
|
270
|
+
# ==== Returns
|
|
271
|
+
# Array[Symbol, String]::
|
|
272
|
+
# A pair consisting of the template method and location.
|
|
273
|
+
def _template_for(thing, content_type, controller=nil, opts={})
|
|
274
|
+
template_method = nil
|
|
275
|
+
template_location = nil
|
|
276
|
+
|
|
277
|
+
self.class._template_roots.reverse_each do |root, template_location|
|
|
278
|
+
template_location = root / (opts[:template] || self.send(template_location, thing, content_type, controller))
|
|
279
|
+
template_method = Merb::Template.template_for(template_location)
|
|
280
|
+
break if template_method && self.respond_to?(template_method)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
[template_method, template_location]
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Called in templates to get at content thrown in another template. The
|
|
287
|
+
# results of rendering a template are automatically thrown into :for_layout,
|
|
288
|
+
# so catch_content or catch_content(:for_layout) can be used inside layouts
|
|
289
|
+
# to get the content rendered by the action template.
|
|
290
|
+
#
|
|
291
|
+
# ==== Parameters
|
|
292
|
+
# obj<Object>:: The key in the thrown_content hash. Defaults to :for_layout.
|
|
293
|
+
#---
|
|
294
|
+
# @public
|
|
295
|
+
def catch_content(obj = :for_layout)
|
|
296
|
+
@_caught_content[obj]
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Called in templates to store up content for later use. Takes a string
|
|
300
|
+
# and/or a block. First, the string is evaluated, and then the block is
|
|
301
|
+
# captured using the capture() helper provided by the template languages. The
|
|
302
|
+
# two are concatenated together.
|
|
303
|
+
#
|
|
304
|
+
# ==== Parameters
|
|
305
|
+
# obj<Object>:: The key in the thrown_content hash.
|
|
306
|
+
# string<String>:: Textual content. Defaults to nil.
|
|
307
|
+
# &block:: A block to be evaluated and concatenated to string.
|
|
308
|
+
#
|
|
309
|
+
# ==== Raises
|
|
310
|
+
# ArgumentError:: Neither string nor block given.
|
|
311
|
+
#
|
|
312
|
+
# ==== Example
|
|
313
|
+
# throw_content(:foo, "Foo")
|
|
314
|
+
# catch_content(:foo) #=> "Foo"
|
|
315
|
+
#---
|
|
316
|
+
# @public
|
|
317
|
+
def throw_content(obj, string = nil, &block)
|
|
318
|
+
unless string || block_given?
|
|
319
|
+
raise ArgumentError, "You must pass a block or a string into throw_content"
|
|
320
|
+
end
|
|
321
|
+
@_caught_content[obj] = string.to_s << (block_given? ? capture(&block) : "")
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
end
|