Más contenido relacionado Similar a RubyConf Argentina 2011 (20) Más de Aaron Patterson (8) RubyConf Argentina 201134. graph.dot
digraph nfa {
rankdir=LR;
world [shape = doublecircle];
hello [shape = circle];
hello -> world [label="greeting"];
}
35. graph.dot
digraph nfa {
rankdir=LR;
world [shape = doublecircle];
hello [shape = circle];
goodbye [shape = circle];
hello -> world [label="greeting"];
goodbye -> world
}
36. hello
greeting
world
goodbye
37. /articles(.:format)
/ articles . (?-mix:[^./?]+)
0 1 2 3 5
/
new
4 6 /articles/new(.:format)
40. Provides
1: URL generation
2: Path Recognition
3: Route parsing
What is a router?
80. ○ Describe node types
○ b
○ b
a *
()
|
a b
83. ○
○ ()
/ articles ○
. :format
84. To String!
parser = Journey::Parser.new
ast = parser.parse '/articles(.:format)'
puts ast.to_s
puts ast.to_regexp
85. OR AST
parser = Journey::Parser.new
trees = [
'/articles(.:format)',
'/articles/new(.:format)',
].map { |s| parser.parse s }
ast = Journey::Nodes::Or.new trees
puts ast.to_dot
86. |
○ ○
○ () ○ ()
/ articles ○ ○ new ○
. :format ○ / . :format
/ articles
93. b a
a b
b 0 1 a
a 2
3
b
94. b
b a
a b
b 0 1 a
a 2
3
b
95. ba
b a
a b
b 0 1 a
a 2
3
b
96. baa
b a
a b
b 0 1 a
a 2
3
b
97. baabb
b a
a b
b 0 1 a
a 2
3
b
98. aab
b a
a b
b 0 1 a
a 2
3
b
101. Storage
class DFA
attr_reader :table
def initialize
@table = Hash.new { |h, from| h[from] = {} }
@table[0]['a'] = 1
@table[0]['b'] = 0
@table[1]['a'] = 1
@table[1]['b'] = 2
@table[2]['a'] = 1
@table[2]['b'] = 3
@table[3]['b'] = 0
@table[3]['a'] = 2
end
end
103. class Simulator
def initialize(dfa)
@dfa = dfa
end
def simulate(symbols)
state = 0
until symbols.empty?
state = @dfa.move(state, symbols.shift)
end
state
end
end
105. irb> sim = Simulator.new(DFA.new)
=> #<Simulator:0x007f95929a82e0 ...>
irb> sim.simulate %w{ b a a b b }
=> 3
irb> sim.simulate %w{ a a b }
=> 2
108. Space: S + T
states.length + transitions.length
113. a|b
a
ε 2 3 ε
0 ε ε 6
b
4 5
115. a
a
ε 2 3 ε
0 ε ε 6
b
4 5
116. Storage
class NFA
def initialize
@table = Hash.new { |h, from|
h[from] = Hash.new { |i,sym| i[sym] = [] }
}
@table[0][nil] << 2
@table[0][nil] << 4
@table[2]['a'] << 3
@table[4]['b'] << 5
@table[3][nil] << 6
@table[5][nil] << 6
end
def nil_closure(states)
states.map { |s| @table[s][nil] }.flatten
end
end
117. FSM Simulation
class Simulator
def initialize(nfa)
@nfa = nfa
end
def simulate(symbols)
states = @nfa.nil_closure([0])
until symbols.empty?
next_s = @nfa.move(states, symbols.shift)
states = @nfa.nil_closure(next_s)
end
states
end
end
119. irb> sim = Simulator.new(NFA.new)
=> #<Simulator:0x007faa188a5f88 ...>
irb> sim.simulate %w{ a }
=> [6]
irb> sim.simulate %w{ b }
=> [6]
irb> sim.simulate %w{ b b }
=> []
irb> sim.simulate %w{ c }
=> []
120. Time: O(r ⨉ x)
r = operators.length, x = string.length
127. ε
/ articles
0 1 2 ε ε 6
. :format
3 4 5
135. SHORTER CODES!
parser = Journey::Parser.new
ast = parser.parse '/articles(.:format)'
dfa = Journey::GTG::Builder.new ast
tt = dfa.transition_table
puts tt.to_dot
137. O(r ⨉ x) => O(x)
r = operations.length, x = string.length
146. resource :users
(?-mix:[^./?]+)
. 3 5
/ users
0 1 2 /
new . (?-mix:[^./?]+)
4 6 8 11
(?-mix:[^./?]+)
/ edit . (?-mix:[^./?]+)
7 9 12 14 15
.
(?-mix:[^./?]+)
10 13
153. Table => JSON
parser = Journey::Parser.new
ast = parser.parse '/articles(.:format)'
dfa = Journey::GTG::Builder.new ast
tt = dfa.transition_table
puts tt.to_json
154. Table => SVG
parser = Journey::Parser.new
ast = parser.parse '/articles(.:format)'
dfa = Journey::GTG::Builder.new ast
tt = dfa.transition_table
puts tt.to_svg
156. JS Simulator
tokenize(input, function(token) {
var new_states = [];
for(var key in states) {
var state = states[key];
if(string_states[state] && string_states[state][token]) {
var new_state = string_states[state][token];
highlight_edge(state, new_state);
highlight_state(new_state);
new_states.push(new_state);
}
}
if(new_states.length == 0) {
return;
}
states = new_states;
});