diff --git a/README.md b/README.md index eb27fdfa..8ccc86cd 100644 --- a/README.md +++ b/README.md @@ -416,8 +416,12 @@ Special values: * `:required => true` Will display a red '*' to show it's required * `:scope => :the_scope` Will scope parameters in the hash, scoping can be nested. See example +* `:method => :method_name` Will use specified method as a parameter value -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. +Retrieving of parameter value goes through several steps: +1. if `method` option is defined and test case responds to this method then this method is used; +2. if test case responds to scoped method then this method is used; +3. overwise unscoped method is used. ```ruby resource "Orders" do @@ -428,10 +432,13 @@ resource "Orders" do post "/orders" do parameter :name, "Order Name", :required => true, :scope => :order parameter :item, "Order items", :scope => :order - parameter :item_id, "Item id", :scope => [:order, :item] + parameter :item_id, "Item id", :scope => [:order, :item], method: :custom_item_id - let(:name) { "My Order" } # OR let(:order_name) { "My Order" } - let(:item_id) { 1 } # OR let(:order_item_item_id) { 1 } + let(:name) { "My Order" } + # OR let(:order_name) { "My Order" } + let(:item_id) { 1 } + # OR let(:custom_item_id) { 1 } + # OR let(:order_item_item_id) { 1 } example "Creating an order" do params.should eq({ diff --git a/lib/rspec_api_documentation/dsl/endpoint.rb b/lib/rspec_api_documentation/dsl/endpoint.rb index dcf6523c..6bb21ebd 100644 --- a/lib/rspec_api_documentation/dsl/endpoint.rb +++ b/lib/rspec_api_documentation/dsl/endpoint.rb @@ -1,6 +1,7 @@ require 'rspec/core/formatters/base_formatter' require 'rack/utils' require 'rack/test/utils' +require 'rspec_api_documentation/dsl/endpoint/params' module RspecApiDocumentation::DSL # DSL methods available inside the RSpec example. @@ -63,11 +64,7 @@ def query_string end def params - parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param| - set_param(hash, param) - end - parameters.deep_merge!(extra_params) - parameters + Params.new(self, example, extra_params).call end def header(name, value) @@ -99,14 +96,6 @@ def status rspec_api_documentation_client.status end - def in_path?(param) - path_params.include?(param) - end - - def path_params - example.metadata[:route].scan(/:(\w+)/).flatten - end - def path example.metadata[:route].gsub(/:(\w+)/) do |match| if extra_params.keys.include?($1) @@ -146,26 +135,5 @@ def delete_extra_param(key) @extra_params.delete(key.to_sym) || @extra_params.delete(key.to_s) end - def set_param(hash, param) - key = param[:name] - - keys = [param[:scope], key].flatten.compact - method_name = keys.join('_') - - return hash if in_path?(method_name) - - unless respond_to?(method_name) - method_name = key - return hash unless respond_to?(method_name) - end - - hash.deep_merge(build_param_hash(keys, method_name)) - end - - def build_param_hash(keys, method_name) - value = keys[1] ? build_param_hash(keys[1..-1], method_name) : send(method_name) - { keys[0].to_s => value } - end - end end diff --git a/lib/rspec_api_documentation/dsl/endpoint/params.rb b/lib/rspec_api_documentation/dsl/endpoint/params.rb new file mode 100644 index 00000000..037788b8 --- /dev/null +++ b/lib/rspec_api_documentation/dsl/endpoint/params.rb @@ -0,0 +1,30 @@ +require 'rspec_api_documentation/dsl/endpoint/set_param' + +module RspecApiDocumentation + module DSL + module Endpoint + class Params + attr_reader :example_group, :example + + def initialize(example_group, example, extra_params) + @example_group = example_group + @example = example + @extra_params = extra_params + end + + def call + parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param| + SetParam.new(self, hash, param).call + end + parameters.deep_merge!(extra_params) + parameters + end + + private + + attr_reader :extra_params + + end + end + end +end diff --git a/lib/rspec_api_documentation/dsl/endpoint/set_param.rb b/lib/rspec_api_documentation/dsl/endpoint/set_param.rb new file mode 100644 index 00000000..f2927658 --- /dev/null +++ b/lib/rspec_api_documentation/dsl/endpoint/set_param.rb @@ -0,0 +1,62 @@ +module RspecApiDocumentation + module DSL + module Endpoint + class SetParam + def initialize(parent, hash, param) + @parent = parent + @hash = hash + @param = param + end + + def call + return hash if path_params.include?(path_name) + return hash unless method_name + + hash.deep_merge build_param_hash(key_scope || [key]) + end + + private + + attr_reader :parent, :hash, :param + delegate :example_group, :example, to: :parent + + def key + @key ||= param[:name] + end + + def key_scope + @key_scope ||= param[:scope] && Array(param[:scope]).dup.push(key) + end + + def scoped_key + @scoped_key ||= key_scope && key_scope.join('_') + end + + def custom_method_name + param[:method] + end + + def path_name + scoped_key || key + end + + def path_params + example.metadata[:route].scan(/:(\w+)/).flatten + end + + def method_name + @method_name ||= begin + [custom_method_name, scoped_key, key].find do |name| + name && example_group.respond_to?(name) + end + end + end + + def build_param_hash(keys) + value = keys[1] ? build_param_hash(keys[1..-1]) : example_group.send(method_name) + { keys[0].to_s => value } + end + end + end + end +end diff --git a/spec/dsl_spec.rb b/spec/dsl_spec.rb index a9ab1162..1c9847c6 100644 --- a/spec/dsl_spec.rb +++ b/spec/dsl_spec.rb @@ -59,8 +59,8 @@ post "/orders" do parameter :type, "The type of drink you want.", :required => true parameter :size, "The size of drink you want.", :required => true - parameter :note, "Any additional notes about your order." - parameter :name, :scope => :order + parameter :note, "Any additional notes about your order.", method: :custom_note + parameter :name, :scope => :order, method: :custom_order_name response_field :type, "The type of drink you ordered.", :scope => :order response_field :size, "The size of drink you ordered.", :scope => :order @@ -71,6 +71,12 @@ let(:type) { "coffee" } let(:size) { "medium" } + let(:note) { "Made in Brazil" } + let(:custom_note) { "Made in India" } + + let(:order_name) { "Nescoffee" } + let(:custom_order_name) { "Jakobz" } + describe "example metadata" do subject { |example| example.metadata } @@ -79,8 +85,8 @@ [ { :name => "type", :description => "The type of drink you want.", :required => true }, { :name => "size", :description => "The size of drink you want.", :required => true }, - { :name => "note", :description => "Any additional notes about your order." }, - { :name => "name", :description => "Order name", :scope => :order}, + { :name => "note", :description => "Any additional notes about your order.", method: :custom_note }, + { :name => "name", :description => "Order name", :scope => :order, method: :custom_order_name }, ] ) end @@ -103,7 +109,12 @@ describe "params" do it "should equal the assigned parameter values" do - expect(params).to eq("type" => "coffee", "size" => "medium") + expect(params).to eq({ + "type" => "coffee", + "size" => "medium", + "note" => "Made in India", + "order" => { "name" => "Jakobz" } + }) end end end