From b55d4eac2749633f06b1d9f1d5159cb5c3e777d2 Mon Sep 17 00:00:00 2001 From: Denis Tataurov Date: Tue, 15 Nov 2016 17:31:10 +0300 Subject: [PATCH 1/3] Add method option to parameter --- README.md | 15 ++++++++--- lib/rspec_api_documentation/dsl/endpoint.rb | 30 +++++++++++++-------- spec/dsl_spec.rb | 21 +++++++++++---- 3 files changed, 46 insertions(+), 20 deletions(-) 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..8a37c75f 100644 --- a/lib/rspec_api_documentation/dsl/endpoint.rb +++ b/lib/rspec_api_documentation/dsl/endpoint.rb @@ -147,19 +147,27 @@ def delete_extra_param(key) 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) + key = param[:name] + key_scope = param[:scope] && Array(param[:scope]).dup.push(key) + scoped_key = key_scope && key_scope.join('_') + custom_method_name = param[:method] + path_name = scoped_key || key + + return hash if in_path?(path_name) + + build_param_data = if custom_method_name && respond_to?(custom_method_name) + [key_scope || [key], custom_method_name] + elsif scoped_key && respond_to?(scoped_key) + [key_scope, scoped_key] + elsif respond_to?(key) + [key_scope || [key], key] + else + [] end + # binding.pry if key == "street" - hash.deep_merge(build_param_hash(keys, method_name)) + return hash if build_param_data.empty? + hash.deep_merge(build_param_hash(*build_param_data)) end def build_param_hash(keys, method_name) 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 From e6dad15e974af7ed3c8427f57f1ccae3e3e9c9e5 Mon Sep 17 00:00:00 2001 From: Denis Tataurov Date: Tue, 15 Nov 2016 18:40:39 +0300 Subject: [PATCH 2/3] Extract Endpoint#params: introduce DSL::Param and DSL::SetParam classes --- lib/rspec_api_documentation/dsl/endpoint.rb | 44 +------------ .../dsl/endpoint/params.rb | 30 +++++++++ .../dsl/endpoint/set_param.rb | 62 +++++++++++++++++++ 3 files changed, 94 insertions(+), 42 deletions(-) create mode 100644 lib/rspec_api_documentation/dsl/endpoint/params.rb create mode 100644 lib/rspec_api_documentation/dsl/endpoint/set_param.rb diff --git a/lib/rspec_api_documentation/dsl/endpoint.rb b/lib/rspec_api_documentation/dsl/endpoint.rb index 8a37c75f..661850c1 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: example, extra_params: 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,34 +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] - key_scope = param[:scope] && Array(param[:scope]).dup.push(key) - scoped_key = key_scope && key_scope.join('_') - custom_method_name = param[:method] - path_name = scoped_key || key - - return hash if in_path?(path_name) - - build_param_data = if custom_method_name && respond_to?(custom_method_name) - [key_scope || [key], custom_method_name] - elsif scoped_key && respond_to?(scoped_key) - [key_scope, scoped_key] - elsif respond_to?(key) - [key_scope || [key], key] - else - [] - end - # binding.pry if key == "street" - - return hash if build_param_data.empty? - hash.deep_merge(build_param_hash(*build_param_data)) - 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..76718bac --- /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: hash, param: 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..8a86988d --- /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 From 2b79b8a63bd11796e0f0f3dbe11314cad96d399a Mon Sep 17 00:00:00 2001 From: Denis Tataurov Date: Tue, 15 Nov 2016 19:09:32 +0300 Subject: [PATCH 3/3] ruby 2.0.0 fixes --- lib/rspec_api_documentation/dsl/endpoint.rb | 2 +- lib/rspec_api_documentation/dsl/endpoint/params.rb | 4 ++-- lib/rspec_api_documentation/dsl/endpoint/set_param.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rspec_api_documentation/dsl/endpoint.rb b/lib/rspec_api_documentation/dsl/endpoint.rb index 661850c1..6bb21ebd 100644 --- a/lib/rspec_api_documentation/dsl/endpoint.rb +++ b/lib/rspec_api_documentation/dsl/endpoint.rb @@ -64,7 +64,7 @@ def query_string end def params - Params.new(self, example: example, extra_params: extra_params).call + Params.new(self, example, extra_params).call end def header(name, value) diff --git a/lib/rspec_api_documentation/dsl/endpoint/params.rb b/lib/rspec_api_documentation/dsl/endpoint/params.rb index 76718bac..037788b8 100644 --- a/lib/rspec_api_documentation/dsl/endpoint/params.rb +++ b/lib/rspec_api_documentation/dsl/endpoint/params.rb @@ -6,7 +6,7 @@ module Endpoint class Params attr_reader :example_group, :example - def initialize(example_group, example:, extra_params:) + def initialize(example_group, example, extra_params) @example_group = example_group @example = example @extra_params = extra_params @@ -14,7 +14,7 @@ def initialize(example_group, example:, extra_params:) def call parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param| - SetParam.new(self, hash: hash, param: param).call + SetParam.new(self, hash, param).call end parameters.deep_merge!(extra_params) parameters diff --git a/lib/rspec_api_documentation/dsl/endpoint/set_param.rb b/lib/rspec_api_documentation/dsl/endpoint/set_param.rb index 8a86988d..f2927658 100644 --- a/lib/rspec_api_documentation/dsl/endpoint/set_param.rb +++ b/lib/rspec_api_documentation/dsl/endpoint/set_param.rb @@ -2,7 +2,7 @@ module RspecApiDocumentation module DSL module Endpoint class SetParam - def initialize(parent, hash:, param:) + def initialize(parent, hash, param) @parent = parent @hash = hash @param = param