From 3dac88cb46f36a6027738c03d180c68abe8a92fd Mon Sep 17 00:00:00 2001 From: Peter Scholz Date: Thu, 28 Jan 2016 23:22:42 +0100 Subject: [PATCH 1/4] upgrades to grape 0.14.x; grape-entity 0.5.x --- .rubocop.yml | 1 + grape-swagger.gemspec | 2 +- lib/grape-swagger/endpoint.rb | 13 +++++++++--- .../api_swagger_v2_response_spec.rb | 20 +++++++++++++------ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index c56a0e7b..38ebe54f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,5 +3,6 @@ AllCops: - vendor/**/* - spec/**/* - swagger_spec1.2/**/* + - example/**/* inherit_from: .rubocop_todo.yml diff --git a/grape-swagger.gemspec b/grape-swagger.gemspec index ed3ff438..1f141e44 100644 --- a/grape-swagger.gemspec +++ b/grape-swagger.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.license = 'MIT' s.add_runtime_dependency 'grape' - s.add_runtime_dependency 'grape-entity', '0.4.8' + s.add_runtime_dependency 'grape-entity' s.add_runtime_dependency 'awesome_print' s.add_development_dependency 'rake' diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index d31ba106..9c225495 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -230,7 +230,7 @@ def parse_request_params(parameters, required, route_paramter) end def parse_response_params(params) - return if params.empty? + return if params.nil? params.each_with_object({}) do |x, memo| x[0] = x.last[:as] if x.last[:as] @@ -247,8 +247,15 @@ def parse_response_params(params) def expose_params_from_model(model) model_name = model.name.demodulize.camelize - # has to be adept, to be ready for grape-entity >0.5.0 - parameters = model.exposures ? model.exposures : model.documentation + # DONE: has to be adept, to be ready for grape-entity >0.5.0 + # TODO: this should only be a temporary hack ;) + if GrapeEntity::VERSION =~ /0\.4\.\d/ + parameters = model.exposures ? model.exposures : model.documentation + elsif GrapeEntity::VERSION =~ /0\.5\.\d/ + parameters = model.root_exposures.each_with_object({}) do |value,memo| + memo[value.attribute] = value.send(:options) + end + end properties = parse_response_params(parameters) @definitions[model_name] = { type: 'object', properties: properties } diff --git a/spec/swagger_v2/api_swagger_v2_response_spec.rb b/spec/swagger_v2/api_swagger_v2_response_spec.rb index 3d1c84ad..d19a4466 100644 --- a/spec/swagger_v2/api_swagger_v2_response_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_response_spec.rb @@ -11,7 +11,7 @@ class ResponseApi < Grape::API desc 'This returns something', params: Entities::UseResponse.documentation, failure: [{code: 400, message: 'NotFound', model: Entities::ApiError}] - get '/params_response' do + post '/params_response' do { "declared_params" => declared(params) } end @@ -71,6 +71,14 @@ def app JSON.parse(last_response.body) end + + # usage of grape-entity 0.4.8 preduces a wrong definition for ParamsResponse, this one: + # "definitions" => { + # "ParamsResponse"=>{"properties"=>{"description"=>{"type"=>"string"}}}, + # "ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer"}, "message"=>{"type"=>"string"}}} + # } + # (`$response` property is missing) + specify do expect(subject).to eql({ "info"=>{"title"=>"API title", "version"=>"v1"}, @@ -80,17 +88,17 @@ def app "schemes"=>["https", "http"], "paths"=>{ "/params_response"=>{ - "get"=>{ + "post"=>{ "produces"=>["application/json"], "parameters"=>[ - {"in"=>"query", "name"=>"description", "description"=>nil, "type"=>"string", "required"=>false, "allowMultiple"=>false}, - {"in"=>"query", "name"=>"$responses", "description"=>nil, "type"=>"string", "required"=>false, "allowMultiple"=>true}], + {"in"=>"formData", "name"=>"description", "description"=>nil, "type"=>"string", "required"=>false, "allowMultiple"=>false}, + {"in"=>"formData", "name"=>"$responses", "description"=>nil, "type"=>"string", "required"=>false, "allowMultiple"=>true}], "responses"=>{ - "200"=>{"description"=>"This returns something", "schema"=>{"$ref"=>"#/definitions/ParamsResponse"}}, + "201"=>{"description"=>"This returns something", "schema"=>{"$ref"=>"#/definitions/ParamsResponse"}}, "400"=>{"description"=>"NotFound", "schema"=>{"$ref"=>"#/definitions/ApiError"}}} }}}, "definitions"=>{ - "ParamsResponse"=>{"properties"=>{"description"=>{"type"=>"string"}}}, + "ParamsResponse"=>{"properties"=>{"description"=>{"type"=>"string"}, "$responses"=>{"type"=>"string"}}}, "ApiError"=>{"type"=>"object", "properties"=>{"code"=>{"type"=>"integer"}, "message"=>{"type"=>"string"}}} }}) end From f5e8ca1a37e4c9fb436b80c09fa1803c7258d7ea Mon Sep 17 00:00:00 2001 From: Peter Scholz Date: Mon, 1 Feb 2016 17:47:58 +0100 Subject: [PATCH 2/4] reduces rubocop warnings --- lib/grape-swagger/endpoint.rb | 20 ++++---- ...api_swagger_v2_format-content_type_spec.rb | 46 +++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 9c225495..3e300a04 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -165,15 +165,13 @@ def response_object(route) response_model = @item response_model = expose_params_from_model(value[:model]) if value[:model] + next unless !response_model.start_with?('Swagger_doc') && ((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model]) + # TODO: proof that the definition exist, if model isn't specified - if !response_model.start_with?('Swagger_doc') && - ((!!@definitions[response_model] && value[:code].to_s.start_with?('2')) || - value[:model]) - if route.route_is_array - memo[value[:code]][:schema] = { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } } - else - memo[value[:code]][:schema] = { '$ref' => "#/definitions/#{response_model}" } - end + if route.route_is_array + memo[value[:code]][:schema] = { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } } + else + memo[value[:code]][:schema] = { '$ref' => "#/definitions/#{response_model}" } end end end @@ -190,7 +188,7 @@ def default_staus_codes def params_object(route) partition_params(route).map do |param, value| - parse_params(param, value, route.route_path, route.route_method) + parse_params(param, { required: false }.merge(value), route.route_path, route.route_method) end end @@ -252,7 +250,7 @@ def expose_params_from_model(model) if GrapeEntity::VERSION =~ /0\.4\.\d/ parameters = model.exposures ? model.exposures : model.documentation elsif GrapeEntity::VERSION =~ /0\.5\.\d/ - parameters = model.root_exposures.each_with_object({}) do |value,memo| + parameters = model.root_exposures.each_with_object({}) do |value, memo| memo[value.attribute] = value.send(:options) end end @@ -289,7 +287,7 @@ def parse_params(param, value, path, method) end description = value.is_a?(Hash) ? value[:desc] || value[:description] : nil - required = value.is_a?(Hash) ? !!value[:required] : false + required = value.is_a?(Hash) ? value[:required] : false default_value = value.is_a?(Hash) ? value[:default] : nil example = value.is_a?(Hash) ? value[:example] : nil is_array = value.is_a?(Hash) ? (value[:is_array] || false) : false diff --git a/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb new file mode 100644 index 00000000..96153161 --- /dev/null +++ b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe 'format, content_type' do + include_context "the api entities" + + before :all do + module TheApi + class ProducesApi < Grape::API + format :json + + desc 'This uses formats for produces', + failure: [{code: 400, model: Entities::ApiError}], + formats: [:xml, :binary, "application/vdns"], + entity: Entities::UseResponse + get '/use_format' do + { "declared_params" => declared(params) } + end + + desc 'This uses content_types for produces', + failure: [{code: 400, model: Entities::ApiError}], + content_types: [:xml, :binary, "application/vdns"], + entity: Entities::UseResponse + get '/use_format' do + { "declared_params" => declared(params) } + end + + add_swagger_documentation + end + end + end + + def app + TheApi::ProducesApi + end + + subject do + get '/swagger_doc' + JSON.parse(last_response.body) + end + + specify do + require 'pry'; binding.pry + expect(subject['paths']['/use_produces']['get']).to include('produces') + # expect(subject['paths']['/use_produces']['get']['produces']).to eql(["application/json"]) + end +end From eb981fd5ceb7814535ae253d27a2a45982e2a4e2 Mon Sep 17 00:00:00 2001 From: Peter Scholz Date: Tue, 2 Feb 2016 00:50:57 +0100 Subject: [PATCH 3/4] documents produces of an end-point --- lib/grape-swagger.rb | 1 + lib/grape-swagger/doc_methods.rb | 2 +- lib/grape-swagger/doc_methods/produces.rb | 12 +++ lib/grape-swagger/endpoint.rb | 14 ++- spec/doc_methods/produces_spec.rb | 98 +++++++++++++++++++ ...api_swagger_v2_format-content_type_spec.rb | 76 ++++++++++++-- spec/swagger_v2/params_hash_spec.rb | 73 ++++++-------- 7 files changed, 221 insertions(+), 55 deletions(-) create mode 100644 lib/grape-swagger/doc_methods/produces.rb create mode 100644 spec/doc_methods/produces_spec.rb diff --git a/lib/grape-swagger.rb b/lib/grape-swagger.rb index c1ec7dd5..4be06772 100644 --- a/lib/grape-swagger.rb +++ b/lib/grape-swagger.rb @@ -2,6 +2,7 @@ require 'grape-swagger/version' require 'grape-swagger/endpoint' require 'grape-swagger/errors' +require 'grape-swagger/doc_methods/produces' require 'grape-swagger/doc_methods' require 'grape-swagger/markdown/kramdown_adapter' require 'grape-swagger/markdown/redcarpet_adapter' diff --git a/lib/grape-swagger/doc_methods.rb b/lib/grape-swagger/doc_methods.rb index d48a102d..fa6470ed 100644 --- a/lib/grape-swagger/doc_methods.rb +++ b/lib/grape-swagger/doc_methods.rb @@ -87,7 +87,7 @@ def defaults base_path: nil, markdown: false, hide_documentation_path: true, - format: nil, + format: :json, models: [], info: {}, scheme: %w( https http ), diff --git a/lib/grape-swagger/doc_methods/produces.rb b/lib/grape-swagger/doc_methods/produces.rb new file mode 100644 index 00000000..5fae1f63 --- /dev/null +++ b/lib/grape-swagger/doc_methods/produces.rb @@ -0,0 +1,12 @@ +module GrapeSwagger + module DocMethods + class Produces + class << self + def call(*args) + return ['application/json'] unless args.flatten.present? + args.flatten.map { |x| Grape::ContentTypes::CONTENT_TYPES[x] || x }.uniq + end + end + end + end +end diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 3e300a04..1057c190 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -129,8 +129,7 @@ def method_object(route, options) methods[:description] = description_object(route, options[:markdown]) methods[:headers] = route.route_headers if route.route_headers - mime_types = options[:format] ? Grape::ContentTypes::CONTENT_TYPES[options[:format]] : Grape::ContentTypes::CONTENT_TYPES[:json] - methods[:produces] = [mime_types] + methods[:produces] = produces_object(route, options) methods[:parameters] = params_object(route) methods[:responses] = response_object(route) @@ -150,6 +149,17 @@ def description_object(route, markdown) description end + def produces_object(route, options) + mime_types = GrapeSwagger::DocMethods::Produces.call(options[:format]) + + route_mime_types = [:route_formats, :route_content_types, :route_produces].map do |producer| + possible = route.send(producer) + GrapeSwagger::DocMethods::Produces.call(possible) if possible.present? + end.flatten.compact.uniq + + route_mime_types.present? ? route_mime_types : mime_types + end + def response_object(route) default_code = default_staus_codes[route.route_method.downcase.to_sym] default_code[:model] = @entity if @entity diff --git a/spec/doc_methods/produces_spec.rb b/spec/doc_methods/produces_spec.rb new file mode 100644 index 00000000..262177a5 --- /dev/null +++ b/spec/doc_methods/produces_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +describe GrapeSwagger::DocMethods::Produces do + describe ":json (default)" do + subject { described_class.call } + + specify do + expect(subject).to eql( ['application/json'] ) + end + end + + describe "accept symbols of" do + describe "single" do + subject { described_class.call(:xml) } + + specify do + expect(subject).to eql( ['application/xml'] ) + end + end + + describe "multiple" do + subject { described_class.call(:xml, :serializable_hash, :json, :binary, :txt) } + + specify do + expect(subject).to eql( [ + 'application/xml', + 'application/json', + 'application/octet-stream', + 'text/plain' + ] ) + end + end + end + + describe "accept mime_types of" do + describe "single" do + subject { described_class.call('application/xml') } + + specify do + expect(subject).to eql( ['application/xml'] ) + end + end + + describe "multiple" do + subject { described_class.call( + 'application/xml', + 'application/json', + 'application/octet-stream', + 'text/plain' + ) } + + specify do + expect(subject).to eql( [ + 'application/xml', + 'application/json', + 'application/octet-stream', + 'text/plain' + ] ) + end + end + end + + describe "mix it up" do + subject { described_class.call( + :xml, + :serializable_hash, + 'application/json', + 'application/octet-stream', + :txt + ) } + + specify do + expect(subject).to eql( [ + 'application/xml', + 'application/json', + 'application/octet-stream', + 'text/plain' + ] ) + end + + subject { described_class.call( [ + :xml, + :serializable_hash, + 'application/json', + 'application/octet-stream', + :txt + ] ) } + + specify do + expect(subject).to eql( [ + 'application/xml', + 'application/json', + 'application/octet-stream', + 'text/plain' + ] ) + end + end +end diff --git a/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb index 96153161..8b5fbccc 100644 --- a/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb @@ -8,11 +8,18 @@ module TheApi class ProducesApi < Grape::API format :json + desc 'This uses json (default) for produces', + failure: [{code: 400, model: Entities::ApiError}], + entity: Entities::UseResponse + get '/use_default' do + { "declared_params" => declared(params) } + end + desc 'This uses formats for produces', failure: [{code: 400, model: Entities::ApiError}], formats: [:xml, :binary, "application/vdns"], entity: Entities::UseResponse - get '/use_format' do + get '/use_formats' do { "declared_params" => declared(params) } end @@ -20,7 +27,15 @@ class ProducesApi < Grape::API failure: [{code: 400, model: Entities::ApiError}], content_types: [:xml, :binary, "application/vdns"], entity: Entities::UseResponse - get '/use_format' do + get '/use_content_types' do + { "declared_params" => declared(params) } + end + + desc 'This uses produces for produces', + failure: [{code: 400, model: Entities::ApiError}], + produces: [:xml, :binary, "application/vdns"], + entity: Entities::UseResponse + get '/use_produces' do { "declared_params" => declared(params) } end @@ -33,14 +48,57 @@ def app TheApi::ProducesApi end - subject do - get '/swagger_doc' - JSON.parse(last_response.body) + let(:produced) {[ + 'application/xml', + 'application/octet-stream', + 'application/vdns' + ]} + + describe "formats" do + subject do + get '/swagger_doc/use_default' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/use_default']['get']).to include('produces') + expect(subject['paths']['/use_default']['get']['produces']).to eql(['application/json']) + end end - specify do - require 'pry'; binding.pry - expect(subject['paths']['/use_produces']['get']).to include('produces') - # expect(subject['paths']['/use_produces']['get']['produces']).to eql(["application/json"]) + describe "formats" do + subject do + get '/swagger_doc/use_formats' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/use_formats']['get']).to include('produces') + expect(subject['paths']['/use_formats']['get']['produces']).to eql(produced) + end + end + + describe "content types" do + subject do + get '/swagger_doc/use_content_types' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/use_content_types']['get']).to include('produces') + expect(subject['paths']['/use_content_types']['get']['produces']).to eql(produced) + end + end + + describe "produces" do + subject do + get '/swagger_doc/use_produces' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/use_produces']['get']).to include('produces') + expect(subject['paths']['/use_produces']['get']['produces']).to eql(produced) + end end end diff --git a/spec/swagger_v2/params_hash_spec.rb b/spec/swagger_v2/params_hash_spec.rb index 2e18343d..e8a6fdce 100644 --- a/spec/swagger_v2/params_hash_spec.rb +++ b/spec/swagger_v2/params_hash_spec.rb @@ -11,7 +11,7 @@ def app requires :required_param_2 end end - post '/groups' do + post '/use_groups' do { 'declared_params' => declared(params) } end @@ -23,7 +23,7 @@ def app optional :others, type: Integer, values: [1, 2, 3] end end - post '/type_given' do + post '/use_given_type' do { 'declared_params' => declared(params) } end @@ -31,48 +31,35 @@ def app end end - it 'retrieves the documentation for group parameters' do - get '/swagger_doc/groups' - body = JSON.parse last_response.body - expect(body).to eql({ - "info"=>{"title"=>"API title", "version"=>"v1"}, - "swagger"=>"2.0", - "produces"=>["application/json"], - "host"=>"example.org", - "schemes" => ["https", "http"], - "paths"=>{ - "/groups"=>{ - "post"=>{ - "produces"=>["application/json"], - "responses"=>{"201"=>{"description"=>"created Group"}}, - "parameters"=>[ - {"in"=>"formData", "name"=>"required_group[required_param_1]", "description"=>nil, "type"=>"string", "required"=>true, "allowMultiple"=>false}, - {"in"=>"formData", "name"=>"required_group[required_param_2]", "description"=>nil, "type"=>"string", "required"=>true, "allowMultiple"=>false} - ]}}}} - ) - end + describe "grouped parameters" do + subject do + get '/swagger_doc/use_groups' + JSON.parse(last_response.body) + end - it 'retrieves the documentation for typed group parameters' do - get '/swagger_doc/type_given' - body = JSON.parse last_response.body - expect(body).to eql({ - "info"=>{"title"=>"API title", "version"=>"v1"}, - "swagger"=>"2.0", - "produces"=>["application/json"], - "host"=>"example.org", - "schemes" => ["https", "http"], - "paths"=>{ - "/type_given"=>{ - "post"=>{ - "produces"=>["application/json"], - "responses"=>{"201"=>{"description"=>"created TypeGiven"}}, - "parameters"=>[ - {"in"=>"formData", "name"=>"typed_group[id]", "description"=>"integer given", "type"=>"integer", "required"=>true, "allowMultiple"=>false, "format"=>"int32"}, - {"in"=>"formData", "name"=>"typed_group[name]", "description"=>"string given", "type"=>"string", "required"=>true, "allowMultiple"=>false}, - {"in"=>"formData", "name"=>"typed_group[email]", "description"=>"email given", "type"=>"string", "required"=>false, "allowMultiple"=>false}, - {"in"=>"formData", "name"=>"typed_group[others]", "description"=>nil, "type"=>"integer", "required"=>false, "allowMultiple"=>false, "format"=>"int32", "enum"=>[1, 2, 3]} - ]}}}} - ) + specify do + expect(subject['paths']['/use_groups']['post']).to include('parameters') + expect(subject['paths']['/use_groups']['post']['parameters']).to eql([ + {"in"=>"formData", "name"=>"required_group[required_param_1]", "description"=>nil, "type"=>"string", "required"=>true, "allowMultiple"=>false}, + {"in"=>"formData", "name"=>"required_group[required_param_2]", "description"=>nil, "type"=>"string", "required"=>true, "allowMultiple"=>false} + ]) + end end + describe "grouped parameters with given type" do + subject do + get '/swagger_doc/use_given_type' + JSON.parse(last_response.body) + end + + specify do + expect(subject['paths']['/use_given_type']['post']).to include('parameters') + expect(subject['paths']['/use_given_type']['post']['parameters']).to eql([ + {"in"=>"formData", "name"=>"typed_group[id]", "description"=>"integer given", "type"=>"integer", "required"=>true, "allowMultiple"=>false, "format"=>"int32"}, + {"in"=>"formData", "name"=>"typed_group[name]", "description"=>"string given", "type"=>"string", "required"=>true, "allowMultiple"=>false}, + {"in"=>"formData", "name"=>"typed_group[email]", "description"=>"email given", "type"=>"string", "required"=>false, "allowMultiple"=>false}, + {"in"=>"formData", "name"=>"typed_group[others]", "description"=>nil, "type"=>"integer", "required"=>false, "allowMultiple"=>false, "format"=>"int32", "enum"=>[1, 2, 3]} + ]) + end + end end From b3ce344968a37d889897b1165f3238e3045b0ee0 Mon Sep 17 00:00:00 2001 From: peter scholz Date: Mon, 1 Feb 2016 20:54:23 +0100 Subject: [PATCH 4/4] Update api_swagger_v2_format-content_type_spec.rb removes pry runs under 2.3 updates gems, corrects parameter, which is in array, make rubocop happy fixes jruby build changes for TravisCI --- .rubocop_todo.yml | 2 +- .travis.yml | 17 +++++----- CHANGELOG.md | 12 ++++++- Gemfile | 12 +++---- grape-swagger.gemspec | 12 +++---- lib/grape-swagger.rb | 17 +++++----- lib/grape-swagger/endpoint.rb | 31 ++++++++++--------- lib/grape-swagger/version.rb | 2 +- spec/markdown/kramdown_adapter_spec.rb | 6 ---- spec/markdown/redcarpet_adapter_spec.rb | 14 --------- spec/support/api_swagger_v2_result.rb | 9 +++--- spec/swagger_v2/api_swagger_v2_detail_spec.rb | 6 ++-- ...api_swagger_v2_format-content_type_spec.rb | 2 +- 13 files changed, 67 insertions(+), 75 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3c306c5b..5f290a1f 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -13,7 +13,7 @@ Metrics/AbcSize: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 142 + Max: 333 # Offense count: 6 Metrics/CyclomaticComplexity: diff --git a/.travis.yml b/.travis.yml index ddebb320..a1781a2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,18 +3,17 @@ language: ruby sudo: false rvm: - - 2.2.2 - - 2.1.1 - - 2.0.0 - - rbx-2.2.10 + - 2.3.0 + - 2.2.3 + - 2.1.7 + - rbx-2 - jruby-19mode +matrix: + allow_failures: + - rvm: rbx-2 env: - - GRAPE_VERSION=0.8.0 - - GRAPE_VERSION=0.9.0 - - GRAPE_VERSION=0.10.0 - - GRAPE_VERSION=0.10.1 - - GRAPE_VERSION=0.11.0 - GRAPE_VERSION=0.12.0 - GRAPE_VERSION=0.13.0 + - GRAPE_VERSION=0.14.0 - GRAPE_VERSION=HEAD diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f133aff..824f60df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ + +n.n.n / 2016-02-05 +================== + ### 0.10.3 (Next) -* Your contribution here. +[#336](https://github.com/ruby-grape/grape-swagger/pull/336) changes of swagger-2.0 fork, to support it + +* updates gems, corrects parameter, which is in array, make rubocop happy +* runs under 2.3 +* documents produces of an end-point +* Update api_swagger_v2_format-content_type_spec.rb +* upgrades to grape 0.14.x; grape-entity 0.5.x ### 0.10.2 (August 19, 2015) diff --git a/Gemfile b/Gemfile index 69cb418e..d05a7adf 100644 --- a/Gemfile +++ b/Gemfile @@ -2,9 +2,9 @@ source 'http://rubygems.org' gemspec -# case version = ENV['GRAPE_VERSION'] || '~> 0.14.1' -# when 'HEAD' -gem 'grape', github: 'ruby-grape/grape' -# else -# gem 'grape', version -# end +case version = ENV['GRAPE_VERSION'] || '~> 0.14.0' +when 'HEAD' + gem 'grape', github: 'ruby-grape/grape' +else + gem 'grape', version +end diff --git a/grape-swagger.gemspec b/grape-swagger.gemspec index 1f141e44..2fe2559e 100644 --- a/grape-swagger.gemspec +++ b/grape-swagger.gemspec @@ -22,12 +22,12 @@ Gem::Specification.new do |s| s.add_development_dependency 'bundler' s.add_development_dependency 'rack-test' s.add_development_dependency 'rack-cors' - s.add_development_dependency 'rubocop', '0.33.0' - s.add_development_dependency 'kramdown', '~> 1.4.1' - s.add_development_dependency 'redcarpet', '~> 3.1.2' unless RUBY_PLATFORM.eql? 'java' - s.add_development_dependency 'rouge', '~> 1.6.1' - s.add_development_dependency 'pry' - s.add_development_dependency 'pry-byebug' + s.add_development_dependency 'rubocop' + s.add_development_dependency 'kramdown' + s.add_development_dependency 'redcarpet' unless RUBY_PLATFORM.eql? 'java' + s.add_development_dependency 'rouge' unless RUBY_PLATFORM.eql? 'java' + s.add_development_dependency 'pry' unless RUBY_PLATFORM.eql? 'java' + s.add_development_dependency 'pry-byebug' unless RUBY_PLATFORM.eql? 'java' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec}/*`.split("\n") diff --git a/lib/grape-swagger.rb b/lib/grape-swagger.rb index 4be06772..89bdd5db 100644 --- a/lib/grape-swagger.rb +++ b/lib/grape-swagger.rb @@ -89,11 +89,11 @@ def combine_namespace_routes(namespaces) if namespace.options.key?(:swagger) && namespace.options[:swagger][:nested] == false # Namespace shall appear as standalone resource, use specified name or use normalized path as name - if namespace.options[:swagger].key?(:name) - identifier = namespace.options[:swagger][:name].tr(' ', '-') - else - identifier = name.tr('_', '-').gsub(/\//, '_') - end + identifier = if namespace.options[:swagger].key?(:name) + name.tr(' ', '-') + else + name.tr('_', '-').gsub(/\//, '_') + end @target_class.combined_namespace_identifiers[identifier] = name @target_class.combined_namespace_routes[identifier] = namespace_routes @@ -105,8 +105,8 @@ def combine_namespace_routes(namespaces) # default case when not explicitly specified or nested == true standalone_namespaces = namespaces.reject do |_, ns| !ns.options.key?(:swagger) || - !ns.options[:swagger].key?(:nested) || - ns.options[:swagger][:nested] != false + !ns.options[:swagger].key?(:nested) || + ns.options[:swagger][:nested] != false end parent_standalone_namespaces = standalone_namespaces.reject { |ns_name, _| !name.start_with?(ns_name) } @@ -143,8 +143,7 @@ def route_path_start_with?(route, name) route_prefix = route.route_prefix ? "/#{route.route_prefix}/#{name}" : "/#{name}" route_versioned_prefix = route.route_prefix ? "/#{route.route_prefix}/:version/#{name}" : "/:version/#{name}" - route.route_path.start_with?(route_prefix) || - route.route_path.start_with?(route_versioned_prefix) + route.route_path.start_with?(route_prefix, route_versioned_prefix) end def standalone_sub_namespaces(name, namespaces) diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 1057c190..4df28807 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -11,7 +11,7 @@ class Endpoint 'byte' => %w(string byte), 'date' => %w(string date), 'dateTime' => %w(string date-time) - } + }.freeze def content_types_for(target_class) content_types = (target_class.content_types || {}).values @@ -103,7 +103,7 @@ def path_item(routes, options) path.gsub!(/:(\w+)/, '{\1}') # set item from path, this could be used for the definitions object - @item = path.gsub(/\/\{(.+?)\}/, '').split('/').last.singularize.underscore.camelize || 'Item' + @item = path.gsub(%r{/{(.+?)}}, '').split('/').last.singularize.underscore.camelize || 'Item' @entity = route.route_entity || route.route_success # ... replacing version params through submitted version @@ -175,14 +175,15 @@ def response_object(route) response_model = @item response_model = expose_params_from_model(value[:model]) if value[:model] - next unless !response_model.start_with?('Swagger_doc') && ((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model]) + next unless !response_model.start_with?('Swagger_doc') && + ((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model]) # TODO: proof that the definition exist, if model isn't specified - if route.route_is_array - memo[value[:code]][:schema] = { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } } - else - memo[value[:code]][:schema] = { '$ref' => "#/definitions/#{response_model}" } - end + memo[value[:code]][:schema] = if route.route_is_array + { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } } + else + { '$ref' => "#/definitions/#{response_model}" } + end end end @@ -287,7 +288,7 @@ def hidden?(route) end def parse_params(param, value, path, method) - items = {} + @array_items = {} additional_documentation = value.is_a?(Hash) ? value[:documentation] : nil data_type = data_type(value) @@ -306,6 +307,7 @@ def parse_params(param, value, path, method) enum_or_range_values = parse_enum_or_range_values(values) value_type = { value: value, data_type: data_type, path: path } + parsed_params = { in: param_type(value_type, param, method, is_array), name: name, @@ -319,12 +321,10 @@ def parse_params(param, value, path, method) parsed_params[:type], parsed_params[:format] = PRIMITIVE_MAPPINGS[data_type] end - parsed_params[:items] = items if items.present? + parsed_params[:items] = @array_items if @array_items.present? parsed_params[:defaultValue] = example if example - if default_value && example.blank? - parsed_params[:defaultValue] = default_value - end + parsed_params[:defaultValue] = default_value if default_value && example.blank? parsed_params.merge!(enum_or_range_values) if enum_or_range_values parsed_params @@ -368,8 +368,9 @@ def param_type(value_type, param, method, is_array) value_type[:value][:documentation].key?(:param_type) if is_array - items = { '$ref' => value_type[:data_type] } - data_type = 'array' + @array_items = { 'type' => value_type[:data_type] } + + 'array' end else case diff --git a/lib/grape-swagger/version.rb b/lib/grape-swagger/version.rb index b9ffc4e8..48c84326 100644 --- a/lib/grape-swagger/version.rb +++ b/lib/grape-swagger/version.rb @@ -1,3 +1,3 @@ module GrapeSwagger - VERSION = '0.10.3' + VERSION = '0.11.0'.freeze end diff --git a/spec/markdown/kramdown_adapter_spec.rb b/spec/markdown/kramdown_adapter_spec.rb index 9612ac25..e6f9390f 100644 --- a/spec/markdown/kramdown_adapter_spec.rb +++ b/spec/markdown/kramdown_adapter_spec.rb @@ -15,12 +15,6 @@ expect(adapter.options).to eq(options) end - - it 'raises an GrapeSwagger::Errors::MarkdownDependencyMissingError if module can not be required' do - expect_any_instance_of(Kernel).to receive(:require).with('kramdown').and_raise(LoadError) - - expect { GrapeSwagger::Markdown::KramdownAdapter.new }.to raise_error(GrapeSwagger::Errors::MarkdownDependencyMissingError, 'Missing required dependency: kramdown') - end end context 'markdown' do diff --git a/spec/markdown/redcarpet_adapter_spec.rb b/spec/markdown/redcarpet_adapter_spec.rb index cea3b771..9838ab5a 100644 --- a/spec/markdown/redcarpet_adapter_spec.rb +++ b/spec/markdown/redcarpet_adapter_spec.rb @@ -30,12 +30,6 @@ expect(adapter.extension_options).to eq(extensions) expect(adapter.render_options).to eq(no_links: true) end - - it 'raises an GrapeSwagger::Errors::MarkdownDependencyMissingError if module can not be required.' do - expect_any_instance_of(Kernel).to receive(:require).with('redcarpet').and_raise(LoadError) - - expect { GrapeSwagger::Markdown::RedcarpetAdapter.new }.to raise_error(GrapeSwagger::Errors::MarkdownDependencyMissingError, 'Missing required dependency: redcarpet') - end end context 'markdown' do @@ -60,14 +54,6 @@ expect(renderer.superclass).to be(Redcarpet::Render::HTML) end - it 'throws an error when rouge syntax highlighter cant be included' do - adapter = GrapeSwagger::Markdown::RedcarpetAdapter.new - - expect_any_instance_of(Kernel).to receive(:require).with('rouge').and_raise(LoadError) - - expect { adapter.send(:new_redcarpet_renderer, :rouge) }.to raise_error(GrapeSwagger::Errors::MarkdownDependencyMissingError, 'Missing required dependency: rouge') - end - it 'returns a default syntax highlighter' do adapter = GrapeSwagger::Markdown::RedcarpetAdapter.new renderer = adapter.send(:new_redcarpet_renderer, :none) diff --git a/spec/support/api_swagger_v2_result.rb b/spec/support/api_swagger_v2_result.rb index c2aba54f..93a20805 100644 --- a/spec/support/api_swagger_v2_result.rb +++ b/spec/support/api_swagger_v2_result.rb @@ -77,10 +77,11 @@ class ApiError < Grape::Entity "/v3/other_thing/{elements}"=>{ "get"=>{ "produces"=>["application/json"], - "parameters"=>[{"in"=>"array", "name"=>"elements", "description"=>"Set of configuration", "type"=>"string", "required"=>true, "allowMultiple"=>true}], - "responses"=>{"200"=>{"description"=>"nested route inside namespace", "schema"=>{"$ref"=>"#/definitions/QueryInput"}}}, - "x-amazon-apigateway-auth"=>{"type"=>"none"}, - "x-amazon-apigateway-integration"=>{"type"=>"aws", "uri"=>"foo_bar_uri", "httpMethod"=>"get"}}}, + "parameters"=>[ + {"in"=>"array", "name"=>"elements", "description"=>"Set of configuration", "type"=>"string", "required"=>true, "allowMultiple"=>true, "items"=>{"type"=>"string"}}], + "responses"=>{"200"=>{"description"=>"nested route inside namespace", "schema"=>{"$ref"=>"#/definitions/QueryInput"}}}, + "x-amazon-apigateway-auth"=>{"type"=>"none"}, + "x-amazon-apigateway-integration"=>{"type"=>"aws", "uri"=>"foo_bar_uri", "httpMethod"=>"get"}}}, "/thing"=>{ "get"=>{ "produces"=>["application/json"], diff --git a/spec/swagger_v2/api_swagger_v2_detail_spec.rb b/spec/swagger_v2/api_swagger_v2_detail_spec.rb index db463046..6d789df7 100644 --- a/spec/swagger_v2/api_swagger_v2_detail_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_detail_spec.rb @@ -1,3 +1,5 @@ +# encoding: UTF-8 + require 'spec_helper' def details @@ -109,7 +111,7 @@ def app end end - describe 'details, convert markdown with redcarpet' do + describe 'details, convert markdown with redcarpet', unless: RUBY_PLATFORM.eql?('java') do include_context "the api entities" before :all do @@ -142,7 +144,7 @@ def app specify do expect(subject['paths']['/use_gfm_rc_detail']['get']).to include('description') expect(subject['paths']['/use_gfm_rc_detail']['get']['description']).to eql( - "

Burgers in Heaven

\n\n
\n

A burger doesn't come for free

\n
\n\n

If you want to reserve a burger in heaven, you have to do\nsome crazy stuff on earth.

\n
def do_good\nputs 'help people'\nend\n
\n\n
    \n
  • Will go to Heaven: Probably
  • \n
  • Will go to Hell: Probably not
  • \n
" + "

Burgers in Heaven

\n\n
\n

A burger doesn't come for free

\n
\n\n

If you want to reserve a burger in heaven, you have to do\nsome crazy stuff on earth.

\n
def do_good\nputs 'help people'\nend\n
\n\n
    \n
  • Will go to Heaven: Probably
  • \n
  • Will go to Hell: Probably not
  • \n
" ) end end diff --git a/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb index 8b5fbccc..02ea3908 100644 --- a/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb @@ -99,6 +99,6 @@ def app specify do expect(subject['paths']['/use_produces']['get']).to include('produces') expect(subject['paths']['/use_produces']['get']['produces']).to eql(produced) - end + end end end