Skip to content

Commit

Permalink
2. part of param type body handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Scholz committed Apr 8, 2016
1 parent 41b4958 commit d668dc1
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 118 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ rvm:
- 2.3.0
- 2.2.3
- 2.1.7
- rbx-2
- jruby-19mode
- jruby-9.0.5.0
- rbx-2

matrix:
allow_failures:
- rvm: rbx-2
- rvm: jruby-19mode
env:
- GRAPE_VERSION=0.12.0
- GRAPE_VERSION=0.13.0
Expand Down
79 changes: 56 additions & 23 deletions lib/grape-swagger/doc_methods/move_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class << self
def to_definition(paths, definitions)
@definitions = definitions
find_post_put(paths) do |path|
find_definition_and_parameters(path)
find_definition_and_params(path)
end
end

Expand All @@ -16,41 +16,35 @@ def find_post_put(paths)
end
end

def find_definition_and_parameters(path)
def find_definition_and_params(path)
path.keys.each do |verb|
parameters = path[verb][:parameters]
params = path[verb][:parameters]

next if parameters.nil?
next unless should_move?(parameters)
next if params.nil?
next unless should_move?(params)

unify!(parameters)
unify!(params)

status_code = GrapeSwagger::DocMethods::StatusCodes.get[verb.to_sym][:code]
response = path[verb][:responses][status_code]
referenced_definition = parse_model(response[:schema]['$ref'])

name = build_definition(verb, referenced_definition)
name = build_definition(referenced_definition, verb)

move_params_to_new(verb, name, parameters)
@definitions[name].delete(:required) if @definitions[name][:required].empty?
move_params_to_new(name, params)
path[verb][:parameters] << build_body_parameter(response.dup, name)
end
end

def build_definition(verb, name)
name = "#{verb}Request#{name}".to_sym
@definitions[name] = { type: 'object', properties: {}, required: [] }

name
end

def move_params_to_new(_, name, parameters)
def move_params_to_new(name, params)
properties = {}
definition = @definitions[name]
request_parameters = parameters.dup

request_parameters.each do |param|
nested_definitions(name, params, properties)

params.dup.each do |param|
next unless movable?(param)

name = param[:name].to_sym
properties[name] = {}

Expand All @@ -61,13 +55,37 @@ def move_params_to_new(_, name, parameters)
end

properties[name][:readOnly] = true unless deletable?(param)
parameters.delete(param) if deletable?(param)
params.delete(param) if deletable?(param)

definition[:required] << name if deletable?(param) && param[:required]
end

definition.delete(:required) if definition[:required].empty?
definition[:properties] = properties
end

def nested_definitions(name, params, properties)
loop do
nested_name = params.bsearch { |x| x[:name].include?('[') }
return if nested_name.nil?

nested_name = nested_name[:name].split('[').first

nested, = params.partition { |x| x[:name].start_with?("#{nested_name}[") }
nested.each { |x| params.delete(x) }
nested_def_name = GrapeSwagger::DocMethods::OperationId.manipulate(nested_name)
def_name = "#{name}#{nested_def_name}"
properties[nested_name] = { '$ref' => "#/definitions/#{def_name}" }

prepare_nested_names(nested)
build_definition(def_name)

move_params_to_new(def_name, nested)
end
end

private

def build_body_parameter(response, name = false)
body_param = {}
body_param.tap do |x|
Expand All @@ -79,7 +97,22 @@ def build_body_parameter(response, name = false)
end
end

private
def build_definition(name, verb = nil)
name = "#{verb}Request#{name}" if verb
@definitions[name] = { type: 'object', properties: {}, required: [] }

name
end

def prepare_nested_names(params)
params.each do |param|
param.tap do |x|
name = x[:name].partition('[').last.sub(']', '')
name = name.partition('[').last.sub(']', '') if name.start_with?('[')
x[:name] = name
end
end
end

def unify!(params)
params.each do |param|
Expand Down Expand Up @@ -110,8 +143,8 @@ def deletable?(param)
false
end

def should_move?(parameters)
!parameters.select { |x| x[:in] == 'body' || x[:param_type] == 'body' }.empty?
def should_move?(params)
!params.select { |x| x[:in] == 'body' || x[:param_type] == 'body' }.empty?
end
end
end
Expand Down
24 changes: 14 additions & 10 deletions lib/grape-swagger/doc_methods/operation_id.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ module GrapeSwagger
module DocMethods
class OperationId
class << self
def build(method, path = nil)
def build(method = nil, path = nil)
verb = method.to_s.downcase

unless path.nil?
operation = path.split('/').map(&:capitalize).join
operation.gsub!(/\-(\w)/, &:upcase).delete!('-') if operation.include?('-')
operation.gsub!(/\_(\w)/, &:upcase).delete!('_') if operation.include?('_')
if path.include?('{')
operation.gsub!(/\{(\w)/, &:upcase)
operation.delete!('{').delete!('}')
end
end
operation = manipulate(path) unless path.nil?

"#{verb}#{operation}"
end

def manipulate(path)
operation = path.split('/').map(&:capitalize).join
operation.gsub!(/\-(\w)/, &:upcase).delete!('-') if operation.include?('-')
operation.gsub!(/\_(\w)/, &:upcase).delete!('_') if operation.include?('_')
if path.include?('{')
operation.gsub!(/\{(\w)/, &:upcase)
operation.delete!('{').delete!('}')
end

operation
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/grape-swagger/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def response_object(route)
value[:code] = 204
end

# next if memo.key?(204)
next unless !response_model.start_with?('Swagger_doc') &&
((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model])

Expand Down
124 changes: 86 additions & 38 deletions spec/lib/move_params_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,12 @@
end
end

describe 'build_definition' do
let(:verb) { 'post' }
let(:name) { 'Foo' }
let(:definitions) {{}}

describe 'find_definition_and_params' do
specify do
subject.instance_variable_set(:@definitions, definitions)
subject.build_definition(verb, name)
subject.find_definition_and_params(found_path)

definition = definitions.to_a.first
expect(definition.first).to eql :postRequestFoo
expect(definition.last).to eql({ type: 'object', properties: {}, required: [] })
expect(definitions.keys).to include 'InBody', 'postRequestInBody'
end
end

Expand All @@ -61,8 +55,8 @@

specify do
subject.instance_variable_set(:@definitions, definitions)
name = subject.build_definition(verb, name)
subject.move_params_to_new(verb, name, params)
name = subject.send(:build_definition, name, verb)
subject.move_params_to_new(name, params)

expect(definitions[name]).to eql expected_post_defs
expect(params).to be_empty
Expand All @@ -75,50 +69,105 @@

specify do
subject.instance_variable_set(:@definitions, definitions)
name, definition = subject.build_definition(verb, name)
subject.move_params_to_new(verb, name, params)
name, definition = subject.send(:build_definition, name, verb)
subject.move_params_to_new(name, params)

expect(definitions[name]).to eql expected_put_defs
expect(params.length).to be 1
end
end
end

describe 'find_definition' do
specify do
subject.instance_variable_set(:@definitions, definitions)
subject.find_definition_and_parameters(found_path)
describe 'nested definitions related' do
describe 'prepare_nested_names' do
before do
subject.send(:prepare_nested_names, params)
end

expect(definitions.keys).to include 'InBody', :postRequestInBody
describe 'simple' do
let(:params) {[{:in=>"body", :name=>"address[street]", :description=>"street", :type=>"string", :required=>true}]}
let(:expected) {[{:in=>"body", :name=>"street", :description=>"street", :type=>"string", :required=>true}]}
specify do
expect(params).to eql expected
end
end

describe 'nested' do
let(:params) {[{:in=>"body", :name=>"address[street][name]", :description=>"street", :type=>"string", :required=>true}]}
let(:expected) {[{:in=>"body", :name=>"street[name]", :description=>"street", :type=>"string", :required=>true}]}
specify do
expect(params).to eql expected
end
end

describe 'array' do
let(:params) {[{:in=>"body", :name=>"address[][street_lines]", :description=>"street lines", :type=>"array", :required=>true}]}
let(:expected) {[{:in=>"body", :name=>"street_lines", :description=>"street lines", :type=>"array", :required=>true}]}
specify do
expect(params).to eql expected
end
end
end
end

describe 'build_body_parameter' do
let(:response) {{ schema: { '$ref' => '#/definitions/Somewhere'} }}
describe 'private methods' do
describe 'build_definition' do
before do
subject.instance_variable_set(:@definitions, definitions)
subject.send(:build_definition, name, verb)
end

describe 'no name given' do
let(:expected_param) {
{:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/Somewhere"}}
}
specify do
parameter = subject.build_body_parameter(response)
expect(parameter).to eql expected_param
describe 'verb given' do
let(:verb) { 'post' }
let(:name) { 'Foo' }
let(:definitions) {{}}

specify do
definition = definitions.to_a.first
expect(definition.first).to eql 'postRequestFoo'
expect(definition.last).to eql({ type: 'object', properties: {}, required: [] })
end
end

describe 'no verb given' do
let(:name) { 'FooBar' }
let(:definitions) {{}}
let(:verb) { nil }

specify do
definition = definitions.to_a.first
expect(definition.first).to eql 'FooBar'
expect(definition.last).to eql({ type: 'object', properties: {}, required: [] })
end
end
end

describe 'name given' do
let(:name) { 'Foo' }
let(:expected_param) {
{:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/#{name}"}}
}
specify do
parameter = subject.build_body_parameter(response, name)
expect(parameter).to eql expected_param
describe 'build_body_parameter' do
let(:response) {{ schema: { '$ref' => '#/definitions/Somewhere'} }}

describe 'no name given' do
let(:name) { nil }
let(:expected_param) {
{:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/Somewhere"}}
}
specify do
parameter = subject.send(:build_body_parameter, response)
expect(parameter).to eql expected_param
end
end

describe 'name given' do
let(:name) { 'Foo' }
let(:expected_param) {
{:name=>"Somewhere", :in=>"body", :required=>true, :schema=>{'$ref' => "#/definitions/#{name}"}}
}
specify do
parameter = subject.send(:build_body_parameter, response, name)
expect(parameter).to eql expected_param
end
end
end
end

describe 'private methods' do
describe 'parse_model' do
let(:ref) { '#/definitions/InBody' }
subject(:object) { described_class.send(:parse_model, ref) }
Expand Down Expand Up @@ -245,6 +294,5 @@
it { expect(params).to eql expected_params }
end
end

end
end
Loading

0 comments on commit d668dc1

Please sign in to comment.