Created
November 15, 2008 15:37
-
-
Save jm/25263 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ActionController | |
module Routing | |
class RouteSet | |
attr_accessor :routes, :recognizer | |
def initialize | |
@routes = [] | |
@route_structure = {} | |
end | |
def add_named_route(name, path, options = {}) | |
add_route(path, options) | |
end | |
def add_route(route_string, *args) | |
@route_structure ||= {} | |
@routes ||= [] | |
params = [] | |
args = (args.pop || {}) | |
request_method = args[:conditions] && args[:conditions][:method] ? args[:conditions].delete(:method) : :get | |
requirements = args.delete(:requirements) || {} | |
segments = route_string.split("/").map! do |segment| | |
segment = Regexp.escape(segment) | |
if segment =~ /:\w+/ | |
segment_symbols = segment.scan(/:(\w+)/).flatten | |
segment_symbols.each do |segment_symbol| | |
params << segment_symbol.to_sym | |
requirements[segment_symbol] || ".*" | |
segment.gsub!(/:#{segment_symbol}/, '.*') | |
end | |
end | |
segment | |
end | |
raise "Invalid route: Controller not specified" unless (params.include?(:controller) || args.keys.include?(:controller)) | |
new_route = RouterFu::Route.new(segments, params, request_method, args) | |
@routes << new_route | |
new_route.arguments[:controller] ||= :controller | |
new_route.arguments[:action] ||= :action | |
@route_structure[request_method] ||= {} | |
@route_structure[request_method][new_route.arguments[:controller]] ||= {} | |
@route_structure[request_method][new_route.arguments[:controller]][new_route.arguments[:action]] ||= [] | |
@route_structure[request_method][new_route.arguments[:controller]][new_route.arguments[:action]] << new_route | |
end | |
def recognize(request) | |
# path, request_method = :GET | |
path = request.path | |
request_method = (request.request_method || :get) | |
@recognizer ||= build_recognizer | |
RAILS_DEFAULT_LOGGER.error(@recognizer) | |
matched = {} | |
# RAILS_DEFAULT_LOGGER.error("#{request_method} #{path}") | |
captures = @recognizer.match("#{request_method} #{path}").captures[1..-1] | |
# RAILS_DEFAULT_LOGGER.error(@recognizer.pretty_inspect) | |
# RAILS_DEFAULT_LOGGER.error(@routes.pretty_inspect) | |
# | |
# RAILS_DEFAULT_LOGGER.error(@routes[captures.index(captures.compact.last)].pretty_inspect) | |
if r = @routes[captures.index(captures.compact.last)] | |
path_segments = path.gsub(/^\//, '').split("/") | |
index = -1 | |
r.segments.each do |segment| | |
next unless segment == "(.*)" # FIXFXIFXIFXFIX | |
index += 1 | |
matched[r.params[index]] = path_segments[index] | |
end | |
matched = r.arguments.merge(matched) | |
RAILS_DEFAULT_LOGGER.error(matched.pretty_inspect) | |
matched[:action] = 'index' if matched[:action] == :action | |
end | |
request.path_parameters = matched | |
"#{matched[:controller].camelize}Controller".constantize | |
end | |
def generate(*args) | |
params = args.pop | |
request_method = params[:method].to_sym || :get | |
if params.keys.include?(:controller) | |
controller_routes = @route_structure[:request_method][params[:controller]] | |
unless controller_routes | |
controller_routes = @route_structure[:request_method][:controller] | |
end | |
action_routes = controller_routes[(params[:action] || 'index')] || controller_routes[:action] | |
action_routes.each do |route| | |
if (route.params - params.keys).empty? | |
puts "generating from #{route.inspect}" | |
return generate_url(route, params) | |
else | |
raise "No route to match that" | |
end | |
end | |
else | |
raise "No controller provided" | |
end | |
end | |
def generate_url(route, params) | |
route_string = route.segments.join("/") | |
return route_string unless route_string.include?("(.*)") | |
index = -1 | |
route_string.gsub!(/\(\.\*\)/) do |match| | |
index += 1 | |
params[route.params[index]] | |
end | |
end | |
def route_resources(resources) | |
resources = resources.to_s | |
add_route resources, :controller => resources.to_sym, :action => 'index', :method => :get | |
add_route resources, :controller => resources.to_sym, :action => 'create', :method => :post | |
add_route "#{resources}/:id", :controller => resources.to_sym, :action => 'show', :method => :get | |
add_route "#{resources}/:id", :controller => resources.to_sym, :action => 'update', :method => :put | |
add_route "#{resources}/:id", :controller => resources.to_sym, :action => 'destroy', :method => :delete | |
add_route "#{resources}/new", :controller => resources.to_sym, :action => 'new', :method => :get | |
add_route "#{resources}/:id/edit", :controller => resources.to_sym, :action => 'edit', :method => :get | |
end | |
def build_recognizer | |
recognizers = [] | |
@routes.each do |route| | |
recognizers << "(#{route.request_method} #{route.recognizer})" | |
end | |
@recognizer = /^(#{recognizers.join("|")})$/ | |
end | |
end | |
end | |
end | |
module RouterFu | |
class Route | |
attr_accessor :params, :segments, :arguments | |
attr_reader :recognizer, :request_method | |
def initialize(segment_list, param_list, request_method, argument_list = {}) | |
@segments = segment_list | |
@params = param_list | |
@arguments = argument_list || {} | |
@recognizer = "#{@segments.join("\/")}$" | |
@request_method = request_method | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment