diff --git a/CHANGELOG.md b/CHANGELOG.md index 0177ac299b..ca2b42bf95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Next Release * [#540](/~https://github.com/intridea/grape/pull/540): Ruby 2.1.0 is now supported - [@salimane](/~https://github.com/salimane). * [#544](/~https://github.com/intridea/grape/pull/544): The `rescue_from` keyword now handles subclasses of exceptions by default - [@xevix](/~https://github.com/xevix). * [#545](/~https://github.com/intridea/grape/pull/545): Added `type` (Array or Hash) support to `requires`, `optional` and `group` - [@bwalex](/~https://github.com/bwalex). +* [#550](/~https://github.com/intridea/grape/pull/550): Added possibility to define reusable params - [@dm1try](/~https://github.com/dm1try). * Your contribution here. #### Fixes diff --git a/README.md b/README.md index 192bc1cf3b..44e55b7a22 100644 --- a/README.md +++ b/README.md @@ -576,6 +576,58 @@ class API < Grape::API end ``` +You can define reusable `params` using `helpers`. + +```ruby +class API < Grape::API + helpers do + params :pagination do + optional :page, type: Integer + optional :per_page, type: Integer + end + end + + desc "Get collection" + params do + use :pagination # aliases: includes, use_scope + end + get do + Collection.page(params[:page]).per(params[:per_page]) + end +end +``` + +You can also define reusable `params` using shared helpers. + +```ruby +module SharedParams + extend Grape::API::Helpers + + params :period do + optional :start_date + optional :end_date + end + + params :pagination do + optional :page, type: Integer + optional :per_page, type: Integer + end +end + +class API < Grape::API + helpers SharedParams + + desc "Get collection" + params do + use :period, :pagination + end + get do + Collection.from(params[:start_date]).to(params[:end_date]) + .page(params[:page]).per(params[:per_page]) + end +end +``` + ## Cookies You can set, get and delete your cookies very simply using `cookies` method. diff --git a/lib/grape/api.rb b/lib/grape/api.rb index f1dc829900..1163944621 100644 --- a/lib/grape/api.rb +++ b/lib/grape/api.rb @@ -268,11 +268,16 @@ def helpers(new_mod = nil, &block) if block_given? || new_mod mod = settings.peek[:helpers] || Module.new if new_mod + inject_api_helpers_to_mod(new_mod) if new_mod.is_a?(Helpers) mod.class_eval do include new_mod end end - mod.class_eval(&block) if block_given? + if block_given? + inject_api_helpers_to_mod(mod) do + mod.class_eval(&block) + end + end set(:helpers, mod) else mod = Module.new @@ -509,6 +514,12 @@ def inherit_settings(other_stack) e.options[:app].inherit_settings(other_stack) if e.options[:app].respond_to?(:inherit_settings, true) end end + + def inject_api_helpers_to_mod(mod, &block) + mod.extend(Helpers) + yield if block_given? + mod.api_changed(self) + end end def initialize @@ -581,5 +592,28 @@ def add_head_not_allowed_methods_and_options_methods end end end + + # This module extends user defined helpers + # to provide some API-specific functionality + module Helpers + attr_accessor :api + def params(name, &block) + @named_params ||= {} + @named_params.merge! name => block + end + + def api_changed(new_api) + @api = new_api + process_named_params + end + + protected + + def process_named_params + if @named_params && @named_params.any? + api.imbue(:named_params, @named_params) + end + end + end end end diff --git a/lib/grape/validations.rb b/lib/grape/validations.rb index 886cddab1a..61a2afe4a2 100644 --- a/lib/grape/validations.rb +++ b/lib/grape/validations.rb @@ -147,6 +147,18 @@ def params(params) params end + def use(*names) + named_params = @api.settings[:named_params] || {} + names.each do |name| + params_block = named_params.fetch(name) do + raise "Params :#{name} not found!" + end + instance_eval(¶ms_block) + end + end + alias_method :use_scope, :use + alias_method :includes, :use + def full_name(name) return "#{@parent.full_name(@element)}[#{name}]" if @parent name.to_s diff --git a/spec/grape/validations_spec.rb b/spec/grape/validations_spec.rb index 12824ceccc..a5b26d00ca 100644 --- a/spec/grape/validations_spec.rb +++ b/spec/grape/validations_spec.rb @@ -698,5 +698,60 @@ def validate_param!(attr_name, params) end end end # end custom validation + + context 'named' do + context 'can be defined' do + it 'in helpers' do + subject.helpers do + params :pagination do + end + end + end + + it 'in helper module which kind of Grape::API::Helpers' do + module SharedParams + extend Grape::API::Helpers + params :pagination do + end + end + subject.helpers SharedParams + end + end + + context 'can be included in usual params' do + before do + module SharedParams + extend Grape::API::Helpers + params :period do + optional :start_date + optional :end_date + end + end + subject.helpers SharedParams + + subject.helpers do + params :pagination do + optional :page, type: Integer + optional :per_page, type: Integer + end + end + end + + it 'by #use' do + subject.params do + use :pagination + end + subject.settings[:declared_params].should eq [:page, :per_page] + end + + it 'by #use with multiple params' do + subject.params do + use :pagination, :period + end + subject.settings[:declared_params].should eq [:page, :per_page, :start_date, :end_date] + end + + end + end end end