actionpack 4.2.8 → 5.2.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (166) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +285 -444
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller.rb +12 -5
  6. data/lib/abstract_controller/asset_paths.rb +2 -0
  7. data/lib/abstract_controller/base.rb +45 -49
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
  10. data/lib/abstract_controller/callbacks.rb +47 -31
  11. data/lib/abstract_controller/collector.rb +8 -11
  12. data/lib/abstract_controller/error.rb +6 -0
  13. data/lib/abstract_controller/helpers.rb +25 -25
  14. data/lib/abstract_controller/logger.rb +2 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
  16. data/lib/abstract_controller/rendering.rb +42 -41
  17. data/lib/abstract_controller/translation.rb +10 -7
  18. data/lib/abstract_controller/url_for.rb +2 -0
  19. data/lib/action_controller.rb +29 -21
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/api/api_rendering.rb +16 -0
  22. data/lib/action_controller/base.rb +27 -19
  23. data/lib/action_controller/caching.rb +14 -57
  24. data/lib/action_controller/form_builder.rb +50 -0
  25. data/lib/action_controller/log_subscriber.rb +10 -15
  26. data/lib/action_controller/metal.rb +98 -83
  27. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  28. data/lib/action_controller/metal/conditional_get.rb +118 -44
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +3 -3
  31. data/lib/action_controller/metal/data_streaming.rb +27 -46
  32. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
  34. data/lib/action_controller/metal/exceptions.rb +8 -14
  35. data/lib/action_controller/metal/flash.rb +4 -3
  36. data/lib/action_controller/metal/force_ssl.rb +23 -21
  37. data/lib/action_controller/metal/head.rb +21 -19
  38. data/lib/action_controller/metal/helpers.rb +24 -14
  39. data/lib/action_controller/metal/http_authentication.rb +64 -57
  40. data/lib/action_controller/metal/implicit_render.rb +62 -8
  41. data/lib/action_controller/metal/instrumentation.rb +19 -21
  42. data/lib/action_controller/metal/live.rb +90 -106
  43. data/lib/action_controller/metal/mime_responds.rb +33 -46
  44. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  45. data/lib/action_controller/metal/params_wrapper.rb +61 -53
  46. data/lib/action_controller/metal/redirecting.rb +49 -28
  47. data/lib/action_controller/metal/renderers.rb +87 -44
  48. data/lib/action_controller/metal/rendering.rb +72 -50
  49. data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
  50. data/lib/action_controller/metal/rescue.rb +9 -16
  51. data/lib/action_controller/metal/streaming.rb +12 -10
  52. data/lib/action_controller/metal/strong_parameters.rb +582 -165
  53. data/lib/action_controller/metal/testing.rb +2 -17
  54. data/lib/action_controller/metal/url_for.rb +19 -10
  55. data/lib/action_controller/railtie.rb +28 -10
  56. data/lib/action_controller/railties/helpers.rb +2 -0
  57. data/lib/action_controller/renderer.rb +117 -0
  58. data/lib/action_controller/template_assertions.rb +11 -0
  59. data/lib/action_controller/test_case.rb +280 -411
  60. data/lib/action_dispatch.rb +27 -19
  61. data/lib/action_dispatch/http/cache.rb +93 -47
  62. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  63. data/lib/action_dispatch/http/filter_parameters.rb +26 -20
  64. data/lib/action_dispatch/http/filter_redirect.rb +10 -11
  65. data/lib/action_dispatch/http/headers.rb +55 -22
  66. data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
  67. data/lib/action_dispatch/http/mime_type.rb +134 -121
  68. data/lib/action_dispatch/http/mime_types.rb +20 -6
  69. data/lib/action_dispatch/http/parameter_filter.rb +25 -11
  70. data/lib/action_dispatch/http/parameters.rb +98 -39
  71. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  72. data/lib/action_dispatch/http/request.rb +200 -118
  73. data/lib/action_dispatch/http/response.rb +225 -110
  74. data/lib/action_dispatch/http/upload.rb +12 -6
  75. data/lib/action_dispatch/http/url.rb +110 -28
  76. data/lib/action_dispatch/journey.rb +7 -5
  77. data/lib/action_dispatch/journey/formatter.rb +55 -32
  78. data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
  79. data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
  80. data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
  81. data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
  82. data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
  83. data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
  84. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
  85. data/lib/action_dispatch/journey/nodes/node.rb +18 -6
  86. data/lib/action_dispatch/journey/parser.rb +23 -22
  87. data/lib/action_dispatch/journey/parser.y +3 -2
  88. data/lib/action_dispatch/journey/parser_extras.rb +12 -4
  89. data/lib/action_dispatch/journey/path/pattern.rb +50 -44
  90. data/lib/action_dispatch/journey/route.rb +106 -28
  91. data/lib/action_dispatch/journey/router.rb +35 -23
  92. data/lib/action_dispatch/journey/router/utils.rb +20 -11
  93. data/lib/action_dispatch/journey/routes.rb +18 -16
  94. data/lib/action_dispatch/journey/scanner.rb +18 -15
  95. data/lib/action_dispatch/journey/visitors.rb +99 -52
  96. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  97. data/lib/action_dispatch/middleware/cookies.rb +304 -193
  98. data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
  99. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  100. data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
  101. data/lib/action_dispatch/middleware/executor.rb +21 -0
  102. data/lib/action_dispatch/middleware/flash.rb +78 -54
  103. data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
  104. data/lib/action_dispatch/middleware/reloader.rb +5 -91
  105. data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
  106. data/lib/action_dispatch/middleware/request_id.rb +17 -9
  107. data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
  108. data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
  109. data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
  110. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
  111. data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
  112. data/lib/action_dispatch/middleware/ssl.rb +114 -36
  113. data/lib/action_dispatch/middleware/stack.rb +31 -44
  114. data/lib/action_dispatch/middleware/static.rb +57 -50
  115. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  116. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
  125. data/lib/action_dispatch/railtie.rb +19 -11
  126. data/lib/action_dispatch/request/session.rb +106 -59
  127. data/lib/action_dispatch/request/utils.rb +67 -24
  128. data/lib/action_dispatch/routing.rb +17 -18
  129. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  130. data/lib/action_dispatch/routing/inspector.rb +58 -67
  131. data/lib/action_dispatch/routing/mapper.rb +734 -447
  132. data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
  133. data/lib/action_dispatch/routing/redirection.rb +36 -26
  134. data/lib/action_dispatch/routing/route_set.rb +321 -291
  135. data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
  136. data/lib/action_dispatch/routing/url_for.rb +65 -25
  137. data/lib/action_dispatch/system_test_case.rb +147 -0
  138. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  139. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  140. data/lib/action_dispatch/system_testing/server.rb +31 -0
  141. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  143. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  144. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  145. data/lib/action_dispatch/testing/assertions.rb +6 -4
  146. data/lib/action_dispatch/testing/assertions/response.rb +45 -20
  147. data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
  148. data/lib/action_dispatch/testing/integration.rb +347 -209
  149. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  150. data/lib/action_dispatch/testing/test_process.rb +28 -22
  151. data/lib/action_dispatch/testing/test_request.rb +27 -34
  152. data/lib/action_dispatch/testing/test_response.rb +35 -7
  153. data/lib/action_pack.rb +4 -2
  154. data/lib/action_pack/gem_version.rb +5 -3
  155. data/lib/action_pack/version.rb +3 -1
  156. metadata +56 -39
  157. data/lib/action_controller/metal/hide_actions.rb +0 -40
  158. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  159. data/lib/action_controller/middleware.rb +0 -39
  160. data/lib/action_controller/model_naming.rb +0 -12
  161. data/lib/action_dispatch/journey/backwards.rb +0 -5
  162. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  163. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  164. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  165. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  166. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -30,7 +30,7 @@ rule
30
30
  | dot
31
31
  ;
32
32
  slash
33
- : SLASH { Slash.new('/') }
33
+ : SLASH { Slash.new(val.first) }
34
34
  ;
35
35
  symbol
36
36
  : SYMBOL { Symbol.new(val.first) }
@@ -45,5 +45,6 @@ rule
45
45
  end
46
46
 
47
47
  ---- header
48
+ # :stopdoc:
48
49
 
49
- require 'action_dispatch/journey/parser_extras'
50
+ require "action_dispatch/journey/parser_extras"
@@ -1,11 +1,18 @@
1
- require 'action_dispatch/journey/scanner'
2
- require 'action_dispatch/journey/nodes/node'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/journey/scanner"
4
+ require "action_dispatch/journey/nodes/node"
3
5
 
4
6
  module ActionDispatch
5
- module Journey # :nodoc:
6
- class Parser < Racc::Parser # :nodoc:
7
+ # :stopdoc:
8
+ module Journey
9
+ class Parser < Racc::Parser
7
10
  include Journey::Nodes
8
11
 
12
+ def self.parse(string)
13
+ new.parse string
14
+ end
15
+
9
16
  def initialize
10
17
  @scanner = Scanner.new
11
18
  end
@@ -20,4 +27,5 @@ module ActionDispatch
20
27
  end
21
28
  end
22
29
  end
30
+ # :startdoc:
23
31
  end
@@ -1,4 +1,4 @@
1
- require 'action_dispatch/journey/router/strexp'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActionDispatch
4
4
  module Journey # :nodoc:
@@ -6,15 +6,21 @@ module ActionDispatch
6
6
  class Pattern # :nodoc:
7
7
  attr_reader :spec, :requirements, :anchored
8
8
 
9
- def self.from_string string
10
- new Journey::Router::Strexp.build(string, {}, ["/.?"], true)
9
+ def self.from_string(string)
10
+ build(string, {}, "/.?", true)
11
11
  end
12
12
 
13
- def initialize(strexp)
14
- @spec = strexp.ast
15
- @requirements = strexp.requirements
16
- @separators = strexp.separators.join
17
- @anchored = strexp.anchor
13
+ def self.build(path, requirements, separators, anchored)
14
+ parser = Journey::Parser.new
15
+ ast = parser.parse path
16
+ new ast, requirements, separators, anchored
17
+ end
18
+
19
+ def initialize(ast, requirements, separators, anchored)
20
+ @spec = ast
21
+ @requirements = requirements
22
+ @separators = separators
23
+ @anchored = anchored
18
24
 
19
25
  @names = nil
20
26
  @optional_names = nil
@@ -27,13 +33,20 @@ module ActionDispatch
27
33
  Visitors::FormatBuilder.new.accept(spec)
28
34
  end
29
35
 
36
+ def eager_load!
37
+ required_names
38
+ offsets
39
+ to_regexp
40
+ nil
41
+ end
42
+
30
43
  def ast
31
- @spec.grep(Nodes::Symbol).each do |node|
44
+ @spec.find_all(&:symbol?).each do |node|
32
45
  re = @requirements[node.to_sym]
33
46
  node.regexp = re if re
34
47
  end
35
48
 
36
- @spec.grep(Nodes::Star).each do |node|
49
+ @spec.find_all(&:star?).each do |node|
37
50
  node = node.left
38
51
  node.regexp = @requirements[node.to_sym] || /(.+)/
39
52
  end
@@ -42,7 +55,7 @@ module ActionDispatch
42
55
  end
43
56
 
44
57
  def names
45
- @names ||= spec.grep(Nodes::Symbol).map { |n| n.name }
58
+ @names ||= spec.find_all(&:symbol?).map(&:name)
46
59
  end
47
60
 
48
61
  def required_names
@@ -50,34 +63,9 @@ module ActionDispatch
50
63
  end
51
64
 
52
65
  def optional_names
53
- @optional_names ||= spec.grep(Nodes::Group).flat_map { |group|
54
- group.grep(Nodes::Symbol)
55
- }.map { |n| n.name }.uniq
56
- end
57
-
58
- class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
59
- attr_reader :offsets
60
-
61
- def initialize(matchers)
62
- @matchers = matchers
63
- @capture_count = [0]
64
- end
65
-
66
- def visit(node)
67
- super
68
- @capture_count
69
- end
70
-
71
- def visit_SYMBOL(node)
72
- node = node.to_sym
73
-
74
- if @matchers.key?(node)
75
- re = /#{@matchers[node]}|/
76
- @capture_count.push((re.match('').length - 1) + (@capture_count.last || 0))
77
- else
78
- @capture_count << (@capture_count.last || 0)
79
- end
80
- end
66
+ @optional_names ||= spec.find_all(&:group?).flat_map { |group|
67
+ group.find_all(&:symbol?)
68
+ }.map(&:name).uniq
81
69
  end
82
70
 
83
71
  class AnchoredRegexp < Journey::Visitors::Visitor # :nodoc:
@@ -119,14 +107,20 @@ module ActionDispatch
119
107
  end
120
108
 
121
109
  def visit_STAR(node)
122
- re = @matchers[node.left.to_sym] || '.+'
110
+ re = @matchers[node.left.to_sym] || ".+"
123
111
  "(#{re})"
124
112
  end
113
+
114
+ def visit_OR(node)
115
+ children = node.children.map { |n| visit n }
116
+ "(?:#{children.join(?|)})"
117
+ end
125
118
  end
126
119
 
127
120
  class UnanchoredRegexp < AnchoredRegexp # :nodoc:
128
121
  def accept(node)
129
- %r{\A#{visit node}}
122
+ path = visit node
123
+ path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
130
124
  end
131
125
  end
132
126
 
@@ -140,7 +134,7 @@ module ActionDispatch
140
134
  end
141
135
 
142
136
  def captures
143
- (length - 1).times.map { |i| self[i + 1] }
137
+ Array.new(length - 1) { |i| self[i + 1] }
144
138
  end
145
139
 
146
140
  def [](x)
@@ -184,8 +178,20 @@ module ActionDispatch
184
178
  def offsets
185
179
  return @offsets if @offsets
186
180
 
187
- viz = RegexpOffsets.new(@requirements)
188
- @offsets = viz.accept(spec)
181
+ @offsets = [0]
182
+
183
+ spec.find_all(&:symbol?).each do |node|
184
+ node = node.to_sym
185
+
186
+ if @requirements.key?(node)
187
+ re = /#{@requirements[node]}|/
188
+ @offsets.push((re.match("").length - 1) + @offsets.last)
189
+ else
190
+ @offsets << @offsets.last
191
+ end
192
+ end
193
+
194
+ @offsets
189
195
  end
190
196
  end
191
197
  end
@@ -1,42 +1,106 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionDispatch
2
- module Journey # :nodoc:
3
- class Route # :nodoc:
4
- attr_reader :app, :path, :defaults, :name
4
+ # :stopdoc:
5
+ module Journey
6
+ class Route
7
+ attr_reader :app, :path, :defaults, :name, :precedence
5
8
 
6
- attr_reader :constraints
9
+ attr_reader :constraints, :internal
7
10
  alias :conditions :constraints
8
11
 
9
- attr_accessor :precedence
12
+ module VerbMatchers
13
+ VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
14
+ VERBS.each do |v|
15
+ class_eval <<-eoc, __FILE__, __LINE__ + 1
16
+ class #{v}
17
+ def self.verb; name.split("::").last; end
18
+ def self.call(req); req.#{v.downcase}?; end
19
+ end
20
+ eoc
21
+ end
22
+
23
+ class Unknown
24
+ attr_reader :verb
25
+
26
+ def initialize(verb)
27
+ @verb = verb
28
+ end
29
+
30
+ def call(request); @verb === request.request_method; end
31
+ end
32
+
33
+ class All
34
+ def self.call(_); true; end
35
+ def self.verb; ""; end
36
+ end
37
+
38
+ VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash|
39
+ klass = const_get verb
40
+ hash[verb] = klass
41
+ hash[verb.downcase] = klass
42
+ hash[verb.downcase.to_sym] = klass
43
+ end
44
+ end
45
+
46
+ def self.verb_matcher(verb)
47
+ VerbMatchers::VERB_TO_CLASS.fetch(verb) do
48
+ VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
49
+ end
50
+ end
51
+
52
+ def self.build(name, app, path, constraints, required_defaults, defaults)
53
+ request_method_match = verb_matcher(constraints.delete(:request_method))
54
+ new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
55
+ end
10
56
 
11
57
  ##
12
58
  # +path+ is a path constraint.
13
59
  # +constraints+ is a hash of constraints to be applied to this route.
14
- def initialize(name, app, path, constraints, defaults = {})
60
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
15
61
  @name = name
16
62
  @app = app
17
63
  @path = path
18
64
 
65
+ @request_method_match = request_method_match
19
66
  @constraints = constraints
20
67
  @defaults = defaults
21
68
  @required_defaults = nil
69
+ @_required_defaults = required_defaults
22
70
  @required_parts = nil
23
71
  @parts = nil
24
72
  @decorated_ast = nil
25
- @precedence = 0
73
+ @precedence = precedence
26
74
  @path_formatter = @path.build_formatter
75
+ @internal = internal
76
+ end
77
+
78
+ def eager_load!
79
+ path.eager_load!
80
+ ast
81
+ parts
82
+ required_defaults
83
+ nil
27
84
  end
28
85
 
29
86
  def ast
30
87
  @decorated_ast ||= begin
31
88
  decorated_ast = path.ast
32
- decorated_ast.grep(Nodes::Terminal).each { |n| n.memo = self }
89
+ decorated_ast.find_all(&:terminal?).each { |n| n.memo = self }
33
90
  decorated_ast
34
91
  end
35
92
  end
36
93
 
37
- def requirements # :nodoc:
38
- # needed for rails `rake routes`
39
- @defaults.merge(path.requirements).delete_if { |_,v|
94
+ # Needed for `rails routes`. Picks up succinctly defined requirements
95
+ # for a route, for example route
96
+ #
97
+ # get 'photo/:id', :controller => 'photos', :action => 'show',
98
+ # :id => /[A-Z]\d{5}/
99
+ #
100
+ # will have {:controller=>"photos", :action=>"show", :id=>/[A-Z]\d{5}/}
101
+ # as requirements.
102
+ def requirements
103
+ @defaults.merge(path.requirements).delete_if { |_, v|
40
104
  /.+?/ == v
41
105
  }
42
106
  end
@@ -49,18 +113,23 @@ module ActionDispatch
49
113
  required_parts + required_defaults.keys
50
114
  end
51
115
 
52
- def score(constraints)
116
+ def score(supplied_keys)
53
117
  required_keys = path.required_names
54
- supplied_keys = constraints.map { |k,v| v && k.to_s }.compact
55
118
 
56
- return -1 unless (required_keys - supplied_keys).empty?
119
+ required_keys.each do |k|
120
+ return -1 unless supplied_keys.include?(k)
121
+ end
122
+
123
+ score = 0
124
+ path.names.each do |k|
125
+ score += 1 if supplied_keys.include?(k)
126
+ end
57
127
 
58
- score = (supplied_keys & path.names).length
59
128
  score + (required_defaults.length * 2)
60
129
  end
61
130
 
62
131
  def parts
63
- @parts ||= segments.map { |n| n.to_sym }
132
+ @parts ||= segments.map(&:to_sym)
64
133
  end
65
134
  alias :segment_keys :parts
66
135
 
@@ -68,20 +137,16 @@ module ActionDispatch
68
137
  @path_formatter.evaluate path_options
69
138
  end
70
139
 
71
- def optional_parts
72
- path.optional_names.map { |n| n.to_sym }
73
- end
74
-
75
140
  def required_parts
76
- @required_parts ||= path.required_names.map { |n| n.to_sym }
141
+ @required_parts ||= path.required_names.map(&:to_sym)
77
142
  end
78
143
 
79
144
  def required_default?(key)
80
- (constraints[:required_defaults] || []).include?(key)
145
+ @_required_defaults.include?(key)
81
146
  end
82
147
 
83
148
  def required_defaults
84
- @required_defaults ||= @defaults.dup.delete_if do |k,_|
149
+ @required_defaults ||= @defaults.dup.delete_if do |k, _|
85
150
  parts.include?(k) || !required_default?(k)
86
151
  end
87
152
  end
@@ -95,9 +160,8 @@ module ActionDispatch
95
160
  end
96
161
 
97
162
  def matches?(request)
98
- constraints.all? do |method, value|
99
- next true unless request.respond_to?(method)
100
-
163
+ match_verb(request) &&
164
+ constraints.all? { |method, value|
101
165
  case value
102
166
  when Regexp, String
103
167
  value === request.send(method).to_s
@@ -110,16 +174,30 @@ module ActionDispatch
110
174
  else
111
175
  value === request.send(method)
112
176
  end
113
- end
177
+ }
114
178
  end
115
179
 
116
180
  def ip
117
181
  constraints[:ip] || //
118
182
  end
119
183
 
184
+ def requires_matching_verb?
185
+ !@request_method_match.all? { |x| x == VerbMatchers::All }
186
+ end
187
+
120
188
  def verb
121
- constraints[:request_method] || //
189
+ verbs.join("|")
122
190
  end
191
+
192
+ private
193
+ def verbs
194
+ @request_method_match.map(&:verb)
195
+ end
196
+
197
+ def match_verb(request)
198
+ @request_method_match.any? { |m| m.call request }
199
+ end
123
200
  end
124
201
  end
202
+ # :startdoc:
125
203
  end
@@ -1,15 +1,16 @@
1
- require 'action_dispatch/journey/router/utils'
2
- require 'action_dispatch/journey/router/strexp'
3
- require 'action_dispatch/journey/routes'
4
- require 'action_dispatch/journey/formatter'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/journey/router/utils"
4
+ require "action_dispatch/journey/routes"
5
+ require "action_dispatch/journey/formatter"
5
6
 
6
7
  before = $-w
7
8
  $-w = false
8
- require 'action_dispatch/journey/parser'
9
+ require "action_dispatch/journey/parser"
9
10
  $-w = before
10
11
 
11
- require 'action_dispatch/journey/route'
12
- require 'action_dispatch/journey/path/pattern'
12
+ require "action_dispatch/journey/route"
13
+ require "action_dispatch/journey/path/pattern"
13
14
 
14
15
  module ActionDispatch
15
16
  module Journey # :nodoc:
@@ -17,15 +18,19 @@ module ActionDispatch
17
18
  class RoutingError < ::StandardError # :nodoc:
18
19
  end
19
20
 
20
- # :nodoc:
21
- VERSION = '2.0.0'
22
-
23
21
  attr_accessor :routes
24
22
 
25
23
  def initialize(routes)
26
24
  @routes = routes
27
25
  end
28
26
 
27
+ def eager_load!
28
+ # Eagerly trigger the simulator's initialization so
29
+ # it doesn't happen during a request cycle.
30
+ simulator
31
+ nil
32
+ end
33
+
29
34
  def serve(req)
30
35
  find_routes(req).each do |match, parameters, route|
31
36
  set_params = req.path_parameters
@@ -33,16 +38,20 @@ module ActionDispatch
33
38
  script_name = req.script_name
34
39
 
35
40
  unless route.path.anchored
36
- req.script_name = (script_name.to_s + match.to_s).chomp('/')
41
+ req.script_name = (script_name.to_s + match.to_s).chomp("/")
37
42
  req.path_info = match.post_match
38
43
  req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
39
44
  end
40
45
 
46
+ parameters = route.defaults.merge parameters.transform_values { |val|
47
+ val.dup.force_encoding(::Encoding::UTF_8)
48
+ }
49
+
41
50
  req.path_parameters = set_params.merge parameters
42
51
 
43
52
  status, headers, body = route.app.serve(req)
44
53
 
45
- if 'pass' == headers['X-Cascade']
54
+ if "pass" == headers["X-Cascade"]
46
55
  req.script_name = script_name
47
56
  req.path_info = path_info
48
57
  req.path_parameters = set_params
@@ -52,7 +61,7 @@ module ActionDispatch
52
61
  return [status, headers, body]
53
62
  end
54
63
 
55
- return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
64
+ [404, { "X-Cascade" => "pass" }, ["Not Found"]]
56
65
  end
57
66
 
58
67
  def recognize(rails_req)
@@ -62,21 +71,24 @@ module ActionDispatch
62
71
  rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
63
72
  end
64
73
 
74
+ parameters = route.defaults.merge parameters
65
75
  yield(route, parameters)
66
76
  end
67
77
  end
68
78
 
69
79
  def visualizer
70
80
  tt = GTG::Builder.new(ast).transition_table
71
- groups = partitioned_routes.first.map(&:ast).group_by { |a| a.to_s }
72
- asts = groups.values.map { |v| v.first }
81
+ groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
82
+ asts = groups.values.map(&:first)
73
83
  tt.visualizer(asts)
74
84
  end
75
85
 
76
86
  private
77
87
 
78
88
  def partitioned_routes
79
- routes.partitioned_routes
89
+ routes.partition { |r|
90
+ r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? }
91
+ }
80
92
  end
81
93
 
82
94
  def ast
@@ -88,7 +100,7 @@ module ActionDispatch
88
100
  end
89
101
 
90
102
  def custom_routes
91
- partitioned_routes.last
103
+ routes.custom_routes
92
104
  end
93
105
 
94
106
  def filter_routes(path)
@@ -96,13 +108,13 @@ module ActionDispatch
96
108
  simulator.memos(path) { [] }
97
109
  end
98
110
 
99
- def find_routes req
111
+ def find_routes(req)
100
112
  routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
101
113
  r.path.match(req.path_info)
102
114
  }
103
115
 
104
116
  routes =
105
- if req.request_method == "HEAD"
117
+ if req.head?
106
118
  match_head_routes(routes, req)
107
119
  else
108
120
  match_routes(routes, req)
@@ -111,9 +123,9 @@ module ActionDispatch
111
123
  routes.sort_by!(&:precedence)
112
124
 
113
125
  routes.map! { |r|
114
- match_data = r.path.match(req.path_info)
115
- path_parameters = r.defaults.dup
116
- match_data.names.zip(match_data.captures) { |name,val|
126
+ match_data = r.path.match(req.path_info)
127
+ path_parameters = {}
128
+ match_data.names.zip(match_data.captures) { |name, val|
117
129
  path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
118
130
  }
119
131
  [match_data, path_parameters, r]
@@ -121,7 +133,7 @@ module ActionDispatch
121
133
  end
122
134
 
123
135
  def match_head_routes(routes, req)
124
- verb_specific_routes = routes.reject { |route| route.verb == // }
136
+ verb_specific_routes = routes.select(&:requires_matching_verb?)
125
137
  head_routes = match_routes(verb_specific_routes, req)
126
138
 
127
139
  if head_routes.empty?