“use” keyword/word in Ruby/Rails/Rack code
-
26-06-2021 - |
Question
Recently I happened to see this word in Ruby code, use
, when I was going through some code related to goliath, middleware etc. Looks like it is different from include
/extend
, and require
.
Can somebody explain why this use
keyword exists, and how it is different from include
/require
? How does it work, when to use it?
Solution
The Documentation
As people have pointed out, use
is not a Ruby keyword, it is in fact a method of the Rack::Builder
class:
use(middleware, *args, &block)
Specifies middleware to use in a stack.
This documentation (pointed out by @user166390) describes it like this:
Rack::Builder
implements a small DSL to iteratively constructRack
applications.Example:
app = Rack::Builder.new { use Rack::CommonLogger use Rack::ShowExceptions map "/lobster" do use Rack::Lint run Rack::Lobster.new end }
Or
app = Rack::Builder.app do use Rack::CommonLogger lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] } end
use
adds a middleware to the stack,run
dispatches to an application.
The Source Code
I'm not too familiar with the Rack::Builder
source code, but it looks like each time you call use
with a new middleware module, it gets added to an array, and each module is run/injected in the reverse order in which it was added (last-in-first-out order, a.k.a. stack order). The result of running the previous middleware is passed to the next middleware in the stack via inject
:
-
def initialize(default_app = nil,&block) # @use is parallel assigned to []. @use, @map, @run = [], nil, default_app instance_eval(&block) if block_given? end
-
def use(middleware, *args, &block) if @map mapping, @map = @map, nil @use << proc { |app| generate_map app, mapping } end # The new middleware is added to the @use array. @use << proc { |app| middleware.new(app, *args, &block) } end
-
def to_app app = @map ? generate_map(@run, @map) : @run fail "missing run or map statement" unless app # The middlewares are injected in reverse order. @use.reverse.inject(app) { |a,e| e[a] } end