Class: Blix::Rest::RequestMapper
- Inherits:
-
Object
- Object
- Blix::Rest::RequestMapper
- Defined in:
- lib/blix/rest/request_mapper.rb
Overview
register routes with this class and then we can match paths to these routes and return an associated block and parameters.
Defined Under Namespace
Classes: TableNode
Constant Summary collapse
- WILD_PLACEHOLDER =
'/'- PATH_SEP =
'/'- STAR_PLACEHOLDER =
'*'- @@mutex =
Mutex.new
Class Method Summary collapse
-
.add_path(verb, path, opts = {}, &blk) ⇒ Object
declare a route.
-
.compile ⇒ Object
compile routes into a tree structure for easy lookup.
- .dump ⇒ Object
- .dump_node(item, indent = 0) ⇒ Object
-
.ensure_full_path(path) ⇒ Object
ensure that absolute path is the full path.
- .full_path(path) ⇒ Object
- .locations ⇒ Object
-
.match(verb, path) ⇒ Object
match a given path to declared route.
- .path_root ⇒ Object
- .path_root_length ⇒ Object
-
.process(verb, path) ⇒ Object
match a path to a route and call any associated block with the extracted parameters.
-
.reset(vals = nil) ⇒ Object
used for testing only !!.
- .routes ⇒ Object
-
.set_path_root(root) ⇒ Object
the root always starts with ‘/’ and finishes with ‘/’.
- .table ⇒ Object
Class Method Details
.add_path(verb, path, opts = {}, &blk) ⇒ Object
declare a route
161 162 163 164 165 166 |
# File 'lib/blix/rest/request_mapper.rb', line 161 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 true end |
.compile ⇒ Object
compile routes into a tree structure for easy lookup
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/blix/rest/request_mapper.rb', line 127 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 ⇒ Object
97 98 99 100 101 102 |
# File 'lib/blix/rest/request_mapper.rb', line 97 def dump table.each do |k, v| puts k dump_node(v, 1) end end |
.dump_node(item, indent = 0) ⇒ Object
104 105 106 107 |
# File 'lib/blix/rest/request_mapper.rb', line 104 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 |
.ensure_full_path(path) ⇒ Object
ensure that absolute path is the full path
81 82 83 84 85 86 |
# File 'lib/blix/rest/request_mapper.rb', line 81 def ensure_full_path(path) if path[0, 1] == '/' && (path_root_length>0) && path[0, path_root_length] != path_root[0, path_root_length] path = path_root + path[1..-1] end path end |
.full_path(path) ⇒ Object
75 76 77 78 |
# File 'lib/blix/rest/request_mapper.rb', line 75 def full_path(path) path = path[1..-1] if path[0, 1] == '/' path_root + path end |
.locations ⇒ Object
88 89 90 |
# File 'lib/blix/rest/request_mapper.rb', line 88 def locations @locations ||= Hash.new { |h, k| h[k] = [] } end |
.match(verb, path) ⇒ Object
match a given path to declared route.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/blix/rest/request_mapper.rb', line 169 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 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, true] 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, true] 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, true] else return [nil, {}, nil] end end end end [nil, {}, nil] end |
.path_root ⇒ Object
67 68 69 |
# File 'lib/blix/rest/request_mapper.rb', line 67 def path_root @path_root || '/' end |
.path_root_length ⇒ Object
71 72 73 |
# File 'lib/blix/rest/request_mapper.rb', line 71 def path_root_length @path_root_length.to_i end |
.process(verb, path) ⇒ Object
match a path to a route and call any associated block with the extracted parameters.
298 299 300 301 |
# File 'lib/blix/rest/request_mapper.rb', line 298 def process(verb, path) blk, params = match(verb, path) blk&.call(params) end |
.reset(vals = nil) ⇒ Object
used for testing only !!
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/blix/rest/request_mapper.rb', line 110 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 ⇒ Object
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/blix/rest/request_mapper.rb', line 303 def routes hash = {} locations.values.each do |group| group.each do |route| verb = route[0] = route[2] = String.new = ' ' + .inspect.to_s unless .empty? path = '/' + route[1] hash[path] ||= {} hash[path][verb] = 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) ⇒ Object
the root always starts with ‘/’ and finishes with ‘/’
59 60 61 62 63 64 65 |
# File 'lib/blix/rest/request_mapper.rb', line 59 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 ⇒ Object
92 93 94 95 |
# File 'lib/blix/rest/request_mapper.rb', line 92 def table # compile the table in one thread only. @table ||= @@mutex.synchronize{@table ||= compile} end |