Top Banner
Who makes the best Asado?
180

RubyConf Argentina 2011

Jun 29, 2015

Download

Technology

Aaron Patterson

RubyConf Argentina 2011
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: RubyConf Argentina 2011

Who makes the best Asado?

Page 2: RubyConf Argentina 2011
Page 3: RubyConf Argentina 2011
Page 4: RubyConf Argentina 2011
Page 5: RubyConf Argentina 2011
Page 6: RubyConf Argentina 2011
Page 7: RubyConf Argentina 2011
Page 8: RubyConf Argentina 2011

What country has the best footballers?

Page 9: RubyConf Argentina 2011
Page 10: RubyConf Argentina 2011

Argentina!

Page 11: RubyConf Argentina 2011

river

Page 12: RubyConf Argentina 2011

Nacional B???

river

Page 13: RubyConf Argentina 2011
Page 14: RubyConf Argentina 2011

NOOOOOOOO!!!!

Page 15: RubyConf Argentina 2011

Aaron Patterson

Page 16: RubyConf Argentina 2011

@tenderlove

Page 17: RubyConf Argentina 2011

Ruby core team

Page 18: RubyConf Argentina 2011

Rails core team

Page 19: RubyConf Argentina 2011

! WARNING !

Page 20: RubyConf Argentina 2011

ZOMG!

Page 21: RubyConf Argentina 2011

We are in Argentina!

Page 22: RubyConf Argentina 2011
Page 23: RubyConf Argentina 2011

YoJosé

Page 24: RubyConf Argentina 2011

WWFMD?

Page 25: RubyConf Argentina 2011

me gusta

Page 26: RubyConf Argentina 2011

¿Por qué Maria?

Page 27: RubyConf Argentina 2011

THANKS!!

Page 28: RubyConf Argentina 2011
Page 29: RubyConf Argentina 2011

ResourceManagement

Page 30: RubyConf Argentina 2011

Path Management

Page 31: RubyConf Argentina 2011

PatternMatching

Move between theory and practice

Page 32: RubyConf Argentina 2011

Graphvizhttp://graphviz.org

Page 33: RubyConf Argentina 2011

worldhello greeting

Page 34: RubyConf Argentina 2011

digraph nfa { rankdir=LR;

world [shape = doublecircle]; hello [shape = circle]; hello -> world [label="greeting"];}

graph.dot

Page 35: RubyConf Argentina 2011

digraph nfa { rankdir=LR;

world [shape = doublecircle]; hello [shape = circle]; goodbye [shape = circle];

hello -> world [label="greeting"]; goodbye -> world}

graph.dot

Page 36: RubyConf Argentina 2011

world

hellogreeting

goodbye

Page 37: RubyConf Argentina 2011

2 3.

4

/

/articles(.:format)

5

6 /articles/new(.:format)

0 1/ articles (?-mix:[^./?]+)

new

Page 38: RubyConf Argentina 2011

Journey

Page 39: RubyConf Argentina 2011

JourneyYes, it's named after the '70s rock sensation

Page 40: RubyConf Argentina 2011

What is a router?

Provides1: URL generation2: Path Recognition3: Route parsing

Page 41: RubyConf Argentina 2011

Why a new router?

Page 42: RubyConf Argentina 2011

Maintenance

Page 43: RubyConf Argentina 2011

0

750

1500

2250

3000

Journey Journey-2 Rack-Mount

LOC

Page 44: RubyConf Argentina 2011

Known algorithms

Page 45: RubyConf Argentina 2011

References

•Compilers: Principles, Techniques, & Tools (Aho, Lam, Sethi, Ullman)

• Intro to Formal Languages and Automata (Linz)

Page 46: RubyConf Argentina 2011

Predictability

Page 47: RubyConf Argentina 2011

CPU Time

Page 48: RubyConf Argentina 2011

Memory Usage

Page 49: RubyConf Argentina 2011

Current Performance

url generation path recognition route parsing

rack-mount Journey

Page 50: RubyConf Argentina 2011

me gusta

Page 51: RubyConf Argentina 2011

Patterns

Page 52: RubyConf Argentina 2011

Why patterns matter

Page 53: RubyConf Argentina 2011

Regular Expressions/om(g)!/

Page 54: RubyConf Argentina 2011

Rails Routes

Page 55: RubyConf Argentina 2011

resource :articles

Page 56: RubyConf Argentina 2011

/articles(.:format) /articles/new(.:format) /articles/:id/edit(.:format) /articles/:id(.:format)

Page 57: RubyConf Argentina 2011

Parens don't capture

Page 58: RubyConf Argentina 2011

:whatever => /([^./?]+)/

Page 59: RubyConf Argentina 2011

/articles(.:format)

/\/articles(?:\.([^.\/?]+))?$/

Page 60: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

Page 61: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /articles/new

Page 62: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /articles/new

Page 63: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /articles/new

200 OK!

Page 64: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

Page 65: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

Page 66: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

Page 67: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

Page 68: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

Page 69: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

Page 70: RubyConf Argentina 2011

/\/articles(?:.([^.\/?]+))?$/

/\/articles\/new(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)\/edit(?:.([^.\/?]+))?$/

/\/articles\/([^.\/?]+)(?:.([^.\/?]+))?$/

GET /foos/new

404 Not Found

Page 71: RubyConf Argentina 2011

How long does this take?

Page 72: RubyConf Argentina 2011

r = routes.length

Page 73: RubyConf Argentina 2011

x = regexp compare

Page 74: RubyConf Argentina 2011

O(r ⨉ x)

Page 75: RubyConf Argentina 2011

Can we do better?

Page 76: RubyConf Argentina 2011

Finite State Machines

Parse Trees

Automata

Page 77: RubyConf Argentina 2011

Parse Trees

Page 78: RubyConf Argentina 2011

Parsing regexp

Page 79: RubyConf Argentina 2011

(a|b)*abb

Page 80: RubyConf Argentina 2011

○○ b

○ b

a *

a b

()

|

Describe node types

Page 81: RubyConf Argentina 2011

Parsing rails routes

Page 82: RubyConf Argentina 2011

Journey::Parserparser = Journey::Parser.newast = parser.parse '/articles(.:format)'

puts ast.to_dot

Page 83: RubyConf Argentina 2011

○ ()

/ articles ○

. :format

Page 84: RubyConf Argentina 2011

To String!

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'puts ast.to_sputs ast.to_regexp

Page 85: RubyConf Argentina 2011

OR ASTparser = Journey::Parser.new

trees = [ '/articles(.:format)', '/articles/new(.:format)',].map { |s| parser.parse s }

ast = Journey::Nodes::Or.new trees

puts ast.to_dot

Page 86: RubyConf Argentina 2011

|

○ ○

○ ()

/ articles ○

. :format

○ ()

○ new

○ /

/ articles

. :format

Page 87: RubyConf Argentina 2011

SECRET FEATUREparser = Journey::Parser.newast = parser.parse '/articles|books(.:format)'

Page 88: RubyConf Argentina 2011

SECRET FEATUREparser = Journey::Parser.newast = parser.parse '/articles|books(.:format)'

SUPER SECRET!

Page 89: RubyConf Argentina 2011

Automata

Page 90: RubyConf Argentina 2011

(a|b)*abb

Page 91: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

Double circle is acceptance state

Page 92: RubyConf Argentina 2011

baabb

Page 93: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

Page 94: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

b

Page 95: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

ba

Page 96: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

baa

Page 97: RubyConf Argentina 2011

3

0b2a

b

1aa

b

b

a

baabb

Page 98: RubyConf Argentina 2011

aab

3

0b2a

b

1aa

b

b

a

Page 99: RubyConf Argentina 2011

Deterministic Finite Automaton

Page 100: RubyConf Argentina 2011

Only one path

Page 101: RubyConf Argentina 2011

Storageclass 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 endend

Page 102: RubyConf Argentina 2011

FSM Simulation

Page 103: RubyConf Argentina 2011

class Simulator def initialize(dfa) @dfa = dfa end

def simulate(symbols) state = 0 until symbols.empty? state = @dfa.move(state, symbols.shift) end state endend

Page 104: RubyConf Argentina 2011

class DFA ...

def move(from, symbol) @table[from][symbol] endend

move function

Page 105: RubyConf Argentina 2011

irb> sim = Simulator.new(DFA.new)=> #<Simulator:0x007f95929a82e0 ...>irb> sim.simulate %w{ b a a b b }=> 3irb> sim.simulate %w{ a a b }=> 2

Page 106: RubyConf Argentina 2011

Time: O(n)n = string.length

Page 107: RubyConf Argentina 2011

me gusta

Page 108: RubyConf Argentina 2011

Space: S + Tstates.length + transitions.length

Page 109: RubyConf Argentina 2011

Nondeterministic Finite Automaton

Page 110: RubyConf Argentina 2011

Has nil edges

Page 111: RubyConf Argentina 2011

Can't tell direction

Page 112: RubyConf Argentina 2011

Simulation of NFA

Page 113: RubyConf Argentina 2011

602ε

3a

5b

εε

a|b

Page 114: RubyConf Argentina 2011

602ε

3a

5b

εε

nil-closure

Page 115: RubyConf Argentina 2011

602ε

3a ε

5b ε

a

Page 116: RubyConf Argentina 2011

Storageclass 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 endend

Page 117: RubyConf Argentina 2011

FSM Simulationclass 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 endend

Page 118: RubyConf Argentina 2011

Move function

class NFA ...

def move(states, symbol) states.map { |s| @table[s][symbol] }.flatten endend

Page 119: RubyConf Argentina 2011

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 }=> []

Page 120: RubyConf Argentina 2011

Time: O(r ⨉ x)r = operators.length, x = string.length

Page 121: RubyConf Argentina 2011

Who cares about NFA?

Page 122: RubyConf Argentina 2011

NFA Construction

Page 123: RubyConf Argentina 2011

○ ()

/ articles ○

. :format

/articles(.:format)

Page 124: RubyConf Argentina 2011

cat nodes

10 /

Page 125: RubyConf Argentina 2011

/articles

20 1/ articles

Page 126: RubyConf Argentina 2011

Optional

30ε

2????? ε

Page 127: RubyConf Argentina 2011

60 1/ 2articlesε

4. 5:format ε

Page 128: RubyConf Argentina 2011

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'nfa = Journey::NFA::Builder.new ast

tt = nfa.transition_tableputs tt.to_dot

Journey::NFA

Page 129: RubyConf Argentina 2011

ConvertingNFA to DFA

Page 130: RubyConf Argentina 2011

Eliminate nil transitions

Page 131: RubyConf Argentina 2011

Collapse duplicate edges

Page 132: RubyConf Argentina 2011

60 1/ 2articlesε

4. 5:format ε

/articles(.:format)

Page 133: RubyConf Argentina 2011

2 3. 40 1/ articles :format

/articles(.:format)

Page 134: RubyConf Argentina 2011

CODES!

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'nfa = Journey::NFA::Builder.new ast

tt = nfa.transition_table.generalized_tableputs tt.to_dot

Page 135: RubyConf Argentina 2011

SHORTER CODES!

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'dfa = Journey::GTG::Builder.new ast

tt = dfa.transition_tableputs tt.to_dot

Page 136: RubyConf Argentina 2011

ANY NFAconverts to DFA

Page 137: RubyConf Argentina 2011

O(r ⨉ x) => O(x)r = operations.length, x = string.length

Page 138: RubyConf Argentina 2011

me gusta

Page 139: RubyConf Argentina 2011

Converting Automata to Regexp

Page 140: RubyConf Argentina 2011

2 3. 40 1/ articles :format

/articles(.:format)

Page 141: RubyConf Argentina 2011

2 3. 40 /articles :format

/articles(.:format)

Page 142: RubyConf Argentina 2011

/articles(.:format)

2 4.:format0 /articles

Page 143: RubyConf Argentina 2011

/articles(.:format)

40 /articles(.:format)?

Page 144: RubyConf Argentina 2011

Generalized Transition Graph

Page 145: RubyConf Argentina 2011

/users(.:format) /users/new(.:format) /users/:id/edit(.:format) /users/:id(.:format)

resource :users

Page 146: RubyConf Argentina 2011

2

3.

4/

5

6 8.

7 9/

10

.

11

12 14.

13

15

0 1/ users

(?-mix:[^./?]+)

new(?-mix:[^./?]+)

(?-mix:[^./?]+)

edit

(?-mix:[^./?]+)

(?-mix:[^./?]+)

resource :users

Page 147: RubyConf Argentina 2011

The Plan?

Page 148: RubyConf Argentina 2011

Combine All Routes

Page 149: RubyConf Argentina 2011

Produce DFA

Page 150: RubyConf Argentina 2011

Simulate in O(n) Time

Page 151: RubyConf Argentina 2011

Routing To The Future

Page 152: RubyConf Argentina 2011

JS Simulation

Page 153: RubyConf Argentina 2011

Table => JSON

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'dfa = Journey::GTG::Builder.new ast

tt = dfa.transition_tableputs tt.to_json

Page 154: RubyConf Argentina 2011

Table => SVG

parser = Journey::Parser.newast = parser.parse '/articles(.:format)'dfa = Journey::GTG::Builder.new ast

tt = dfa.transition_tableputs tt.to_svg

Page 155: RubyConf Argentina 2011

JS Tokenizer

function tokenize(input, callback) { while(input.length > 0) { callback(input.match(/^[\/\.\?]|[^\/\.\?]+/)[0]); input = input.replace(/^[\/\.\?]|[^\/\.\?]+/, ''); }}

Page 156: RubyConf Argentina 2011

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; });

Page 157: RubyConf Argentina 2011

d3.js

Page 158: RubyConf Argentina 2011
Page 159: RubyConf Argentina 2011

Rails Console

irb> File.open('out.html', 'wb') { |f|irb* f.write(irb* Wot::Application.routes.router.visualizerirb> )}=> 69074

Page 160: RubyConf Argentina 2011

routes.rb marshalling

Page 161: RubyConf Argentina 2011

Test suggestions

Page 162: RubyConf Argentina 2011

Test coverage

Page 163: RubyConf Argentina 2011

Usage Heat Maps

Page 164: RubyConf Argentina 2011

REGEXP

AST

NFA

DFA

Page 165: RubyConf Argentina 2011

ROFLSCALE!!!

Page 166: RubyConf Argentina 2011

DFA => YACC

Page 167: RubyConf Argentina 2011

DFA => RACC

Page 168: RubyConf Argentina 2011

DFA => Ragel

Page 169: RubyConf Argentina 2011

Open Questions

Page 170: RubyConf Argentina 2011

Is our GTG deterministic?

Page 171: RubyConf Argentina 2011

/users/new|/users/:id

4

5

0 1/ 2users 3/new

(?-mix:[^./?]+)

Page 172: RubyConf Argentina 2011

"new" =~ /new|[^.\/?]+/

Page 173: RubyConf Argentina 2011

Can we make it deterministic?

Page 174: RubyConf Argentina 2011

L1 = {new}L2 = {[^./?]+}

Page 175: RubyConf Argentina 2011

/users/new|/users/:id

4

5

0 1/ 2users 3/L1

L2 - L1

Page 176: RubyConf Argentina 2011

Is it worth our effort?

Page 177: RubyConf Argentina 2011

REGEXP

AST

NFA

DFA

Page 178: RubyConf Argentina 2011

Is it worth our effort?

Page 179: RubyConf Argentina 2011

Thank You!!

Page 180: RubyConf Argentina 2011

<3<3<3<3<3