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
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
handler = Kemal::StaticFileHandler.new "#{__DIR__}/static", fallthrough
|
handler = Kemal::StaticFileHandler.new "#{__DIR__}/static", fallthrough
|
||||||
handler.call context
|
handler.call context
|
||||||
response.close
|
response.close
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
require "./kemal/base"
|
require "./kemal/base"
|
||||||
require "./kemal/dsl"
|
require "./kemal/dsl"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require "./helpers/*"
|
||||||
|
|
||||||
# Kemal Base
|
# Kemal Base
|
||||||
# The DSL currently consists of
|
# The DSL currently consists of
|
||||||
# - get post put patch delete options
|
# - get post put patch delete options
|
||||||
|
@ -5,6 +7,10 @@
|
||||||
# - before_*
|
# - before_*
|
||||||
# - error
|
# - error
|
||||||
class Kemal::Base
|
class Kemal::Base
|
||||||
|
include FileHelpers
|
||||||
|
include Templates
|
||||||
|
include Macros
|
||||||
|
|
||||||
HTTP_METHODS = %w(get post put patch delete options)
|
HTTP_METHODS = %w(get post put patch delete options)
|
||||||
FILTER_METHODS = %w(get post put patch delete options all)
|
FILTER_METHODS = %w(get post put patch delete options all)
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,11 @@ module Kemal
|
||||||
|
|
||||||
def serve_static?(key)
|
def serve_static?(key)
|
||||||
config = @serve_static
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
# - WebSocket(ws)
|
# - WebSocket(ws)
|
||||||
# - before_*
|
# - before_*
|
||||||
# - error
|
# - error
|
||||||
|
require "./dsl/*"
|
||||||
|
|
||||||
{% for method in Kemal::Base::HTTP_METHODS %}
|
{% for method in Kemal::Base::HTTP_METHODS %}
|
||||||
def {{method.id}}(path, &block : HTTP::Server::Context -> _)
|
def {{method.id}}(path, &block : HTTP::Server::Context -> _)
|
||||||
|
|
|
@ -26,7 +26,7 @@ end
|
||||||
# Logs the output via `logger`.
|
# Logs the output via `logger`.
|
||||||
# This is the built-in `Kemal::LogHandler` by default which uses STDOUT.
|
# This is the built-in `Kemal::LogHandler` by default which uses STDOUT.
|
||||||
def log(message : String)
|
def log(message : String)
|
||||||
Kemal.application.logger.write "#{message}\n"
|
Kemal.application.log(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables / Disables logging.
|
# Enables / Disables logging.
|
||||||
|
@ -65,7 +65,6 @@ end
|
||||||
# ```
|
# ```
|
||||||
def logger(logger : Kemal::BaseLogHandler)
|
def logger(logger : Kemal::BaseLogHandler)
|
||||||
Kemal.application.logger = logger
|
Kemal.application.logger = logger
|
||||||
Kemal.application.add_handler logger
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables / Disables static file serving.
|
# Enables / Disables static file serving.
|
||||||
|
@ -94,7 +93,7 @@ end
|
||||||
# end
|
# end
|
||||||
# ```
|
# ```
|
||||||
def headers(env : HTTP::Server::Context, additional_headers : Hash(String, String))
|
def headers(env : HTTP::Server::Context, additional_headers : Hash(String, String))
|
||||||
env.response.headers.merge!(additional_headers)
|
Kemal.application.headers(env, additional_headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Send a file with given path and base the mime-type on the file extension
|
# 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"
|
# send_file env, "./path/to/file", "image/jpeg"
|
||||||
# ```
|
# ```
|
||||||
def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil)
|
def send_file(env : HTTP::Server::Context, path : String, mime_type : String? = nil)
|
||||||
config = Kemal.config.serve_static
|
Kemal.application.send_file(env, path, mime_type)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Send a file with given data and default `application/octet-stream` mime_type.
|
# 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"
|
# send_file env, data_slice, "image/jpeg"
|
||||||
# ```
|
# ```
|
||||||
def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil)
|
def send_file(env : HTTP::Server::Context, data : Slice(UInt8), mime_type : String? = nil)
|
||||||
mime_type ||= "application/octet-stream"
|
Kemal.application.send_file(env, data, mime_type)
|
||||||
env.response.content_type = mime_type
|
|
||||||
env.response.content_length = data.bytesize
|
|
||||||
env.response.write data
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Configures an `HTTP::Server::Response` to compress the response
|
# Configures an `HTTP::Server::Response` to compress the response
|
||||||
|
@ -211,7 +132,7 @@ end
|
||||||
#
|
#
|
||||||
# Disabled by default.
|
# Disabled by default.
|
||||||
def gzip(status : Bool = false)
|
def gzip(status : Bool = false)
|
||||||
add_handler HTTP::CompressHandler.new if status
|
Kemal.application.gzip(status)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adds headers to `Kemal::StaticFileHandler`. This is especially useful for `CORS`.
|
# 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"
|
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
|
# `content_for` is a set of helpers that allows you to capture
|
||||||
# blocks inside views to be rendered later during the request. The most
|
# 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.
|
# common use is to populate different parts of your layout from your view.
|
||||||
#
|
#
|
||||||
# The currently supported engines are: ecr and slang.
|
# The currently supported engines are: ecr and slang.
|
||||||
#
|
#
|
||||||
# ## Usage
|
# ## Usage
|
||||||
#
|
#
|
||||||
# You call `content_for`, generally from a view, to capture a block of markup
|
# You call `content_for`, generally from a view, to capture a block of markup
|
||||||
# giving it an identifier:
|
# giving it an identifier:
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# # index.ecr
|
# # index.ecr
|
||||||
# <% content_for "some_key" do %>
|
# <% content_for "some_key" do %>
|
||||||
# <chunk of="html">...</chunk>
|
# <chunk of="html">...</chunk>
|
||||||
# <% end %>
|
# <% end %>
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# Then, you call `yield_content` with that identifier, generally from a
|
# Then, you call `yield_content` with that identifier, generally from a
|
||||||
# layout, to render the captured block:
|
# layout, to render the captured block:
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# # layout.ecr
|
# # layout.ecr
|
||||||
# <%= yield_content "some_key" %>
|
# <%= yield_content "some_key" %>
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# ## And How Is This Useful?
|
# ## And How Is This Useful?
|
||||||
#
|
#
|
||||||
# For example, some of your views might need a few javascript tags and
|
# 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.
|
# 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
|
# Then you can put `<%= yield_content :scripts_and_styles %>` on your
|
||||||
# layout, inside the <head> tag, and each view can call `content_for`
|
# 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.
|
# setting the appropriate set of tags that should be added to the layout.
|
||||||
macro content_for(key, file = __FILE__)
|
macro content_for(key, file = __FILE__)
|
||||||
%proc = ->() {
|
%proc = ->() {
|
||||||
__kilt_io__ = IO::Memory.new
|
__kilt_io__ = IO::Memory.new
|
||||||
{{ yield }}
|
{{ yield }}
|
||||||
__kilt_io__.to_s
|
__kilt_io__.to_s
|
||||||
}
|
}
|
||||||
|
|
||||||
CONTENT_FOR_BLOCKS[{{key}}] = Tuple.new {{file}}, %proc
|
content_for_blocks[{{key}}] = Tuple.new {{file}}, %proc
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Yields content for the given key if a `content_for` block exists for that key.
|
# Yields content for the given key if a `content_for` block exists for that key.
|
||||||
macro yield_content(key)
|
macro yield_content(key)
|
||||||
if CONTENT_FOR_BLOCKS.has_key?({{key}})
|
if content_for_blocks.has_key?({{key}})
|
||||||
__caller_filename__ = CONTENT_FOR_BLOCKS[{{key}}][0]
|
__caller_filename__ = content_for_blocks[{{key}}][0]
|
||||||
%proc = CONTENT_FOR_BLOCKS[{{key}}][1]
|
%proc = content_for_blocks[{{key}}][1]
|
||||||
%proc.call if __content_filename__ == __caller_filename__
|
%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
|
||||||
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.
|
# This file contains the built-in view templates that Kemal uses.
|
||||||
# Currently it contains templates for 404 and 500 error codes.
|
# Currently it contains templates for 404 and 500 error codes.
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
def render_404
|
def render_404
|
||||||
<<-HTML
|
<<-HTML
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -32,4 +33,57 @@ def render_500(context, exception, verbosity)
|
||||||
|
|
||||||
context.response.print template
|
context.response.print template
|
||||||
context
|
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
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue