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.
@@ -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,11 @@
1
+ class Signpost
2
+ class Sign
3
+
4
+ class Namespace < Nested
5
+ def builder
6
+ Builder::Namespace
7
+ end
8
+ end
9
+
10
+ end
11
+ 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
@@ -0,0 +1,13 @@
1
+ class Signpost
2
+ module VERSION
3
+ MAJOR = 0.freeze
4
+ MINOR = 1.freeze
5
+ PATCH = 0.freeze
6
+
7
+ String = [MAJOR, MINOR, PATCH].join('.').freeze
8
+
9
+ def self.to_s
10
+ String
11
+ end
12
+ end
13
+ 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: