hanami-controller/spec/support/fixtures.rb

1642 lines
30 KiB
Ruby

require 'json'
require 'digest/md5'
require 'hanami/router'
require 'hanami/utils/escape'
require 'hanami/action/params'
require 'hanami/action/cookies'
require 'hanami/action/session'
require 'hanami/action/cache'
require 'hanami/action/glue'
HTTP_TEST_STATUSES_WITHOUT_BODY = Set.new((100..199).to_a << 204 << 205 << 304).freeze
HTTP_TEST_STATUSES = {
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
103 => 'Checkpoint',
122 => 'Request-URI too long',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
208 => 'Already Reported',
226 => 'IM Used',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Payload Too Large',
414 => 'URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot',
420 => 'Enhance Your Calm',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
444 => 'No Response',
449 => 'Retry With',
450 => 'Blocked by Windows Parental Controls',
451 => 'Wrong Exchange server',
499 => 'Client Closed Request',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
510 => 'Not Extended',
511 => 'Network Authentication Required',
598 => 'Network read timeout error',
599 => 'Network connect timeout error'
}
class RecordNotFound < StandardError
end
module Test
class Index
include Hanami::Action
expose :xyz
def call(params)
@xyz = params[:name]
end
end
end
class CallAction
include Hanami::Action
def call(params)
self.status = 201
self.body = 'Hi from TestAction!'
self.headers.merge!({ 'X-Custom' => 'OK' })
end
end
class ErrorCallAction
include Hanami::Action
def call(params)
raise
end
end
class MyCustomError < StandardError ; end
class ErrorCallFromInheritedErrorClass
include Hanami::Action
handle_exception StandardError => :handler
def call(params)
raise MyCustomError
end
private
def handler(exception)
status 501, 'An inherited exception occurred!'
end
end
class ErrorCallFromInheritedErrorClassStack
include Hanami::Action
handle_exception StandardError => :standard_handler
handle_exception MyCustomError => :handler
def call(params)
raise MyCustomError
end
private
def handler(exception)
status 501, 'MyCustomError was thrown'
end
def standard_handler(exception)
status 501, 'An unknown error was thrown'
end
end
class ErrorCallWithSymbolMethodNameAsHandlerAction
include Hanami::Action
handle_exception StandardError => :handler
def call(params)
raise StandardError
end
private
def handler(exception)
status 501, 'Please go away!'
end
end
class ErrorCallWithStringMethodNameAsHandlerAction
include Hanami::Action
handle_exception StandardError => 'standard_error_handler'
def call(params)
raise StandardError
end
private
def standard_error_handler(exception)
status 502, exception.message
end
end
class ErrorCallWithUnsetStatusResponse
include Hanami::Action
handle_exception ArgumentError => 'arg_error_handler'
def call(params)
raise ArgumentError
end
private
def arg_error_handler(exception)
end
end
class ErrorCallWithSpecifiedStatusCodeAction
include Hanami::Action
handle_exception StandardError => 422
def call(params)
raise StandardError
end
end
class ExposeAction
include Hanami::Action
expose :film, :time
def call(params)
@film = '400 ASA'
end
end
class ExposeReservedWordAction
include Hanami::Action
include Hanami::Action::Session
def self.expose_reserved_word(using_internal_method: false)
if using_internal_method
_expose :flash
else
expose :flash
end
end
end
class ZMiddleware
def initialize(app, &message)
@app = app
@message = message
end
def call(env)
code, headers, body = @app.call(env)
[code, headers.merge!('Z-Middleware' => @message.call), body]
end
end
class YMiddleware
def initialize(app)
@app = app
end
def call(env)
code, headers, body = @app.call(env)
[code, headers.merge!('Y-Middleware' => 'OK'), body]
end
end
class XMiddleware
def initialize(app)
@app = app
end
def call(env)
code, headers, body = @app.call(env)
[code, headers.merge!('X-Middleware' => 'OK'), body]
end
end
module UseAction
class Index
include Hanami::Action
use XMiddleware
def call(params)
self.body = 'Hello from UseAction::Index'
end
end
class Show
include Hanami::Action
use YMiddleware
def call(params)
self.body = 'Hello from UseAction::Show'
end
end
class Edit
include Hanami::Action
use ZMiddleware do
'OK'
end
def call(params)
self.body = 'Hello from UseAction::Edit'
end
end
end
module NoUseAction
class Index
include Hanami::Action
def call(params)
self.body = 'Hello from NoUseAction::Index'
end
end
end
class BeforeMethodAction
include Hanami::Action
expose :article, :logger
before :set_article, :reverse_article
append_before :add_first_name_to_logger, :add_last_name_to_logger
prepend_before :add_title_to_logger
def initialize
@logger = []
end
def call(params)
end
private
def set_article
@article = 'Bonjour!'
end
def reverse_article
@article.reverse!
end
def add_first_name_to_logger
@logger << 'John'
end
def add_last_name_to_logger
@logger << 'Doe'
end
def add_title_to_logger
@logger << 'Mr.'
end
end
class SubclassBeforeMethodAction < BeforeMethodAction
before :upcase_article
private
def upcase_article
@article.upcase!
end
end
class ParamsBeforeMethodAction < BeforeMethodAction
expose :exposed_params
private
def upcase_article
end
def set_article(params)
@exposed_params = params
@article = super() + params[:bang]
end
end
class ErrorBeforeMethodAction < BeforeMethodAction
private
def set_article
raise
end
end
class HandledErrorBeforeMethodAction < BeforeMethodAction
configuration.handle_exceptions true
handle_exception RecordNotFound => 404
private
def set_article
raise RecordNotFound.new
end
end
class BeforeBlockAction
include Hanami::Action
expose :article
before { @article = 'Good morning!' }
before { @article.reverse! }
def call(params)
end
end
class YieldBeforeBlockAction < BeforeBlockAction
expose :yielded_params
before {|params| @yielded_params = params }
end
class AfterMethodAction
include Hanami::Action
expose :egg, :logger
after :set_egg, :scramble_egg
append_after :add_first_name_to_logger, :add_last_name_to_logger
prepend_after :add_title_to_logger
def initialize
@logger = []
end
def call(params)
end
private
def set_egg
@egg = 'Egg!'
end
def scramble_egg
@egg = 'gE!g'
end
def add_first_name_to_logger
@logger << 'Jane'
end
def add_last_name_to_logger
@logger << 'Dixit'
end
def add_title_to_logger
@logger << 'Mrs.'
end
end
class SubclassAfterMethodAction < AfterMethodAction
after :upcase_egg
private
def upcase_egg
@egg.upcase!
end
end
class ParamsAfterMethodAction < AfterMethodAction
private
def scramble_egg(params)
@egg = super() + params[:question]
end
end
class ErrorAfterMethodAction < AfterMethodAction
private
def set_egg
raise
end
end
class HandledErrorAfterMethodAction < AfterMethodAction
configuration.handle_exceptions true
handle_exception RecordNotFound => 404
private
def set_egg
raise RecordNotFound.new
end
end
class AfterBlockAction
include Hanami::Action
expose :egg
after { @egg = 'Coque' }
after { @egg.reverse! }
def call(params)
end
end
class YieldAfterBlockAction < AfterBlockAction
expose :meaning_of_life_params
before {|params| @meaning_of_life_params = params }
end
class SessionAction
include Hanami::Action
include Hanami::Action::Session
def call(params)
end
end
class FlashAction
include Hanami::Action
include Hanami::Action::Session
def call(params)
flash[:error] = "ouch"
end
end
class RedirectAction
include Hanami::Action
def call(params)
redirect_to '/destination'
end
end
class StatusRedirectAction
include Hanami::Action
def call(params)
redirect_to '/destination', status: 301
end
end
class SafeStringRedirectAction
include Hanami::Action
def call(params)
location = Hanami::Utils::Escape::SafeString.new('/destination')
redirect_to location
end
end
class GetCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
self.body = cookies[:foo]
end
end
class ChangeCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
self.body = cookies[:foo]
cookies[:foo] = 'baz'
end
end
class GetDefaultCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
self.body = ''
cookies[:bar] = 'foo'
end
end
class GetOverwrittenCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
self.body = ''
cookies[:bar] = { value: 'foo', domain: 'hanamirb.com', path: '/action', secure: false, httponly: false }
end
end
class GetAutomaticallyExpiresCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
cookies[:bar] = { value: 'foo', max_age: 120 }
end
end
class SetCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
self.body = 'yo'
cookies[:foo] = 'yum!'
end
end
class SetCookiesWithOptionsAction
include Hanami::Action
include Hanami::Action::Cookies
def initialize(expires: Time.now.utc)
@expires = expires
end
def call(params)
cookies[:kukki] = { value: 'yum!', domain: 'hanamirb.org', path: '/controller', expires: @expires, secure: true, httponly: true }
end
end
class RemoveCookiesAction
include Hanami::Action
include Hanami::Action::Cookies
def call(params)
cookies[:rm] = nil
end
end
class ThrowCodeAction
include Hanami::Action
def call(params)
halt params[:status].to_i, params[:message]
end
end
class CatchAndThrowSymbolAction
include Hanami::Action
def call(params)
catch :done do
throw :done, 1
raise "This code shouldn't be reachable"
end
end
end
class ThrowBeforeMethodAction
include Hanami::Action
before :authorize!
before :set_body
def call(params)
self.body = 'Hello!'
end
private
def authorize!
halt 401
end
def set_body
self.body = 'Hi!'
end
end
class ThrowBeforeBlockAction
include Hanami::Action
before { halt 401 }
before { self.body = 'Hi!' }
def call(params)
self.body = 'Hello!'
end
end
class ThrowAfterMethodAction
include Hanami::Action
after :raise_timeout!
after :set_body
def call(params)
self.body = 'Hello!'
end
private
def raise_timeout!
halt 408
end
def set_body
self.body = 'Later!'
end
end
class ThrowAfterBlockAction
include Hanami::Action
after { halt 408 }
after { self.body = 'Later!' }
def call(params)
self.body = 'Hello!'
end
end
class HandledExceptionAction
include Hanami::Action
handle_exception RecordNotFound => 404
def call(params)
raise RecordNotFound.new
end
end
class DomainLogicException < StandardError
end
Hanami::Controller.class_eval do
configure do
handle_exception DomainLogicException => 400
end
end
class GlobalHandledExceptionAction
include Hanami::Action
def call(params)
raise DomainLogicException.new
end
end
Hanami::Controller.unload!
class UnhandledExceptionAction
include Hanami::Action
def call(params)
raise RecordNotFound.new
end
end
class ParamsAction
include Hanami::Action
def call(params)
self.body = params.to_h.inspect
end
end
class WhitelistedParamsAction
class Params < Hanami::Action::Params
params do
required(:id).maybe
required(:article).schema do
required(:tags).each(:str?)
end
end
end
include Hanami::Action
params Params
def call(params)
self.body = params.to_h.inspect
end
end
class WhitelistedDslAction
include Hanami::Action
params do
required(:username).filled
end
def call(params)
self.body = params.to_h.inspect
end
end
class WhitelistedUploadDslAction
include Hanami::Action
params do
required(:id).maybe
required(:upload).filled
end
def call(params)
self.body = params.to_h.inspect
end
end
class ParamsValidationAction
include Hanami::Action
params do
required(:email).filled(:str?)
end
def call(params)
halt 400 unless params.valid?
end
end
class TestParams < Hanami::Action::Params
params do
required(:email).filled(format?: /\A.+@.+\z/)
optional(:password).filled(:str?).confirmation
required(:name).filled
required(:tos).filled(:bool?)
required(:age).filled(:int?)
required(:address).schema do
required(:line_one).filled
required(:deep).schema do
required(:deep_attr).filled(:str?)
end
end
optional(:array).maybe do
each do
schema do
required(:name).filled(:str?)
end
end
end
end
end
class NestedParams < Hanami::Action::Params
params do
required(:signup).schema do
required(:name).filled(:str?)
required(:age).filled(:int?, gteq?: 18)
end
end
end
class Root
include Hanami::Action
def call(params)
self.body = params.to_h.inspect
headers.merge!({'X-Test' => 'test'})
end
end
module About
class Team < Root
end
class Contacts
include Hanami::Action
def call(params)
self.body = params.to_h.inspect
end
end
end
module Identity
class Action
include Hanami::Action
def call(params)
self.body = params.to_h.inspect
end
end
Show = Class.new(Action)
New = Class.new(Action)
Create = Class.new(Action)
Edit = Class.new(Action)
Update = Class.new(Action)
Destroy = Class.new(Action)
end
module Flowers
class Action
include Hanami::Action
def call(params)
self.body = params.to_h.inspect
end
end
Index = Class.new(Action)
Show = Class.new(Action)
New = Class.new(Action)
Create = Class.new(Action)
Edit = Class.new(Action)
Update = Class.new(Action)
Destroy = Class.new(Action)
end
module Painters
class Update
include Hanami::Action
params do
required(:painter).schema do
required(:first_name).filled(:str?)
required(:last_name).filled(:str?)
end
end
def call(params)
self.body = params.to_h.inspect
end
end
end
module Dashboard
class Index
include Hanami::Action
include Hanami::Action::Session
before :authenticate!
def call(params)
self.body = "User ID from session: #{session[:user_id]}"
end
private
def authenticate!
halt 401 unless loggedin?
end
def loggedin?
session.has_key?(:user_id)
end
end
end
module Sessions
class Create
include Hanami::Action
include Hanami::Action::Session
def call(params)
session[:user_id] = 23
redirect_to '/'
end
end
class Destroy
include Hanami::Action
include Hanami::Action::Session
def call(params)
session[:user_id] = nil
end
end
end
class StandaloneSession
include Hanami::Action
include Hanami::Action::Session
def call(params)
session[:age] = Time.now.year - 1982
end
end
module Glued
class SendFile
include Hanami::Action
include Hanami::Action::Glue
configuration.public_directory "spec/support/fixtures"
def call(params)
send_file "test.txt"
end
end
end
class ArtistNotFound < StandardError
end
module App
class CustomError < StandardError
end
class StandaloneAction
include Hanami::Action
handle_exception App::CustomError => 400
def call(params)
raise App::CustomError
end
end
end
module App2
class CustomError < StandardError
end
module Standalone
class Index
include Hanami::Action
configuration.handle_exception App2::CustomError => 400
def call(params)
raise App2::CustomError
end
end
end
end
module MusicPlayer
Controller = Hanami::Controller.dupe
Action = Hanami::Action.dup
Controller.module_eval do
configuration.reset!
configure do
handle_exception ArgumentError => 400
action_module MusicPlayer::Action
default_headers({
"X-Frame-Options" => "DENY"
})
prepare do
include Hanami::Action::Cookies
include Hanami::Action::Session
include MusicPlayer::Controllers::Authentication
end
end
end
module Controllers
module Authentication
def self.included(action)
action.class_eval { expose :current_user }
end
private
def current_user
'Luca'
end
end
class Dashboard
class Index
include MusicPlayer::Action
def call(params)
self.body = 'Muzic!'
headers['X-Frame-Options'] = 'ALLOW FROM https://example.org'
end
end
class Show
include MusicPlayer::Action
def call(params)
raise ArgumentError
end
end
end
module Artists
class Index
include MusicPlayer::Action
def call(params)
self.body = current_user
end
end
class Show
include MusicPlayer::Action
handle_exception ArtistNotFound => 404
def call(params)
raise ArtistNotFound
end
end
end
end
class StandaloneAction
include MusicPlayer::Action
def call(params)
raise ArgumentError
end
end
end
class VisibilityAction
include Hanami::Action
include Hanami::Action::Cookies
include Hanami::Action::Session
self.configuration.handle_exceptions false
def call(params)
self.body = 'x'
self.status = 201
self.format = :json
self.headers.merge!('X-Custom' => 'OK')
headers.merge!('Y-Custom' => 'YO')
self.session[:foo] = 'bar'
# PRIVATE
# self.configuration
# self.finish
# PROTECTED
self.response
self.cookies
self.session
response
cookies
session
end
end
module SendFileTest
Controller = Hanami::Controller.duplicate(self) do
handle_exceptions false
public_directory "spec/support/fixtures"
end
module Files
class Show
include SendFileTest::Action
def call(params)
id = params[:id]
# This if statement is only for testing purpose
if id == "1"
send_file Pathname.new('test.txt')
elsif id == "2"
send_file Pathname.new('hanami.png')
elsif id == "3"
send_file Pathname.new('Gemfile')
elsif id == "100"
send_file Pathname.new('unknown.txt')
else
# a more realistic example of globbing ':id(.:format)'
@resource = repository_dot_find_by_id(id)
# this is usually 406, but I want to distinguish it from the 406 below.
halt 400 unless @resource
extension = params[:format]
case(extension)
when 'html'
# in reality we'd render a template here, but as a test fixture, we'll simulate that answer
# we should have also checked #accept? but w/e
self.body = ::File.read(Pathname.new("spec/support/fixtures/#{@resource.asset_path}.html"))
self.status = 200
self.format = :html
when 'json', nil
self.format = :json
send_file Pathname.new("#{@resource.asset_path}.json")
else
halt 406
end
end
end
private
Model = Struct.new(:id, :asset_path)
def repository_dot_find_by_id(id)
return nil unless id =~ /^\d+$/
return Model.new(id.to_i, "resource-#{id}")
end
end
class UnsafeLocal
include SendFileTest::Action
def call(params)
unsafe_send_file "Gemfile"
end
end
class UnsafePublic
include SendFileTest::Action
def call(params)
unsafe_send_file "spec/support/fixtures/test.txt"
end
end
class UnsafeAbsolute
include SendFileTest::Action
def call(params)
unsafe_send_file Pathname.new("Gemfile").realpath
end
end
class UnsafeMissingLocal
include SendFileTest::Action
def call(params)
unsafe_send_file "missing"
end
end
class UnsafeMissingAbsolute
include SendFileTest::Action
def call(params)
unsafe_send_file Pathname.new(".").join("missing")
end
end
class Flow
include SendFileTest::Action
def call(params)
send_file Pathname.new('test.txt')
redirect_to '/'
end
end
class Glob
include Hanami::Action
def call(params)
halt 202
end
end
end
end
module HeadTest
Controller = Hanami::Controller.duplicate(self) do
handle_exceptions false
default_headers({
"X-Frame-Options" => "DENY"
})
prepare do
include Hanami::Action::Glue
include Hanami::Action::Session
end
end
module Home
class Index
include HeadTest::Action
def call(params)
self.body = 'index'
end
end
class Code
include HeadTest::Action
include HeadTest::Action::Cache
def call(params)
content = 'code'
headers.merge!(
'Allow' => 'GET, HEAD',
'Content-Encoding' => 'identity',
'Content-Language' => 'en',
'Content-Length' => content.length,
'Content-Location' => 'relativeURI',
'Content-MD5' => Digest::MD5.hexdigest(content),
'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT',
'Last-Modified' => 'Wed, 21 Jan 2015 11:32:10 GMT'
)
self.status = params[:code].to_i
self.body = 'code'
end
end
class Override
include HeadTest::Action
def call(params)
self.headers.merge!(
'Last-Modified' => 'Fri, 27 Nov 2015 13:32:36 GMT',
'X-Rate-Limit' => '4000',
'X-No-Pass' => 'true'
)
self.status = 204
end
private
def keep_response_header?(header)
super || 'X-Rate-Limit' == header
end
end
end
end
module FullStack
Controller = Hanami::Controller.duplicate(self) do
handle_exceptions false
prepare do
include Hanami::Action::Glue
include Hanami::Action::Session
end
end
module Controllers
module Home
class Index
include FullStack::Action
expose :greeting
def call(params)
@greeting = 'Hello'
end
end
class Head
include FullStack::Action
def call(params)
headers['X-Renderable'] = renderable?.to_s
self.body = 'foo'
end
end
end
module Books
class Index
include FullStack::Action
def call(params)
end
end
class Create
include FullStack::Action
params do
required(:title).filled(:str?)
end
def call(params)
params.valid?
redirect_to '/books'
end
end
class Update
include FullStack::Action
params do
required(:id).value(:int?)
required(:book).schema do
required(:title).filled(:str?)
required(:author).schema do
required(:name).filled(:str?)
required(:favourite_colour)
end
end
end
def call(params)
valid = params.valid?
self.status = 201
self.body = JSON.generate({
symbol_access: params[:book][:author] && params[:book][:author][:name],
valid: valid,
errors: params.errors.to_h
})
end
end
end
module Settings
class Index
include FullStack::Action
def call(params)
end
end
class Create
include FullStack::Action
def call(params)
flash[:message] = "Saved!"
redirect_to "/settings"
end
end
end
module Poll
class Start
include FullStack::Action
def call(params)
redirect_to '/poll/1'
end
end
class Step1
include FullStack::Action
def call(params)
if @_env['REQUEST_METHOD'] == 'GET'
flash[:notice] = "Start the poll"
else
flash[:notice] = "Step 1 completed"
redirect_to '/poll/2'
end
end
end
class Step2
include FullStack::Action
def call(params)
if @_env['REQUEST_METHOD'] == 'POST'
flash[:notice] = "Poll completed"
redirect_to '/'
end
end
end
end
module Users
class Show
include FullStack::Action
before :redirect_to_root
after :set_body
def call(params)
self.body = "call method shouldn't be called"
end
private
def redirect_to_root
redirect_to '/'
end
def set_body
self.body = "after callback shouldn't be called"
end
end
end
end
class Renderer
def render(env, response)
action = env.delete('hanami.action')
if response[0] == 200 && action.renderable?
response[2] = "#{ action.class.name } #{ action.exposures } params: #{ action.params.to_h } flash: #{ action.exposures[:flash].inspect }"
end
response
end
end
class Application
def initialize
resolver = Hanami::Routing::EndpointResolver.new(namespace: FullStack::Controllers)
routes = Hanami::Router.new(resolver: resolver) do
get '/', to: 'home#index'
get '/head', to: 'home#head'
resources :books, only: [:index, :create, :update]
get '/settings', to: 'settings#index'
post '/settings', to: 'settings#create'
get '/poll', to: 'poll#start'
namespace 'poll' do
get '/1', to: 'poll#step1'
post '/1', to: 'poll#step1'
get '/2', to: 'poll#step2'
post '/2', to: 'poll#step2'
end
namespace 'users' do
get '/1', to: 'users#show'
end
end
@renderer = Renderer.new
@middleware = Rack::Builder.new do
use Rack::Session::Cookie, secret: SecureRandom.hex(16)
run routes
end
end
def call(env)
@renderer.render(env, @middleware.call(env))
end
end
end
class MethodInspectionAction
include Hanami::Action
def call(params)
self.body = request_method
end
end
class RackExceptionAction
include Hanami::Action
class TestException < ::StandardError
end
def call(params)
raise TestException.new
end
end
class HandledRackExceptionAction
include Hanami::Action
class TestException < ::StandardError
end
handle_exception TestException => 500
def call(params)
raise TestException.new
end
end
class HandledRackExceptionSubclassAction
include Hanami::Action
class TestException < ::StandardError
end
class TestSubclassException < TestException
end
handle_exception TestException => 500
def call(params)
raise TestSubclassException.new
end
end
module SessionWithCookies
Controller = Hanami::Controller.duplicate(self) do
handle_exceptions false
prepare do
include Hanami::Action::Glue
include Hanami::Action::Session
include Hanami::Action::Cookies
end
end
module Controllers
module Home
class Index
include SessionWithCookies::Action
def call(params)
end
end
end
end
class Renderer
def render(env, response)
action = env.delete('hanami.action')
if response[0] == 200 && action.renderable?
response[2] = "#{ action.class.name } #{ action.exposures }"
end
response
end
end
class Application
def initialize
resolver = Hanami::Routing::EndpointResolver.new(namespace: SessionWithCookies::Controllers)
routes = Hanami::Router.new(resolver: resolver) do
get '/', to: 'home#index'
end
@renderer = Renderer.new
@middleware = Rack::Builder.new do
use Rack::Session::Cookie, secret: SecureRandom.hex(16)
run routes
end
end
def call(env)
@renderer.render(env, @middleware.call(env))
end
end
end
module SessionsWithoutCookies
Controller = Hanami::Controller.duplicate(self) do
handle_exceptions false
prepare do
include Hanami::Action::Glue
include Hanami::Action::Session
end
end
module Controllers
module Home
class Index
include SessionsWithoutCookies::Action
def call(params)
end
end
end
end
class Renderer
def render(env, response)
action = env.delete('hanami.action')
if response[0] == 200 && action.renderable?
response[2] = "#{ action.class.name } #{ action.exposures }"
end
response
end
end
class Application
def initialize
resolver = Hanami::Routing::EndpointResolver.new(namespace: SessionsWithoutCookies::Controllers)
routes = Hanami::Router.new(resolver: resolver) do
get '/', to: 'home#index'
end
@renderer = Renderer.new
@middleware = Rack::Builder.new do
use Rack::Session::Cookie, secret: SecureRandom.hex(16)
run routes
end
end
def call(env)
@renderer.render(env, @middleware.call(env))
end
end
end