Class: Jets::Router

Inherits:
Object
  • Object
show all
Includes:
Dsl
Defined in:
lib/jets/router/route.rb,
lib/jets/router.rb,
lib/jets/router/dsl.rb,
lib/jets/router/util.rb,
lib/jets/router/error.rb,
lib/jets/router/scope.rb,
lib/jets/router/state.rb,
lib/jets/router/finder.rb,
lib/jets/router/matcher.rb,
lib/jets/router/method_creator.rb

Overview

route = Jets::Router::Route.new(

path: "posts",
method: :get,
to: "posts#index",

)

Defined Under Namespace

Modules: Dsl, Helpers, Resources, Util Classes: Error, Finder, Matcher, MethodCreator, Route, Scope, State

Constant Summary collapse

@@drawn_router =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Dsl

#collection, #default_param, #each_resource, #each_resources, #member, #namespace, #prefix, #resource, #resources, #root, #scope, #scope_options!

Methods included from Dsl::Mount

#mount

Constructor Details

#initializeRouter

Returns a new instance of Router.



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

def initialize
  @routes = []
  @scope = Scope.new
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”]



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

def all_paths
  drawn_router.all_paths
end

.all_routes_valid?Boolean

Returns:

  • (Boolean)


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

def all_routes_valid?
  invalid_routes.empty?
end

.check_route_connected_functionsObject

Checks that all routes are validate and have corresponding lambda functions



181
182
183
184
185
186
187
188
189
# File 'lib/jets/router.rb', line 181

def check_route_connected_functions
  return true if all_routes_valid?

  puts "Please double check the routes below map to valid controllers:".color(:red)
  invalid_routes.each do |route|
    puts "  /#{route.path} => #{route.controller_name}##{route.action_name}"
  end
  false
end

.clear!Object



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

def clear!
  @@drawn_router = nil
  Jets::Router::Helpers::NamedRoutesHelper.clear!
end

.drawObject

Class methods



116
117
118
# File 'lib/jets/router.rb', line 116

def draw
  drawn_router
end

.drawn_routerObject



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

def drawn_router
  return @@drawn_router if @@drawn_router

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

.has_controller?(name) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/jets/router.rb', line 111

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

.help(routes) ⇒ Object



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

def help(routes)
  return "Your routes table is empty." if routes.empty?

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

.invalid_routesObject



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

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

.routesObject



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

def routes
  drawn_router.routes
end

.to_jsonObject

So we can save state in s3 post deploy. Example of structure.

[
  {"scope"=>{"options"=>{"as"=>"posts", "prefix"=>"posts", "param"=>nil, "from"=>"resources"}, "parent"=>{"options"=>{}, "parent"=>nil, "level"=>1}, "level"=>2}, "options"=>{"to"=>"posts#index", "from_scope"=>true, "path"=>"posts", "method"=>"get"}, "path"=>"posts", "to"=>"posts#index", "as"=>"posts"},
  {"scope"=>{"options"=>{"as"=>"posts", "prefix"=>"posts", "param"=>nil, "from"=>"resources"}, "parent"=>{"options"=>{}, "parent"=>nil, "level"=>1}, "level"=>2}, "options"=>{"to"=>"posts#new", "from_scope"=>true, "path"=>"posts/new", "method"=>"get"}, "path"=>"posts/new", "to"=>"posts#new", "as"=>"new_post"},
  ...
]


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

def to_json
  JSON.dump(routes.map(&:to_h))
end

.validate_routes!Object



176
177
178
# File 'lib/jets/router.rb', line 176

def validate_routes!
  check_route_connected_functions
end

Instance Method Details

#all_pathsObject

Useful for creating API Gateway Resources



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/jets/router.rb', line 77

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)


62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/jets/router.rb', line 62

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



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

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



26
27
28
29
30
31
32
33
# File 'lib/jets/router.rb', line 26

def create_route(options)
  # TODO: Can use it to add additional things like authorization_type
  # Would be good to add authorization_type at the controller level also
  infer_to_option!(options)
  handle_on!(options)
  MethodCreator.new(options, @scope).define_url_helper!
  @routes << Route.new(options, @scope)
end

#draw(&block) ⇒ Object



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

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

#handle_on!(options) ⇒ Object



55
56
57
58
59
60
# File 'lib/jets/router.rb', line 55

def handle_on!(options)
  if options[:on] && !%w[resources resource].include?(@scope.from.to_s)
    raise Error.new("ERROR: The `on:` option can only be used within a resource or resources block")
  end
  options[:on] ||= @on_option if @on_option
end

#infer_to_option!(options) ⇒ Object

Can possibly infer to option from the path. Example:

get 'posts/index'
get 'posts', to: 'posts#index'

get 'posts/show'
get 'posts', to: 'posts#show'


43
44
45
46
47
48
49
50
51
52
53
# File 'lib/jets/router.rb', line 43

def infer_to_option!(options)
  return if options[:to]

  path = options[:path].to_s
  return unless path.include?('/')

  items = path.split('/')
  if items.size == 2
    options[:to] = items.join('#')
  end
end

#ordered_routesObject

Useful for RouterMatcher

Precedence: Routes with wildcards are considered after routes without wildcards

Routes with fewer captures are ordered first since both /posts/:post_id/comments/new and /posts/:post_id/comments/:id are equally long

Routes with the same amount of captures and wildcards are orderd so that the longest path is considered first since posts/:id and posts/:id/edit can both match.



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

def ordered_routes
  length = Proc.new { |r| [r.path.count("*"), r.path.count(":"), r.path.length * -1] }
  routes.sort_by(&length)
end