signpost 0.1.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 +7 -0
- data/lib/signpost.rb +29 -0
- data/lib/signpost/builder.rb +416 -0
- data/lib/signpost/builder/namespace.rb +13 -0
- data/lib/signpost/builder/nested.rb +34 -0
- data/lib/signpost/endpoint/action.rb +54 -0
- data/lib/signpost/endpoint/builder.rb +22 -0
- data/lib/signpost/endpoint/dynamic.rb +24 -0
- data/lib/signpost/endpoint/redirect.rb +65 -0
- data/lib/signpost/endpoint/resolver.rb +144 -0
- data/lib/signpost/middleware.rb +17 -0
- data/lib/signpost/route/nested.rb +20 -0
- data/lib/signpost/route/simple.rb +89 -0
- data/lib/signpost/router.rb +59 -0
- data/lib/signpost/sign/flat.rb +79 -0
- data/lib/signpost/sign/flat/path.rb +114 -0
- data/lib/signpost/sign/flat/redirect.rb +60 -0
- data/lib/signpost/sign/namespace.rb +11 -0
- data/lib/signpost/sign/nested.rb +39 -0
- data/lib/signpost/version.rb +13 -0
- metadata +92 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
class Signpost
|
2
|
+
class Router
|
3
|
+
RACK_REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
4
|
+
RACK_REQUEST_PATH = 'PATH_INFO'.freeze
|
5
|
+
RACK_QUERY_HASH = 'rack.request.query_hash'.freeze
|
6
|
+
|
7
|
+
attr_reader :routes
|
8
|
+
|
9
|
+
attr_reader :named_routes
|
10
|
+
|
11
|
+
attr_reader :params_key
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@routes[env[RACK_REQUEST_METHOD]].each do |route|
|
15
|
+
params = route.match(env[RACK_REQUEST_PATH], env)
|
16
|
+
|
17
|
+
case params
|
18
|
+
when nil
|
19
|
+
next
|
20
|
+
when Hash
|
21
|
+
if @options[:rack_params]
|
22
|
+
env[RACK_QUERY_HASH] = env[RACK_QUERY_HASH] ? env[RACK_QUERY_HASH].merge(params) : params
|
23
|
+
end
|
24
|
+
|
25
|
+
env[params_key] = params
|
26
|
+
|
27
|
+
return route.endpoint.call(env)
|
28
|
+
else
|
29
|
+
return params
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
default_action
|
34
|
+
end
|
35
|
+
|
36
|
+
def expand(name, data={})
|
37
|
+
@named_routes[name].expand(data)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def initialize(builders, options, root=false)
|
43
|
+
@routes = SUPPORTED_METHODS.each_with_object({}) { |m, h| h[m] = [] }.freeze
|
44
|
+
@named_routes = {}
|
45
|
+
@options = options
|
46
|
+
@root = root
|
47
|
+
|
48
|
+
@params_key = options[:params_key]
|
49
|
+
|
50
|
+
builders.each do |builder|
|
51
|
+
builder.expose(self, @routes, @named_routes)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_action
|
56
|
+
@root ? [404, {}, ['']] : nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Signpost
|
2
|
+
class Sign
|
3
|
+
|
4
|
+
class Flat
|
5
|
+
|
6
|
+
##
|
7
|
+
# Do not match given pattern
|
8
|
+
#
|
9
|
+
# Params:
|
10
|
+
# - pattern {String} pattern to ignore
|
11
|
+
#
|
12
|
+
# Examples:
|
13
|
+
#
|
14
|
+
# delete('/pages/:id').except('/pages/1')
|
15
|
+
# get('/pages/*slug/edit').except('/pages/system/*/edit')
|
16
|
+
#
|
17
|
+
def except(pattern)
|
18
|
+
@except = pattern
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Define pattern constraints for the route
|
24
|
+
#
|
25
|
+
# Params:
|
26
|
+
# - constraints {Hash|Array|Symbol|RegExp|String}
|
27
|
+
#
|
28
|
+
# Examples:
|
29
|
+
#
|
30
|
+
# get('/:id').capture(:digit)
|
31
|
+
# get('/:id').capture(/\d+/)
|
32
|
+
# get('/:id_or_slug').capture([/\d+/, :word])
|
33
|
+
# get('/:id.:ext').capture(id: /\d+/, ext: ['png', 'jpg'])
|
34
|
+
#
|
35
|
+
def capture(constraints)
|
36
|
+
@capture = constraints
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def expose(router, routing_table, named_routes)
|
41
|
+
route = Route::Simple.new(get_matcher, build_stack(router), build_params, @constraints, @name)
|
42
|
+
named_routes[route.name.to_sym] = route if route.name
|
43
|
+
|
44
|
+
http_methods.each do |method|
|
45
|
+
routing_table[method] << route
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def initialize(pattern, options, &block)
|
52
|
+
@pattern = pattern
|
53
|
+
@options = options
|
54
|
+
@namespace = options[:namespace]
|
55
|
+
|
56
|
+
@params = {}
|
57
|
+
@endpoint_params = {}
|
58
|
+
@constraints = []
|
59
|
+
|
60
|
+
@block = block
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Private: Build Mustermann matcher from given pattern and options
|
65
|
+
#
|
66
|
+
def get_matcher
|
67
|
+
matcher_opts = {
|
68
|
+
type: @options[:style] || :sinatra
|
69
|
+
}
|
70
|
+
|
71
|
+
matcher_opts[:capture] = @capture if @capture
|
72
|
+
matcher_opts[:except] = @except if @except
|
73
|
+
|
74
|
+
Mustermann.new(@pattern, matcher_opts)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Signpost
|
2
|
+
class Sign
|
3
|
+
class Flat
|
4
|
+
|
5
|
+
class Path < self
|
6
|
+
|
7
|
+
##
|
8
|
+
# Route endpoint specification
|
9
|
+
# Might be a string, hash or class wich defines controller and action
|
10
|
+
# names. Rack-compatible block is also acceptable.
|
11
|
+
#
|
12
|
+
# Params:
|
13
|
+
# - spec {String|Hash|Class|Proc} endpoint spec
|
14
|
+
#
|
15
|
+
# Examples:
|
16
|
+
#
|
17
|
+
# get('/').to('admin/users#index')
|
18
|
+
# get('/').to('Admin::Users#index')
|
19
|
+
# get('/').to(controller: 'Admin::Users', action: 'index')
|
20
|
+
# get('/').to(Admin::Users::List)
|
21
|
+
# get('/').to do |env|
|
22
|
+
# [200, {}, ['Hello world!']]
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
def to(spec=nil, &block)
|
26
|
+
@to = spec || block
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Define named route
|
32
|
+
#
|
33
|
+
# Params:
|
34
|
+
# - name {String|Symbol} route name
|
35
|
+
#
|
36
|
+
def as(name, postfix=nil)
|
37
|
+
@name = (postfix ? [name, @namespace, postfix] : [@namespace, name]).flatten.compact.join('_')
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Define domain constraints for the route
|
43
|
+
#
|
44
|
+
# Params:
|
45
|
+
# - constraints {Array}
|
46
|
+
#
|
47
|
+
# Examples:
|
48
|
+
#
|
49
|
+
# get('/stats').constraint(->(env) { env['RACK_ENV'] == 'development' })
|
50
|
+
#
|
51
|
+
def constraint(*constraints)
|
52
|
+
@constraints = constraints
|
53
|
+
self
|
54
|
+
end
|
55
|
+
alias :constraints :constraint
|
56
|
+
|
57
|
+
##
|
58
|
+
# Define default or additional params
|
59
|
+
#
|
60
|
+
# Params:
|
61
|
+
# - params {Hash}
|
62
|
+
#
|
63
|
+
# Examples:
|
64
|
+
#
|
65
|
+
# get('/pages/:id').params(id: 1)
|
66
|
+
# match('/:controller/:action').params(from: :dynamic_route)
|
67
|
+
#
|
68
|
+
def params(params)
|
69
|
+
@params = params
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def build_stack(router)
|
76
|
+
if @block && @block.arity == 0
|
77
|
+
@to = Endpoint::Action.new(@block, router)
|
78
|
+
end
|
79
|
+
|
80
|
+
resolved = Endpoint::Resolver.new(@to || @block, @options).resolve
|
81
|
+
|
82
|
+
@endpoint_params = resolved.params
|
83
|
+
|
84
|
+
Endpoint::Builder.new(resolved.endpoint, @options[:middlewares] || []).build
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_params
|
88
|
+
@endpoint_params.merge(@params)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Signpost::SUPPORTED_METHODS.each do |meth|
|
93
|
+
class_eval <<-BUILD, __FILE__, __LINE__
|
94
|
+
class #{meth} < Path
|
95
|
+
def http_methods
|
96
|
+
Set['#{meth}']
|
97
|
+
end
|
98
|
+
end
|
99
|
+
BUILD
|
100
|
+
end
|
101
|
+
|
102
|
+
class Any < Path
|
103
|
+
def via(*methods)
|
104
|
+
@http_methods = methods.map { |m| m.to_s.upcase }.keep_if { |m| Signpost::SUPPORTED_METHODS.include?(m) }.to_set
|
105
|
+
end
|
106
|
+
|
107
|
+
def http_methods
|
108
|
+
@http_methods || Signpost::SUPPORTED_METHODS
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Signpost
|
2
|
+
class Sign
|
3
|
+
class Flat
|
4
|
+
|
5
|
+
class Redirect < self
|
6
|
+
|
7
|
+
def to(path_or_name=nil, additional_values=nil, &block)
|
8
|
+
if block_given?
|
9
|
+
@to = block
|
10
|
+
else
|
11
|
+
@to = path_or_name
|
12
|
+
@additional = additional_values if additional_values
|
13
|
+
end
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def permanent
|
19
|
+
@status = 301
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def temporary
|
24
|
+
@status = 303
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def with_status(status)
|
29
|
+
@status = status
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def initialize(*)
|
36
|
+
super
|
37
|
+
@status = @options[:default_redirect_status]
|
38
|
+
@additional = @options[:default_redirect_additional_values] || :ignore
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_stack(router)
|
42
|
+
to_opts = { additional_values: @additional }
|
43
|
+
to = @to.is_a?(String) ? Mustermann::Expander.new(@to, to_opts) : @to
|
44
|
+
|
45
|
+
endpoint = Signpost::Endpoint::Redirect.new(to || @block, router, @status)
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_params
|
49
|
+
@endpoint_params
|
50
|
+
end
|
51
|
+
|
52
|
+
def http_methods
|
53
|
+
Signpost::SUPPORTED_METHODS
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Signpost
|
2
|
+
class Sign
|
3
|
+
|
4
|
+
class Nested
|
5
|
+
|
6
|
+
def expose(_router, routing_table, named_routes)
|
7
|
+
subrouter = @builder.build
|
8
|
+
subroutes = subrouter.routes
|
9
|
+
|
10
|
+
named_routes.merge!(subrouter.named_routes)
|
11
|
+
|
12
|
+
subroutes.keys.reject { |m| subroutes[m].empty? }.each do |method|
|
13
|
+
routing_table[method] << Route::Nested.new(@subpath, subrouter)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def initialize(subpath, options, &block)
|
20
|
+
@subpath = subpath
|
21
|
+
@options = options
|
22
|
+
@builder = builder.new(builder_options, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def builder
|
26
|
+
Builder::Nested
|
27
|
+
end
|
28
|
+
|
29
|
+
def builder_options
|
30
|
+
@options.merge({
|
31
|
+
subroute: @subpath,
|
32
|
+
middlewares: @options[:middlewares].dup
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: signpost
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrey Savchenko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mustermann
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: inflecto
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.2
|
41
|
+
description: Standalone router for rack and nothing else
|
42
|
+
email:
|
43
|
+
- andrey@aejis.eu
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/signpost.rb
|
49
|
+
- lib/signpost/builder.rb
|
50
|
+
- lib/signpost/builder/namespace.rb
|
51
|
+
- lib/signpost/builder/nested.rb
|
52
|
+
- lib/signpost/endpoint/action.rb
|
53
|
+
- lib/signpost/endpoint/builder.rb
|
54
|
+
- lib/signpost/endpoint/dynamic.rb
|
55
|
+
- lib/signpost/endpoint/redirect.rb
|
56
|
+
- lib/signpost/endpoint/resolver.rb
|
57
|
+
- lib/signpost/middleware.rb
|
58
|
+
- lib/signpost/route/nested.rb
|
59
|
+
- lib/signpost/route/simple.rb
|
60
|
+
- lib/signpost/router.rb
|
61
|
+
- lib/signpost/sign/flat.rb
|
62
|
+
- lib/signpost/sign/flat/path.rb
|
63
|
+
- lib/signpost/sign/flat/redirect.rb
|
64
|
+
- lib/signpost/sign/namespace.rb
|
65
|
+
- lib/signpost/sign/nested.rb
|
66
|
+
- lib/signpost/version.rb
|
67
|
+
homepage: https://github.com/Ptico/signpost
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '2.0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.2.2
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Yet another router for rack
|
91
|
+
test_files: []
|
92
|
+
has_rdoc:
|