Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

namespace support options argument, only requirements options now #363

Merged
merged 1 commit into from
Mar 12, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Next Release
* Parsed body input from POST and PUT requests is now available in `api.request.body` - [@dblock](/~https://github.com/dblock).
* [#343](/~https://github.com/intridea/grape/pull/343): Fix: return `Content-Type: text/plain` with error 405 - [@gustavosaume](/~https://github.com/gustavosaume), [@wyattisimo](/~https://github.com/wyattisimo).
* [#357](/~https://github.com/intridea/grape/pull/357): Grape now requires Rack 1.3.0 or newer - [@jhecking](/~https://github.com/jhecking).
* [#320](/~https://github.com/intridea/grape/issues/320): Namespace accept requirements now - [@niedhui](/~https://github.com/niedhui).
* Your contribution here.

0.3.2 (2/28/2013)
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,20 @@ header "X-Robots-Tag", "noindex"
## Routes

Optionally, you can define requirements for your named route parameters using regular
expressions. The route will match only if all requirements are met.
expressions on namespace or endpoint. The route will match only if all requirements are met.

```ruby
get ':id', :requirements => { :id => /[0-9]*/ } do
Status.find(params[:id])
end

namespace :outer, :requirements => { :id => /[0-9]*/ } do
get :id do
end

get ":id/edit" do
end
end
```

## Helpers
Expand Down Expand Up @@ -855,7 +863,7 @@ section above. It also supports custom data formats. You must declare additional
`content_type` and optionally supply a parser via `parser` unless a parser is already available within
Grape to enable a custom format. Such a parser can be a function or a class.

With a parser, parsed data is available "as-is" in `env['api.request.body']`.
With a parser, parsed data is available "as-is" in `env['api.request.body']`.
Without a parser, data is available "as-is" and in `env['api.request.input']`.

The following example is a trivial parser that will assign any input with the "text/custom" content-type
Expand Down
1 change: 1 addition & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module Grape
autoload :API, 'grape/api'
autoload :Endpoint, 'grape/endpoint'
autoload :Route, 'grape/route'
autoload :Namespace, 'grape/namespace'
autoload :Cookies, 'grape/cookies'
autoload :Validations, 'grape/validations'

Expand Down
6 changes: 3 additions & 3 deletions lib/grape/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -356,17 +356,17 @@ def delete(paths = ['/'], options = {}, &block); route('DELETE', paths, options,
def options(paths = ['/'], options = {}, &block); route('OPTIONS', paths, options, &block) end
def patch(paths = ['/'], options = {}, &block); route('PATCH', paths, options, &block) end

def namespace(space = nil, &block)
def namespace(space = nil, options = {}, &block)
if space || block_given?
previous_namespace_description = @namespace_description
@namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
@last_description = nil
nest(block) do
set(:namespace, space.to_s) if space
set(:namespace, Namespace.new(space, options)) if space
end
@namespace_description = previous_namespace_description
else
Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace].try(:space)}.join('/'))
end
end

Expand Down
12 changes: 8 additions & 4 deletions lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ def generate_api_method(method_name, &block)
def initialize(settings, options = {}, &block)
@settings = settings
if block_given?
method_name = [
method_name = [
options[:method],
settings.gather(:namespace).join("/"),
settings.gather(:namespace).map(&:space).join("/"),
settings.gather(:mount_path).join("/"),
Array(options[:path]).join("/")
].join(" ")
Expand Down Expand Up @@ -88,7 +88,11 @@ def prepare_routes
anchor = options[:route_options][:anchor]
anchor = anchor.nil? ? true : anchor

requirements = options[:route_options][:requirements] || {}
endpoint_requirements = options[:route_options][:requirements] || {}
all_requirements = (settings.gather(:namespace).map(&:requirements) << endpoint_requirements)
requirements = all_requirements.reduce({}) do |base_requirements, single_requirements|
base_requirements.merge!(single_requirements)
end

path = compile_path(prepared_path, anchor && !options[:app], requirements)
regex = Rack::Mount::RegexpWithNamedGroups.new(path)
Expand Down Expand Up @@ -137,7 +141,7 @@ def prepare_path(path)
end

def namespace
Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace].try(:space)}.join('/'))
end

def compile_path(prepared_path, anchor = true, requirements = {})
Expand Down
16 changes: 16 additions & 0 deletions lib/grape/namespace.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Grape
class Namespace
attr_reader :space, :options

# options:
# requirements: a hash
def initialize(space, options = {})
@space, @options = space.to_s, options
end

def requirements
options[:requirements] || {}
end

end
end
31 changes: 31 additions & 0 deletions spec/grape/endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def app; subject end
end

context 'with special requirements' do

it 'parses email param with provided requirements for params' do
subject.get('/:person_email', :requirements => { :person_email => /.*/ }) do
params[:person_email]
Expand Down Expand Up @@ -273,6 +274,36 @@ def app; subject end
get 'rodzyn@test.com/wrong_middle/1'
last_response.status.should == 404
end

context ' namespace requirements' do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space after the quote.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks. Will be more careful next time

before :each do
subject.namespace :outer, :requirements => { :person_email => /abc@(.*).com/ } do
get('/:person_email') do
params[:person_email]
end

namespace :inner, :requirements => {:number => /[0-9]/, :person_email => /rodzyn@(.*).com/ }do
get '/:person_email/test/:number' do
params[:person_email] << params[:number]
end
end
end
end
it "parse email param with provided requirements for params" do
get '/outer/abc@grape.com'
last_response.body.should == 'abc@grape.com'
end

it "should override outer namespace's requirements" do
get '/outer/inner/rodzyn@testing.wrong/test/1'
last_response.status.should == 404

get '/outer/inner/rodzyn@testing.com/test/1'
last_response.status.should == 200
last_response.body.should == 'rodzyn@testing.com1'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use @example.com for all emails, that's a good convention for tests. Lets not help bots generate more spam going nowhere :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it

end

end
end

context 'from body parameters' do
Expand Down