Class: Bridgetown::Rack::Routes

Inherits:
Object
  • Object
show all
Includes:
Prioritizable
Defined in:
lib/bridgetown-core/rack/routes.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Prioritizable

#<=>, included

Constructor Details

#initialize(roda_app) ⇒ Routes

Returns a new instance of Routes.

Parameters:



195
196
197
# File 'lib/bridgetown-core/rack/routes.rb', line 195

def initialize(roda_app)
  @_roda_app = roda_app
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, **kwargs, &block) ⇒ Object

Any missing methods are passed along to the underlying Roda app if possible



208
209
210
211
212
213
214
# File 'lib/bridgetown-core/rack/routes.rb', line 208

def method_missing(method_name, *args, **kwargs, &block)
  if @_roda_app.respond_to?(method_name.to_sym)
    @_roda_app.send method_name.to_sym, *args, **kwargs, &block
  else
    super
  end
end

Class Attribute Details

.router_blockProc

Returns:

  • (Proc)


58
59
60
# File 'lib/bridgetown-core/rack/routes.rb', line 58

def router_block
  @router_block
end

.tracked_subclassesHash<String, Class(Routes)>

Returns:

  • (Hash<String, Class(Routes)>)


55
56
57
# File 'lib/bridgetown-core/rack/routes.rb', line 55

def tracked_subclasses
  @tracked_subclasses
end

Class Method Details

.<=>(other) ⇒ Integer

Spaceship is priority [higher -> lower]

Parameters:

  • other (Class(Routes))

    The class to be compared.

Returns:

  • (Integer)

    -1, 0, 1.



64
65
66
# File 'lib/bridgetown-core/rack/routes.rb', line 64

def <=>(other)
  "#{priorities[priority]}#{self}" <=> "#{priorities[other.priority]}#{other}"
end

.inherited(base) ⇒ Object

Parameters:



69
70
71
72
# File 'lib/bridgetown-core/rack/routes.rb', line 69

def inherited(base)
  Bridgetown::Rack::Routes.track_subclass base
  super
end

.load_all_routes(roda_app) ⇒ void

This method returns an undefined value.

Run the Roda public plugin first, set up live reload if allowed, then run through all the Routes blocks. If the file-based router plugin is available, kick off that request process next.

Parameters:



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/bridgetown-core/rack/routes.rb', line 148

def load_all_routes(roda_app)
  roda_app.request.public

  if Bridgetown.env.development? &&
      !Bridgetown::Current.preloaded_configuration.skip_live_reload
    setup_live_reload roda_app
  end

  Bridgetown::Rack::Routes.sorted_subclasses&.each do |klass|
    klass.merge roda_app
  end
end

.merge(roda_app) ⇒ Object

Initialize a new Routes instance and execute the route as part of the Roda app request cycle

Parameters:



115
116
117
118
119
# File 'lib/bridgetown-core/rack/routes.rb', line 115

def merge(roda_app)
  return unless router_block

  new(roda_app).handle_routes
end

rubocop:disable Bridgetown/NoPutsAllowed, Metrics/MethodLength



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
50
51
# File 'lib/bridgetown-core/rack/routes.rb', line 24

def print_routes
  # TODO: this needs to be fully documented
  routes = begin
    JSON.parse(
      File.read(
        File.join(Bridgetown::Current.preloaded_configuration.root_dir, ".routes.json")
      )
    )
  rescue StandardError
    []
  end
  puts
  puts "Routes:"
  puts "======="
  if routes.blank?
    puts "No routes found. Have you commented all of your routes?"
    puts "Documentation: https://github.com/jeremyevans/roda-route_list#basic-usage-"
  end

  routes.each do |route|
    puts [
      route["methods"]&.join("|") || "GET",
      route["path"],
      route["file"] ? "\n  File: #{route["file"]}" : nil,
    ].compact.join(" ")
  end
  puts
end

.reload_subclassesvoid

This method returns an undefined value.



86
87
88
89
90
91
92
# File 'lib/bridgetown-core/rack/routes.rb', line 86

def reload_subclasses
  Bridgetown::Rack::Routes.tracked_subclasses&.each_key do |klassname|
    Kernel.const_get(klassname)
  rescue NameError
    Bridgetown::Rack::Routes.tracked_subclasses.delete klassname
  end
end

.route(&block) ⇒ Object

Add a router block via the current Routes class

Example:

class Routes::Hello < Bridgetown::Rack::Routes route do |r| r.get "hello", String do |name| { hello: "friend #name" } end end end

Parameters:

  • block (Proc)


107
108
109
# File 'lib/bridgetown-core/rack/routes.rb', line 107

def route(&block)
  self.router_block = block
end

.setup_live_reload(app) ⇒ Object

Parameters:



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/bridgetown-core/rack/routes.rb', line 162

def setup_live_reload(app) # rubocop:disable Metrics
  sleep_interval = 0.2
  file_to_check = File.join(Bridgetown::Current.preloaded_configuration.destination,
                            "index.html")
  errors_file = Bridgetown.build_errors_path

  app.request.get "_bridgetown/live_reload" do
    app.response["Content-Type"] = "text/event-stream"

    @_mod = File.exist?(file_to_check) ? File.stat(file_to_check).mtime.to_i : 0
    app.stream async: true do |out|
      # 5 second intervals so Puma's threads aren't all exausted
      (5 / sleep_interval).to_i.times do
        break if Bridgetown::Rack.interrupted

        new_mod = File.exist?(file_to_check) ? File.stat(file_to_check).mtime.to_i : 0
        if @_mod < new_mod
          out << "data: reloaded!\n\n"
          break
        elsif File.exist?(errors_file)
          out << "event: builderror\ndata: #{File.read(errors_file).to_json}\n\n"
        else
          out << "data: #{new_mod}\n\n"
        end

        sleep sleep_interval
      end
    end
  end
end

.sorted_subclassesArray<Class(Routes)>

Returns:



81
82
83
# File 'lib/bridgetown-core/rack/routes.rb', line 81

def sorted_subclasses
  Bridgetown::Rack::Routes.tracked_subclasses&.values&.sort
end

.start!(roda_app) ⇒ void

This method returns an undefined value.

Start the Roda app request cycle. There are two different code paths depending on if there's a site base_path configured

Parameters:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/bridgetown-core/rack/routes.rb', line 126

def start!(roda_app)
  if Bridgetown::Current.preloaded_configuration.base_path == "/"
    load_all_routes roda_app
    return
  end

  # Support custom base_path configurations
  roda_app.request.on(
    Bridgetown::Current.preloaded_configuration.base_path.delete_prefix("/")
  ) do
    load_all_routes roda_app
  end

  nil
end

.track_subclass(klass) ⇒ Object

Parameters:



75
76
77
78
# File 'lib/bridgetown-core/rack/routes.rb', line 75

def track_subclass(klass)
  Bridgetown::Rack::Routes.tracked_subclasses ||= {}
  Bridgetown::Rack::Routes.tracked_subclasses[klass.name] = klass
end

Instance Method Details

#handle_routesObject

Execute the router block via the instance, passing it the Roda request

Returns:

  • (Object)

    whatever is returned by the router block as expected by the Roda API



203
204
205
# File 'lib/bridgetown-core/rack/routes.rb', line 203

def handle_routes
  instance_exec(@_roda_app.request, &self.class.router_block)
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


216
217
218
# File 'lib/bridgetown-core/rack/routes.rb', line 216

def respond_to_missing?(method_name, include_private = false)
  @_roda_app.respond_to?(method_name.to_sym, include_private) || super
end