# frozen-string-literal: true#classRodamoduleRodaPlugins# The _optimized_matching plugin is automatically used internally to speed# up matching when a single argument String instance, String class, Integer# class, or Regexp matcher is passed to +r.on+, +r.is_+, or a verb method# such as +r.get+ or +r.post+.# # The optimization works by avoiding the +if_match+ method if possible.# Instead of clearing the captures array on every call, and having the# matching append to the captures, it checks directly for the match,# and on succesful match, it yields directly to the block without using# the captures array.moduleOptimizedMatchingTERM=Base::RequestMethods::TERMmoduleRequestMethods# Optimize the r.is method handling of a single string, String, Integer,# regexp, or true, argument.defis(*args,&block)caseargs.lengthwhen1_is1(args,&block)when0always(&block)if@remaining_path.empty?elseif_match(args<<TERM,&block)endend# Optimize the r.on method handling of a single string, String, Integer,# or regexp argument. Inline the related matching code to avoid the# need to modify @captures.defon(*args,&block)caseargs.lengthwhen1casematcher=args[0]whenStringalways{yield}if_match_string(matcher)whenClassifmatcher==Stringrp=@remaining_pathifrp.getbyte(0)==47iflast=rp.index('/',1)@remaining_path=rp[last,rp.length]always{yieldrp[1,last-1]}elsif(len=rp.length)>1@remaining_path=""always{yieldrp[1,len]}endendelsifmatcher==Integerif(matchdata=/\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path))&&(value=_match_class_convert_Integer(matchdata[1]))@remaining_path=matchdata.post_matchalways{yield(value)}endelsepath=@remaining_pathcaptures=@captures.clearmeth=:"_match_class_#{matcher}"ifrespond_to?(meth,true)# Allow calling private methods, as match methods are generally privateifsend(meth,&block)block_result(yield(*captures))throw:halt,response.finishelse@remaining_path=pathfalseendelseunsupported_matcher(matcher)endendwhenRegexpifmatchdata=self.class.cached_matcher(matcher){matcher}.match(@remaining_path)@remaining_path=matchdata.post_matchalways{yield(*matchdata.captures)}endwhentruealways(&block)whenfalse,nil# nothingelsepath=@remaining_pathcaptures=@captures.clearmatched=casematcherwhenArray_match_array(matcher)whenHash_match_hash(matcher)whenSymbol_match_symbol(matcher)whenProcmatcher.callelseunsupported_matcher(matcher)endifmatchedblock_result(yield(*captures))throw:halt,response.finishelse@remaining_path=pathfalseendendwhen0always(&block)elseif_match(args,&block)endendprivate# Optimize the r.get/r.post method handling of a single string, String, Integer,# regexp, or true, argument.def_verb(args,&block)caseargs.lengthwhen0always(&block)when1_is1(args,&block)elseif_match(args<<TERM,&block)endend# Internals of r.is/r.get/r.post optimization. Inline the related matching# code to avoid the need to modify @captures.def_is1(args,&block)casematcher=args[0]whenStringrp=@remaining_pathif_match_string(matcher)if@remaining_path.empty?always{yield}else@remaining_path=rpnilendendwhenClassifmatcher==Stringrp=@remaining_pathifrp.getbyte(0)==47&&!rp.index('/',1)&&(len=rp.length)>1@remaining_path=''always{yieldrp[1,len]}endelsifmatcher==Integerif(matchdata=/\A\/(\d{1,100})\z/.match(@remaining_path))&&(value=_match_class_convert_Integer(matchdata[1]))@remaining_path=''always{yield(value)}endelsepath=@remaining_pathcaptures=@captures.clearmeth=:"_match_class_#{matcher}"ifrespond_to?(meth,true)# Allow calling private methods, as match methods are generally privateifsend(meth,&block)&&@remaining_path.empty?block_result(yield(*captures))throw:halt,response.finishelse@remaining_path=pathfalseendelseunsupported_matcher(matcher)endendwhenRegexpif(matchdata=self.class.cached_matcher(matcher){matcher}.match(@remaining_path))&&matchdata.post_match.empty?@remaining_path=''always{yield(*matchdata.captures)}endwhentruealways(&block)if@remaining_path.empty?whenfalse,nil# nothingelsepath=@remaining_pathcaptures=@captures.clearmatched=casematcherwhenArray_match_array(matcher)whenHash_match_hash(matcher)whenSymbol_match_symbol(matcher)whenProcmatcher.callelseunsupported_matcher(matcher)endifmatched&&@remaining_path.empty?block_result(yield(*captures))throw:halt,response.finishelse@remaining_path=pathfalseendendendendendregister_plugin(:_optimized_matching,OptimizedMatching)endend