actionpack 4.1.7 → 4.2.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/CHANGELOG.md +311 -527
- data/README.rdoc +7 -2
- data/lib/abstract_controller/base.rb +16 -6
- data/lib/abstract_controller/callbacks.rb +28 -51
- data/lib/abstract_controller/helpers.rb +11 -4
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/action_controller/base.rb +2 -1
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +26 -26
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +1 -1
- data/lib/action_controller/metal/head.rb +7 -3
- data/lib/action_controller/metal/http_authentication.rb +14 -9
- data/lib/action_controller/metal/instrumentation.rb +8 -5
- data/lib/action_controller/metal/live.rb +57 -6
- data/lib/action_controller/metal/mime_responds.rb +23 -246
- data/lib/action_controller/metal/params_wrapper.rb +2 -2
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +14 -8
- data/lib/action_controller/metal/renderers.rb +30 -10
- data/lib/action_controller/metal/rendering.rb +2 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +125 -12
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +12 -11
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +4 -0
- data/lib/action_controller/test_case.rb +112 -75
- data/lib/action_controller.rb +1 -1
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/headers.rb +43 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
- data/lib/action_dispatch/http/mime_type.rb +2 -2
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +11 -26
- data/lib/action_dispatch/http/request.rb +37 -11
- data/lib/action_dispatch/http/response.rb +70 -18
- data/lib/action_dispatch/http/upload.rb +3 -8
- data/lib/action_dispatch/http/url.rb +88 -69
- data/lib/action_dispatch/journey/formatter.rb +33 -17
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +52 -60
- data/lib/action_dispatch/journey/parser.y +11 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +3 -18
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router.rb +53 -77
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -92
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +29 -29
- data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
- data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
- data/lib/action_dispatch/middleware/flash.rb +13 -7
- data/lib/action_dispatch/middleware/params_parser.rb +1 -1
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
- data/lib/action_dispatch/middleware/static.rb +66 -37
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -12
- data/lib/action_dispatch/routing/mapper.rb +410 -281
- data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
- data/lib/action_dispatch/routing/redirection.rb +10 -12
- data/lib/action_dispatch/routing/route_set.rb +297 -168
- data/lib/action_dispatch/routing/url_for.rb +15 -4
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +2 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +24 -19
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +7 -0
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +55 -13
- data/lib/action_controller/metal/responder.rb +0 -297
|
@@ -18,6 +18,7 @@ module ActionDispatch
|
|
|
18
18
|
# A +Tempfile+ object with the actual uploaded file. Note that some of
|
|
19
19
|
# its interface is available directly.
|
|
20
20
|
attr_accessor :tempfile
|
|
21
|
+
alias :to_io :tempfile
|
|
21
22
|
|
|
22
23
|
# A string with the headers of the multipart request.
|
|
23
24
|
attr_accessor :headers
|
|
@@ -26,7 +27,8 @@ module ActionDispatch
|
|
|
26
27
|
@tempfile = hash[:tempfile]
|
|
27
28
|
raise(ArgumentError, ':tempfile is required') unless @tempfile
|
|
28
29
|
|
|
29
|
-
@original_filename =
|
|
30
|
+
@original_filename = hash[:filename]
|
|
31
|
+
@original_filename &&= @original_filename.encode "UTF-8"
|
|
30
32
|
@content_type = hash[:type]
|
|
31
33
|
@headers = hash[:head]
|
|
32
34
|
end
|
|
@@ -65,13 +67,6 @@ module ActionDispatch
|
|
|
65
67
|
def eof?
|
|
66
68
|
@tempfile.eof?
|
|
67
69
|
end
|
|
68
|
-
|
|
69
|
-
private
|
|
70
|
-
|
|
71
|
-
def encode_filename(filename)
|
|
72
|
-
# Encode the filename in the utf8 encoding, unless it is nil
|
|
73
|
-
filename.force_encoding(Encoding::UTF_8).encode! if filename
|
|
74
|
-
end
|
|
75
70
|
end
|
|
76
71
|
end
|
|
77
72
|
end
|
|
@@ -5,51 +5,83 @@ module ActionDispatch
|
|
|
5
5
|
module Http
|
|
6
6
|
module URL
|
|
7
7
|
IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
|
|
8
|
-
HOST_REGEXP = /(
|
|
8
|
+
HOST_REGEXP = /(^[^:]+:\/\/)?([^:]+)(?::(\d+$))?/
|
|
9
9
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
|
10
10
|
|
|
11
11
|
mattr_accessor :tld_length
|
|
12
12
|
self.tld_length = 1
|
|
13
13
|
|
|
14
14
|
class << self
|
|
15
|
-
def extract_domain(host, tld_length
|
|
16
|
-
host
|
|
15
|
+
def extract_domain(host, tld_length)
|
|
16
|
+
extract_domain_from(host, tld_length) if named_host?(host)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def extract_subdomains(host, tld_length
|
|
19
|
+
def extract_subdomains(host, tld_length)
|
|
20
20
|
if named_host?(host)
|
|
21
|
-
|
|
22
|
-
parts[0..-(tld_length + 2)]
|
|
21
|
+
extract_subdomains_from(host, tld_length)
|
|
23
22
|
else
|
|
24
23
|
[]
|
|
25
24
|
end
|
|
26
25
|
end
|
|
27
26
|
|
|
28
|
-
def extract_subdomain(host, tld_length
|
|
27
|
+
def extract_subdomain(host, tld_length)
|
|
29
28
|
extract_subdomains(host, tld_length).join('.')
|
|
30
29
|
end
|
|
31
30
|
|
|
32
|
-
def url_for(options
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
def url_for(options)
|
|
32
|
+
if options[:only_path]
|
|
33
|
+
path_for options
|
|
34
|
+
else
|
|
35
|
+
full_url_for options
|
|
36
|
+
end
|
|
37
|
+
end
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
def full_url_for(options)
|
|
40
|
+
host = options[:host]
|
|
41
|
+
protocol = options[:protocol]
|
|
42
|
+
port = options[:port]
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
unless host
|
|
45
|
+
raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
|
|
46
|
+
end
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
build_host_url(host, port, protocol, options, path_for(options))
|
|
49
|
+
end
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
def path_for(options)
|
|
52
|
+
path = options[:script_name].to_s.chomp("/")
|
|
53
|
+
path << options[:path] if options.key?(:path)
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
|
56
|
+
add_params(path, options[:params]) if options.key?(:params)
|
|
57
|
+
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
|
58
|
+
|
|
59
|
+
path
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
private
|
|
52
63
|
|
|
64
|
+
def add_params(path, params)
|
|
65
|
+
params = { params: params } unless params.is_a?(Hash)
|
|
66
|
+
params.reject! { |_,v| v.to_param.nil? }
|
|
67
|
+
path << "?#{params.to_query}" unless params.empty?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def add_anchor(path, anchor)
|
|
71
|
+
if anchor
|
|
72
|
+
path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def extract_domain_from(host, tld_length)
|
|
77
|
+
host.split('.').last(1 + tld_length).join('.')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def extract_subdomains_from(host, tld_length)
|
|
81
|
+
parts = host.split('.')
|
|
82
|
+
parts[0..-(tld_length + 2)]
|
|
83
|
+
end
|
|
84
|
+
|
|
53
85
|
def add_trailing_slash(path)
|
|
54
86
|
# includes querysting
|
|
55
87
|
if path.include?('?')
|
|
@@ -58,54 +90,38 @@ module ActionDispatch
|
|
|
58
90
|
elsif !path.include?(".")
|
|
59
91
|
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
|
60
92
|
end
|
|
61
|
-
|
|
62
|
-
path
|
|
63
93
|
end
|
|
64
94
|
|
|
65
|
-
def build_host_url(options)
|
|
66
|
-
if
|
|
67
|
-
|
|
95
|
+
def build_host_url(host, port, protocol, options, path)
|
|
96
|
+
if match = host.match(HOST_REGEXP)
|
|
97
|
+
protocol ||= match[1] unless protocol == false
|
|
98
|
+
host = match[2]
|
|
99
|
+
port = match[3] unless options.key? :port
|
|
68
100
|
end
|
|
69
101
|
|
|
70
|
-
|
|
102
|
+
protocol = normalize_protocol protocol
|
|
103
|
+
host = normalize_host(host, options)
|
|
71
104
|
|
|
72
|
-
|
|
73
|
-
if match = options[:host].match(HOST_REGEXP)
|
|
74
|
-
options[:protocol] ||= match[1] unless options[:protocol] == false
|
|
75
|
-
options[:host] = match[2]
|
|
76
|
-
options[:port] = match[3] unless options.key?(:port)
|
|
77
|
-
end
|
|
105
|
+
result = protocol.dup
|
|
78
106
|
|
|
79
|
-
|
|
80
|
-
options[:
|
|
81
|
-
options[:port] = normalize_port(options)
|
|
82
|
-
|
|
83
|
-
result << options[:protocol]
|
|
84
|
-
result << rewrite_authentication(options)
|
|
85
|
-
result << options[:host]
|
|
86
|
-
result << ":#{options[:port]}" if options[:port]
|
|
107
|
+
if options[:user] && options[:password]
|
|
108
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
|
87
109
|
end
|
|
88
|
-
result
|
|
89
|
-
end
|
|
90
110
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
111
|
+
result << host
|
|
112
|
+
normalize_port(port, protocol) { |normalized_port|
|
|
113
|
+
result << ":#{normalized_port}"
|
|
114
|
+
}
|
|
94
115
|
|
|
95
|
-
|
|
96
|
-
(options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
|
|
116
|
+
result.concat path
|
|
97
117
|
end
|
|
98
118
|
|
|
99
|
-
def
|
|
100
|
-
|
|
101
|
-
"#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
|
102
|
-
else
|
|
103
|
-
""
|
|
104
|
-
end
|
|
119
|
+
def named_host?(host)
|
|
120
|
+
IP_HOST_REGEXP !~ host
|
|
105
121
|
end
|
|
106
122
|
|
|
107
|
-
def normalize_protocol(
|
|
108
|
-
case
|
|
123
|
+
def normalize_protocol(protocol)
|
|
124
|
+
case protocol
|
|
109
125
|
when nil
|
|
110
126
|
"http://"
|
|
111
127
|
when false, "//"
|
|
@@ -113,36 +129,39 @@ module ActionDispatch
|
|
|
113
129
|
when PROTOCOL_REGEXP
|
|
114
130
|
"#{$1}://"
|
|
115
131
|
else
|
|
116
|
-
raise ArgumentError, "Invalid :protocol option: #{
|
|
132
|
+
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
|
117
133
|
end
|
|
118
134
|
end
|
|
119
135
|
|
|
120
|
-
def normalize_host(options)
|
|
121
|
-
return
|
|
136
|
+
def normalize_host(_host, options)
|
|
137
|
+
return _host unless named_host?(_host)
|
|
122
138
|
|
|
123
139
|
tld_length = options[:tld_length] || @@tld_length
|
|
140
|
+
subdomain = options.fetch :subdomain, true
|
|
141
|
+
domain = options[:domain]
|
|
124
142
|
|
|
125
143
|
host = ""
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
host <<
|
|
144
|
+
if subdomain == true
|
|
145
|
+
return _host if domain.nil?
|
|
146
|
+
|
|
147
|
+
host << extract_subdomains_from(_host, tld_length).join('.')
|
|
148
|
+
elsif subdomain
|
|
149
|
+
host << subdomain.to_param
|
|
130
150
|
end
|
|
131
151
|
host << "." unless host.empty?
|
|
132
|
-
host << (
|
|
152
|
+
host << (domain || extract_domain_from(_host, tld_length))
|
|
133
153
|
host
|
|
134
154
|
end
|
|
135
155
|
|
|
136
|
-
def normalize_port(
|
|
137
|
-
return
|
|
156
|
+
def normalize_port(port, protocol)
|
|
157
|
+
return unless port
|
|
138
158
|
|
|
139
|
-
case
|
|
140
|
-
when "//"
|
|
141
|
-
options[:port]
|
|
159
|
+
case protocol
|
|
160
|
+
when "//" then yield port
|
|
142
161
|
when "https://"
|
|
143
|
-
|
|
162
|
+
yield port unless port.to_i == 443
|
|
144
163
|
else
|
|
145
|
-
|
|
164
|
+
yield port unless port.to_i == 80
|
|
146
165
|
end
|
|
147
166
|
end
|
|
148
167
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'action_controller/metal/exceptions'
|
|
2
|
+
require 'active_support/deprecation'
|
|
2
3
|
|
|
3
4
|
module ActionDispatch
|
|
4
5
|
module Journey
|
|
@@ -12,12 +13,12 @@ module ActionDispatch
|
|
|
12
13
|
@cache = nil
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
def generate(
|
|
16
|
-
constraints =
|
|
16
|
+
def generate(name, options, path_parameters, parameterize = nil)
|
|
17
|
+
constraints = path_parameters.merge(options)
|
|
17
18
|
missing_keys = []
|
|
18
19
|
|
|
19
20
|
match_route(name, constraints) do |route|
|
|
20
|
-
parameterized_parts = extract_parameterized_parts(route, options,
|
|
21
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
|
|
21
22
|
|
|
22
23
|
# Skip this route unless a name has been provided or it is a
|
|
23
24
|
# standard Rails route since we can't determine whether an options
|
|
@@ -30,11 +31,17 @@ module ActionDispatch
|
|
|
30
31
|
parameterized_parts.key?(key) || route.defaults.key?(key)
|
|
31
32
|
end
|
|
32
33
|
|
|
34
|
+
defaults = route.defaults
|
|
35
|
+
required_parts = route.required_parts
|
|
36
|
+
parameterized_parts.delete_if do |key, value|
|
|
37
|
+
value.to_s == defaults[key].to_s && !required_parts.include?(key)
|
|
38
|
+
end
|
|
39
|
+
|
|
33
40
|
return [route.format(parameterized_parts), params]
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
message = "No route matches #{Hash[constraints.sort].inspect}"
|
|
37
|
-
message << " missing required keys: #{missing_keys.sort.inspect}"
|
|
44
|
+
message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
|
|
38
45
|
|
|
39
46
|
raise ActionController::UrlGenerationError, message
|
|
40
47
|
end
|
|
@@ -74,14 +81,28 @@ module ActionDispatch
|
|
|
74
81
|
if named_routes.key?(name)
|
|
75
82
|
yield named_routes[name]
|
|
76
83
|
else
|
|
77
|
-
|
|
84
|
+
# Make sure we don't show the deprecation warning more than once
|
|
85
|
+
warned = false
|
|
86
|
+
|
|
87
|
+
routes = non_recursive(cache, options)
|
|
78
88
|
|
|
79
89
|
hash = routes.group_by { |_, r| r.score(options) }
|
|
80
90
|
|
|
81
91
|
hash.keys.sort.reverse_each do |score|
|
|
82
|
-
|
|
92
|
+
break if score < 0
|
|
83
93
|
|
|
84
94
|
hash[score].sort_by { |i, _| i }.each do |_, route|
|
|
95
|
+
if name && !warned
|
|
96
|
+
ActiveSupport::Deprecation.warn <<-MSG.squish
|
|
97
|
+
You are trying to generate the URL for a named route called
|
|
98
|
+
#{name.inspect} but no such route was found. In the future,
|
|
99
|
+
this will result in an `ActionController::UrlGenerationError`
|
|
100
|
+
exception.
|
|
101
|
+
MSG
|
|
102
|
+
|
|
103
|
+
warned = true
|
|
104
|
+
end
|
|
105
|
+
|
|
85
106
|
yield route
|
|
86
107
|
end
|
|
87
108
|
end
|
|
@@ -90,14 +111,14 @@ module ActionDispatch
|
|
|
90
111
|
|
|
91
112
|
def non_recursive(cache, options)
|
|
92
113
|
routes = []
|
|
93
|
-
|
|
114
|
+
queue = [cache]
|
|
94
115
|
|
|
95
|
-
while
|
|
96
|
-
c =
|
|
116
|
+
while queue.any?
|
|
117
|
+
c = queue.shift
|
|
97
118
|
routes.concat(c[:___routes]) if c.key?(:___routes)
|
|
98
119
|
|
|
99
120
|
options.each do |pair|
|
|
100
|
-
|
|
121
|
+
queue << c[pair] if c.key?(pair)
|
|
101
122
|
end
|
|
102
123
|
end
|
|
103
124
|
|
|
@@ -121,14 +142,9 @@ module ActionDispatch
|
|
|
121
142
|
def possibles(cache, options, depth = 0)
|
|
122
143
|
cache.fetch(:___routes) { [] } + options.find_all { |pair|
|
|
123
144
|
cache.key?(pair)
|
|
124
|
-
}.
|
|
145
|
+
}.flat_map { |pair|
|
|
125
146
|
possibles(cache[pair], options, depth + 1)
|
|
126
|
-
}
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# Returns +true+ if no missing keys are present, otherwise +false+.
|
|
130
|
-
def verify_required_parts!(route, parts)
|
|
131
|
-
missing_keys(route, parts).empty?
|
|
147
|
+
}
|
|
132
148
|
end
|
|
133
149
|
|
|
134
150
|
def build_cache
|
|
@@ -27,7 +27,7 @@ module ActionDispatch
|
|
|
27
27
|
marked[s] = true # mark s
|
|
28
28
|
|
|
29
29
|
s.group_by { |state| symbol(state) }.each do |sym, ps|
|
|
30
|
-
u = ps.
|
|
30
|
+
u = ps.flat_map { |l| followpos(l) }
|
|
31
31
|
next if u.empty?
|
|
32
32
|
|
|
33
33
|
if u.uniq == [DUMMY]
|
|
@@ -90,7 +90,7 @@ module ActionDispatch
|
|
|
90
90
|
firstpos(node.left)
|
|
91
91
|
end
|
|
92
92
|
when Nodes::Or
|
|
93
|
-
node.children.
|
|
93
|
+
node.children.flat_map { |c| firstpos(c) }.uniq
|
|
94
94
|
when Nodes::Unary
|
|
95
95
|
firstpos(node.left)
|
|
96
96
|
when Nodes::Terminal
|
|
@@ -105,7 +105,7 @@ module ActionDispatch
|
|
|
105
105
|
when Nodes::Star
|
|
106
106
|
firstpos(node.left)
|
|
107
107
|
when Nodes::Or
|
|
108
|
-
node.children.
|
|
108
|
+
node.children.flat_map { |c| lastpos(c) }.uniq
|
|
109
109
|
when Nodes::Cat
|
|
110
110
|
if nullable?(node.right)
|
|
111
111
|
lastpos(node.left) | lastpos(node.right)
|
|
@@ -19,6 +19,14 @@ module ActionDispatch
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def simulate(string)
|
|
22
|
+
ms = memos(string) { return }
|
|
23
|
+
MatchData.new(ms)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias :=~ :simulate
|
|
27
|
+
alias :match :simulate
|
|
28
|
+
|
|
29
|
+
def memos(string)
|
|
22
30
|
input = StringScanner.new(string)
|
|
23
31
|
state = [0]
|
|
24
32
|
while sym = input.scan(%r([/.?]|[^/.?]+))
|
|
@@ -29,15 +37,10 @@ module ActionDispatch
|
|
|
29
37
|
tt.accepting? s
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
return if acceptance_states.empty?
|
|
40
|
+
return yield if acceptance_states.empty?
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
MatchData.new(memos)
|
|
42
|
+
acceptance_states.flat_map { |x| tt.memo(x) }.compact
|
|
37
43
|
end
|
|
38
|
-
|
|
39
|
-
alias :=~ :simulate
|
|
40
|
-
alias :match :simulate
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
end
|
|
@@ -40,7 +40,19 @@ module ActionDispatch
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def move(t, a)
|
|
43
|
-
|
|
43
|
+
return [] if t.empty?
|
|
44
|
+
|
|
45
|
+
regexps = []
|
|
46
|
+
|
|
47
|
+
t.map { |s|
|
|
48
|
+
if states = @regexp_states[s]
|
|
49
|
+
regexps.concat states.map { |re, v| re === a ? v : nil }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if states = @string_states[s]
|
|
53
|
+
states[a]
|
|
54
|
+
end
|
|
55
|
+
}.compact.concat regexps
|
|
44
56
|
end
|
|
45
57
|
|
|
46
58
|
def as_json(options = nil)
|
|
@@ -76,13 +88,13 @@ module ActionDispatch
|
|
|
76
88
|
erb = File.read File.join(viz_dir, 'index.html.erb')
|
|
77
89
|
states = "function tt() { return #{to_json}; }"
|
|
78
90
|
|
|
79
|
-
fun_routes = paths.
|
|
91
|
+
fun_routes = paths.sample(3).map do |ast|
|
|
80
92
|
ast.map { |n|
|
|
81
93
|
case n
|
|
82
94
|
when Nodes::Symbol
|
|
83
95
|
case n.left
|
|
84
96
|
when ':id' then rand(100).to_s
|
|
85
|
-
when ':format' then %w{ xml json }.
|
|
97
|
+
when ':format' then %w{ xml json }.sample
|
|
86
98
|
else
|
|
87
99
|
'omg'
|
|
88
100
|
end
|
|
@@ -114,17 +126,17 @@ module ActionDispatch
|
|
|
114
126
|
end
|
|
115
127
|
|
|
116
128
|
def states
|
|
117
|
-
ss = @string_states.keys + @string_states.values.
|
|
118
|
-
rs = @regexp_states.keys + @regexp_states.values.
|
|
129
|
+
ss = @string_states.keys + @string_states.values.flat_map(&:values)
|
|
130
|
+
rs = @regexp_states.keys + @regexp_states.values.flat_map(&:values)
|
|
119
131
|
(ss + rs).uniq
|
|
120
132
|
end
|
|
121
133
|
|
|
122
134
|
def transitions
|
|
123
|
-
@string_states.
|
|
135
|
+
@string_states.flat_map { |from, hash|
|
|
124
136
|
hash.map { |s, to| [from, s, to] }
|
|
125
|
-
}
|
|
137
|
+
} + @regexp_states.flat_map { |from, hash|
|
|
126
138
|
hash.map { |s, to| [from, s, to] }
|
|
127
|
-
}
|
|
139
|
+
}
|
|
128
140
|
end
|
|
129
141
|
|
|
130
142
|
private
|
|
@@ -139,26 +151,6 @@ module ActionDispatch
|
|
|
139
151
|
raise ArgumentError, 'unknown symbol: %s' % sym.class
|
|
140
152
|
end
|
|
141
153
|
end
|
|
142
|
-
|
|
143
|
-
def move_regexp(t, a)
|
|
144
|
-
return [] if t.empty?
|
|
145
|
-
|
|
146
|
-
t.map { |s|
|
|
147
|
-
if states = @regexp_states[s]
|
|
148
|
-
states.map { |re, v| re === a ? v : nil }
|
|
149
|
-
end
|
|
150
|
-
}.flatten.compact.uniq
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def move_string(t, a)
|
|
154
|
-
return [] if t.empty?
|
|
155
|
-
|
|
156
|
-
t.map do |s|
|
|
157
|
-
if states = @string_states[s]
|
|
158
|
-
states[a]
|
|
159
|
-
end
|
|
160
|
-
end.compact
|
|
161
|
-
end
|
|
162
154
|
end
|
|
163
155
|
end
|
|
164
156
|
end
|