diff --git a/.travis.yml b/.travis.yml index 9ecb4d7b..3130e447 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,10 @@ matrix: env: GRAPE_VERSION=0.14.0 - rvm: 2.3.1 env: GRAPE_VERSION=0.15.0 -# - rvm: 2.3.1 -# env: GRAPE_VERSION=0.16.0 -# - rvm: 2.3.1 -# env: GRAPE_VERSION=HEAD + - rvm: 2.3.1 + env: GRAPE_VERSION=0.16.0 + - rvm: 2.3.1 + env: GRAPE_VERSION=HEAD - rvm: 2.3.0 - rvm: 2.2.5 - rvm: 2.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d315e9..bb4d616e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * [#406](https://github.com/ruby-grape/grape-swagger/pull/406): Force usage of entities for response definition [issue #385](https://github.com/ruby-grape/grape-swagger/issues/385) - [@LeFnord](https://github.com/LeFnord). * [#405](https://github.com/ruby-grape/grape-swagger/pull/405), [#403](https://github.com/ruby-grape/grape-swagger/issues/403): Added version support matrix - [@LeFnord](https://github.com/LeFnord). * [#408](https://github.com/ruby-grape/grape-swagger/pull/408): Added support for `HEAD` endpoints - [@Bugagazavr](https://github.com/Bugagazavr). -* [#407](https://github.com/ruby-grape/grape-swagger/issues/407): Added support for Grape 0.15.x - [@dblock](https://github.com/dblock). +* [#407](https://github.com/ruby-grape/grape-swagger/issues/407): Added support for Grape 0.15.x and 0.16.x - [@dblock](https://github.com/dblock). * Your contribution here. #### Fixes diff --git a/Gemfile b/Gemfile index 034dad50..31d8037e 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'http://rubygems.org' gemspec -case version = ENV['GRAPE_VERSION'] || '~> 0.15.0' +case version = ENV['GRAPE_VERSION'] || '~> 0.16.2' when 'HEAD' gem 'grape', github: 'ruby-grape/grape' else diff --git a/grape-swagger.gemspec b/grape-swagger.gemspec index 64e8c057..b98b1464 100644 --- a/grape-swagger.gemspec +++ b/grape-swagger.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| s.summary = 'A simple way to add auto generated documentation to your Grape API that can be displayed with Swagger.' s.license = 'MIT' - s.add_runtime_dependency 'grape', ['>= 0.12.0', '< 0.16.0'] + s.add_runtime_dependency 'grape', '>= 0.12.0' s.add_runtime_dependency 'grape-entity' s.add_runtime_dependency 'awesome_print' diff --git a/lib/grape-swagger.rb b/lib/grape-swagger.rb index 290c3e3f..95fc3052 100644 --- a/lib/grape-swagger.rb +++ b/lib/grape-swagger.rb @@ -1,4 +1,7 @@ require 'grape' + +require 'grape-swagger/grape/route' + require 'grape-swagger/version' require 'grape-swagger/endpoint' require 'grape-swagger/errors' @@ -48,8 +51,8 @@ def version_for(options) def combine_routes(app, doc_klass) app.routes.each do |route| - route_path = route.route_path - route_match = route_path.split(/^.*?#{route.route_prefix.to_s}/).last + route_path = route.path + route_match = route_path.split(/^.*?#{route.prefix.to_s}/).last next unless route_match route_match = route_match.match('\/([\w|-]*?)[\.\/\(]') || route_match.match('\/([\w|-]*)$') next unless route_match @@ -57,7 +60,7 @@ def combine_routes(app, doc_klass) next if resource.empty? resource.downcase! @target_class.combined_routes[resource] ||= [] - next if doc_klass.hide_documentation_path && route.route_path.match(/#{doc_klass.mount_path}($|\/|\(\.)/) + next if doc_klass.hide_documentation_path && route.path.match(/#{doc_klass.mount_path}($|\/|\(\.)/) @target_class.combined_routes[resource] << route end end @@ -141,10 +144,10 @@ def route_instance_variable_equals?(route, name) end 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_prefix = route.prefix ? "/#{route.prefix}/#{name}" : "/#{name}" + route_versioned_prefix = route.prefix ? "/#{route.prefix}/:version/#{name}" : "/:version/#{name}" - route.route_path.start_with?(route_prefix, route_versioned_prefix) + route.path.start_with?(route_prefix, route_versioned_prefix) end def standalone_sub_namespaces(name, namespaces) diff --git a/lib/grape-swagger/doc_methods/extensions.rb b/lib/grape-swagger/doc_methods/extensions.rb index 816a4c4b..c4d3845b 100644 --- a/lib/grape-swagger/doc_methods/extensions.rb +++ b/lib/grape-swagger/doc_methods/extensions.rb @@ -4,10 +4,10 @@ class Extensions class << self def add(path, definitions, route) @route = route - description = route.route_settings[:description] + description = route.settings[:description] add_extension_to(path[method], extension(description)) if description && extended?(description, :x) - settings = route.route_settings + settings = route.settings add_extensions_to_path(settings, path) if settings && extended?(settings, :x_path) add_extensions_to_definition(settings, path, definitions) if settings && extended?(settings, :x_def) end @@ -67,7 +67,7 @@ def extension(part, identifier = :x) end def method - @route.route_method.downcase.to_sym + @route.request_method.downcase.to_sym end end end diff --git a/lib/grape-swagger/doc_methods/headers.rb b/lib/grape-swagger/doc_methods/headers.rb index f6cd2501..8b3eac3b 100644 --- a/lib/grape-swagger/doc_methods/headers.rb +++ b/lib/grape-swagger/doc_methods/headers.rb @@ -3,7 +3,7 @@ module DocMethods class Headers class << self def parse(route) - route.route_headers.to_a.map do |route_header| + route.headers.to_a.map do |route_header| route_header.tap do |header| hash = header[1] description = hash.delete('description') diff --git a/lib/grape-swagger/doc_methods/operation_id.rb b/lib/grape-swagger/doc_methods/operation_id.rb index 677c3d54..a1872a8b 100644 --- a/lib/grape-swagger/doc_methods/operation_id.rb +++ b/lib/grape-swagger/doc_methods/operation_id.rb @@ -3,7 +3,7 @@ module DocMethods class OperationId class << self def build(route, path = nil) - verb = route.route_method.to_s.downcase + verb = route.request_method.to_s.downcase operation = manipulate(path) unless path.nil? diff --git a/lib/grape-swagger/doc_methods/parse_params.rb b/lib/grape-swagger/doc_methods/parse_params.rb index 5a617f3f..ef66700b 100644 --- a/lib/grape-swagger/doc_methods/parse_params.rb +++ b/lib/grape-swagger/doc_methods/parse_params.rb @@ -3,8 +3,8 @@ module DocMethods class ParseParams class << self def call(param, settings, route) - path = route.route_path - method = route.route_method + path = route.path + method = route.request_method data_type = GrapeSwagger::DocMethods::DataType.call(settings) additional_documentation = settings[:documentation] diff --git a/lib/grape-swagger/doc_methods/tag_name_description.rb b/lib/grape-swagger/doc_methods/tag_name_description.rb index 9cbc26ff..7cdf9023 100644 --- a/lib/grape-swagger/doc_methods/tag_name_description.rb +++ b/lib/grape-swagger/doc_methods/tag_name_description.rb @@ -8,7 +8,7 @@ def build(options = {}) namespace_routes = target_class.combined_namespace_routes namespace_routes.keys.map do |local_route| - next if namespace_routes[local_route].map(&:route_hidden).all? { |value| value.respond_to?(:call) ? value.call : value } + next if namespace_routes[local_route].map { |route| route.options[:hidden] }.all? { |value| value.respond_to?(:call) ? value.call : value } original_namespace_name = target_class.combined_namespace_identifiers.key?(local_route) ? target_class.combined_namespace_identifiers[local_route] : local_route description = namespaces[original_namespace_name] && namespaces[original_namespace_name].options[:desc] diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index a8974a96..320cf5f6 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -86,8 +86,8 @@ def path_item(routes, options) routes.each do |route| next if hidden?(route) - @item, path = GrapeSwagger::DocMethods::PathString.build(route.route_path, options) - @entity = route.route_entity || route.route_success + @item, path = GrapeSwagger::DocMethods::PathString.build(route.path, options) + @entity = route.entity || route.options[:success] verb, method_object = method_object(route, options, path) @@ -112,14 +112,14 @@ def method_object(route, options, path) method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path) method.delete_if { |_, value| value.blank? } - [route.route_method.downcase.to_sym, method] + [route.request_method.downcase.to_sym, method] end def description_object(route, markdown) - description = route.route_desc if route.route_desc.present? - description = route.route_description if route.route_description.present? + description = route.options[:desc] if route.options.key?(:desc) + description = route.description if route.description.present? description = "# #{description} " if markdown - description += "\n #{route.route_detail}" if route.route_detail + description += "\n #{route.options[:detail]}" if route.options.key?(:detail) description = markdown.markdown(description.to_s).chomp if markdown description @@ -128,8 +128,8 @@ def description_object(route, markdown) def produces_object(route, format) mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format) - route_mime_types = [:route_formats, :route_content_types, :route_produces].map do |producer| - possible = route.send(producer) + route_mime_types = [:formats, :content_types, :produces].map do |producer| + possible = route.options[producer] GrapeSwagger::DocMethods::ProducesConsumes.call(possible) if possible.present? end.flatten.compact.uniq @@ -137,8 +137,8 @@ def produces_object(route, format) end def consumes_object(route, format) - method = route.route_method.downcase.to_sym - format = route.route_settings[:description][:consumes] if route.route_settings[:description] && route.route_settings[:description][:consumes] + method = route.request_method.downcase.to_sym + format = route.settings[:description][:consumes] if route.settings[:description] && route.settings[:description][:consumes] mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format) if [:post, :put].include?(method) mime_types @@ -153,11 +153,11 @@ def params_object(route) end def response_object(route, markdown) - default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.route_method.downcase.to_sym] + default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.request_method.downcase.to_sym] default_code[:model] = @entity if @entity - default_code[:message] = route.route_description || default_code[:message].sub('{item}', @item) + default_code[:message] = route.description || default_code[:message].sub('{item}', @item) - codes = [default_code] + (route.route_http_codes || route.route_failure || []) + codes = [default_code] + (route.http_codes || route.options[:failure] || []) codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2] } : x } codes.each_with_object({}) do |value, memo| @@ -166,7 +166,7 @@ def response_object(route, markdown) response_model = @item response_model = expose_params_from_model(value[:model]) if value[:model] - if memo.key?(200) && route.route_method == 'DELETE' && value[:model].nil? + if memo.key?(200) && route.request_method == 'DELETE' && value[:model].nil? memo[204] = memo.delete(200) value[:code] = 204 end @@ -177,7 +177,7 @@ def response_object(route, markdown) @definitions[response_model][:description] = description_object(route, markdown) # TODO: proof that the definition exist, if model isn't specified - memo[value[:code]][:schema] = if route.route_is_array + memo[value[:code]][:schema] = if route.options[:is_array] { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } } else { '$ref' => "#/definitions/#{response_model}" } @@ -186,23 +186,23 @@ def response_object(route, markdown) end def tag_object(route, version) - Array(route.route_path.split('{')[0].split('/').reject(&:empty?).delete_if { |i| ((i == route.route_prefix.to_s) || (i == version)) }.first) + Array(route.path.split('{')[0].split('/').reject(&:empty?).delete_if { |i| ((i == route.prefix.to_s) || (i == version)) }.first) end private def partition_params(route) - declared_params = route.route_settings[:declared_params] if route.route_settings[:declared_params].present? - required, exposed = route.route_params.partition { |x| x.first.is_a? String } - required.concat GrapeSwagger::DocMethods::Headers.parse(route) unless route.route_headers.nil? + declared_params = route.settings[:declared_params] if route.settings[:declared_params].present? + required, exposed = route.params.partition { |x| x.first.is_a? String } + required.concat GrapeSwagger::DocMethods::Headers.parse(route) unless route.headers.nil? default_type(required) default_type(exposed) - unless declared_params.nil? && route.route_headers.nil? + unless declared_params.nil? && route.headers.nil? request_params = parse_request_params(required) end - return route.route_params if route.route_params.present? && !route.route_settings[:declared_params].present? + return route.params if route.params.present? && !route.settings[:declared_params].present? request_params || {} end @@ -295,11 +295,9 @@ def could_it_be_a_model?(value) end def hidden?(route) - if route.route_hidden - return route.route_hidden.is_a?(Proc) ? route.route_hidden.call : route.route_hidden - end - - false + route_hidden = route.options[:hidden] + route_hidden = route_hidden.call if route_hidden.is_a?(Proc) + route_hidden end end end diff --git a/lib/grape-swagger/grape/route.rb b/lib/grape-swagger/grape/route.rb new file mode 100644 index 00000000..f9dc6309 --- /dev/null +++ b/lib/grape-swagger/grape/route.rb @@ -0,0 +1,16 @@ +# backwards compatibility for Grape < 0.16.0 +module Grape + class Route + [:path, :prefix, :entity, :description, :settings, :params, :headers, :http_codes].each do |m| + define_method m do + send "route_#{m}" + end + end + + def request_method + route_method + end + + attr_reader :options + end +end if defined?(Grape::VERSION) && Gem::Version.new(::Grape::VERSION) < Gem::Version.new('0.16.0') diff --git a/spec/lib/operation_id_spec.rb b/spec/lib/operation_id_spec.rb index e68826d7..12dcd50c 100644 --- a/spec/lib/operation_id_spec.rb +++ b/spec/lib/operation_id_spec.rb @@ -7,7 +7,11 @@ specify { expect(subject).to respond_to :build } describe 'build' do - let(:route) { Grape::Route.new(method: method) } + if defined?(Grape::VERSION) && Gem::Version.new(::Grape::VERSION) < Gem::Version.new('0.16.0') + let(:route) { Grape::Route.new(method: method) } + else + let(:route) { Grape::Router::Route.new(method, '/path', requirements: {}) } + end describe 'GET' do let(:method) { 'GET' } diff --git a/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb b/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb index f015ae27..eafddcab 100644 --- a/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +++ b/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb @@ -44,7 +44,7 @@ def app end specify do - expect(subject['paths']['/bookings/{id}']['put']['parameters']).to eql( + expect(subject['paths']['/bookings/{id}']['put']['parameters'].sort_by { |p| p['name'] }).to eql( [ { 'in' => 'path', 'name' => 'id', 'type' => 'integer', 'format' => 'int32', 'required' => true }, { 'in' => 'formData', 'name' => 'name', 'type' => 'string', 'required' => false }