lib/roda/plugins/custom_matchers.rb
# frozen-string-literal: true # class Roda module RodaPlugins # The custom_matchers plugin supports using arbitrary objects # as matchers, as long as the application has been configured # to accept such objects. # # After loading the plugin, support for custom matchers can be # configured using the +custom_matcher+ class method. This # method is generally passed the class of the object you want # to use as a custom matcher, as well as a block. The block # will be called in the context of the request instance # with the specific matcher used in the match method. # # Blocks can append to the captures in order to yield the appropriate # values to match blocks, or call request methods that append to the # captures. # # Example: # # plugin :custom_matchers # method_segment = Struct.new(:request_method, :next_segment) # custom_matcher(method_segment) do |matcher| # # self is the request instance ("r" yielded in the route block below) # if matcher.request_method == self.request_method # match(matcher.next_segment) # end # end # # get_foo = method_segment.new('GET', 'foo') # post_any = method_segment.new('POST', String) # route do |r| # r.on('baz') do # r.on(get_foo) do # # GET method, /baz/foo prefix # end # # r.is(post_any) do |seg| # # for POST /baz/bar, seg is "bar" # end # end # # r.on('quux') do # r.is(get_foo) do # # GET method, /quux/foo route # end # # r.on(post_any) do |seg| # # for POST /quux/xyz, seg is "xyz" # end # end # end module CustomMatchers def self.configure(app) app.opts[:custom_matchers] ||= OPTS end module ClassMethods def custom_matcher(match_class, &block) custom_matchers = Hash[opts[:custom_matchers]] meth = custom_matchers[match_class] = custom_matchers[match_class] || :"_custom_matcher_#{match_class}" opts[:custom_matchers] = custom_matchers.freeze self::RodaRequest.send(:define_method, meth, &block) nil end end module RequestMethods private # Try custom matchers before calling super def unsupported_matcher(matcher) roda_class.opts[:custom_matchers].each do |match_class, meth| if match_class === matcher return send(meth, matcher) end end super end end end register_plugin(:custom_matchers, CustomMatchers) end end