Class: Porous::Router

Inherits:
Object
  • Object
show all
Includes:
Component
Defined in:
lib/porous/router.rb

Constant Summary

Constants included from VirtualDOM::DOM

VirtualDOM::DOM::HTML_TAGS, VirtualDOM::DOM::SVG_TAGS

Instance Attribute Summary collapse

Attributes included from Injection

#injections

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Component

#props, #to_s, #with_props

Methods included from Injection

#init, #init_injections, #inject, #with_root_component

Methods included from Component::Render

#before_render, #render_virtual_dom

Methods included from Component::Virtual

#component

Methods included from VirtualDOM::DOM

#class_names, #merge_string, #method_missing, #process_params, #process_tag, #text, #to_vnode

Constructor Details

#initialize(props = {}) ⇒ Router

Returns a new instance of Router.

Raises:



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/porous/router.rb', line 9

def initialize(props = {})
  @props = props
  @routes = Routes.new

  # Extract the routes from all Pages
  ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Porous::Page }.each do |klass|
    # TODO: Figure out where these classes are coming from
    # puts "#{klass}: #{klass.ancestors.first} (#{klass.respond_to? :new})"
    next if klass.to_s.start_with? '#<Class:' # skip singleton classes

    @routes.combine klass.new.route!
  end

  raise Error, 'No Porous::Page components found!' if @routes.routes.empty?

  find_route
  parse_url_params
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class VirtualDOM::DOM

Instance Attribute Details

#paramsObject (readonly)

Returns the value of attribute params.



7
8
9
# File 'lib/porous/router.rb', line 7

def params
  @params
end

Class Method Details

.included(base) ⇒ Object



32
33
34
# File 'lib/porous/router.rb', line 32

def self.included(base)
  base.extend(Porous::Component::ClassMethods)
end

Instance Method Details

#call_on_enter_callback(route) ⇒ Object



57
58
59
60
61
62
63
# File 'lib/porous/router.rb', line 57

def call_on_enter_callback(route)
  return unless route[:on_enter]

  return unless route[:on_enter].respond_to?(:call)

  route[:on_enter].call
end

#component_url_paramsObject



84
85
86
# File 'lib/porous/router.rb', line 84

def component_url_params
  @route[:params].zip(path.match(@route[:regex])[1..]).to_h
end

#current_url?(name) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/porous/router.rb', line 110

def current_url?(name)
  path == url_for(name, params)
end

#find_component(route) ⇒ Object



47
48
49
50
51
# File 'lib/porous/router.rb', line 47

def find_component(route)
  call_on_enter_callback(route)
  @component_props = route[:component_props]
  route[:component]
end

#find_routeObject

Raises:



36
37
38
39
40
41
42
43
44
45
# File 'lib/porous/router.rb', line 36

def find_route
  @routes.routes.each do |route|
    next unless path.match(route[:regex])
    return go_to(url_for(route[:redirect_to])) if route[:redirect_to]

    return @route = route
  end
  available_routes = @routes.routes.map { |r| "  #{r[:path]} => #{r[:component]}" }.join
  raise InvalidRouteError, "Unknown route for: #{path}\n\nAvailable routes:\n\n#{available_routes}"
end

#go_to(path) ⇒ Object



65
66
67
68
69
70
71
72
# File 'lib/porous/router.rb', line 65

def go_to(path)
  # Figure out how to change path
  @props[:path] = path
  find_route
  parse_url_params
  render!
  false
end

#parse_url_paramsObject



74
75
76
77
78
79
80
81
82
# File 'lib/porous/router.rb', line 74

def parse_url_params
  @params = component_url_params
  return if query.empty?

  query[1..].split('&').each do |param|
    key, value = param.split('=')
    @params[key] = value
  end
end

#pathObject



106
107
108
# File 'lib/porous/router.rb', line 106

def path
  @props ? @props[:path] : '/'
end

#queryObject



102
103
104
# File 'lib/porous/router.rb', line 102

def query
  @props ? @props[:query] : ''
end

#renderObject



53
54
55
# File 'lib/porous/router.rb', line 53

def render
  component find_component(@route), props: @component_props if @route
end

#routesObject



28
29
30
# File 'lib/porous/router.rb', line 28

def routes
  @routes.routes
end

#url_for(name, params = nil) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/porous/router.rb', line 88

def url_for(name, params = nil)
  route = @routes.routes.find do |r|
    case name
    when String
      r[:name] == name || r[:path] == name
    when Object
      r[:component] == name
    else
      false
    end
  end
  route ? url_with_params(route, params) : raise(Error, "Route '#{name}' not found.")
end

#url_with_params(route, params) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/porous/router.rb', line 114

def url_with_params(route, params)
  path = route[:path]
  params&.each do |key, value|
    path = path.gsub(":#{key}", value.to_s)
  end
  path
end