zero-rails_openapi 1.4.3 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fefcfd0fc562daad7532e1dadd0121e8c30c0adb
4
- data.tar.gz: 25cf51020674fce5fb428f6b121b6c6a25c02c72
3
+ metadata.gz: 8973e94b7dd3112572e08cbf838ed9d5288ae092
4
+ data.tar.gz: a89c1d354004e40c6441c0ede06b848111a5c8bb
5
5
  SHA512:
6
- metadata.gz: 77306d030cba3bfbcb7f6d31eaac31c9ed7dd60355a012166a040633cd6420ebe898b483dcef1fae571da47fcb64871489da7c91069014246dd788e78c2e0815
7
- data.tar.gz: 5ad12c05afbf059b177bc1e797e401f49595d7be696e386f89b6e1f945daa511ebc2919c2564b4439e07c0951147682c3ee116efc0f9de4708f845e8e06327b8
6
+ metadata.gz: 170477a27cca4298664b2d95a7ac65879b79bcbd64ab42f23aaa917b0c45f61506e54c7d5027d9503ae96a04a031f0de34c1dc21cf0ad96ffd5962d98ec9916f
7
+ data.tar.gz: 532e6c8c37abdcd5e7d00c5f10cdedc5ceab6c2e187760a636c1dfda9b4d5b71b9aa5b6ac5d85cfca69c7b8fd3aa21de3a2ff0c2170e790104993a1317320b17
data/.gitignore CHANGED
@@ -9,5 +9,6 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ coverage
12
13
 
13
14
  .idea/*
data/.travis.yml CHANGED
@@ -1,5 +1,16 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4.1
4
+ - 2.4.0
5
5
  before_install: gem install bundler -v 1.16.0.pre.2
6
+ env:
7
+ global:
8
+ - CC_TEST_REPORTER_ID=fd0a238819079b92c19e99f5f4d6dcc8a5b5b2baf087fceb3723837604b5b0e9
9
+ before_script:
10
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
11
+ - chmod +x ./cc-test-reporter
12
+ - ./cc-test-reporter before-build
13
+ script:
14
+ - bundle exec rspec
15
+ after_script:
16
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Version Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [1.5.1 - 100% Test Coverage] - 2017/12/21 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.4.3...v1.5.0)
6
+
7
+ ### Completed the test code (250+ examples), and make it 100% coverage.
8
+
9
+ ### Feature
10
+
11
+ 1. `type: [String, Integer ..]` will generate an array, which's items
12
+ would be a oneOf combined schema.
13
+
14
+ ### Fixed:
15
+
16
+ 1. `desc` will override dry's.
17
+ 2. `type: something` is passed to `schema_hash`, but not `type`.
18
+ 3. Should not `skip` the params inside block.
19
+ 4. `body_ref` invalid.
20
+ 5. schema `length`'s order is reversed.
21
+ 6. Example Obj ref.
22
+
23
+ ### Added:
24
+
25
+ 1. Use `simplecov`.
26
+ 2. CodeClimate test hook.
27
+ 3. Test's support.
28
+ 4. Designed RSpec matchers `have_keys` and `have_size`.
29
+ 5. Designed a set of RSpec's DSL (DSSL) for testing.
30
+
31
+ ### Changed:
32
+
33
+ 1. WILL NOT do `recognize_is_options_in`.
34
+ 2. `instance_eval` => `instance_exec` in dsl.rb.
35
+ 3. Guard Clause for `generate_docs` and where schema could be defined.
36
+ 4. Change signature of `server` in `api`.
37
+ 5. Simplify `recursive`s.
38
+ 6. `enum: { 'desc' => :enum1 }` => `enum!: { 'desc' => :enum1 }`
39
+
3
40
  ## [1.4.2 & 1.4.3] - 2017/12/11&13 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.4.1...v1.4.3)
4
41
 
5
42
  ### Feature
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zero-rails_openapi (1.4.3)
4
+ zero-rails_openapi (1.5.1)
5
5
  activesupport (>= 3)
6
6
  rails (>= 3)
7
7
 
@@ -50,20 +50,20 @@ GEM
50
50
  concurrent-ruby (1.0.5)
51
51
  crass (1.0.3)
52
52
  diff-lcs (1.3)
53
+ docile (1.1.5)
53
54
  erubi (1.7.0)
54
55
  globalid (0.4.1)
55
56
  activesupport (>= 4.2.0)
56
57
  i18n (0.9.1)
57
58
  concurrent-ruby (~> 1.0)
59
+ json (2.1.0)
58
60
  loofah (2.1.1)
59
61
  crass (~> 1.0.2)
60
62
  nokogiri (>= 1.5.9)
61
- mail (2.6.6)
62
- mime-types (>= 1.16, < 4)
63
+ mail (2.7.0)
64
+ mini_mime (>= 0.1.1)
63
65
  method_source (0.9.0)
64
- mime-types (3.1)
65
- mime-types-data (~> 3.2015)
66
- mime-types-data (3.2016.0521)
66
+ mini_mime (1.0.0)
67
67
  mini_portile2 (2.3.0)
68
68
  minitest (5.10.3)
69
69
  nio4r (2.1.0)
@@ -109,6 +109,11 @@ GEM
109
109
  diff-lcs (>= 1.2.0, < 2.0)
110
110
  rspec-support (~> 3.6.0)
111
111
  rspec-support (3.6.0)
112
+ simplecov (0.15.1)
113
+ docile (~> 1.1.0)
114
+ json (>= 1.8, < 3)
115
+ simplecov-html (~> 0.10.0)
116
+ simplecov-html (0.10.2)
112
117
  sprockets (3.7.1)
113
118
  concurrent-ruby (~> 1.0)
114
119
  rack (> 1, < 3)
@@ -122,7 +127,7 @@ GEM
122
127
  thread_safe (~> 0.1)
123
128
  websocket-driver (0.6.5)
124
129
  websocket-extensions (>= 0.1.0)
125
- websocket-extensions (0.1.2)
130
+ websocket-extensions (0.1.3)
126
131
 
127
132
  PLATFORMS
128
133
  ruby
@@ -131,6 +136,7 @@ DEPENDENCIES
131
136
  bundler (~> 1.16.a)
132
137
  rake (~> 10.0)
133
138
  rspec (~> 3.0)
139
+ simplecov
134
140
  zero-rails_openapi!
135
141
 
136
142
  BUNDLED WITH
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/zero-rails_openapi.svg)](https://badge.fury.io/rb/zero-rails_openapi)
4
4
  [![Build Status](https://travis-ci.org/zhandao/zero-rails_openapi.svg?branch=master)](https://travis-ci.org/zhandao/zero-rails_openapi)
5
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/471fd60f6eb7b019ceed/maintainability)](https://codeclimate.com/github/zhandao/zero-rails_openapi/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/471fd60f6eb7b019ceed/test_coverage)](https://codeclimate.com/github/zhandao/zero-rails_openapi/test_coverage)
6
7
  [![Gitter Chat](https://badges.gitter.im/zero-rails_openapi/Lobby.svg)](https://gitter.im/zero-rails_openapi/Lobby)
7
8
 
8
9
  Concise DSL for generating OpenAPI Specification 3 (**OAS3**, formerly Swagger3) JSON documentation for Rails application,
@@ -13,6 +14,9 @@
13
14
  **Hi, here is ZhanDao = ▽ =
14
15
  I think it's a very useful tool when you want to write API document clearly.
15
16
  I'm looking forward to your issue and PR, thanks!**
17
+
18
+ And, if you have any questions, please read the test code first.
19
+ such as [api DSL](spec/api_info_obj_spec.rb) and [schema Obj](spec/oas_objs/schema_obj_spec.rb).
16
20
 
17
21
  ## Table of Contents
18
22
 
@@ -271,7 +275,7 @@
271
275
  email: 'desc of the parameter :email'
272
276
  ```
273
277
 
274
- You can of course describe the input in it's DSL method (like `query! :done ...`, [this line](https://github.com/zhandao/zero-rails_openapi#-dsl-usage-example)),
278
+ You can of course describe the input in it's DSL method (like `query! :done ...`, [this line](https://github.com/zhandao/zero-rails_openapi#dsl-usage-example)),
275
279
  but that will make it long and ugly. We recommend that unite descriptions in this place.
276
280
 
277
281
  In addition, when you want to dry the same parameters (each with a different description), it will be of great use.
@@ -445,8 +449,8 @@
445
449
  4. *[IMPORTANT]* Each request bodies you declared will **FUSION** together. <a name="fusion"></a>
446
450
  (1) Media-Types will be merged to `requestBody["content"]`
447
451
  ```ruby
448
- form 'desc', data: { }
449
- body :json, 'desc', data: { }
452
+ form data: { }, desc: 'desc'
453
+ body :json, data: { }, desc: 'desc'
450
454
  # will generate: "content": { "multipart/form-data": { }, "application/json": { } }
451
455
  ```
452
456
  (2) The same media-types will fusion, but not merge:
@@ -476,6 +480,7 @@
476
480
  # method signature
477
481
  response(code, desc, media_type = nil, data: { }, type: nil)
478
482
  # usage
483
+ resp 200, 'json response', :json, data: { name: 'test' }
479
484
  response 200, 'query result', :pdf, type: File
480
485
  # same as:
481
486
  response 200, 'query result', :pdf, data: File
@@ -550,9 +555,9 @@
550
555
 
551
556
  ```ruby
552
557
  # method signature
553
- server(url, desc)
558
+ server(url, desc: '')
554
559
  # usage
555
- server 'http://localhost:3000', 'local'
560
+ server 'http://localhost:3000', desc: 'local'
556
561
  ```
557
562
 
558
563
  ### DSL methods inside [components]()'s block ([code source](lib/open_api/dsl/components.rb))
@@ -687,7 +692,7 @@
687
692
 
688
693
  You can also use Hash to define `enum`:
689
694
  ```ruby
690
- query :view, String, desc: 'allows values<br/>', enum: {
695
+ query :view, String, desc: 'allows values<br/>', enum!: {
691
696
  'all goods (default)': :all,
692
697
  'only online': :online,
693
698
  'only offline': :offline,
@@ -715,7 +720,7 @@
715
720
  ### Trick6 - Combined Schema (one_of / all_of / any_of / not)
716
721
 
717
722
  ```ruby
718
- query :combination, one_of: [ :GoodSchema, String, { type: Integer, desc: 'integer input'}]
723
+ query :combination, one_of: [ :GoodSchema, String, { type: Integer, desc: 'integer input' } ]
719
724
 
720
725
  form '', data: {
721
726
  :combination_in_form => { any_of: [ Integer, String ] }
data/README_zh.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/zero-rails_openapi.svg)](https://badge.fury.io/rb/zero-rails_openapi)
4
4
  [![Build Status](https://travis-ci.org/zhandao/zero-rails_openapi.svg?branch=master)](https://travis-ci.org/zhandao/zero-rails_openapi)
5
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/471fd60f6eb7b019ceed/maintainability)](https://codeclimate.com/github/zhandao/zero-rails_openapi/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/471fd60f6eb7b019ceed/test_coverage)](https://codeclimate.com/github/zhandao/zero-rails_openapi/test_coverage)
6
7
  [![Gitter Chat](https://badges.gitter.im/zero-rails_openapi/Lobby.svg)](https://gitter.im/zero-rails_openapi/Lobby)
7
8
 
8
9
  一套简洁的 DSL,用于为 Rails 应用生成 OpenAPI Specification 3 (**OAS3**, 旧称「Swagger3」) 标准的 JSON 文档。
@@ -15,6 +16,10 @@
15
16
  你还可以复用其所[产出](#about-openapidocs-and-openapipaths_index)来写一些扩展,比如参数自动校验什么的(我有写哦)。
16
17
  有什么想法敬请 PR,谢过!
17
18
  另外,走过路过不妨来个 star?**
19
+
20
+ 另外,如果对其行为表现有任何疑惑,敬请先阅读测试代码,这其中已然表明清楚我的大多数考量。
21
+ 值得一读的测试:[api DSL](spec/api_info_obj_spec.rb) 以及 [schema Obj](spec/oas_objs/schema_obj_spec.rb)。
22
+
18
23
 
19
24
  ## Table of Contents
20
25
 
@@ -12,7 +12,7 @@ class V1::GoodsDoc < BaseDoc
12
12
 
13
13
  # Instead of:
14
14
  # query :view, String, enum: %w[ all online offline expensive cheap ]
15
- query :view, String, enum: {
15
+ query :view, String, enum!: {
16
16
  'all goods (default)': :all,
17
17
  'only online': :online,
18
18
  'only offline': :offline,
@@ -1,4 +1,4 @@
1
- class V2::GoodsDoc < BaseDoc
1
+ class V2::GoodsDoc < ApiDoc
2
2
  SCHEMA_DRY = { a: 1, b: 2 }
3
3
 
4
4
  # skip: [ 'Token' ] do # you can also skip parameters
@@ -8,7 +8,7 @@ class V2::GoodsDoc < BaseDoc
8
8
  search_type!: 'search field, allows:<br/>'
9
9
 
10
10
  # Single `query`
11
- query :view, String, enum: {
11
+ query :view, String, enum!: {
12
12
  'all goods (default)': :all,
13
13
  'only online': :online,
14
14
  'only offline': :offline,
@@ -13,16 +13,14 @@ module OpenApi
13
13
  @schemas = combined_schema.values.first
14
14
  end
15
15
 
16
- def process_for(param_name = nil, options = { desc_inside: false })
16
+ def process(options = { inside_desc: false })
17
17
  processed[@mode] = @schemas.map do |schema|
18
18
  type = schema.is_a?(Hash) ? schema[:type] : schema
19
19
  schema = { } unless schema.is_a?(Hash)
20
- SchemaObj.new(type, schema).process_for(param_name, options)
20
+ SchemaObj.new(type, schema).process(options)
21
21
  end
22
22
  processed
23
23
  end
24
-
25
- alias process process_for
26
24
  end
27
25
  end
28
26
  end
@@ -21,7 +21,7 @@ module OpenApi
21
21
  if keys_of_value.present? && value.is_a?(Array)
22
22
  { value: Hash[keys_of_value.zip(value)] }
23
23
  elsif value.is_a?(Symbol) && value['$']
24
- { '$ref': RefObj.new(:example, value).process }
24
+ RefObj.new(value.to_s.delete('$'), :example).process
25
25
  else
26
26
  { value: value }
27
27
  end
@@ -38,20 +38,10 @@ module OpenApi
38
38
 
39
39
  def to_processed(who)
40
40
  return processed unless truly_present?(@assign)
41
-
42
- if who.is_a?(Symbol)
43
- send("#{who}=", @assign)
44
- else
45
- processed[who.to_sym] = @assign
46
- end
47
-
41
+ processed[who.to_sym] = @assign
48
42
  processed
49
43
  end
50
44
 
51
- def to(who)
52
- self[who.to_sym] = @assign if truly_present?(@assign)
53
- end
54
-
55
45
  def then_merge! # to_processed
56
46
  processed.tap { |it| it.merge! @assign if truly_present?(@assign) }
57
47
  end
@@ -29,6 +29,7 @@ module OpenApi
29
29
  # https://en.wikipedia.org/wiki/Media_type
30
30
  # https://zh.wikipedia.org/wiki/%E4%BA%92%E8%81%94%E7%BD%91%E5%AA%92%E4%BD%93%E7%B1%BB%E5%9E%8B
31
31
  # https://www.iana.org/assignments/media-types/media-types.xhtml
32
+ # :nocov:
32
33
  def media_type_mapping(media_type)
33
34
  return media_type if media_type.is_a? String
34
35
  case media_type
@@ -60,6 +61,7 @@ module OpenApi
60
61
  else nil
61
62
  end
62
63
  end
64
+ # :nocov:
63
65
  end
64
66
  end
65
67
  end
@@ -20,12 +20,12 @@ module OpenApi
20
20
 
21
21
  def process
22
22
  assign(desc).to_processed 'description'
23
- processed.tap { |it| it[:schema] = schema.process_for(processed[:name]) }
23
+ processed.tap { |it| it[:schema] = schema.process }
24
24
  end
25
25
 
26
26
  def desc
27
27
  return _desc unless __desc.present?
28
- schema.preprocess_with_desc __desc, self[:name]
28
+ schema.preprocess_with_desc __desc
29
29
  end
30
30
 
31
31
 
@@ -22,12 +22,6 @@ module OpenApi
22
22
  assign(media_types.map(&:process).reduce({ }, &fusion)).to_processed 'content'
23
23
  processed
24
24
  end
25
-
26
- def override(type_hash)
27
- @hash[:type].merge!(type_hash)
28
- self.media_type = MediaTypeObj.new(@mt, @hash)
29
- self
30
- end
31
25
  end
32
26
  end
33
27
  end
@@ -26,39 +26,34 @@ module OpenApi
26
26
  merge! schema_hash
27
27
  end
28
28
 
29
-
30
- def process_for(param_name = nil, options = { desc_inside: false })
31
- return processed if @preprocessed
29
+ def process(options = { inside_desc: false })
30
+ return processed if preprocessed
32
31
 
33
32
  processed.merge!(processed_type)
34
33
  reducx(
35
34
  processed_enum_and_length,
36
35
  processed_range,
37
- processed_is_and_format(param_name),
36
+ processed_is_and_format,
38
37
  {
39
38
  pattern: _pattern.is_a?(String)? _pattern : _pattern&.inspect&.delete('/'),
40
- default: nil,
39
+ default: _default,
41
40
  examples: self[:examples].present? ? ExampleObj.new(self[:examples], self[:exp_by]).process : nil
42
41
  },
43
- { as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if, blankable: _blank }
42
+ { as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if, blankable: _blank },
44
43
  ).then_merge!
45
- processed[:default] = _default unless _default.nil?
46
-
47
- reducx(processed_desc(options)).then_merge!
44
+ reducx(processed_desc(options)).then_merge! # TODO
48
45
  end
49
46
 
50
- alias process process_for
51
-
52
- def preprocess_with_desc desc, param_name = nil
47
+ def preprocess_with_desc desc
53
48
  self.__desc = desc
54
- process_for param_name
49
+ process
55
50
  self.preprocessed = true
56
51
  __desc
57
52
  end
58
53
 
59
54
  def processed_desc(options)
60
- result = __desc ? self.__desc = auto_generate_desc : _desc
61
- options[:desc_inside] ? { description: result } : nil
55
+ result = __desc ? auto_generate_desc : _desc
56
+ options[:inside_desc] ? { description: result } : nil
62
57
  end
63
58
 
64
59
  def processed_type(type = self.type)
@@ -66,16 +61,16 @@ module OpenApi
66
61
  if t.is_a? Hash
67
62
  processed_hash_type(t)
68
63
  elsif t.is_a? Array
69
- recursive_array_type(t)
64
+ processed_array_type(t)
70
65
  elsif t.is_a? Symbol
71
66
  RefObj.new(:schema, t).process
72
- elsif t.in? %w[float double int32 int64]
73
- { type: t.match?('int') ? 'integer' : 'number', format: t}
74
- elsif t.in? %w[binary base64]
75
- { type: 'string', format: t}
76
- elsif t.eql? 'file'
67
+ elsif t.in? %w[ float double int32 int64 ]
68
+ { type: t.match?('int') ? 'integer' : 'number', format: t }
69
+ elsif t.in? %w[ binary base64 ]
70
+ { type: 'string', format: t }
71
+ elsif t == 'file'
77
72
  { type: 'string', format: Config.dft_file_format }
78
- elsif t.eql? 'datetime'
73
+ elsif t == 'datetime'
79
74
  { type: 'string', format: 'date-time' }
80
75
  else # other string
81
76
  { type: t }
@@ -84,32 +79,38 @@ module OpenApi
84
79
 
85
80
  def processed_hash_type(t)
86
81
  # For supporting this:
87
- # form 'desc', data: {
82
+ # form 'desc', type: {
88
83
  # id!: { type: Integer, enum: 0..5, desc: 'user id' }
89
- # }
84
+ # }, should have description within schema
90
85
  if t.key?(:type)
91
- SchemaObj.new(t[:type], t).process_for(@prop_name, desc_inside: true)
92
- # For supporting combined schema in nested schema.
86
+ SchemaObj.new(t[:type], t).process(inside_desc: true)
87
+
88
+ # For supporting combined schema in nested schema.
93
89
  elsif (t.keys & %i[ one_of any_of all_of not ]).present?
94
- CombinedSchema.new(t).process_for(@prop_name, desc_inside: true)
90
+ CombinedSchema.new(t).process(inside_desc: true)
95
91
  else
96
- recursive_obj_type(t)
92
+ processed_obj_type(t)
97
93
  end
98
94
  end
99
95
 
100
96
  def processed_enum_and_length
101
97
  process_enum_info
102
- process_enum_lth_range
98
+ process_range_enum_and_lth
103
99
 
104
100
  # generate length range fields by _lth array
105
- lth = _length || [ ]
106
- max = lth.is_a?(Array) ? lth.first : ("#{lth}".match?('ge') ? "#{lth}".split('_').last.to_i : nil)
107
- min = lth.is_a?(Array) ? lth.last : ("#{lth}".match?('le') ? "#{lth}".split('_').last.to_i : nil)
101
+ if (lth = _length || [ ]).is_a?(Array)
102
+ min, max = [lth.first&.to_i, lth.last&.to_i]
103
+ elsif lth['ge']
104
+ max = lth.to_s.split('_').last.to_i
105
+ elsif lth['le']
106
+ min = lth.to_s.split('_').last.to_i
107
+ end
108
+
108
109
  if processed[:type] == 'array'
109
- { minItems: max, maxItems: min }
110
+ { minItems: min, maxItems: max }
110
111
  else
111
- { minLength: max, maxLength: min }
112
- end.merge!(enum: _enum).keep_if &value_present
112
+ { minLength: min, maxLength: max }
113
+ end.merge(enum: _enum).keep_if &value_present
113
114
  end
114
115
 
115
116
  def processed_range
@@ -122,22 +123,11 @@ module OpenApi
122
123
  }.keep_if &value_present
123
124
  end
124
125
 
125
- def processed_is_and_format(name)
126
- return if name.nil?
127
- recognize_is_options_in name
128
- { }.tap do |it|
129
- # `format` that generated in process_type() may be overwrote here.
130
- it[:format] = _format || _is if processed[:format].blank? || _format.present?
131
- it[:is] = _is
132
- end
133
- end
134
-
135
- def recognize_is_options_in(name)
136
- return unless _is.nil?
137
- # identify whether `is` patterns matched the name, if so, generate `is`.
138
- Config.is_options.each do |pattern|
139
- (self._is = pattern) or break if name.match?(/#{pattern}/)
140
- end
126
+ def processed_is_and_format
127
+ result = { is: _is }
128
+ # `format` that generated in process_type() may be overwrote here.
129
+ result[:format] = _format || _is if processed[:format].blank? || _format.present?
130
+ result
141
131
  end
142
132
 
143
133
 
@@ -3,65 +3,62 @@ module OpenApi
3
3
  module SchemaObjHelpers
4
4
  # TODO: more info and desc configure
5
5
  def auto_generate_desc
6
- if processed[:enum].present?
7
- if @enum_info.present?
8
- @enum_info.each_with_index do |(info, value), index|
9
- __desc.concat "<br/>#{index + 1}/ #{info}: #{value}"
10
- end
11
- else
12
- processed[:enum].each_with_index do |value, index|
13
- __desc.concat "<br/>#{index + 1}/ #{value}"
14
- end
6
+ return __desc if processed[:enum].blank?
7
+
8
+ if @enum_info.present?
9
+ @enum_info.each_with_index do |(info, value), index|
10
+ __desc.concat "<br/>#{index + 1}/ #{info}: #{value}"
11
+ end
12
+ else
13
+ processed[:enum].each_with_index do |value, index|
14
+ __desc.concat "<br/>#{index + 1}/ #{value}"
15
15
  end
16
16
  end
17
17
  __desc
18
18
  end
19
19
 
20
- def recursive_obj_type(t) # ZRO use { prop_name: prop_type } to represent object structure
21
- return processed_type(t) if !t.is_a?(Hash) || (t.keys & %i[ type one_of any_of all_of not ]).present?
20
+ def processed_obj_type(t)
21
+ obj_type = { type: 'object', properties: { }, required: [ ] }
22
22
 
23
- _schema = {
24
- type: 'object',
25
- properties: { },
26
- required: [ ]
27
- }
28
23
  t.each do |prop_name, prop_type|
29
- @prop_name = prop_name
30
- _schema[:required] << "#{prop_name}".delete('!') if prop_name['!']
31
- _schema[:properties]["#{prop_name}".delete('!').to_sym] = recursive_obj_type prop_type
24
+ obj_type[:required] << prop_name.to_s.delete('!') if prop_name['!']
25
+ obj_type[:properties][prop_name.to_s.delete('!').to_sym] = processed_type(prop_type)
32
26
  end
33
- _schema.keep_if(&value_present)
27
+ obj_type.keep_if &value_present
34
28
  end
35
29
 
36
- def recursive_array_type(t)
37
- return processed_type(t) unless t.is_a? Array
38
-
30
+ def processed_array_type(t)
31
+ t = t.size == 1 ? t.first : { one_of: t }
39
32
  {
40
33
  type: 'array',
41
- # TODO: [[String], [Integer]] <= One Of? Object?(0=>[S], 1=>[I])
42
- items: recursive_array_type(t.first)
34
+ items: processed_type(t)
43
35
  }
44
36
  end
45
37
 
46
- def process_enum_lth_range
47
- self[:_enum] = _enum.to_a if _enum.present? && _enum.is_a?(Range)
48
- self[:_length] = _length.to_a if _length.present? && _length.is_a?(Range)
38
+ def process_range_enum_and_lth
39
+ self[:_enum] = str_range_2a(_enum) if _enum.present? && _enum.is_a?(Range)
40
+ self[:_length] = str_range_2a(_length) if _length.present? && _length.is_a?(Range)
49
41
 
50
- # generate_enums_by_enum_array
51
42
  values = _enum || _value
52
43
  self._enum = Array(values) if truly_present?(values)
53
44
  end
54
45
 
46
+ def str_range_2a(val)
47
+ val_class = val.first.class
48
+ action = "to_#{val_class.to_s.downcase[0]}".to_sym
49
+ (val.first.to_s..val.last.to_s).to_a.map(&action)
50
+ end
51
+
55
52
  def process_enum_info
56
53
  # Support this writing for auto generating desc from enum.
57
- # enum: {
58
- # 'all_data': :all,
59
- # 'one_page': :one
54
+ # enum!: {
55
+ # 'all_desc': :all,
56
+ # 'one_desc': :one
60
57
  # }
61
- if _enum.is_a? Hash
62
- @enum_info = _enum
63
- self._enum = _enum.values
64
- end
58
+ self._enum ||= self[:enum!]
59
+ return unless self[:enum!].is_a? Hash
60
+ @enum_info = self[:enum!]
61
+ self._enum = self[:enum!].values
65
62
  end
66
63
  end
67
64
  end
data/lib/open_api.rb CHANGED
@@ -1,7 +1,7 @@
1
- require "open_api/version"
2
- require "open_api/config"
3
- require "open_api/generator"
4
- require "open_api/dsl"
1
+ require 'open_api/version'
2
+ require 'open_api/config'
3
+ require 'open_api/generator'
4
+ require 'open_api/dsl'
5
5
 
6
6
  module OpenApi
7
7
  include Generator
@@ -47,10 +47,6 @@ module OpenApi
47
47
  }
48
48
  end
49
49
 
50
- cattr_accessor :is_options do
51
- %w[ email phone mobile password uuid uri url time date ]
52
- end
53
-
54
50
  cattr_accessor :dft_file_format do
55
51
  'binary'
56
52
  end
@@ -10,7 +10,7 @@ module OpenApi
10
10
  end
11
11
 
12
12
  def info version:, title:, desc: '', **addition
13
- open_api_docs[@api][:info] = { version: version, title: title, description: desc, **addition }
13
+ open_api_docs[@api][:info] = { version: version, title: title, description: desc, **addition }
14
14
  end
15
15
 
16
16
  def server url, desc: ''
@@ -30,7 +30,7 @@ module OpenApi
30
30
  security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format }.merge(other_info)
31
31
  end
32
32
 
33
- def api_key scheme_name, field:, in:, **other_info
33
+ def api_key scheme_name, field:, in: 'header', **other_info
34
34
  _in = binding.local_variable_get(:in)
35
35
  security_scheme scheme_name, { type: 'apiKey', name: field, in: _in }.merge(other_info)
36
36
  end
data/lib/open_api/dsl.rb CHANGED
@@ -26,7 +26,7 @@ module OpenApi
26
26
  def components &block
27
27
  apis_tag if @_ctrl_infos.nil?
28
28
  current_ctrl = @_ctrl_infos[:components] = Components.new
29
- current_ctrl.instance_eval(&block)
29
+ current_ctrl.instance_exec(&block)
30
30
  current_ctrl.process_objs
31
31
  end
32
32
 
@@ -41,25 +41,22 @@ module OpenApi
41
41
  .merge! description: '', summary: summary, operationId: action, tags: [@_apis_tag],
42
42
  parameters: [ ], requestBody: '', responses: { }, security: [ ], servers: [ ]
43
43
  [action, :all].each { |blk_key| @_api_dry_blocks&.[](blk_key)&.each { |blk| api.instance_eval(&blk) } }
44
+ api.param_use = [ ] # `skip` and `use` only affect `api_dry`'s blocks
45
+ api.param_skip = [ ]
44
46
  api.param_use = [ ] # `skip` and `use` only affect `api_dry`'s blocks
45
- api.instance_eval(&block) if block_given?
47
+ api.instance_exec(&block) if block_given?
46
48
  api.process_objs
47
49
  api.delete_if { |_, v| v.blank? }
48
50
 
49
51
  path = (@_api_infos ||= { })[routes_info[:path]] ||= { }
50
- http_verbs = (http || routes_info[:http_verb]).split('|')
51
- http_verbs.each { |verb| path[verb] = api }
52
+ (http || routes_info[:http_verb]).split('|').each { |verb| path[verb] = api }
52
53
  api
53
54
  end
54
55
 
55
56
  # method could be symbol array, like: %i[ .. ]
56
57
  def api_dry action = :all, desc = '', &block
57
58
  @_api_dry_blocks ||= { }
58
- if action.is_a? Array
59
- action.each { |m| (@_api_dry_blocks[m.to_sym] ||= [ ]) << block }
60
- else
61
- (@_api_dry_blocks[action.to_sym] ||= [ ]) << block
62
- end
59
+ Array(action).each { |a| (@_api_dry_blocks[a.to_sym] ||= [ ]) << block }
63
60
  end
64
61
 
65
62
  def ctrl_routes_list
@@ -19,9 +19,9 @@ module OpenApi
19
19
  self[:deprecated] = true
20
20
  end
21
21
 
22
- alias this_api_is_expired! this_api_is_invalid!
23
- alias this_api_is_unused! this_api_is_invalid!
24
- alias this_api_is_under_repair this_api_is_invalid!
22
+ alias this_api_is_expired! this_api_is_invalid!
23
+ alias this_api_is_unused! this_api_is_invalid!
24
+ alias this_api_is_under_repair! this_api_is_invalid!
25
25
 
26
26
  def desc desc, param_descs = { }
27
27
  self.param_descs = param_descs
@@ -33,14 +33,24 @@ module OpenApi
33
33
  return if param_use.present? && param_use.exclude?(name)
34
34
 
35
35
  _t = nil
36
- schema_hash[:desc] = _t if (_t = param_descs[name]).present?
37
- schema_hash[:desc!] = _t if (_t = param_descs["#{name}!".to_sym]).present?
36
+ schema_hash[:desc] ||= _t if (_t = param_descs[name]).present?
37
+ schema_hash[:desc!] ||= _t if (_t = param_descs["#{name}!".to_sym]).present?
38
38
 
39
39
  param_obj = ParamObj.new(name, param_type, type, required, schema_hash)
40
40
  # The definition of the same name parameter will be overwritten
41
41
  fill_in_parameters(param_obj)
42
42
  end
43
43
 
44
+ # [ header header! path path! query query! cookie cookie! ]
45
+ def _param_agent name, type = nil, one_of: nil, all_of: nil, any_of: nil, not: nil, **schema_hash
46
+ combined_schema = one_of || all_of || any_of || (_not = binding.local_variable_get(:not))
47
+ type = schema_hash[:type] ||= type
48
+ pp "[ZRO] Syntax Error: param `#{name}` has no schema type!" and return if type.nil? && combined_schema.nil?
49
+
50
+ schema_hash = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
51
+ param @param_type.to_s.delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
52
+ end
53
+
44
54
  # For supporting this: (just like `form '', data: { }` usage)
45
55
  # do_query by: {
46
56
  # :search_type => { type: String },
@@ -49,19 +59,12 @@ module OpenApi
49
59
  %i[ header header! path path! query query! cookie cookie! ].each do |param_type|
50
60
  define_method "do_#{param_type}" do |by:|
51
61
  by.each do |key, value|
52
- args = [ key.dup.to_s.delete('!').to_sym, value.delete(:type), value ]
53
- key.to_s['!'] ? send("#{param_type}!", *args) : send(param_type, *args)
62
+ action = param_type.to_s.delete('!')
63
+ type, value = value.is_a?(Hash) ? [value[:type], value] : [value, { }]
64
+ args = [ key.to_s.delete('!').to_sym, type, value ]
65
+ param_type['!'] || key['!'] ? send("#{action}!", *args) : send(action, *args)
54
66
  end
55
- end unless param_type.to_s['!']
56
- end
57
-
58
- def _param_agent name, type = nil, one_of: nil, all_of: nil, any_of: nil, not: nil, **schema_hash
59
- (schema_hash = type) and (type = type.delete(:type)) if type.is_a?(Hash) && type.key?(:type)
60
- type = schema_hash[:type] if type.nil?
61
-
62
- combined_schema = one_of || all_of || any_of || (_not = binding.local_variable_get(:not))
63
- schema_hash = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
64
- param "#{@param_type}".delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
67
+ end
65
68
  end
66
69
 
67
70
  def param_ref component_key, *keys
@@ -75,18 +78,13 @@ module OpenApi
75
78
  self[:requestBody].add_or_fusion(media_type, options.merge(data: data))
76
79
  end
77
80
 
81
+ # [ body body! ]
78
82
  def _request_body_agent media_type, data: { }, **options
79
83
  request_body (@method_name['!'] ? :req : :opt), media_type, data: data, **options
80
84
  end
81
85
 
82
86
  def body_ref component_key
83
- self[:requestBody] = RefObj.new(:requestBody, component_key).process
84
- end
85
-
86
- def response_ref code_compkey_hash
87
- code_compkey_hash.each do |code, component_key|
88
- self[:responses][code] = RefObj.new(:response, component_key).process
89
- end
87
+ self[:requestBody] = RefObj.new(:requestBody, component_key)
90
88
  end
91
89
 
92
90
  def form data:, **options
@@ -110,6 +108,12 @@ module OpenApi
110
108
  body! media_type, data: data, **options
111
109
  end
112
110
 
111
+ def response_ref code_compkey_hash
112
+ code_compkey_hash.each do |code, component_key|
113
+ self[:responses][code] = RefObj.new(:response, component_key).process
114
+ end
115
+ end
116
+
113
117
  def security_require scheme_name, scopes: [ ]
114
118
  self[:security] << { scheme_name => scopes }
115
119
  end
@@ -118,12 +122,13 @@ module OpenApi
118
122
  alias auth security_require
119
123
  alias need_auth security_require
120
124
 
121
- def server url, desc
125
+ def server url, desc: ''
122
126
  self[:servers] << { url: url, description: desc }
123
127
  end
124
128
 
125
129
  def order *param_names
126
130
  self.param_order = param_names
131
+ # use when api_dry
127
132
  self.param_use = param_order if param_use.blank?
128
133
  self.param_skip = param_use - param_order
129
134
  end
@@ -136,7 +141,6 @@ module OpenApi
136
141
 
137
142
  alias examples param_examples
138
143
 
139
-
140
144
  def process_objs
141
145
  self[:parameters]&.each_with_index do |p, index|
142
146
  self[:parameters][index] = p.process if p.is_a?(ParamObj)
@@ -7,13 +7,13 @@ module OpenApi
7
7
  include DSL::Helpers
8
8
 
9
9
  def schema component_key, type = nil, one_of: nil, all_of: nil, any_of: nil, not: nil, **schema_hash
10
- (schema_hash = type) and (type = type.delete(:type)) if type.is_a?(Hash) && type.key?(:type)
11
- type ||= schema_hash[:type]
12
- type ||= load_schema component_key if component_key.try(:superclass) == Config.active_record_base || ApplicationRecord
13
-
14
10
  combined_schema = (_not = binding.local_variable_get(:not)) || one_of || all_of || any_of
11
+ schema_hash[:type] ||= type
12
+ schema_hash = load_schema component_key if component_key.try(:superclass) == (Config.active_record_base || ApplicationRecord)
13
+ pp "[ZRO] Syntax Error: component schema `#{component_key}` has no type!" and return if schema_hash[:type].nil? && combined_schema.nil?
14
+
15
15
  combined_schema = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
16
- (self[:schemas] ||= { })[component_key.to_s.to_sym] = combined_schema&.process || SchemaObj.new(type, schema_hash).process
16
+ (self[:schemas] ||= { })[component_key.to_s.to_sym] = combined_schema&.process || SchemaObj.new(schema_hash, { }).process
17
17
  end
18
18
  arrow_enable :schema
19
19
 
@@ -26,9 +26,11 @@ module OpenApi
26
26
  (self[:parameters] ||= { })[component_key] = ParamObj.new(name, param_type, type, required, schema_hash).process
27
27
  end
28
28
 
29
+ # [ header header! path path! query query! cookie cookie! ]
29
30
  def _param_agent component_key, name, type = nil, one_of: nil, all_of: nil, any_of: nil, not: nil, **schema_hash
30
- (schema_hash = type) and (type = type.delete(:type)) if type.is_a?(Hash) && type.key?(:type)
31
- type = schema_hash[:type] if type.nil?
31
+ combined_schema = one_of || all_of || any_of || (_not = binding.local_variable_get(:not))
32
+ schema_hash[:type] ||= type
33
+ pp "[ZRO] Syntax Error: param `#{name}` has no schema type!" and return if schema_hash[:type].nil? && combined_schema.nil?
32
34
 
33
35
  combined_schema = one_of || all_of || any_of || (_not = binding.local_variable_get(:not))
34
36
  schema_hash = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
@@ -44,6 +46,7 @@ module OpenApi
44
46
  self[:requestBodies][component_key] = cur.add_or_fusion(media_type, options.merge(data: data))
45
47
  end
46
48
 
49
+ # [ body body! ]
47
50
  def _request_body_agent component_key, media_type, data: { }, **options
48
51
  request_body component_key,
49
52
  (@method_name['!'] ? :req : :opt), media_type, data: data, **options
@@ -71,7 +74,7 @@ module OpenApi
71
74
  end
72
75
  arrow_enable :bearer_auth
73
76
 
74
- def api_key scheme_name, field:, in:, **other_info
77
+ def api_key scheme_name, field:, in: 'header', **other_info
75
78
  _in = binding.local_variable_get(:in)
76
79
  security_scheme scheme_name, { type: 'apiKey', name: field, in: _in }.merge(other_info)
77
80
  end
@@ -5,6 +5,7 @@ module OpenApi
5
5
  base.extend ClassMethods
6
6
  end
7
7
 
8
+ # :nocov:
8
9
  def load_schema(model)
9
10
  # About `show_attrs`, see:
10
11
  # (1) BuilderSupport module: https://github.com/zhandao/zero-rails/blob/master/app/models/concerns/builder_support.rb
@@ -37,6 +38,7 @@ module OpenApi
37
38
  end rescue next
38
39
  end
39
40
  end
41
+ # :nocov:
40
42
 
41
43
  def fill_in_parameters(param_obj)
42
44
  name = param_obj.processed[:name]
@@ -8,17 +8,17 @@ module OpenApi
8
8
 
9
9
  module ClassMethods
10
10
  def generate_docs(doc_name = nil)
11
+ pp '[ZRO] No documents have been configured!' and return if Config.docs.keys.blank?
12
+
11
13
  Dir['./app/controllers/**/*_controller.rb'].each do |file|
12
14
  # Do Not `require`!
13
15
  # It causes problems, such as making `skip_before_action` not working.
16
+ # :nocov:
14
17
  file.sub('./app/controllers/', '').sub('.rb', '').camelize.constantize
18
+ # :nocov:
15
19
  end
16
20
  Dir[*Array(Config.doc_location)].each { |file| require file }
17
- if doc_name.present?
18
- [{ doc_name => generate_doc(doc_name) }]
19
- else
20
- Config.docs.keys.map { |api_key| { api_key => generate_doc(api_key) } }.reduce({ }, :merge)
21
- end
21
+ (doc_name || Config.docs.keys).map { |name| { name => generate_doc(name) } }.reduce({ }, :merge)
22
22
  end
23
23
 
24
24
  def generate_doc(doc_name)
@@ -42,12 +42,13 @@ module OpenApi
42
42
  doc[:tags] = doc[:tags].sort { |a, b| a[:name] <=> b[:name] }
43
43
  doc[:paths] = doc[:paths].sort.to_h
44
44
 
45
- OpenApi.docs[doc_name] ||= ActiveSupport::HashWithIndifferentAccess.new(doc.delete_if { |_, v| v.blank? })
45
+ OpenApi.docs[doc_name] = ActiveSupport::HashWithIndifferentAccess.new(doc.delete_if { |_, v| v.blank? })
46
46
  end
47
47
 
48
48
  def write_docs(generate_files: true)
49
49
  docs = generate_docs
50
50
  return unless generate_files
51
+ # :nocov:
51
52
  output_path = Config.file_output_path
52
53
  FileUtils.mkdir_p output_path
53
54
  max_length = docs.keys.map(&:size).sort.last
@@ -56,6 +57,7 @@ module OpenApi
56
57
  puts "[ZRO] `#{doc_name.to_s.rjust(max_length)}.json` has been generated."
57
58
  File.open("#{output_path}/#{doc_name}.json", 'w') { |file| file.write JSON.pretty_generate doc }
58
59
  end
60
+ # :nocov:
59
61
  end
60
62
  end
61
63
 
@@ -64,12 +66,14 @@ module OpenApi
64
66
  if (f = Config.rails_routes_file)
65
67
  File.read(f)
66
68
  else
69
+ # :nocov:
67
70
  # ref https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/routes.rake
68
71
  require './config/routes'
69
72
  all_routes = Rails.application.routes.routes
70
73
  require 'action_dispatch/routing/inspector'
71
74
  inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
72
75
  inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, nil)
76
+ # :nocov:
73
77
  end
74
78
 
75
79
  @routes_list ||= routes.split("\n").drop(1).map do |line|
@@ -1,3 +1,3 @@
1
1
  module OpenApi
2
- VERSION = '1.4.3'
2
+ VERSION = '1.5.1'
3
3
  end
@@ -1,32 +1,33 @@
1
1
 
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "open_api/version"
4
+ require 'open_api/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "zero-rails_openapi"
7
+ spec.name = 'zero-rails_openapi'
8
8
  spec.version = OpenApi::VERSION
9
- spec.authors = ["zhandao"]
10
- spec.email = ["x@skippingcat.com"]
9
+ spec.authors = ['zhandao']
10
+ spec.email = ['x@skippingcat.com']
11
11
 
12
- spec.summary = %q{Concise DSL for generating OpenAPI3 documentation.}
13
- spec.description = %q{Concise DSL for generating OpenAPI Specification 3 (OAS3) JSON documentation for Rails application.}
14
- spec.homepage = "https://github.com/zhandao/zero-rails_openapi"
15
- spec.license = "MIT"
12
+ spec.summary = 'Concise DSL for generating OpenAPI3 documentation.'
13
+ spec.description = 'Concise DSL for generating OpenAPI Specification 3 (OAS3) JSON documentation for Rails application.'
14
+ spec.homepage = 'https://github.com/zhandao/zero-rails_openapi'
15
+ spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
18
  f.match(%r{^(test|spec|features)/})
19
19
  end
20
- spec.bindir = "exe"
20
+ spec.bindir = 'exe'
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
22
+ spec.require_paths = ['lib']
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.16.a"
25
- spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_development_dependency 'bundler', '~> 1.16.a'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.0'
27
+ spec.add_development_dependency 'simplecov'
27
28
 
28
- spec.add_runtime_dependency "rails", ">= 3"
29
- spec.add_runtime_dependency "activesupport", ">= 3"
29
+ spec.add_runtime_dependency 'rails', '>= 3'
30
+ spec.add_runtime_dependency 'activesupport', '>= 3'
30
31
 
31
32
  # spec.post_install_message = ""
32
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zero-rails_openapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - zhandao
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-12 00:00:00.000000000 Z
11
+ date: 2017-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rails
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
164
  version: '0'
151
165
  requirements: []
152
166
  rubyforge_project:
153
- rubygems_version: 2.6.13
167
+ rubygems_version: 2.6.12
154
168
  signing_key:
155
169
  specification_version: 4
156
170
  summary: Concise DSL for generating OpenAPI3 documentation.