From b3fe9afc0f9eb843dc6d68c4876a4e260f73a72f Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 23 May 2023 09:01:25 -0700 Subject: [PATCH] Allow symbol_matcher in symbol_matchers plugin to take a block to allow type conversion This allows symbol matchers to have the same flexibility as class matchers. This changes the behavior of the automatically generated match_symbol_* private request methods to return an array of the regexp and any conversion block, instead of just the regexp. --- CHANGELOG | 4 +++ lib/roda/plugins/symbol_matchers.rb | 41 +++++++++++++++++++++++++---- spec/plugin/symbol_matchers_spec.rb | 18 ++++++++++--- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 679be234..13981857 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ += master + +* Allow symbol_matcher in symbol_matchers plugin to take a block to allow type conversion (jeremyevans) + = 3.68.0 (2023-05-11) * Make Roda.run in multi_run plugin accept blocks to allow autoloading the apps to dispatch to (jeremyevans) diff --git a/lib/roda/plugins/symbol_matchers.rb b/lib/roda/plugins/symbol_matchers.rb index 9afded88..cb80814a 100644 --- a/lib/roda/plugins/symbol_matchers.rb +++ b/lib/roda/plugins/symbol_matchers.rb @@ -37,6 +37,35 @@ module RodaPlugins # # If using this plugin with the params_capturing plugin, this plugin should # be loaded first. + # + # You can provide a block when calling +symbol_matcher+, and it will be called + # for all matches to allow for type conversion. The block must return an + # array: + # + # symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d| + # [Date.new(y.to_i, m.to_i, d.to_i)] + # end + # + # route do |r| + # r.on :date do |date| + # # date is an instance of Date + # end + # end + # + # If you have a segment match the passed regexp, but decide during block + # processing that you do not want to treat it as a match, you can have the + # block return nil or false. This is useful if you want to make sure you + # are using valid data: + # + # symbol_matcher(:date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d| + # y = y.to_i + # m = m.to_i + # d = d.to_i + # [Date.new(y, m, d)] if Date.valid_date?(y, m, d) + # end + # + # However, if providing a block to the symbol_matchers plugin, the symbol may + # not work with the params_capturing plugin. module SymbolMatchers def self.load_dependencies(app) app.plugin :_symbol_regexp_matchers @@ -50,9 +79,10 @@ def self.configure(app) module ClassMethods # Set the regexp to use for the given symbol, instead of the default. - def symbol_matcher(s, re) + def symbol_matcher(s, re, &block) meth = :"match_symbol_#{s}" - self::RodaRequest.send(:define_method, meth){re} + array = [re, block].freeze + self::RodaRequest.send(:define_method, meth){array} self::RodaRequest.send(:private, meth) end end @@ -67,8 +97,8 @@ def _match_symbol(s) meth = :"match_symbol_#{s}" if respond_to?(meth, true) # Allow calling private match methods - re = send(meth) - consume(self.class.cached_matcher(re){re}) + re, block = send(meth) + consume(self.class.cached_matcher(re){re}, &block) else super end @@ -80,7 +110,8 @@ def _match_symbol_regexp(s) meth = :"match_symbol_#{s}" if respond_to?(meth, true) # Allow calling private match methods - send(meth) + re, = send(meth) + re else super end diff --git a/spec/plugin/symbol_matchers_spec.rb b/spec/plugin/symbol_matchers_spec.rb index e136a7a5..412d7caa 100644 --- a/spec/plugin/symbol_matchers_spec.rb +++ b/spec/plugin/symbol_matchers_spec.rb @@ -5,6 +5,9 @@ app(:bare) do plugin :symbol_matchers symbol_matcher(:f, /(f+)/) + symbol_matcher(:c, /(c+)/) do |cs| + [cs, cs.length] unless cs.length == 5 + end route do |r| r.is :d do |d| @@ -19,6 +22,10 @@ "f#{f}" end + r.is :c do |cs, nc| + "#{cs}#{nc}" + end + r.is 'q', :rest do |rest| "rest#{rest}" end @@ -27,8 +34,8 @@ "w#{w}" end - r.is :d, :w, :f do |d, w, f| - "dwf#{d}#{w}#{f}" + r.is :d, :w, :f, :c do |d, w, f, cs, nc| + "dwfc#{d}#{w}#{f}#{cs}#{nc}" end end end @@ -40,9 +47,12 @@ body("/1az0").must_equal 'w1az0' body("/f").must_equal 'ff' body("/ffffffffffffffff").must_equal 'fffffffffffffffff' + body("/c").must_equal 'c1' + body("/cccc").must_equal 'cccc4' + body("/ccccc").must_equal 'wccccc' status("/-").must_equal 404 - body("/1/1a/f").must_equal 'dwf11af' - body("/12/1azy/fffff").must_equal 'dwf121azyfffff' + body("/1/1a/f/cc").must_equal 'dwfc11afcc2' + body("/12/1azy/fffff/ccc").must_equal 'dwfc121azyfffffccc3' status("/1/f/a").must_equal 404 body("/q/a/b/c/d//f/g").must_equal 'resta/b/c/d//f/g' body('/q/').must_equal 'rest'