Skip to content

Instantly share code, notes, and snippets.

@juliocesar
Created April 20, 2010 00:23
Show Gist options
  • Save juliocesar/371842 to your computer and use it in GitHub Desktop.
Save juliocesar/371842 to your computer and use it in GitHub Desktop.
Simple object regex method router
# >> class MyClass; include RegexRouter; end
# => MyClass
# >> obj = MyClass.new
# => #<MyClass:0x101859100 @routes={}>
# >> obj[%r(/words/(\w+))] = lambda do |word| puts "Found: #{word}" end
# => #<Proc:0x000000010184bb40@(irb):3>
# >> obj.go '/words/boo'
# Found: boo
# => nil
module RegexRouter
def self.included(base)
base.class_eval do
def initialize(*args, &block)
@routes = {}
super(*args, &block)
end
end
end
def []=(*args)
@routes.send :[]=, *(args.map { |arg| arg.is_a?(String) ? Regexp.new(arg) : arg })
end
def go(route)
@routes.each do |regex, block|
if match = regex.match(route)
return (match.captures.any? ? block.call(*match.captures) : block.call)
end
end
raise NoMethodError, "Route not found: #{route}"
end
def routes
@routes
end
def @routes.count
@routes.keys.length
end
end
if $0 =~ /spec/
require 'rubygems'
gem 'rspec', '>= 1.3.0'; require 'spec'
describe RegexRouter do
before do
class MyClass
include RegexRouter
end
@instance = MyClass.new
end
context 'methods' do
subject { @instance }
it { should respond_to :[]= }
it { should respond_to :routes }
it { subject.routes.should respond_to(:count) }
end
it 'works by passing a regex to [] and a block increments the route count by 1' do
@instance[/boo/] = lambda do 'omg' end
@instance.routes.count.should == 1
end
context 'dispatching routes' do
it 'dispatches a method associated with a route when the param matches' do
jug = 'empty'
@instance[/foo/] = lambda do jug = 'water' end
@instance.go 'foo'
jug.should == 'water'
end
it "uses regex captures as arguments for a route's block" do
book = nil
@instance[%r(/books/(\d))] = lambda do |book_id|
book = book_id
end
@instance.go '/books/1'
book.should == '1'
end
end
it 'raises a NoMethodError when dispatching to a non-existent route' do
lambda do
@instance.go 'zomg'
end.should raise_error(NoMethodError)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment