Skip to content

Instantly share code, notes, and snippets.

@benolee
Forked from tenderlove/.gitignore
Created April 25, 2013 01:52
Show Gist options
  • Save benolee/5456940 to your computer and use it in GitHub Desktop.
Save benolee/5456940 to your computer and use it in GitHub Desktop.

Journey Routing Table => Ragel PoC

Run this to generate and compile your routes:

$ rake

Run the tests (after compile):

$ ruby -I. test.rb

TODO

  • Need to add support for regexps.

  • The current implementation translates the AST directly to ragel, should we generate a GTG first so the table is more compact?

require 'mkmf'
# :stopdoc:
create_makefile 'router'
# :startdoc:
task :clean do
rm_f 'router.c'
rm_f 'router.rl'
rm_f 'router.o'
rm_f 'Makefile'
rm_f 'router.bundle'
rm_f 'router.so'
end
task :default do
ruby 'route_compiler.rb > router.rl'
sh 'ragel router.rl'
ruby 'extconf.rb'
sh 'make'
end
require 'journey'
def asts paths
parser = Journey::Parser.new
Journey::Nodes::Or.new paths.map { |x| parser.parse x }
end
class Ragel < Journey::Visitors::Visitor
def terminal(n)
n.left.inspect
end
def visit_OR(n)
"(#{n.children.map { |x| visit x }.join ' | '})"
end
def visit_GROUP(n)
"(#{visit n})"
end
def visit_CAT(n)
"#{visit n.left} . #{visit n.right}"
end
end
## These come from your routes.rb
ast = asts %w{
/articles
/articles/new
}
ragel = Ragel.new.accept ast
data = <<-eoc
#include <ruby.h>
%%{
machine router;
action match { ret = Qtrue; }
main := #{ragel} %match;
}%%
%% write data;
static VALUE match(VALUE self, VALUE string)
{
int cs = 0;
char *p = RSTRING_PTR(string);
char *pe = p + RSTRING_LEN(string);
char *eof = pe;
VALUE ret = Qfalse;
%% write init;
%% write exec;
return ret;
}
void Init_router()
{
VALUE mRouter = rb_define_class("Router", rb_cObject);
rb_define_method(mRouter, "match", match, 1);
}
eoc
puts data
# ruby -I. test.rb
require 'router'
require 'minitest/autorun'
class RouterTest < MiniTest::Unit::TestCase
def setup
@router = Router.new
end
def test_omg
assert @router.match '/articles/new'
refute @router.match '/articles/nw'
assert @router.match '/articles'
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment