Skip to content

Commit ba62ae1

Browse files
authored
Merge pull request #312 from sineed/sineed-custom-parameter-method
Custom parameter method
2 parents 470da85 + 2b79b8a commit ba62ae1

File tree

5 files changed

+121
-43
lines changed

5 files changed

+121
-43
lines changed

README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,12 @@ Special values:
416416

417417
* `:required => true` Will display a red '*' to show it's required
418418
* `:scope => :the_scope` Will scope parameters in the hash, scoping can be nested. See example
419+
* `:method => :method_name` Will use specified method as a parameter value
419420

420-
The value of scoped parameters can be set with both scoped (`let(:order_item_item_id)`) and unscoped (`let(:item_id)`) methods. It always searches for the scoped method first and falls back to the unscoped method.
421+
Retrieving of parameter value goes through several steps:
422+
1. if `method` option is defined and test case responds to this method then this method is used;
423+
2. if test case responds to scoped method then this method is used;
424+
3. overwise unscoped method is used.
421425

422426
```ruby
423427
resource "Orders" do
@@ -428,10 +432,13 @@ resource "Orders" do
428432
post "/orders" do
429433
parameter :name, "Order Name", :required => true, :scope => :order
430434
parameter :item, "Order items", :scope => :order
431-
parameter :item_id, "Item id", :scope => [:order, :item]
435+
parameter :item_id, "Item id", :scope => [:order, :item], method: :custom_item_id
432436

433-
let(:name) { "My Order" } # OR let(:order_name) { "My Order" }
434-
let(:item_id) { 1 } # OR let(:order_item_item_id) { 1 }
437+
let(:name) { "My Order" }
438+
# OR let(:order_name) { "My Order" }
439+
let(:item_id) { 1 }
440+
# OR let(:custom_item_id) { 1 }
441+
# OR let(:order_item_item_id) { 1 }
435442

436443
example "Creating an order" do
437444
params.should eq({

lib/rspec_api_documentation/dsl/endpoint.rb

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'rspec/core/formatters/base_formatter'
22
require 'rack/utils'
33
require 'rack/test/utils'
4+
require 'rspec_api_documentation/dsl/endpoint/params'
45

56
module RspecApiDocumentation::DSL
67
# DSL methods available inside the RSpec example.
@@ -63,11 +64,7 @@ def query_string
6364
end
6465

6566
def params
66-
parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param|
67-
set_param(hash, param)
68-
end
69-
parameters.deep_merge!(extra_params)
70-
parameters
67+
Params.new(self, example, extra_params).call
7168
end
7269

7370
def header(name, value)
@@ -99,14 +96,6 @@ def status
9996
rspec_api_documentation_client.status
10097
end
10198

102-
def in_path?(param)
103-
path_params.include?(param)
104-
end
105-
106-
def path_params
107-
example.metadata[:route].scan(/:(\w+)/).flatten
108-
end
109-
11099
def path
111100
example.metadata[:route].gsub(/:(\w+)/) do |match|
112101
if extra_params.keys.include?($1)
@@ -146,26 +135,5 @@ def delete_extra_param(key)
146135
@extra_params.delete(key.to_sym) || @extra_params.delete(key.to_s)
147136
end
148137

149-
def set_param(hash, param)
150-
key = param[:name]
151-
152-
keys = [param[:scope], key].flatten.compact
153-
method_name = keys.join('_')
154-
155-
return hash if in_path?(method_name)
156-
157-
unless respond_to?(method_name)
158-
method_name = key
159-
return hash unless respond_to?(method_name)
160-
end
161-
162-
hash.deep_merge(build_param_hash(keys, method_name))
163-
end
164-
165-
def build_param_hash(keys, method_name)
166-
value = keys[1] ? build_param_hash(keys[1..-1], method_name) : send(method_name)
167-
{ keys[0].to_s => value }
168-
end
169-
170138
end
171139
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require 'rspec_api_documentation/dsl/endpoint/set_param'
2+
3+
module RspecApiDocumentation
4+
module DSL
5+
module Endpoint
6+
class Params
7+
attr_reader :example_group, :example
8+
9+
def initialize(example_group, example, extra_params)
10+
@example_group = example_group
11+
@example = example
12+
@extra_params = extra_params
13+
end
14+
15+
def call
16+
parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param|
17+
SetParam.new(self, hash, param).call
18+
end
19+
parameters.deep_merge!(extra_params)
20+
parameters
21+
end
22+
23+
private
24+
25+
attr_reader :extra_params
26+
27+
end
28+
end
29+
end
30+
end
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
module RspecApiDocumentation
2+
module DSL
3+
module Endpoint
4+
class SetParam
5+
def initialize(parent, hash, param)
6+
@parent = parent
7+
@hash = hash
8+
@param = param
9+
end
10+
11+
def call
12+
return hash if path_params.include?(path_name)
13+
return hash unless method_name
14+
15+
hash.deep_merge build_param_hash(key_scope || [key])
16+
end
17+
18+
private
19+
20+
attr_reader :parent, :hash, :param
21+
delegate :example_group, :example, to: :parent
22+
23+
def key
24+
@key ||= param[:name]
25+
end
26+
27+
def key_scope
28+
@key_scope ||= param[:scope] && Array(param[:scope]).dup.push(key)
29+
end
30+
31+
def scoped_key
32+
@scoped_key ||= key_scope && key_scope.join('_')
33+
end
34+
35+
def custom_method_name
36+
param[:method]
37+
end
38+
39+
def path_name
40+
scoped_key || key
41+
end
42+
43+
def path_params
44+
example.metadata[:route].scan(/:(\w+)/).flatten
45+
end
46+
47+
def method_name
48+
@method_name ||= begin
49+
[custom_method_name, scoped_key, key].find do |name|
50+
name && example_group.respond_to?(name)
51+
end
52+
end
53+
end
54+
55+
def build_param_hash(keys)
56+
value = keys[1] ? build_param_hash(keys[1..-1]) : example_group.send(method_name)
57+
{ keys[0].to_s => value }
58+
end
59+
end
60+
end
61+
end
62+
end

spec/dsl_spec.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
post "/orders" do
6060
parameter :type, "The type of drink you want.", :required => true
6161
parameter :size, "The size of drink you want.", :required => true
62-
parameter :note, "Any additional notes about your order."
63-
parameter :name, :scope => :order
62+
parameter :note, "Any additional notes about your order.", method: :custom_note
63+
parameter :name, :scope => :order, method: :custom_order_name
6464

6565
response_field :type, "The type of drink you ordered.", :scope => :order
6666
response_field :size, "The size of drink you ordered.", :scope => :order
@@ -71,6 +71,12 @@
7171
let(:type) { "coffee" }
7272
let(:size) { "medium" }
7373

74+
let(:note) { "Made in Brazil" }
75+
let(:custom_note) { "Made in India" }
76+
77+
let(:order_name) { "Nescoffee" }
78+
let(:custom_order_name) { "Jakobz" }
79+
7480
describe "example metadata" do
7581
subject { |example| example.metadata }
7682

@@ -79,8 +85,8 @@
7985
[
8086
{ :name => "type", :description => "The type of drink you want.", :required => true },
8187
{ :name => "size", :description => "The size of drink you want.", :required => true },
82-
{ :name => "note", :description => "Any additional notes about your order." },
83-
{ :name => "name", :description => "Order name", :scope => :order},
88+
{ :name => "note", :description => "Any additional notes about your order.", method: :custom_note },
89+
{ :name => "name", :description => "Order name", :scope => :order, method: :custom_order_name },
8490
]
8591
)
8692
end
@@ -103,7 +109,12 @@
103109

104110
describe "params" do
105111
it "should equal the assigned parameter values" do
106-
expect(params).to eq("type" => "coffee", "size" => "medium")
112+
expect(params).to eq({
113+
"type" => "coffee",
114+
"size" => "medium",
115+
"note" => "Made in India",
116+
"order" => { "name" => "Jakobz" }
117+
})
107118
end
108119
end
109120
end

0 commit comments

Comments
 (0)