pendragon 0.5.0 → 0.5.1
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/Gemfile.lock +46 -10
- data/README.md +1 -1
- data/lib/pendragon/configuration.rb +7 -3
- data/lib/pendragon/engine/compiler.rb +23 -7
- data/lib/pendragon/engine/recognizer.rb +19 -13
- data/lib/pendragon/error.rb +71 -0
- data/lib/pendragon/matcher.rb +30 -17
- data/lib/pendragon/padrino/route.rb +1 -1
- data/lib/pendragon/route.rb +50 -9
- data/lib/pendragon/router.rb +24 -8
- data/lib/pendragon/version.rb +1 -1
- data/lib/pendragon.rb +4 -3
- data/pendragon.gemspec +1 -1
- data/test/helper.rb +1 -0
- data/test/padrino_test.rb +0 -1
- metadata +8 -8
- data/lib/pendragon/error_handler.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50f2cc54ef1c804fa05b8de3a47d6bf731e86f8f
|
4
|
+
data.tar.gz: 90c08c4129ae507b429d35487ff7824a37ad424e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf8e88346a526a08c48e63db31f861d4b401754bcaea842e0ac0ce6446e241a0cf51b87d2c61ff6f1dcbf29c4e10d975a078fa31f9413881b578c60845a53a41
|
7
|
+
data.tar.gz: 070bc4ce928f628ba6f22260e42f05087ee96caccba81c0084a3ccf5fe7491cfa94aebaf7f695a539ef26c9a86944313e0674dd23c9240e255fa23b05bc5e922
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pendragon (0.
|
4
|
+
pendragon (0.5.1)
|
5
5
|
mustermann (= 0.2.0)
|
6
6
|
rack (>= 1.3.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activesupport (4.1.
|
11
|
+
activesupport (4.1.4)
|
12
12
|
i18n (~> 0.6, >= 0.6.9)
|
13
13
|
json (~> 1.7, >= 1.7.7)
|
14
14
|
minitest (~> 5.1)
|
@@ -19,20 +19,53 @@ GEM
|
|
19
19
|
http_router (0.11.1)
|
20
20
|
rack (>= 1.0.0)
|
21
21
|
url_mount (~> 0.2.1)
|
22
|
-
i18n (0.6.
|
22
|
+
i18n (0.6.11)
|
23
23
|
json (1.8.1)
|
24
|
+
mail (2.5.4)
|
25
|
+
mime-types (~> 1.16)
|
26
|
+
treetop (~> 1.4.8)
|
24
27
|
metaclass (0.0.4)
|
25
|
-
|
28
|
+
mime-types (1.25.1)
|
29
|
+
minitest (5.4.0)
|
26
30
|
mocha (1.1.0)
|
27
31
|
metaclass (~> 0.0.1)
|
32
|
+
moneta (0.7.20)
|
28
33
|
mustermann (0.2.0)
|
29
|
-
padrino
|
34
|
+
padrino (0.12.2)
|
35
|
+
padrino-admin (= 0.12.2)
|
36
|
+
padrino-cache (= 0.12.2)
|
37
|
+
padrino-core (= 0.12.2)
|
38
|
+
padrino-gen (= 0.12.2)
|
39
|
+
padrino-helpers (= 0.12.2)
|
40
|
+
padrino-mailer (= 0.12.2)
|
41
|
+
padrino-support (= 0.12.2)
|
42
|
+
padrino-admin (0.12.2)
|
43
|
+
padrino-core (= 0.12.2)
|
44
|
+
padrino-helpers (= 0.12.2)
|
45
|
+
padrino-cache (0.12.2)
|
46
|
+
moneta (~> 0.7.0)
|
47
|
+
padrino-core (= 0.12.2)
|
48
|
+
padrino-helpers (= 0.12.2)
|
49
|
+
padrino-core (0.12.2)
|
30
50
|
activesupport (>= 3.1)
|
31
51
|
http_router (~> 0.11.0)
|
52
|
+
padrino-support (= 0.12.2)
|
32
53
|
rack-protection (>= 1.5.0)
|
33
54
|
sinatra (~> 1.4.2)
|
34
|
-
thor (~> 0.
|
55
|
+
thor (~> 0.18.0)
|
56
|
+
padrino-gen (0.12.2)
|
57
|
+
bundler (~> 1.0)
|
58
|
+
padrino-core (= 0.12.2)
|
59
|
+
padrino-helpers (0.12.2)
|
60
|
+
i18n (~> 0.6, >= 0.6.7)
|
61
|
+
padrino-support (= 0.12.2)
|
35
62
|
tilt (~> 1.4.1)
|
63
|
+
padrino-mailer (0.12.2)
|
64
|
+
mail (~> 2.5.3)
|
65
|
+
padrino-core (= 0.12.2)
|
66
|
+
padrino-support (0.12.2)
|
67
|
+
activesupport (>= 3.1)
|
68
|
+
polyglot (0.3.5)
|
36
69
|
rack (1.5.2)
|
37
70
|
rack-protection (1.5.3)
|
38
71
|
rack
|
@@ -43,10 +76,13 @@ GEM
|
|
43
76
|
rack (~> 1.4)
|
44
77
|
rack-protection (~> 1.4)
|
45
78
|
tilt (~> 1.3, >= 1.3.4)
|
46
|
-
thor (0.
|
47
|
-
thread_safe (0.3.
|
79
|
+
thor (0.18.1)
|
80
|
+
thread_safe (0.3.4)
|
48
81
|
tilt (1.4.1)
|
49
|
-
|
82
|
+
treetop (1.4.15)
|
83
|
+
polyglot
|
84
|
+
polyglot (>= 0.3.1)
|
85
|
+
tzinfo (1.2.1)
|
50
86
|
thread_safe (~> 0.1)
|
51
87
|
url_mount (0.2.1)
|
52
88
|
rack
|
@@ -57,7 +93,7 @@ PLATFORMS
|
|
57
93
|
DEPENDENCIES
|
58
94
|
haml
|
59
95
|
mocha (>= 0.10.0)
|
60
|
-
padrino
|
96
|
+
padrino (~> 0.12.2)
|
61
97
|
pendragon!
|
62
98
|
rack-test (>= 0.5.0)
|
63
99
|
rake (>= 0.8.7)
|
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module Pendragon
|
2
|
+
# A class for configuration of Pendragon
|
3
|
+
# @!visibility private
|
2
4
|
class Configuration
|
3
|
-
|
4
|
-
#
|
5
|
+
# Defines an accessor as boolean method
|
6
|
+
# @example
|
7
|
+
# attr_boolean_accessor :accessor_name
|
5
8
|
def self.attr_boolean_accessor(*keys)
|
6
9
|
keys.each do |key|
|
7
10
|
attr_accessor key
|
@@ -15,8 +18,9 @@ module Pendragon
|
|
15
18
|
# @see Pendragon::Router#compile
|
16
19
|
attr_boolean_accessor :enable_compiler
|
17
20
|
|
18
|
-
# Automatically
|
21
|
+
# Automatically converts response into Rack format.
|
19
22
|
# Default value is `true`.
|
23
|
+
# @see Pendragon::Router#invoke
|
20
24
|
attr_boolean_accessor :auto_rack_format
|
21
25
|
|
22
26
|
# Constructs an instance of Pendragon::Configuration
|
@@ -1,11 +1,23 @@
|
|
1
1
|
require 'pendragon/engine/recognizer'
|
2
2
|
|
3
3
|
module Pendragon
|
4
|
+
# One of the engine classes for recognizing routes
|
5
|
+
# This engine will perform better than the recognizer engine
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# Pendragon.new do |config|
|
9
|
+
# config.enable_compiler = true
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# @!visibility private
|
4
13
|
class Compiler < Recognizer
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
14
|
+
# Concatenates all routes, recognizes routes matched with pattern, and returns them
|
15
|
+
# @overload call
|
16
|
+
# @param [Rack::Request] request
|
17
|
+
# @raise [Pendragon::BadRequest] raised if request is bad request
|
18
|
+
# @raise [Pendragon::NotFound] raised if cannot find routes that match with pattern
|
19
|
+
# @raise [Pendragon::MethodNotAllowed] raised if routes can be find and do not match with verb
|
20
|
+
# @return [Array] The return value will be something like [Pendragon::Route, Hash]
|
9
21
|
def call(request)
|
10
22
|
compile! unless compiled?
|
11
23
|
pattern, verb, params = parse_request(request)
|
@@ -17,8 +29,7 @@ module Pendragon
|
|
17
29
|
candidacies.map{|route| [route, params_for(route, pattern, params)]}
|
18
30
|
end
|
19
31
|
|
20
|
-
private
|
21
|
-
|
32
|
+
# @!visibility private
|
22
33
|
def compile!
|
23
34
|
return if compiled?
|
24
35
|
@regexps = @routes.map.with_index do |route, index|
|
@@ -30,6 +41,7 @@ module Pendragon
|
|
30
41
|
@regexps = compile(@regexps)
|
31
42
|
end
|
32
43
|
|
44
|
+
# @!visibility private
|
33
45
|
def compile(regexps, paths = [])
|
34
46
|
return paths if regexps.length.zero?
|
35
47
|
paths << Regexp.union(regexps)
|
@@ -37,14 +49,16 @@ module Pendragon
|
|
37
49
|
compile(regexps, paths)
|
38
50
|
end
|
39
51
|
|
52
|
+
# @!visibility private
|
40
53
|
def compiled?
|
41
54
|
!!@regexps
|
42
55
|
end
|
43
56
|
|
57
|
+
# @!visibility private
|
44
58
|
def match_with(pattern)
|
45
59
|
offset = 0
|
46
60
|
conditions = [pattern]
|
47
|
-
conditions << pattern[0..-2] if pattern !=
|
61
|
+
conditions << pattern[0..-2] if pattern != Matcher::PATH_DELIMITER && pattern.end_with?(Matcher::PATH_DELIMITER)
|
48
62
|
loop.with_object([]) do |_, candidacies|
|
49
63
|
return candidacies unless conditions.any?{|x| @regexps[offset] === x }
|
50
64
|
route = @routes[offset..-1].detect{|route| Regexp.last_match("_#{route.index}") }
|
@@ -52,5 +66,7 @@ module Pendragon
|
|
52
66
|
offset = route.index + 1
|
53
67
|
end
|
54
68
|
end
|
69
|
+
|
70
|
+
private :compile!, :compile, :compiled?, :match_with
|
55
71
|
end
|
56
72
|
end
|
@@ -1,17 +1,29 @@
|
|
1
1
|
module Pendragon
|
2
|
+
# One of the engine classes for recognizing routes
|
3
|
+
# @!visibility private
|
2
4
|
class Recognizer
|
5
|
+
# The keys for rack headers
|
6
|
+
PATH_INFO = "PATH_INFO".freeze
|
7
|
+
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
8
|
+
|
9
|
+
# Constructs an instance of Pendragon::Recognizer
|
10
|
+
# @param [Array<Pendragon::Route>] routes
|
3
11
|
def initialize(routes)
|
4
12
|
@routes = routes
|
5
13
|
end
|
6
14
|
|
15
|
+
# Recognized routes, and returns them
|
16
|
+
# @param [Rack::Request] request
|
17
|
+
# @raise [Pendragon::BadRequest] raised if request is bad request
|
18
|
+
# @raise [Pendragon::NotFound] raised if cannot find routes that match with pattern
|
19
|
+
# @raise [Pendragon::MethodNotAllowed] raised if routes can be find and do not match with verb
|
20
|
+
# @return [Array] The return value will be something like [Pendragon::Route, Hash]
|
7
21
|
def call(request)
|
8
22
|
pattern, verb, params = parse_request(request)
|
9
23
|
raise_exception(400) unless valid_verb?(verb)
|
10
24
|
fetch(pattern, verb){|route| [route, params_for(route, pattern, params)] }
|
11
25
|
end
|
12
26
|
|
13
|
-
private
|
14
|
-
|
15
27
|
# @!visibility private
|
16
28
|
def params_for(route, pattern, params)
|
17
29
|
route.params(pattern, params)
|
@@ -19,7 +31,7 @@ module Pendragon
|
|
19
31
|
|
20
32
|
# @!visibility private
|
21
33
|
def valid_verb?(verb)
|
22
|
-
Pendragon::HTTP_VERBS.include?(verb
|
34
|
+
Pendragon::HTTP_VERBS.include?(verb)
|
23
35
|
end
|
24
36
|
|
25
37
|
# @!visibility private
|
@@ -34,17 +46,9 @@ module Pendragon
|
|
34
46
|
# @!visibility private
|
35
47
|
def parse_request(request)
|
36
48
|
if request.is_a?(Hash)
|
37
|
-
[request[
|
49
|
+
[request[PATH_INFO], request[REQUEST_METHOD].upcase, {}]
|
38
50
|
else
|
39
|
-
[request.path_info, request.request_method.
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# @!visibility private
|
44
|
-
def parse_request_params(params)
|
45
|
-
params.inject({}) do |result, entry|
|
46
|
-
result[entry[0].to_sym] = entry[1]
|
47
|
-
result
|
51
|
+
[request.path_info, request.request_method.upcase, request.params]
|
48
52
|
end
|
49
53
|
end
|
50
54
|
|
@@ -61,5 +65,7 @@ module Pendragon
|
|
61
65
|
end
|
62
66
|
}.(error_code)
|
63
67
|
end
|
68
|
+
|
69
|
+
private :params_for, :valid_verb?, :fetch, :parse_request, :raise_exception
|
64
70
|
end
|
65
71
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Pendragon
|
2
|
+
# Raises the exception if routes that matches the condition do not exist
|
3
|
+
InvalidRouteException = Class.new(ArgumentError)
|
4
|
+
|
5
|
+
# A base class for error responses
|
6
|
+
# ResponseError#status and ResponseError#body must be implemented by subclass
|
7
|
+
class ResponseError < StandardError
|
8
|
+
def initialize(*args)
|
9
|
+
@args = args
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
[status, headers, Array(body)]
|
14
|
+
end
|
15
|
+
|
16
|
+
def status
|
17
|
+
raise NotImplementedError, "`status` must be implemented by subclass"
|
18
|
+
end
|
19
|
+
|
20
|
+
def body
|
21
|
+
raise NotImplementedError, "`body` must be implemented by subclass"
|
22
|
+
end
|
23
|
+
|
24
|
+
def headers
|
25
|
+
@headers ||= { "Content-Type" => "text/plain" }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# A class for BadRequest response
|
30
|
+
class BadRequest < ResponseError
|
31
|
+
def status
|
32
|
+
@status ||= 400
|
33
|
+
end
|
34
|
+
|
35
|
+
def body
|
36
|
+
@body ||= "Bad Request"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# A class for NotFound response
|
41
|
+
class NotFound < ResponseError
|
42
|
+
def status
|
43
|
+
@status ||= 404
|
44
|
+
end
|
45
|
+
|
46
|
+
def body
|
47
|
+
@body ||= "Not Found"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# A class for MethodNotAllowed response
|
52
|
+
class MethodNotAllowed < ResponseError
|
53
|
+
ALLOW = "Allow".freeze
|
54
|
+
COMMA = ", ".freeze
|
55
|
+
|
56
|
+
def status
|
57
|
+
@status ||= 405
|
58
|
+
end
|
59
|
+
|
60
|
+
def body
|
61
|
+
@body ||= "Method Not Allowed"
|
62
|
+
end
|
63
|
+
|
64
|
+
def headers
|
65
|
+
@headers ||= begin
|
66
|
+
super_headers = super
|
67
|
+
super_headers.merge!(ALLOW => @args.shift.map{|verb| verb.upcase } * COMMA)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/pendragon/matcher.rb
CHANGED
@@ -1,40 +1,49 @@
|
|
1
1
|
require 'mustermann/sinatra'
|
2
2
|
|
3
3
|
module Pendragon
|
4
|
+
# A class for path matching
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# matcher = Pendragon::Matcher.new("/category/:id", capture: {id: /\d+/})
|
8
|
+
# matcher.match("/category/1234") #=> #<MatchData "/category/1234" id:"1234">
|
9
|
+
#
|
10
|
+
# @!visibility private
|
4
11
|
class Matcher
|
12
|
+
# A character of path delimiter
|
13
|
+
PATH_DELIMITER = "/".freeze
|
14
|
+
|
15
|
+
# A prefix character of query string
|
16
|
+
QUERY_PREFIX = "?".freeze
|
17
|
+
|
18
|
+
# A character of query string delimiter
|
19
|
+
QUERY_DELIMITER = "&".freeze
|
20
|
+
|
21
|
+
# Constructs a new instance of Pendragon::Matcher
|
5
22
|
# @param [String] path The path is string or regexp.
|
6
23
|
# @option options [Hash] :capture Set capture for path pattern.
|
7
24
|
# @option options [Hash] :default_values Set default_values for path pattern.
|
8
|
-
#
|
9
25
|
# @return [Pendragon::Matcher]
|
10
|
-
#
|
11
26
|
def initialize(path, options = {})
|
12
|
-
@path = path.is_a?(String) && path.empty? ?
|
27
|
+
@path = path.is_a?(String) && path.empty? ? PATH_DELIMITER : path
|
13
28
|
@capture = options.delete(:capture)
|
14
29
|
@default_values = options.delete(:default_values)
|
15
30
|
end
|
16
31
|
|
17
|
-
#
|
18
|
-
#
|
32
|
+
# Does the matching.
|
19
33
|
# @param [String] pattern The pattern is actual path (path_info etc).
|
20
|
-
#
|
21
34
|
# @return [MatchData] If the pattern matched this route, return a MatchData.
|
22
35
|
# @return [Nil] If the pattern doesn't matched this route, return a nil.
|
23
|
-
#
|
24
36
|
def match(pattern)
|
25
|
-
pattern = pattern[0..-2] if mustermann? and pattern !=
|
37
|
+
pattern = pattern[0..-2] if mustermann? and pattern != PATH_DELIMITER and pattern.end_with?(PATH_DELIMITER)
|
26
38
|
handler.match(pattern)
|
27
39
|
end
|
28
40
|
|
29
|
-
# Expands
|
30
|
-
#
|
41
|
+
# Expands a path with params.
|
31
42
|
# @param [Hash] params The params for path pattern.
|
32
|
-
#
|
33
43
|
# @example
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
44
|
+
# matcher = Pendragon::Matcher.new("/foo/:bar")
|
45
|
+
# matcher.expand(:bar => 123) #=> "/foo/123"
|
46
|
+
# matcher.expand(:bar => "bar", :baz => "test") #=> "/foo/bar?baz=test"
|
38
47
|
# @return [String] A expaneded path.
|
39
48
|
def expand(params)
|
40
49
|
params = params.dup
|
@@ -44,15 +53,17 @@ module Pendragon
|
|
44
53
|
end
|
45
54
|
params.merge!(@default_values) if @default_values.is_a?(Hash)
|
46
55
|
expanded_path = handler.expand(params)
|
47
|
-
expanded_path = expanded_path +
|
56
|
+
expanded_path = expanded_path + QUERY_PREFIX + query.map{|k,v| "#{k}=#{v}" }.join(QUERY_DELIMITER) unless query.empty?
|
48
57
|
expanded_path
|
49
58
|
end
|
50
59
|
|
60
|
+
# Returns whether the handler is Mustermann
|
51
61
|
# @return [Boolean] This matcher's handler is mustermann ?
|
52
62
|
def mustermann?
|
53
63
|
handler.instance_of?(Mustermann::Sinatra)
|
54
64
|
end
|
55
65
|
|
66
|
+
# Returns the handler
|
56
67
|
# @return [Mustermann::Sinatra] Returns a Mustermann::Sinatra when @path is string.
|
57
68
|
# @return [Regexp] Returns a regexp when @path is regexp.
|
58
69
|
def handler
|
@@ -65,14 +76,16 @@ module Pendragon
|
|
65
76
|
end
|
66
77
|
end
|
67
78
|
|
79
|
+
# Converts the handler into String
|
68
80
|
# @return [String] Returns a converted handler.
|
69
81
|
def to_s
|
70
82
|
handler.to_s
|
71
83
|
end
|
72
84
|
|
85
|
+
# Returns all named captures
|
73
86
|
# @return [Array] Returns a named captures.
|
74
87
|
def names
|
75
|
-
handler.names
|
88
|
+
handler.names
|
76
89
|
end
|
77
90
|
end
|
78
91
|
end
|
@@ -3,7 +3,7 @@ require 'pendragon/route'
|
|
3
3
|
module Pendragon
|
4
4
|
module Padrino
|
5
5
|
class Route < ::Pendragon::Route
|
6
|
-
attr_accessor :action, :cache, :cache_key, :
|
6
|
+
attr_accessor :action, :cache, :cache_key, :cache_expires, :parent,
|
7
7
|
:use_layout, :controller, :user_agent, :path_for_generation
|
8
8
|
|
9
9
|
def before_filters(&block)
|
data/lib/pendragon/route.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
module Pendragon
|
2
|
+
# A class for defining the route
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# route = Pendragon::Route.new("/:id", "GET", capture: id: /\d+/){|params| params[:id].to_s }
|
6
|
+
# route.match("/1234") #=> #<MatchData "/category/1234" id:"1234">
|
7
|
+
# route.arity
|
2
8
|
class Route
|
3
9
|
|
4
10
|
# The accessors are useful to access from Pendragon::Router
|
@@ -14,37 +20,59 @@ module Pendragon
|
|
14
20
|
attr_writer :router
|
15
21
|
|
16
22
|
# Constructs a new instance of Pendragon::Route
|
23
|
+
# @param [String, Regexp] path The path of route
|
24
|
+
# @param [String, Symbol] verb The verb of route
|
25
|
+
# @param [Hash] options The options hash
|
17
26
|
def initialize(path, verb, options = {}, &block)
|
18
27
|
@block = block if block_given?
|
19
|
-
@path, @verb = path, verb
|
28
|
+
@path, @verb = path, verb.to_s.upcase
|
20
29
|
@capture = {}
|
21
30
|
@order = 0
|
22
31
|
merge_with_options!(options)
|
23
32
|
end
|
24
33
|
|
34
|
+
# Returns an instance of Pendragon::Matcherthat is associated with the route
|
35
|
+
# @return [Pendragon::Matcher]
|
25
36
|
def matcher
|
26
37
|
@matcher ||= Matcher.new(@path, :capture => @capture,
|
27
38
|
:default_values => options[:default_values])
|
28
39
|
end
|
29
40
|
|
41
|
+
# Returns arity of route block
|
42
|
+
# @return [Fixnum]
|
30
43
|
def arity
|
31
44
|
@block.arity
|
32
45
|
end
|
33
46
|
|
47
|
+
# Calls the route block with arguments
|
48
|
+
# @param [Array] args The arguments are passed to the route block
|
34
49
|
def call(*args)
|
35
50
|
@block.call(*args)
|
36
51
|
end
|
37
52
|
|
53
|
+
# Matches a pattern with the route matcher
|
54
|
+
# @param [String] pattern The pattern will be matched with route matcher
|
55
|
+
# @return (see Pendragon::Matcher#match)
|
38
56
|
def match(pattern)
|
39
57
|
matcher.match(pattern)
|
40
58
|
end
|
41
59
|
|
60
|
+
# Associates the block with the route, and increments current order of the router
|
61
|
+
# @yield The route block
|
42
62
|
def to(&block)
|
43
63
|
@block = block if block_given?
|
44
64
|
@order = @router.current
|
45
65
|
@router.increment_order!
|
46
66
|
end
|
47
67
|
|
68
|
+
# Expands a path using parameters
|
69
|
+
# @param [Array] args
|
70
|
+
# @example
|
71
|
+
# pendragon = Pendragon.new
|
72
|
+
# route = pendragon.get("/category/:name"){}
|
73
|
+
# route.path(name: "Doraemon") #=> "/category/Doraemon"
|
74
|
+
# route.path(name: "Doraemon", hey: "Hey") #=> "/category/Doraemon?hey=Hey"
|
75
|
+
# @return [String] The expanded path
|
48
76
|
def path(*args)
|
49
77
|
return @path if args.empty?
|
50
78
|
params = args[0]
|
@@ -52,21 +80,28 @@ module Pendragon
|
|
52
80
|
matcher.expand(params) if matcher.mustermann?
|
53
81
|
end
|
54
82
|
|
83
|
+
# Matches a pattern with the route matcher, and then returns the route params
|
84
|
+
# @param [String] pattern The pattern will be matched with the matcher
|
85
|
+
# @param [Hash] parameters The parameters are base of the route params
|
86
|
+
# @example
|
87
|
+
# pendragon = Pendragon.new
|
88
|
+
# route = pendragon.get("/category/:name"){}
|
89
|
+
# route.params("/category/Doraemon") #=> {:name=>"Doraemon"}
|
90
|
+
# route.params("/category/Doraemon", hey: "Hey") #=> {:name=>"Doraemon", :hey=>"Hey"}
|
91
|
+
# @return [Hash] The params for use in routing engines
|
55
92
|
def params(pattern, parameters = {})
|
56
|
-
match_data, params = match(pattern),
|
93
|
+
match_data, params = match(pattern), indifferent_hash
|
57
94
|
if match_data.names.empty?
|
58
95
|
params.merge!(:captures => match_data.captures) unless match_data.captures.empty?
|
59
96
|
params
|
60
97
|
else
|
61
|
-
|
62
|
-
|
98
|
+
params_from_matcher = matcher.handler.params(pattern, :captures => match_data)
|
99
|
+
params.merge!(params_from_matcher) if params_from_matcher
|
100
|
+
params.merge(parameters){|key, old, new| old || new }
|
63
101
|
end
|
64
102
|
end
|
65
103
|
|
66
|
-
|
67
|
-
parameters.inject({}){|result, (key, val)| result[key.to_sym] = val; result }
|
68
|
-
end
|
69
|
-
|
104
|
+
# @!visibility private
|
70
105
|
def merge_with_options!(options)
|
71
106
|
@options = {} unless @options
|
72
107
|
options.each_pair do |key, value|
|
@@ -74,10 +109,16 @@ module Pendragon
|
|
74
109
|
end
|
75
110
|
end
|
76
111
|
|
112
|
+
# @!visibility private
|
77
113
|
def accessor?(key)
|
78
114
|
respond_to?("#{key}=") && respond_to?(key)
|
79
115
|
end
|
80
116
|
|
81
|
-
|
117
|
+
# @!visibility private
|
118
|
+
def indifferent_hash
|
119
|
+
Hash.new{|hash, key| hash[key.to_s] if key.instance_of?(Symbol) }
|
120
|
+
end
|
121
|
+
|
122
|
+
private :merge_with_options!, :accessor?, :indifferent_hash
|
82
123
|
end
|
83
124
|
end
|
data/lib/pendragon/router.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'pendragon/route'
|
2
2
|
require 'pendragon/matcher'
|
3
|
-
require 'pendragon/
|
3
|
+
require 'pendragon/error'
|
4
4
|
require 'pendragon/configuration'
|
5
5
|
require 'pendragon/engine/compiler'
|
6
6
|
require 'rack'
|
7
7
|
|
8
8
|
module Pendragon
|
9
|
+
# A class for the router
|
10
|
+
#
|
11
|
+
# @example Construct with a block which has no argument
|
12
|
+
# router = Pendragon do
|
13
|
+
# get("/"){ "hello world" }
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# @example Construct with a block which has an argument
|
17
|
+
# router = Pendragon.new do |config|
|
18
|
+
# config.enable_compiler = true
|
19
|
+
# end
|
9
20
|
class Router
|
10
|
-
|
11
21
|
# The accessors are useful to access from Pendragon::Route
|
12
22
|
attr_accessor :current, :routes
|
13
23
|
|
@@ -47,6 +57,10 @@ module Pendragon
|
|
47
57
|
$!.call
|
48
58
|
end
|
49
59
|
|
60
|
+
# Calls a route, and build return value of the router
|
61
|
+
# @param [Pendragon::Route] route The route matched with the condition of request
|
62
|
+
# @param [Hash] params The params will be passed with the route
|
63
|
+
# @return [Array<Fixnum, Hash, Array>] The return value of the route block
|
50
64
|
def invoke(route, params)
|
51
65
|
response = route.arity != 0 ? route.call(params) : route.call
|
52
66
|
return response unless configuration.auto_rack_format?
|
@@ -110,10 +124,10 @@ module Pendragon
|
|
110
124
|
# @return [Array]
|
111
125
|
def recognize_path(path_info)
|
112
126
|
route, params = recognize(Rack::MockRequest.env_for(path_info)).first
|
113
|
-
[route.name, params]
|
127
|
+
[route.name, params.inject({}){|hash, (key, value)| hash[key.to_sym] = value; hash }]
|
114
128
|
end
|
115
129
|
|
116
|
-
# Returns
|
130
|
+
# Returns an expanded path matched with the conditions as arguments
|
117
131
|
# @return [String, Regexp]
|
118
132
|
# @example
|
119
133
|
# router = Pendragon.new
|
@@ -126,12 +140,12 @@ module Pendragon
|
|
126
140
|
end
|
127
141
|
end
|
128
142
|
|
143
|
+
# Returns Pendragon configuration
|
144
|
+
# @return [Pendragon::Configuration]
|
129
145
|
def configuration
|
130
146
|
@configuration || Pendragon.configuration
|
131
147
|
end
|
132
148
|
|
133
|
-
private
|
134
|
-
|
135
149
|
# @!visibility private
|
136
150
|
# @example
|
137
151
|
# extract_with_name(:index) do |route, params|
|
@@ -146,8 +160,8 @@ module Pendragon
|
|
146
160
|
if !args.empty? and matcher.mustermann?
|
147
161
|
matcher_names = matcher.names
|
148
162
|
params_for_expand = Hash[matcher_names.map{|matcher_name|
|
149
|
-
[matcher_name.to_sym, (params[matcher_name
|
150
|
-
params_for_expand.merge!(Hash[params.select{|k, v| !matcher_names.include?(name
|
163
|
+
[matcher_name.to_sym, (params[matcher_name] || args.shift)]}]
|
164
|
+
params_for_expand.merge!(Hash[params.select{|k, v| !matcher_names.include?(name) }])
|
151
165
|
args = saved_args.dup
|
152
166
|
else
|
153
167
|
params_for_expand = params.dup
|
@@ -156,5 +170,7 @@ module Pendragon
|
|
156
170
|
end
|
157
171
|
raise InvalidRouteException
|
158
172
|
end
|
173
|
+
|
174
|
+
private :extract_with_name
|
159
175
|
end
|
160
176
|
end
|
data/lib/pendragon/version.rb
CHANGED
data/lib/pendragon.rb
CHANGED
@@ -3,7 +3,7 @@ require 'pendragon/router'
|
|
3
3
|
module Pendragon
|
4
4
|
|
5
5
|
# Allow the verbs of these.
|
6
|
-
HTTP_VERBS = [
|
6
|
+
HTTP_VERBS = %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK].freeze
|
7
7
|
|
8
8
|
class << self
|
9
9
|
# A new instance of Pendragon::Router
|
@@ -38,8 +38,7 @@ module Pendragon
|
|
38
38
|
@configuration = nil
|
39
39
|
end
|
40
40
|
|
41
|
-
private
|
42
|
-
|
41
|
+
# @!visibility private
|
43
42
|
def configuration_warning(method)
|
44
43
|
warn <<-WARN
|
45
44
|
Pendragon.#{method} is deprecated because it isn't thread-safe.
|
@@ -50,5 +49,7 @@ Pendragon.new do |config|
|
|
50
49
|
end
|
51
50
|
WARN
|
52
51
|
end
|
52
|
+
|
53
|
+
private :configuration_warning
|
53
54
|
end
|
54
55
|
end
|
data/pendragon.gemspec
CHANGED
@@ -16,5 +16,5 @@ Gem::Specification.new "pendragon", Pendragon::VERSION do |s|
|
|
16
16
|
s.add_development_dependency "rack-test", ">= 0.5.0"
|
17
17
|
s.add_development_dependency "mocha", ">= 0.10.0"
|
18
18
|
s.add_development_dependency "haml"
|
19
|
-
s.add_development_dependency "padrino
|
19
|
+
s.add_development_dependency "padrino", "~> 0.12.2"
|
20
20
|
end
|
data/test/helper.rb
CHANGED
data/test/padrino_test.rb
CHANGED
@@ -6,7 +6,6 @@ class FooError < RuntimeError; end
|
|
6
6
|
|
7
7
|
describe "Pendragon::Padrino" do
|
8
8
|
setup do
|
9
|
-
Padrino::Application.send(:register, Padrino::Rendering)
|
10
9
|
Padrino::Application.send(:register, Pendragon::Padrino)
|
11
10
|
Padrino::Rendering::DEFAULT_RENDERING_OPTIONS[:strict_format] = false
|
12
11
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pendragon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- namusyaka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -95,19 +95,19 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name: padrino
|
98
|
+
name: padrino
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ~>
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.12.
|
103
|
+
version: 0.12.2
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ~>
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.12.
|
110
|
+
version: 0.12.2
|
111
111
|
description: Provides an HTTP router for use in Rack and Padrino.
|
112
112
|
email: namusyaka@gmail.com
|
113
113
|
executables: []
|
@@ -124,7 +124,7 @@ files:
|
|
124
124
|
- lib/pendragon/configuration.rb
|
125
125
|
- lib/pendragon/engine/compiler.rb
|
126
126
|
- lib/pendragon/engine/recognizer.rb
|
127
|
-
- lib/pendragon/
|
127
|
+
- lib/pendragon/error.rb
|
128
128
|
- lib/pendragon/matcher.rb
|
129
129
|
- lib/pendragon/padrino.rb
|
130
130
|
- lib/pendragon/padrino/ext/class_methods.rb
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Pendragon
|
2
|
-
class ErrorHandler < StandardError
|
3
|
-
def call
|
4
|
-
response = []
|
5
|
-
response << (settings[:status] || default_response[0])
|
6
|
-
response << (settings[:headers] || default_response[1])
|
7
|
-
response << Array(settings[:body] || default_response[2])
|
8
|
-
end
|
9
|
-
|
10
|
-
def settings
|
11
|
-
self.class.settings
|
12
|
-
end
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def set(key, value)
|
16
|
-
settings[key] = value
|
17
|
-
end
|
18
|
-
|
19
|
-
def settings
|
20
|
-
@settings ||= {}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def default_response
|
27
|
-
@default_response ||= [404, {'Content-Type' => 'text/html'}, ["Not Found"]]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
NotFound = Class.new(ErrorHandler)
|
32
|
-
InvalidRouteException = Class.new(ArgumentError)
|
33
|
-
|
34
|
-
class MethodNotAllowed < ErrorHandler
|
35
|
-
set :status, 405
|
36
|
-
set :body, "Method Not Allowed"
|
37
|
-
|
38
|
-
def initialize(verbs)
|
39
|
-
default_response[1].merge!("Allow" => verbs.map{|verb| verb.upcase } * ", ")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class BadRequest < ErrorHandler
|
44
|
-
set :status, 400
|
45
|
-
set :body, "Bad Request"
|
46
|
-
end
|
47
|
-
end
|