Class: Jets::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/jets/router.rb,
lib/jets/router/scope.rb

Defined Under Namespace

Classes: Scope

Constant Summary collapse

@@drawn_router =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRouter

Returns a new instance of Router.



8
9
10
# File 'lib/jets/router.rb', line 8

def initialize
  @routes = []
end

Instance Attribute Details

#routesObject (readonly)

Returns the value of attribute routes.



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

def routes
  @routes
end

Class Method Details

.all_pathsObject

Returns all paths including subpaths. Example: Input: [“posts/:id/edit”] Output: [“posts”, “posts/:id”, “posts/:id/edit”]



152
153
154
# File 'lib/jets/router.rb', line 152

def self.all_paths
  drawn_router.all_paths
end

.all_routes_validObject



167
168
169
# File 'lib/jets/router.rb', line 167

def self.all_routes_valid
  invalid_routes.empty?
end

.drawObject

Class methods



132
133
134
# File 'lib/jets/router.rb', line 132

def self.draw
  drawn_router
end

.drawn_routerObject



137
138
139
140
141
142
# File 'lib/jets/router.rb', line 137

def self.drawn_router
  return @@drawn_router if @@drawn_router

  router = Jets.application.routes
  @@drawn_router = router
end

.has_controller?(name) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/jets/router.rb', line 127

def self.has_controller?(name)
  routes.detect { |r| r.controller_name == name }
end

.invalid_routesObject



171
172
173
# File 'lib/jets/router.rb', line 171

def self.invalid_routes
  routes.select { |r| !r.valid? }
end

.routesObject



144
145
146
# File 'lib/jets/router.rb', line 144

def self.routes
  drawn_router.routes
end

.routes_helpObject



156
157
158
159
160
161
162
163
164
165
# File 'lib/jets/router.rb', line 156

def self.routes_help
  return "Your routes table is empty." if routes.empty?

  table = Text::Table.new
  table.head = %w[Verb Path Controller#action]
  routes.each do |route|
    table.rows << [route.method, route.path, route.to]
  end
  table
end

Instance Method Details

#add_namespace(path) ⇒ Object



40
41
42
43
44
45
# File 'lib/jets/router.rb', line 40

def add_namespace(path)
  return path unless @scope
  ns = @scope.full_namespace
  return path unless ns
  "#{ns}/#{path}"
end

#all_pathsObject

Useful for creating API Gateway Resources



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/jets/router.rb', line 94

def all_paths
  results = []
  paths = routes.map(&:path)
  paths.each do |p|
    sub_paths = []
    parts = p.split('/')
    until parts.empty?
      parts.pop
      sub_path = parts.join('/')
      sub_paths << sub_path unless sub_path == ''
    end
    results += sub_paths
  end
  @all_paths = (results + paths).sort.uniq
end

#api_mode?Boolean

Returns:

  • (Boolean)


72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/jets/router.rb', line 72

def api_mode?
  if Jets.config.key?(:api_mode) || Jets.config.key?(:api_generator)
    puts <<~EOL.color(:yellow)
      DEPRECATED: Jets.config.api_generator
      Instead, please update your config/application.rb to use:
        Jets.config.mode = 'api'
      You can also run:
        jets upgrade
    EOL
  end
  api_mode = Jets.config.mode == 'api' || Jets.config.api_mode || Jets.config.api_generator
  api_mode
end

#check_collision!Object

Validate routes that deployable



18
19
20
21
22
23
# File 'lib/jets/router.rb', line 18

def check_collision!
  paths = self.routes.map(&:path)
  collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
  collide = collision.collision?(paths)
  raise collision.exception if collide
end

#create_route(options) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/jets/router.rb', line 32

def create_route(options)
  # Currently only using scope to add namespace
  # TODO: Can use it to add additional things like authorization_type
  # Would be good to add authorization_type at the controller level also
  options[:path] = add_namespace(options[:path])
  @routes << Route.new(options)
end

#draw(&block) ⇒ Object



12
13
14
15
# File 'lib/jets/router.rb', line 12

def draw(&block)
  instance_eval(&block)
  check_collision!
end

#namespace(ns, &block) ⇒ Object



47
48
49
# File 'lib/jets/router.rb', line 47

def namespace(ns, &block)
  scope(namespace: ns, &block)
end

#ordered_routesObject

Useful for RouterMatcher

Precedence:

  1. Routes with no captures get highest precedence: posts/new

  2. Then consider the routes with captures: post/:id

  3. Last consider the routes with wildcards: *catchall

Within these 2 groups we consider the routes with the longest path first since posts/:id and posts/:id/edit can both match.



119
120
121
122
123
124
125
# File 'lib/jets/router.rb', line 119

def ordered_routes
  length = Proc.new { |r| r.path.length * -1 }
  capture_routes = routes.select { |r| r.path.include?(':') }.sort_by(&length)
  wildcard_routes = routes.select { |r| r.path.include?('*') }.sort_by(&length)
  simple_routes = (routes - capture_routes - wildcard_routes).sort_by(&length)
  simple_routes + capture_routes + wildcard_routes
end

#resources(name) ⇒ Object

resources macro expands to all the routes



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/jets/router.rb', line 60

def resources(name)
  get "#{name}", to: "#{name}#index"
  get "#{name}/new", to: "#{name}#new" unless api_mode?
  get "#{name}/:id", to: "#{name}#show"
  post "#{name}", to: "#{name}#create"
  get "#{name}/:id/edit", to: "#{name}#edit" unless api_mode?
  put "#{name}/:id", to: "#{name}#update"
  post "#{name}/:id", to: "#{name}#update" # for binary uploads
  patch "#{name}/:id", to: "#{name}#update"
  delete "#{name}/:id", to: "#{name}#delete"
end

#root(to, options = {}) ⇒ Object

root “posts#index”



87
88
89
90
91
# File 'lib/jets/router.rb', line 87

def root(to, options={})
  default = {path: '', to: to, method: :get, root: true}
  options = default.merge(options)
  @routes << Route.new(options)
end

#scope(options = {}) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/jets/router.rb', line 51

def scope(options={})
  root_level = @scope.nil?
  @scope = root_level ? Scope.new(options) : @scope.new(options)
  yield
ensure
  @scope = @scope.parent if @scope
end