Skip to content

Instantly share code, notes, and snippets.

@dblock
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dblock/05941e1485af8d1cd459 to your computer and use it in GitHub Desktop.
Save dblock/05941e1485af8d1cd459 to your computer and use it in GitHub Desktop.
for anatomy of a ruby gem, work in progress
module Grape
class Endpoint
attr_accessor :block, :settings
attr_reader :env, :request, :headers, :params
def initialize(settings, block)
@settings = settings
method = instance_method(...) # with some unique name
@block = proc { |endpoint_instance| method.bind(endpoint_instance).call }
end
def routes
@routes ||= prepare_routes
end
def prepare_routes
routes = []
methods.each do |method|
paths.each do |path|
routes << Route.new(method: method, path: path)
end
end
routes
end
def mount_in(route_set)
routes.each do |route|
methods = [route.route_method]
methods.each do |method|
route_set.add_route(self, {
path_info: route.route_compiled,
request_method: method
}, route_info: route)
end
end
end
def call(env)
dup.call!(env)
end
def call!(env)
builder = build_middleware
builder.run(env)
end
def build_middleware
b = Rack::Builder.new
b.use Rack::Head
b.use Grape::Middleware::Error, ...
b.use Grape::Middleware::Versioner, ...
b.use Grape::Middleware::Formatter, ...
b
end
# End the request and display an error to the
# end user with the specified message.
#
# @param message [String] The message to display.
# @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
def error!(message, status = nil, headers = nil)
status = settings[:default_error_status] unless status
throw :error, message: message, status: status, headers: headers
end
# Redirect to a new url.
#
# @param url [String] The url to be redirect.
# @param options [Hash] The options used when redirect.
# :permanent, default true.
def redirect(url, options = {})
merged_options = { permanent: false }.merge(options)
if merged_options[:permanent]
status 301
else
if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase != "GET"
status 303
else
status 302
end
end
header "Location", url
body ""
end
# Set or retrieve the HTTP status code.
#
# @param status [Integer] The HTTP Status Code to return for this request.
def status(status = nil)
if status
@status = status
else
return @status if @status
case request.request_method.to_s.upcase
when 'POST'
201
else
200
end
end
end
# Set an individual header or retrieve
# all headers that have been set.
def header(key = nil, val = nil)
if key
val ? @header[key.to_s] = val : @header.delete(key.to_s)
else
@header
end
end
# Set response content-type
def content_type(val)
header('Content-Type', val)
end
# Set or get a cookie
#
# @example
# cookies[:mycookie] = 'mycookie val'
# cookies['mycookie-string'] = 'mycookie string val'
# cookies[:more] = { value: '123', expires: Time.at(0) }
# cookies.delete :more
#
def cookies
@cookies ||= Cookies.new
end
# Allows you to define the response body as something other than the
# return value.
#
# @example
# get '/body' do
# body "Body"
# "Not the Body"
# end
#
# GET /body # => "Body"
def body(value = nil)
if value
@body = value
else
@body
end
end
protected
def run(env)
@env = env
@request = Grape::Request.new(env)
@params = @request.params
@headers = @request.headers
response_text = @block ? @block.call(self) : nil
[status, header, [body || response_text]]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment