From b87430fc523cba57a2664ce9f34f2fdd4e9e03ad Mon Sep 17 00:00:00 2001 From: Juan Carlos Garcia Date: Mon, 13 Nov 2023 21:44:22 +0100 Subject: [PATCH] fix(#20): Add `params` option to the mustermann grape pattern for taking into account the parameter type --- .rspec | 2 ++ CHANGELOG.md | 10 ++++++++++ README.md | 7 ++++++- lib/mustermann/grape.rb | 19 ++++++++++++++++++- spec/grape_spec.rb | 29 +++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 .rspec create mode 100644 CHANGELOG.md diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..b3eb8b4 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ef2d64b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +### 1.0.3 (Next) + +#### Features + +* Your contribution here. + +#### Fixes + +* [#21](https://github.com/ruby-grape/mustermann-grape/pull/21): Introducing the `params` option to `Mustermann::Grape` to enhance matching by offering detailed information regarding the parameter types. - [@jcagarcia](https://github.com/jcagarcia). +* Your contribution here. \ No newline at end of file diff --git a/README.md b/README.md index c8ea566..c860815 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,17 @@ This gem implements the `grape` pattern type for Mustermann. ## Overview **Supported options:** -`capture`, `except`, `greedy`, `space_matches_plus`, `uri_decode`, `converters` and `ignore_unknown_options` +`capture`, `converters`, `except`, `greedy`, `ignore_unknown_options`, `params`, `space_matches_plus` and `uri_decode` ``` ruby require 'mustermann/grape' Mustermann.new('/:id', type: :grape).params('/foo') # => { id: 'foo' } + +# Providing params option +Mustermann.new('/:id', type: :grape, params: {"id"=>{:type=>"Integer"}}).params('/1') # => { id: '1'} +Mustermann.new('/:id', type: :grape, params: {"id"=>{:type=>"Integer"}}).params('/foo') # => nil +Mustermann.new('/:id', type: :grape, params: {"id"=>{:type=>"String"}}).params('/foo') # => { id: 'foo'} ``` ## Syntax diff --git a/lib/mustermann/grape.rb b/lib/mustermann/grape.rb index 036aa53..edd005d 100644 --- a/lib/mustermann/grape.rb +++ b/lib/mustermann/grape.rb @@ -13,11 +13,28 @@ module Mustermann # @see file:README.md#grape Syntax description in the README class Grape < AST::Pattern register :grape + supported_options :params on(nil, '?', ')') { |c| unexpected(c) } on('*') { |_c| scan(/\w+/) ? node(:named_splat, buffer.matched) : node(:splat) } - on(':') { |_c| node(:capture, constraint: "[^/\\?#\.]") { scan(/\w+/) } } + on(':') do |_c| + param_name = scan(/\w+/) + return node(:capture, param_name, constraint: "[^/\\?#\.]") { scan(/\w+/) } unless pattern + + params_opt = pattern.options[:params] + if params_opt && params_opt[param_name] && params_opt[param_name][:type] + param_type = params_opt[param_name][:type] + case(param_type) + when "Integer" + node(:capture, param_name, constraint: /\d/) { scan(/\w+/) } + else + node(:capture, param_name, constraint: "[^/\\?#\.]") { scan(/\w+/) } + end + else + node(:capture, param_name, constraint: "[^/\\?#\.]") { scan(/\w+/) } + end + end on('\\') { |_c| node(:char, expect(/./)) } on('(') { |_c| node(:optional, node(:group) { read unless scan(')') }) } on('|') { |_c| node(:or) } diff --git a/spec/grape_spec.rb b/spec/grape_spec.rb index 7336bf0..c47109d 100644 --- a/spec/grape_spec.rb +++ b/spec/grape_spec.rb @@ -751,4 +751,33 @@ example { pattern.peek_params('/foo bar') .should be_nil } end end + + context 'when params option is provided' do + context 'and they contain parameters information' do + pattern '/foo/:id', params: {"id"=>{:type=>"Integer"}} do + it { should match('/foo/1') } + it { should_not match('/foo/bar') } + end + + context 'and inherit routes are present' do + pattern '/foo/:id/bar/:reference', params: {"id"=>{:type=>"Integer"}, "reference"=>{:type=>"String"}} do + it { should match('/foo/1/bar/wadus') } + it { should_not match('/foo/bar/bar/wadus') } + end + + pattern '/foo/:id/bar/:reference', params: {"id"=>{:type=>"Integer"}, "reference"=>{:type=>"Integer"}} do + it { should match('/foo/1/bar/1') } + it { should_not match('/foo/1/bar/wadus') } + it { should_not match('/foo/bar/bar/1') } + end + end + end + + context 'and they do NOT contain parameters information' do + pattern '/foo/:id' do + it { should match('/foo/1') } + it { should match('/foo/bar') } + end + end + end end