mirror of
				https://gitea.invidious.io/iv-org/shard-kemal.git
				synced 2024-08-15 00:53:36 +00:00 
			
		
		
		
	Refactor helpers into module namespaces
This commit is contained in:
		
							parent
							
								
									aaa2109837
								
							
						
					
					
						commit
						1cd329b92f
					
				
					 11 changed files with 357 additions and 177 deletions
				
			
		|  | @ -4,6 +4,7 @@ private def handle(request, fallthrough = true) | |||
|   io = IO::Memory.new | ||||
|   response = HTTP::Server::Response.new(io) | ||||
|   context = HTTP::Server::Context.new(request, response) | ||||
|   context.app = Kemal.application | ||||
|   handler = Kemal::StaticFileHandler.new "#{__DIR__}/static", fallthrough | ||||
|   handler.call context | ||||
|   response.close | ||||
|  |  | |||
|  | @ -1,3 +1,5 @@ | |||
| require "./helpers/*" | ||||
| 
 | ||||
| # Kemal Base | ||||
| # The DSL currently consists of | ||||
| # - get post put patch delete options | ||||
|  | @ -5,6 +7,10 @@ | |||
| # - before_* | ||||
| # - error | ||||
| class Kemal::Base | ||||
|   include FileHelpers | ||||
|   include Templates | ||||
|   include Macros | ||||
| 
 | ||||
|   HTTP_METHODS   = %w(get post put patch delete options) | ||||
|   FILTER_METHODS = %w(get post put patch delete options all) | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,7 +51,11 @@ module Kemal | |||
| 
 | ||||
|     def serve_static?(key) | ||||
|       config = @serve_static | ||||
|       config.try(&.[key]?) || config == true | ||||
|       (config.is_a?(Hash) && config[key]?) || false | ||||
|     end | ||||
| 
 | ||||
| 
 | ||||
|     def extra_options(&@extra_options : OptionParser ->) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| # - WebSocket(ws) | ||||
| # - before_* | ||||
| # - error | ||||
| require "./dsl/*" | ||||
| 
 | ||||
| {% for method in Kemal::Base::HTTP_METHODS %} | ||||
|   def {{method.id}}(path, &block : HTTP::Server::Context -> _) | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ end | |||
| # Logs the output via `logger`. | ||||
| # This is the built-in `Kemal::LogHandler` by default which uses STDOUT. | ||||
| def log(message : String) | ||||
|   Kemal.application.logger.write "#{message}\n" | ||||
|   Kemal.application.log(message) | ||||
| end | ||||
| 
 | ||||
| # Enables / Disables logging. | ||||
|  | @ -65,7 +65,6 @@ end | |||
| # ``` | ||||
| def logger(logger : Kemal::BaseLogHandler) | ||||
|   Kemal.application.logger = logger | ||||
|   Kemal.application.add_handler logger | ||||
| end | ||||
| 
 | ||||
| # Enables / Disables static file serving. | ||||
|  | @ -94,7 +93,7 @@ end | |||
| # end | ||||
| # ``` | ||||
| def headers(env : HTTP::Server::Context, additional_headers : Hash(String, String)) | ||||
|   env.response.headers.merge!(additional_headers) | ||||
|   Kemal.application.headers(env, additional_headers) | ||||
| end | ||||
| 
 | ||||
| # Send a file with given path and base the mime-type on the file extension | ||||
|  | @ -110,82 +109,7 @@ end | |||
| # send_file env, "./path/to/file", "image/jpeg" | ||||
| # ``` | ||||
| def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil) | ||||
|   config = Kemal.config.serve_static | ||||
|   file_path = File.expand_path(path, Dir.current) | ||||
|   mime_type ||= Kemal::Utils.mime_type(file_path) | ||||
|   env.response.content_type = mime_type | ||||
|   env.response.headers["Accept-Ranges"] = "bytes" | ||||
|   env.response.headers["X-Content-Type-Options"] = "nosniff" | ||||
|   minsize = 860 # http://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits ?? | ||||
|   request_headers = env.request.headers | ||||
|   filesize = File.size(file_path) | ||||
|   filestat = File.info(file_path) | ||||
| 
 | ||||
|   Kemal.config.static_headers.try(&.call(env.response, file_path, filestat)) | ||||
| 
 | ||||
|   File.open(file_path) do |file| | ||||
|     if env.request.method == "GET" && env.request.headers.has_key?("Range") | ||||
|       next multipart(file, env) | ||||
|     end | ||||
| 
 | ||||
|     condition = config.is_a?(Hash) && config["gzip"]? == true && filesize > minsize && Kemal::Utils.zip_types(file_path) | ||||
|     if condition && request_headers.includes_word?("Accept-Encoding", "gzip") | ||||
|       env.response.headers["Content-Encoding"] = "gzip" | ||||
|       Gzip::Writer.open(env.response) do |deflate| | ||||
|         IO.copy(file, deflate) | ||||
|       end | ||||
|     elsif condition && request_headers.includes_word?("Accept-Encoding", "deflate") | ||||
|       env.response.headers["Content-Encoding"] = "deflate" | ||||
|       Flate::Writer.open(env.response) do |deflate| | ||||
|         IO.copy(file, deflate) | ||||
|       end | ||||
|     else | ||||
|       env.response.content_length = filesize | ||||
|       IO.copy(file, env.response) | ||||
|     end | ||||
|   end | ||||
|   return | ||||
| end | ||||
| 
 | ||||
| private def multipart(file, env : HTTP::Server::Context) | ||||
|   # See http://httpwg.org/specs/rfc7233.html | ||||
|   fileb = file.size | ||||
|   startb = endb = 0 | ||||
| 
 | ||||
|   if match = env.request.headers["Range"].match /bytes=(\d{1,})-(\d{0,})/ | ||||
|     startb = match[1].to_i { 0 } if match.size >= 2 | ||||
|     endb = match[2].to_i { 0 } if match.size >= 3 | ||||
|   end | ||||
| 
 | ||||
|   endb = fileb - 1 if endb == 0 | ||||
| 
 | ||||
|   if startb < endb < fileb | ||||
|     content_length = 1 + endb - startb | ||||
|     env.response.status_code = 206 | ||||
|     env.response.content_length = content_length | ||||
|     env.response.headers["Accept-Ranges"] = "bytes" | ||||
|     env.response.headers["Content-Range"] = "bytes #{startb}-#{endb}/#{fileb}" # MUST | ||||
| 
 | ||||
|     if startb > 1024 | ||||
|       skipped = 0 | ||||
|       # file.skip only accepts values less or equal to 1024 (buffer size, undocumented) | ||||
|       until (increase_skipped = skipped + 1024) > startb | ||||
|         file.skip(1024) | ||||
|         skipped = increase_skipped | ||||
|       end | ||||
|       if (skipped_minus_startb = skipped - startb) > 0 | ||||
|         file.skip skipped_minus_startb | ||||
|       end | ||||
|     else | ||||
|       file.skip(startb) | ||||
|     end | ||||
| 
 | ||||
|     IO.copy(file, env.response, content_length) | ||||
|   else | ||||
|     env.response.content_length = fileb | ||||
|     env.response.status_code = 200 # Range not satisfable, see 4.4 Note | ||||
|     IO.copy(file, env.response) | ||||
|   end | ||||
|   Kemal.application.send_file(env, path, mime_type) | ||||
| end | ||||
| 
 | ||||
| # Send a file with given data and default `application/octet-stream` mime_type. | ||||
|  | @ -200,10 +124,7 @@ end | |||
| # send_file env, data_slice, "image/jpeg" | ||||
| # ``` | ||||
| def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil) | ||||
|   mime_type ||= "application/octet-stream" | ||||
|   env.response.content_type = mime_type | ||||
|   env.response.content_length = data.bytesize | ||||
|   env.response.write data | ||||
|   Kemal.application.send_file(env, data, mime_type) | ||||
| end | ||||
| 
 | ||||
| # Configures an `HTTP::Server::Response` to compress the response | ||||
|  | @ -211,7 +132,7 @@ end | |||
| # | ||||
| # Disabled by default. | ||||
| def gzip(status : Bool = false) | ||||
|   add_handler HTTP::CompressHandler.new if status | ||||
|   Kemal.application.gzip(status) | ||||
| end | ||||
| 
 | ||||
| # Adds headers to `Kemal::StaticFileHandler`. This is especially useful for `CORS`. | ||||
							
								
								
									
										47
									
								
								src/kemal/dsl/macros.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/kemal/dsl/macros.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| def content_for_blocks | ||||
|   Kemal.application.content_for_blocks | ||||
| end | ||||
| 
 | ||||
| macro content_for(key, file = __FILE__) | ||||
|   Kemal::Macros.content_for({{key}}, {{file}}) do | ||||
|     {{yield}} | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| # Yields content for the given key if a `content_for` block exists for that key. | ||||
| macro yield_content(key) | ||||
|   Kemal::Macros.yield_content({{key}}) | ||||
| end | ||||
| 
 | ||||
| # Render view with a layout as the superview. | ||||
| # | ||||
| #   render "src/views/index.ecr", "src/views/layout.ecr" | ||||
| # | ||||
| macro render(filename, layout) | ||||
|   Kemal::Macros.render({{filename}}, {{layout}}) | ||||
| end | ||||
| 
 | ||||
| # Render view with the given filename. | ||||
| macro render(filename) | ||||
|   Kemal::Macros.render({{filename}}) | ||||
| end | ||||
| 
 | ||||
| # Halt execution with the current context. | ||||
| # Returns 200 and an empty response by default. | ||||
| # | ||||
| #   halt env, status_code: 403, response: "Forbidden" | ||||
| macro halt(env, status_code = 200, response = "") | ||||
|   Kemal::Macros.halt({{env}}, {{status_code}}, {{response}}) | ||||
| end | ||||
| 
 | ||||
| # Extends context storage with user defined types. | ||||
| # | ||||
| # class User | ||||
| #   property name | ||||
| # end | ||||
| # | ||||
| # add_context_storage_type(User) | ||||
| # | ||||
| macro add_context_storage_type(type) | ||||
|   Kemal::Macros.add_context_storage_type({{type}}) | ||||
| end | ||||
							
								
								
									
										7
									
								
								src/kemal/dsl/templates.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/kemal/dsl/templates.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| def render_404 | ||||
|   Kemal.application.render_404 | ||||
| end | ||||
| 
 | ||||
| def render_500(context, backtrace, verbosity) | ||||
|   Kemal.application.render_500(context, backtrace, verbosity) | ||||
| end | ||||
							
								
								
									
										136
									
								
								src/kemal/helpers/file_helpers.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/kemal/helpers/file_helpers.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| module Kemal::FileHelpers | ||||
|   def log(message) | ||||
|     logger.write "#{message}\n" | ||||
|   end | ||||
| 
 | ||||
|   # Send a file with given path and base the mime-type on the file extension | ||||
|   # or default `application/octet-stream` mime_type. | ||||
|   # | ||||
|   # ``` | ||||
|   # send_file env, "./path/to/file" | ||||
|   # ``` | ||||
|   # | ||||
|   # Optionally you can override the mime_type | ||||
|   # | ||||
|   # ``` | ||||
|   # send_file env, "./path/to/file", "image/jpeg" | ||||
|   # ``` | ||||
|   def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil) | ||||
|     config = env.app.config | ||||
|     file_path = File.expand_path(path, Dir.current) | ||||
|     mime_type ||= Kemal::Utils.mime_type(file_path) | ||||
|     env.response.content_type = mime_type | ||||
|     env.response.headers["Accept-Ranges"] = "bytes" | ||||
|     env.response.headers["X-Content-Type-Options"] = "nosniff" | ||||
|     minsize = 860 # http://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits ?? | ||||
|     request_headers = env.request.headers | ||||
|     filesize = File.size(file_path) | ||||
|     filestat = File.stat(file_path) | ||||
| 
 | ||||
|     config.static_headers.try(&.call(env.response, file_path, filestat)) | ||||
| 
 | ||||
|     File.open(file_path) do |file| | ||||
|       if env.request.method == "GET" && env.request.headers.has_key?("Range") | ||||
|         next multipart(file, env) | ||||
|       end | ||||
|       if request_headers.includes_word?("Accept-Encoding", "gzip") && config.serve_static?("gzip") && filesize > minsize && Kemal::Utils.zip_types(file_path) | ||||
|         env.response.headers["Content-Encoding"] = "gzip" | ||||
|         Gzip::Writer.open(env.response) do |deflate| | ||||
|           IO.copy(file, deflate) | ||||
|         end | ||||
|       elsif request_headers.includes_word?("Accept-Encoding", "deflate") && config.serve_static?("gzip") && filesize > minsize && Kemal::Utils.zip_types(file_path) | ||||
|         env.response.headers["Content-Encoding"] = "deflate" | ||||
|         Flate::Writer.open(env.response) do |deflate| | ||||
|           IO.copy(file, deflate) | ||||
|         end | ||||
|       else | ||||
|         env.response.content_length = filesize | ||||
|         IO.copy(file, env.response) | ||||
|       end | ||||
|     end | ||||
|     return | ||||
|   end | ||||
| 
 | ||||
|   private def multipart(file, env : HTTP::Server::Context) | ||||
|     # See http://httpwg.org/specs/rfc7233.html | ||||
|     fileb = file.size | ||||
| 
 | ||||
|     range = env.request.headers["Range"] | ||||
|     match = range.match(/bytes=(\d{1,})-(\d{0,})/) | ||||
| 
 | ||||
|     startb = 0 | ||||
|     endb = 0 | ||||
| 
 | ||||
|     if match | ||||
|       if match.size >= 2 | ||||
|         startb = match[1].to_i { 0 } | ||||
|       end | ||||
| 
 | ||||
|       if match.size >= 3 | ||||
|         endb = match[2].to_i { 0 } | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     if endb == 0 | ||||
|       endb = fileb - 1 | ||||
|     end | ||||
| 
 | ||||
|     if startb < endb && endb < fileb | ||||
|       content_length = 1 + endb - startb | ||||
|       env.response.status_code = 206 | ||||
|       env.response.content_length = content_length | ||||
|       env.response.headers["Accept-Ranges"] = "bytes" | ||||
|       env.response.headers["Content-Range"] = "bytes #{startb}-#{endb}/#{fileb}" # MUST | ||||
| 
 | ||||
|       if startb > 1024 | ||||
|         skipped = 0 | ||||
|         # file.skip only accepts values less or equal to 1024 (buffer size, undocumented) | ||||
|         until skipped + 1024 > startb | ||||
|           file.skip(1024) | ||||
|           skipped += 1024 | ||||
|         end | ||||
|         if skipped - startb > 0 | ||||
|           file.skip(skipped - startb) | ||||
|         end | ||||
|       else | ||||
|         file.skip(startb) | ||||
|       end | ||||
| 
 | ||||
|       IO.copy(file, env.response, content_length) | ||||
|     else | ||||
|       env.response.content_length = fileb | ||||
|       env.response.status_code = 200 # Range not satisfable, see 4.4 Note | ||||
|       IO.copy(file, env.response) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def headers(env, additional_headers) | ||||
|     env.response.headers.merge!(additional_headers) | ||||
|   end | ||||
| 
 | ||||
|   # Send a file with given data and default `application/octet-stream` mime_type. | ||||
|   # | ||||
|   # ``` | ||||
|   # send_file env, data_slice | ||||
|   # ``` | ||||
|   # | ||||
|   # Optionally you can override the mime_type | ||||
|   # | ||||
|   # ``` | ||||
|   # send_file env, data_slice, "image/jpeg" | ||||
|   # ``` | ||||
|   def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil) | ||||
|     mime_type ||= "application/octet-stream" | ||||
|     env.response.content_type = mime_type | ||||
|     env.response.content_length = data.bytesize | ||||
|     env.response.write data | ||||
|   end | ||||
| 
 | ||||
|   # Configures an `HTTP::Server::Response` to compress the response | ||||
|   # output, either using gzip or deflate, depending on the `Accept-Encoding` request header. | ||||
|   # | ||||
|   # Disabled by default. | ||||
|   def gzip(status : Bool = false) | ||||
|     add_handler HTTP::CompressHandler.new if status | ||||
|   end | ||||
| end | ||||
|  | @ -1,98 +1,101 @@ | |||
| require "kilt" | ||||
| 
 | ||||
| CONTENT_FOR_BLOCKS = Hash(String, Tuple(String, Proc(String))).new | ||||
| module Kemal::Macros | ||||
|   def content_for_blocks | ||||
|     @content_for_blocks ||= Hash(String, Tuple(String, Proc(String))).new | ||||
|   end | ||||
| 
 | ||||
| # `content_for` is a set of helpers that allows you to capture | ||||
| # blocks inside views to be rendered later during the request. The most | ||||
| # common use is to populate different parts of your layout from your view. | ||||
| # | ||||
| # The currently supported engines are: ecr and slang. | ||||
| # | ||||
| # ## Usage | ||||
| # | ||||
| # You call `content_for`, generally from a view, to capture a block of markup | ||||
| # giving it an identifier: | ||||
| # | ||||
| # ``` | ||||
| # # index.ecr | ||||
| # <% content_for "some_key" do %> | ||||
| #   <chunk of="html">...</chunk> | ||||
| # <% end %> | ||||
| # ``` | ||||
| # | ||||
| # Then, you call `yield_content` with that identifier, generally from a | ||||
| # layout, to render the captured block: | ||||
| # | ||||
| # ``` | ||||
| # # layout.ecr | ||||
| # <%= yield_content "some_key" %> | ||||
| # ``` | ||||
| # | ||||
| # ## And How Is This Useful? | ||||
| # | ||||
| # For example, some of your views might need a few javascript tags and | ||||
| # stylesheets, but you don't want to force this files in all your pages. | ||||
| # Then you can put `<%= yield_content :scripts_and_styles %>` on your | ||||
| # layout, inside the <head> tag, and each view can call `content_for` | ||||
| # setting the appropriate set of tags that should be added to the layout. | ||||
| macro content_for(key, file = __FILE__) | ||||
|   %proc = ->() { | ||||
|     __kilt_io__ = IO::Memory.new | ||||
|     {{ yield }} | ||||
|     __kilt_io__.to_s | ||||
|   } | ||||
|   # `content_for` is a set of helpers that allows you to capture | ||||
|   # blocks inside views to be rendered later during the request. The most | ||||
|   # common use is to populate different parts of your layout from your view. | ||||
|   # | ||||
|   # The currently supported engines are: ecr and slang. | ||||
|   # | ||||
|   # ## Usage | ||||
|   # | ||||
|   # You call `content_for`, generally from a view, to capture a block of markup | ||||
|   # giving it an identifier: | ||||
|   # | ||||
|   # ``` | ||||
|   # # index.ecr | ||||
|   # <% content_for "some_key" do %> | ||||
|   #   <chunk of="html">...</chunk> | ||||
|   # <% end %> | ||||
|   # ``` | ||||
|   # | ||||
|   # Then, you call `yield_content` with that identifier, generally from a | ||||
|   # layout, to render the captured block: | ||||
|   # | ||||
|   # ``` | ||||
|   # # layout.ecr | ||||
|   # <%= yield_content "some_key" %> | ||||
|   # ``` | ||||
|   # | ||||
|   # ## And How Is This Useful? | ||||
|   # | ||||
|   # For example, some of your views might need a few javascript tags and | ||||
|   # stylesheets, but you don't want to force this files in all your pages. | ||||
|   # Then you can put `<%= yield_content :scripts_and_styles %>` on your | ||||
|   # layout, inside the <head> tag, and each view can call `content_for` | ||||
|   # setting the appropriate set of tags that should be added to the layout. | ||||
|   macro content_for(key, file = __FILE__) | ||||
|     %proc = ->() { | ||||
|       __kilt_io__ = IO::Memory.new | ||||
|       {{ yield }} | ||||
|       __kilt_io__.to_s | ||||
|     } | ||||
| 
 | ||||
|   CONTENT_FOR_BLOCKS[{{key}}] = Tuple.new {{file}}, %proc | ||||
|   nil | ||||
| end | ||||
|     content_for_blocks[{{key}}] = Tuple.new {{file}}, %proc | ||||
|     nil | ||||
|   end | ||||
| 
 | ||||
| # Yields content for the given key if a `content_for` block exists for that key. | ||||
| macro yield_content(key) | ||||
|   if CONTENT_FOR_BLOCKS.has_key?({{key}}) | ||||
|     __caller_filename__ = CONTENT_FOR_BLOCKS[{{key}}][0] | ||||
|     %proc = CONTENT_FOR_BLOCKS[{{key}}][1] | ||||
|     %proc.call if __content_filename__ == __caller_filename__ | ||||
|   # Yields content for the given key if a `content_for` block exists for that key. | ||||
|   macro yield_content(key) | ||||
|     if content_for_blocks.has_key?({{key}}) | ||||
|       __caller_filename__ = content_for_blocks[{{key}}][0] | ||||
|       %proc = content_for_blocks[{{key}}][1] | ||||
|       %proc.call if __content_filename__ == __caller_filename__ | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   # Render view with a layout as the superview. | ||||
|   # ``` | ||||
|   # render "src/views/index.ecr", "src/views/layout.ecr" | ||||
|   # ``` | ||||
|   macro render(filename, layout) | ||||
|     __content_filename__ = {{filename}} | ||||
|     content = render {{filename}} | ||||
|     render {{layout}} | ||||
|   end | ||||
| 
 | ||||
|   # Render view with the given filename. | ||||
|   macro render(filename) | ||||
|     Kilt.render({{filename}}) | ||||
|   end | ||||
| 
 | ||||
|   # Halt execution with the current context. | ||||
|   # Returns 200 and an empty response by default. | ||||
|   # | ||||
|   # ``` | ||||
|   # halt env, status_code: 403, response: "Forbidden" | ||||
|   # ``` | ||||
|   macro halt(env, status_code = 200, response = "") | ||||
|     {{env}}.response.status_code = {{status_code}} | ||||
|     {{env}}.response.print {{response}} | ||||
|     {{env}}.response.close | ||||
|     next | ||||
|   end | ||||
| 
 | ||||
|   # Extends context storage with user defined types. | ||||
|   # | ||||
|   # ``` | ||||
|   # class User | ||||
|   #   property name | ||||
|   # end | ||||
|   # | ||||
|   # add_context_storage_type(User) | ||||
|   # ``` | ||||
|   macro add_context_storage_type(type) | ||||
|     {{ HTTP::Server::Context::STORE_MAPPINGS.push(type) }} | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| # Render view with a layout as the superview. | ||||
| # | ||||
| # ``` | ||||
| # render "src/views/index.ecr", "src/views/layout.ecr" | ||||
| # ``` | ||||
| macro render(filename, layout) | ||||
|   __content_filename__ = {{filename}} | ||||
|   content = render {{filename}} | ||||
|   render {{layout}} | ||||
| end | ||||
| 
 | ||||
| # Render view with the given filename. | ||||
| macro render(filename) | ||||
|   Kilt.render({{filename}}) | ||||
| end | ||||
| 
 | ||||
| # Halt execution with the current context. | ||||
| # Returns 200 and an empty response by default. | ||||
| # | ||||
| # ``` | ||||
| # halt env, status_code: 403, response: "Forbidden" | ||||
| # ``` | ||||
| macro halt(env, status_code = 200, response = "") | ||||
|   {{env}}.response.status_code = {{status_code}} | ||||
|   {{env}}.response.print {{response}} | ||||
|   {{env}}.response.close | ||||
|   next | ||||
| end | ||||
| 
 | ||||
| # Extends context storage with user defined types. | ||||
| # | ||||
| # ``` | ||||
| # class User | ||||
| #   property name | ||||
| # end | ||||
| # | ||||
| # add_context_storage_type(User) | ||||
| # ``` | ||||
| macro add_context_storage_type(type) | ||||
|   {{ HTTP::Server::Context::STORE_MAPPINGS.push(type) }} | ||||
| end | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| # This file contains the built-in view templates that Kemal uses. | ||||
| # Currently it contains templates for 404 and 500 error codes. | ||||
| 
 | ||||
| <<<<<<< HEAD | ||||
| def render_404 | ||||
|   <<-HTML | ||||
|     <!DOCTYPE html> | ||||
|  | @ -32,4 +33,57 @@ def render_500(context, exception, verbosity) | |||
| 
 | ||||
|   context.response.print template | ||||
|   context | ||||
| ======= | ||||
| module Kemal::Templates | ||||
|   def render_404 | ||||
|     template = <<-HTML | ||||
|         <!DOCTYPE html> | ||||
|         <html> | ||||
|         <head> | ||||
|           <style type="text/css"> | ||||
|           body { text-align:center;font-family:helvetica,arial;font-size:22px; | ||||
|             color:#888;margin:20px} | ||||
|           img { max-width: 579px; width: 100%; } | ||||
|           #c {margin:0 auto;width:500px;text-align:left} | ||||
|           </style> | ||||
|         </head> | ||||
|         <body> | ||||
|           <h2>Kemal doesn't know this way.</h2> | ||||
|           <img src="/__kemal__/404.png"> | ||||
|         </body> | ||||
|         </html> | ||||
|     HTML | ||||
|   end | ||||
| 
 | ||||
|   def render_500(context, backtrace, verbosity) | ||||
|     message = if verbosity | ||||
|                 "<pre>#{HTML.escape(backtrace)}</pre>" | ||||
|               else | ||||
|                 "<p>Something wrong with the server :(</p>" | ||||
|               end | ||||
| 
 | ||||
|     template = <<-HTML | ||||
|         <!DOCTYPE html> | ||||
|         <html> | ||||
|         <head> | ||||
|           <style type="text/css"> | ||||
|           body { text-align:center;font-family:helvetica,arial;font-size:22px; | ||||
|             color:#888;margin:20px} | ||||
|           #c {margin:0 auto;width:500px;text-align:left} | ||||
|           pre {text-align:left;font-size:14px;color:#fff;background-color:#222; | ||||
|             font-family:Operator,"Source Code Pro",Menlo,Monaco,Inconsolata,monospace; | ||||
|             line-height:1.5;padding:10px;border-radius:2px;overflow:scroll} | ||||
|           </style> | ||||
|         </head> | ||||
|         <body> | ||||
|           <h2>Kemal has encountered an error. (500)</h2> | ||||
|           #{message} | ||||
|         </body> | ||||
|         </html> | ||||
|     HTML | ||||
|     context.response.status_code = 500 | ||||
|     context.response.print template | ||||
|     context | ||||
|   end | ||||
| >>>>>>> Refactor helpers into module namespaces | ||||
| end | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue