Skip to content

Commit 6f3ac88

Browse files
authored
Merge branch 'master' into feat-interited-entity-name
2 parents e2aa8ea + e86c9ba commit 6f3ac88

File tree

12 files changed

+270
-30
lines changed

12 files changed

+270
-30
lines changed

.rubocop.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ AllCops:
1111
Layout/EmptyLinesAroundArguments:
1212
Enabled: false
1313

14+
Layout/EmptyLinesAroundAttributeAccessor:
15+
Enabled: true
16+
1417
Layout/FirstHashElementIndentation:
1518
EnforcedStyle: consistent
1619

@@ -24,6 +27,12 @@ Layout/SpaceAroundMethodCallOperator:
2427

2528
# Lint stuff
2629
#
30+
Lint/DeprecatedOpenSSLConstant:
31+
Enabled: true
32+
33+
Lint/MixedRegexpCaptureTypes:
34+
Enabled: true
35+
2736
Lint/RaiseException:
2837
Enabled: true
2938

@@ -39,6 +48,9 @@ Metrics/BlockLength:
3948
Metrics/ClassLength:
4049
Max: 300
4150

51+
Metrics/CyclomaticComplexity:
52+
Max: 17
53+
4254
Metrics/MethodLength:
4355
Exclude:
4456
- spec/**/*
@@ -64,3 +76,15 @@ Style/HashTransformValues:
6476

6577
Style/RegexpLiteral:
6678
Enabled: false
79+
80+
Style/RedundantFetchBlock:
81+
Enabled: true
82+
83+
Style/RedundantRegexpCharacterClass:
84+
Enabled: true
85+
86+
Style/RedundantRegexpEscape:
87+
Enabled: true
88+
89+
Style/SlicingWithRange:
90+
Enabled: false

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@ jobs:
3333
- rvm: 2.4.10
3434
- rvm: ruby-head
3535
- rvm: jruby-head
36+
37+
- env: GRAPE_VERSION=HEAD

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
* [#794](https://github.com/ruby-grape/grape-swagger/pull/794): Allow entity_name to be inherited, fixes #659 - [@urkle](https://githubcom/urkle).
66
* Your contribution here.
7+
* [#793](https://github.com/ruby-grape/grape-swagger/pull/793): Features/inheritance and discriminator - [@MaximeRDY](https://github.com/MaximeRDY).
78

89
#### Fixes
910

1011
* Your contribution here.
12+
* [#796](https://github.com/ruby-grape/grape-swagger/pull/796): Support grape 1.4.0 - [@thedanielhanke](https://github.com/thedanielhanke).
1113

1214

1315
### 1.1.0 (April 20, 2020)

Gemfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ gem 'grape', case version = ENV['GRAPE_VERSION'] || '>= 1.3.0'
1414
end
1515

1616
gem ENV['MODEL_PARSER'] if ENV.key?('MODEL_PARSER')
17+
1718
group :development, :test do
1819
gem 'bundler'
1920
gem 'grape-entity'
@@ -26,12 +27,16 @@ group :development, :test do
2627
gem 'rake'
2728
gem 'rdoc'
2829
gem 'rspec', '~> 3.9'
29-
gem 'rubocop', '~> 0.82', require: false
30+
gem 'rubocop', '~> 0.85', require: false
3031
end
3132

3233
group :test do
3334
gem 'coveralls_reborn', require: false
34-
gem 'grape-swagger-entity'
35+
3536
gem 'ruby-grape-danger', '~> 0.1.1', require: false
3637
gem 'simplecov', require: false
38+
39+
unless ENV['MODEL_PARSER'] == 'grape-swagger-entity'
40+
gem 'grape-swagger-entity', git: 'https://github.com/ruby-grape/grape-swagger-entity'
41+
end
3742
end

README.md

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ This screenshot is based on the [Hussars](https://github.com/LeFnord/hussars) sa
4444
The following versions of grape, grape-entity and grape-swagger can currently be used together.
4545

4646
| grape-swagger | swagger spec | grape | grape-entity | representable |
47-
|---------------|--------------|-------------------------|--------------|---------------|
48-
| 0.10.5 | 1.2 | >= 0.10.0 ... <= 0.14.0 | < 0.5.0 | n/a |
49-
| 0.11.0 | 1.2 | >= 0.16.2 | < 0.5.0 | n/a |
50-
| 0.25.2 | 2.0 | >= 0.14.0 ... <= 0.18.0 | <= 0.6.0 | >= 2.4.1 |
51-
| 0.26.0 | 2.0 | >= 0.16.2 ... <= 1.1.0 | <= 0.6.1 | >= 2.4.1 |
52-
| 0.27.0 | 2.0 | >= 0.16.2 ... <= 1.1.0 | >= 0.5.0 | >= 2.4.1 |
53-
| 0.32.0 | 2.0 | >= 0.16.2 | >= 0.5.0 | >= 2.4.1 |
54-
| 0.34.0 | 2.0 | >= 0.16.2 ... < 1.3.0 | >= 0.5.0 | >= 2.4.1 |
55-
| >= 1.0.0 | 2.0 | >= 1.3.0 | >= 0.5.0 | >= 2.4.1 |
47+
| ------------- | ------------ | ----------------------- | ------------ | ------------- |
48+
| 0.10.5 | 1.2 | >= 0.10.0 ... <= 0.14.0 | < 0.5.0 | n/a |
49+
| 0.11.0 | 1.2 | >= 0.16.2 | < 0.5.0 | n/a |
50+
| 0.25.2 | 2.0 | >= 0.14.0 ... <= 0.18.0 | <= 0.6.0 | >= 2.4.1 |
51+
| 0.26.0 | 2.0 | >= 0.16.2 ... <= 1.1.0 | <= 0.6.1 | >= 2.4.1 |
52+
| 0.27.0 | 2.0 | >= 0.16.2 ... <= 1.1.0 | >= 0.5.0 | >= 2.4.1 |
53+
| 0.32.0 | 2.0 | >= 0.16.2 | >= 0.5.0 | >= 2.4.1 |
54+
| 0.34.0 | 2.0 | >= 0.16.2 ... < 1.3.0 | >= 0.5.0 | >= 2.4.1 |
55+
| >= 1.0.0 | 2.0 | >= 1.3.0 | >= 0.5.0 | >= 2.4.1 |
5656

5757

5858
## Swagger-Spec <a name="swagger-spec"></a>
@@ -1381,6 +1381,94 @@ module API
13811381
end
13821382
```
13831383

1384+
#### Inheritance with allOf and discriminator
1385+
```ruby
1386+
module Entities
1387+
class Pet < Grape::Entity
1388+
expose :type, documentation: {
1389+
type: 'string',
1390+
is_discriminator: true,
1391+
required: true
1392+
}
1393+
expose :name, documentation: {
1394+
type: 'string',
1395+
required: true
1396+
}
1397+
end
1398+
1399+
class Cat < Pet
1400+
expose :huntingSkill, documentation: {
1401+
type: 'string',
1402+
description: 'The measured skill for hunting',
1403+
default: 'lazy',
1404+
values: %w[
1405+
clueless
1406+
lazy
1407+
adventurous
1408+
aggressive
1409+
]
1410+
}
1411+
end
1412+
end
1413+
```
1414+
1415+
Should generate this definitions:
1416+
```JSON
1417+
{
1418+
"definitions": {
1419+
"Pet": {
1420+
"type": "object",
1421+
"discriminator": "petType",
1422+
"properties": {
1423+
"name": {
1424+
"type": "string"
1425+
},
1426+
"petType": {
1427+
"type": "string"
1428+
}
1429+
},
1430+
"required": [
1431+
"name",
1432+
"petType"
1433+
]
1434+
},
1435+
"Cat": {
1436+
"description": "A representation of a cat",
1437+
"allOf": [
1438+
{
1439+
"$ref": "#/definitions/Pet"
1440+
},
1441+
{
1442+
"type": "object",
1443+
"properties": {
1444+
"huntingSkill": {
1445+
"type": "string",
1446+
"description": "The measured skill for hunting",
1447+
"default": "lazy",
1448+
"enum": [
1449+
"clueless",
1450+
"lazy",
1451+
"adventurous",
1452+
"aggressive"
1453+
]
1454+
},
1455+
"petType": {
1456+
"type": "string",
1457+
"enum": ["Cat"]
1458+
}
1459+
},
1460+
"required": [
1461+
"huntingSkill",
1462+
"petType"
1463+
]
1464+
}
1465+
]
1466+
}
1467+
}
1468+
}
1469+
```
1470+
1471+
13841472

13851473

13861474
## Securing the Swagger UI <a name="oauth"></a>

grape-swagger.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
1414
s.license = 'MIT'
1515

1616
s.required_ruby_version = '>= 2.4'
17-
s.add_runtime_dependency 'grape', '~> 1.3.0'
17+
s.add_runtime_dependency 'grape', '~> 1.3'
1818

1919
s.files = `git ls-files`.split("\n")
2020
s.test_files = `git ls-files -- {test,spec}/*`.split("\n")

lib/grape-swagger.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ def route_path_start_with?(route, name)
109109
module SwaggerDocumentationAdder
110110
attr_accessor :combined_namespaces, :combined_namespace_identifiers
111111
attr_accessor :combined_routes, :combined_namespace_routes
112+
112113
include SwaggerRouting
113114

114115
def add_swagger_documentation(options = {})

lib/grape-swagger/doc_methods/build_model_definition.rb

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ module GrapeSwagger
44
module DocMethods
55
class BuildModelDefinition
66
class << self
7-
def build(model, properties, required)
8-
definition = { type: 'object', properties: properties }
7+
def build(model, properties, required, other_def_properties = {})
8+
definition = { type: 'object', properties: properties }.merge(other_def_properties)
99

1010
if required.nil?
1111
required_attrs = required_attributes(model)
@@ -17,6 +17,57 @@ def build(model, properties, required)
1717
definition
1818
end
1919

20+
def parse_params_from_model(parsed_response, model, model_name)
21+
if parsed_response.is_a?(Hash) && parsed_response.keys.first == :allOf
22+
refs_or_models = parsed_response[:allOf]
23+
parsed = parse_refs_and_models(refs_or_models, model)
24+
25+
{
26+
allOf: parsed
27+
}
28+
else
29+
properties, required = parsed_response
30+
unless properties&.any?
31+
raise GrapeSwagger::Errors::SwaggerSpec,
32+
"Empty model #{model_name}, swagger 2.0 doesn't support empty definitions."
33+
end
34+
properties, other_def_properties = parse_properties(properties)
35+
36+
build(
37+
model, properties, required, other_def_properties
38+
)
39+
end
40+
end
41+
42+
def parse_properties(properties)
43+
other_properties = {}
44+
45+
discriminator_key, discriminator_value =
46+
properties.find do |_key, value|
47+
value[:documentation].try(:[], :is_discriminator)
48+
end
49+
50+
if discriminator_key
51+
discriminator_value.delete(:documentation)
52+
properties[discriminator_key] = discriminator_value
53+
54+
other_properties[:discriminator] = discriminator_key
55+
end
56+
57+
[properties, other_properties]
58+
end
59+
60+
def parse_refs_and_models(refs_or_models, model)
61+
refs_or_models.map do |ref_or_models|
62+
if ref_or_models.is_a?(Hash) && ref_or_models.keys.first == '$ref'
63+
ref_or_models
64+
else
65+
properties, required = ref_or_models
66+
GrapeSwagger::DocMethods::BuildModelDefinition.build(model, properties, required)
67+
end
68+
end
69+
end
70+
2071
private
2172

2273
def required_attributes(model)

lib/grape-swagger/doc_methods/operation_id.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ def build(route, path = nil)
1616

1717
def manipulate(path)
1818
operation = path.split('/').map(&:capitalize).join
19-
operation.gsub!(/\-(\w)/, &:upcase).delete!('-') if operation[/\-(\w)/]
20-
operation.gsub!(/\_(\w)/, &:upcase).delete!('_') if operation.include?('_')
19+
operation.gsub!(/-(\w)/, &:upcase).delete!('-') if operation[/-(\w)/]
20+
operation.gsub!(/_(\w)/, &:upcase).delete!('_') if operation.include?('_')
2121
operation.gsub!(/\.(\w)/, &:upcase).delete!('.') if operation[/\.(\w)/]
2222
if path.include?('{')
2323
operation.gsub!(/\{(\w)/, &:upcase)

lib/grape-swagger/doc_methods/parse_params.rb

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ def document_array_param(value_type, definitions)
7777

7878
param_type ||= value_type[:param_type]
7979

80+
array_items = parse_array_item(
81+
definitions,
82+
type,
83+
value_type
84+
)
85+
86+
@parsed_param[:in] = param_type || 'formData'
87+
@parsed_param[:items] = array_items
88+
@parsed_param[:type] = 'array'
89+
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
90+
end
91+
92+
def parse_array_item(definitions, type, value_type)
8093
array_items = {}
8194
if definitions[value_type[:data_type]]
8295
array_items['$ref'] = "#/definitions/#{@parsed_param[:type]}"
@@ -91,10 +104,7 @@ def document_array_param(value_type, definitions)
91104

92105
array_items[:default] = value_type[:default] if value_type[:default].present?
93106

94-
@parsed_param[:in] = param_type || 'formData'
95-
@parsed_param[:items] = array_items
96-
@parsed_param[:type] = 'array'
97-
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
107+
array_items
98108
end
99109

100110
def document_additional_properties(settings)

lib/grape-swagger/endpoint.rb

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,7 @@ def params_object(route, options, path)
196196
end
197197

198198
def response_object(route, options)
199-
codes = http_codes_from_route(route)
200-
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x }
201-
202-
codes.each_with_object({}) do |value, memo|
199+
codes(route).each_with_object({}) do |value, memo|
203200
value[:message] ||= ''
204201
memo[value[:code]] = { description: value[:message] }
205202

@@ -225,6 +222,12 @@ def response_object(route, options)
225222
end
226223
end
227224

225+
def codes(route)
226+
http_codes_from_route(route).map do |x|
227+
x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x
228+
end
229+
end
230+
228231
def success_code?(code)
229232
status = code.is_a?(Array) ? code.first : code[:code]
230233
status.between?(200, 299)
@@ -340,12 +343,10 @@ def expose_params_from_model(model)
340343
parser = GrapeSwagger.model_parsers.find(model)
341344
raise GrapeSwagger::Errors::UnregisteredParser, "No parser registered for #{model_name}." unless parser
342345

343-
properties, required = parser.new(model, self).call
344-
unless properties&.any?
345-
raise GrapeSwagger::Errors::SwaggerSpec,
346-
"Empty model #{model_name}, swagger 2.0 doesn't support empty definitions."
347-
end
348-
@definitions[model_name] = GrapeSwagger::DocMethods::BuildModelDefinition.build(model, properties, required)
346+
parsed_response = parser.new(model, self).call
347+
348+
@definitions[model_name] =
349+
GrapeSwagger::DocMethods::BuildModelDefinition.parse_params_from_model(parsed_response, model, model_name)
349350

350351
model_name
351352
end

0 commit comments

Comments
 (0)