lib/roda/plugins/autoload_hash_branches.rb
# frozen-string-literal: true # class Roda module RodaPlugins # The autoload_hash_branches plugin builds on the hash_branches plugin and allows for # delaying loading of a file containing a hash branch for an application until there # is a request that uses the hash branch. This can be useful in development # to improvement startup time by not loading all branches up front. It can also be # useful in testing subsets of an application by only loading the hash branches being # tested. # # You can specify a single hash branch for autoloading: # # plugin :autoload_hash_branches # autoload_hash_branch('branch_name', '/absolute/path/to/file') # autoload_hash_branch('namespace', 'branch_name', 'relative/path/to/file') # # You can also set the plugin to autoload load all hash branch files in a given directory. # This will look at each .rb file in the directory, and add an autoload for it, using the # filename without the .rb as the branch name: # # autoload_hash_branch_dir('/path/to/dir') # autoload_hash_branch_dir('namespace', '/path/to/dir') # # In both cases, when the autoloaded file is required, it should redefine the same # hash branch. If it does not, requests to the hash branch will result in a 404 error. # # When freezing an application, all hash branches are automatically loaded, because # autoloading hash branches does not work for frozen applications. module AutoloadHashBranches def self.load_dependencies(app) app.plugin :hash_branches end def self.configure(app) app.opts[:autoload_hash_branch_files] ||= [] end module ClassMethods # Autoload the given file when there is request for the hash branch. # The given file should configure the hash branch specified. def autoload_hash_branch(namespace='', segment, file) segment = "/#{segment}" file = File.expand_path(file) opts[:autoload_hash_branch_files] << file routes = opts[:hash_branches][namespace] ||= {} meth = routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1) do |r| loc = method(routes[segment]).source_location require file # Avoid infinite loop in case method is not overridden if method(meth).source_location != loc send(meth, r) end end nil end # For each .rb file in the given directory, add an autoloaded hash branch # based on the file name. def autoload_hash_branch_dir(namespace='', dir) Dir.new(dir).entries.each do |file| if file =~ /\.rb\z/i autoload_hash_branch(namespace, file.sub(/\.rb\z/i, ''), File.join(dir, file)) end end end # Eagerly load all hash branches when freezing the application. def freeze opts.delete(:autoload_hash_branch_files).each{|file| require file} super end end end register_plugin(:autoload_hash_branches, AutoloadHashBranches) end end