actionpack 3.2.22.5 → 4.0.0.beta1

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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,38 +1,81 @@
1
1
  module ActionDispatch
2
2
  module Http
3
+ # Models uploaded files.
4
+ #
5
+ # The actual file is accessible via the +tempfile+ accessor, though some
6
+ # of its interface is available directly for convenience.
7
+ #
8
+ # Uploaded files are temporary files whose lifespan is one request. When
9
+ # the object is finalized Ruby unlinks the file, so there is not need to
10
+ # clean them with a separate maintenance task.
3
11
  class UploadedFile
4
- attr_accessor :original_filename, :content_type, :tempfile, :headers
12
+ # The basename of the file in the client.
13
+ attr_accessor :original_filename
14
+
15
+ # A string with the MIME type of the file.
16
+ attr_accessor :content_type
17
+
18
+ # A +Tempfile+ object with the actual uploaded file. Note that some of
19
+ # its interface is available directly.
20
+ attr_accessor :tempfile
21
+
22
+ # A string with the headers of the multipart request.
23
+ attr_accessor :headers
24
+
25
+ def initialize(hash) # :nodoc:
26
+ @tempfile = hash[:tempfile]
27
+ raise(ArgumentError, ':tempfile is required') unless @tempfile
5
28
 
6
- def initialize(hash)
7
29
  @original_filename = encode_filename(hash[:filename])
8
30
  @content_type = hash[:type]
9
31
  @headers = hash[:head]
10
- @tempfile = hash[:tempfile]
11
- raise(ArgumentError, ':tempfile is required') unless @tempfile
12
32
  end
13
33
 
14
- def read(*args)
15
- @tempfile.read(*args)
34
+ # Shortcut for +tempfile.read+.
35
+ def read(length=nil, buffer=nil)
36
+ @tempfile.read(length, buffer)
16
37
  end
17
38
 
18
- # Delegate these methods to the tempfile.
19
- [:open, :path, :rewind, :size].each do |method|
20
- class_eval "def #{method}; @tempfile.#{method}; end"
39
+ # Shortcut for +tempfile.open+.
40
+ def open
41
+ @tempfile.open
42
+ end
43
+
44
+ # Shortcut for +tempfile.close+.
45
+ def close(unlink_now=false)
46
+ @tempfile.close(unlink_now)
47
+ end
48
+
49
+ # Shortcut for +tempfile.path+.
50
+ def path
51
+ @tempfile.path
52
+ end
53
+
54
+ # Shortcut for +tempfile.rewind+.
55
+ def rewind
56
+ @tempfile.rewind
57
+ end
58
+
59
+ # Shortcut for +tempfile.size+.
60
+ def size
61
+ @tempfile.size
62
+ end
63
+
64
+ # Shortcut for +tempfile.eof?+.
65
+ def eof?
66
+ @tempfile.eof?
21
67
  end
22
68
 
23
69
  private
70
+
24
71
  def encode_filename(filename)
25
- # Encode the filename in the utf8 encoding, unless it is nil or we're in 1.8
26
- if "ruby".encoding_aware? && filename
27
- filename.force_encoding("UTF-8").encode!
28
- else
29
- filename
30
- end
72
+ # Encode the filename in the utf8 encoding, unless it is nil
73
+ filename.force_encoding(Encoding::UTF_8).encode! if filename
31
74
  end
32
75
  end
33
76
 
34
- module Upload
35
- # Convert nested Hash to HashWithIndifferentAccess and replace
77
+ module Upload # :nodoc:
78
+ # Convert nested Hash to ActiveSupport::HashWithIndifferentAccess and replace
36
79
  # file upload hash with UploadedFile objects
37
80
  def normalize_parameters(value)
38
81
  if Hash === value && value.has_key?(:tempfile)
@@ -1,19 +1,26 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'active_support/core_ext/hash/slice'
3
+
1
4
  module ActionDispatch
2
5
  module Http
3
6
  module URL
7
+ IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
8
+
4
9
  mattr_accessor :tld_length
5
10
  self.tld_length = 1
6
11
 
7
12
  class << self
8
13
  def extract_domain(host, tld_length = @@tld_length)
9
- return nil unless named_host?(host)
10
- host.split('.').last(1 + tld_length).join('.')
14
+ host.split('.').last(1 + tld_length).join('.') if named_host?(host)
11
15
  end
12
16
 
13
17
  def extract_subdomains(host, tld_length = @@tld_length)
14
- return [] unless named_host?(host)
15
- parts = host.split('.')
16
- parts[0..-(tld_length+2)]
18
+ if named_host?(host)
19
+ parts = host.split('.')
20
+ parts[0..-(tld_length + 2)]
21
+ else
22
+ []
23
+ end
17
24
  end
18
25
 
19
26
  def extract_subdomain(host, tld_length = @@tld_length)
@@ -21,42 +28,51 @@ module ActionDispatch
21
28
  end
22
29
 
23
30
  def url_for(options = {})
24
- unless options[:host].present? || options[:only_path].present?
31
+ path = options.delete(:script_name).to_s.chomp("/")
32
+ path << options.delete(:path).to_s
33
+
34
+ params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params)
35
+ params.reject! { |_,v| v.to_param.nil? }
36
+
37
+ result = build_host_url(options)
38
+ if options[:trailing_slash]
39
+ if path.include?('?')
40
+ result << path.sub(/\?/, '/\&')
41
+ else
42
+ result << path.sub(/[^\/]\z|\A\z/, '\&/')
43
+ end
44
+ else
45
+ result << path
46
+ end
47
+ result << "?#{params.to_query}" unless params.empty?
48
+ result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
49
+ result
50
+ end
51
+
52
+ private
53
+
54
+ def build_host_url(options)
55
+ if options[:host].blank? && options[:only_path].blank?
25
56
  raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
26
57
  end
27
58
 
28
- rewritten_url = ""
59
+ result = ""
29
60
 
30
61
  unless options[:only_path]
31
62
  unless options[:protocol] == false
32
- rewritten_url << (options[:protocol] || "http")
33
- rewritten_url << ":" unless rewritten_url.match(%r{:|//})
63
+ result << (options[:protocol] || "http")
64
+ result << ":" unless result.match(%r{:|//})
34
65
  end
35
- rewritten_url << "//" unless rewritten_url.match("//")
36
- rewritten_url << rewrite_authentication(options)
37
- rewritten_url << host_or_subdomain_and_domain(options)
38
- rewritten_url << ":#{options.delete(:port)}" if options[:port]
39
- end
40
-
41
- path = options.delete(:path) || ''
42
-
43
- params = options[:params] || {}
44
- params.reject! {|k,v| v.to_param.nil? }
45
-
46
- if options[:trailing_slash] && !path.ends_with?('/')
47
- rewritten_url << path.sub(/(\?|\z)/) { "/" + $& }
48
- else
49
- rewritten_url << path
66
+ result << "//" unless result.match("//")
67
+ result << rewrite_authentication(options)
68
+ result << host_or_subdomain_and_domain(options)
69
+ result << ":#{options.delete(:port)}" if options[:port]
50
70
  end
51
- rewritten_url << "?#{params.to_query}" unless params.empty?
52
- rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
53
- rewritten_url
71
+ result
54
72
  end
55
73
 
56
- private
57
-
58
74
  def named_host?(host)
59
- !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
75
+ host && IP_HOST_REGEXP !~ host
60
76
  end
61
77
 
62
78
  def rewrite_authentication(options)
@@ -82,6 +98,12 @@ module ActionDispatch
82
98
  end
83
99
  end
84
100
 
101
+ def initialize(env)
102
+ super
103
+ @protocol = nil
104
+ @port = nil
105
+ end
106
+
85
107
  # Returns the complete URL used for this request.
86
108
  def url
87
109
  protocol + host_with_port + fullpath
@@ -171,7 +193,7 @@ module ActionDispatch
171
193
  # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt>
172
194
  # in "www.rubyonrails.co.uk".
173
195
  def subdomain(tld_length = @@tld_length)
174
- subdomains(tld_length).join(".")
196
+ ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
175
197
  end
176
198
  end
177
199
  end
@@ -0,0 +1,5 @@
1
+ require 'action_dispatch/journey/router'
2
+ require 'action_dispatch/journey/gtg/builder'
3
+ require 'action_dispatch/journey/gtg/simulator'
4
+ require 'action_dispatch/journey/nfa/builder'
5
+ require 'action_dispatch/journey/nfa/simulator'
@@ -0,0 +1,5 @@
1
+ module Rack # :nodoc:
2
+ Mount = ActionDispatch::Journey::Router
3
+ Mount::RouteSet = ActionDispatch::Journey::Router
4
+ Mount::RegexpWithNamedGroups = ActionDispatch::Journey::Path::Pattern
5
+ end
@@ -0,0 +1,146 @@
1
+ require 'action_controller/metal/exceptions'
2
+
3
+ module ActionDispatch
4
+ module Journey
5
+ # The Formatter class is used for formatting URLs. For example, parameters
6
+ # passed to +url_for+ in rails will eventually call Formatter#generate.
7
+ class Formatter # :nodoc:
8
+ attr_reader :routes
9
+
10
+ def initialize(routes)
11
+ @routes = routes
12
+ @cache = nil
13
+ end
14
+
15
+ def generate(type, name, options, recall = {}, parameterize = nil)
16
+ constraints = recall.merge(options)
17
+ missing_keys = []
18
+
19
+ match_route(name, constraints) do |route|
20
+ parameterized_parts = extract_parameterized_parts(route, options, recall, parameterize)
21
+ next if !name && route.requirements.empty? && route.parts.empty?
22
+
23
+ missing_keys = missing_keys(route, parameterized_parts)
24
+ next unless missing_keys.empty?
25
+ params = options.dup.delete_if do |key, _|
26
+ parameterized_parts.key?(key) || route.defaults.key?(key)
27
+ end
28
+
29
+ return [route.format(parameterized_parts), params]
30
+ end
31
+
32
+ message = "No route matches #{constraints.inspect}"
33
+ message << " missing required keys: #{missing_keys.inspect}" if name
34
+
35
+ raise ActionController::UrlGenerationError, message
36
+ end
37
+
38
+ def clear
39
+ @cache = nil
40
+ end
41
+
42
+ private
43
+
44
+ def extract_parameterized_parts(route, options, recall, parameterize = nil)
45
+ parameterized_parts = recall.merge(options)
46
+
47
+ keys_to_keep = route.parts.reverse.drop_while { |part|
48
+ !options.key?(part) || (options[part] || recall[part]).nil?
49
+ } | route.required_parts
50
+
51
+ (parameterized_parts.keys - keys_to_keep).each do |bad_key|
52
+ parameterized_parts.delete(bad_key)
53
+ end
54
+
55
+ if parameterize
56
+ parameterized_parts.each do |k, v|
57
+ parameterized_parts[k] = parameterize.call(k, v)
58
+ end
59
+ end
60
+
61
+ parameterized_parts.keep_if { |_, v| v }
62
+ parameterized_parts
63
+ end
64
+
65
+ def named_routes
66
+ routes.named_routes
67
+ end
68
+
69
+ def match_route(name, options)
70
+ if named_routes.key?(name)
71
+ yield named_routes[name]
72
+ else
73
+ routes = non_recursive(cache, options.to_a)
74
+
75
+ hash = routes.group_by { |_, r| r.score(options) }
76
+
77
+ hash.keys.sort.reverse_each do |score|
78
+ next if score < 0
79
+
80
+ hash[score].sort_by { |i, _| i }.each do |_, route|
81
+ yield route
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def non_recursive(cache, options)
88
+ routes = []
89
+ stack = [cache]
90
+
91
+ while stack.any?
92
+ c = stack.shift
93
+ routes.concat(c[:___routes]) if c.key?(:___routes)
94
+
95
+ options.each do |pair|
96
+ stack << c[pair] if c.key?(pair)
97
+ end
98
+ end
99
+
100
+ routes
101
+ end
102
+
103
+ # Returns an array populated with missing keys if any are present.
104
+ def missing_keys(route, parts)
105
+ missing_keys = []
106
+ tests = route.path.requirements
107
+ route.required_parts.each { |key|
108
+ if tests.key?(key)
109
+ missing_keys << key unless /\A#{tests[key]}\Z/ === parts[key]
110
+ else
111
+ missing_keys << key unless parts[key]
112
+ end
113
+ }
114
+ missing_keys
115
+ end
116
+
117
+ def possibles(cache, options, depth = 0)
118
+ cache.fetch(:___routes) { [] } + options.find_all { |pair|
119
+ cache.key?(pair)
120
+ }.map { |pair|
121
+ possibles(cache[pair], options, depth + 1)
122
+ }.flatten(1)
123
+ end
124
+
125
+ # Returns +true+ if no missing keys are present, otherwise +false+.
126
+ def verify_required_parts!(route, parts)
127
+ missing_keys(route, parts).empty?
128
+ end
129
+
130
+ def build_cache
131
+ root = { ___routes: [] }
132
+ routes.each_with_index do |route, i|
133
+ leaf = route.required_defaults.inject(root) do |h, tuple|
134
+ h[tuple] ||= {}
135
+ end
136
+ (leaf[:___routes] ||= []) << [i, route]
137
+ end
138
+ root
139
+ end
140
+
141
+ def cache
142
+ @cache ||= build_cache
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,162 @@
1
+ require 'action_dispatch/journey/gtg/transition_table'
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ module GTG # :nodoc:
6
+ class Builder # :nodoc:
7
+ DUMMY = Nodes::Dummy.new
8
+
9
+ attr_reader :root, :ast, :endpoints
10
+
11
+ def initialize(root)
12
+ @root = root
13
+ @ast = Nodes::Cat.new root, DUMMY
14
+ @followpos = nil
15
+ end
16
+
17
+ def transition_table
18
+ dtrans = TransitionTable.new
19
+ marked = {}
20
+ state_id = Hash.new { |h,k| h[k] = h.length }
21
+
22
+ start = firstpos(root)
23
+ dstates = [start]
24
+ until dstates.empty?
25
+ s = dstates.shift
26
+ next if marked[s]
27
+ marked[s] = true # mark s
28
+
29
+ s.group_by { |state| symbol(state) }.each do |sym, ps|
30
+ u = ps.map { |l| followpos(l) }.flatten
31
+ next if u.empty?
32
+
33
+ if u.uniq == [DUMMY]
34
+ from = state_id[s]
35
+ to = state_id[Object.new]
36
+ dtrans[from, to] = sym
37
+
38
+ dtrans.add_accepting(to)
39
+ ps.each { |state| dtrans.add_memo(to, state.memo) }
40
+ else
41
+ dtrans[state_id[s], state_id[u]] = sym
42
+
43
+ if u.include?(DUMMY)
44
+ to = state_id[u]
45
+
46
+ accepting = ps.find_all { |l| followpos(l).include?(DUMMY) }
47
+
48
+ accepting.each { |accepting_state|
49
+ dtrans.add_memo(to, accepting_state.memo)
50
+ }
51
+
52
+ dtrans.add_accepting(state_id[u])
53
+ end
54
+ end
55
+
56
+ dstates << u
57
+ end
58
+ end
59
+
60
+ dtrans
61
+ end
62
+
63
+ def nullable?(node)
64
+ case node
65
+ when Nodes::Group
66
+ true
67
+ when Nodes::Star
68
+ true
69
+ when Nodes::Or
70
+ node.children.any? { |c| nullable?(c) }
71
+ when Nodes::Cat
72
+ nullable?(node.left) && nullable?(node.right)
73
+ when Nodes::Terminal
74
+ !node.left
75
+ when Nodes::Unary
76
+ nullable?(node.left)
77
+ else
78
+ raise ArgumentError, 'unknown nullable: %s' % node.class.name
79
+ end
80
+ end
81
+
82
+ def firstpos(node)
83
+ case node
84
+ when Nodes::Star
85
+ firstpos(node.left)
86
+ when Nodes::Cat
87
+ if nullable?(node.left)
88
+ firstpos(node.left) | firstpos(node.right)
89
+ else
90
+ firstpos(node.left)
91
+ end
92
+ when Nodes::Or
93
+ node.children.map { |c| firstpos(c) }.flatten.uniq
94
+ when Nodes::Unary
95
+ firstpos(node.left)
96
+ when Nodes::Terminal
97
+ nullable?(node) ? [] : [node]
98
+ else
99
+ raise ArgumentError, 'unknown firstpos: %s' % node.class.name
100
+ end
101
+ end
102
+
103
+ def lastpos(node)
104
+ case node
105
+ when Nodes::Star
106
+ firstpos(node.left)
107
+ when Nodes::Or
108
+ node.children.map { |c| lastpos(c) }.flatten.uniq
109
+ when Nodes::Cat
110
+ if nullable?(node.right)
111
+ lastpos(node.left) | lastpos(node.right)
112
+ else
113
+ lastpos(node.right)
114
+ end
115
+ when Nodes::Terminal
116
+ nullable?(node) ? [] : [node]
117
+ when Nodes::Unary
118
+ lastpos(node.left)
119
+ else
120
+ raise ArgumentError, 'unknown lastpos: %s' % node.class.name
121
+ end
122
+ end
123
+
124
+ def followpos(node)
125
+ followpos_table[node]
126
+ end
127
+
128
+ private
129
+
130
+ def followpos_table
131
+ @followpos ||= build_followpos
132
+ end
133
+
134
+ def build_followpos
135
+ table = Hash.new { |h, k| h[k] = [] }
136
+ @ast.each do |n|
137
+ case n
138
+ when Nodes::Cat
139
+ lastpos(n.left).each do |i|
140
+ table[i] += firstpos(n.right)
141
+ end
142
+ when Nodes::Star
143
+ lastpos(n).each do |i|
144
+ table[i] += firstpos(n)
145
+ end
146
+ end
147
+ end
148
+ table
149
+ end
150
+
151
+ def symbol(edge)
152
+ case edge
153
+ when Journey::Nodes::Symbol
154
+ edge.regexp
155
+ else
156
+ edge.left
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end