zero-rails_openapi 1.4.2 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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