pakyow-core 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/pakyow-core/CHANGELOG.md +23 -0
- data/pakyow-core/lib/pakyow/core/app.rb +81 -0
- data/pakyow-core/lib/{core → pakyow/core}/app_context.rb +0 -0
- data/pakyow-core/lib/pakyow/core/base.rb +61 -0
- data/pakyow-core/lib/pakyow/core/call_context.rb +171 -0
- data/pakyow-core/lib/{core → pakyow/core}/config/app.rb +10 -30
- data/pakyow-core/lib/pakyow/core/config/cookies.rb +4 -0
- data/pakyow-core/lib/{core → pakyow/core}/config/logger.rb +11 -16
- data/pakyow-core/lib/pakyow/core/config/reloader.rb +10 -0
- data/pakyow-core/lib/{core → pakyow/core}/config/server.rb +2 -4
- data/pakyow-core/lib/pakyow/core/config/session.rb +41 -0
- data/pakyow-core/lib/{core → pakyow/core}/config.rb +2 -0
- data/pakyow-core/lib/{core → pakyow/core}/errors.rb +0 -0
- data/pakyow-core/lib/pakyow/core/helpers/configuring.rb +142 -0
- data/pakyow-core/lib/pakyow/core/helpers/hooks.rb +106 -0
- data/pakyow-core/lib/pakyow/core/helpers/running.rb +124 -0
- data/pakyow-core/lib/{core → pakyow/core}/helpers.rb +21 -5
- data/pakyow-core/lib/{core → pakyow/core}/loader.rb +1 -1
- data/pakyow-core/lib/{core → pakyow/core}/middleware/logger.rb +8 -2
- data/pakyow-core/lib/pakyow/core/middleware/override.rb +3 -0
- data/pakyow-core/lib/pakyow/core/middleware/reloader.rb +23 -0
- data/pakyow-core/lib/pakyow/core/middleware/req_path_normalizer.rb +49 -0
- data/pakyow-core/lib/pakyow/core/middleware/session.rb +5 -0
- data/pakyow-core/lib/pakyow/core/middleware/static.rb +76 -0
- data/pakyow-core/lib/{core → pakyow/core}/multilog.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/request.rb +7 -3
- data/pakyow-core/lib/{core → pakyow/core}/response.rb +4 -2
- data/pakyow-core/lib/{core → pakyow/core}/route_eval.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/route_expansion_eval.rb +1 -1
- data/pakyow-core/lib/{core → pakyow/core}/route_lookup.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/route_merger.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/route_module.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/route_set.rb +2 -2
- data/pakyow-core/lib/{core → pakyow/core}/route_template_defaults.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/route_template_eval.rb +0 -0
- data/pakyow-core/lib/{core → pakyow/core}/router.rb +4 -0
- data/pakyow-core/lib/pakyow/core.rb +8 -0
- data/pakyow-core/lib/pakyow-core.rb +1 -11
- metadata +41 -34
- data/pakyow-core/lib/core/app.rb +0 -469
- data/pakyow-core/lib/core/base.rb +0 -56
- data/pakyow-core/lib/core/config/cookies.rb +0 -4
- data/pakyow-core/lib/core/middleware/reloader.rb +0 -14
- data/pakyow-core/lib/core/middleware/static.rb +0 -40
- data/pakyow-core/lib/views/errors/404.html +0 -13
- data/pakyow-core/lib/views/errors/500.html +0 -15
@@ -0,0 +1,106 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Helpers
|
3
|
+
# Methods to register and call hooks before and after particular triggers.
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
module Hooks
|
7
|
+
TYPES = %i(before after)
|
8
|
+
TRIGGERS = %i(init load process route match error configure reload)
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
protected
|
12
|
+
|
13
|
+
def hook_around(trigger)
|
14
|
+
call_hooks :before, trigger
|
15
|
+
yield
|
16
|
+
call_hooks :after, trigger
|
17
|
+
end
|
18
|
+
|
19
|
+
def call_hooks(type, trigger)
|
20
|
+
self.class.hook(type, trigger).each do |block|
|
21
|
+
instance_exec(&block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.extended(object)
|
27
|
+
object.send(:include, InstanceMethods)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Registers a before hook for a particular trigger.
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def before(trigger, &block)
|
34
|
+
register_hook(:before, trigger, block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Registers an after hook for a particular trigger.
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
def after(trigger, &block)
|
41
|
+
register_hook(:after, trigger, block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Fetches a hook by type (before | after) and trigger.
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
def hook(type, trigger)
|
48
|
+
check_hook_type(type)
|
49
|
+
check_trigger(trigger)
|
50
|
+
|
51
|
+
hooks[type.to_sym][trigger.to_sym]
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def hooks
|
57
|
+
return @hooks unless @hooks.nil?
|
58
|
+
|
59
|
+
@hooks = {
|
60
|
+
before: {},
|
61
|
+
after: {}
|
62
|
+
}
|
63
|
+
|
64
|
+
TRIGGERS.each do |name|
|
65
|
+
@hooks[:before][name.to_sym] = []
|
66
|
+
@hooks[:after][name.to_sym] = []
|
67
|
+
end
|
68
|
+
|
69
|
+
@hooks
|
70
|
+
end
|
71
|
+
|
72
|
+
def register_hook(type, trigger, block)
|
73
|
+
raise ArgumentError, 'Expected a block' if block.nil?
|
74
|
+
|
75
|
+
trigger = trigger.to_sym
|
76
|
+
|
77
|
+
check_trigger(trigger)
|
78
|
+
check_hook_type(type)
|
79
|
+
|
80
|
+
hooks[type][trigger] << block
|
81
|
+
end
|
82
|
+
|
83
|
+
def hook_around(trigger)
|
84
|
+
call_hooks :before, trigger
|
85
|
+
yield
|
86
|
+
call_hooks :after, trigger
|
87
|
+
end
|
88
|
+
|
89
|
+
def call_hooks(type, trigger)
|
90
|
+
hook(type, trigger).each do |block|
|
91
|
+
instance_exec(&block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_trigger(trigger)
|
96
|
+
return true if TRIGGERS.include?(trigger)
|
97
|
+
raise ArgumentError, "Hook trigger #{trigger} doesn't exist"
|
98
|
+
end
|
99
|
+
|
100
|
+
def check_hook_type(type)
|
101
|
+
return true if TYPES.include?(type)
|
102
|
+
raise ArgumentError, "Hook type #{type} doesn't exist"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'rack/builder'
|
2
|
+
require 'rack/handler'
|
3
|
+
|
4
|
+
module Pakyow
|
5
|
+
module Helpers
|
6
|
+
# Methods run running an app.
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
module Running
|
10
|
+
STOP_METHODS = ['stop!', 'stop']
|
11
|
+
HANDLERS = ['puma', 'thin', 'mongrel', 'webrick']
|
12
|
+
SIGNALS = [:INT, :TERM]
|
13
|
+
|
14
|
+
# Prepares the app for being staged in one or more environments by
|
15
|
+
# loading config(s), middleware, and setting the load path.
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def prepare(*env_or_envs)
|
19
|
+
return true if prepared?
|
20
|
+
|
21
|
+
# load config for one or more environments
|
22
|
+
load_env_config(*env_or_envs)
|
23
|
+
|
24
|
+
# load each block from middleware stack
|
25
|
+
load_middleware
|
26
|
+
|
27
|
+
# add app/lib to load path
|
28
|
+
$LOAD_PATH.unshift config.app.src_dir
|
29
|
+
|
30
|
+
@prepared = true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Stages the app by preparing and returning an instance. This is
|
34
|
+
# essentially everything short of running it.
|
35
|
+
#
|
36
|
+
# @api public
|
37
|
+
def stage(*env_or_envs)
|
38
|
+
prepare(*env_or_envs)
|
39
|
+
self.new
|
40
|
+
end
|
41
|
+
|
42
|
+
# Runs the staged app.
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def run(*env_or_envs)
|
46
|
+
return true if running?
|
47
|
+
@running = true
|
48
|
+
builder.run(stage(*env_or_envs))
|
49
|
+
detect_handler.run(builder, Host: config.server.host, Port: config.server.port) do |server|
|
50
|
+
SIGNALS.each do |signal|
|
51
|
+
trap(signal) { stop(server) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true if the application is prepared.
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def prepared?
|
60
|
+
@prepared == true
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns true if the application is running.
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def running?
|
67
|
+
@running == true
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns true if the application is staged.
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def staged?
|
74
|
+
!Pakyow.app.nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a rack builder instance.
|
78
|
+
#
|
79
|
+
# @api public
|
80
|
+
def builder
|
81
|
+
@builder ||= Rack::Builder.new
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns an instance of the rack handler.
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
def detect_handler
|
88
|
+
if config.server.handler
|
89
|
+
HANDLERS.unshift(config.server.handler).uniq!
|
90
|
+
end
|
91
|
+
|
92
|
+
HANDLERS.each do |handler_name|
|
93
|
+
begin
|
94
|
+
handler = Rack::Handler.get(handler_name)
|
95
|
+
return handler unless handler.nil?
|
96
|
+
rescue LoadError
|
97
|
+
rescue NameError
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
raise 'No handler found'
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
def stop(server)
|
107
|
+
STOP_METHODS.each do |method|
|
108
|
+
if server.respond_to?(method)
|
109
|
+
return server.send(method)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# exit ungracefully
|
114
|
+
Process.exit!
|
115
|
+
end
|
116
|
+
|
117
|
+
def load_middleware
|
118
|
+
middleware.each do |block|
|
119
|
+
instance_exec(builder, &block)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
module Pakyow
|
2
|
-
#
|
2
|
+
# Helpers available anywhere
|
3
|
+
#
|
4
|
+
# @api public
|
3
5
|
module Helpers
|
4
6
|
def context
|
5
7
|
@context or raise NoContextError
|
6
8
|
end
|
7
9
|
|
8
10
|
def logger
|
9
|
-
request.logger
|
11
|
+
request.logger || Pakyow.logger
|
10
12
|
end
|
11
13
|
|
12
14
|
def router
|
@@ -38,8 +40,22 @@ module Pakyow
|
|
38
40
|
def config
|
39
41
|
Pakyow::Config
|
40
42
|
end
|
41
|
-
end
|
42
43
|
|
43
|
-
|
44
|
-
|
44
|
+
# Returns the primary app environment.
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def env
|
48
|
+
config.env
|
49
|
+
end
|
50
|
+
|
51
|
+
# Helpers for Pakyow::App
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
module App; end
|
55
|
+
|
56
|
+
# Helpers for Pakyow::CallContext
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
module Context; end
|
60
|
+
end
|
45
61
|
end
|
@@ -17,7 +17,7 @@ module Pakyow
|
|
17
17
|
next if FileTest.directory?(path)
|
18
18
|
next if path.split('.')[-1] != 'rb'
|
19
19
|
|
20
|
-
if Config.
|
20
|
+
if Config.reloader.enabled
|
21
21
|
if !@times[path] || (@times[path] && File.mtime(path) - @times[path] > 0)
|
22
22
|
load(path)
|
23
23
|
@times[path] = File.mtime(path)
|
@@ -41,7 +41,7 @@ module Pakyow
|
|
41
41
|
|
42
42
|
def <<(msg = nil, severity = :unknown)
|
43
43
|
return if @log.nil?
|
44
|
-
msg << "\n"
|
44
|
+
(msg || "") << "\n"
|
45
45
|
|
46
46
|
msg = format(msg, severity) if @format
|
47
47
|
@mutex.synchronize do
|
@@ -83,7 +83,7 @@ module Pakyow
|
|
83
83
|
|
84
84
|
def format(msg, level)
|
85
85
|
return msg unless color = level_color(level)
|
86
|
-
return COLOR_SEQ % (30 + COLOR_TABLE.index(color)) + msg + RESET_SEQ
|
86
|
+
return COLOR_SEQ % (30 + COLOR_TABLE.index(color)) + (msg || "") + RESET_SEQ
|
87
87
|
end
|
88
88
|
|
89
89
|
def level_color(level)
|
@@ -99,6 +99,12 @@ end
|
|
99
99
|
|
100
100
|
module Pakyow
|
101
101
|
module Middleware
|
102
|
+
Pakyow::App.middleware do |builder|
|
103
|
+
if Pakyow::Config.logger.enabled
|
104
|
+
builder.use Pakyow::Middleware::Logger
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
102
108
|
class Logger
|
103
109
|
# handles logging after an error occurs
|
104
110
|
Pakyow::App.after(:error) {
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pakyow
|
2
|
+
module Middleware
|
3
|
+
Pakyow::App.middleware do |builder|
|
4
|
+
if Pakyow::Config.reloader.enabled
|
5
|
+
builder.use Pakyow::Middleware::Reloader
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Rack compatible middleware that tells app to reload on each request.
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class Reloader
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
Pakyow.app.reload
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pakyow/core/call_context'
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Middleware
|
5
|
+
Pakyow::App.middleware do |builder|
|
6
|
+
builder.use Pakyow::Middleware::ReqPathNormalizer
|
7
|
+
end
|
8
|
+
|
9
|
+
# Rack compatible middleware that normalize the path if contains '//'
|
10
|
+
# or has a trailing '/', it replace '//' with '/', remove trailing `/`
|
11
|
+
# and issue a 301 redirect to the normalized path.
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
class ReqPathNormalizer
|
15
|
+
TAIL_SLASH_REPLACE_REGEX = /(\/)+$/
|
16
|
+
TAIL_SLASH_REGEX = /(.)+(\/)+$/
|
17
|
+
|
18
|
+
def initialize(app)
|
19
|
+
@app = app
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
path = env['PATH_INFO']
|
24
|
+
|
25
|
+
if double_slash?(path) || tail_slash?(path)
|
26
|
+
catch :halt do
|
27
|
+
CallContext.new(env).redirect(normalize_path(path), 301)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def normalize_path(path)
|
35
|
+
normalized = path
|
36
|
+
.gsub('//', '/')
|
37
|
+
.gsub(TAIL_SLASH_REPLACE_REGEX, '')
|
38
|
+
end
|
39
|
+
|
40
|
+
def double_slash?(path)
|
41
|
+
path.include?('//')
|
42
|
+
end
|
43
|
+
|
44
|
+
def tail_slash?(path)
|
45
|
+
(TAIL_SLASH_REGEX =~ path).nil? ? false : true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'pakyow/core/config'
|
2
|
+
require 'pakyow/core/call_context'
|
3
|
+
|
4
|
+
module Pakyow
|
5
|
+
module Middleware
|
6
|
+
# Rack compatible middleware that serves static files from one or more configured resource stores.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# Pakyow::Config.app.resources = {
|
10
|
+
# default: './public'
|
11
|
+
# }
|
12
|
+
#
|
13
|
+
# Pakyow::App.builder.use Pakyow::Middleware::Static
|
14
|
+
#
|
15
|
+
# # Assuming './public/foo.png' exists, a GET request to '/foo.png' will
|
16
|
+
# # result in this middleware responding with the static file.
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
class Static
|
20
|
+
Pakyow::App.middleware do |builder|
|
21
|
+
if Pakyow::Config.app.static
|
22
|
+
builder.use Pakyow::Middleware::Static
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(app)
|
27
|
+
@app = app
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
static, resource_path = self.class.static?(env)
|
32
|
+
return @app.call(env) unless static
|
33
|
+
|
34
|
+
catch :halt do
|
35
|
+
CallContext.new(env).send(File.open(resource_path))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
STATIC_REGEX = /\.(.*)$/
|
41
|
+
STATIC_HTTP_METHODS = %w(GET)
|
42
|
+
|
43
|
+
# Checks if `path` can be found in any configured resource store.
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def static?(env)
|
47
|
+
path, method = env.values_at('PATH_INFO', 'REQUEST_METHOD')
|
48
|
+
|
49
|
+
return false unless STATIC_HTTP_METHODS.include?(method)
|
50
|
+
return false unless static_path?(path)
|
51
|
+
|
52
|
+
resources_contain?(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def static_path?(path)
|
58
|
+
path =~ STATIC_REGEX
|
59
|
+
end
|
60
|
+
|
61
|
+
def resources_contain?(path)
|
62
|
+
resources.each_pair do |_, resource_path|
|
63
|
+
full_path = File.join(resource_path, path)
|
64
|
+
return true, full_path if File.exists?(full_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def resources
|
71
|
+
Config.app.resources
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
File without changes
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'rack'
|
2
3
|
|
3
4
|
module Pakyow
|
4
5
|
|
@@ -58,9 +59,12 @@ module Pakyow
|
|
58
59
|
|
59
60
|
# Returns indifferent params (see {HashUtils.strhash} for more info on indifferent hashes).
|
60
61
|
def params
|
61
|
-
@params
|
62
|
-
|
63
|
-
@params =
|
62
|
+
return @params unless @params.nil?
|
63
|
+
|
64
|
+
@params = super
|
65
|
+
@params.merge!(env['pakyow.data']) if env['pakyow.data'].is_a?(Hash)
|
66
|
+
@params.merge!(JSON.parse(body.read.to_s)) if format == :json
|
67
|
+
@params = Hash.strhash(@params)
|
64
68
|
end
|
65
69
|
|
66
70
|
# Returns array of url components.
|
@@ -4,6 +4,8 @@ module Pakyow
|
|
4
4
|
class Response < Rack::Response
|
5
5
|
attr_reader :format
|
6
6
|
|
7
|
+
DEFAULT_CONTENT_TYPE = 'text/html;charset=utf-8'.freeze
|
8
|
+
|
7
9
|
STATUS_CODE_NAMES = {
|
8
10
|
100 => 'Continue',
|
9
11
|
101 => 'Switching Protocols',
|
@@ -117,13 +119,13 @@ module Pakyow
|
|
117
119
|
def initialize(*args)
|
118
120
|
super
|
119
121
|
|
120
|
-
self["Content-Type"] ||=
|
122
|
+
self["Content-Type"] ||= DEFAULT_CONTENT_TYPE
|
121
123
|
@format = Rack::Mime::MIME_TYPES.key(type)
|
122
124
|
end
|
123
125
|
|
124
126
|
def format=(format)
|
125
127
|
@format = format
|
126
|
-
self["Content-Type"] = Rack::Mime.mime_type(".#{format}")
|
128
|
+
self["Content-Type"] = format == :html ? DEFAULT_CONTENT_TYPE : Rack::Mime.mime_type(".#{format}")
|
127
129
|
end
|
128
130
|
|
129
131
|
def type
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -28,7 +28,7 @@ module Pakyow
|
|
28
28
|
method = method.to_sym
|
29
29
|
method = :get if method == :head
|
30
30
|
|
31
|
-
@routes[method].each
|
31
|
+
(@routes[method] || []).each do |r|
|
32
32
|
#TODO can we do this without conditionals? fall-through?
|
33
33
|
case r[0]
|
34
34
|
when Regexp
|
@@ -40,7 +40,7 @@ module Pakyow
|
|
40
40
|
return r, nil
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
end
|
44
44
|
|
45
45
|
nil
|
46
46
|
end
|
File without changes
|
File without changes
|
@@ -37,6 +37,10 @@ module Pakyow
|
|
37
37
|
raise MissingRoute, "Could not find route '#{name}'"
|
38
38
|
end
|
39
39
|
|
40
|
+
def exists?(context)
|
41
|
+
!match(context.request).empty?
|
42
|
+
end
|
43
|
+
|
40
44
|
# Performs the initial routing for a request.
|
41
45
|
#
|
42
46
|
def perform(context, app = Pakyow.app, &after_match)
|