Class: Lennarb::RouteNode

Inherits:
Object
  • Object
show all
Defined in:
lib/lennarb/route_node.rb

Overview

Note:

RouteNode use a trie data structure to store the routes and match them.

RouteNode is key to the routing system. It is a tree structure that represents the routes of the application.

Examples:

node = RouteNode.new
node.add_route(["foo", "bar"], :GET, -> {})

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRouteNode

Initialize the route node.



18
19
20
21
22
23
# File 'lib/lennarb/route_node.rb', line 18

def initialize
  @blocks = {}
  @param_key = nil
  @static_children = {}
  @dynamic_children = {}
end

Instance Attribute Details

#blocksObject

Returns the value of attribute blocks.



12
13
14
# File 'lib/lennarb/route_node.rb', line 12

def blocks
  @blocks
end

#dynamic_childrenObject

Returns the value of attribute dynamic_children.



12
13
14
# File 'lib/lennarb/route_node.rb', line 12

def dynamic_children
  @dynamic_children
end

#param_keyObject

Returns the value of attribute param_key.



12
13
14
# File 'lib/lennarb/route_node.rb', line 12

def param_key
  @param_key
end

#static_childrenObject

Returns the value of attribute static_children.



12
13
14
# File 'lib/lennarb/route_node.rb', line 12

def static_children
  @static_children
end

Instance Method Details

#add_route(parts, http_method, block) ⇒ Object

Add a route to the route node.

Parameters:

  • parts (Array<String>)

    The parts of the route.

  • http_method (String)

    The HTTP method.

  • block (Proc)

    The block to be executed when the route is matched.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/lennarb/route_node.rb', line 33

def add_route(parts, http_method, block)
  current_node = self

  parts.each do |part|
    if part.start_with?(":")
      param_sym = part[1..].to_sym
      current_node.dynamic_children[param_sym] ||= RouteNode.new
      dynamic_node = current_node.dynamic_children[param_sym]
      dynamic_node.param_key = param_sym
      current_node = dynamic_node
    else
      current_node.static_children[part] ||= RouteNode.new
      current_node = current_node.static_children[part]
    end
  end

  current_node.blocks[http_method] = block
end

#match_route(parts, http_method, params: {}) ⇒ Object

Match a route.

Parameters:

  • parts (Array<String>)

    The parts of the route.

  • http_method (String)

    The HTTP method.

  • params (Hash) (defaults to: {})

    The parameters of the route.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/lennarb/route_node.rb', line 60

def match_route(parts, http_method, params: {})
  if parts.empty?
    return [blocks[http_method], params] if blocks[http_method]
  else
    part = parts.first
    rest = parts[1..]

    if static_children.key?(part)
      result_block, result_params = static_children[part].match_route(rest, http_method, params:)
      return [result_block, result_params] if result_block
    end

    dynamic_children.each_value do |dyn_node|
      new_params = params.dup
      new_params[dyn_node.param_key] = part
      result_block, result_params = dyn_node.match_route(rest, http_method, params: new_params)

      return [result_block, result_params] if result_block
    end
  end

  [nil, nil]
end

#merge!(other) ⇒ Object

Merge another route node into this one.

Parameters:

  • other (RouteNode)

    The other route node.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/lennarb/route_node.rb', line 90

def merge!(other)
  other.blocks.each do |http_method, block|
    if @blocks[http_method]
      raise Lennarb::DuplicateRouteError, "Duplicate route for HTTP method: #{http_method}"
    end
    @blocks[http_method] = block
  end

  other.static_children.each do |path, node|
    if @static_children[path]
      @static_children[path].merge!(node)
    else
      @static_children[path] = node
    end
  end

  other.dynamic_children.each do |param, node|
    if @dynamic_children[param]
      @dynamic_children[param].merge!(node)
    else
      @dynamic_children[param] = node
    end
  end
end