# frozen_string_literal: true require 'sinatra/base' module Sinatra # = Sinatra::Extension # # Sinatra::Extension is a mixin that provides some syntactic sugar # for your extensions. It allows you to call almost any # Sinatra::Base method directly inside your extension # module. This means you can use +get+ to define a route, +before+ # to define a before filter, +set+ to define a setting and so on. # # Is important to be aware that this mixin remembers the method calls you # make, and then, when your extension is registered, replays them on the # Sinatra application that has been extended. In order to do that, it # defines a registered method, so, if your extension defines one # too, remember to call +super+. # # == Usage # # Just require the mixin and extend your extension with it: # # require 'sinatra/extension' # # module MyExtension # extend Sinatra::Extension # # # set some settings for development # configure :development do # set :reload_stuff, true # end # # # define a route # get '/' do # 'Hello World' # end # # # The rest of your extension code goes here... # end # # You can also create an extension with the +new+ method: # # MyExtension = Sinatra::Extension.new do # # Your extension code goes here... # end # # This is useful when you just want to pass a block to # Sinatra::Base.register. module Extension def self.new(&block) ext = Module.new.extend(self) ext.class_eval(&block) ext end def settings self end def configure(*args, &block) record(:configure, *args) { |c| c.instance_exec(c, &block) } end def registered(base = nil, &block) base ? replay(base) : record(:class_eval, &block) end private def record(method, *args, &block) recorded_methods << [method, args, block] end def replay(object) recorded_methods.each { |m, a, b| object.send(m, *a, &b) } end def recorded_methods @recorded_methods ||= [] end def method_missing(method, *args, &block) return super unless Sinatra::Base.respond_to? method record(method, *args, &block) DontCall.new(method) end class DontCall < BasicObject def initialize(method) @method = method end def method_missing(*) raise "not supposed to use result of #{@method}!" end def inspect; "#<#{self.class}: #{@method}>" end end end end