zero-rails_openapi 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8973e94b7dd3112572e08cbf838ed9d5288ae092
4
- data.tar.gz: a89c1d354004e40c6441c0ede06b848111a5c8bb
3
+ metadata.gz: 7f7b1eb53af2017d4b4b522191cd0b59e9a69df8
4
+ data.tar.gz: e476592261a8979af7ce367dce37485a0b6f85e8
5
5
  SHA512:
6
- metadata.gz: 170477a27cca4298664b2d95a7ac65879b79bcbd64ab42f23aaa917b0c45f61506e54c7d5027d9503ae96a04a031f0de34c1dc21cf0ad96ffd5962d98ec9916f
7
- data.tar.gz: 532e6c8c37abdcd5e7d00c5f10cdedc5ceab6c2e187760a636c1dfda9b4d5b71b9aa5b6ac5d85cfca69c7b8fd3aa21de3a2ff0c2170e790104993a1317320b17
6
+ metadata.gz: 4022825604733ac97526339adbcd940603b12465e0cfe69fddc3317e3359d1ab019c2275e086aad688b447611baf2c51328682a2730adb79e2a1654949c60196
7
+ data.tar.gz: 250f949531bb8d03cc1b386b55dd4d7026ed67eeeef7fb42b42fbf778ff624819a221d2ab0b21157f429309cb6d590085e1cfea03618b8d0e7abb4a9f7bf85d0
data/CHANGELOG.md CHANGED
@@ -2,7 +2,28 @@
2
2
 
3
3
  ## [Unreleased]
4
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)
5
+ ## [1.5.2] - 2018/1/2 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.5.1...v1.5.2)
6
+
7
+ ## Added
8
+
9
+ 1. `do_*` can be passed common schema after (or before) `by:`.
10
+ 2. when this action can be accessed through multiple HTTP methods (but not set through `match`),
11
+ it also matches and generate both HTTP methods.
12
+
13
+ ## Changed
14
+
15
+ 1. `root_controller` => `base_doc_class`.
16
+ 2. `ctrl_path` => `ctrl_base`.
17
+ 3. `apis_tag` => `doc_tag`.
18
+ 4. `@_ctrl_infos` => `@doc_info`, `@_api_infos` => `@api_info`, `@_apis_dry_blocks` => `@zro_dry_blocks`.
19
+ 5. `OpenApi.paths_index` => `OpenApi.routes_index`.
20
+ 6. `get_actions_by_ctrl_path` => `get_actions_by_route_base`.
21
+ 7. `Config.dft_file_format` => `Config.file_format`.
22
+ 8. Modify the description of the test case (remove `should`).
23
+ 9. `deep_merge!` instead of `_fusion`.
24
+ 10. `ApiInfoObj` => `ApiInfo`.
25
+
26
+ ## [1.5.1 - 100% Test Coverage] - 2017/12/21 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.4.3...v1.5.1)
6
27
 
7
28
  ### Completed the test code (250+ examples), and make it 100% coverage.
8
29
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zero-rails_openapi (1.5.1)
4
+ zero-rails_openapi (1.5.2)
5
5
  activesupport (>= 3)
6
6
  rails (>= 3)
7
7
 
@@ -66,7 +66,7 @@ GEM
66
66
  mini_mime (1.0.0)
67
67
  mini_portile2 (2.3.0)
68
68
  minitest (5.10.3)
69
- nio4r (2.1.0)
69
+ nio4r (2.2.0)
70
70
  nokogiri (1.8.1)
71
71
  mini_portile2 (~> 2.3.0)
72
72
  rack (2.0.3)
data/README.md CHANGED
@@ -36,7 +36,7 @@
36
36
  - [Atuo Generate index/show Actions's Responses Based on DB Schema](#trick5---auto-generate-indexshow-actionss-response-types-based-on-db-schema)
37
37
  - [Combined Schema (one_of / all_of / any_of / not)](#trick6---combined-schema-one_of--all_of--any_of--not)
38
38
  - [Troubleshooting](#troubleshooting)
39
- - [About `OpenApi.docs` and `OpenApi.paths_index`](#about-openapidocs-and-openapipaths_index)
39
+ - [About `OpenApi.docs` and `OpenApi.routes_index`](#about-openapidocs-and-openapiroutes_index)
40
40
 
41
41
  ## About OAS
42
42
 
@@ -83,8 +83,8 @@
83
83
  c.open_api_docs = {
84
84
  # The definition of the document `homepage`.
85
85
  homepage: {
86
- # [REQUIRED] ZRO will scan all the descendants of root_controller, then generate their docs.
87
- root_controller: Api::V1::BaseController,
86
+ # [REQUIRED] ZRO will scan all the descendants of base_doc_class, then generate their docs.
87
+ base_doc_class: Api::V1::BaseController,
88
88
 
89
89
  # [REQUIRED] OAS Info Object: The section contains API information.
90
90
  info: {
@@ -112,7 +112,7 @@
112
112
 
113
113
  OpenApi::Config.tap do |c|
114
114
  c.instance_eval do
115
- open_api :homepage_api, root_controller: ApiDoc
115
+ open_api :homepage_api, base_doc_class: ApiDoc
116
116
  info version: '1.0.0', title: 'Homepage APIs'
117
117
  end
118
118
  end
@@ -138,7 +138,7 @@
138
138
  Here is the simplest usage:
139
139
 
140
140
  ```ruby
141
- class Api::V1::ExamplesController < Api::V1::BaseController
141
+ class Api::ExamplesController < ApiController
142
142
  api :index, 'GET list' do
143
143
  query :page, Integer#, desc: 'page, greater than 1', range: { ge: 1 }, dft: 1
144
144
  query :rows, Integer#, desc: 'per page', range: { ge: 1 }, default: 10
@@ -151,26 +151,26 @@
151
151
 
152
152
  ### DSL as class methods ([source code](lib/open_api/dsl.rb))
153
153
 
154
- #### (1) `ctrl_path` (controller path) [optional if you're writing DSL in controller]
154
+ #### (1) `route_base` [optional if you're writing DSL in controller]
155
155
 
156
156
  ```ruby
157
157
  # method signature
158
- ctrl_path(path)
158
+ route_base(path)
159
159
  # usage
160
- ctrl_path 'api/v1/examples'
160
+ route_base 'api/v1/examples'
161
161
  ```
162
- It is optional because `ctrl_path` defaults to `controller_path`.
162
+ It is optional because `route_base` defaults to `controller_path`.
163
163
 
164
- [Here's a trick](#trick1---write-the-dsl-somewhere-else): Using `ctrl_path`, you can write the DSL somewhere else
164
+ [Here's a trick](#trick1---write-the-dsl-somewhere-else): Using `route_base`, you can write the DSL somewhere else
165
165
  to simplify the current controller.
166
166
 
167
- #### (2) `apis_tag` [optional]
167
+ #### (2) `doc_tag` [optional]
168
168
 
169
169
  ```ruby
170
170
  # method signature
171
- apis_tag(name: nil, desc: '', external_doc_url: '')
171
+ doc_tag(name: nil, desc: '', external_doc_url: nil)
172
172
  # usage
173
- apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
173
+ doc_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
174
174
  ```
175
175
  This method allows you to set the Tag (which is a node of [OpenApi Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#openapi-object)).
176
176
 
@@ -640,7 +640,7 @@
640
640
  ```ruby
641
641
  # config/initializers/open_api.rb
642
642
  # in your configuration
643
- root_controller: ApiDoc
643
+ base_doc_class: ApiDoc
644
644
 
645
645
  # app/api_doc/api_doc.rb
646
646
  require 'open_api/dsl'
@@ -651,7 +651,7 @@
651
651
 
652
652
  # app/api_doc/v1/examples_doc.rb
653
653
  class V1::ExamplesDoc < ApiDoc
654
- ctrl_path 'api/v1/examples'
654
+ route_base 'api/v1/examples'
655
655
 
656
656
  api :index do
657
657
  # ...
@@ -750,14 +750,14 @@
750
750
  3. Put `c.rails_routes_file = 'config/routes.txt'` to your ZRO config.
751
751
 
752
752
 
753
- ## About `OpenApi.docs` and `OpenApi.paths_index`
753
+ ## About `OpenApi.docs` and `OpenApi.routes_index`
754
754
 
755
755
  After `OpenApi.write_docs`, the above two module variables will be generated.
756
756
 
757
757
  `OpenApi.docs`: A Hash with API names as keys, and documents of each APIs as values.
758
758
  documents are instances of ActiveSupport::HashWithIndifferentAccess.
759
759
 
760
- `OpenApi.paths_index`: Inverted index of controller path to API name mappings.
760
+ `OpenApi.routes_index`: Inverted index of controller path to API name mappings.
761
761
  Like: `{ 'api/v1/examples' => :homepage_api }`
762
762
  It's useful when you want to look up a document based on a controller and do something.
763
763
 
data/README_zh.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  **这里是栈刀 = ▽ =
15
15
  如果你在寻找能清晰书写 OAS API 文档的 DSL 工具,俺这个还挺不错的 ~
16
- 你还可以复用其所[产出](#about-openapidocs-and-openapipaths_index)来写一些扩展,比如参数自动校验什么的(我有写哦)。
16
+ 你还可以复用其所[产出](#about-openapidocs-and-openapiroutes_index)来写一些扩展,比如参数自动校验什么的(我有写哦)。
17
17
  有什么想法敬请 PR,谢过!
18
18
  另外,走过路过不妨来个 star?**
19
19
 
@@ -39,7 +39,7 @@
39
39
  - [基于 DB Schema 自动生成 response 的格式](#trick5---auto-generate-indexshow-actionss-response-types-based-on-db-schema)
40
40
  - [定义组合的 Schema (one_of / all_of / any_of / not)](#trick6---combined-schema-one_of--all_of--any_of--not)
41
41
  - [问题集](#troubleshooting)
42
- - [有关 `OpenApi.docs` 和 `OpenApi.paths_index`](#about-openapidocs-and-openapipaths_index)
42
+ - [有关 `OpenApi.docs` 和 `OpenApi.routes_index`](#about-openapidocs-and-openapiroutes_index)
43
43
 
44
44
  ## About OAS
45
45
 
@@ -81,8 +81,8 @@
81
81
  c.open_api_docs = {
82
82
  # 对文档 `homepage` 进行定义
83
83
  homepage: {
84
- # [REQUIRED] ZRO will scan all the descendants of root_controller, then generate their docs.
85
- root_controller: Api::V1::BaseController,
84
+ # [REQUIRED] ZRO will scan all the descendants of base_doc_class, then generate their docs.
85
+ base_doc_class: Api::V1::BaseController,
86
86
 
87
87
  # [REQUIRED] OAS Info Object: The section contains API information.
88
88
  info: {
@@ -109,7 +109,7 @@
109
109
 
110
110
  OpenApi::Config.tap do |c|
111
111
  c.instance_eval do
112
- open_api :homepage_api, root_controller: ApiDoc
112
+ open_api :homepage_api, base_doc_class: ApiDoc
113
113
  info version: '1.0.0', title: 'Homepage APIs'
114
114
  end
115
115
  end
@@ -135,7 +135,7 @@
135
135
  这是一个最简单的实例:
136
136
 
137
137
  ```ruby
138
- class Api::V1::ExamplesController < Api::V1::BaseController
138
+ class Api::ExamplesController < ApiController
139
139
  api :index, 'GET list' do
140
140
  query :page, Integer#, desc: 'page, greater than 1', range: { ge: 1 }, dft: 1
141
141
  query :rows, Integer#, desc: 'per page', range: { ge: 1 }, default: 10
@@ -148,25 +148,25 @@
148
148
 
149
149
  ### 作为类方法的 DSL ([source code](lib/open_api/dsl.rb))
150
150
 
151
- #### (1) `ctrl_path` (controller path) [无需调用,当且仅当你是在控制器中写文档时]
151
+ #### (1) `route_base` [无需调用,当且仅当你是在控制器中写文档时]
152
152
 
153
153
  ```ruby
154
154
  # method signature
155
- ctrl_path(path)
155
+ route_base(path)
156
156
  # usage
157
- ctrl_path 'api/v1/examples'
157
+ route_base 'api/v1/examples'
158
158
  ```
159
159
  其默认设定为 `controller_path`.
160
160
 
161
- [这个技巧](#trick1---write-the-dsl-somewhere-else) 展示如何使用 `ctrl_path` 来让你将 DSL 写在他处(与控制器分离),来简化你的控制器。
161
+ [这个技巧](#trick1---write-the-dsl-somewhere-else) 展示如何使用 `route_base` 来让你将 DSL 写在他处(与控制器分离),来简化你的控制器。
162
162
 
163
- #### (2) `apis_tag` [optional]
163
+ #### (2) `doc_tag` [optional]
164
164
 
165
165
  ```ruby
166
166
  # method signature
167
- apis_tag(name: nil, desc: '', external_doc_url: '')
167
+ doc_tag(name: nil, desc: '', external_doc_url: '')
168
168
  # usage
169
- apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
169
+ doc_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
170
170
  ```
171
171
  This method allows you to set the Tag (which is a node of [OpenApi Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#openapi-object)).
172
172
 
@@ -617,7 +617,7 @@
617
617
  ```ruby
618
618
  # config/initializers/open_api.rb
619
619
  # in your configuration
620
- root_controller: ApiDoc
620
+ base_doc_class: ApiDoc
621
621
 
622
622
  # app/api_doc/api_doc.rb
623
623
  require 'open_api/dsl'
@@ -628,7 +628,7 @@
628
628
 
629
629
  # app/api_doc/v1/examples_doc.rb
630
630
  class V1::ExamplesDoc < ApiDoc
631
- ctrl_path 'api/v1/examples'
631
+ route_base 'api/v1/examples'
632
632
 
633
633
  api :index do
634
634
  # ...
@@ -727,14 +727,14 @@
727
727
  3. Put `c.rails_routes_file = 'config/routes.txt'` to your ZRO config.
728
728
 
729
729
 
730
- ## About `OpenApi.docs` and `OpenApi.paths_index`
730
+ ## About `OpenApi.docs` and `OpenApi.routes_index`
731
731
 
732
732
  After `OpenApi.write_docs`, the above two module variables will be generated.
733
733
 
734
734
  `OpenApi.docs`: A Hash with API names as keys, and documents of each APIs as values.
735
735
  documents are instances of ActiveSupport::HashWithIndifferentAccess.
736
736
 
737
- `OpenApi.paths_index`: Inverted index of controller path to API name mappings.
737
+ `OpenApi.routes_index`: Inverted index of controller path to API name mappings.
738
738
  Like: `{ 'api/v1/examples' => :homepage_api }`
739
739
  It's useful when you want to look up a document based on a controller and do something.
740
740
 
@@ -11,7 +11,7 @@ module AutoGenDoc
11
11
  super
12
12
  subclass.class_eval do
13
13
  break unless self.name.match?(/sController|sDoc/)
14
- ctrl_path self.name.sub('Doc', '').downcase.gsub('::', '/') if self.name.match?(/sDoc/)
14
+ route_base self.name.sub('Doc', '').downcase.gsub('::', '/') if self.name.match?(/sDoc/)
15
15
  open_api_dry
16
16
  end
17
17
  end
@@ -19,8 +19,8 @@ module AutoGenDoc
19
19
  private
20
20
 
21
21
  def open_api_dry
22
- ctrl_path = try(:controller_path) || instance_variable_get('@_ctrl_path')
23
- ::OpenApi::Generator.get_actions_by_ctrl_path(ctrl_path)&.each do |action|
22
+ route_base = try(:controller_path) || instance_variable_get('@route_base')
23
+ ::OpenApi::Generator.get_actions_by_route_base(route_base)&.each do |action|
24
24
  api_dry action do
25
25
  header! 'Token', String, desc: 'user token'
26
26
 
@@ -1,5 +1,5 @@
1
1
  class Api::V1::ExamplesController < Api::V1::BaseController
2
- apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
2
+ doc_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
3
3
 
4
4
  components do
5
5
  schema :DogSchema => [ String, dft: 'doge' ]
@@ -3,7 +3,7 @@ require 'open_api'
3
3
  OpenApi::Config.tap do |c|
4
4
  # Config DSL
5
5
  c.instance_eval do
6
- open_api :zero_rails, root_controller: ApiDoc
6
+ open_api :zero_rails, base_doc_class: ApiDoc
7
7
  info version: '0.0.1', title: 'Zero Rails APIs', description: 'API documentation of Zero-Rails Application.'
8
8
  server 'http://localhost:3000', desc: 'Main (production) server'
9
9
  server 'http://localhost:3000', desc: 'Internal staging server for testing'
@@ -21,8 +21,8 @@ OpenApi::Config.tap do |c|
21
21
  # Getting started: https://swagger.io/docs/specification/basic-structure/
22
22
  c.open_api_docs = {
23
23
  blog_api: {
24
- # [REQUIRED] ZRO will scan all the descendants of the root_controller, then generate their docs.
25
- root_controller: ApiController,
24
+ # [REQUIRED] ZRO will scan all the descendants of the base_doc_class, then generate their docs.
25
+ base_doc_class: ApiController,
26
26
 
27
27
  # [REQUIRED] Info Object: The info section contains API information
28
28
  info: {
@@ -20,7 +20,7 @@ int32, float, date ...
20
20
  All the types you can use as following:
21
21
  - **String, 'binary', 'base64'**
22
22
  - **Integer, Long, 'int32', 'int64', Float, Double**
23
- - **File** (it will be converted to `{ type: 'string', format: Config.dft_file_format }`)
23
+ - **File** (it will be converted to `{ type: 'string', format: Config.file_format }`)
24
24
  - **Date, DateTime**
25
25
  - **Boolean**
26
26
  - **Array**: `Array[String]` or `[String]`
@@ -24,3 +24,19 @@ module OpenApi
24
24
  end
25
25
  end
26
26
  end
27
+
28
+ __END__
29
+
30
+ Inside schema:
31
+
32
+ "oneOf": [
33
+ {
34
+ "$ref": "#components/schemas/DogSchema"
35
+ },
36
+ {
37
+ "type": "string"
38
+ },
39
+ {
40
+ "type": "integer"
41
+ }
42
+ ]
@@ -1,19 +1,7 @@
1
1
  module OpenApi
2
2
  module Helpers
3
3
  def fusion
4
- proc { |a, b| a.merge!(b, &_fusion) }
5
- end
6
-
7
- def _fusion
8
- proc do |_common_key, x, y|
9
- if x.is_a?(Hash) && y.is_a?(Hash)
10
- x.merge(y, &_fusion)
11
- elsif x.is_a?(Array) && y.is_a?(Array)
12
- x.concat(y)
13
- else
14
- y
15
- end
16
- end
4
+ proc { |a, b| a.deep_merge!(b) { |common_key, va, vb| common_key == :required ? va + vb : vb } }
17
5
  end
18
6
 
19
7
  def truly_present?(obj)
@@ -32,7 +20,7 @@ module OpenApi
32
20
 
33
21
  # reducx.then_merge! => for Hash
34
22
  def reducx(*values)
35
- @assign = values.compact.reduce({ }, :merge).keep_if &value_present
23
+ @assign = values.compact.reduce({ }, :merge!).keep_if &value_present
36
24
  self
37
25
  end
38
26
 
@@ -69,7 +69,7 @@ module OpenApi
69
69
  elsif t.in? %w[ binary base64 ]
70
70
  { type: 'string', format: t }
71
71
  elsif t == 'file'
72
- { type: 'string', format: Config.dft_file_format }
72
+ { type: 'string', format: Config.file_format }
73
73
  elsif t == 'datetime'
74
74
  { type: 'string', format: 'date-time' }
75
75
  else # other string
@@ -110,7 +110,7 @@ module OpenApi
110
110
  { minItems: min, maxItems: max }
111
111
  else
112
112
  { minLength: min, maxLength: max }
113
- end.merge(enum: _enum).keep_if &value_present
113
+ end.merge!(enum: _enum).keep_if &value_present
114
114
  end
115
115
 
116
116
  def processed_range
data/lib/open_api.rb CHANGED
@@ -6,7 +6,7 @@ require 'open_api/dsl'
6
6
  module OpenApi
7
7
  include Generator
8
8
 
9
- cattr_accessor :paths_index do
9
+ cattr_accessor :routes_index do
10
10
  { }
11
11
  end
12
12
 
@@ -32,8 +32,8 @@ module OpenApi
32
32
  {
33
33
  # # [REQUIRED] At least one doc.
34
34
  # zero_rails: {
35
- # # [REQUIRED] ZRO will scan all the descendants of the root_controller, and then generate their docs.
36
- # root_controller: ApplicationController,
35
+ # # [REQUIRED] ZRO will scan all the descendants of the base_doc_class, and then generate their docs.
36
+ # base_doc_class: ApplicationController,
37
37
  #
38
38
  # # [REQUIRED] Info Object: The info section contains API information
39
39
  # info: {
@@ -47,7 +47,7 @@ module OpenApi
47
47
  }
48
48
  end
49
49
 
50
- cattr_accessor :dft_file_format do
50
+ cattr_accessor :file_format do
51
51
  'binary'
52
52
  end
53
53
 
@@ -4,9 +4,9 @@ module OpenApi
4
4
  base.class_eval do
5
5
  module_function
6
6
 
7
- def open_api name, root_controller:
7
+ def open_api name, base_doc_class:
8
8
  @api = name
9
- open_api_docs[name] = { root_controller: root_controller }
9
+ open_api_docs[name] = { base_doc_class: base_doc_class }
10
10
  end
11
11
 
12
12
  def info version:, title:, desc: '', **addition
@@ -23,16 +23,16 @@ module OpenApi
23
23
  end
24
24
 
25
25
  def base_auth scheme_name, other_info = { }
26
- security_scheme scheme_name, { type: 'http', scheme: 'basic' }.merge(other_info)
26
+ security_scheme scheme_name, { type: 'http', scheme: 'basic', **other_info }
27
27
  end
28
28
 
29
29
  def bearer_auth scheme_name, format = 'JWT', other_info = { }
30
- security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format }.merge(other_info)
30
+ security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format, **other_info }
31
31
  end
32
32
 
33
33
  def api_key scheme_name, field:, in: 'header', **other_info
34
34
  _in = binding.local_variable_get(:in)
35
- security_scheme scheme_name, { type: 'apiKey', name: field, in: _in }.merge(other_info)
35
+ security_scheme scheme_name, { type: 'apiKey', name: field, in: _in, **other_info }
36
36
  end
37
37
 
38
38
  def global_security_require scheme_name, scopes: [ ]
data/lib/open_api/dsl.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'open_api/dsl/api_info_obj'
1
+ require 'open_api/dsl/api_info'
2
2
  require 'open_api/dsl/components'
3
3
 
4
4
  module OpenApi
@@ -9,58 +9,59 @@ module OpenApi
9
9
 
10
10
  # TODO: Doc-Block Comments
11
11
  module ClassMethods
12
- def ctrl_path path
13
- @_ctrl_path = path
14
- @_apis_tag = path.split('/').last.camelize
12
+ def route_base path
13
+ @route_base = path
14
+ @doc_tag = path.split('/').last.camelize
15
15
  end
16
16
 
17
- def apis_tag name: nil, desc: '', external_doc_url: ''
18
- # current `tag`, this means that tags is currently divided by controllers.
19
- @_apis_tag = name if name.present?
20
- @_apis_tag ||= controller_name.camelize
21
- tag = (@_ctrl_infos = { })[:tag] = { name: @_apis_tag }
17
+ def doc_tag name: nil, desc: '', external_doc_url: nil
18
+ # apis will group by the tags.
19
+ @doc_tag = name if name.present?
20
+ @doc_tag ||= controller_name.camelize
21
+ tag = (@doc_info = { })[:tag] = { name: @doc_tag }
22
22
  tag[:description] = desc if desc.present?
23
- tag[:externalDocs] = { description: 'ref', url: external_doc_url } if external_doc_url.present?
23
+ tag[:externalDocs] = { description: 'ref', url: external_doc_url } if external_doc_url
24
24
  end
25
25
 
26
26
  def components &block
27
- apis_tag if @_ctrl_infos.nil?
28
- current_ctrl = @_ctrl_infos[:components] = Components.new
29
- current_ctrl.instance_exec(&block)
30
- current_ctrl.process_objs
27
+ doc_tag if @doc_info.nil?
28
+ current_doc = @doc_info[:components] = Components.new
29
+ current_doc.instance_exec(&block)
30
+ current_doc.process_objs
31
31
  end
32
32
 
33
- def api action, summary = '', http: nil, skip: [ ], use: [ ], &block
34
- apis_tag if @_ctrl_infos.nil?
33
+ def api action, summary = '', http: http_method = nil, skip: [ ], use: [ ], &block
34
+ doc_tag if @doc_info.nil?
35
35
  # select the routing info (corresponding to the current method) from routing list.
36
- action_path = "#{@_ctrl_path ||= controller_path}##{action}"
37
- routes_info = ctrl_routes_list&.select { |api| api[:action_path].match?(/^#{action_path}$/) }&.first
38
- pp "[ZRO Warning] Routing mapping failed: #{@_ctrl_path}##{action}" and return if routes_info.nil?
36
+ action_path = "#{@route_base ||= controller_path}##{action}"
37
+ routes = ctrl_routes_list&.select { |api| api[:action_path].match?(/^#{action_path}$/) }
38
+ pp "[ZRO Warning] Routing mapping failed: #{@route_base}##{action}" and return if routes.blank?
39
39
 
40
- api = ApiInfoObj.new(action_path, skip: Array(skip), use: Array(use))
41
- .merge! description: '', summary: summary, operationId: action, tags: [@_apis_tag],
42
- parameters: [ ], requestBody: '', responses: { }, security: [ ], servers: [ ]
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 = [ ]
46
- api.param_use = [ ] # `skip` and `use` only affect `api_dry`'s blocks
40
+ api = ApiInfo.new(action_path, skip: Array(skip), use: Array(use))
41
+ .merge! description: '', summary: summary, operationId: action, tags: [@doc_tag],
42
+ parameters: [ ], requestBody: '', responses: { }, security: [ ], servers: [ ]
43
+ [action, :all].each { |blk_key| @zro_dry_blocks&.[](blk_key)&.each { |blk| api.instance_eval(&blk) } }
44
+ api.param_use = api.param_skip = [ ] # `skip` and `use` only affect `api_dry`'s blocks
47
45
  api.instance_exec(&block) if block_given?
48
46
  api.process_objs
49
47
  api.delete_if { |_, v| v.blank? }
50
48
 
51
- path = (@_api_infos ||= { })[routes_info[:path]] ||= { }
52
- (http || routes_info[:http_verb]).split('|').each { |verb| path[verb] = api }
49
+ routes.each do |route|
50
+ path = (@api_info ||= { })[route[:path]] ||= { }
51
+ (http || route[:http_verb]).split('|').each { |verb| path[verb] = api }
52
+ end
53
+
53
54
  api
54
55
  end
55
56
 
56
57
  # method could be symbol array, like: %i[ .. ]
57
58
  def api_dry action = :all, desc = '', &block
58
- @_api_dry_blocks ||= { }
59
- Array(action).each { |a| (@_api_dry_blocks[a.to_sym] ||= [ ]) << block }
59
+ @zro_dry_blocks ||= { }
60
+ Array(action).each { |a| (@zro_dry_blocks[a.to_sym] ||= [ ]) << block }
60
61
  end
61
62
 
62
63
  def ctrl_routes_list
63
- Generator.routes_list[@_ctrl_path]
64
+ Generator.routes_list[@route_base]
64
65
  end
65
66
  end
66
67
  end
@@ -2,7 +2,7 @@ require 'open_api/dsl/common_dsl'
2
2
 
3
3
  module OpenApi
4
4
  module DSL
5
- class ApiInfoObj < Hash
5
+ class ApiInfo < Hash
6
6
  include DSL::CommonDSL
7
7
  include DSL::Helpers
8
8
 
@@ -57,12 +57,12 @@ module OpenApi
57
57
  # :export! => { type: Boolean }
58
58
  # }
59
59
  %i[ header header! path path! query query! cookie cookie! ].each do |param_type|
60
- define_method "do_#{param_type}" do |by:|
61
- by.each do |key, value|
60
+ define_method "do_#{param_type}" do |by:, **common_schema|
61
+ by.each do |p_name, schema|
62
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)
63
+ type, schema = schema.is_a?(Hash) ? [schema[:type], schema] : [schema, { }]
64
+ args = [ p_name.to_s.delete('!').to_sym, type, schema.reverse_merge!(common_schema) ]
65
+ param_type['!'] || p_name['!'] ? send("#{action}!", *args) : send(action, *args)
66
66
  end
67
67
  end
68
68
  end
@@ -75,7 +75,7 @@ module OpenApi
75
75
  def request_body required, media_type, data: { }, **options
76
76
  desc = options.delete(:desc) || ''
77
77
  self[:requestBody] = RequestBodyObj.new(required, desc) unless self[:requestBody].is_a?(RequestBodyObj)
78
- self[:requestBody].add_or_fusion(media_type, options.merge(data: data))
78
+ self[:requestBody].add_or_fusion(media_type, { data: data , **options })
79
79
  end
80
80
 
81
81
  # [ body body! ]
@@ -43,7 +43,7 @@ module OpenApi
43
43
  desc = options.delete(:desc) || ''
44
44
  cur = (self[:requestBodies] ||= { })[component_key]
45
45
  cur = RequestBodyObj.new(required, desc) unless cur.is_a?(RequestBodyObj)
46
- self[:requestBodies][component_key] = cur.add_or_fusion(media_type, options.merge(data: data))
46
+ self[:requestBodies][component_key] = cur.add_or_fusion(media_type, { data: data, **options })
47
47
  end
48
48
 
49
49
  # [ body body! ]
@@ -65,18 +65,18 @@ module OpenApi
65
65
  alias auth_scheme security_scheme
66
66
 
67
67
  def base_auth scheme_name, other_info = { }
68
- security_scheme scheme_name, { type: 'http', scheme: 'basic' }.merge(other_info)
68
+ security_scheme scheme_name, { type: 'http', scheme: 'basic', **other_info }
69
69
  end
70
70
  arrow_enable :base_auth
71
71
 
72
72
  def bearer_auth scheme_name, format = 'JWT', other_info = { }
73
- security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format }.merge(other_info)
73
+ security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format, **other_info }
74
74
  end
75
75
  arrow_enable :bearer_auth
76
76
 
77
77
  def api_key scheme_name, field:, in: 'header', **other_info
78
78
  _in = binding.local_variable_get(:in)
79
- security_scheme scheme_name, { type: 'apiKey', name: field, in: _in }.merge(other_info)
79
+ security_scheme scheme_name, { type: 'apiKey', name: field, in: _in, **other_info }
80
80
  end
81
81
  arrow_enable :api_key
82
82
 
@@ -16,7 +16,7 @@ module OpenApi
16
16
  _load_schema_based_on_show_attr(model)
17
17
  else
18
18
  model.columns.map { |column| _type_mapping(column) }
19
- end.compact.reduce({ }, :merge) rescue ''
19
+ end.compact.reduce({ }, :merge!) rescue ''
20
20
  end
21
21
 
22
22
  def _type_mapping(column)
@@ -1,7 +1,10 @@
1
+ require 'active_support/hash_with_indifferent_access'
1
2
  require 'open_api/config'
2
3
 
3
4
  module OpenApi
4
5
  module Generator
6
+ extend self
7
+
5
8
  def self.included(base)
6
9
  base.extend ClassMethods
7
10
  end
@@ -18,31 +21,33 @@ module OpenApi
18
21
  # :nocov:
19
22
  end
20
23
  Dir[*Array(Config.doc_location)].each { |file| require file }
21
- (doc_name || Config.docs.keys).map { |name| { name => generate_doc(name) } }.reduce({ }, :merge)
24
+ (doc_name || Config.docs.keys).map { |name| { name => generate_doc(name) } }.reduce({ }, :merge!)
22
25
  end
23
26
 
24
27
  def generate_doc(doc_name)
25
28
  settings = Config.docs[doc_name]
26
- doc = { openapi: '3.0.0' }.merge(settings.slice :info, :servers).merge(
29
+ doc = { openapi: '3.0.0', **settings.slice(:info, :servers) }.merge!(
27
30
  security: settings[:global_security], tags: [ ], paths: { },
28
31
  components: {
29
32
  securitySchemes: { }, schemas: { }, parameters: { }, requestBodies: { }
30
- }.merge(settings[:components] || { })
33
+ }.merge!(settings[:components] || { })
31
34
  )
32
35
 
33
- settings[:root_controller].descendants.each do |ctrl|
34
- ctrl_infos = ctrl.instance_variable_get('@_ctrl_infos')
35
- next if ctrl_infos.nil?
36
- doc[:paths].merge! ctrl.instance_variable_get('@_api_infos') || { }
37
- doc[:tags] << ctrl_infos[:tag]
38
- doc[:components].merge!(ctrl_infos[:components] || { }) { |_key, l, r| l.merge(r) }
39
- OpenApi.paths_index[ctrl.instance_variable_get('@_ctrl_path')] = doc_name
36
+ settings[:base_doc_class].descendants.each do |ctrl|
37
+ doc_info = ctrl.instance_variable_get('@doc_info')
38
+ next if doc_info.nil?
39
+
40
+ doc[:paths].merge!(ctrl.instance_variable_get('@api_info') || { })
41
+ doc[:tags] << doc_info[:tag]
42
+ doc[:components].deep_merge!(doc_info[:components] || { })
43
+ OpenApi.routes_index[ctrl.instance_variable_get('@route_base')] = doc_name
40
44
  end
45
+
41
46
  doc[:components].delete_if { |_, v| v.blank? }
42
47
  doc[:tags] = doc[:tags].sort { |a, b| a[:name] <=> b[:name] }
43
48
  doc[:paths] = doc[:paths].sort.to_h
44
49
 
45
- OpenApi.docs[doc_name] = ActiveSupport::HashWithIndifferentAccess.new(doc.delete_if { |_, v| v.blank? })
50
+ OpenApi.docs[doc_name] = HashWithIndifferentAccess.new(doc.delete_if { |_, v| v.blank? })
46
51
  end
47
52
 
48
53
  def write_docs(generate_files: true)
@@ -52,30 +57,31 @@ module OpenApi
52
57
  output_path = Config.file_output_path
53
58
  FileUtils.mkdir_p output_path
54
59
  max_length = docs.keys.map(&:size).sort.last
55
- # puts '[ZRO] * * * * * *'
56
60
  docs.each do |doc_name, doc|
57
61
  puts "[ZRO] `#{doc_name.to_s.rjust(max_length)}.json` has been generated."
58
62
  File.open("#{output_path}/#{doc_name}.json", 'w') { |file| file.write JSON.pretty_generate doc }
59
63
  end
60
64
  # :nocov:
61
65
  end
62
- end
66
+ end # end of module
63
67
 
64
- def self.routes_list
65
- routes =
66
- if (f = Config.rails_routes_file)
67
- File.read(f)
68
- else
69
- # :nocov:
70
- # ref https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/routes.rake
71
- require './config/routes'
72
- all_routes = Rails.application.routes.routes
73
- require 'action_dispatch/routing/inspector'
74
- inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
75
- inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, nil)
76
- # :nocov:
77
- end
68
+ def routes
69
+ @routes ||=
70
+ if (file = Config.rails_routes_file)
71
+ File.read(file)
72
+ else
73
+ # :nocov:
74
+ # ref https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/routes.rake
75
+ require './config/routes'
76
+ all_routes = Rails.application.routes.routes
77
+ require 'action_dispatch/routing/inspector'
78
+ inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
79
+ inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, nil)
80
+ # :nocov:
81
+ end
82
+ end
78
83
 
84
+ def routes_list
79
85
  @routes_list ||= routes.split("\n").drop(1).map do |line|
80
86
  next unless line.match?('#')
81
87
  infos = line.match(/[A-Z|].*/).to_s.split(' ') # => [GET, /api/v1/examples/:id, api/v1/examples#index]
@@ -90,14 +96,14 @@ module OpenApi
90
96
  end.compact.group_by { |api| api[:action_path].split('#').first } # => { "api/v1/examples" => [..] }, group by paths
91
97
  end
92
98
 
93
- def self.get_actions_by_ctrl_path(ctrl_path)
94
- routes_list[ctrl_path]&.map do |action_info|
99
+ def get_actions_by_route_base(route_base)
100
+ routes_list[route_base]&.map do |action_info|
95
101
  action_info[:action_path].split('#').last
96
102
  end
97
103
  end
98
104
 
99
- def self.find_path_httpverb_by(ctrl_path, action)
100
- routes_list[ctrl_path]&.map do |action_info|
105
+ def find_path_httpverb_by(route_base, action)
106
+ routes_list[route_base]&.map do |action_info|
101
107
  if action_info[:action_path].split('#').last == action.to_s
102
108
  return [ action_info[:path], action_info[:http_verb].split('|').first ]
103
109
  end
@@ -1,3 +1,3 @@
1
1
  module OpenApi
2
- VERSION = '1.5.1'
2
+ VERSION = '1.5.2'
3
3
  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.5.1
4
+ version: 1.5.2
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-21 00:00:00.000000000 Z
11
+ date: 2018-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -137,7 +137,7 @@ files:
137
137
  - lib/open_api/config.rb
138
138
  - lib/open_api/config_dsl.rb
139
139
  - lib/open_api/dsl.rb
140
- - lib/open_api/dsl/api_info_obj.rb
140
+ - lib/open_api/dsl/api_info.rb
141
141
  - lib/open_api/dsl/common_dsl.rb
142
142
  - lib/open_api/dsl/components.rb
143
143
  - lib/open_api/dsl/helpers.rb