zero-rails_openapi 1.4.2 → 1.4.3

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: 5f96bf52633bfd7fe91394003f64571c24bfc4ad
4
- data.tar.gz: f44d8713d0691eacd66ae9a5ff62f90f21b97595
3
+ metadata.gz: fefcfd0fc562daad7532e1dadd0121e8c30c0adb
4
+ data.tar.gz: 25cf51020674fce5fb428f6b121b6c6a25c02c72
5
5
  SHA512:
6
- metadata.gz: 9ad13a356350c385963ac5a62233afc6f4a182360b6684e2536782ffaadb86d4458112844ec44eff8055adf5c1957c2dd2ac92b32c906445c221de17693aa34a
7
- data.tar.gz: 1dc8b8bb3002a33ac62ab4016fb2359e72a4ce1e43b378c520cf3dbd40dd43227162e43a31801ef824a02323b1fbe5c9f9cdeb51cfe42cb6ee7ba6d3cc174cab
6
+ metadata.gz: 77306d030cba3bfbcb7f6d31eaac31c9ed7dd60355a012166a040633cd6420ebe898b483dcef1fae571da47fcb64871489da7c91069014246dd788e78c2e0815
7
+ data.tar.gz: 5ad12c05afbf059b177bc1e797e401f49595d7be696e386f89b6e1f945daa511ebc2919c2564b4439e07c0951147682c3ee116efc0f9de4708f845e8e06327b8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Version Changelog
2
2
 
3
+ ## [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
+
5
+ ### Feature
6
+
7
+ 1. `example` method in `components` block.
8
+ 2. Request Body (also Response):
9
+ 1. The same media-types will be fusion together.
10
+ (This means you can write `form` separately.)
11
+ 2. Different media-types will not be replaced, all will be merged in `content`.
12
+ 3. Support flat statement form-data by `data`.
13
+
14
+ ### Fixed
15
+
16
+ 1. `generate_doc` raise 'should not nil when merge' if settings[:components] not set.
17
+ 2. `@preprocessed not initialize` warning.
18
+
19
+ ### Added
20
+
21
+ 1. Schema option `blankable`.
22
+ 2. Schema option alias `in` to `enum`.
23
+ 3. Schema option `pattern` could be `String` for supporting Time Format.
24
+
25
+ ### Changed
26
+
27
+ 1. `form` mandatory requirements pass `data: { }`.
28
+ 2. Remove `request_body`'s parameter `desc` to `**options`.
29
+ 3. Remove aliases of `response`.
3
30
 
4
31
  ## [1.4.1] - 2017/12/6 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.4.0...v1.4.1)
5
32
 
@@ -52,7 +79,7 @@
52
79
  2. Support designated http method in `api`.
53
80
  3. The completion of the basic README.
54
81
 
55
- ## [1.3.2 & 1.3.3] - 2017/11/10,21 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.3.1...v1.3.3)
82
+ ## [1.3.2 & 1.3.3] - 2017/11/10&21 - [view diff](https://github.com/zhandao/zero-rails_openapi/compare/v1.3.1...v1.3.3)
56
83
 
57
84
  ### Feature
58
85
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zero-rails_openapi (1.4.2)
4
+ zero-rails_openapi (1.4.3)
5
5
  activesupport (>= 3)
6
6
  rails (>= 3)
7
7
 
data/README.md CHANGED
@@ -22,8 +22,8 @@
22
22
  - [Usage - DSL](#usage---dsl)
23
23
  - [DSL methods inside `api` and `api_dry`'s block](#dsl-methods-inside-api-and-api_drys-block)
24
24
  - [DSL methods inside `components`'s block](#dsl-methods-inside-componentss-block-code-source)
25
- - [Usage - Generate JSON documentation file](#usage---generate-json-documentation-file)
26
- - [Usage - Use Swagger UI(very beautiful web page) to show your Documentation](#usage---use-swagger-uivery-beautiful-web-page-to-show-your-documentation)
25
+ - [Run! - Generate JSON documentation file](#run---generate-json-documentation-file)
26
+ - [Use Swagger UI(very beautiful web page) to show your Documentation](#use-swagger-uivery-beautiful-web-page-to-show-your-documentation)
27
27
  - [Tricks](#tricks)
28
28
  - [Write DSL somewhere else](#trick1---write-the-dsl-somewhere-else)
29
29
  - [Global DRYing](#trick2---global-drying)
@@ -370,16 +370,18 @@
370
370
  # it links sepcified RefObjs (by component keys) to current body.
371
371
  body, body! # alias of request_body
372
372
  form, form! # define a multipart/form-data body
373
+ data # define [a] property in the form-data body
373
374
  file, file! # define a File media-type body
374
375
  ```
375
-
376
+ Bang methods(!) means the specified media-type body is required.
377
+
376
378
  ```ruby
377
379
  # method signature
378
- request_body(is_required, media_type, desc = '', schema_hash = { })
380
+ request_body(required, media_type, data: { }, **options)
379
381
  # usage
380
- request_body :opt, :form, '', type: { id!: Integer, name: String }
381
- # or
382
- request_body :opt, :form, '', data: { id!: Integer, name: String }
382
+ # (1) `data` contains all the attributes required by this request body.
383
+ # (2) `param_name!` means it is required, otherwise without '!' means optional.
384
+ request_body :opt, :form, data: { id!: Integer, name: { type: String, desc: 'name' } }, desc: 'form-data'
383
385
 
384
386
 
385
387
  # method signature
@@ -389,23 +391,23 @@
389
391
 
390
392
 
391
393
  # method signature
392
- body!(media_type, desc = '', schema_hash = { })
394
+ body!(media_type, data: { }, **options)
393
395
  # usage
394
396
  body :json
395
397
 
396
398
 
397
399
  # method implement
398
- def form desc = '', schema_hash = { }
399
- body :form, desc, schema_hash
400
+ def form data:, **options
401
+ body :form, data: data, **options
400
402
  end
401
403
  # usage
402
- form! 'register', data: {
404
+ form! data: {
403
405
  name: String,
404
406
  password: String,
405
407
  password_confirmation: String
406
408
  }
407
409
  # advance usage
408
- form 'for creating a user', data: {
410
+ form data: {
409
411
  :name! => { type: String, desc: 'user name' },
410
412
  :password! => { type: String, pattern: /[0-9]{6,10}/, desc: 'password' },
411
413
  # optional
@@ -414,62 +416,77 @@
414
416
  examples: { # ↓ ↓
415
417
  :right_input => [ 'user1', '123456' ],
416
418
  :wrong_input => [ 'user2', 'abc' ]
417
- }
418
-
419
+ },
420
+ desc: 'for creating a user'
421
+
422
+
423
+ # method implement
424
+ def data name, type = nil, schema_hash = { }
425
+ schema_hash[:type] = type if type.present?
426
+ form data: { name => schema_hash }
427
+ end
428
+ # usage: please look at the 4th point below
419
429
 
420
430
  # about `file`
421
- def file! media_type, desc = '', schema_hash = { type: File }
422
- body! media_type, desc, schema_hash
431
+ def file! media_type, data: { type: File }, **options
432
+ body! media_type, data: data, **options
423
433
  end
424
434
  ```
425
435
 
426
- 1. **Notice:** Each API should only declare a request body
427
- That is, all of the above methods you can only choose one of them.
428
- (But **multiple media types** will be supported in the future).
429
- 2. `media_type`: we provide some [mapping](lib/oas_objs/media_type_obj.rb) from symbols to real media-types.
430
- 3. `schema_hash`: as above (see param).
431
- **One thing that should be noted is: when use Hash writing, `scham_type` is writed in schema_hash using key :type.**
432
- 4. `exp_by` and `examples`: for the above example, the following has the same effect:
436
+ 1. `media_type`: we provide some [mapping](lib/oas_objs/media_type_obj.rb) from symbols to real media-types.
437
+ 2. `schema_hash`: as above (see param).
438
+ 3. `exp_by` and `examples`: for the above example, the following has the same effect:
433
439
  ```
434
440
  examples: {
435
441
  :right_input => { name: 'user1', password: '123456' },
436
442
  :wrong_input => { name: 'user2', password: 'abc' }
437
443
  }
438
444
  ```
445
+ 4. *[IMPORTANT]* Each request bodies you declared will **FUSION** together. <a name="fusion"></a>
446
+ (1) Media-Types will be merged to `requestBody["content"]`
447
+ ```ruby
448
+ form 'desc', data: { }
449
+ body :json, 'desc', data: { }
450
+ # will generate: "content": { "multipart/form-data": { }, "application/json": { } }
451
+ ```
452
+ (2) The same media-types will fusion, but not merge:
453
+ (So that you can write `form` separately, and make `data` method possible.)
454
+ ```ruby
455
+ data :param_a!, String
456
+ data :param_b, Integer
457
+ # or same as:
458
+ form '', data: { :param_a! => String }
459
+ form '', data: { :param_b => Integer }
460
+ # will generate: { "param_a": { "type": "string" }, "param_b": { "type": "integer" } } (call it X)
461
+ # therefore:
462
+ # "content": { "multipart/form-data":
463
+ # { "schema": { "type": "object", "properties": { X }, "required": [ "param_a" ] }
464
+ # }
465
+ ```
439
466
 
440
467
  #### (5) `response` family methods (OAS - [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#response-object))
441
468
 
442
469
  Define the responses for the API (action).
443
470
  ```
444
- response or resp
471
+ response # aliases: `resp` and `error`
445
472
  response_ref
446
- default_response or dft_resp
447
- error_response, other_response, oth_resp, error, err_resp # response's aliases, should be used in the error response context.
448
- merge_to_resp
449
473
  ```
450
474
 
451
475
  ```ruby
452
476
  # method signature
453
- response(response_code, desc, media_type = nil, schema_hash = { })
477
+ response(code, desc, media_type = nil, data: { }, type: nil)
454
478
  # usage
455
479
  response 200, 'query result', :pdf, type: File
480
+ # same as:
481
+ response 200, 'query result', :pdf, data: File
456
482
 
457
483
  # method signature
458
484
  response_ref(code_compkey_hash)
459
485
  # usage
460
486
  response_ref 700 => :AResp, 800 => :BResp
461
-
462
- # method signature
463
- merge_to_resp(code, by:)
464
- # usage
465
- merge_to_resp 200, by: {
466
- data: {
467
- type: String
468
- }
469
- }
470
487
  ```
471
488
 
472
- **practice:** Combined with wrong class, automatically generate error responses. [AutoGenDoc](documentation/examples/auto_gen_doc.rb#L63)
489
+ **practice:** Automatically generate responses based on the agreed error class. [AutoGenDoc](documentation/examples/auto_gen_doc.rb#L63)
473
490
 
474
491
  #### (6) Authentication and Authorization
475
492
 
@@ -541,11 +558,11 @@
541
558
  ### DSL methods inside [components]()'s block ([code source](lib/open_api/dsl/components.rb))
542
559
 
543
560
  (Here corresponds to OAS [Components Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#componentsObject))
544
-
561
+
545
562
  Inside `components`'s block,
546
563
  you can use the same DSL as [[DSL methods inside `api` and `api_dry`'s block]](#dsl-methods-inside-api-and-api_drys-block).
547
564
  But there are two differences:
548
-
565
+
549
566
  (1) Each method needs to pass one more parameter `component_key`
550
567
  (in the first parameter position),
551
568
  this will be used as the reference name for the component.
@@ -560,9 +577,9 @@
560
577
  ```ruby
561
578
  query! :UidQuery => [:uid, String]
562
579
  ```
563
-
580
+
564
581
  (2) You can use `schema` to define a Schema Component.
565
-
582
+
566
583
  ```ruby
567
584
  # method signature
568
585
  schema(component_key, type = nil, one_of: nil, all_of: nil, any_of: nil, not: nil, **schema_hash)
@@ -585,8 +602,8 @@
585
602
  schema User # easy! And the component_key will be :User
586
603
  ```
587
604
  [1] see: [Type](documentation/parameter.md#type-schema_type)
588
-
589
- ## Usage - Generate JSON Documentation File
605
+
606
+ ## Run! - Generate JSON Documentation File
590
607
 
591
608
  Use `OpenApi.write_docs`:
592
609
 
@@ -600,7 +617,7 @@
600
617
 
601
618
  Then the JSON files will be written to the directories you set. (Each API a file.)
602
619
 
603
- ## Usage - Use Swagger UI(very beautiful web page) to show your Documentation
620
+ ## Use Swagger UI(very beautiful web page) to show your Documentation
604
621
 
605
622
  Download [Swagger UI](https://github.com/swagger-api/swagger-ui) (version >= 2.3.0 support the OAS3)
606
623
  to your project,
data/README_zh.md CHANGED
@@ -24,8 +24,8 @@
24
24
  - [DSL 介绍及用例](#usage---dsl)
25
25
  - [用于 `api` 和 `api_dry` 块内的 DSL(描述 API 的参数、响应等)](#dsl-methods-inside-api-and-api_drys-block)
26
26
  - [用于 `components` 块内的 DSL(描述可复用的组件)](#dsl-methods-inside-componentss-block-code-source)
27
- - [执行文档生成](#usage---generate-json-documentation-file)
28
- - [使用 Swagger-UI 可视化所生成的文档](#usage---use-swagger-uivery-beautiful-web-page-to-show-your-documentation)
27
+ - [执行文档生成](#run---generate-json-documentation-file)
28
+ - [使用 Swagger-UI 可视化所生成的文档](#use-swagger-uivery-beautiful-web-page-to-show-your-documentation)
29
29
  - [技巧](#tricks)
30
30
  - [将 DSL 写于他处,与控制器分离](#trick1---write-the-dsl-somewhere-else)
31
31
  - [全局 DRY](#trick2---global-drying)
@@ -580,7 +580,7 @@
580
580
  ```
581
581
  [1] see: [Type](documentation/parameter.md#type-schema_type)
582
582
 
583
- ## Usage - Generate JSON Documentation File
583
+ ## Run! - Generate JSON Documentation File
584
584
 
585
585
  Use `OpenApi.write_docs`:
586
586
 
@@ -594,7 +594,7 @@
594
594
 
595
595
  Then the JSON files will be written to the directories you set. (Each API a file.)
596
596
 
597
- ## Usage - Use Swagger UI(very beautiful web page) to show your Documentation
597
+ ## Use Swagger UI(very beautiful web page) to show your Documentation
598
598
 
599
599
  Download [Swagger UI](https://github.com/swagger-api/swagger-ui) (version >= 2.3.0 support the OAS3)
600
600
  to your project,
@@ -50,7 +50,7 @@ module AutoGenDoc
50
50
  # default_response 'default response', :json
51
51
  model = Object.const_get(action_path.split('#').first.split('/').last[0..-2].camelize) rescue nil
52
52
  type = action.in?(%w[ index show ]) ? Array[load_schema(model)] : String
53
- response '200', 'success', :json, type: {
53
+ response '200', 'success', :json, data: {
54
54
  code: { type: Integer, dft: 200 },
55
55
  msg: { type: String, dft: 'success' },
56
56
  data: { type: type }
@@ -30,20 +30,16 @@ class Api::V1::ExamplesController < Api::V1::BaseController
30
30
 
31
31
  query :test_type, type: String
32
32
  query :combination, one_of: [ :DogSchema, String, { type: Integer, desc: 'integer input'}]
33
- form '', data: {
33
+ form data: {
34
34
  :combination => { any_of: [ Integer, String ] }
35
35
  }
36
36
 
37
- response :success, 'success response', :json, type: :DogSchema
38
- merge_to_resp 200, by: {
39
- data: {
40
- type: [
41
- String
42
- ]
43
- }
44
- }
37
+ response :success, 'success response', :json#, data: :Pet
38
+ security :Token
45
39
 
46
- security :ApiKeyAuth
40
+ resp 200, '', :json, data: {
41
+ a: String
42
+ }
47
43
  end
48
44
 
49
45
 
@@ -54,7 +50,7 @@ class Api::V1::ExamplesController < Api::V1::BaseController
54
50
 
55
51
 
56
52
  api :create do
57
- form 'for creating a user', data: {
53
+ form! data: {
58
54
  :name! => String, # <= schema_type is `String`
59
55
  :password! => { type: String, pattern: /[0-9]{6,10}/, desc: 'password' },
60
56
  # optional
@@ -28,7 +28,7 @@ class V2::GoodsDoc < BaseDoc
28
28
 
29
29
 
30
30
  api :create, 'POST create a good', use: 'Token' do
31
- form! 'for creating a good', data: {
31
+ form! data: {
32
32
  :name! => { type: String, desc: 'good\'s name' },
33
33
  :category_id! => { type: Integer, desc: 'sub_category\'s id', npmt: true, range: { ge: 1 }, as: :cate },
34
34
  :price! => { type: Float, desc: 'good\'s price', range: { ge: 0 } },
@@ -62,6 +62,7 @@ You can set the schema by following keys (all are optional), the words in parent
62
62
  for example the parameter name "user_email" will generate "is: email". Default `is` options are:
63
63
  [email phone password uuid uri url time date], to overwrite it you can set it in initializer `c.is_options = %w[]`.
64
64
  5. If type is Object, for describing each property's schema, the only way is use ref type, like: `{ id: :Id, name: :Name }`
65
- - **pattern (regexp, pr, reg)**
65
+ - **pattern (regexp, pr, reg)**
66
+ Regexp or Time Format
66
67
  - **default (dft, default_value)**
67
68
  - **as** # TODO
@@ -14,12 +14,12 @@ module OpenApi
14
14
  end
15
15
 
16
16
  def process_for(param_name = nil, options = { desc_inside: false })
17
- processed.tap do |it|
18
- it[@mode] = @schemas.map do |schema|
19
- type = schema.is_a?(Hash) ? schema[:type] : schema
20
- schema = { } unless schema.is_a?(Hash)
21
- SchemaObj.new(type, schema).process_for(param_name, options) end
17
+ processed[@mode] = @schemas.map do |schema|
18
+ type = schema.is_a?(Hash) ? schema[:type] : schema
19
+ schema = { } unless schema.is_a?(Hash)
20
+ SchemaObj.new(type, schema).process_for(param_name, options)
22
21
  end
22
+ processed
23
23
  end
24
24
 
25
25
  alias process process_for
@@ -1,5 +1,21 @@
1
1
  module OpenApi
2
2
  module Helpers
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
17
+ end
18
+
3
19
  def truly_present?(obj)
4
20
  obj == false || obj.present?
5
21
  end
@@ -14,7 +30,7 @@ module OpenApi
14
30
  self
15
31
  end
16
32
 
17
- # reduceee.then_merge! => for Hash
33
+ # reducx.then_merge! => for Hash
18
34
  def reducx(*values)
19
35
  @assign = values.compact.reduce({ }, :merge).keep_if &value_present
20
36
  self
@@ -8,14 +8,19 @@ module OpenApi
8
8
  class RequestBodyObj < Hash
9
9
  include Helpers
10
10
 
11
- attr_accessor :processed, :media_type
12
- def initialize(required, media_type, desc, hash)
13
- self.media_type = MediaTypeObj.new(media_type, hash)
14
- self.processed = { required: required.to_s.match?(/req/), description: desc }
11
+ attr_accessor :processed, :media_types
12
+ def initialize(required, desc)
13
+ self.media_types = [ ]
14
+ self.processed = { required: required.match?('req'), description: desc }
15
+ end
16
+
17
+ def add_or_fusion(media_type, hash)
18
+ media_types << MediaTypeObj.new(media_type, hash)
19
+ self
15
20
  end
16
21
 
17
22
  def process
18
- assign(media_type.process).to_processed 'content'
23
+ assign(media_types.map(&:process).reduce({ }, &fusion)).to_processed 'content'
19
24
  processed
20
25
  end
21
26
  end
@@ -7,17 +7,19 @@ module OpenApi
7
7
  class ResponseObj < Hash
8
8
  include Helpers
9
9
 
10
- attr_accessor :processed, :code, :media_type
11
- def initialize(desc, media_type, hash)
12
- @hash = hash
13
- @mt = media_type
14
- self.code = code.to_s
15
- self.media_type = MediaTypeObj.new(media_type, hash)
16
- self.processed = { description: desc }
10
+ attr_accessor :processed, :media_types
11
+ def initialize(desc)
12
+ self.media_types = [ ]
13
+ self.processed = { description: desc }
14
+ end
15
+
16
+ def add_or_fusion(media_type, hash)
17
+ media_types << MediaTypeObj.new(media_type, hash)
18
+ self
17
19
  end
18
20
 
19
21
  def process
20
- assign(media_type.process).to_processed 'content'
22
+ assign(media_types.map(&:process).reduce({ }, &fusion)).to_processed 'content'
21
23
  processed
22
24
  end
23
25
 
@@ -30,17 +30,17 @@ module OpenApi
30
30
  def process_for(param_name = nil, options = { desc_inside: false })
31
31
  return processed if @preprocessed
32
32
 
33
- processed.merge! processed_type
33
+ processed.merge!(processed_type)
34
34
  reducx(
35
35
  processed_enum_and_length,
36
36
  processed_range,
37
37
  processed_is_and_format(param_name),
38
38
  {
39
- pattern: _pattern&.inspect&.delete('/'),
40
- default: _default.nil? ? nil : '_default',
39
+ pattern: _pattern.is_a?(String)? _pattern : _pattern&.inspect&.delete('/'),
40
+ default: nil,
41
41
  examples: self[:examples].present? ? ExampleObj.new(self[:examples], self[:exp_by]).process : nil
42
42
  },
43
- { as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if }
43
+ { as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if, blankable: _blank }
44
44
  ).then_merge!
45
45
  processed[:default] = _default unless _default.nil?
46
46
 
@@ -69,7 +69,7 @@ module OpenApi
69
69
  recursive_array_type(t)
70
70
  elsif t.is_a? Symbol
71
71
  RefObj.new(:schema, t).process
72
- elsif t.in? %w[float double int32 int64] # to README: 这些值应该传 string 进来, symbol 只允许 $ref
72
+ elsif t.in? %w[float double int32 int64]
73
73
  { type: t.match?('int') ? 'integer' : 'number', format: t}
74
74
  elsif t.in? %w[binary base64]
75
75
  { type: 'string', format: t}
@@ -142,7 +142,7 @@ module OpenApi
142
142
 
143
143
 
144
144
  { # SELF_MAPPING
145
- _enum: %i[ enum values allowable_values ],
145
+ _enum: %i[ enum in values allowable_values ],
146
146
  _value: %i[ must_be value allowable_value ],
147
147
  _range: %i[ range number_range ],
148
148
  _length: %i[ length lth size ],
@@ -157,6 +157,7 @@ module OpenApi
157
157
  _npermit: %i[ npmt not_permit unpermit ], # NOT OAS Spec, it's for zero-params_processor
158
158
  _req_if: %i[ req_if req_when ], # NOT OAS Spec, it's for zero-params_processor
159
159
  _opt_if: %i[ opt_if opt_when ], # NOT OAS Spec, it's for zero-params_processor
160
+ _blank: %i[ blank blankable ], # NOT OAS Spec, it's for zero-params_processor
160
161
  }.each do |key, aliases|
161
162
  define_method key do
162
163
  return self[key] unless self[key].nil?
data/lib/open_api/dsl.rb CHANGED
@@ -27,7 +27,7 @@ module OpenApi
27
27
  apis_tag if @_ctrl_infos.nil?
28
28
  current_ctrl = @_ctrl_infos[:components] = Components.new
29
29
  current_ctrl.instance_eval(&block)
30
- current_ctrl._process_objs
30
+ current_ctrl.process_objs
31
31
  end
32
32
 
33
33
  def api action, summary = '', http: nil, skip: [ ], use: [ ], &block
@@ -43,7 +43,7 @@ module OpenApi
43
43
  [action, :all].each { |blk_key| @_api_dry_blocks&.[](blk_key)&.each { |blk| api.instance_eval(&blk) } }
44
44
  api.param_use = [ ] # `skip` and `use` only affect `api_dry`'s blocks
45
45
  api.instance_eval(&block) if block_given?
46
- api._process_objs
46
+ api.process_objs
47
47
  api.delete_if { |_, v| v.blank? }
48
48
 
49
49
  path = (@_api_infos ||= { })[routes_info[:path]] ||= { }
@@ -38,8 +38,7 @@ module OpenApi
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
- 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
41
+ fill_in_parameters(param_obj)
43
42
  end
44
43
 
45
44
  # For supporting this: (just like `form '', data: { }` usage)
@@ -69,45 +68,46 @@ module OpenApi
69
68
  self[:parameters].concat([component_key].concat(keys).map { |key| RefObj.new(:parameter, key).process })
70
69
  end
71
70
 
72
- def request_body required, media_type, desc = '', hash = { }
73
- self[:requestBody] = RequestBodyObj.new(required, media_type, desc, hash).process
71
+ # options: `exp_by` and `examples`
72
+ def request_body required, media_type, data: { }, **options
73
+ desc = options.delete(:desc) || ''
74
+ self[:requestBody] = RequestBodyObj.new(required, desc) unless self[:requestBody].is_a?(RequestBodyObj)
75
+ self[:requestBody].add_or_fusion(media_type, options.merge(data: data))
74
76
  end
75
77
 
76
- def _request_body_agent media_type, desc = '', hash = { }
77
- request_body (@method_name['!'] ? :req : :opt), media_type, desc, hash
78
+ def _request_body_agent media_type, data: { }, **options
79
+ request_body (@method_name['!'] ? :req : :opt), media_type, data: data, **options
78
80
  end
79
81
 
80
82
  def body_ref component_key
81
83
  self[:requestBody] = RefObj.new(:requestBody, component_key).process
82
84
  end
83
85
 
84
- def merge_to_resp code, by:
85
- _response = self[:responses].fetch(code)
86
- self[:responses][code] = _response.override(by).process
87
- end
88
-
89
86
  def response_ref code_compkey_hash
90
87
  code_compkey_hash.each do |code, component_key|
91
88
  self[:responses][code] = RefObj.new(:response, component_key).process
92
89
  end
93
90
  end
94
91
 
95
- # TODO: 目前只能写一句 request body,包括 form file, 需要同时支持一下扁平化
96
- def form desc = '', hash = { }
97
- body :form, desc, hash
92
+ def form data:, **options
93
+ body :form, data: data, **options
98
94
  end
99
95
 
100
- def form! desc = '', hash = { }
101
- body! :form, desc, hash
96
+ def form! data:, **options
97
+ body! :form, data: data, **options
102
98
  end
103
99
 
104
- # TODO: 这种情况下 form file 无法共存,需要解决(通过 combined?)
105
- def file media_type, desc = '', hash = { type: File }
106
- body media_type, desc, hash
100
+ def data name, type = nil, schema_hash = { }
101
+ schema_hash[:type] = type if type.present?
102
+ form data: { name => schema_hash }
107
103
  end
108
104
 
109
- def file! media_type, desc = '', hash = { type: File }
110
- body! media_type, desc, hash
105
+ def file media_type, data: { type: File }, **options
106
+ body media_type, data: data, **options
107
+ end
108
+
109
+ def file! media_type, data: { type: File }, **options
110
+ body! media_type, data: data, **options
111
111
  end
112
112
 
113
113
  def security_require scheme_name, scopes: [ ]
@@ -129,7 +129,7 @@ module OpenApi
129
129
  end
130
130
 
131
131
  def param_examples exp_by = :all, examples_hash
132
- _process_objs
132
+ process_objs
133
133
  exp_by = self[:parameters].map { |p| p[:name] } if exp_by == :all
134
134
  self[:examples] = ExampleObj.new(examples_hash, exp_by).process
135
135
  end
@@ -137,7 +137,7 @@ module OpenApi
137
137
  alias examples param_examples
138
138
 
139
139
 
140
- def _process_objs
140
+ def process_objs
141
141
  self[:parameters]&.each_with_index do |p, index|
142
142
  self[:parameters][index] = p.process if p.is_a?(ParamObj)
143
143
  end
@@ -147,6 +147,8 @@ module OpenApi
147
147
  self[:parameters][param_order.index(p[:name]) || -1] = p
148
148
  end if param_order.present?
149
149
 
150
+ self[:requestBody] = self[:requestBody].try :process
151
+
150
152
  self[:responses]&.each do |code, obj|
151
153
  self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
152
154
  end
@@ -25,23 +25,13 @@ module OpenApi
25
25
  end
26
26
 
27
27
  # `code`: when defining components, `code` means `component_key`
28
- def response code, desc, media_type = nil, hash = { }
29
- (self[:responses] ||= { })[code] = ResponseObj.new(desc, media_type, hash)
28
+ def response code, desc, media_type = nil, data: { }, type: nil
29
+ self[:responses][code] = ResponseObj.new(desc) unless (self[:responses] ||= { })[code].is_a?(ResponseObj)
30
+ self[:responses][code].add_or_fusion(media_type, { data: type || data })
30
31
  end
31
32
 
32
- def default_response desc, media_type = nil, hash = { }
33
- response :default, desc, media_type, hash
34
- end
35
-
36
- { # alias_methods mapping
37
- response: %i[ error_response resp ],
38
- default_response: %i[ dft_resp dft_response ],
39
- error_response: %i[ other_response oth_resp error err_resp ],
40
- }.each do |original_name, aliases|
41
- aliases.each do |alias_name|
42
- alias_method alias_name, original_name
43
- end
44
- end
33
+ alias_method :resp, :response
34
+ alias_method :error, :response
45
35
  end
46
36
  end
47
37
  end
@@ -37,13 +37,16 @@ module OpenApi
37
37
  end
38
38
  arrow_enable :_param_agent
39
39
 
40
- def request_body component_key, required, media_type, desc = '', schema_hash = { }
41
- (self[:requestBodies] ||= { })[component_key] = RequestBodyObj.new(required, media_type, desc, schema_hash).process
40
+ def request_body component_key, required, media_type, data: { }, **options
41
+ desc = options.delete(:desc) || ''
42
+ cur = (self[:requestBodies] ||= { })[component_key]
43
+ cur = RequestBodyObj.new(required, desc) unless cur.is_a?(RequestBodyObj)
44
+ self[:requestBodies][component_key] = cur.add_or_fusion(media_type, options.merge(data: data))
42
45
  end
43
46
 
44
- def _request_body_agent component_key, media_type, desc = '', schema_hash = { }
47
+ def _request_body_agent component_key, media_type, data: { }, **options
45
48
  request_body component_key,
46
- (@method_name['!'] ? :req : :opt), media_type, desc, schema_hash
49
+ (@method_name['!'] ? :req : :opt), media_type, data: data, **options
47
50
  end
48
51
  arrow_enable :_request_body_agent
49
52
 
@@ -74,7 +77,11 @@ module OpenApi
74
77
  end
75
78
  arrow_enable :api_key
76
79
 
77
- def _process_objs
80
+ def process_objs
81
+ self[:requestBodies]&.each do |key, obj|
82
+ self[:requestBodies][key] = obj.process
83
+ end
84
+
78
85
  self[:responses]&.each do |code, obj|
79
86
  self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
80
87
  end
@@ -38,6 +38,12 @@ module OpenApi
38
38
  end
39
39
  end
40
40
 
41
+ def fill_in_parameters(param_obj)
42
+ name = param_obj.processed[:name]
43
+ index = self[:parameters].map { |p| p.processed[:name] if p.is_a?(ParamObj) }.index(name)
44
+ index.present? ? self[:parameters][index] = param_obj : self[:parameters] << param_obj
45
+ end
46
+
41
47
  # Arrow Writing:
42
48
  # response :RespComponent => [ '200', 'success', :json ]
43
49
  # It is equivalent to:
@@ -1,3 +1,3 @@
1
1
  module OpenApi
2
- VERSION = '1.4.2'
2
+ VERSION = '1.4.3'
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.4.2
4
+ version: 1.4.3
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-10 00:00:00.000000000 Z
11
+ date: 2017-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler