zero-rails_openapi 1.3.0 → 1.3.1

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: 7670c75c3357ce813ab3664c7403386a9e544c58
4
- data.tar.gz: 00f1a35580391046946ce002d39ef66dad3d0a71
3
+ metadata.gz: 5b6fc0f663e643a98f744b0f75431c21a9484014
4
+ data.tar.gz: 2f0318d949040999a345d91b08f9d1ed63b525f3
5
5
  SHA512:
6
- metadata.gz: e149d59f5e44dcf5349f980debf0f000345a3bf398fe9084dda7733305af6a99c42b9aed21f2fc87eabda030ca8e24e0c423a10e8ab2617296ad136dd60bea53
7
- data.tar.gz: 12e6d7ad092fda104aa439dcf17c64bcb93d5a0e9467c1e5b4a27802d0ff21dc0c4a63c99523958f7bea7f174a877e43a04c0b5d1aad1f446343eb2e46e9a514
6
+ metadata.gz: 2e9a713e9bb2296ffb3bd9e0c5433256cf90ccf72135c92495d4eebb53778e53a151b6882bf47baf137c2b000b40fc181974f5cfa0dce45048665be7f05f29b4
7
+ data.tar.gz: 1691cb0d3d6e3e6517f6439ca869a7eeddf7032f6d3c9eb3118e446ac62a8d1e89da05d90cbfda7b5f32a63c70e4601749b11686b1c430664af8fd7426d1b74b
data/Gemfile CHANGED
@@ -3,4 +3,8 @@ source "https://rubygems.org"
3
3
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in zero-rails_openapi.gemspec
6
- gemspec
6
+ gemspec
7
+
8
+ ruby '>= 2.3.0'
9
+
10
+ gem 'activesupport'
@@ -1,12 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zero-rails_openapi (1.3.0)
4
+ zero-rails_openapi (1.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ activesupport (5.1.4)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (~> 0.7)
12
+ minitest (~> 5.1)
13
+ tzinfo (~> 1.1)
14
+ concurrent-ruby (1.0.5)
9
15
  diff-lcs (1.3)
16
+ i18n (0.9.0)
17
+ concurrent-ruby (~> 1.0)
18
+ minitest (5.10.3)
10
19
  rake (10.5.0)
11
20
  rspec (3.6.0)
12
21
  rspec-core (~> 3.6.0)
@@ -21,15 +30,22 @@ GEM
21
30
  diff-lcs (>= 1.2.0, < 2.0)
22
31
  rspec-support (~> 3.6.0)
23
32
  rspec-support (3.6.0)
33
+ thread_safe (0.3.6)
34
+ tzinfo (1.2.4)
35
+ thread_safe (~> 0.1)
24
36
 
25
37
  PLATFORMS
26
38
  ruby
27
39
 
28
40
  DEPENDENCIES
41
+ activesupport
29
42
  bundler (~> 1.16.a)
30
43
  rake (~> 10.0)
31
44
  rspec (~> 3.0)
32
45
  zero-rails_openapi!
33
46
 
47
+ RUBY VERSION
48
+ ruby 2.4.1p111
49
+
34
50
  BUNDLED WITH
35
51
  1.16.0.pre.2
data/README.md CHANGED
@@ -29,7 +29,7 @@ but I dont have enough time now = ▽ =
29
29
  - [Global DRYing](#trick2---global-drying)
30
30
  - [Auto generate description](#trick3---auto-generate-description)
31
31
  - [Skip or Use parameters define in api_dry](#trick4---skip-or-use-parameters-define-in-api_dry)
32
- - [Atuo Generate index/show Actions's Responses Based on DB Schema](#trick5)
32
+ - [Atuo Generate index/show Actions's Responses Based on DB Schema](#trick5---auto-generate-indexshow-actionss-responses-based-on-db-schema)
33
33
  - [Troubleshooting](#troubleshooting)
34
34
 
35
35
  ## About OAS
@@ -96,7 +96,7 @@ end
96
96
  You can also set the *global configuration(/component)* of OAS:
97
97
  Server Object / Security Scheme Object / Security Requirement Object ...
98
98
 
99
- For more detailed configuration: [open_api.rb](https://github.com/zhandao/zero-rails_openapi/blob//examples/open_api.rb)
99
+ For more detailed configuration: [open_api.rb](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/open_api.rb)
100
100
 
101
101
  ## Usage
102
102
 
@@ -106,19 +106,19 @@ For more detailed configuration: [open_api.rb](https://github.com/zhandao/zero-r
106
106
 
107
107
  ```ruby
108
108
  # application_controller.rb
109
- require 'open_api/dsl'
110
-
111
109
  class ApplicationController < ActionController::API
112
110
  include OpenApi::DSL
113
111
  end
114
112
  ```
115
113
 
116
- #### \> [DSL Usage Example](https://github.com/zhandao/zero-rails_openapi/blob/masterdocumentation/examples/examples_controller.rb)
114
+ #### \> [DSL Usage Example](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/examples_controller.rb)
117
115
 
118
116
  (TODO: I consider that, here should be put in a the simplest case.)
119
117
  ```ruby
120
118
  class Api::V1::ExamplesController < Api::V1::BaseController
121
- apis_set 'ExamplesController\'s APIs' do
119
+ apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
120
+
121
+ components do
122
122
  schema :Dog => [ String, must_be: 'doge' ]
123
123
  query! :QueryCompUuid => [ :product_uuid, String, desc: 'product uuid' ]
124
124
  path! :PathCompId => [ :id, Integer, desc: 'user id' ]
@@ -169,22 +169,33 @@ end
169
169
  ctrl_path 'api/v1/examples'
170
170
  ```
171
171
  This option 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
- [Here's a trick](#write-the-dsl-somewhere-else-recommend): Using `ctrl_path`, you can write the DSL somewhere else
172
+ [Here's a trick](#trick1---write-the-dsl-somewhere-else): Using `ctrl_path`, you can write the DSL somewhere else
173
173
  to simplify the current controller.
174
174
  \* take the tag from `path.split('/').last`
175
175
 
176
- - `apis_set` [Optional]
176
+ - `apis_tag` [Optional]
177
177
 
178
178
  ```ruby
179
179
  # method signature
180
- apis_set desc = '', external_doc_url = '', &block
180
+ apis_tag name: nil, desc: '', external_doc_url: ''
181
181
  # usage
182
- apis_set 'ExamplesController\'s APIs' do
182
+ apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
183
+ ```
184
+ desc and external_doc_url will be output to the tags[the current tag] (tag defaults to controller_name ), but are optional.
185
+
186
+ - `components` [Optional]
187
+
188
+ ```ruby
189
+ # method signature
190
+ components &block
191
+ # usage
192
+ components do
183
193
  # DSL for defining components
194
+ schema :Dog => [ String, dft: { id: 1, name: 'pet' } ]
184
195
  end
185
196
  ```
186
- desc and external_doc_url will be output to the tags[the current tag] (tag defaults to controller_name ), but are optional.
187
- the focus is on the block, the DSL methods in the block will generate components.
197
+ Component can be used to simplify your DSL code in `*_ref` methods.
198
+ Each RefObj you define is associated with components through component key.
188
199
 
189
200
  - `api_dry` [Optional]
190
201
 
@@ -207,15 +218,15 @@ end
207
218
 
208
219
  ```ruby
209
220
  # method signature
210
- open_api method, summary = '', options = { }, &block
221
+ open_api method, summary = '', builder: nil, skip: [ ], use: [ ], &block
211
222
  # usage
212
- open_api :index, '(SUMMARY) this api blah blah ...', builder: template1 do end
223
+ open_api :index, '(SUMMARY) this api blah blah ...', builder: :template1 do end
213
224
  ```
214
- If pass `builder` or `bd` to the third parameter,
215
- and `generate_jbuilder_file` in your setting file is set `true`,
225
+ If pass `builder` to the third parameter,
226
+ and `generate_jbuilder_file` is set `true` in your initializer file,
216
227
  ZRO will generate JBuilder file by using specified template that you set
217
228
  `template1` in your setting file.
218
- For example, see: [open_api.rb](https://github.com/zhandao/zero-rails_openapi/blob//examples/open_api.rb)
229
+ You can see: [open_api.rb](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/open_api.rb)
219
230
 
220
231
 
221
232
  #### \>\> DSL methods inside *open_api* and *api_dry*'s block ([source code](https://github.com/zhandao/zero-rails_openapi/blob/master/lib/open_api/dsl_inside_block.rb):: ApiInfoObj)
@@ -241,7 +252,7 @@ parameters, request body, responses, securities, servers.
241
252
 
242
253
  ```ruby
243
254
  # method signature
244
- desc desc, inputs_descs = { }
255
+ desc desc, param_descs = { }
245
256
  # usage
246
257
  desc 'current API\'s description',
247
258
  id: 'user id',
@@ -257,7 +268,8 @@ parameters, request body, responses, securities, servers.
257
268
  - `param`
258
269
  - `param_ref`
259
270
  - `header`, `path`, `query`, `cookie` and bang methods: `header!`, `path!`, `query!`, `cookie!`
260
- **The bang method(`!`) means it is required, so it is optional without `!`, the same below.**
271
+ - `do_* by: { }`
272
+ **The bang method(`!`) means it is required, so without `!` means it is optional. the same below.**
261
273
 
262
274
  Define the parameters for the API(operation).
263
275
  You can use the Reference Object to link to parameters that are defined at the components/parameters by method param_ref().
@@ -266,24 +278,35 @@ parameters, request body, responses, securities, servers.
266
278
  # method signature
267
279
  param param_type, name, type, required, schema_hash = { }
268
280
  # usage
269
- param :query, :page, Integer, :req, range: { gt: 0, le: 5 }, desc: 'page'
281
+ param :query, :page, Integer, :req, range: { gt: 0, le: 5 }, desc: 'page'
270
282
 
271
283
  # method signature
272
284
  param_ref component_key, *component_keys
273
285
  # usage
274
286
  param_ref :PathCompId
275
- param_ref :PathCompId, :QueryCompUuid, ...
287
+ param_ref :PathCompId, :QueryComp#, ...
276
288
 
277
289
  # method signature
278
290
  header name, type, schema_hash = { }
279
291
  header! name, type, schema_hash = { }
280
292
  query! name, type, schema_hash = { }
281
293
  # usage
282
- header! :'Token', String
283
- query! :done, Boolean, must_be: false, default: true
294
+ header! 'Token', String
295
+ query! :read, Boolean, must_be: true, default: false
296
+
297
+ # method signature
298
+ do_query by:
299
+ # usage
300
+ do_query by: {
301
+ :search_type => { type: String },
302
+ :export! => { type: Boolean }
303
+ }
304
+ # Same as below, but a little more succinctly
305
+ query :search_type, String
306
+ query! :export, Boolean
284
307
  ```
285
308
 
286
- [**>> More About Param DSL <<**](https://github.com/zhandao/zero-rails_openapi/blob//parameter.md)
309
+ [**>> More About Param DSL <<**](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/parameter.md)
287
310
 
288
311
  - request_body family methods (OAS - [Request Body Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#requestBodyObject))
289
312
  - `request_body`
@@ -307,7 +330,7 @@ parameters, request body, responses, securities, servers.
307
330
  body_ref :Body
308
331
 
309
332
  # method signature
310
- body(!) media_type, desc = '', schema_hash = { }
333
+ body! media_type, desc = '', schema_hash = { }
311
334
  # usage
312
335
  body :json
313
336
 
@@ -369,7 +392,7 @@ parameters, request body, responses, securities, servers.
369
392
 
370
393
  - server: TODO
371
394
 
372
- #### \>\> DSL methods inside apis_set'block ([code source](https://github.com/zhandao/zero-rails_openapi/blob/master/lib/open_api/dsl_inside_block.rb):: CtrlInfoObj )
395
+ #### \>\> DSL methods inside components'block ([code source](https://github.com/zhandao/zero-rails_openapi/blob/master/lib/open_api/dsl_inside_block.rb):: CtrlInfoObj )
373
396
 
374
397
  (Here corresponds to OAS [Components Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#componentsObject))
375
398
 
@@ -409,7 +432,7 @@ The DSL methods used to generate the components in this block are:
409
432
  # or (unrecommended)
410
433
  schema :Dog, { id!: Integer, name: String }, dft: { id: 1, name: 'pet' }
411
434
  ```
412
- *: see: [Type](https://github.com/zhandao/zero-rails_openapi/blob//parameter.md#type)
435
+ *: see: [Type](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/parameter.md#type)
413
436
 
414
437
  ### Generate JSON Documentation File
415
438
 
@@ -465,7 +488,7 @@ Notes: convention is the file name ends with `_doc.rb`
465
488
 
466
489
  Method `api_dry` is for DRY but its scope is limited to the current controller.
467
490
 
468
- I have no idea of best practices, But you can look at this [file](https://github.com/zhandao/zero-rails_openapi/blob/masterdocumentation/examples/auto_gen_doc.rb).
491
+ I have no idea of best practices, But you can look at this [file](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/auto_gen_doc.rb).
469
492
  The implementation of the file is: do `api_dry` when inherits the base controller inside `inherited` method.
470
493
 
471
494
  #### Trick3 - Auto Generate Description
@@ -485,7 +508,7 @@ Notice `!` use (`search_type!`, `desc!`), it tells ZRO to append
485
508
  information that analyzed from definitions (enum, must_be ..) to description automatically.
486
509
 
487
510
  Any one of above will generate:
488
- `search field, allows:<br/>1/ name<br/>2/ creator,<br/>3/ category<br/>4/ price<br/>`
511
+ > search field, allows:<br/>1/ name<br/>2/ creator,<br/>3/ category<br/>4/ price<br/>
489
512
 
490
513
  ZRO also allows you use Hash to define `enum`:
491
514
  ```ruby
@@ -497,7 +520,7 @@ query :view, String, enum: {
497
520
  'cheap goods': :borrow,
498
521
  }
499
522
  ```
500
- Read this [file](https://github.com/zhandao/zero-rails_openapi/blob/examples/auto_gen_desc.rb) to learn more.
523
+ Read this [file](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/auto_gen_desc.rb) to learn more.
501
524
 
502
525
  #### Trick4 - Skip or Use parameters define in api_dry
503
526
 
@@ -506,13 +529,13 @@ Pass `skip: []` and `use: []` to `open_api` like following code:
506
529
  open_api :index, 'desc', builder: :index, skip: [ :Token ]
507
530
  ```
508
531
 
509
- Look at this [file](https://github.com/zhandao/zero-rails_openapi/blob/examples/goods_doc.rb) to learn more.
532
+ Look at this [file](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/goods_doc.rb) to learn more.
510
533
 
511
- #### Trick5 - Auto Generate index/show Actions's Responses Based on DB Schema
534
+ #### Trick5 - Auto Generate index/show Actions's Response-Types Based on DB Schema
512
535
 
513
536
  Use method `load_schema` in `api_dry`.
514
537
 
515
- See this [file](https://github.com/zhandao/zero-rails_openapi/blob/examples/auto_gen_doc.rb#L51) for uasge information.
538
+ See this [file](https://github.com/zhandao/zero-rails_openapi/blob/master/documentation/examples/auto_gen_doc.rb#L51) for uasge information.
516
539
 
517
540
 
518
541
  ## Troubleshooting
@@ -22,7 +22,7 @@ module AutoGenDoc
22
22
  ctrl_path = try(:controller_path) || instance_variable_get('@_ctrl_path')
23
23
  ::OpenApi::Generator.get_actions_by_ctrl_path(ctrl_path)&.each do |action|
24
24
  api_dry action do
25
- header! :Token, String, desc: 'user token'
25
+ header! 'Token', String, desc: 'user token'
26
26
 
27
27
  # Common :index parameters
28
28
  if action == 'index'
@@ -73,9 +73,8 @@ module AutoGenDoc
73
73
  # # api/v1/examples#index => ExamplesError
74
74
  # error_class_name = action_path.split('#').first.split('/').last.camelize.concat('Error')
75
75
  # error_class = Object.const_get(error_class_name) rescue next
76
- # errors = error_class.errors
77
- # cur_errs = (errors[action.to_sym] || []) + (errors[:private] || [ ]) + (errors[:_public] || [ ])
78
- # cur_errs.each do |error|
76
+ # cur_api_errs = error_class.errors.values_at(action.to_sym, :private, :_public).flatten.compact.uniq
77
+ # cur_api_errs.each do |error|
79
78
  # info = error_class.send(error, :info)
80
79
  # response info[:code], info[:msg]
81
80
  # end
@@ -1,5 +1,7 @@
1
1
  class Api::V1::ExamplesController < Api::V1::BaseController
2
- apis_set 'ExamplesController\'s APIs' do
2
+ apis_tag name: 'ExampleTagName', desc: 'ExamplesController\'s APIs'
3
+
4
+ components do
3
5
  schema :Dog => [{
4
6
  id!: Integer,
5
7
  name: { type: String, must_be: 'zhandao', desc: 'name' }
@@ -1,7 +1,7 @@
1
1
  class V2::GoodsDoc < BaseDoc
2
2
 
3
3
  open_api :index, 'Get list of Goods.', builder: :index,
4
- use: [ :Token ] do # use parameters write in AutoGenDoc#api_dry
4
+ use: [ 'Token' ] do # use parameters write in AutoGenDoc#api_dry
5
5
  # skip: %i[ Token ] do # you can also skip parameters
6
6
  desc 'listing Goods',
7
7
  view!: 'search view, allows::<br/>',
@@ -18,7 +18,7 @@ class V2::GoodsDoc < BaseDoc
18
18
  end
19
19
 
20
20
 
21
- open_api :create, 'Create a Good', builder: :success_or_not, use: token do
21
+ open_api :create, 'Create a Good', builder: :success_or_not, use: 'Token' do
22
22
  form! 'for creating a good', data: {
23
23
  :name! => { type: String, desc: 'good\'s name' },
24
24
  :category_id! => { type: Integer, desc: 'sub_category\'s id', npmt: true, range: { ge: 1 }, as: :cate },
@@ -31,8 +31,8 @@ class V2::GoodsDoc < BaseDoc
31
31
  end
32
32
 
33
33
 
34
- open_api :show, 'Show a Good.', builder: :show, use: [ :Token, :id ]
34
+ open_api :show, 'Show a Good.', builder: :show, use: [ 'Token', :id ]
35
35
 
36
36
 
37
- open_api :destroy, 'Delete a Good.', builder: :success_or_not, use: [ :Token, :id ]
37
+ open_api :destroy, 'Delete a Good.', builder: :success_or_not, use: [ 'Token', :id ]
38
38
  end
@@ -87,45 +87,49 @@ OpenApi::Config.tap do |c|
87
87
  c.overwrite_jbuilder_file = false
88
88
  c.jbuilder_templates = {
89
89
  index: (
90
- <<-FILE
91
- json.partial! 'api/base', total: @data.count
92
-
93
- json.data do
94
- # @data = @data.page(@_page).per(@_rows) if @_page || @_rows
95
- # json.array! @data do |datum|
96
- json.array! @data.page(@_page).per(@_rows) do |datum|
97
- json.(datum, *datum.show_attrs) if datum.present?
98
- end
99
- end
90
+ <<~FILE
91
+ # *** Generated by ZRO ***
92
+ json.partial! 'api/base', total: @data.size
93
+
94
+ json.data do
95
+ # @data = @data.page(@_page).per(@_rows) if @_page || @_rows
96
+ # json.array! @data do |datum|
97
+ json.array! @data.page(@_page).per(@_rows) do |datum|
98
+ json.(datum, *datum.show_attrs) if datum.present?
99
+ end
100
+ end
100
101
  FILE
101
102
  ),
102
103
 
103
104
  show: (
104
- <<-FILE
105
- json.partial! 'api/base', total: 1
106
-
107
- json.data do
108
- json.array! [ @data ] do |datum|
109
- json.(datum, *datum.show_attrs) if datum.present?
110
- end
111
- end
105
+ <<~FILE
106
+ # *** Generated by ZRO ***
107
+ json.partial! 'api/base', total: 1
108
+
109
+ json.data do
110
+ json.array! [ @data ] do |datum|
111
+ json.(datum, *datum.show_attrs) if datum.present?
112
+ end
113
+ end
112
114
  FILE
113
115
  ),
114
116
 
115
117
  success: (
116
- <<-FILE
117
- json.partial! 'api/success'
118
+ <<~FILE
119
+ # *** Generated by ZRO ***
120
+ json.partial! 'api/success'
118
121
  FILE
119
122
  ),
120
123
 
121
124
  success_or_not: (
122
- <<-FILE
123
- unless @status
124
- # @_code, @_msg = @error_info.present? ? @error_info : ApiError.action_failed.info
125
- end
126
-
127
- json.partial! 'api/base', total: 0
128
- json.data ''
125
+ <<~FILE
126
+ # *** Generated by ZRO ***
127
+ unless @status
128
+ # @_code, @_msg = @error_info.present? ? @error_info : ApiError.action_failed.info
129
+ end
130
+
131
+ json.partial! 'api/base', total: 0
132
+ json.data ''
129
133
  FILE
130
134
  ),
131
135
  }
@@ -134,4 +138,4 @@ end
134
138
 
135
139
  Object.const_set('Boolean', 'boolean') # Support `Boolean` writing in DSL
136
140
 
137
- OpenApi.write_docs # Generate doc when Rails initializing
141
+ OpenApi.write_docs generate_files: !Rails.env.production?
@@ -8,7 +8,9 @@ module OpenApi
8
8
  include Helpers
9
9
 
10
10
  attr_accessor :processed, :code, :media_type
11
- def initialize(code, desc, media_type, schema_hash)
11
+ def initialize(desc, media_type, schema_hash)
12
+ @schema_hash = schema_hash
13
+ @mt = media_type
12
14
  self.code = code.to_s
13
15
  self.media_type = MediaTypeObj.new(media_type, schema_hash)
14
16
  self.processed = { description: desc }
@@ -16,7 +18,13 @@ module OpenApi
16
18
 
17
19
  def process
18
20
  assign(media_type.process).to_processed 'content'
19
- { code => processed }
21
+ processed
22
+ end
23
+
24
+ def override type_hash
25
+ @schema_hash[:type].merge!(type_hash)
26
+ self.media_type = MediaTypeObj.new(@mt, @schema_hash)
27
+ self
20
28
  end
21
29
  end
22
30
  end
@@ -40,7 +40,7 @@ module OpenApi
40
40
 
41
41
  reduceee(processed_desc options).then_merge!
42
42
  end
43
- alias_method :process, :process_for
43
+ alias process process_for
44
44
 
45
45
  def preprocess_with_desc desc, param_name = nil
46
46
  self.__desc = desc
@@ -109,7 +109,7 @@ module OpenApi
109
109
  }
110
110
  t.each do |prop_name, prop_type|
111
111
  @prop_name = prop_name
112
- _schema[:required] << "#{prop_name}".delete('!') if "#{prop_name}".match? '!'
112
+ _schema[:required] << "#{prop_name}".delete('!') if prop_name['!']
113
113
  _schema[:properties]["#{prop_name}".delete('!').to_sym] = recursive_obj_type prop_type
114
114
  end
115
115
  _schema.keep_if &value_present
@@ -1,5 +1,9 @@
1
+ require 'open_api/config_dsl'
2
+
1
3
  module OpenApi
2
4
  module Config
5
+ include ConfigDSL
6
+
3
7
  # [REQUIRED] The location where .json doc file will be output.
4
8
  cattr_accessor :file_output_path do
5
9
  'public/open_api'
@@ -49,45 +53,49 @@ module OpenApi
49
53
  cattr_accessor :jbuilder_templates do
50
54
  {
51
55
  index: (
52
- <<-FILE
53
- json.partial! 'api/base', total: @data.count
54
-
55
- json.data do
56
- # @data = @data.page(@_page).per(@_rows) if @_page || @_rows
57
- # json.array! @data do |datum|
58
- json.array! @data.page(@_page).per(@_rows) do |datum|
59
- json.(datum, *datum.show_attrs) if datum.present?
60
- end
61
- end
56
+ <<~FILE
57
+ # *** Generated by ZRO ***
58
+ json.partial! 'api/base', total: @data.size
59
+
60
+ json.data do
61
+ # @data = @data.page(@_page).per(@_rows) if @_page || @_rows
62
+ # json.array! @data do |datum|
63
+ json.array! @data.page(@_page).per(@_rows) do |datum|
64
+ json.(datum, *datum.show_attrs) if datum.present?
65
+ end
66
+ end
62
67
  FILE
63
68
  ),
64
69
 
65
70
  show: (
66
- <<-FILE
67
- json.partial! 'api/base', total: 1
68
-
69
- json.data do
70
- json.array! [ @data ] do |datum|
71
- json.(datum, *datum.show_attrs) if datum.present?
72
- end
73
- end
71
+ <<~FILE
72
+ # *** Generated by ZRO ***
73
+ json.partial! 'api/base', total: 1
74
+
75
+ json.data do
76
+ json.array! [ @data ] do |datum|
77
+ json.(datum, *datum.show_attrs) if datum.present?
78
+ end
79
+ end
74
80
  FILE
75
81
  ),
76
82
 
77
83
  success: (
78
- <<-FILE
79
- json.partial! 'api/success'
84
+ <<~FILE
85
+ # *** Generated by ZRO ***
86
+ json.partial! 'api/success'
80
87
  FILE
81
88
  ),
82
89
 
83
90
  success_or_not: (
84
- <<-FILE
85
- unless @status
86
- # @_code, @_msg = @error_info.present? ? @error_info : ApiError.action_failed.info
87
- end
88
-
89
- json.partial! 'api/base', total: 0
90
- json.data ''
91
+ <<~FILE
92
+ # *** Generated by ZRO ***
93
+ unless @status
94
+ # @_code, @_msg = @error_info.present? ? @error_info : ApiError.action_failed.info
95
+ end
96
+
97
+ json.partial! 'api/base', total: 0
98
+ json.data ''
91
99
  FILE
92
100
  ),
93
101
  }
@@ -0,0 +1,13 @@
1
+ module OpenApi
2
+ module ConfigDSL
3
+ def self.included(base)
4
+ base.class_eval do
5
+ module_function
6
+
7
+ def info
8
+ 1
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,5 @@
1
- require 'open_api/dsl_inside_block'
1
+ require 'open_api/dsl/api_info_obj'
2
+ require 'open_api/dsl/ctrl_info_obj'
2
3
 
3
4
  module OpenApi
4
5
  module DSL
@@ -13,46 +14,45 @@ module OpenApi
13
14
  @_apis_tag = path.split('/').last.camelize
14
15
  end
15
16
 
16
- def apis_set desc = '', external_doc_url = '', &block
17
- @_ctrl_infos = { }
17
+ def apis_tag name: nil, desc: '', external_doc_url: ''
18
18
  # current `tag`, this means that tags is currently divided by controllers.
19
- tag = @_ctrl_infos[:tag] = { name: @_apis_tag ||= controller_name.camelize }
19
+ @_apis_tag = name if name.present?
20
+ @_apis_tag ||= controller_name.camelize
21
+ tag = (@_ctrl_infos = { })[:tag] = { name: @_apis_tag }
20
22
  tag[:description] = desc if desc.present?
21
23
  tag[:externalDocs] = { description: 'ref', url: external_doc_url } if external_doc_url.present?
24
+ end
22
25
 
26
+ def components &block
27
+ apis_tag if @_ctrl_infos.nil?
23
28
  current_ctrl = @_ctrl_infos[:components] = CtrlInfoObj.new
24
- current_ctrl.instance_eval &block if block_given?
29
+ current_ctrl.instance_eval &block
30
+ current_ctrl._process_objs
25
31
  end
26
32
 
27
- def open_api method, summary = '', options = { }, &block
28
- apis_set if @_ctrl_infos.nil?
33
+ def open_api method, summary = '', builder: nil, skip: [ ], use: [ ], &block
34
+ apis_tag if @_ctrl_infos.nil?
29
35
 
30
36
  # select the routing info (corresponding to the current method) from the routing list.
31
37
  action_path = "#{@_ctrl_path ||= controller_path}##{method}"
32
38
  routes_info = ctrl_routes_list&.select { |api| api[:action_path].match? /^#{action_path}$/ }&.first
33
39
  pp "[ZRO Warnning] Routing mapping failed: #{@_ctrl_path}##{method}" and return if routes_info.nil?
40
+ Generator.generate_builder_file(action_path, builder) if builder.present?
34
41
 
35
42
  # structural { #path: { #http_method:{ } } }, for pushing into Paths Object.
36
43
  path = (@_api_infos ||= { })[routes_info[:path]] ||= { }
37
44
  current_api = path[routes_info[:http_verb]] =
38
- ApiInfoObj.new(action_path, options.slice(:skip, :use))
45
+ ApiInfoObj.new(action_path, skip: skip, use: use)
39
46
  .merge! description: '', summary: summary, operationId: method, tags: [@_apis_tag],
40
- parameters: [ ], requestBody: '', responses: { }, security: [ ], servers: [ ]
41
-
42
- if (builder = options.values_at(:builder, :bd, :jbuilder).compact.first).present?
43
- Generator
44
- .generate_builder_file path: action_path.split('#').first,
45
- action: action_path.split('#').last,
46
- builder: builder
47
- end
47
+ parameters: [ ], requestBody: '', responses: { }, security: [ ], servers: [ ]
48
48
 
49
49
  current_api.tap do |api|
50
50
  [method, :all].each do |key| # blocks_store_key
51
51
  @_apis_blocks&.[](key)&.each { |blk| api.instance_eval &blk }
52
52
  end
53
- api.param_use = nil
53
+ api.param_use = [ ] # skip 和 use 是对 dry 块而言的
54
54
  api.instance_eval &block if block_given?
55
- api.instance_eval { process_params }
55
+ api._process_objs
56
56
  api.delete_if { |_, v| v.blank? }
57
57
  end
58
58
  end
@@ -0,0 +1,124 @@
1
+ require 'open_api/dsl/common_dsl'
2
+
3
+ module OpenApi
4
+ module DSL
5
+ class ApiInfoObj < Hash
6
+ include DSL::CommonDSL
7
+ include DSL::Helpers
8
+
9
+ attr_accessor :action_path, :param_skip, :param_use, :param_descs
10
+
11
+ def initialize(action_path, skip: [ ], use: [ ])
12
+ self.action_path = action_path
13
+ self.param_skip = skip
14
+ self.param_use = use
15
+ self.param_descs = { }
16
+ end
17
+
18
+ def this_api_is_invalid! explain = ''
19
+ self[:deprecated] = true
20
+ end
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!
25
+
26
+ def desc desc, param_descs = { }
27
+ self.param_descs = param_descs
28
+ self[:description] = desc
29
+ end
30
+
31
+ def param param_type, name, type, required, schema_hash = { }
32
+ return if param_skip.include?(name)
33
+ return if param_use.present? && !param_use.include?(name)
34
+
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?
38
+
39
+ param_obj = ParamObj.new(name, param_type, type, required, schema_hash)
40
+ # The definition of the same name parameter will be overwritten
41
+ index = self[:parameters].map { |p| p.processed[:name] if p.is_a? ParamObj }.index name
42
+ index.present? ? self[:parameters][index] = param_obj : self[:parameters] << param_obj
43
+ end
44
+
45
+ # Support this writing: (just like `form '', data: { }`)
46
+ # do_query by: {
47
+ # :search_type => { type: String },
48
+ # :export! => { type: Boolean }
49
+ # }
50
+ %i[header header! path path! query query! cookie cookie!].each do |param_type|
51
+ define_method "do_#{param_type}" do |by:|
52
+ by.each do |key, value|
53
+ args = [ key.dup.to_s.delete('!'), value.delete(:type), value ]
54
+ key.to_s['!'] ? send("#{param_type}!", *args) : send(param_type, *args)
55
+ end
56
+ end unless param_type.to_s['!']
57
+ end
58
+
59
+ def _param_agent name, type, schema_hash = { }
60
+ param "#{@param_type}".delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
61
+ end
62
+
63
+ def param_ref component_key, *keys
64
+ self[:parameters].concat([component_key].concat(keys).map { |key| RefObj.new(:parameter, key).process })
65
+ end
66
+
67
+ def request_body required, media_type, desc = '', schema_hash = { }
68
+ self[:requestBody] = RequestBodyObj.new(required, media_type, desc, schema_hash).process
69
+ end
70
+
71
+ def _request_body_agent media_type, desc = '', schema_hash = { }
72
+ request_body (@method_name['!'] ? :req : :opt), media_type, desc, schema_hash
73
+ end
74
+
75
+ def body_ref component_key
76
+ self[:requestBody] = RefObj.new(:requestBody, component_key).process
77
+ end
78
+
79
+ def override_response code, type_hash
80
+ _response = self[:responses].fetch(code)
81
+ self[:responses][code] = _response.override(type_hash).process
82
+ end
83
+
84
+ def response_ref code_compkey_hash
85
+ code_compkey_hash.each do |code, component_key|
86
+ self[:responses][code] = RefObj.new(:response, component_key).process
87
+ end
88
+ end
89
+
90
+ # TODO: 目前只能写一句 request body,包括 form 和 file, 需要同时支持一下扁平化
91
+ def form desc = '', schema_hash = { }
92
+ body :form, desc, schema_hash
93
+ end
94
+ def form! desc = '', schema_hash = { }
95
+ body! :form, desc, schema_hash
96
+ end
97
+ def file media_type, desc = '', schema_hash = { type: File }
98
+ body media_type, desc, schema_hash
99
+ end
100
+ def file! media_type, desc = '', schema_hash = { type: File }
101
+ body! media_type, desc, schema_hash
102
+ end
103
+
104
+ def security scheme_name, requirements = [ ]
105
+ self[:security] << { scheme_name => requirements }
106
+ end
107
+
108
+ def server url, desc
109
+ self[:servers] << { url: url, description: desc }
110
+ end
111
+
112
+
113
+ def _process_objs
114
+ self[:parameters]&.each_with_index do |p, index|
115
+ self[:parameters][index] = p.process if p.is_a?(ParamObj)
116
+ end
117
+
118
+ self[:responses]&.each do |code, obj|
119
+ self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
120
+ end
121
+ end
122
+ end # ----------------------------------------- end of ApiInfoObj
123
+ end
124
+ end
@@ -0,0 +1,45 @@
1
+ require 'oas_objs/schema_obj'
2
+ require 'oas_objs/param_obj'
3
+ require 'oas_objs/response_obj'
4
+ require 'oas_objs/request_body_obj'
5
+ require 'oas_objs/ref_obj'
6
+ require 'open_api/dsl/helpers'
7
+
8
+ module OpenApi
9
+ module DSL
10
+ module CommonDSL
11
+ %i[ header header! path path! query query! cookie cookie! ].each do |param_type|
12
+ define_method param_type do |*args|
13
+ @param_type = param_type
14
+ _param_agent *args
15
+ end
16
+ end
17
+
18
+ %i[ body body! ].each do |method|
19
+ define_method method do |*args|
20
+ @method_name = method
21
+ _request_body_agent *args
22
+ end
23
+ end
24
+
25
+ # `code`: when defining components, `code` means `component_key`
26
+ def response code, desc, media_type = nil, schema_hash = { }
27
+ (self[:responses] ||= { })[code] = ResponseObj.new(desc, media_type, schema_hash)
28
+ end
29
+
30
+ def default_response desc, media_type = nil, schema_hash = { }
31
+ response :default, desc, media_type, schema_hash
32
+ end
33
+
34
+ { # alias_methods mapping
35
+ response: %i[ error_response resp ],
36
+ default_response: %i[ dft_resp dft_response ],
37
+ error_response: %i[ other_response oth_resp error err_resp ],
38
+ }.each do |original_name, aliases|
39
+ aliases.each do |alias_name|
40
+ alias_method alias_name, original_name
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ require 'open_api/dsl/common_dsl'
2
+
3
+ module OpenApi
4
+ module DSL
5
+ class CtrlInfoObj < Hash
6
+ include DSL::CommonDSL
7
+ include DSL::Helpers
8
+
9
+ def schema component_key, type, schema_hash = { }
10
+ (self[:schemas] ||= { })[component_key] = SchemaObj.new(type, schema_hash).process
11
+ end
12
+ arrow_enable :schema
13
+
14
+ def param component_key, param_type, name, type, required, schema_hash = { }
15
+ (self[:parameters] ||= { })[component_key] =
16
+ ParamObj.new(name, param_type, type, required, schema_hash).process
17
+ end
18
+
19
+ def _param_agent component_key, name, type, schema_hash = { }
20
+ param component_key,
21
+ "#{@param_type}".delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
22
+ end
23
+ arrow_enable :_param_agent
24
+
25
+ def request_body component_key, required, media_type, desc = '', schema_hash = { }
26
+ (self[:requestBodies] ||= { })[component_key] =
27
+ RequestBodyObj.new(required, media_type, desc, schema_hash).process
28
+ end
29
+
30
+ def _request_body_agent component_key, media_type, desc = '', schema_hash = { }
31
+ request_body component_key,
32
+ (@method_name['!'] ? :req : :opt), media_type, desc, schema_hash
33
+ end
34
+ arrow_enable :_request_body_agent
35
+
36
+ arrow_enable :resp # alias_method 竟然也会指向旧的方法?
37
+ arrow_enable :response
38
+
39
+
40
+ def _process_objs
41
+ self[:responses]&.each do |code, obj|
42
+ self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,6 +1,10 @@
1
1
  module OpenApi
2
2
  module DSL
3
3
  module Helpers
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
4
8
  def load_schema(model)
5
9
  # About `show_attrs`, see:
6
10
  # (1) BuilderSupport module: https://github.com/zhandao/zero-rails/blob/master/app/models/concerns/builder_support.rb
@@ -19,7 +23,7 @@ module OpenApi
19
23
  # TODO: 如何获知关系是 many?因为不能只判断结尾是否 ‘s’
20
24
  assoc_model = Object.const_get(attr.to_s.split('_').first.singularize.camelize)
21
25
  { attr => load_schema(assoc_model) }
22
- end
26
+ end rescue next
23
27
  end
24
28
  else
25
29
  model&.columns&.map do |column|
@@ -30,6 +34,28 @@ module OpenApi
30
34
  end
31
35
  end&.compact&.reduce({ }, :merge)
32
36
  end
37
+
38
+ # Arrow Writing:
39
+ # response :RespComponent => [ '200', 'success', :json ]
40
+ # It is equivalent to:
41
+ # response :RespComponent, '200', 'success', :json
42
+ # But I think, in the definition of a component,
43
+ # the key-value (arrow) writing is easy to understand.
44
+ def arrow_writing_support
45
+ proc do |args, executor|
46
+ _args = args.size == 1 && args.first.is_a?(Hash) ? args[0].to_a.flatten : args
47
+ send executor, *_args
48
+ end
49
+ end
50
+
51
+ module ClassMethods
52
+ def arrow_enable method
53
+ alias_method "_#{method}".to_sym, method
54
+ define_method method do |*args|
55
+ arrow_writing_support.call(args, "_#{method}")
56
+ end
57
+ end
58
+ end
33
59
  end
34
60
  end
35
61
  end
@@ -40,7 +40,7 @@ module OpenApi
40
40
  ActiveSupport::HashWithIndifferentAccess.new(doc.delete_if { |_, v| v.blank? })
41
41
  end
42
42
 
43
- def write_docs(generate_files = true)
43
+ def write_docs(generate_files: true)
44
44
  docs = generate_docs
45
45
  return unless generate_files
46
46
  output_path = Config.file_output_path
@@ -48,23 +48,26 @@ module OpenApi
48
48
  max_length = docs.keys.map(&:size).sort.last
49
49
  puts '[ZRO] * * * * * *'
50
50
  docs.each do |doc_name, doc|
51
- puts "[ZRO] `%#{max_length}s.json` is generated." % "#{doc_name}"
51
+ puts "[ZRO] `%#{max_length}s.json` has been generated." % "#{doc_name}"
52
52
  File.open("#{output_path}/#{doc_name}.json", 'w') { |file| file.write JSON.pretty_generate doc }
53
53
  end
54
54
  # pp $open_apis
55
55
  end
56
56
  end
57
57
 
58
- def self.generate_builder_file(option)
58
+ def self.generate_builder_file(action_path, builder)
59
59
  return unless Config.generate_jbuilder_file
60
- return unless option[:builder]
61
- dir_path = "app/views/#{option[:path]}"
60
+ return if builder.nil?
61
+
62
+ path, action = action_path.split('#')
63
+ dir_path = "app/views/#{path}"
62
64
  FileUtils.mkdir_p dir_path
63
- file_path = "#{dir_path}/#{option[:action]}.json.jbuilder"
64
- File.open(file_path, 'w') do |file|
65
- file.write Config.jbuilder_templates[option[:builder]]
66
- puts "[ZRO] JBuilder file generated: #{option[:path]}/#{option[:action]}"
67
- end unless !Config.overwrite_jbuilder_file && File::exists?(file_path)
65
+ file_path = "#{dir_path}/#{action}.json.jbuilder"
66
+
67
+ unless !Config.overwrite_jbuilder_file && File::exists?(file_path)
68
+ File.open(file_path, 'w') { |file| file.write Config.jbuilder_templates[builder] }
69
+ puts "[ZRO] JBuilder file has been generated: #{path}/#{action}"
70
+ end
68
71
  end
69
72
 
70
73
  def self.generate_routes_list
@@ -79,7 +82,7 @@ module OpenApi
79
82
  {
80
83
  http_verb: infos[0].downcase, # => "get"
81
84
  path: infos[1][0..-11].split('/').map do |item|
82
- item.match?(/:/) ? "{#{item[1..-1]}}" : item
85
+ item[':'] ? "{#{item[1..-1]}}" : item
83
86
  end.join('/'), # => "/api/v1/examples/{id}"
84
87
  action_path: infos[2] # => "api/v1/examples#index"
85
88
  } rescue next
@@ -1,3 +1,3 @@
1
1
  module OpenApi
2
- VERSION = '1.3.0'
2
+ VERSION = '1.3.1'
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.3.0
4
+ version: 1.3.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-10-26 00:00:00.000000000 Z
11
+ date: 2017-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -90,10 +90,13 @@ files:
90
90
  - lib/oas_objs/schema_obj.rb
91
91
  - lib/open_api.rb
92
92
  - lib/open_api/config.rb
93
+ - lib/open_api/config_dsl.rb
93
94
  - lib/open_api/dsl.rb
94
- - lib/open_api/dsl_inside_block.rb
95
+ - lib/open_api/dsl/api_info_obj.rb
96
+ - lib/open_api/dsl/common_dsl.rb
97
+ - lib/open_api/dsl/ctrl_info_obj.rb
98
+ - lib/open_api/dsl/helpers.rb
95
99
  - lib/open_api/generator.rb
96
- - lib/open_api/helpers.rb
97
100
  - lib/open_api/version.rb
98
101
  - zero-rails_openapi.gemspec
99
102
  homepage: https://github.com/zhandao/zero-rails_openapi
@@ -116,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
119
  version: '0'
117
120
  requirements: []
118
121
  rubyforge_project:
119
- rubygems_version: 2.6.12
122
+ rubygems_version: 2.6.13
120
123
  signing_key:
121
124
  specification_version: 4
122
125
  summary: Generate the OpenAPI Specification 3 documentation for Rails application.
@@ -1,214 +0,0 @@
1
- require 'oas_objs/schema_obj'
2
- require 'oas_objs/param_obj'
3
- require 'oas_objs/response_obj'
4
- require 'oas_objs/request_body_obj'
5
- require 'oas_objs/ref_obj'
6
- require 'open_api/helpers'
7
-
8
- module OpenApi
9
- module DSL
10
- module CommonDSL
11
- def arrow_writing_support
12
- proc do |args, executor|
13
- if args.count == 1 && args.first.is_a?(Hash)
14
- send(executor, args[0].keys.first, *args[0].values.first)
15
- else
16
- send(executor, *args)
17
- end
18
- end
19
- end
20
-
21
- %i[header header! path path! query query! cookie cookie!].each do |param_type|
22
- define_method param_type do |*args|
23
- @param_type = param_type
24
- _param_agent *args
25
- end
26
- end
27
-
28
- %i[body body!].each do |method|
29
- define_method method do |*args|
30
- @method_name = method
31
- _request_body_agent *args
32
- end
33
- end
34
-
35
- # code represents `component_key` when declare response component
36
- def _response code, desc, media_type = nil, schema_hash = { }
37
- (self[:responses] ||= { }).merge! ResponseObj.new(code, desc, media_type, schema_hash).process
38
- end
39
-
40
- def response *args
41
- arrow_writing_support.call(args, :_response)
42
- end
43
-
44
- def default_response desc, media_type = nil, schema_hash = { }
45
- response :default, desc, media_type, schema_hash
46
- end
47
-
48
- { # alias_methods mapping
49
- response: %i[ error_response resp ],
50
- default_response: %i[ dft_resp dft_response ],
51
- error_response: %i[ other_response oth_resp error err_resp ],
52
- }.each do |original_name, aliases|
53
- aliases.each do |alias_name|
54
- alias_method alias_name, original_name
55
- end
56
- end
57
- end # ----------------------------------------- end of CommonDSL
58
-
59
-
60
-
61
-
62
- class CtrlInfoObj < Hash
63
- include DSL::CommonDSL
64
-
65
- def _schema component_key, type, schema_hash = { }
66
- (self[:schemas] ||= { }).merge! component_key => SchemaObj.new(type, schema_hash).process
67
- end
68
- def schema *args
69
- arrow_writing_support.call(args, :_schema)
70
- end
71
-
72
- def param component_key, param_type, name, type, required, schema_hash = { }
73
- (self[:parameters] ||= { })
74
- .merge! component_key => ParamObj.new(name, param_type, type, required, schema_hash).process
75
- end
76
-
77
- def _param_agent *args
78
- arrow_writing_support.call(args, :_param_arg_agent)
79
- end
80
-
81
- def _param_arg_agent component_key, name, type, schema_hash = { }
82
- param component_key, "#{@param_type}".delete('!'), name, type,
83
- ("#{@param_type}".match?(/!/) ? :req : :opt), schema_hash
84
- end
85
-
86
- def request_body component_key, required, media_type, desc = '', schema_hash = { }
87
- self[:requestBodies] = { component_key => RequestBodyObj.new(required, media_type, desc, schema_hash).process }
88
- end
89
-
90
- def _request_body_agent *args
91
- arrow_writing_support.call(args, :_request_body_arg_agent)
92
- end
93
-
94
- def _request_body_arg_agent component_key, media_type, desc = '', schema_hash = { }
95
- request_body component_key, ("#{@method_name}".match?(/!/) ? :req : :opt), media_type, desc, schema_hash
96
- end
97
- end # ----------------------------------------- end of CtrlInfoObj
98
-
99
-
100
-
101
-
102
- class ApiInfoObj < Hash
103
- include DSL::CommonDSL
104
- include DSL::Helpers
105
-
106
- attr_accessor :action_path, :param_skip, :param_use
107
- def initialize(action_path, options = { })
108
- self.action_path = action_path
109
- self.param_skip = options[:skip] || [ ]
110
- self.param_use = options[:use] || [ ]
111
- end
112
-
113
- def this_api_is_invalid! explain = ''
114
- self[:deprecated] = true
115
- end
116
- alias_method :this_api_is_expired!, :this_api_is_invalid!
117
- alias_method :this_api_is_unused!, :this_api_is_invalid!
118
- alias_method :this_api_is_under_repair, :this_api_is_invalid!
119
-
120
- def desc desc, inputs_descs = { }
121
- @inputs_descs = inputs_descs
122
- merge_desc_for_dryed_param
123
- self[:description] = desc
124
- end
125
-
126
- # TODO: HACK
127
- def merge_desc_for_dryed_param
128
- @inputs_descs.each do |param_name, desc|
129
- self[:parameters].each do |param|
130
- if param_name.match?(?!) && param.processed[:name].to_s == param_name.to_s.delete(?!)
131
- param.merge!(desc!: desc).process
132
- end
133
- end
134
- end
135
- end
136
-
137
- def param param_type, name, type, required, schema_hash = { }
138
- return if param_skip.include? name
139
- return unless param_use.include? name if param_use.present?
140
-
141
- if @inputs_descs&.[](name).present?
142
- schema_hash[:desc] = @inputs_descs[name]
143
- elsif @inputs_descs&.[]("#{name}!".to_sym).present?
144
- schema_hash[:desc!] = @inputs_descs["#{name}!".to_sym]
145
- end
146
-
147
- param_obj = ParamObj.new(name, param_type, type, required, schema_hash)
148
- # The definition of the same name parameter will be overwritten
149
- index = self[:parameters].map do |p|
150
- p.processed[:name] if p.is_a? ParamObj
151
- end.index name
152
- if index.present?
153
- self[:parameters][index] = param_obj
154
- else
155
- self[:parameters] << param_obj
156
- end
157
- end
158
-
159
- def process_params
160
- self[:parameters].each_with_index do |p, index|
161
- self[:parameters][index] = p.is_a?(ParamObj) ? p.process : p
162
- end
163
- end
164
-
165
- def _param_agent name, type, schema_hash = { }
166
- param "#{@param_type}".delete('!'), name, type, ("#{@param_type}".match?(/!/) ? :req : :opt), schema_hash
167
- end
168
-
169
- def param_ref component_key, *keys
170
- self[:parameters].concat [component_key].concat(keys).map { |key| RefObj.new(:parameter, key).process }
171
- end
172
-
173
- def request_body required, media_type, desc = '', schema_hash = { }
174
- self[:requestBody] = RequestBodyObj.new(required, media_type, desc, schema_hash).process
175
- end
176
-
177
- def _request_body_agent media_type, desc = '', schema_hash = { }
178
- request_body ("#{@method_name}".match?(/!/) ? :req : :opt), media_type, desc, schema_hash
179
- end
180
-
181
- def body_ref component_key
182
- self[:requestBody] = RefObj.new(:requestBody, component_key).process
183
- end
184
-
185
- def response_ref code_compkey_hash
186
- code_compkey_hash.each do |code, component_key|
187
- self[:responses].merge! code => RefObj.new(:response, component_key).process
188
- end
189
- end
190
-
191
- # TODO: 目前只能写一句 request body,包括 form 和 file, 需要同时支持一下扁平化
192
- def form desc = '', schema_hash = { }
193
- body :form, desc, schema_hash
194
- end
195
- def form! desc = '', schema_hash = { }
196
- body! :form, desc, schema_hash
197
- end
198
- def file media_type, desc = '', schema_hash = { type: File }
199
- body media_type, desc, schema_hash
200
- end
201
- def file! media_type, desc = '', schema_hash = { type: File }
202
- body! media_type, desc, schema_hash
203
- end
204
-
205
- def security scheme_name, requirements = [ ]
206
- self[:security] << { scheme_name => requirements }
207
- end
208
-
209
- def server url, desc
210
- self[:servers] << { url: url, description: desc }
211
- end
212
- end # ----------------------------------------- end of ApiInfoObj
213
- end
214
- end