Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
3aa327f9
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3aa327f9
编写于
12月 20, 2012
作者:
R
Rafael Mendonça França
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #8567 from frodsan/update_coding_conventions_journey
update AD::Journey to follow Rails coding conventions
上级
a8ad694a
eb493f5a
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
440 addition
and
438 deletion
+440
-438
actionpack/Rakefile
actionpack/Rakefile
+1
-1
actionpack/lib/action_dispatch/journey/formatter.rb
actionpack/lib/action_dispatch/journey/formatter.rb
+82
-84
actionpack/lib/action_dispatch/journey/gtg/builder.rb
actionpack/lib/action_dispatch/journey/gtg/builder.rb
+41
-40
actionpack/lib/action_dispatch/journey/gtg/simulator.rb
actionpack/lib/action_dispatch/journey/gtg/simulator.rb
+6
-6
actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
...npack/lib/action_dispatch/journey/gtg/transition_table.rb
+25
-24
actionpack/lib/action_dispatch/journey/nfa/builder.rb
actionpack/lib/action_dispatch/journey/nfa/builder.rb
+17
-17
actionpack/lib/action_dispatch/journey/nfa/simulator.rb
actionpack/lib/action_dispatch/journey/nfa/simulator.rb
+9
-9
actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
...npack/lib/action_dispatch/journey/nfa/transition_table.rb
+29
-32
actionpack/lib/action_dispatch/journey/nodes/node.rb
actionpack/lib/action_dispatch/journey/nodes/node.rb
+5
-5
actionpack/lib/action_dispatch/journey/parser_extras.rb
actionpack/lib/action_dispatch/journey/parser_extras.rb
+2
-2
actionpack/lib/action_dispatch/journey/path/pattern.rb
actionpack/lib/action_dispatch/journey/path/pattern.rb
+31
-30
actionpack/lib/action_dispatch/journey/route.rb
actionpack/lib/action_dispatch/journey/route.rb
+4
-4
actionpack/lib/action_dispatch/journey/router.rb
actionpack/lib/action_dispatch/journey/router.rb
+58
-58
actionpack/lib/action_dispatch/journey/router/strexp.rb
actionpack/lib/action_dispatch/journey/router/strexp.rb
+1
-1
actionpack/lib/action_dispatch/journey/routes.rb
actionpack/lib/action_dispatch/journey/routes.rb
+8
-8
actionpack/lib/action_dispatch/journey/scanner.rb
actionpack/lib/action_dispatch/journey/scanner.rb
+26
-25
actionpack/lib/action_dispatch/journey/visitors.rb
actionpack/lib/action_dispatch/journey/visitors.rb
+95
-92
未找到文件。
actionpack/Rakefile
浏览文件 @
3aa327f9
...
...
@@ -80,4 +80,4 @@ rule '.rb' => '.y' do |t|
sh
"racc -l -o
#{
t
.
name
}
#{
t
.
source
}
"
end
task
:compile
=>
'lib/action_dispatch/journey/parser.rb'
task
compile:
'lib/action_dispatch/journey/parser.rb'
actionpack/lib/action_dispatch/journey/formatter.rb
浏览文件 @
3aa327f9
...
...
@@ -5,17 +5,17 @@ module Journey
class
Formatter
# :nodoc:
attr_reader
:routes
def
initialize
routes
def
initialize
(
routes
)
@routes
=
routes
@cache
=
nil
end
def
generate
type
,
name
,
options
,
recall
=
{},
parameterize
=
nil
constraints
=
recall
.
merge
options
def
generate
(
type
,
name
,
options
,
recall
=
{},
parameterize
=
nil
)
constraints
=
recall
.
merge
(
options
)
missing_keys
=
[]
match_route
(
name
,
constraints
)
do
|
route
|
parameterized_parts
=
extract_parameterized_parts
route
,
options
,
recall
,
parameterize
parameterized_parts
=
extract_parameterized_parts
(
route
,
options
,
recall
,
parameterize
)
next
if
!
name
&&
route
.
requirements
.
empty?
&&
route
.
parts
.
empty?
missing_keys
=
missing_keys
(
route
,
parameterized_parts
)
...
...
@@ -35,112 +35,110 @@ def clear
end
private
def
extract_parameterized_parts
route
,
options
,
recall
,
parameterize
=
nil
constraints
=
recall
.
merge
options
data
=
constraints
.
dup
keys_to_keep
=
route
.
parts
.
reverse
.
drop_while
{
|
part
|
!
options
.
key?
(
part
)
||
(
options
[
part
]
||
recall
[
part
]).
nil?
}
|
route
.
required_parts
def
extract_parameterized_parts
(
route
,
options
,
recall
,
parameterize
=
nil
)
constraints
=
recall
.
merge
(
options
)
data
=
constraints
.
dup
(
data
.
keys
-
keys_to_keep
).
each
do
|
bad_key
|
data
.
delete
bad_key
end
keys_to_keep
=
route
.
parts
.
reverse
.
drop_while
{
|
part
|
!
options
.
key?
(
part
)
||
(
options
[
part
]
||
recall
[
part
]).
nil?
}
|
route
.
required_parts
(
data
.
keys
-
keys_to_keep
).
each
do
|
bad_key
|
data
.
delete
(
bad_key
)
end
parameterized_parts
=
data
.
dup
parameterized_parts
=
data
.
dup
if
parameterize
parameterized_parts
.
each
do
|
k
,
v
|
parameterized_parts
[
k
]
=
parameterize
.
call
(
k
,
v
)
if
parameterize
parameterized_parts
.
each
do
|
k
,
v
|
parameterized_parts
[
k
]
=
parameterize
.
call
(
k
,
v
)
end
end
end
parameterized_parts
.
keep_if
{
|
_
,
v
|
v
}
parameterized_parts
end
parameterized_parts
.
keep_if
{
|
_
,
v
|
v
}
parameterized_parts
end
def
named_routes
routes
.
named_routes
end
def
named_routes
routes
.
named_routes
end
def
match_route
name
,
options
if
named_routes
.
key?
name
yield
named_routes
[
name
]
else
#routes = possibles(@cache, options.to_a)
routes
=
non_recursive
(
cache
,
options
.
to_a
)
def
match_route
(
name
,
options
)
if
named_routes
.
key?
(
name
)
yield
named_routes
[
name
]
else
routes
=
non_recursive
(
cache
,
options
.
to_a
)
hash
=
routes
.
group_by
{
|
_
,
r
|
r
.
score
options
}
hash
=
routes
.
group_by
{
|
_
,
r
|
r
.
score
(
options
)
}
hash
.
keys
.
sort
.
reverse_each
do
|
score
|
next
if
score
<
0
hash
.
keys
.
sort
.
reverse_each
do
|
score
|
next
if
score
<
0
hash
[
score
].
sort_by
{
|
i
,
_
|
i
}.
each
do
|
_
,
route
|
yield
route
hash
[
score
].
sort_by
{
|
i
,
_
|
i
}.
each
do
|
_
,
route
|
yield
route
end
end
end
end
end
def
non_recursive
cache
,
options
routes
=
[]
stack
=
[
cache
]
def
non_recursive
(
cache
,
options
)
routes
=
[]
stack
=
[
cache
]
while
stack
.
any?
c
=
stack
.
shift
routes
.
concat
c
[
:___routes
]
if
c
.
key?
:___routes
while
stack
.
any?
c
=
stack
.
shift
routes
.
concat
(
c
[
:___routes
])
if
c
.
key?
(
:___routes
)
options
.
each
do
|
pair
|
stack
<<
c
[
pair
]
if
c
.
key?
pair
options
.
each
do
|
pair
|
stack
<<
c
[
pair
]
if
c
.
key?
(
pair
)
end
end
end
routes
end
routes
end
# Returns an array populated with missing keys if any are present.
def
missing_keys
route
,
parts
missing_keys
=
[]
tests
=
route
.
path
.
requirements
route
.
required_parts
.
each
{
|
key
|
if
tests
.
key?
key
missing_keys
<<
key
unless
/\A
#{
tests
[
key
]
}
\Z/
===
parts
[
key
]
else
missing_keys
<<
key
unless
parts
[
key
]
end
}
missing_keys
end
# Returns an array populated with missing keys if any are present.
def
missing_keys
(
route
,
parts
)
missing_keys
=
[]
tests
=
route
.
path
.
requirements
route
.
required_parts
.
each
{
|
key
|
if
tests
.
key?
(
key
)
missing_keys
<<
key
unless
/\A
#{
tests
[
key
]
}
\Z/
===
parts
[
key
]
else
missing_keys
<<
key
unless
parts
[
key
]
end
}
missing_keys
end
def
possibles
cache
,
options
,
depth
=
0
cache
.
fetch
(
:___routes
)
{
[]
}
+
options
.
find_all
{
|
pair
|
cache
.
key?
pair
}.
map
{
|
pair
|
possibles
(
cache
[
pair
],
options
,
depth
+
1
)
}.
flatten
(
1
)
end
def
possibles
(
cache
,
options
,
depth
=
0
)
cache
.
fetch
(
:___routes
)
{
[]
}
+
options
.
find_all
{
|
pair
|
cache
.
key?
(
pair
)
}.
map
{
|
pair
|
possibles
(
cache
[
pair
],
options
,
depth
+
1
)
}.
flatten
(
1
)
end
# Returns +true+ if no missing keys are present, otherwise +false+.
def
verify_required_parts!
route
,
parts
missing_keys
(
route
,
parts
).
empty?
end
# Returns +true+ if no missing keys are present, otherwise +false+.
def
verify_required_parts!
(
route
,
parts
)
missing_keys
(
route
,
parts
).
empty?
end
def
build_cache
root
=
{
:___routes
=>
[]
}
routes
.
each_with_index
do
|
route
,
i
|
leaf
=
route
.
required_defaults
.
inject
(
root
)
do
|
h
,
tuple
|
h
[
tuple
]
||=
{}
def
build_cache
root
=
{
___routes:
[]
}
routes
.
each_with_index
do
|
route
,
i
|
leaf
=
route
.
required_defaults
.
inject
(
root
)
do
|
h
,
tuple
|
h
[
tuple
]
||=
{}
end
(
leaf
[
:___routes
]
||=
[])
<<
[
i
,
route
]
end
(
leaf
[
:___routes
]
||=
[])
<<
[
i
,
route
]
root
end
root
end
def
cache
@cache
||=
build_cache
end
def
cache
@cache
||=
build_cache
end
end
end
end
actionpack/lib/action_dispatch/journey/gtg/builder.rb
浏览文件 @
3aa327f9
...
...
@@ -8,10 +8,10 @@ class Builder # :nodoc:
attr_reader
:root
,
:ast
,
:endpoints
def
initialize
root
@root
=
root
@ast
=
Nodes
::
Cat
.
new
root
,
DUMMY
@followpos
=
nil
def
initialize
(
root
)
@root
=
root
@ast
=
Nodes
::
Cat
.
new
root
,
DUMMY
@followpos
=
nil
end
def
transition_table
...
...
@@ -35,21 +35,21 @@ def transition_table
to
=
state_id
[
Object
.
new
]
dtrans
[
from
,
to
]
=
sym
dtrans
.
add_accepting
to
ps
.
each
{
|
state
|
dtrans
.
add_memo
to
,
state
.
memo
}
dtrans
.
add_accepting
(
to
)
ps
.
each
{
|
state
|
dtrans
.
add_memo
(
to
,
state
.
memo
)
}
else
dtrans
[
state_id
[
s
],
state_id
[
u
]]
=
sym
if
u
.
include?
DUMMY
if
u
.
include?
(
DUMMY
)
to
=
state_id
[
u
]
accepting
=
ps
.
find_all
{
|
l
|
followpos
(
l
).
include?
DUMMY
}
accepting
=
ps
.
find_all
{
|
l
|
followpos
(
l
).
include?
(
DUMMY
)
}
accepting
.
each
{
|
accepting_state
|
dtrans
.
add_memo
to
,
accepting_state
.
memo
dtrans
.
add_memo
(
to
,
accepting_state
.
memo
)
}
dtrans
.
add_accepting
state_id
[
u
]
dtrans
.
add_accepting
(
state_id
[
u
])
end
end
...
...
@@ -60,7 +60,7 @@ def transition_table
dtrans
end
def
nullable?
node
def
nullable?
(
node
)
case
node
when
Nodes
::
Group
true
...
...
@@ -73,18 +73,18 @@ def nullable? node
when
Nodes
::
Terminal
!
node
.
left
when
Nodes
::
Unary
nullable?
node
.
left
nullable?
(
node
.
left
)
else
raise
ArgumentError
,
'unknown nullable: %s'
%
node
.
class
.
name
end
end
def
firstpos
node
def
firstpos
(
node
)
case
node
when
Nodes
::
Star
firstpos
(
node
.
left
)
when
Nodes
::
Cat
if
nullable?
node
.
left
if
nullable?
(
node
.
left
)
firstpos
(
node
.
left
)
|
firstpos
(
node
.
right
)
else
firstpos
(
node
.
left
)
...
...
@@ -100,14 +100,14 @@ def firstpos node
end
end
def
lastpos
node
def
lastpos
(
node
)
case
node
when
Nodes
::
Star
firstpos
(
node
.
left
)
when
Nodes
::
Or
node
.
children
.
map
{
|
c
|
lastpos
(
c
)
}.
flatten
.
uniq
when
Nodes
::
Cat
if
nullable?
node
.
right
if
nullable?
(
node
.
right
)
lastpos
(
node
.
left
)
|
lastpos
(
node
.
right
)
else
lastpos
(
node
.
right
)
...
...
@@ -121,40 +121,41 @@ def lastpos node
end
end
def
followpos
node
def
followpos
(
node
)
followpos_table
[
node
]
end
private
def
followpos_table
@followpos
||=
build_followpos
end
def
build_followpos
table
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
@ast
.
each
do
|
n
|
case
n
when
Nodes
::
Cat
lastpos
(
n
.
left
).
each
do
|
i
|
table
[
i
]
+=
firstpos
(
n
.
right
)
end
when
Nodes
::
Star
lastpos
(
n
).
each
do
|
i
|
table
[
i
]
+=
firstpos
(
n
)
def
followpos_table
@followpos
||=
build_followpos
end
def
build_followpos
table
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
@ast
.
each
do
|
n
|
case
n
when
Nodes
::
Cat
lastpos
(
n
.
left
).
each
do
|
i
|
table
[
i
]
+=
firstpos
(
n
.
right
)
end
when
Nodes
::
Star
lastpos
(
n
).
each
do
|
i
|
table
[
i
]
+=
firstpos
(
n
)
end
end
end
table
end
table
end
def
symbol
edge
case
edge
when
Journey
::
Nodes
::
Symbol
edge
.
regexp
else
edge
.
left
def
symbol
(
edge
)
case
edge
when
Journey
::
Nodes
::
Symbol
edge
.
regexp
else
edge
.
left
end
end
end
end
end
end
...
...
actionpack/lib/action_dispatch/journey/gtg/simulator.rb
浏览文件 @
3aa327f9
...
...
@@ -6,7 +6,7 @@ module GTG # :nodoc:
class
MatchData
# :nodoc:
attr_reader
:memos
def
initialize
memos
def
initialize
(
memos
)
@memos
=
memos
end
end
...
...
@@ -14,12 +14,12 @@ def initialize memos
class
Simulator
# :nodoc:
attr_reader
:tt
def
initialize
transition_table
def
initialize
(
transition_table
)
@tt
=
transition_table
end
def
simulate
string
input
=
StringScanner
.
new
string
def
simulate
(
string
)
input
=
StringScanner
.
new
(
string
)
state
=
[
0
]
while
sym
=
input
.
scan
(
%r([/.?]|[^/.?]+)
)
state
=
tt
.
move
(
state
,
sym
)
...
...
@@ -31,9 +31,9 @@ def simulate string
return
if
acceptance_states
.
empty?
memos
=
acceptance_states
.
map
{
|
x
|
tt
.
memo
x
}.
flatten
.
compact
memos
=
acceptance_states
.
map
{
|
x
|
tt
.
memo
(
x
)
}.
flatten
.
compact
MatchData
.
new
memos
MatchData
.
new
(
memos
)
end
alias
:
=~
:simulate
...
...
actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
浏览文件 @
3aa327f9
...
...
@@ -15,7 +15,7 @@ def initialize
@memos
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
end
def
add_accepting
state
def
add_accepting
(
state
)
@accepting
[
state
]
=
true
end
...
...
@@ -23,24 +23,24 @@ def accepting_states
@accepting
.
keys
end
def
accepting?
state
def
accepting?
(
state
)
@accepting
[
state
]
end
def
add_memo
idx
,
memo
def
add_memo
(
idx
,
memo
)
@memos
[
idx
]
<<
memo
end
def
memo
idx
def
memo
(
idx
)
@memos
[
idx
]
end
def
eclosure
t
def
eclosure
(
t
)
Array
(
t
)
end
def
move
t
,
a
move_string
(
t
,
a
).
concat
move_regexp
(
t
,
a
)
def
move
(
t
,
a
)
move_string
(
t
,
a
).
concat
(
move_regexp
(
t
,
a
)
)
end
def
to_json
...
...
@@ -55,15 +55,15 @@ def to_json
end
JSON
.
dump
({
:regexp_states
=>
simple_regexp
,
:string_states
=>
@string_states
,
:accepting
=>
@accepting
regexp_states:
simple_regexp
,
string_states:
@string_states
,
accepting:
@accepting
})
end
def
to_svg
svg
=
IO
.
popen
(
"dot -Tsvg"
,
'w+'
)
{
|
f
|
f
.
write
to_dot
svg
=
IO
.
popen
(
'dot -Tsvg'
,
'w+'
)
{
|
f
|
f
.
write
(
to_dot
)
f
.
close_write
f
.
readlines
}
...
...
@@ -71,7 +71,7 @@ def to_svg
svg
.
join
.
sub
(
/width="[^"]*"/
,
''
).
sub
(
/height="[^"]*"/
,
''
)
end
def
visualizer
paths
,
title
=
'FSM'
def
visualizer
(
paths
,
title
=
'FSM'
)
viz_dir
=
File
.
join
File
.
dirname
(
__FILE__
),
'..'
,
'visualizer'
fsm_js
=
File
.
read
File
.
join
(
viz_dir
,
'fsm.js'
)
fsm_css
=
File
.
read
File
.
join
(
viz_dir
,
'fsm.css'
)
...
...
@@ -110,7 +110,7 @@ def visualizer paths, title = 'FSM'
template
.
result
(
binding
)
end
def
[]=
from
,
to
,
sym
def
[]=
(
from
,
to
,
sym
)
case
sym
when
String
@string_states
[
from
][
sym
]
=
to
...
...
@@ -136,19 +136,20 @@ def transitions
end
private
def
move_regexp
t
,
a
return
[]
if
t
.
empty?
t
.
map
{
|
s
|
@regexp_states
[
s
].
map
{
|
re
,
v
|
re
===
a
?
v
:
nil
}
}.
flatten
.
compact
.
uniq
end
def
move_regexp
(
t
,
a
)
return
[]
if
t
.
empty?
def
move_string
t
,
a
return
[]
if
t
.
empty?
t
.
map
{
|
s
|
@regexp_states
[
s
].
map
{
|
re
,
v
|
re
===
a
?
v
:
nil
}
}.
flatten
.
compact
.
uniq
end
t
.
map
{
|
s
|
@string_states
[
s
][
a
]
}.
compact
end
def
move_string
(
t
,
a
)
return
[]
if
t
.
empty?
t
.
map
{
|
s
|
@string_states
[
s
][
a
]
}.
compact
end
end
end
end
...
...
actionpack/lib/action_dispatch/journey/nfa/builder.rb
浏览文件 @
3aa327f9
...
...
@@ -5,23 +5,23 @@ module ActionDispatch
module
Journey
# :nodoc:
module
NFA
# :nodoc:
class
Visitor
<
Visitors
::
Visitor
# :nodoc:
def
initialize
tt
def
initialize
(
tt
)
@tt
=
tt
@i
=
-
1
end
def
visit_CAT
node
left
=
visit
node
.
left
right
=
visit
node
.
right
def
visit_CAT
(
node
)
left
=
visit
(
node
.
left
)
right
=
visit
(
node
.
right
)
@tt
.
merge
left
.
last
,
right
.
first
@tt
.
merge
(
left
.
last
,
right
.
first
)
[
left
.
first
,
right
.
last
]
end
def
visit_GROUP
node
def
visit_GROUP
(
node
)
from
=
@i
+=
1
left
=
visit
node
.
left
left
=
visit
(
node
.
left
)
to
=
@i
+=
1
@tt
.
accepting
=
to
...
...
@@ -33,14 +33,14 @@ def visit_GROUP node
[
from
,
to
]
end
def
visit_OR
node
from
=
@i
+=
1
children
=
node
.
children
.
map
{
|
c
|
visit
c
}
to
=
@i
+=
1
def
visit_OR
(
node
)
from
=
@i
+=
1
children
=
node
.
children
.
map
{
|
c
|
visit
(
c
)
}
to
=
@i
+=
1
children
.
each
do
|
child
|
@tt
[
from
,
child
.
first
]
=
nil
@tt
[
child
.
last
,
to
]
=
nil
@tt
[
from
,
child
.
first
]
=
nil
@tt
[
child
.
last
,
to
]
=
nil
end
@tt
.
accepting
=
to
...
...
@@ -48,26 +48,26 @@ def visit_OR node
[
from
,
to
]
end
def
terminal
node
def
terminal
(
node
)
from_i
=
@i
+=
1
# new state
to_i
=
@i
+=
1
# new state
@tt
[
from_i
,
to_i
]
=
node
@tt
.
accepting
=
to_i
@tt
.
add_memo
to_i
,
node
.
memo
@tt
.
add_memo
(
to_i
,
node
.
memo
)
[
from_i
,
to_i
]
end
end
class
Builder
# :nodoc:
def
initialize
ast
def
initialize
(
ast
)
@ast
=
ast
end
def
transition_table
tt
=
TransitionTable
.
new
Visitor
.
new
(
tt
).
accept
@ast
Visitor
.
new
(
tt
).
accept
(
@ast
)
tt
end
end
...
...
actionpack/lib/action_dispatch/journey/nfa/simulator.rb
浏览文件 @
3aa327f9
...
...
@@ -6,7 +6,7 @@ module NFA # :nodoc:
class
MatchData
# :nodoc:
attr_reader
:memos
def
initialize
memos
def
initialize
(
memos
)
@memos
=
memos
end
end
...
...
@@ -14,29 +14,29 @@ def initialize memos
class
Simulator
# :nodoc:
attr_reader
:tt
def
initialize
transition_table
def
initialize
(
transition_table
)
@tt
=
transition_table
end
def
simulate
string
input
=
StringScanner
.
new
string
state
=
tt
.
eclosure
0
def
simulate
(
string
)
input
=
StringScanner
.
new
(
string
)
state
=
tt
.
eclosure
(
0
)
until
input
.
eos?
sym
=
input
.
scan
(
%r([/.?]|[^/.?]+)
)
# FIXME: tt.eclosure is not needed for the GTG
state
=
tt
.
eclosure
tt
.
move
(
state
,
sym
)
state
=
tt
.
eclosure
(
tt
.
move
(
state
,
sym
)
)
end
acceptance_states
=
state
.
find_all
{
|
s
|
tt
.
accepting?
tt
.
eclosure
(
s
).
sort
.
last
tt
.
accepting?
(
tt
.
eclosure
(
s
).
sort
.
last
)
}
return
if
acceptance_states
.
empty?
memos
=
acceptance_states
.
map
{
|
x
|
tt
.
memo
x
}.
flatten
.
compact
memos
=
acceptance_states
.
map
{
|
x
|
tt
.
memo
(
x
)
}.
flatten
.
compact
MatchData
.
new
memos
MatchData
.
new
(
memos
)
end
alias
:
=~
:simulate
...
...
actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
浏览文件 @
3aa327f9
...
...
@@ -16,7 +16,7 @@ def initialize
@inverted
=
nil
end
def
accepting?
state
def
accepting?
(
state
)
accepting
==
state
end
...
...
@@ -24,20 +24,20 @@ def accepting_states
[
accepting
]
end
def
add_memo
idx
,
memo
def
add_memo
(
idx
,
memo
)
@memos
[
idx
]
=
memo
end
def
memo
idx
def
memo
(
idx
)
@memos
[
idx
]
end
def
[]=
i
,
f
,
s
def
[]=
(
i
,
f
,
s
)
@table
[
f
][
i
]
=
s
end
def
merge
left
,
right
@memos
[
right
]
=
@memos
.
delete
left
def
merge
(
left
,
right
)
@memos
[
right
]
=
@memos
.
delete
(
left
)
@table
[
right
]
=
@table
.
delete
(
left
)
end
...
...
@@ -45,11 +45,10 @@ def states
(
@table
.
keys
+
@table
.
values
.
map
(
&
:keys
).
flatten
).
uniq
end
###
# Returns a generalized transition graph with reduced states. The states
# Returns a generalized transition graph with reduced states. The states
# are reduced like a DFA, but the table must be simulated like an NFA.
#
# Edges of the GTG are regular expressions
# Edges of the GTG are regular expressions
.
def
generalized_table
gt
=
GTG
::
TransitionTable
.
new
marked
=
{}
...
...
@@ -80,28 +79,26 @@ def generalized_table
final_groups
.
each
do
|
states
|
id
=
state_id
[
states
]
gt
.
add_accepting
id
gt
.
add_accepting
(
id
)
save
=
states
.
find
{
|
s
|
@memos
.
key?
(
s
)
&&
eclosure
(
s
).
sort
.
last
==
accepting
}
gt
.
add_memo
id
,
memo
(
save
)
gt
.
add_memo
(
id
,
memo
(
save
)
)
end
gt
end
###
# Returns set of NFA states to which there is a transition on ast symbol
# +a+ from some state +s+ in +t+.
def
following_states
t
,
a
def
following_states
(
t
,
a
)
Array
(
t
).
map
{
|
s
|
inverted
[
s
][
a
]
}.
flatten
.
uniq
end
###
# Returns set of NFA states to which there is a transition on ast symbol
# +a+ from some state +s+ in +t+.
def
move
t
,
a
def
move
(
t
,
a
)
Array
(
t
).
map
{
|
s
|
inverted
[
s
].
keys
.
compact
.
find_all
{
|
sym
|
sym
===
a
...
...
@@ -113,10 +110,9 @@ def alphabet
inverted
.
values
.
map
(
&
:keys
).
flatten
.
compact
.
uniq
.
sort_by
{
|
x
|
x
.
to_s
}
end
###
# Returns a set of NFA states reachable from some NFA state +s+ in set
# +t+ on nil-transitions alone.
def
eclosure
t
def
eclosure
(
t
)
stack
=
Array
(
t
)
seen
=
{}
children
=
[]
...
...
@@ -128,7 +124,7 @@ def eclosure t
seen
[
s
]
=
true
children
<<
s
stack
.
concat
inverted
[
s
][
nil
]
stack
.
concat
(
inverted
[
s
][
nil
])
end
children
.
uniq
...
...
@@ -141,26 +137,27 @@ def transitions
end
private
def
inverted
return
@inverted
if
@inverted
@inverted
=
Hash
.
new
{
|
h
,
from
|
h
[
from
]
=
Hash
.
new
{
|
j
,
s
|
j
[
s
]
=
[]
}
}
def
inverted
return
@inverted
if
@inverted
@inverted
=
Hash
.
new
{
|
h
,
from
|
h
[
from
]
=
Hash
.
new
{
|
j
,
s
|
j
[
s
]
=
[]
}
}
@table
.
each
{
|
to
,
hash
|
hash
.
each
{
|
from
,
sym
|
if
sym
sym
=
Nodes
::
Symbol
===
sym
?
sym
.
regexp
:
sym
.
left
end
@table
.
each
{
|
to
,
hash
|
hash
.
each
{
|
from
,
sym
|
if
sym
sym
=
Nodes
::
Symbol
===
sym
?
sym
.
regexp
:
sym
.
left
end
@inverted
[
from
][
sym
]
<<
to
@inverted
[
from
][
sym
]
<<
to
}
}
}
@inverted
@inverted
end
end
end
end
end
end
actionpack/lib/action_dispatch/journey/nodes/node.rb
浏览文件 @
3aa327f9
...
...
@@ -8,7 +8,7 @@ class Node # :nodoc:
attr_accessor
:left
,
:memo
def
initialize
left
def
initialize
(
left
)
@left
=
left
@memo
=
nil
end
...
...
@@ -51,7 +51,7 @@ def type; :LITERAL; end
end
class
Dummy
<
Literal
# :nodoc:
def
initialize
x
=
Object
.
new
def
initialize
(
x
=
Object
.
new
)
super
end
...
...
@@ -71,7 +71,7 @@ class Symbol < Terminal # :nodoc:
alias
:symbol
:regexp
DEFAULT_EXP
=
/[^\.\/\?]+/
def
initialize
left
def
initialize
(
left
)
super
@regexp
=
DEFAULT_EXP
end
...
...
@@ -98,7 +98,7 @@ def type; :STAR; end
class
Binary
<
Node
# :nodoc:
attr_accessor
:right
def
initialize
left
,
right
def
initialize
(
left
,
right
)
super
(
left
)
@right
=
right
end
...
...
@@ -113,7 +113,7 @@ def type; :CAT; end
class
Or
<
Node
# :nodoc:
attr_reader
:children
def
initialize
children
def
initialize
(
children
)
@children
=
children
end
...
...
actionpack/lib/action_dispatch/journey/parser_extras.rb
浏览文件 @
3aa327f9
...
...
@@ -10,8 +10,8 @@ def initialize
@scanner
=
Scanner
.
new
end
def
parse
string
@scanner
.
scan_setup
string
def
parse
(
string
)
@scanner
.
scan_setup
(
string
)
do_parse
end
...
...
actionpack/lib/action_dispatch/journey/path/pattern.rb
浏览文件 @
3aa327f9
...
...
@@ -4,18 +4,18 @@ module Path # :nodoc:
class
Pattern
# :nodoc:
attr_reader
:spec
,
:requirements
,
:anchored
def
initialize
strexp
def
initialize
(
strexp
)
parser
=
Journey
::
Parser
.
new
@anchored
=
true
case
strexp
when
String
@spec
=
parser
.
parse
strexp
@spec
=
parser
.
parse
(
strexp
)
@requirements
=
{}
@separators
=
"/.?"
when
Router
::
Strexp
@spec
=
parser
.
parse
strexp
.
path
@spec
=
parser
.
parse
(
strexp
.
path
)
@requirements
=
strexp
.
requirements
@separators
=
strexp
.
separators
.
join
@anchored
=
strexp
.
anchor
...
...
@@ -61,20 +61,20 @@ def optional_names
class
RegexpOffsets
<
Journey
::
Visitors
::
Visitor
# :nodoc:
attr_reader
:offsets
def
initialize
matchers
def
initialize
(
matchers
)
@matchers
=
matchers
@capture_count
=
[
0
]
end
def
visit
node
def
visit
(
node
)
super
@capture_count
end
def
visit_SYMBOL
node
def
visit_SYMBOL
(
node
)
node
=
node
.
to_sym
if
@matchers
.
key?
node
if
@matchers
.
key?
(
node
)
re
=
/
#{
@matchers
[
node
]
}
|/
@capture_count
.
push
((
re
.
match
(
''
).
length
-
1
)
+
(
@capture_count
.
last
||
0
))
else
...
...
@@ -84,51 +84,51 @@ def visit_SYMBOL node
end
class
AnchoredRegexp
<
Journey
::
Visitors
::
Visitor
# :nodoc:
def
initialize
separator
,
matchers
def
initialize
(
separator
,
matchers
)
@separator
=
separator
@matchers
=
matchers
@separator_re
=
"([^
#{
separator
}
]+)"
super
()
end
def
accept
node
def
accept
(
node
)
%r{
\A
#{
visit
node
}
\Z
}
end
def
visit_CAT
node
def
visit_CAT
(
node
)
[
visit
(
node
.
left
),
visit
(
node
.
right
)].
join
end
def
visit_SYMBOL
node
def
visit_SYMBOL
(
node
)
node
=
node
.
to_sym
return
@separator_re
unless
@matchers
.
key?
node
return
@separator_re
unless
@matchers
.
key?
(
node
)
re
=
@matchers
[
node
]
"(
#{
re
}
)"
end
def
visit_GROUP
node
def
visit_GROUP
(
node
)
"(?:
#{
visit
node
.
left
}
)?"
end
def
visit_LITERAL
node
Regexp
.
escape
node
.
left
def
visit_LITERAL
(
node
)
Regexp
.
escape
(
node
.
left
)
end
alias
:visit_DOT
:visit_LITERAL
def
visit_SLASH
node
def
visit_SLASH
(
node
)
node
.
left
end
def
visit_STAR
node
def
visit_STAR
(
node
)
re
=
@matchers
[
node
.
left
.
to_sym
]
||
'.+'
"(
#{
re
}
)"
end
end
class
UnanchoredRegexp
<
AnchoredRegexp
# :nodoc:
def
accept
node
def
accept
(
node
)
%r{
\A
#{
visit
node
}
}
end
end
...
...
@@ -136,7 +136,7 @@ def accept node
class
MatchData
# :nodoc:
attr_reader
:names
def
initialize
names
,
offsets
,
match
def
initialize
(
names
,
offsets
,
match
)
@names
=
names
@offsets
=
offsets
@match
=
match
...
...
@@ -146,7 +146,7 @@ def captures
(
length
-
1
).
times
.
map
{
|
i
|
self
[
i
+
1
]
}
end
def
[]
x
def
[]
(
x
)
idx
=
@offsets
[
x
-
1
]
+
x
@match
[
idx
]
end
...
...
@@ -164,9 +164,9 @@ def to_s
end
end
def
match
other
def
match
(
other
)
return
unless
match
=
to_regexp
.
match
(
other
)
MatchData
.
new
names
,
offsets
,
match
MatchData
.
new
(
names
,
offsets
,
match
)
end
alias
:
=~
:match
...
...
@@ -179,16 +179,17 @@ def to_regexp
end
private
def
regexp_visitor
@anchored
?
AnchoredRegexp
:
UnanchoredRegexp
end
def
offsets
return
@offsets
if
@offsets
def
regexp_visitor
@anchored
?
AnchoredRegexp
:
UnanchoredRegexp
end
viz
=
RegexpOffsets
.
new
@requirements
@offsets
=
viz
.
accept
spec
end
def
offsets
return
@offsets
if
@offsets
viz
=
RegexpOffsets
.
new
(
@requirements
)
@offsets
=
viz
.
accept
(
spec
)
end
end
end
end
...
...
actionpack/lib/action_dispatch/journey/route.rb
浏览文件 @
3aa327f9
...
...
@@ -11,7 +11,7 @@ class Route # :nodoc:
##
# +path+ is a path constraint.
# +constraints+ is a hash of constraints to be applied to this route.
def
initialize
name
,
app
,
path
,
constraints
,
defaults
=
{}
def
initialize
(
name
,
app
,
path
,
constraints
,
defaults
=
{})
constraints
=
constraints
.
dup
@name
=
name
@app
=
app
...
...
@@ -52,7 +52,7 @@ def required_keys
path
.
required_names
.
map
{
|
x
|
x
.
to_sym
}
+
required_defaults
.
keys
end
def
score
constraints
def
score
(
constraints
)
required_keys
=
path
.
required_names
supplied_keys
=
constraints
.
map
{
|
k
,
v
|
v
&&
k
.
to_s
}.
compact
...
...
@@ -67,7 +67,7 @@ def parts
end
alias
:segment_keys
:parts
def
format
path_options
def
format
(
path_options
)
path_options
.
delete_if
do
|
key
,
value
|
value
.
to_s
==
defaults
[
key
].
to_s
&&
!
required_parts
.
include?
(
key
)
end
...
...
@@ -86,7 +86,7 @@ def required_parts
def
required_defaults
@required_defaults
||=
begin
matches
=
parts
@defaults
.
dup
.
delete_if
{
|
k
,
_
|
matches
.
include?
k
}
@defaults
.
dup
.
delete_if
{
|
k
,
_
|
matches
.
include?
(
k
)
}
end
end
end
...
...
actionpack/lib/action_dispatch/journey/router.rb
浏览文件 @
3aa327f9
...
...
@@ -22,7 +22,7 @@ class RoutingError < ::StandardError # :nodoc:
class
NullReq
# :nodoc:
attr_reader
:env
def
initialize
env
def
initialize
(
env
)
@env
=
env
end
...
...
@@ -44,15 +44,15 @@ def [](k); env[k]; end
attr_reader
:request_class
,
:formatter
attr_accessor
:routes
def
initialize
routes
,
options
def
initialize
(
routes
,
options
)
@options
=
options
@params_key
=
options
[
:parameters_key
]
@request_class
=
options
[
:request_class
]
||
NullReq
@routes
=
routes
end
def
call
env
env
[
'PATH_INFO'
]
=
Utils
.
normalize_path
env
[
'PATH_INFO'
]
def
call
(
env
)
env
[
'PATH_INFO'
]
=
Utils
.
normalize_path
(
env
[
'PATH_INFO'
])
find_routes
(
env
).
each
do
|
match
,
parameters
,
route
|
script_name
,
path_info
,
set_params
=
env
.
values_at
(
'SCRIPT_NAME'
,
...
...
@@ -81,7 +81,7 @@ def call env
return
[
404
,
{
'X-Cascade'
=>
'pass'
},
[
'Not Found'
]]
end
def
recognize
req
def
recognize
(
req
)
find_routes
(
req
.
env
).
each
do
|
match
,
parameters
,
route
|
unless
route
.
path
.
anchored
req
.
env
[
'SCRIPT_NAME'
]
=
match
.
to_s
...
...
@@ -96,73 +96,73 @@ def visualizer
tt
=
GTG
::
Builder
.
new
(
ast
).
transition_table
groups
=
partitioned_routes
.
first
.
map
(
&
:ast
).
group_by
{
|
a
|
a
.
to_s
}
asts
=
groups
.
values
.
map
{
|
v
|
v
.
first
}
tt
.
visualizer
asts
tt
.
visualizer
(
asts
)
end
private
def
partitioned_routes
routes
.
partitioned_routes
end
def
partitioned_routes
routes
.
partitioned_routes
end
def
ast
routes
.
ast
end
def
ast
routes
.
ast
end
def
simulator
routes
.
simulator
end
def
simulator
routes
.
simulator
end
def
custom_routes
partitioned_routes
.
last
end
def
custom_routes
partitioned_routes
.
last
end
def
filter_routes
path
return
[]
unless
ast
data
=
simulator
.
match
(
path
)
data
?
data
.
memos
:
[]
end
def
filter_routes
(
path
)
return
[]
unless
ast
data
=
simulator
.
match
(
path
)
data
?
data
.
memos
:
[]
end
def
find_routes
env
req
=
request_class
.
new
env
def
find_routes
env
req
=
request_class
.
new
(
env
)
routes
=
filter_routes
(
req
.
path_info
).
concat
custom_routes
.
find_all
{
|
r
|
r
.
path
.
match
(
req
.
path_info
)
}
routes
.
concat
get_routes_as_head
(
routes
)
routes
=
filter_routes
(
req
.
path_info
).
concat
custom_routes
.
find_all
{
|
r
|
r
.
path
.
match
(
req
.
path_info
)
}
routes
.
concat
get_routes_as_head
(
routes
)
routes
.
sort_by!
(
&
:precedence
).
select!
{
|
r
|
r
.
constraints
.
all?
{
|
k
,
v
|
v
===
req
.
send
(
k
)
}
&&
r
.
verb
===
req
.
request_method
}
routes
.
reject!
{
|
r
|
req
.
ip
&&
!
(
r
.
ip
===
req
.
ip
)
}
routes
.
sort_by!
(
&
:precedence
).
select!
{
|
r
|
r
.
constraints
.
all?
{
|
k
,
v
|
v
===
req
.
send
(
k
)
}
&&
r
.
verb
===
req
.
request_method
}
routes
.
reject!
{
|
r
|
req
.
ip
&&
!
(
r
.
ip
===
req
.
ip
)
}
routes
.
map!
{
|
r
|
match_data
=
r
.
path
.
match
(
req
.
path_info
)
match_names
=
match_data
.
names
.
map
{
|
n
|
n
.
to_sym
}
match_values
=
match_data
.
captures
.
map
{
|
v
|
v
&&
Utils
.
unescape_uri
(
v
)
}
info
=
Hash
[
match_names
.
zip
(
match_values
).
find_all
{
|
_
,
y
|
y
}]
routes
.
map!
{
|
r
|
match_data
=
r
.
path
.
match
(
req
.
path_info
)
match_names
=
match_data
.
names
.
map
{
|
n
|
n
.
to_sym
}
match_values
=
match_data
.
captures
.
map
{
|
v
|
v
&&
Utils
.
unescape_uri
(
v
)
}
info
=
Hash
[
match_names
.
zip
(
match_values
).
find_all
{
|
_
,
y
|
y
}]
[
match_data
,
r
.
defaults
.
merge
(
info
),
r
]
}
end
[
match_data
,
r
.
defaults
.
merge
(
info
),
r
]
}
end
def
get_routes_as_head
(
routes
)
precedence
=
(
routes
.
map
(
&
:precedence
).
max
||
0
)
+
1
routes
=
routes
.
select
{
|
r
|
r
.
verb
===
"GET"
&&
!
(
r
.
verb
===
"HEAD"
)
}.
map!
{
|
r
|
Route
.
new
(
r
.
name
,
r
.
app
,
r
.
path
,
r
.
conditions
.
merge
(
:request_method
=>
"HEAD"
),
r
.
defaults
).
tap
do
|
route
|
route
.
precedence
=
r
.
precedence
+
precedence
end
}
routes
.
flatten!
routes
end
def
get_routes_as_head
(
routes
)
precedence
=
(
routes
.
map
(
&
:precedence
).
max
||
0
)
+
1
routes
=
routes
.
select
{
|
r
|
r
.
verb
===
"GET"
&&
!
(
r
.
verb
===
"HEAD"
)
}.
map!
{
|
r
|
Route
.
new
(
r
.
name
,
r
.
app
,
r
.
path
,
r
.
conditions
.
merge
(
request_method:
"HEAD"
),
r
.
defaults
).
tap
do
|
route
|
route
.
precedence
=
r
.
precedence
+
precedence
end
}
routes
.
flatten!
routes
end
end
end
end
actionpack/lib/action_dispatch/journey/router/strexp.rb
浏览文件 @
3aa327f9
...
...
@@ -8,7 +8,7 @@ class << self
attr_reader
:path
,
:requirements
,
:separators
,
:anchor
def
initialize
path
,
requirements
,
separators
,
anchor
=
true
def
initialize
(
path
,
requirements
,
separators
,
anchor
=
true
)
@path
=
path
@requirements
=
requirements
@separators
=
separators
...
...
actionpack/lib/action_dispatch/journey/routes.rb
浏览文件 @
3aa327f9
...
...
@@ -50,12 +50,11 @@ def simulator
return
@simulator
if
@simulator
gtg
=
GTG
::
Builder
.
new
(
ast
).
transition_table
@simulator
=
GTG
::
Simulator
.
new
gtg
@simulator
=
GTG
::
Simulator
.
new
(
gtg
)
end
###
# Add a route to the routing table.
def
add_route
app
,
path
,
conditions
,
defaults
,
name
=
nil
def
add_route
(
app
,
path
,
conditions
,
defaults
,
name
=
nil
)
route
=
Route
.
new
(
name
,
app
,
path
,
conditions
,
defaults
)
route
.
precedence
=
routes
.
length
...
...
@@ -66,11 +65,12 @@ def add_route app, path, conditions, defaults, name = nil
end
private
def
clear_cache!
@ast
=
nil
@partitioned_routes
=
nil
@simulator
=
nil
end
def
clear_cache!
@ast
=
nil
@partitioned_routes
=
nil
@simulator
=
nil
end
end
end
end
actionpack/lib/action_dispatch/journey/scanner.rb
浏览文件 @
3aa327f9
...
...
@@ -7,8 +7,8 @@ def initialize
@ss
=
nil
end
def
scan_setup
str
@ss
=
StringScanner
.
new
str
def
scan_setup
(
str
)
@ss
=
StringScanner
.
new
(
str
)
end
def
eos?
...
...
@@ -31,30 +31,31 @@ def next_token
end
private
def
scan
case
# /
when
text
=
@ss
.
scan
(
/\//
)
[
:SLASH
,
text
]
when
text
=
@ss
.
scan
(
/\*\w+/
)
[
:STAR
,
text
]
when
text
=
@ss
.
scan
(
/\(/
)
[
:LPAREN
,
text
]
when
text
=
@ss
.
scan
(
/\)/
)
[
:RPAREN
,
text
]
when
text
=
@ss
.
scan
(
/\|/
)
[
:OR
,
text
]
when
text
=
@ss
.
scan
(
/\./
)
[
:DOT
,
text
]
when
text
=
@ss
.
scan
(
/:\w+/
)
[
:SYMBOL
,
text
]
when
text
=
@ss
.
scan
(
/[\w%\-~]+/
)
[
:LITERAL
,
text
]
# any char
when
text
=
@ss
.
scan
(
/./
)
[
:LITERAL
,
text
]
def
scan
case
# /
when
text
=
@ss
.
scan
(
/\//
)
[
:SLASH
,
text
]
when
text
=
@ss
.
scan
(
/\*\w+/
)
[
:STAR
,
text
]
when
text
=
@ss
.
scan
(
/\(/
)
[
:LPAREN
,
text
]
when
text
=
@ss
.
scan
(
/\)/
)
[
:RPAREN
,
text
]
when
text
=
@ss
.
scan
(
/\|/
)
[
:OR
,
text
]
when
text
=
@ss
.
scan
(
/\./
)
[
:DOT
,
text
]
when
text
=
@ss
.
scan
(
/:\w+/
)
[
:SYMBOL
,
text
]
when
text
=
@ss
.
scan
(
/[\w%\-~]+/
)
[
:LITERAL
,
text
]
# any char
when
text
=
@ss
.
scan
(
/./
)
[
:LITERAL
,
text
]
end
end
end
end
end
end
actionpack/lib/action_dispatch/journey/visitors.rb
浏览文件 @
3aa327f9
...
...
@@ -7,69 +7,70 @@ class Visitor # :nodoc:
h
[
k
]
=
"visit_
#{
k
}
"
}
def
accept
node
visit
node
def
accept
(
node
)
visit
(
node
)
end
private
def
visit
node
send
DISPATCH_CACHE
[
node
.
type
],
node
end
def
binary
node
visit
node
.
left
visit
node
.
right
end
def
visit_CAT
(
n
);
binary
(
n
);
end
def
visit
node
send
(
DISPATCH_CACHE
[
node
.
type
],
node
)
end
def
nary
node
node
.
children
.
each
{
|
c
|
visit
c
}
end
def
visit_OR
(
n
);
nary
(
n
);
end
def
binary
(
node
)
visit
(
node
.
left
)
visit
(
node
.
right
)
end
def
visit_CAT
(
n
);
binary
(
n
);
end
def
unary
node
visit
node
.
left
end
def
visit_GROUP
(
n
);
unary
(
n
);
end
def
visit_STAR
(
n
);
unary
(
n
);
end
def
nary
(
node
)
node
.
children
.
each
{
|
c
|
visit
(
c
)
}
end
def
visit_OR
(
n
);
nary
(
n
);
end
def
terminal
node
;
end
%w{ LITERAL SYMBOL SLASH DOT }
.
each
do
|
t
|
class_eval
%{ def visit_#{t}(n); terminal(n); end }
,
__FILE__
,
__LINE__
end
def
unary
(
node
)
visit
(
node
.
left
)
end
def
visit_GROUP
(
n
);
unary
(
n
);
end
def
visit_STAR
(
n
);
unary
(
n
);
end
def
terminal
(
node
);
end
%w{ LITERAL SYMBOL SLASH DOT }
.
each
do
|
t
|
class_eval
%{ def visit_#{t}(n); terminal(n); end }
,
__FILE__
,
__LINE__
end
end
# Loop through the requirements AST
class
Each
<
Visitor
# :nodoc:
attr_reader
:block
def
initialize
block
def
initialize
(
block
)
@block
=
block
end
def
visit
node
def
visit
(
node
)
super
block
.
call
node
block
.
call
(
node
)
end
end
class
String
<
Visitor
# :nodoc:
private
def
binary
node
def
binary
(
node
)
[
visit
(
node
.
left
),
visit
(
node
.
right
)].
join
end
def
nary
node
node
.
children
.
map
{
|
c
|
visit
c
}.
join
'|'
def
nary
(
node
)
node
.
children
.
map
{
|
c
|
visit
(
c
)
}.
join
'|'
end
def
terminal
node
def
terminal
(
node
)
node
.
left
end
def
visit_GROUP
node
"(
#{
visit
node
.
left
}
)"
def
visit_GROUP
(
node
)
"(
#{
visit
(
node
.
left
)
}
)"
end
end
...
...
@@ -77,43 +78,44 @@ def visit_GROUP node
class
Formatter
<
Visitor
# :nodoc:
attr_reader
:options
,
:consumed
def
initialize
options
def
initialize
(
options
)
@options
=
options
@consumed
=
{}
end
private
def
visit_GROUP
node
if
consumed
==
options
nil
else
route
=
visit
node
.
left
route
.
include?
(
"
\0
"
)
?
nil
:
route
def
visit_GROUP
(
node
)
if
consumed
==
options
nil
else
route
=
visit
(
node
.
left
)
route
.
include?
(
"
\0
"
)
?
nil
:
route
end
end
end
def
terminal
node
node
.
left
end
def
terminal
(
node
)
node
.
left
end
def
binary
node
[
visit
(
node
.
left
),
visit
(
node
.
right
)].
join
end
def
binary
(
node
)
[
visit
(
node
.
left
),
visit
(
node
.
right
)].
join
end
def
nary
node
node
.
children
.
map
{
|
c
|
visit
c
}.
join
end
def
nary
(
node
)
node
.
children
.
map
{
|
c
|
visit
(
c
)
}.
join
end
def
visit_SYMBOL
node
key
=
node
.
to_sym
def
visit_SYMBOL
(
node
)
key
=
node
.
to_sym
if
value
=
options
[
key
]
consumed
[
key
]
=
value
Router
::
Utils
.
escape_path
(
value
)
else
"
\0
"
if
value
=
options
[
key
]
consumed
[
key
]
=
value
Router
::
Utils
.
escape_path
(
value
)
else
"
\0
"
end
end
end
end
class
Dot
<
Visitor
# :nodoc:
...
...
@@ -122,7 +124,7 @@ def initialize
@edges
=
[]
end
def
accept
node
def
accept
(
node
)
super
<<-
eodot
digraph parse_tree {
...
...
@@ -136,50 +138,51 @@ def accept node
end
private
def
binary
node
node
.
children
.
each
do
|
c
|
@edges
<<
"
#{
node
.
object_id
}
->
#{
c
.
object_id
}
;"
def
binary
(
node
)
node
.
children
.
each
do
|
c
|
@edges
<<
"
#{
node
.
object_id
}
->
#{
c
.
object_id
}
;"
end
super
end
super
end
def
nary
node
node
.
children
.
each
do
|
c
|
@edges
<<
"
#{
node
.
object_id
}
->
#{
c
.
object_id
}
;"
def
nary
(
node
)
node
.
children
.
each
do
|
c
|
@edges
<<
"
#{
node
.
object_id
}
->
#{
c
.
object_id
}
;"
end
super
end
super
end
def
unary
node
@edges
<<
"
#{
node
.
object_id
}
->
#{
node
.
left
.
object_id
}
;"
super
end
def
unary
(
node
)
@edges
<<
"
#{
node
.
object_id
}
->
#{
node
.
left
.
object_id
}
;"
super
end
def
visit_GROUP
node
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
()
\"
];"
super
end
def
visit_GROUP
(
node
)
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
()
\"
];"
super
end
def
visit_CAT
node
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
○
\"
];"
super
end
def
visit_CAT
(
node
)
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
○
\"
];"
super
end
def
visit_STAR
node
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
*
\"
];"
super
end
def
visit_STAR
(
node
)
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
*
\"
];"
super
end
def
visit_OR
node
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
|
\"
];"
super
end
def
visit_OR
(
node
)
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
|
\"
];"
super
end
def
terminal
node
value
=
node
.
left
def
terminal
(
node
)
value
=
node
.
left
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
#{
value
}
\"
];"
end
@nodes
<<
"
#{
node
.
object_id
}
[label=
\"
#{
value
}
\"
];"
end
end
end
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录