class Blix::Rest::RequestMapper
register routes with this class and then we can match paths to these routes and return an associated block and parameters.
Constants
- PATH_SEP
- STAR_PLACEHOLDER
- WILD_PLACEHOLDER
Attributes
path_root_length[R]
Public Class Methods
add_path(verb, path, opts = {}, &blk)
click to toggle source
declare a route
# File lib/blix/rest/request_mapper.rb, line 146 def add_path(verb, path, opts = {}, &blk) path = path[1..-1] if path[0, 1] == PATH_SEP RequestMapper.locations[verb] << [verb, path, opts, blk] @table = nil # force recompile end
compile()
click to toggle source
compile routes into a tree structure for easy lookup
# File lib/blix/rest/request_mapper.rb, line 112 def compile @table = Hash.new { |h, k| h[k] = TableNode.new('') } locations.each do |verb, routes| routes.each do |info| verb, path, opts, blk = info parts = path.split(PATH_SEP) current = @table[verb] parts.each_with_index do |section, idx| node = TableNode.new(section) # check that a wildstar is the last element. if (section[0] == STAR_PLACEHOLDER) && (idx < (parts.length - 1)) raise RequestMapperError, "do not add a path after the * in #{path}" end # check that wild card match in name if current[node.value] if (node.value == WILD_PLACEHOLDER) && (node.parameter != current[node.value].parameter) raise RequestMapperError, "parameter mismatch in route=#{path}, expected #{current[node.value].parameter} but got #{node.parameter}" end else current[node.value] = node end current = current[node.value] end current.blk = blk current.opts = opts || {} current.extract_format = opts[:extension] if opts.key?(:extension) end end @table end
dump()
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 82 def dump table.each do |k, v| puts k dump_node(v, 1) end end
dump_node(item, indent = 0)
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 89 def dump_node(item, indent = 0) puts "#{' ' * indent} value=#{item.value.inspect} opts=#{item.opts.inspect} params=#{item.parameter.inspect}" item.children.each_value { |c| dump_node(c, indent + 1) } end
full_path(path)
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 69 def full_path(path) path = path[1..-1] if path[0, 1] == '/' path_root + path end
locations()
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 74 def locations @locations ||= Hash.new { |h, k| h[k] = [] } end
match(verb, path)
click to toggle source
match a given path to declared route.
# File lib/blix/rest/request_mapper.rb, line 153 def match(verb, path) path = PATH_SEP + path if path[0, 1] != PATH_SEP # ensure a leading slash on path path = path[path_root_length..-1] if (path_root_length.to_i > 0) #&& (path[0,path_root_length] == path_root) if path path = path[1..-1] if path[0, 1] == PATH_SEP # remove the leading slash else return [nil, {}, nil] end parameters = StringHash.new parts = path.split(PATH_SEP) current = table[verb] limit = parts.length - 1 # handle the root node here if path == '' if current.blk return [current.blk, parameters, current.opts] elsif (havewild = current[STAR_PLACEHOLDER]) parameters[havewild.parameter.to_s] = '/' return [havewild.blk, parameters, havewild.opts] else return [nil, {}, nil] end end parts.each_with_index do |section, idx| # first save the last node that we used # before updating the current node. last = current # table nodes # check to see if there is a path which includes a format part # only on the last section if idx == limit if last[section] current = last[section] else format = File.extname(section) base = File.basename(section, format) current = last[base] if current parameters['format'] = format[1..-1].to_sym # !format.empty? section = base end end else current = last[section] end # if current is set here that means that this section matches a fixed # part of the route. if current # if this is the last section then we have to decide here if we # have a valid result.. # .. if we have a block then fine .. # .. if there is a wildpath foloowing then fine .. # .. otherwise an error ! if idx == limit # the last section of request if current.blk return [current.blk, parameters, current.opts] elsif (havewild = current[STAR_PLACEHOLDER]) parameters[havewild.parameter.to_s] = '/' return [havewild.blk, parameters, havewild.opts] else return [nil, {}, nil] end end else # this section is not part of a static path so # check if we have a path variable first .. current = last[WILD_PLACEHOLDER] if current # yes this is a path variable section if idx == limit # the last section of request - if current.extract_format format = File.extname(section) base = File.basename(section, format) parameters[current.parameter.to_s] = base parameters['format'] = format[1..-1].to_sym unless format.empty? else parameters[current.parameter.to_s] = section end # check if we have a valid block otherwise see if # a wild path follows. if current.blk return [current.blk, parameters, current.opts] elsif (havewild = current[STAR_PLACEHOLDER]) parameters[havewild.parameter.to_s] = '/' return [havewild.blk, parameters, havewild.opts] else return [nil, {}, nil] end else parameters[current.parameter.to_s] = section end else current = last[STAR_PLACEHOLDER] if current wildpath = '/' + parts[idx..-1].join('/') wildformat = File.extname(wildpath) unless wildformat.empty? || !current.extract_format wildpath = wildpath[0..-(wildformat.length + 1)] parameters['format'] = wildformat[1..-1].to_sym end parameters[current.parameter.to_s] = wildpath return [current.blk, parameters, current.opts] else return [nil, {}, nil] end end end end [nil, {}, nil] end
path_root()
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 63 def path_root @path_root || '/' end
process(verb, path)
click to toggle source
match a path to a route and call any associated block with the extracted parameters.
# File lib/blix/rest/request_mapper.rb, line 282 def process(verb, path) blk, params = match(verb, path) blk&.call(params) end
reset(vals = nil)
click to toggle source
used for testing only !!
# File lib/blix/rest/request_mapper.rb, line 95 def reset(vals = nil) save = [@table&.dup, @locations&.dup, @path_root&.dup, @path_root_length] if vals @table = vals[0] @locations = vals[1] @path_root = vals[2] @path_root_length = vals[3] else @table = nil @locations = nil @path_root = nil @path_root_length = 0 end save end
routes()
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 287 def routes hash = {} locations.values.each do |group| group.each do |route| verb = route[0] options = route[2] options_string = String.new options_string = ' ' + options.inspect.to_s unless options.empty? path = '/' + route[1] hash[path] ||= {} hash[path][verb] = options_string end end list = hash.to_a list.sort! { |a, b| a[0] <=> b[0] } str = String.new list.each do |route| #pairs = route[1] (HTTP_VERBS + ['ALL']).each do |verb| if route[1].key? verb str << verb << "\t" << route[0] << route[1][verb] << "\n" end end str << "\n" end str end
set_path_root(root)
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 55 def set_path_root(root) root = root.to_s root = '/' + root if root[0, 1] != '/' root += '/' if root[-1, 1] != '/' @path_root = root @path_root_length = @path_root.length - 1 end
table()
click to toggle source
# File lib/blix/rest/request_mapper.rb, line 78 def table @table ||= compile end