api docs: add deprecation functionality + documentation
Adds the @deprecated_method, @deprecated_argument, and @deprecated_response_field tags for API documentation. Also adds the 'deprecated', 'deprecation_notice', 'deprecation_effective', and 'deprecation_description' attributes for the API models and their properties. closes GRADE-1450 Test Plan: 1. Read the deprecation_README provided in this commit and verify you can deprecate methods, arguments, response fields, models, and model attributes. This verificiation process should include: - Verifying the `rake doc:api` command throws an error when invalid and/or missing parameters are used for the deprecation tags - Verifying the deprecations show up in the generated documentation (located at public/doc/api/index.html) after running `rake doc:api`. 2. Verify the @argument, @response_field, and @model tags still work and generate appropriate documentation when running `rake doc:api` Change-Id: If6c2b0ee9fccbbd202990d8835c6266017e2dfa5 Reviewed-on: https://gerrit.instructure.com/138581 Reviewed-by: Gary Mei <gmei@instructure.com> Reviewed-by: Derek Bender <djbender@instructure.com> QA-Review: Gary Mei <gmei@instructure.com> Tested-by: Jenkins Product-Review: Simon Williams <simon@instructure.com>
This commit is contained in:
parent
91820598a9
commit
3792afc12e
|
@ -0,0 +1,117 @@
|
|||
# Canvas API Deprecation
|
||||
In the examples below, the deprecation dates should follow these rules:
|
||||
* The `NOTICE` date should be the date that the deprecation warning
|
||||
will first be visible in production.
|
||||
* To determine the `EFFECTIVE` date, add 90 days to the `NOTICE`
|
||||
date. If that day is a production release date, use that date. If that
|
||||
date is _not_ a production release date, use the next production release
|
||||
date after that date.
|
||||
* Both dates should be formatted as YYYY-MM-DD.
|
||||
|
||||
## API Method Deprecation
|
||||
To deprecate an API method, use the `@deprecated_method` tag. You must provide
|
||||
a `NOTICE` date and an `EFFECTIVE` date for the deprecation, along with a
|
||||
description for the deprecation.
|
||||
|
||||
### Deprecate a method with a replacement
|
||||
```ruby
|
||||
# @deprecated_method NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the deprecated method and why we're deprecating it.
|
||||
# Use {api:FooController#bar_action Foo#bar_action} instead.
|
||||
def foo_action
|
||||
end
|
||||
|
||||
def bar_action
|
||||
end
|
||||
```
|
||||
|
||||
### Deprecate a method without a replacement
|
||||
```ruby
|
||||
# @deprecated_method NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the deprecated method and why we're deprecating it.
|
||||
def foo_action
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
## API Model Deprecation
|
||||
To deprecate an API model, add the `deprecated`, `deprecation_notice`,
|
||||
`deprecation_effective`, and `deprecation_description` keys. These keys can be
|
||||
applied at the base model level to deprecate the entire model, or they can be
|
||||
applied at the property level to individually deprecate model properties.
|
||||
|
||||
### Deprecate an entire API model
|
||||
```ruby
|
||||
# @model Foo
|
||||
# {
|
||||
# "id": "Foo",
|
||||
# "description": "A description.",
|
||||
# "deprecated": true,
|
||||
# "deprecation_notice": "YYYY-MM-DD",
|
||||
# "deprecation_effective": "YYYY-MM-DD",
|
||||
# "deprecation_description": "A description of the deprecation.",
|
||||
# "properties": {
|
||||
# "bar": {
|
||||
# "description": "A property.",
|
||||
# "example": "baz",
|
||||
# "type": "string"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
```
|
||||
|
||||
### Deprecate an API model property
|
||||
```ruby
|
||||
# @model Foo
|
||||
# {
|
||||
# "id": "Foo",
|
||||
# "description": "A description.",
|
||||
# "properties": {
|
||||
# "bar": {
|
||||
# "deprecated": true,
|
||||
# "deprecation_notice": "YYYY-MM-DD",
|
||||
# "deprecation_effective": "YYYY-MM-DD",
|
||||
# "deprecation_description": "A description of the deprecation.",
|
||||
# "description": "A property.",
|
||||
# "example": "baz",
|
||||
# "type": "string"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
```
|
||||
|
||||
## API Argument Deprecation
|
||||
To deprecate an API argument, rename the `@argument` tag to
|
||||
`@deprecated_argument`. You must provide a `NOTICE` date and an `EFFECTIVE` date
|
||||
for the deprecation, along with a description for the deprecation.
|
||||
|
||||
Before:
|
||||
```ruby
|
||||
# @argument foo [Required, String]
|
||||
# A description of the argument.
|
||||
```
|
||||
|
||||
After:
|
||||
```ruby
|
||||
# @deprecated_argument foo [Required, String] NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the argument, along with a description of the deprecation.
|
||||
```
|
||||
|
||||
## API Response Field Deprecation
|
||||
To deprecate an API response field, rename the `@response_field` tag to
|
||||
`@deprecated_response_field`. You must provide a `NOTICE` date and an
|
||||
`EFFECTIVE` date for the deprecation, along with a description for the
|
||||
deprecation.
|
||||
|
||||
Before:
|
||||
```ruby
|
||||
# @response_field foo
|
||||
# A description of the response field.
|
||||
```
|
||||
|
||||
After:
|
||||
```ruby
|
||||
# @deprecated_response_field foo NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the response field, along with a description of the
|
||||
# deprecation.
|
||||
```
|
|
@ -46,8 +46,20 @@ end
|
|||
# Extend YARD to generate our API documentation
|
||||
YARD::Tags::Library.define_tag("Is an API method", :API)
|
||||
YARD::Tags::Library.define_tag("API method argument", :argument)
|
||||
# Expected Format:
|
||||
# @deprecated_argument argument_name NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the deprecation. (required)
|
||||
YARD::Tags::Library.define_tag("API method argument is deprecated", :deprecated_argument)
|
||||
# Expected Format:
|
||||
# @deprecated_method NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# Use {api:FooController#some_action Foo#some_action} instead. A description of the deprecated method. (required)
|
||||
YARD::Tags::Library.define_tag("API method is deprecated", :deprecated_method)
|
||||
YARD::Tags::Library.define_tag("API response field", :request_field)
|
||||
YARD::Tags::Library.define_tag("API response field", :response_field)
|
||||
# Expected Format:
|
||||
# @deprecated_response_field response_field NOTICE YYYY-MM-DD EFFECTIVE YYYY-MM-DD
|
||||
# A description of the deprecation. (required)
|
||||
YARD::Tags::Library.define_tag("API response field is deprecated", :deprecated_response_field)
|
||||
YARD::Tags::Library.define_tag("API example request", :example_request)
|
||||
YARD::Tags::Library.define_tag("API example response", :example_response)
|
||||
YARD::Tags::Library.define_tag("API subtopic", :subtopic)
|
||||
|
|
|
@ -36,6 +36,11 @@ p {
|
|||
font-family: monospace;
|
||||
}
|
||||
|
||||
.note.deprecated { background: #ffe5e5; border-color: #e9dada; padding: 1.33em; }
|
||||
.note.title.deprecated { background: #ffe5e5; border-color: #e9dada; }
|
||||
.request-param.deprecated, .response-field.deprecated { background: #ffe5e5; border-color: #e9dada; }
|
||||
.param-deprecated { width: 185px; }
|
||||
|
||||
h1 a:link, h1 a:visited,
|
||||
h2 a:link, h2 a:visited,
|
||||
h3 a:link, h3 a:visited,
|
||||
|
@ -362,36 +367,38 @@ code.enum {
|
|||
padding: 12px;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
table.request-params {
|
||||
table.request-params, table.response-fields {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
margin-bottom: 1.33em;
|
||||
}
|
||||
table.request-params, table.request-params th, table.request-params td {
|
||||
|
||||
table.request-params, table.request-params th, table.request-params td, table.response-fields, table.response-fields th, table.response-fields td {
|
||||
border: 0;
|
||||
text-align: left;
|
||||
}
|
||||
table.request-params td {
|
||||
table.request-params td, table.response-fields td {
|
||||
border-bottom: 1px solid #ccc;
|
||||
vertical-align: text-top;
|
||||
font-family: Monaco, Lucida Console, monospace;
|
||||
font-size: 12px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
table.request-params td.param-desc {
|
||||
table.request-params td.param-desc, table.response-fields td.param-desc {
|
||||
font-family: "Helvetica Neue", Helvetica;
|
||||
}
|
||||
table.request-params td.param-desc ul {
|
||||
table.request-params td.param-desc ul, table.response-fields td.param-desc ul {
|
||||
padding: 0;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
.param-name {
|
||||
.param-name, .field-name {
|
||||
width: 20em;
|
||||
}
|
||||
.param-req {
|
||||
width: 5em;
|
||||
}
|
||||
.param-type {
|
||||
.param-type, .param-deprecated, .param-effective, .field-type, .field-deprecated, .field-effective, {
|
||||
width: 10em;
|
||||
}
|
||||
.param-desc {
|
||||
|
|
|
@ -122,6 +122,8 @@ module YARD::Templates::Helpers::BaseHelper
|
|||
end
|
||||
|
||||
module YARD::Templates::Helpers::HtmlHelper
|
||||
include CanvasAPI::Deprecatable
|
||||
|
||||
def topicize(str)
|
||||
str.gsub(' ', '_').underscore
|
||||
end
|
||||
|
|
|
@ -16,16 +16,23 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require_relative 'canvas_api/deprecatable'
|
||||
require 'hash_view'
|
||||
|
||||
class ArgumentView < HashView
|
||||
attr_reader :line, :http_verb, :path_variables
|
||||
include CanvasAPI::Deprecatable
|
||||
|
||||
attr_reader :line, :http_verb, :path_variables, :effective_date, :notice_date
|
||||
attr_reader :name, :type, :desc
|
||||
|
||||
DEFAULT_TYPE = "[String]"
|
||||
DEFAULT_DESC = "no description"
|
||||
|
||||
def initialize(line, http_verb = "get", path_variables = [])
|
||||
def initialize(line, http_verb = "get", path_variables = [], deprecated: false)
|
||||
@deprecated = deprecated
|
||||
@deprecated_date_key = :NOTICE
|
||||
@effective_date_key = :EFFECTIVE
|
||||
@tag_declaration_line = line
|
||||
@line, @name, @type, @desc = parse_line(line)
|
||||
@http_verb = http_verb
|
||||
@path_variables = path_variables
|
||||
|
@ -33,7 +40,14 @@ class ArgumentView < HashView
|
|||
end
|
||||
|
||||
def parse_line(line)
|
||||
name, remaining = (line || "").split(/\s/, 2)
|
||||
if deprecated?
|
||||
parse_deprecation_info(line)
|
||||
name_and_remaining = line_without_deprecation_tags(line)
|
||||
else
|
||||
name_and_remaining = line
|
||||
end
|
||||
|
||||
name, remaining = (name_and_remaining || "").split(/\s/, 2)
|
||||
raise(ArgumentError, "param name missing:\n#{line}") unless name
|
||||
name.strip!
|
||||
type, desc = split_type_desc(remaining || "")
|
||||
|
@ -138,6 +152,7 @@ class ArgumentView < HashView
|
|||
"type" => swagger_type,
|
||||
"format" => swagger_format,
|
||||
"required" => required?,
|
||||
"deprecated" => deprecated?,
|
||||
}
|
||||
swagger['enum'] = enums unless enums.empty?
|
||||
if array?
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module CanvasAPI
|
||||
module Deprecatable
|
||||
def deprecated?
|
||||
!!@deprecated
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_deprecation_info(line)
|
||||
validate_line(line)
|
||||
dates = extract_deprecation_dates(line)
|
||||
validate_deprecation_dates(dates)
|
||||
@effective_date = dates[:EFFECTIVE]
|
||||
@notice_date = dates[:NOTICE]
|
||||
end
|
||||
|
||||
def line_without_deprecation_tags(line)
|
||||
line.gsub(/NOTICE \S+\s?|\s?EFFECTIVE \S+\s?/, '')
|
||||
end
|
||||
|
||||
def extract_deprecation_dates(line)
|
||||
args = line.split(/\s/)
|
||||
deprecation_keys = [@deprecated_date_key, @effective_date_key]
|
||||
dates = {}
|
||||
args.each_with_index do |arg, index|
|
||||
key = arg.to_sym
|
||||
next unless deprecation_keys.include?(key)
|
||||
dates[key] = args[index + 1]
|
||||
end
|
||||
dates
|
||||
end
|
||||
|
||||
def validate_deprecation_dates(provided_dates)
|
||||
date_keys = [@deprecated_date_key, @effective_date_key]
|
||||
date_keys.each { |key| validate_date(key, provided_dates) }
|
||||
validate_date_range(provided_dates)
|
||||
end
|
||||
|
||||
def reference_line
|
||||
return @tag_declaration_line if @tag_declaration_line.blank?
|
||||
|
||||
"\n #{@tag_declaration_line}"
|
||||
end
|
||||
|
||||
def validate_deprecation_description
|
||||
if @description.blank?
|
||||
raise(
|
||||
ArgumentError,
|
||||
"Expected a description for #{@description_key.present? ? "`#{@description_key}`": 'the deprecation'}" \
|
||||
", but it was not provided.#{reference_line}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_line(text)
|
||||
line_count = (text || '').split("\n", 2).length
|
||||
if line_count < 2
|
||||
raise(
|
||||
ArgumentError,
|
||||
"Expected two lines: a tag declaration line with deprecation arguments, " \
|
||||
"and a description line, but found #{line_count} #{'line'.pluralize(line_count)}.#{reference_line}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_date(key, provided_dates)
|
||||
if !provided_dates.key?(key)
|
||||
raise(ArgumentError, "Expected argument `#{key}`, but it was not provided.#{reference_line}")
|
||||
elsif provided_dates.fetch(key).blank?
|
||||
raise(
|
||||
ArgumentError,
|
||||
"Expected a value to be present for argument `#{key}`, but it was blank.#{reference_line}"
|
||||
)
|
||||
end
|
||||
|
||||
date = provided_dates[key]
|
||||
begin
|
||||
Date.iso8601(date)
|
||||
rescue ArgumentError
|
||||
raise(
|
||||
ArgumentError,
|
||||
"Expected date `#{date}` for key `#{key}` to be in ISO 8601 format (YYYY-MM-DD).#{reference_line}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_date_range(provided_dates)
|
||||
deprecated_date = provided_dates[@deprecated_date_key]
|
||||
effective_date = provided_dates[@effective_date_key]
|
||||
days_deprecated = Date.iso8601(effective_date) - Date.iso8601(deprecated_date)
|
||||
if days_deprecated < 90
|
||||
raise(
|
||||
ArgumentError,
|
||||
"Expected >= 90 days between the `#{@deprecated_date_key}` (#{deprecated_date}) " \
|
||||
"and `#{@effective_date_key}` (#{effective_date}) dates, but the actual " \
|
||||
"difference was #{days_deprecated.to_i} days.#{reference_line}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require_relative 'canvas_api/deprecatable'
|
||||
require 'hash_view'
|
||||
|
||||
class DeprecatedMethodView < HashView
|
||||
include CanvasAPI::Deprecatable
|
||||
|
||||
attr_reader :description, :effective_date, :notice_date
|
||||
|
||||
def initialize(tag)
|
||||
@deprecated_date_key = :NOTICE
|
||||
@effective_date_key = :EFFECTIVE
|
||||
@tag_declaration_line = tag.text
|
||||
@tag_type = "method"
|
||||
parse_line(tag.text)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_line(text)
|
||||
description = (text || '').split("\n", 2).second
|
||||
@description = description && format(description.strip)
|
||||
parse_deprecation_info(text)
|
||||
end
|
||||
end
|
|
@ -20,6 +20,8 @@ require 'hash_view'
|
|||
require 'argument_view'
|
||||
require 'route_view'
|
||||
require 'return_view'
|
||||
require 'response_field_view'
|
||||
require 'deprecated_method_view'
|
||||
|
||||
class MethodView < HashView
|
||||
def initialize(method)
|
||||
|
@ -52,8 +54,22 @@ class MethodView < HashView
|
|||
format(@method.docstring)
|
||||
end
|
||||
|
||||
def deprecated?
|
||||
select_tags('deprecated_method').any?
|
||||
end
|
||||
|
||||
def deprecation_description
|
||||
tag = select_tags('deprecated_method').first
|
||||
description = tag ? DeprecatedMethodView.new(tag).description : ''
|
||||
format(description)
|
||||
end
|
||||
|
||||
def raw_arguments
|
||||
select_tags("argument")
|
||||
select_tags(['argument', 'deprecated_argument'])
|
||||
end
|
||||
|
||||
def raw_response_fields
|
||||
select_tags(['response_field', 'deprecated_response_field'])
|
||||
end
|
||||
|
||||
def return_tag
|
||||
|
@ -116,10 +132,11 @@ class MethodView < HashView
|
|||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def select_tags(tag_name)
|
||||
protected
|
||||
def select_tags(tag_names)
|
||||
names = Array.wrap(tag_names)
|
||||
@method.tags.select do |tag|
|
||||
tag.tag_name.downcase == tag_name
|
||||
names.include?(tag.tag_name.downcase)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -22,20 +22,31 @@ require 'json'
|
|||
class ModelView < HashView
|
||||
attr_reader :name, :properties, :description, :required
|
||||
|
||||
def initialize(name, properties, description = "", required = [])
|
||||
def initialize(name, properties, description = "", required = [], deprecated: false, deprecation_description: '')
|
||||
@name = name
|
||||
@properties = properties
|
||||
@description = description
|
||||
@required = required
|
||||
@deprecated = deprecated
|
||||
@deprecation_description = deprecation_description
|
||||
end
|
||||
|
||||
def self.new_from_model(model)
|
||||
lines = model.text.lines.to_a
|
||||
json = JSON::parse(lines[1..-1].join)
|
||||
new(lines[0].strip,
|
||||
json["properties"],
|
||||
json["description"] ? json["description"] : "",
|
||||
json["required"] ? json["required"] : [])
|
||||
|
||||
new(
|
||||
lines[0].strip,
|
||||
json["properties"],
|
||||
json["description"] ? json["description"] : "",
|
||||
json["required"] ? json["required"] : [],
|
||||
deprecated: json["deprecated"],
|
||||
deprecation_description: json["deprecation_description"]
|
||||
)
|
||||
end
|
||||
|
||||
def deprecated?
|
||||
!!@deprecated
|
||||
end
|
||||
|
||||
def json_schema
|
||||
|
@ -44,6 +55,8 @@ class ModelView < HashView
|
|||
"id" => name,
|
||||
"description" => description,
|
||||
"required" => required,
|
||||
"deprecated" => deprecated?,
|
||||
"deprecation_description" => format(@deprecation_description),
|
||||
"properties" => properties
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require_relative 'canvas_api/deprecatable'
|
||||
require 'hash_view'
|
||||
|
||||
class ResponseFieldView < HashView
|
||||
include CanvasAPI::Deprecatable
|
||||
|
||||
attr_reader :types, :effective_date, :notice_date
|
||||
|
||||
def initialize(tag)
|
||||
line = tag.text
|
||||
@deprecated = tag.tag_name == 'deprecated_response_field'
|
||||
@deprecated_date_key = :NOTICE
|
||||
@effective_date_key = :EFFECTIVE
|
||||
@tag_declaration_line = line
|
||||
@name, @description = parse_line(line)
|
||||
@types = tag.types
|
||||
end
|
||||
|
||||
def parse_line(line)
|
||||
if deprecated?
|
||||
parse_deprecation_info(line)
|
||||
name_and_remaining = line_without_deprecation_tags(line)
|
||||
else
|
||||
name_and_remaining = line
|
||||
end
|
||||
|
||||
name, remaining = (name_and_remaining || "").split(/\s+/, 2)
|
||||
raise(ArgumentError, "param name missing:\n#{line}") unless name
|
||||
|
||||
raise(ArgumentError, "Expected a description to be present, but it was not provided.\n#{line}") if remaining.nil?
|
||||
description = remaining.strip
|
||||
[name, description]
|
||||
end
|
||||
|
||||
def name
|
||||
format(@name)
|
||||
end
|
||||
|
||||
def description
|
||||
format(@description)
|
||||
end
|
||||
|
||||
def to_swagger
|
||||
{
|
||||
"name" => name,
|
||||
"description" => description,
|
||||
"deprecated" => deprecated?
|
||||
}
|
||||
end
|
||||
end
|
|
@ -63,7 +63,7 @@ class RouteView < HashView
|
|||
|
||||
def query_args
|
||||
method_view.raw_arguments.map do |tag|
|
||||
ArgumentView.new(tag.text, verb, path_variables)
|
||||
ArgumentView.new(tag.text, verb, path_variables, deprecated: tag.tag_name&.downcase == 'deprecated_argument')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -85,6 +85,10 @@ class RouteView < HashView
|
|||
arguments.map { |arg| arg.to_swagger }
|
||||
end
|
||||
|
||||
def response_fields
|
||||
method_view.raw_response_fields.map { |tag| ResponseFieldView.new(tag).to_swagger }
|
||||
end
|
||||
|
||||
def nickname
|
||||
method_view.nickname + method_view.unique_nickname_suffix(self)
|
||||
end
|
||||
|
@ -96,6 +100,9 @@ class RouteView < HashView
|
|||
"notes" => method_view.desc,
|
||||
"nickname" => nickname,
|
||||
"parameters" => parameters,
|
||||
"response_fields" => response_fields,
|
||||
"deprecated" => method_view.deprecated?,
|
||||
"deprecation_description" => method_view.deprecation_description
|
||||
}.merge(method_view.swagger_type)
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,16 @@
|
|||
<span class='defined-in'><a href="https://github.com/instructure/canvas-lms/blob/master/<%= @controller_path %>"><%= "#{@route.requirements[:controller].camelize}Controller\##{@route.requirements[:action]}" %></a></span>
|
||||
<% end %>
|
||||
</h2>
|
||||
|
||||
<% if @deprecated_method.present? %>
|
||||
<div class="deprecated deprecated_method">
|
||||
<div class="note deprecated">
|
||||
<strong>[DEPRECATED] This method is deprecated, effective <%= h @deprecated_method.effective_date %> (notice given <%= h @deprecated_method.notice_date %>):</strong>
|
||||
<%= htmlify_line @deprecated_method.description %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @beta %>
|
||||
<h3 class='beta'>BETA: This API endpoint is not finalized, and there could be breaking changes before its final release.</h3>
|
||||
<% end %>
|
||||
|
|
|
@ -26,6 +26,11 @@ def header
|
|||
route = @routes.first
|
||||
@method_link = "method.#{route.requirements[:controller]}.#{route.requirements[:action]}"
|
||||
@beta = object.tag('beta') || object.parent.tag('beta')
|
||||
|
||||
if object.has_tag?(:deprecated_method)
|
||||
@deprecated_method = DeprecatedMethodView.new(object.tag(:deprecated_method))
|
||||
end
|
||||
|
||||
erb(:header)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
<th class="param-name">Parameter</th>
|
||||
<th class="param-req"></th>
|
||||
<th class="param-type">Type</th>
|
||||
<% if @request_parameters.any?(&:deprecated?) %>
|
||||
<th class="param-deprecated"></th>
|
||||
<% end %>
|
||||
<th class="param-desc">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @request_parameters.each do |param| %>
|
||||
<tr class="request-param">
|
||||
<tr class="request-param <%= param.deprecated? ? 'deprecated' : '' %>">
|
||||
<td><%= h param.name(json: false) %></td>
|
||||
<td>
|
||||
<% if param.required? %>
|
||||
|
@ -18,6 +21,16 @@
|
|||
<% end %>
|
||||
</td>
|
||||
<td><%= h param.swagger_type %></td>
|
||||
|
||||
<% if @request_parameters.any?(&:deprecated?) %>
|
||||
<td>
|
||||
<% if param.deprecated? %>
|
||||
<div><strong>[DEPRECATED]</strong></div>
|
||||
<div>Effective <%= h param.effective_date %> (notice given <%= h param.notice_date %>)</div>
|
||||
<% end %>
|
||||
</td>
|
||||
<% end %>
|
||||
|
||||
<td class="param-desc">
|
||||
<%= htmlify param.desc %>
|
||||
<% if param.enums.present? %>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<h4><%= YARD::Tags::Library.labels[:response_field] %>:</h4>
|
||||
<ul class="response_field">
|
||||
<% @response_fields.each do |field| %>
|
||||
<li>
|
||||
<span class='type'><%= format_types(field.types) %></span>
|
||||
<span class='name'><%= h field.name %></span>
|
||||
|
||||
<% if field.deprecated? %>
|
||||
<div class='response-field deprecated'>
|
||||
<strong>[DEPRECATED] This field is deprecated, effective <%= h field.effective_date %> (notice given <%= h field.notice_date %>):</strong>
|
||||
<div>
|
||||
<% end %>
|
||||
|
||||
<% if field.description.present? %>
|
||||
<%= htmlify_line(field.description) %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
|
@ -31,12 +31,22 @@ def request_field
|
|||
end
|
||||
|
||||
def response_field
|
||||
generic_tag :response_field
|
||||
return unless object.has_tag?(:response_field) || object.has_tag?(:deprecated_response_field)
|
||||
response_field_tags = object.tags.select { |tag| tag.tag_name == 'response_field' || tag.tag_name == 'deprecated_response_field' }
|
||||
@response_fields = response_field_tags.map do |tag|
|
||||
ResponseFieldView.new(tag)
|
||||
end
|
||||
|
||||
erb('response_fields')
|
||||
end
|
||||
|
||||
def argument
|
||||
return unless object.has_tag?(:argument)
|
||||
@request_parameters = object.tags(:argument).map { |t| ArgumentView.new(t.text) }
|
||||
return unless object.has_tag?(:argument) || object.has_tag?(:deprecated_argument)
|
||||
argument_tags = object.tags.select { |tag| tag.tag_name == 'argument' || tag.tag_name == 'deprecated_argument' }
|
||||
@request_parameters = argument_tags.map do |tag|
|
||||
ArgumentView.new(tag.text, deprecated: tag.tag_name == 'deprecated_argument')
|
||||
end
|
||||
|
||||
erb('request_parameters')
|
||||
end
|
||||
|
||||
|
|
|
@ -51,12 +51,22 @@ def indent(str, amount = 2, char = ' ')
|
|||
str.gsub(/^/, char * amount)
|
||||
end
|
||||
|
||||
def render_comment(string)
|
||||
if string
|
||||
indent(word_wrap(string), 1, '// ')
|
||||
else
|
||||
""
|
||||
end
|
||||
def deprecation_message(property)
|
||||
return '' if property.key?('properties') || !property['deprecated']
|
||||
|
||||
parse_swagger_model(property)
|
||||
indent_chars = '// '
|
||||
deprecation_title = "#{indent_chars}[DEPRECATED] This property is deprecated, effective #{property['deprecation_effective']} (notice given #{property['deprecation_notice']}):\n"
|
||||
deprecation_description = indent(word_wrap(property['deprecation_description'], 80 - indent_chars.length), 1, indent_chars)
|
||||
"#{deprecation_title}#{deprecation_description}"
|
||||
end
|
||||
|
||||
def render_comment(property)
|
||||
indent_chars = '// '
|
||||
description = property['description'] ? indent(word_wrap(property['description'], 80 - indent_chars.length), 1, indent_chars) : ''
|
||||
deprecation = deprecation_message(property)
|
||||
separator = description.present? && deprecation.present? ? "//\n" : ''
|
||||
"#{description}#{separator}#{deprecation}"
|
||||
end
|
||||
|
||||
def render_value(prop)
|
||||
|
@ -83,20 +93,32 @@ def render_value(prop)
|
|||
end
|
||||
|
||||
def render_properties(json)
|
||||
json = JSON.parse(json)
|
||||
if (properties = json['properties'])
|
||||
result = ''
|
||||
if json['description'].present?
|
||||
result << render_comment(json['description'])
|
||||
result << render_comment(json)
|
||||
end
|
||||
result << "{\n" + indent(
|
||||
properties.map do |name, prop|
|
||||
render_comment(prop['description']) +
|
||||
%{"#{name}": } + render_value(prop)
|
||||
end.join(",\n")) +
|
||||
"\n}"
|
||||
properties.map do |name, prop|
|
||||
render_comment(prop) +
|
||||
%{"#{name}": } + render_value(prop)
|
||||
end.join(",\n")
|
||||
) + "\n}"
|
||||
end
|
||||
rescue
|
||||
puts "error rendering properties for model:\n#{json}"
|
||||
raise
|
||||
end
|
||||
|
||||
def parse_swagger_model(model)
|
||||
@description_key = :deprecation_description
|
||||
@description = model['deprecation_description']
|
||||
validate_deprecation_description
|
||||
|
||||
@deprecated_date_key = :deprecation_notice
|
||||
@effective_date_key = :deprecation_effective
|
||||
|
||||
@deprecation_date = model['deprecation_notice']
|
||||
@effective_date = model['deprecation_effective']
|
||||
validate_deprecation_dates(deprecation_notice: @deprecation_date, deprecation_effective: @effective_date)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
<%= htmlify(@docstring.strip, :markdown) %>
|
||||
|
||||
<% @json_objects.each do |name, json| %>
|
||||
<% @json_objects.each do |name, unparsed_json| %>
|
||||
<% json = JSON.parse(unparsed_json) %>
|
||||
<% properties = render_properties(json) %>
|
||||
<div class='object_definition'>
|
||||
<h3><a name="<%= name %>"><%= name[0,1] =~ /[aeiou]/i ? "An" : "A" %> <%= name %> object looks like:</a></h3>
|
||||
<pre class="example code prettyprint"><code class="language-js"><%= h properties || json %></code></pre>
|
||||
<pre class="example code prettyprint"><code class="language-js"><%= h properties || unparsed_json %></code></pre>
|
||||
</div>
|
||||
<% if json['deprecated'] %>
|
||||
<% parse_swagger_model(json) %>
|
||||
<p class="note deprecated">
|
||||
<strong>[DEPRECATED] The <%= h name %> model is deprecated, effective <%= h json['deprecation_effective'] %> (notice given <%= h json['deprecation_notice'] %>):</strong><br/>
|
||||
<%= h json['deprecation_description'] %>
|
||||
</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -15,11 +15,16 @@
|
|||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/swagger_helper')
|
||||
require 'spec_helper'
|
||||
require_relative 'swagger_helper'
|
||||
require 'argument_view'
|
||||
|
||||
describe ArgumentView do
|
||||
it '#deprecated? returns false' do
|
||||
view = ArgumentView.new("foo [String]")
|
||||
expect(view).not_to be_deprecated
|
||||
end
|
||||
|
||||
context "type splitter" do
|
||||
let(:view) { ArgumentView.new "arg [String]" }
|
||||
|
||||
|
@ -51,10 +56,15 @@ describe ArgumentView do
|
|||
context "line parser" do
|
||||
let(:view) { ArgumentView.new "arg [String]" }
|
||||
|
||||
it "raises on missing param name" do
|
||||
it "raises on missing param name and missing type" do
|
||||
expect { view.parse_line("") }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
# This is probably not ideal — I'm just documenting existing behavior.
|
||||
it "does not raise on missing param name when type is present" do
|
||||
expect { view.parse_line("[String]") }.not_to raise_error
|
||||
end
|
||||
|
||||
it "parses without desc" do
|
||||
parsed = view.parse_line("arg [String]")
|
||||
expect(parsed).to eq ["arg [String]", "arg", "[String]", ArgumentView::DEFAULT_DESC]
|
||||
|
@ -97,4 +107,184 @@ describe ArgumentView do
|
|||
expect(view.required?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_swagger' do
|
||||
let(:view) { ArgumentView.new("foo [String]") }
|
||||
|
||||
it 'includes a "deprecated" key' do
|
||||
expect(view.to_swagger).to have_key 'deprecated'
|
||||
end
|
||||
|
||||
it 'returns false for "deprecated"' do
|
||||
expect(view.to_swagger.fetch('deprecated')).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'Deprecated ArgumentView' do
|
||||
let(:valid_text) { "foo [Boolean] NOTICE 2018-01-02 EFFECTIVE 2018-04-30\nA description \non multiple lines." }
|
||||
let(:view) { ArgumentView.new(valid_text, deprecated: true) }
|
||||
|
||||
it '#deprecated? returns true' do
|
||||
expect(view).to be_deprecated
|
||||
end
|
||||
|
||||
it '#to_swagger returns true for "deprecated"' do
|
||||
expect(view.to_swagger.fetch('deprecated')).to be true
|
||||
end
|
||||
|
||||
describe '#parse_line' do
|
||||
it 'parses the argument name' do
|
||||
argument_name = view.parse_line(valid_text).second
|
||||
expect(argument_name).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'parses the argument type' do
|
||||
argument_type = view.parse_line(valid_text).third
|
||||
expect(argument_type).to eq '[Boolean]'
|
||||
end
|
||||
|
||||
it 'parses the description' do
|
||||
argument_type = view.parse_line(valid_text).fourth
|
||||
expect(argument_type).to eq "A description \non multiple lines."
|
||||
end
|
||||
|
||||
it 'parses the effective deprecation date' do
|
||||
view.parse_line(valid_text)
|
||||
expect(view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date' do
|
||||
view.parse_line(valid_text)
|
||||
expect(view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
it 'parses the effective deprecation date when it comes before the notice date' do
|
||||
text = valid_text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
view.parse_line(text)
|
||||
expect(view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date when it comes after the effective date' do
|
||||
text = valid_text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
view.parse_line(text)
|
||||
expect(view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
# This is probably not ideal — I'm just documenting existing behavior.
|
||||
it 'uses the argument type as the name if name is not provided' do
|
||||
text = valid_text.gsub('foo ', '')
|
||||
view = ArgumentView.new(text, deprecated: true)
|
||||
argument_name = view.parse_line(text).second
|
||||
expect(argument_name).to eq '[Boolean]'
|
||||
end
|
||||
|
||||
context 'when a type is not provided' do
|
||||
let(:text) { valid_text.gsub('[Boolean] ', '') }
|
||||
let(:view) { ArgumentView.new(text, deprecated: true) }
|
||||
|
||||
it 'parses the argument name' do
|
||||
argument_name = view.parse_line(text).second
|
||||
expect(argument_name).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'uses String as the default type' do
|
||||
argument_type = view.parse_line(text).third
|
||||
expect(argument_type).to eq '[String]'
|
||||
end
|
||||
|
||||
it 'parses the description' do
|
||||
argument_type = view.parse_line(text).fourth
|
||||
expect(argument_type).to eq "A description \non multiple lines."
|
||||
end
|
||||
|
||||
it 'sets the effective deprecation date' do
|
||||
view.parse_line(text)
|
||||
expect(view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'sets the deprecation notice date' do
|
||||
view.parse_line(text)
|
||||
expect(view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
end
|
||||
|
||||
context 'validations' do
|
||||
it 'is invalid when the text "NOTICE" is omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('NOTICE ', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('2018-01-02 ', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected date .+ for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "NOTICE" and the NOTICE date are omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('NOTICE 2018-01-02 ', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is not in YYYY-MM-DD format' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('2018-01-02', '01-02-2018'), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected date `01-02-2018` for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" is omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('EFFECTIVE ', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('2018-04-30', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected a value to be present for argument `EFFECTIVE`, but it was blank./)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" and the EFFECTIVE date are omitted' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub(' EFFECTIVE 2018-04-30', ''), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is not in YYYY-MM-DD format' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('2018-04-30', '04-30-2018'), deprecated: true)
|
||||
}.to raise_error(ArgumentError, /Expected date `04-30-2018` for key `EFFECTIVE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is < 90 days after the NOTICE date' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub('2018-04-30', '2018-02-26'), deprecated: true)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected >= 90 days between the `NOTICE` \(2018-01-02\) and `EFFECTIVE` \(2018-02-26\) dates/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when a description is not provided' do
|
||||
expect {
|
||||
ArgumentView.new(valid_text.gsub("\nA description \non multiple lines.", ''), deprecated: true)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when the description is on the same line as the other content' do
|
||||
text = valid_text.gsub("\nA description \non multiple lines.", ' A description.')
|
||||
expect {
|
||||
ArgumentView.new(text, deprecated: true)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require_relative '../../spec_helper'
|
||||
require_relative 'swagger_helper'
|
||||
require 'deprecated_method_view'
|
||||
|
||||
describe DeprecatedMethodView do
|
||||
let(:valid_text) { "foo [Boolean] NOTICE 2018-01-02 EFFECTIVE 2018-04-30\nA description \non multiple lines." }
|
||||
|
||||
it 'parses the effective deprecation date' do
|
||||
view = DeprecatedMethodView.new(double(text: valid_text))
|
||||
expect(view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date' do
|
||||
view = DeprecatedMethodView.new(double(text: valid_text))
|
||||
expect(view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
it 'parses the description' do
|
||||
view = DeprecatedMethodView.new(double(text: valid_text))
|
||||
expect(view.description).to eq "A description \non multiple lines."
|
||||
end
|
||||
|
||||
it 'parses the effective deprecation date when it comes before the notice date' do
|
||||
text = valid_text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
view = DeprecatedMethodView.new(double(text: text))
|
||||
expect(view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date when it comes after the effective date' do
|
||||
text = valid_text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
view = DeprecatedMethodView.new(double(text: text))
|
||||
expect(view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
context 'validations' do
|
||||
it 'is invalid when the text "NOTICE" is omitted' do
|
||||
text = valid_text.gsub('NOTICE ', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is omitted' do
|
||||
text = valid_text.gsub('2018-01-02 ', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected date .+ for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "NOTICE" and the NOTICE date are omitted' do
|
||||
text = valid_text.gsub('NOTICE 2018-01-02 ', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is not in YYYY-MM-DD format' do
|
||||
text = valid_text.gsub('2018-01-02', '01-02-2018')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected date `01-02-2018` for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" is omitted' do
|
||||
text = valid_text.gsub('EFFECTIVE ', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is omitted' do
|
||||
text = valid_text.gsub('2018-04-30', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected a value to be present for argument `EFFECTIVE`, but it was blank./)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" and the EFFECTIVE date are omitted' do
|
||||
text = valid_text.gsub(' EFFECTIVE 2018-04-30', '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is not in YYYY-MM-DD format' do
|
||||
text = valid_text.gsub('2018-04-30', '04-30-2018')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(ArgumentError, /Expected date `04-30-2018` for key `EFFECTIVE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is < 90 days after the NOTICE date' do
|
||||
text = valid_text.gsub('2018-04-30', '2018-02-26')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected >= 90 days between the `NOTICE` \(2018-01-02\) and `EFFECTIVE` \(2018-02-26\) dates/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when a description is not provided' do
|
||||
text = valid_text.gsub("\nA description \non multiple lines.", '')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when the description is on the same line as the other content' do
|
||||
text = valid_text.gsub("\nA description \non multiple lines.", ' A description.')
|
||||
expect {
|
||||
DeprecatedMethodView.new(double(text: text))
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,103 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require_relative '../../spec_helper'
|
||||
require_relative 'swagger_helper'
|
||||
require 'method_view'
|
||||
|
||||
describe MethodView do
|
||||
let(:argument_tag) do
|
||||
text = "foo [String]\nA description."
|
||||
double(tag_name: 'argument', text: text)
|
||||
end
|
||||
|
||||
let(:deprecated_argument_tag) do
|
||||
text = "foo NOTICE 2018-01-05 EFFECTIVE 2018-05-05\nA description."
|
||||
double(tag_name: 'deprecated_argument', text: text)
|
||||
end
|
||||
|
||||
let(:response_field_tag) do
|
||||
double(tag_name: 'response_field', text: 'bar A description.')
|
||||
end
|
||||
|
||||
let(:deprecated_response_field_tag) do
|
||||
double(tag_name: 'deprecated_response_field', text: "baz NOTICE 2018-01-05 EFFECTIVE 2018-05-05\nA description.")
|
||||
end
|
||||
|
||||
let(:deprecated_method_tag) do
|
||||
text = "NOTICE 2018-01-05 EFFECTIVE 2018-05-05\nA description."
|
||||
double(tag_name: 'deprecated_method', text: text)
|
||||
end
|
||||
|
||||
describe '#deprecated?' do
|
||||
it 'returns true when there is a deprecated method tag' do
|
||||
view = MethodView.new(double(tags: [argument_tag, deprecated_method_tag]))
|
||||
expect(view).to be_deprecated
|
||||
end
|
||||
|
||||
it 'returns false when there is not a deprecated method tag' do
|
||||
view = MethodView.new(double(tags: [argument_tag]))
|
||||
expect(view).not_to be_deprecated
|
||||
end
|
||||
end
|
||||
|
||||
describe '#deprecation_description' do
|
||||
it 'returns an empty string when there is not a deprecated method tag' do
|
||||
view = MethodView.new(double(tags: [argument_tag]))
|
||||
expect(view.deprecation_description).to eq ''
|
||||
end
|
||||
|
||||
it 'returns the deprecation description when there is a deprecated method tag' do
|
||||
view = MethodView.new(double(tags: [argument_tag, deprecated_method_tag]))
|
||||
expect(view.deprecation_description).to eq 'A description.'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#raw_arguments' do
|
||||
it 'excludes tags that are not arguments' do
|
||||
view = MethodView.new(double(tags: [response_field_tag]))
|
||||
expect(view.raw_arguments).not_to include response_field_tag
|
||||
end
|
||||
|
||||
it 'includes argument tags' do
|
||||
view = MethodView.new(double(tags: [argument_tag]))
|
||||
expect(view.raw_arguments).to include argument_tag
|
||||
end
|
||||
|
||||
it 'includes deprecated argument tags' do
|
||||
view = MethodView.new(double(tags: [deprecated_argument_tag]))
|
||||
expect(view.raw_arguments).to include deprecated_argument_tag
|
||||
end
|
||||
end
|
||||
|
||||
describe '#raw_response_fields' do
|
||||
it 'excludes tags that are not response fields' do
|
||||
view = MethodView.new(double(tags: [argument_tag]))
|
||||
expect(view.raw_response_fields).not_to include argument_tag
|
||||
end
|
||||
|
||||
it 'includes response_field tags' do
|
||||
view = MethodView.new(double(tags: [response_field_tag]))
|
||||
expect(view.raw_response_fields).to include response_field_tag
|
||||
end
|
||||
|
||||
it 'includes deprecated response_field tags' do
|
||||
view = MethodView.new(double(tags: [deprecated_response_field_tag]))
|
||||
expect(view.raw_response_fields).to include deprecated_response_field_tag
|
||||
end
|
||||
end
|
||||
end
|
|
@ -20,13 +20,29 @@ require File.expand_path(File.dirname(__FILE__) + '/swagger_helper')
|
|||
require 'model_view'
|
||||
|
||||
describe ModelView do
|
||||
let(:text) { "Example\n{ \"properties\": [] }" }
|
||||
let(:text) do
|
||||
"Example\n{\n \"properties\": [],\n \"deprecated\": true,\n \"deprecation_description\": \"A description.\" }"
|
||||
end
|
||||
|
||||
let(:model) { double('Model', :text => text) }
|
||||
|
||||
it "is created from model" do
|
||||
view = ModelView.new_from_model(model)
|
||||
expect(view.name).to eq "Example"
|
||||
expect(view.properties).to eq []
|
||||
describe '.new_from_model' do
|
||||
it "is created from model" do
|
||||
view = ModelView.new_from_model(model)
|
||||
expect(view.name).to eq "Example"
|
||||
expect(view.properties).to eq []
|
||||
end
|
||||
|
||||
it 'parses the deprecated attribute' do
|
||||
view = ModelView.new_from_model(model)
|
||||
expect(view).to be_deprecated
|
||||
end
|
||||
|
||||
it 'parses the deprecation description' do
|
||||
view = ModelView.new_from_model(model)
|
||||
description = view.json_schema.dig('Example', 'deprecation_description')
|
||||
expect(description).to eq 'A description.'
|
||||
end
|
||||
end
|
||||
|
||||
it "generates a schema" do
|
||||
|
@ -40,8 +56,32 @@ describe ModelView do
|
|||
}
|
||||
},
|
||||
"description" => "",
|
||||
"required" => []
|
||||
"required" => [],
|
||||
"deprecated" => false,
|
||||
"deprecation_description" => ""
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
describe '#deprecated?' do
|
||||
let(:properties) do
|
||||
{
|
||||
"foo" => {
|
||||
"description" => "A description of the property.",
|
||||
"example" => "bar",
|
||||
"type" => "string"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns true if the model is deprecated' do
|
||||
view = ModelView.new('Foo', properties, deprecated: true, deprecation_description: 'A description.')
|
||||
expect(view).to be_deprecated
|
||||
end
|
||||
|
||||
it 'returns false if the model is not deprecated' do
|
||||
view = ModelView.new('Foo', properties)
|
||||
expect(view).not_to be_deprecated
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require_relative '../../spec_helper'
|
||||
require_relative 'swagger_helper'
|
||||
require 'response_field_view'
|
||||
|
||||
describe ResponseFieldView do
|
||||
let(:tag) do
|
||||
double(tag_name: 'response_field', text: 'foo A description.', types: ['String'])
|
||||
end
|
||||
|
||||
let(:view) { ResponseFieldView.new(tag) }
|
||||
|
||||
it '#deprecated? returns false' do
|
||||
expect(view).not_to be_deprecated
|
||||
end
|
||||
|
||||
it 'sets types' do
|
||||
expect(view.types).to eq tag.types
|
||||
end
|
||||
|
||||
describe '#to_swagger' do
|
||||
it 'includes "name"' do
|
||||
expect(view.to_swagger.fetch('name')).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'includes "description"' do
|
||||
expect(view.to_swagger.fetch('description')).to eq 'A description.'
|
||||
end
|
||||
|
||||
it 'includes "deprecated"' do
|
||||
expect(view.to_swagger.fetch('deprecated')).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'line parser' do
|
||||
it 'raises on missing param name and missing description' do
|
||||
expect { view.parse_line('') }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'raises on missing description' do
|
||||
expect {
|
||||
view.parse_line('foo')
|
||||
}.to raise_error(ArgumentError, /Expected a description to be present, but it was not provided./)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the name' do
|
||||
expect(view.name).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'forces the encoding of the name to UTF-8' do
|
||||
response_field_view = ResponseFieldView.new(
|
||||
double(
|
||||
tag_name: 'response_field',
|
||||
text: 'foo A description.'.force_encoding('binary'),
|
||||
types: ['String']
|
||||
)
|
||||
)
|
||||
|
||||
expect(response_field_view.name.encoding.name).to eq 'UTF-8'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the description' do
|
||||
expect(view.description).to eq 'A description.'
|
||||
end
|
||||
|
||||
it 'forces the encoding of the description to UTF-8' do
|
||||
response_field_view = ResponseFieldView.new(
|
||||
double(
|
||||
tag_name: 'response_field',
|
||||
text: 'foo A description.'.force_encoding('binary'),
|
||||
types: ['String']
|
||||
)
|
||||
)
|
||||
|
||||
expect(response_field_view.description.encoding.name).to eq 'UTF-8'
|
||||
end
|
||||
end
|
||||
|
||||
context 'Deprecated ResponseFieldView' do
|
||||
let(:deprecated_tag) do
|
||||
double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: "foo NOTICE 2018-01-02 EFFECTIVE 2018-04-30\nA description \non multiple lines.",
|
||||
types: ['String']
|
||||
)
|
||||
end
|
||||
|
||||
let(:deprecated_view) { ResponseFieldView.new(deprecated_tag) }
|
||||
|
||||
it '#deprecated? returns true' do
|
||||
expect(deprecated_view).to be_deprecated
|
||||
end
|
||||
|
||||
it '#to_swagger returns true for "deprecated"' do
|
||||
expect(deprecated_view.to_swagger.fetch('deprecated')).to be true
|
||||
end
|
||||
|
||||
describe '#parse_line' do
|
||||
it 'parses the argument name' do
|
||||
argument_name = deprecated_view.parse_line(deprecated_tag.text).first
|
||||
expect(argument_name).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'parses the description' do
|
||||
argument_type = deprecated_view.parse_line(deprecated_tag.text).second
|
||||
expect(argument_type).to eq "A description \non multiple lines."
|
||||
end
|
||||
|
||||
it 'parses the effective deprecation date' do
|
||||
deprecated_view.parse_line(deprecated_tag.text)
|
||||
expect(deprecated_view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date' do
|
||||
deprecated_view.parse_line(deprecated_tag.text)
|
||||
expect(deprecated_view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
it 'parses the effective deprecation date when it comes before the notice date' do
|
||||
text = deprecated_tag.text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
deprecated_view.parse_line(text)
|
||||
expect(deprecated_view.effective_date).to eq '2018-04-30'
|
||||
end
|
||||
|
||||
it 'parses the deprecation notice date when it comes after the effective date' do
|
||||
text = deprecated_tag.text.gsub('NOTICE 2018-01-02 EFFECTIVE 2018-04-30', 'EFFECTIVE 2018-04-30 NOTICE 2018-01-02')
|
||||
deprecated_view.parse_line(text)
|
||||
expect(deprecated_view.notice_date).to eq '2018-01-02'
|
||||
end
|
||||
|
||||
context 'validations' do
|
||||
it 'is invalid when the text "NOTICE" is omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('NOTICE ', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('2018-01-02 ', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected date .+ for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "NOTICE" and the NOTICE date are omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('NOTICE 2018-01-02 ', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected argument `NOTICE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the NOTICE date is not in YYYY-MM-DD format' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('2018-01-02', '01-02-2018'),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected date `01-02-2018` for key `NOTICE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" is omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('EFFECTIVE ', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('2018-04-30', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected a value to be present for argument `EFFECTIVE`, but it was blank./)
|
||||
end
|
||||
|
||||
it 'is invalid when the text "EFFECTIVE" and the EFFECTIVE date are omitted' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub(' EFFECTIVE 2018-04-30', ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected argument `EFFECTIVE`/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is not in YYYY-MM-DD format' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('2018-04-30', '04-30-2018'),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(ArgumentError, /Expected date `04-30-2018` for key `EFFECTIVE` to be in ISO 8601 format/)
|
||||
end
|
||||
|
||||
it 'is invalid when the EFFECTIVE date is < 90 days after the NOTICE date' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub('2018-04-30', '2018-02-26'),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected >= 90 days between the `NOTICE` \(2018-01-02\) and `EFFECTIVE` \(2018-02-26\) dates/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when a description is not provided' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub("\nA description \non multiple lines.", ''),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
|
||||
it 'is invalid when the description is on the same line as the other content' do
|
||||
tag = double(
|
||||
tag_name: 'deprecated_response_field',
|
||||
text: deprecated_tag.text.gsub("\nA description \non multiple lines.", ' A description.'),
|
||||
types: ['String']
|
||||
)
|
||||
expect {
|
||||
ResponseFieldView.new(tag)
|
||||
}.to raise_error(
|
||||
ArgumentError,
|
||||
/Expected two lines: a tag declaration line with deprecation arguments, and a description line/
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require_relative '../../spec_helper'
|
||||
require_relative 'swagger_helper'
|
||||
require 'argument_view'
|
||||
require 'route_view'
|
||||
require 'response_field_view'
|
||||
|
||||
describe RouteView do
|
||||
let(:raw_route) do
|
||||
double(verb: 'GET', path: double(spec: 'foo'))
|
||||
end
|
||||
|
||||
describe '#query_args' do
|
||||
let(:argument_tag) do
|
||||
text = "foo [String]\nA description."
|
||||
double(tag_name: 'argument', text: text)
|
||||
end
|
||||
|
||||
let(:deprecated_argument_tag) do
|
||||
text = "foo NOTICE 2018-01-05 EFFECTIVE 2018-05-05\nA description."
|
||||
double(tag_name: 'deprecated_argument', text: text)
|
||||
end
|
||||
|
||||
it 'argument views it returns respond with false to deprecated?' do
|
||||
view = RouteView.new(raw_route, double(raw_arguments: [argument_tag]))
|
||||
expect(view.query_args.first).not_to be_deprecated
|
||||
end
|
||||
|
||||
it 'deprecated argument views it returns respond with true to deprecated?' do
|
||||
view = RouteView.new(raw_route, double(raw_arguments: [deprecated_argument_tag]))
|
||||
expect(view.query_args.first).to be_deprecated
|
||||
end
|
||||
end
|
||||
|
||||
describe '#response_fields' do
|
||||
let(:response_field_tag) do
|
||||
double(tag_name: 'response_field', text: 'bar A description.', types: ['String'])
|
||||
end
|
||||
|
||||
let(:deprecated_response_field_tag) do
|
||||
text = "baz NOTICE 2018-01-05 EFFECTIVE 2018-05-05\nA description."
|
||||
double(tag_name: 'deprecated_response_field', text: text, types: ['String'])
|
||||
end
|
||||
|
||||
it 'returns response fields' do
|
||||
view = RouteView.new(raw_route, double(raw_response_fields: [response_field_tag]))
|
||||
field = view.response_fields.first
|
||||
expect(field).to eq({ "name" => "bar", "description" => "A description.", "deprecated" => false })
|
||||
end
|
||||
|
||||
it 'returns deprecated response fields' do
|
||||
view = RouteView.new(raw_route, double(raw_response_fields: [deprecated_response_field_tag]))
|
||||
field = view.response_fields.first
|
||||
expect(field).to eq({ "name" => "baz", "description" => "A description.", "deprecated" => true })
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue