actionpack 4.2.11.1 → 5.2.6

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 +4 -4
  2. data/CHANGELOG.md +328 -458
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +2 -0
  6. data/lib/abstract_controller/base.rb +45 -49
  7. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +47 -31
  10. data/lib/abstract_controller/collector.rb +8 -11
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +25 -25
  13. data/lib/abstract_controller/logger.rb +2 -0
  14. data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
  15. data/lib/abstract_controller/rendering.rb +42 -41
  16. data/lib/abstract_controller/translation.rb +10 -7
  17. data/lib/abstract_controller/url_for.rb +2 -0
  18. data/lib/abstract_controller.rb +12 -5
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +27 -19
  22. data/lib/action_controller/caching.rb +14 -57
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +10 -15
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +118 -44
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +27 -46
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
  32. data/lib/action_controller/metal/exceptions.rb +8 -14
  33. data/lib/action_controller/metal/flash.rb +4 -3
  34. data/lib/action_controller/metal/force_ssl.rb +23 -21
  35. data/lib/action_controller/metal/head.rb +21 -19
  36. data/lib/action_controller/metal/helpers.rb +24 -14
  37. data/lib/action_controller/metal/http_authentication.rb +65 -58
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +19 -21
  40. data/lib/action_controller/metal/live.rb +90 -106
  41. data/lib/action_controller/metal/mime_responds.rb +33 -46
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +61 -53
  44. data/lib/action_controller/metal/redirecting.rb +49 -28
  45. data/lib/action_controller/metal/renderers.rb +87 -44
  46. data/lib/action_controller/metal/rendering.rb +72 -50
  47. data/lib/action_controller/metal/request_forgery_protection.rb +284 -97
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +12 -10
  50. data/lib/action_controller/metal/strong_parameters.rb +583 -164
  51. data/lib/action_controller/metal/testing.rb +2 -17
  52. data/lib/action_controller/metal/url_for.rb +19 -10
  53. data/lib/action_controller/metal.rb +98 -83
  54. data/lib/action_controller/railtie.rb +28 -10
  55. data/lib/action_controller/railties/helpers.rb +2 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +282 -413
  59. data/lib/action_controller.rb +29 -21
  60. data/lib/action_dispatch/http/cache.rb +93 -47
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +26 -20
  63. data/lib/action_dispatch/http/filter_redirect.rb +10 -11
  64. data/lib/action_dispatch/http/headers.rb +55 -22
  65. data/lib/action_dispatch/http/mime_negotiation.rb +56 -41
  66. data/lib/action_dispatch/http/mime_type.rb +134 -121
  67. data/lib/action_dispatch/http/mime_types.rb +20 -6
  68. data/lib/action_dispatch/http/parameter_filter.rb +25 -11
  69. data/lib/action_dispatch/http/parameters.rb +98 -39
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +200 -118
  72. data/lib/action_dispatch/http/response.rb +225 -110
  73. data/lib/action_dispatch/http/upload.rb +12 -6
  74. data/lib/action_dispatch/http/url.rb +110 -28
  75. data/lib/action_dispatch/journey/formatter.rb +55 -32
  76. data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
  79. data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
  80. data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
  83. data/lib/action_dispatch/journey/nodes/node.rb +18 -6
  84. data/lib/action_dispatch/journey/parser.rb +23 -22
  85. data/lib/action_dispatch/journey/parser.y +3 -2
  86. data/lib/action_dispatch/journey/parser_extras.rb +12 -4
  87. data/lib/action_dispatch/journey/path/pattern.rb +50 -44
  88. data/lib/action_dispatch/journey/route.rb +106 -28
  89. data/lib/action_dispatch/journey/router/utils.rb +20 -11
  90. data/lib/action_dispatch/journey/router.rb +35 -23
  91. data/lib/action_dispatch/journey/routes.rb +18 -16
  92. data/lib/action_dispatch/journey/scanner.rb +18 -15
  93. data/lib/action_dispatch/journey/visitors.rb +99 -52
  94. data/lib/action_dispatch/journey.rb +7 -5
  95. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  96. data/lib/action_dispatch/middleware/cookies.rb +304 -193
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
  98. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  99. data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
  100. data/lib/action_dispatch/middleware/executor.rb +21 -0
  101. data/lib/action_dispatch/middleware/flash.rb +78 -54
  102. data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
  103. data/lib/action_dispatch/middleware/reloader.rb +5 -91
  104. data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
  105. data/lib/action_dispatch/middleware/request_id.rb +17 -9
  106. data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
  107. data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
  108. data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
  109. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
  110. data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
  111. data/lib/action_dispatch/middleware/ssl.rb +114 -36
  112. data/lib/action_dispatch/middleware/stack.rb +31 -44
  113. data/lib/action_dispatch/middleware/static.rb +57 -50
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  115. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
  124. data/lib/action_dispatch/railtie.rb +19 -11
  125. data/lib/action_dispatch/request/session.rb +106 -59
  126. data/lib/action_dispatch/request/utils.rb +67 -24
  127. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  128. data/lib/action_dispatch/routing/inspector.rb +58 -67
  129. data/lib/action_dispatch/routing/mapper.rb +733 -447
  130. data/lib/action_dispatch/routing/polymorphic_routes.rb +166 -140
  131. data/lib/action_dispatch/routing/redirection.rb +36 -26
  132. data/lib/action_dispatch/routing/route_set.rb +321 -291
  133. data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
  134. data/lib/action_dispatch/routing/url_for.rb +65 -25
  135. data/lib/action_dispatch/routing.rb +17 -18
  136. data/lib/action_dispatch/system_test_case.rb +147 -0
  137. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  138. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  139. data/lib/action_dispatch/system_testing/server.rb +31 -0
  140. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  141. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  143. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  144. data/lib/action_dispatch/testing/assertions/response.rb +45 -20
  145. data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
  146. data/lib/action_dispatch/testing/assertions.rb +6 -4
  147. data/lib/action_dispatch/testing/integration.rb +348 -209
  148. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  149. data/lib/action_dispatch/testing/test_process.rb +28 -22
  150. data/lib/action_dispatch/testing/test_request.rb +27 -34
  151. data/lib/action_dispatch/testing/test_response.rb +35 -7
  152. data/lib/action_dispatch.rb +27 -19
  153. data/lib/action_pack/gem_version.rb +5 -3
  154. data/lib/action_pack/version.rb +3 -1
  155. data/lib/action_pack.rb +4 -2
  156. metadata +56 -38
  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
@@ -1,4 +1,6 @@
1
- require 'action_dispatch/journey/nfa/dot'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/journey/nfa/dot"
2
4
 
3
5
  module ActionDispatch
4
6
  module Journey # :nodoc:
@@ -10,7 +12,7 @@ module ActionDispatch
10
12
  attr_reader :memos
11
13
 
12
14
  def initialize
13
- @table = Hash.new { |h,f| h[f] = {} }
15
+ @table = Hash.new { |h, f| h[f] = {} }
14
16
  @memos = {}
15
17
  @accepting = nil
16
18
  @inverted = nil
@@ -45,51 +47,6 @@ module ActionDispatch
45
47
  (@table.keys + @table.values.flat_map(&:keys)).uniq
46
48
  end
47
49
 
48
- # Returns a generalized transition graph with reduced states. The states
49
- # are reduced like a DFA, but the table must be simulated like an NFA.
50
- #
51
- # Edges of the GTG are regular expressions.
52
- def generalized_table
53
- gt = GTG::TransitionTable.new
54
- marked = {}
55
- state_id = Hash.new { |h,k| h[k] = h.length }
56
- alphabet = self.alphabet
57
-
58
- stack = [eclosure(0)]
59
-
60
- until stack.empty?
61
- state = stack.pop
62
- next if marked[state] || state.empty?
63
-
64
- marked[state] = true
65
-
66
- alphabet.each do |alpha|
67
- next_state = eclosure(following_states(state, alpha))
68
- next if next_state.empty?
69
-
70
- gt[state_id[state], state_id[next_state]] = alpha
71
- stack << next_state
72
- end
73
- end
74
-
75
- final_groups = state_id.keys.find_all { |s|
76
- s.sort.last == accepting
77
- }
78
-
79
- final_groups.each do |states|
80
- id = state_id[states]
81
-
82
- gt.add_accepting(id)
83
- save = states.find { |s|
84
- @memos.key?(s) && eclosure(s).sort.last == accepting
85
- }
86
-
87
- gt.add_memo(id, memo(save))
88
- end
89
-
90
- gt
91
- end
92
-
93
50
  # Returns set of NFA states to which there is a transition on ast symbol
94
51
  # +a+ from some state +s+ in +t+.
95
52
  def following_states(t, a)
@@ -107,7 +64,7 @@ module ActionDispatch
107
64
  end
108
65
 
109
66
  def alphabet
110
- inverted.values.flat_map(&:keys).compact.uniq.sort_by { |x| x.to_s }
67
+ inverted.values.flat_map(&:keys).compact.uniq.sort_by(&:to_s)
111
68
  end
112
69
 
113
70
  # Returns a set of NFA states reachable from some NFA state +s+ in set
@@ -1,4 +1,6 @@
1
- require 'action_dispatch/journey/visitors'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/journey/visitors"
2
4
 
3
5
  module ActionDispatch
4
6
  module Journey # :nodoc:
@@ -14,15 +16,15 @@ module ActionDispatch
14
16
  end
15
17
 
16
18
  def each(&block)
17
- Visitors::Each.new(block).accept(self)
19
+ Visitors::Each::INSTANCE.accept(self, block)
18
20
  end
19
21
 
20
22
  def to_s
21
- Visitors::String.new.accept(self)
23
+ Visitors::String::INSTANCE.accept(self, "")
22
24
  end
23
25
 
24
26
  def to_dot
25
- Visitors::Dot.new.accept(self)
27
+ Visitors::Dot::INSTANCE.accept(self)
26
28
  end
27
29
 
28
30
  def to_sym
@@ -30,7 +32,7 @@ module ActionDispatch
30
32
  end
31
33
 
32
34
  def name
33
- left.tr '*:', ''
35
+ left.tr "*:".freeze, "".freeze
34
36
  end
35
37
 
36
38
  def type
@@ -39,10 +41,15 @@ module ActionDispatch
39
41
 
40
42
  def symbol?; false; end
41
43
  def literal?; false; end
44
+ def terminal?; false; end
45
+ def star?; false; end
46
+ def cat?; false; end
47
+ def group?; false; end
42
48
  end
43
49
 
44
50
  class Terminal < Node # :nodoc:
45
51
  alias :symbol :left
52
+ def terminal?; true; end
46
53
  end
47
54
 
48
55
  class Literal < Terminal # :nodoc:
@@ -69,11 +76,13 @@ module ActionDispatch
69
76
  class Symbol < Terminal # :nodoc:
70
77
  attr_accessor :regexp
71
78
  alias :symbol :regexp
79
+ attr_reader :name
72
80
 
73
81
  DEFAULT_EXP = /[^\.\/\?]+/
74
82
  def initialize(left)
75
83
  super
76
84
  @regexp = DEFAULT_EXP
85
+ @name = left.tr "*:".freeze, "".freeze
77
86
  end
78
87
 
79
88
  def default_regexp?
@@ -89,13 +98,15 @@ module ActionDispatch
89
98
 
90
99
  class Group < Unary # :nodoc:
91
100
  def type; :GROUP; end
101
+ def group?; true; end
92
102
  end
93
103
 
94
104
  class Star < Unary # :nodoc:
105
+ def star?; true; end
95
106
  def type; :STAR; end
96
107
 
97
108
  def name
98
- left.name.tr '*:', ''
109
+ left.name.tr "*:", ""
99
110
  end
100
111
  end
101
112
 
@@ -111,6 +122,7 @@ module ActionDispatch
111
122
  end
112
123
 
113
124
  class Cat < Binary # :nodoc:
125
+ def cat?; true; end
114
126
  def type; :CAT; end
115
127
  end
116
128
 
@@ -1,32 +1,33 @@
1
1
  #
2
2
  # DO NOT MODIFY!!!!
3
- # This file is automatically generated by Racc 1.4.11
4
- # from Racc grammer file "".
3
+ # This file is automatically generated by Racc 1.4.14
4
+ # from Racc grammar file "".
5
5
  #
6
6
 
7
7
  require 'racc/parser.rb'
8
8
 
9
+ # :stopdoc:
9
10
 
10
- require 'action_dispatch/journey/parser_extras'
11
+ require "action_dispatch/journey/parser_extras"
11
12
  module ActionDispatch
12
13
  module Journey
13
14
  class Parser < Racc::Parser
14
15
  ##### State transition tables begin ###
15
16
 
16
17
  racc_action_table = [
17
- 13, 15, 14, 7, 21, 16, 8, 19, 13, 15,
18
- 14, 7, 17, 16, 8, 13, 15, 14, 7, 24,
19
- 16, 8, 13, 15, 14, 7, 19, 16, 8 ]
18
+ 13, 15, 14, 7, 19, 16, 8, 19, 13, 15,
19
+ 14, 7, 17, 16, 8, 13, 15, 14, 7, 21,
20
+ 16, 8, 13, 15, 14, 7, 24, 16, 8 ]
20
21
 
21
22
  racc_action_check = [
22
- 2, 2, 2, 2, 17, 2, 2, 2, 0, 0,
23
- 0, 0, 1, 0, 0, 19, 19, 19, 19, 20,
24
- 19, 19, 7, 7, 7, 7, 22, 7, 7 ]
23
+ 2, 2, 2, 2, 22, 2, 2, 2, 19, 19,
24
+ 19, 19, 1, 19, 19, 7, 7, 7, 7, 17,
25
+ 7, 7, 0, 0, 0, 0, 20, 0, 0 ]
25
26
 
26
27
  racc_action_pointer = [
27
- 6, 12, -2, nil, nil, nil, nil, 20, nil, nil,
28
- nil, nil, nil, nil, nil, nil, nil, 4, nil, 13,
29
- 13, nil, 17, nil, nil ]
28
+ 20, 12, -2, nil, nil, nil, nil, 13, nil, nil,
29
+ nil, nil, nil, nil, nil, nil, nil, 19, nil, 6,
30
+ 20, nil, -5, nil, nil ]
30
31
 
31
32
  racc_action_default = [
32
33
  -19, -19, -2, -3, -4, -5, -6, -19, -10, -11,
@@ -134,11 +135,11 @@ Racc_debug_parser = false
134
135
  # reduce 0 omitted
135
136
 
136
137
  def _reduce_1(val, _values)
137
- Cat.new(val.first, val.last)
138
+ Cat.new(val.first, val.last)
138
139
  end
139
140
 
140
141
  def _reduce_2(val, _values)
141
- val.first
142
+ val.first
142
143
  end
143
144
 
144
145
  # reduce 3 omitted
@@ -150,19 +151,19 @@ end
150
151
  # reduce 6 omitted
151
152
 
152
153
  def _reduce_7(val, _values)
153
- Group.new(val[1])
154
+ Group.new(val[1])
154
155
  end
155
156
 
156
157
  def _reduce_8(val, _values)
157
- Or.new([val.first, val.last])
158
+ Or.new([val.first, val.last])
158
159
  end
159
160
 
160
161
  def _reduce_9(val, _values)
161
- Or.new([val.first, val.last])
162
+ Or.new([val.first, val.last])
162
163
  end
163
164
 
164
165
  def _reduce_10(val, _values)
165
- Star.new(Symbol.new(val.last))
166
+ Star.new(Symbol.new(val.last))
166
167
  end
167
168
 
168
169
  # reduce 11 omitted
@@ -174,19 +175,19 @@ end
174
175
  # reduce 14 omitted
175
176
 
176
177
  def _reduce_15(val, _values)
177
- Slash.new('/')
178
+ Slash.new(val.first)
178
179
  end
179
180
 
180
181
  def _reduce_16(val, _values)
181
- Symbol.new(val.first)
182
+ Symbol.new(val.first)
182
183
  end
183
184
 
184
185
  def _reduce_17(val, _values)
185
- Literal.new(val.first)
186
+ Literal.new(val.first)
186
187
  end
187
188
 
188
189
  def _reduce_18(val, _values)
189
- Dot.new(val.first)
190
+ Dot.new(val.first)
190
191
  end
191
192
 
192
193
  def _reduce_none(val, _values)
@@ -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