Class: Rage::Router::Backend

Inherits:
Object
  • Object
show all
Defined in:
lib/rage/router/backend.rb

Constant Summary collapse

OPTIONAL_PARAM_REGEXP =
/\/?\(\/?(:\w+)\/?\)/
STRING_HANDLER_REGEXP =
/^([a-z0-9_\/]+)#([a-z_]+)$/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBackend

Returns a new instance of Backend.



11
12
13
14
15
# File 'lib/rage/router/backend.rb', line 11

def initialize
  @routes = []
  @trees = {}
  @constrainer = Rage::Router::Constrainer.new({})
end

Instance Attribute Details

#routesObject (readonly)

Returns the value of attribute routes.



6
7
8
# File 'lib/rage/router/backend.rb', line 6

def routes
  @routes
end

Instance Method Details

#lookup(env) ⇒ Object



99
100
101
102
# File 'lib/rage/router/backend.rb', line 99

def lookup(env)
  constraints = @constrainer.derive_constraints(env)
  find(env, constraints)
end

#mount(path, handler, methods) ⇒ Object

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rage/router/backend.rb', line 22

def mount(path, handler, methods)
  raise ArgumentError, "Mount handler should respond to `call`" unless handler.respond_to?(:call)

  raw_handler = handler
  is_sidekiq = handler.respond_to?(:name) && handler.name == "Sidekiq::Web"

  handler = ->(env, _params) do
    env["SCRIPT_NAME"] = path
    sub_path = env["PATH_INFO"].delete_prefix!(path)
    env["PATH_INFO"] = "/" if sub_path == ""

    if is_sidekiq
      Rage::SidekiqSession.with_session(env) do
        raw_handler.call(env)
      end
    else
      raw_handler.call(env)
    end

  ensure
    env["PATH_INFO"] = "#{env["SCRIPT_NAME"]}#{sub_path}"
  end

  methods.each do |method|
    __on(method, path, handler, {}, {}, { raw_handler:, mount: true })
    __on(method, "#{path}/*", handler, {}, {}, { raw_handler:, mount: true })
  end
end

#on(method, path, handler, constraints: {}, defaults: nil) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/rage/router/backend.rb', line 51

def on(method, path, handler, constraints: {}, defaults: nil)
  raise "Path could not be empty" if path&.empty?

  if (match_index = (path =~ OPTIONAL_PARAM_REGEXP))
    raise ArgumentError, "Optional Parameter has to be the last parameter of the path" if path.length != match_index + $&.length

    path_full = path.sub(OPTIONAL_PARAM_REGEXP, "/#{$1}")
    path_optional = path.sub(OPTIONAL_PARAM_REGEXP, "")

    on(method, path_full, handler, constraints: constraints, defaults: defaults)
    on(method, path_optional, handler, constraints: constraints, defaults: defaults)
    return
  end

  meta = { raw_handler: handler }

  if handler.is_a?(String)
    raise ArgumentError, "Invalid route handler format, expected to match the 'controller#action' pattern" unless handler =~ STRING_HANDLER_REGEXP

    controller, action = Rage::Router::Util.path_to_class($1), $2

    if controller.ancestors.include?(RageController::API)
      run_action_method_name = controller.__register_action(action.to_sym)

      meta[:controller] = $1
      meta[:action] = $2
      meta[:controller_class] = controller

      handler = eval("->(env, params) { #{controller}.new(env, params).#{run_action_method_name} }")
    else
      # this is a Rails controller; notify `Rage::Router::Util::Cascade` to forward the request to Rails
      handler = ->(_, _) { [404, { "X-Cascade" => "pass" }, []] }
    end
  else
    raise ArgumentError, "Non-string route handler should respond to `call`" unless handler.respond_to?(:call)
    # while regular handlers are expected to be called with the `env` and `params` objects,
    # lambda handlers expect just `env` as an argument;
    # TODO: come up with something nicer?
    orig_handler = handler
    handler = ->(env, _params) { orig_handler.call(env) }
  end

  __on(method, path, handler, constraints, defaults, meta)

rescue Rage::Errors::RouterError => e
  raise e unless Rage.code_loader.reloading?
end

#reset_routesObject



17
18
19
20
# File 'lib/rage/router/backend.rb', line 17

def reset_routes
  @routes = []
  @trees = {}
end