Yessiest
8 months ago
13 changed files with 383 additions and 8 deletions
-
15config.ru
-
1lib/hyde.rb
-
21lib/hyde/LAYOUT.md
-
46lib/hyde/dsl/path_constructors.rb
-
84lib/hyde/dsl/probe_methods.rb
-
8lib/hyde/node.rb
-
22lib/hyde/path.rb
-
12lib/hyde/probe.rb
-
12lib/hyde/probe/binding.rb
-
51lib/hyde/probe/handler.rb
-
74lib/hyde/probe/http_method.rb
-
12lib/hyde/request.rb
-
33lib/hyde/response.rb
@ -0,0 +1,84 @@ |
|||
# frozen_string_literal: true |
|||
|
|||
require_relative '../response' |
|||
|
|||
module Hyde |
|||
module DSL |
|||
# Common methods for Probe objects |
|||
module ProbeMethods |
|||
# Get the current request |
|||
# @return [Hyde::Request] |
|||
def request |
|||
@request |
|||
end |
|||
|
|||
# Stop execution and generate a boilerplate response with the given code |
|||
# @param errorcode [Integer] |
|||
# @param backtrace [Array(String), nil] |
|||
# @raise [UncaughtThrowError] throws :finish to return back to Server |
|||
def die(errorcode, backtrace: nil) |
|||
throw :finish, [errorcode].append( |
|||
*(@properties["handle.#{errorcode}"] or |
|||
@properties["handle.default"]).call( |
|||
errorcode, |
|||
backtrace: backtrace |
|||
) |
|||
) |
|||
end |
|||
|
|||
# Bounce request to the next handler |
|||
# @raise [UncaughtThrowError] throws :break to get out of the callback |
|||
def bounce |
|||
raise :break |
|||
end |
|||
|
|||
# Set response status (generate response if one doesn't exist yet) |
|||
# @param status [Integer] http status code |
|||
def status(status) |
|||
@response = (@response or Hyde::Response.new) |
|||
@response.status = status |
|||
end |
|||
|
|||
alias code status |
|||
|
|||
# Set response header (generate response if one doesn't exist yet) |
|||
# @param key [String] header name |
|||
# @param value [String] header value |
|||
def header(key, value) |
|||
return status(value) if key.downcase == "status" |
|||
|
|||
if key.match(/(?:[(),\/:;<=>?@\[\]{}"]|[^ -~])/) |
|||
raise StandardError, "header key has invalid characters" |
|||
end |
|||
|
|||
if value.match(/[^ -~]/) |
|||
raise StandardError, "value key has invalid characters" |
|||
end |
|||
|
|||
@origin.response = (@origin.response or Hyde::Response.new) |
|||
key = key.downcase |
|||
@origin.response.add_header(key, value) |
|||
end |
|||
|
|||
# Delete a header value from the headers hash |
|||
# If no value is provided, deletes all key entries |
|||
# @param key [String] header name |
|||
# @param value [String, nil] header value |
|||
def remove_header(key, value = nil) |
|||
return unless @origin.response |
|||
|
|||
return if key.downcase == "status" |
|||
|
|||
if key.match(/(?:[(),\/:;<=>?@\[\]{}"]|[^ -~])/) |
|||
raise StandardError, "header key has invalid characters" |
|||
end |
|||
|
|||
if value&.match(/[^ -~]/) |
|||
raise StandardError, "value key has invalid characters" |
|||
end |
|||
|
|||
@origin.response.delete_header(key, value) |
|||
end |
|||
end |
|||
end |
|||
end |
@ -0,0 +1,12 @@ |
|||
# frozen_string_literal: true |
|||
|
|||
require_relative "../dsl/probe_methods" |
|||
|
|||
module Hyde |
|||
class ProbeBinding |
|||
def initialize(origin) |
|||
@origin = origin |
|||
end |
|||
include Hyde::DSL::ProbeMethods |
|||
end |
|||
end |
@ -0,0 +1,51 @@ |
|||
# frozen_string_literal: true |
|||
|
|||
require_relative '../probe' |
|||
require_relative 'binding' |
|||
|
|||
module Hyde |
|||
# Probe that executes a callback on request |
|||
class Handler < Hyde::Probe |
|||
# @param path [Object] |
|||
# @param parent [Hyde::Node] |
|||
# @param exec [#call] |
|||
def initialize(path, parent:, &exec) |
|||
super(path, parent: parent) |
|||
@callback = exec |
|||
@binding = Hyde::ProbeBinding.new(self) |
|||
@response = nil |
|||
end |
|||
|
|||
attr_accessor :response |
|||
|
|||
# Method callback on successful request navigation. |
|||
# Runs block supplied with object initialization. |
|||
# Request's #splat and #param are passed to block. |
|||
# |
|||
# Callback's returned should be one of viable responses: |
|||
# |
|||
# - {Hyde::Response} object |
|||
# - An array that matches Rack return form |
|||
# - An array that matches old (Rack 2.x) return form |
|||
# - A string (returned as HTML with code 200) |
|||
# - false (bounces the request to next handler) |
|||
# @param request [Hyde::Request] |
|||
# @return [Boolean] true if further navigation is possible |
|||
# @raise [UncaughtThrowError] may raise if die() is called. |
|||
def process(request) |
|||
@request = request |
|||
response = catch(:break) do |
|||
@binding.instance_exec(*request.splat, |
|||
**request.param, |
|||
&@callback) |
|||
end |
|||
return false unless response |
|||
|
|||
if @response and [String, File, IO].include? response.class |
|||
@response.body = response |
|||
throw :finish, @response |
|||
end |
|||
throw :finish, response |
|||
end |
|||
end |
|||
end |
@ -0,0 +1,74 @@ |
|||
# frozen_string_literal: true |
|||
|
|||
require_relative '../probe' |
|||
require_relative 'binding' |
|||
require_relative 'handler' |
|||
|
|||
module Hyde |
|||
# Probe that executes callback on a GET |
|||
class GETHandler < Hyde::Handler |
|||
METHOD = "GET" |
|||
|
|||
# Method callback on successful request navigation. |
|||
# Runs block supplied with object initialization. |
|||
# Request's #splat and #param are passed to block. |
|||
# |
|||
# Callback's returned should be one of viable responses: |
|||
# |
|||
# - {Hyde::Response} object |
|||
# - An array that matches Rack return form |
|||
# - An array that matches old (Rack 2.x) return form |
|||
# - A string (returned as HTML with code 200) |
|||
# - false (bounces the request to next handler) |
|||
# @param request [Hyde::Request] |
|||
# @return [Boolean] true if further navigation is possible |
|||
# @raise [UncaughtThrowError] may raise if die() is called. |
|||
def process(request) |
|||
unless request.request_method.casecmp(self.class::METHOD).zero? |
|||
return false |
|||
end |
|||
|
|||
super(request) |
|||
end |
|||
end |
|||
|
|||
# Probe that executes callback on a POST |
|||
class POSTHandler < GETHandler |
|||
METHOD = "POST" |
|||
end |
|||
|
|||
# Probe that executes callback on a HEAD |
|||
class HEADHandler < GETHandler |
|||
METHOD = "HEAD" |
|||
end |
|||
|
|||
# Probe that executes callback on a PUT |
|||
class PUTHandler < GETHandler |
|||
METHOD = "PUT" |
|||
end |
|||
|
|||
# Probe that executes callback on a DELETE |
|||
class DELETEHandler < GETHandler |
|||
METHOD = "DELETE" |
|||
end |
|||
|
|||
# Probe that executes callback on a CONNECT |
|||
class CONNECTHandler < GETHandler |
|||
METHOD = "CONNECT" |
|||
end |
|||
|
|||
# Probe that executes callback on a OPTIONS |
|||
class OPTIONSHandler < GETHandler |
|||
METHOD = "OPTIONS" |
|||
end |
|||
|
|||
# Probe that executes callback on a TRACE |
|||
class TRACEHandler < GETHandler |
|||
METHOD = "TRACE" |
|||
end |
|||
|
|||
# Probe that executes callback on a PATCH |
|||
class PATCHHandler < GETHandler |
|||
METHOD = "PATCH" |
|||
end |
|||
end |
Write
Preview
Loading…
Cancel
Save
Reference in new issue