Skip to content

Commit 037cd3d

Browse files
authored
Merge pull request #1646 from pablonahuelgomez/allow-helpers-to-mix-in-a-list-of-modules
Add ability to include an array of modules as helpers
2 parents f34fe12 + e027e49 commit 037cd3d

File tree

3 files changed

+58
-24
lines changed

3 files changed

+58
-24
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* [#1594](https://github.com/ruby-grape/grape/pull/1594): Replace `Hashie::Mash` parameters with `ActiveSupport::HashWithIndifferentAccess` - [@james2m](https://github.com/james2m), [@dblock](https://github.com/dblock).
66
* [#1622](https://github.com/ruby-grape/grape/pull/1622): Add `except_values` validator to replace `except` option of `values` validator - [@jlfaber](https://github.com/jlfaber).
77
* [#1635](https://github.com/ruby-grape/grape/pull/1635): Instrument validators with ActiveSupport::Notifications - [@ktimothy](https://github.com/ktimothy).
8+
* [#1646](https://github.com/ruby-grape/grape/pull/1646): Add ability to include an array of modules as helpers - [@pablonahuelgomez](https://github.com/pablonahuelgomez).
89
* Your contribution here.
910

1011
#### Fixes

lib/grape/dsl/helpers.rb

+32-18
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module ClassMethods
1313
# When called without a block, all known helpers within this scope
1414
# are included.
1515
#
16-
# @param [Module] new_mod optional module of methods to include
16+
# @param [Array] new_modules optional array of modules to include
1717
# @param [Block] block optional block of methods to include
1818
#
1919
# @example Define some helpers.
@@ -26,28 +26,42 @@ module ClassMethods
2626
# end
2727
# end
2828
#
29-
def helpers(new_mod = nil, &block)
30-
if block_given? || new_mod
31-
mod = new_mod || Module.new
32-
define_boolean_in_mod(mod)
33-
inject_api_helpers_to_mod(mod) if new_mod
29+
# @example Include many modules
30+
#
31+
# class ExampleAPI < Grape::API
32+
# helpers Authentication, Mailer, OtherModule
33+
# end
34+
#
35+
def helpers(*new_modules, &block)
36+
include_new_modules(new_modules) if new_modules.any?
37+
include_block(block) if block_given?
38+
include_all_in_scope if !block_given? && new_modules.empty?
39+
end
3440

35-
inject_api_helpers_to_mod(mod) do
36-
mod.class_eval(&block)
37-
end if block_given?
41+
protected
3842

39-
namespace_stackable(:helpers, mod)
40-
else
41-
mod = Module.new
42-
namespace_stackable(:helpers).each do |mod_to_include|
43-
mod.send :include, mod_to_include
44-
end
45-
change!
46-
mod
43+
def include_new_modules(modules)
44+
modules.each { |mod| make_inclusion(mod) }
45+
end
46+
47+
def include_block(block)
48+
Module.new.tap do |mod|
49+
make_inclusion(mod) { mod.class_eval(&block) }
4750
end
4851
end
4952

50-
protected
53+
def make_inclusion(mod, &block)
54+
define_boolean_in_mod(mod)
55+
inject_api_helpers_to_mod(mod, &block)
56+
namespace_stackable(:helpers, mod)
57+
end
58+
59+
def include_all_in_scope
60+
Module.new.tap do |mod|
61+
namespace_stackable(:helpers).each { |mod_to_include| mod.send :include, mod_to_include }
62+
change!
63+
end
64+
end
5165

5266
def define_boolean_in_mod(mod)
5367
return if defined? mod::Boolean

spec/grape/dsl/helpers_spec.rb

+25-6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ module HelpersSpec
66
class Dummy
77
include Grape::DSL::Helpers
88

9-
def self.mod
10-
namespace_stackable(:helpers).first
9+
def self.mods
10+
namespace_stackable(:helpers)
11+
end
12+
13+
def self.first_mod
14+
mods.first
1115
end
1216
end
1317
end
@@ -36,23 +40,38 @@ def test
3640
expect(subject).to receive(:namespace_stackable).with(:helpers).and_call_original
3741
subject.helpers(&proc)
3842

39-
expect(subject.mod.instance_methods).to include(:test)
43+
expect(subject.first_mod.instance_methods).to include(:test)
4044
end
4145

4246
it 'uses provided modules' do
4347
mod = Module.new
4448

45-
expect(subject).to receive(:namespace_stackable).with(:helpers, kind_of(Grape::DSL::Helpers::BaseHelper)).and_call_original
49+
expect(subject).to receive(:namespace_stackable).with(:helpers, kind_of(Grape::DSL::Helpers::BaseHelper)).and_call_original.exactly(2).times
4650
expect(subject).to receive(:namespace_stackable).with(:helpers).and_call_original
4751
subject.helpers(mod, &proc)
4852

49-
expect(subject.mod).to eq mod
53+
expect(subject.first_mod).to eq mod
54+
end
55+
56+
it 'uses many provided modules' do
57+
mod = Module.new
58+
mod2 = Module.new
59+
mod3 = Module.new
60+
61+
expect(subject).to receive(:namespace_stackable).with(:helpers, kind_of(Grape::DSL::Helpers::BaseHelper)).and_call_original.exactly(4).times
62+
expect(subject).to receive(:namespace_stackable).with(:helpers).and_call_original.exactly(3).times
63+
64+
subject.helpers(mod, mod2, mod3, &proc)
65+
66+
expect(subject.mods).to include(mod)
67+
expect(subject.mods).to include(mod2)
68+
expect(subject.mods).to include(mod3)
5069
end
5170

5271
context 'with an external file' do
5372
it 'sets Boolean as a Virtus::Attribute::Boolean' do
5473
subject.helpers BooleanParam
55-
expect(subject.mod::Boolean).to eq Virtus::Attribute::Boolean
74+
expect(subject.first_mod::Boolean).to eq Virtus::Attribute::Boolean
5675
end
5776
end
5877
end

0 commit comments

Comments
 (0)