Skip to content

Commit 48d98e7

Browse files
author
zhandao
committed
[feat] ApiObj.all_params
1 parent 5d906ec commit 48d98e7

9 files changed

+123
-99
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@
381381
body_ref # 2. it links sepcified RefObjs (by component keys) to the body.
382382
body, body! # 3. alias of request_body
383383
form, form! # 4. to define a multipart/form-data request_body
384+
json, json! # 5. to define a application/json request_body
384385
data # 5. to define [a] property in the form-data request_body
385386
```
386387
Bang methods(!) means the specified media-type body is required.
@@ -422,6 +423,7 @@
422423
name!: String,
423424
password: { type: String, pattern: /[0-9]{6,10}/ },
424425
}
426+
json data: { name!: String }
425427

426428
# Part 5
427429
# ** Method Signature

README_zh.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -722,9 +722,9 @@
722722

723723
### Trick5 - Auto Generate index/show Actions's Response-Types Based on DB Schema
724724

725-
Use method `load_schema` in `api_dry`.
725+
~~Use method `load_schema` in `api_dry`.~~
726726

727-
See this [file](documentation/examples/auto_gen_doc.rb#L51) for uasge information.
727+
~~See this [file](documentation/examples/auto_gen_doc.rb#L51) for uasge information.~~
728728

729729
### Trick6 - Combined Schema (one_of / all_of / any_of / not)
730730

lib/oas_objs/media_type_obj.rb

+27-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

3-
require 'oas_objs/schema_obj'
4-
require 'oas_objs/example_obj'
3+
require "oas_objs/schema_obj"
4+
require "oas_objs/example_obj"
55

66
module OpenApi
77
module DSL
@@ -35,30 +35,30 @@ def process
3535
def media_type_mapping(media_type)
3636
return media_type if media_type.is_a? String
3737
case media_type
38-
when :app then 'application/*'
39-
when :json then 'application/json'
40-
when :xml then 'application/xml'
41-
when :xwww then 'application/x-www-form-urlencoded'
42-
when :pdf then 'application/pdf'
43-
when :zip then 'application/zip'
44-
when :gzip then 'application/gzip'
45-
when :doc then 'application/msword'
46-
when :docx then 'application/application/vnd.openxmlformats-officedocument.wordprocessingml.document'
47-
when :xls then 'application/vnd.ms-excel'
48-
when :xlsx then 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
49-
when :ppt then 'application/vnd.ms-powerpoint'
50-
when :pptx then 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
51-
when :form then 'multipart/form-data'; when :form_data then 'multipart/form-data'
52-
when :text then 'text/*'
53-
when :plain then 'text/plain then charset=utf-8'
54-
when :html then 'text/html'
55-
when :csv then 'text/csv'
56-
when :image then 'image/*'
57-
when :png then 'image/png'
58-
when :jpeg then 'image/jpeg'
59-
when :gif then 'image/gif'
60-
when :audio then 'audio/*'
61-
when :video then 'video/*'
38+
when :app then "application/*"
39+
when :json then "application/json"
40+
when :xml then "application/xml"
41+
when :xwww then "application/x-www-form-urlencoded"
42+
when :pdf then "application/pdf"
43+
when :zip then "application/zip"
44+
when :gzip then "application/gzip"
45+
when :doc then "application/msword"
46+
when :docx then "application/application/vnd.openxmlformats-officedocument.wordprocessingml.document"
47+
when :xls then "application/vnd.ms-excel"
48+
when :xlsx then "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
49+
when :ppt then "application/vnd.ms-powerpoint"
50+
when :pptx then "application/vnd.openxmlformats-officedocument.presentationml.presentation"
51+
when :form then "multipart/form-data"; when :form_data then "multipart/form-data"
52+
when :text then "text/*"
53+
when :plain then "text/plain then charset=utf-8"
54+
when :html then "text/html"
55+
when :csv then "text/csv"
56+
when :image then "image/*"
57+
when :png then "image/png"
58+
when :jpeg then "image/jpeg"
59+
when :gif then "image/gif"
60+
when :audio then "audio/*"
61+
when :video then "video/*"
6262
else nil
6363
end
6464
end
@@ -95,4 +95,4 @@ def media_type_mapping(media_type)
9595
}
9696
}
9797
}
98-
}
98+
}

lib/oas_objs/request_body_obj.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class RequestBodyObj < Hash
1414

1515
def initialize(required, desc)
1616
self.media_types = [ ]
17-
self.processed = { required: required['req'].present?, description: desc }
17+
self.processed = { required: required.to_s[/req/].present?, description: desc }
1818
end
1919

2020
def absorb(media_type, hash)

lib/open_api/dsl/api.rb

+79-51
Original file line numberDiff line numberDiff line change
@@ -7,122 +7,129 @@ module DSL
77
class Api < Hash
88
include DSL::Helpers
99

10+
attr_accessor :_all_params
1011
attr_accessor :action_path, :dry_skip, :dry_only, :dry_blocks, :dryed, :param_order
1112

12-
def initialize(action_path = '', summary: nil, tags: [ ], id: nil)
13+
def initialize(action_path = "", summary: nil, tags: [ ], id: nil)
1314
self.action_path = action_path
1415
self.dry_blocks = [ ]
15-
self.merge!(summary: summary, operationId: id, tags: tags, description: '', parameters: [ ],
16-
requestBody: nil, responses: { }, callbacks: { }, links: { }, security: [ ], servers: [ ])
16+
self._all_params = { }
17+
self.merge!(
18+
summary: summary, operationId: id, tags: tags, description: "", parameters: [ ],
19+
requestBody: nil, responses: { }, callbacks: { }, links: { }, security: [ ], servers: [ ]
20+
)
1721
end
1822

1923
def this_api_is_invalid!(*)
2024
self[:deprecated] = true
2125
end
22-
2326
alias this_api_is_expired! this_api_is_invalid!
2427
alias this_api_is_unused! this_api_is_invalid!
2528
alias this_api_is_under_repair! this_api_is_invalid!
2629

27-
def desc desc
30+
def desc(desc)
2831
self[:description] = desc
2932
end
30-
3133
alias description desc
3234

33-
def dry only: nil, skip: nil, none: false
35+
def dry(only: nil, skip: nil, none: false)
3436
return if dry_blocks.blank? || dryed
35-
self.dry_skip = skip && Array(skip)
36-
self.dry_only = none ? [:none] : only && Array(only)
37+
38+
self.dry_skip = Array(skip).compact.presence
39+
self.dry_only = none ? [:none] : Array(only).compact.presence
3740
dry_blocks.each { |blk| instance_eval(&blk) }
3841
self.dry_skip = self.dry_only = nil
3942
self.dryed = true
4043
end
4144

42-
def param param_type, name, type, required, schema = { }
45+
def param(param_type, name, type, required, schema = { })
4346
return if dry_skip&.include?(name) || dry_only&.exclude?(name)
47+
return unless (schema_obj = process_schema_input(type, schema, name))
4448

45-
return unless schema = process_schema_input(type, schema, name)
46-
param_obj = ParamObj.new(name, param_type, type, required, schema)
47-
# The definition of the same name parameter will be overwritten
48-
index = self[:parameters].map(&:name).index(param_obj.name)
49-
index ? self[:parameters][index] = param_obj : self[:parameters] << param_obj
49+
_all_params[name] = schema.is_a?(Hash) ? schema.merge(type:) : { type: } unless param_type["header"]
50+
override_or_append_to_parameters(
51+
ParamObj.new(name, param_type, type, required, schema_obj)
52+
)
5053
end
51-
5254
alias parameter param
5355

56+
# @!method query(name, type = nil, **schema)
57+
# @!method query!(name, type = nil, **schema)
58+
# @!method in_query(**params)
59+
# @!method in_query!(**params)
5460
%i[ header header! path path! query query! cookie cookie! ].each do |param_type|
55-
define_method param_type do |name, type = nil, **schema|
56-
param param_type, name, type, (param_type['!'] ? :req : :opt), schema
61+
define_method(param_type) do |name, type = nil, **schema|
62+
param param_type, name, type, required?(param_type), schema
5763
end
5864

59-
define_method "in_#{param_type}" do |params|
65+
define_method("in_#{param_type}") do |params|
6066
params.each_pair do |param_name, schema|
61-
param param_type, param_name, nil, (param_type['!'] || param_name['!'] ? :req : :opt), schema
67+
param param_type, param_name, nil, required?(param_type, param_name), schema
6268
end
6369
end
6470
end
6571

66-
def param_ref component_key, *keys
72+
def param_ref(component_key, *keys)
6773
self[:parameters] += [component_key, *keys].map { |key| RefObj.new(:parameter, key) }
6874
end
6975

7076
# options: `exp_params` and `examples`
71-
def request_body required, media_type, data: { }, desc: '', **options
72-
(self[:requestBody] ||= RequestBodyObj.new(required, desc)).absorb(media_type, { data: data , **options })
77+
def request_body(required, media_type, data: { }, desc: "", **options)
78+
self[:requestBody] ||= RequestBodyObj.new(required, desc)
79+
self[:requestBody].absorb(media_type, { data:, **options })
80+
_all_params.merge!(data)
7381
end
7482

75-
def body_ref component_key
76-
self[:requestBody] = RefObj.new(:requestBody, component_key)
77-
end
83+
def body(media_type, data: { }, **) = request_body(:optional, media_type, data:, **)
84+
def body!(media_type, data: { }, **) = request_body(:required, media_type, data:, **)
7885

79-
%i[ body body! ].each do |method|
80-
define_method method do |media_type, data: { }, **options|
81-
request_body (method['!'] ? :req : :opt), media_type, data: data, **options
82-
end
83-
end
84-
85-
def form data:, **options
86-
body :form, data: data, **options
87-
end
86+
def json(data:, **) = body(:json, data:, **)
87+
def json!(data:, **) = body!(:json, data:, **)
88+
def form(data:, **) = body(:form, data:, **)
89+
def form!(data:, **) = body!(:form, data:, **)
8890

89-
def form! data:, **options
90-
body! :form, data: data, **options
91-
end
92-
93-
def data name, type = nil, schema = { }
91+
def data(name, type = nil, schema = { })
9492
schema[:type] = type if type.present?
9593
form data: { name => schema }
9694
end
9795

98-
def response code, desc, media_type = nil, headers: { }, data: { }, **options
99-
(self[:responses][code.to_s] ||= ResponseObj.new(desc)).absorb(desc, media_type, headers: headers, data: data, **options)
96+
def body_ref(component_key)
97+
self[:requestBody] = RefObj.new(:requestBody, component_key)
98+
end
99+
100+
def response(code, desc, media_type = nil, headers: { }, data: { }, **)
101+
self[:responses][code.to_s] ||= ResponseObj.new(desc)
102+
self[:responses][code.to_s].absorb(desc, media_type, headers:, data:, **)
100103
end
101104

102105
alias_method :resp, :response
103106
alias_method :error, :response
104107

105-
def response_ref code_and_compkey # = { }
106-
code_and_compkey.each { |code, component_key| self[:responses][code.to_s] = RefObj.new(:response, component_key) }
108+
def response_ref(code_and_compkey) # = { }
109+
code_and_compkey.each do |code, component_key|
110+
self[:responses][code.to_s] = RefObj.new(:response, component_key)
111+
end
107112
end
108113

109-
def security_require scheme_name, scopes: [ ]
114+
def security_require(scheme_name, scopes: [ ])
110115
self[:security] << { scheme_name => scopes }
111116
end
112117

113118
alias security security_require
114119
alias auth security_require
115120
alias auth_with security_require
116121

117-
def callback event_name, http_method, callback_url, &block
118-
self[:callbacks].deep_merge! CallbackObj.new(event_name, http_method, callback_url, &block).process
122+
def callback(event_name, http_method, callback_url, &block)
123+
self[:callbacks].deep_merge!(
124+
CallbackObj.new(event_name, http_method, callback_url, &block).process
125+
)
119126
end
120127

121-
def server url, desc: ''
128+
def server(url, desc: "")
122129
self[:servers] << { url: url, description: desc }
123130
end
124131

125-
def param_examples exp_params = :all, examples_hash
132+
def param_examples(exp_params = :all, examples_hash)
126133
exp_params = self[:parameters].map(&:name) if exp_params == :all
127134
self[:examples] = ExampleObj.new(examples_hash, exp_params, multiple: true).process
128135
end
@@ -135,10 +142,31 @@ def run_dsl(dry: false, &block)
135142

136143
self[:parameters].map!(&:process)
137144
self[:requestBody] = self[:requestBody].try(:process)
138-
self[:responses].each { |code, response| self[:responses][code] = response.process }
139-
self[:responses] = self[:responses].sort.to_h
145+
self[:responses] = self[:responses].transform_values(&:process).sort.to_h
140146
self.delete_if { |_, v| v.blank? }
141147
end
148+
149+
def all_params
150+
_all_params.transform_values do |t|
151+
if t.is_a?(Hash)
152+
t.key?(:type) ? t.merge!(type: t[:type].to_s.underscore) : { type: t }
153+
else
154+
{ type: t.to_s.underscore }
155+
end
156+
end
157+
end
158+
159+
private
160+
161+
def override_or_append_to_parameters(param_obj)
162+
# The definition of the same name parameter will be override.
163+
index = self[:parameters].map(&:name).index(param_obj.name)
164+
index ? self[:parameters][index] = param_obj : self[:parameters] << param_obj
165+
end
166+
167+
def required?(*passed)
168+
passed.join["!"] ? :required : :optional
169+
end
142170
end
143171
end
144172
end

lib/open_api/dsl/components.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def initialize
1212
end
1313

1414
def schema component_key, type = nil, **schema
15-
return unless schema = process_schema_input(type, schema, component_key, model: component_key)
15+
return unless (schema = process_schema_input(type, schema, component_key))
1616
self[:schemas][component_key.to_s.to_sym] = schema.process
1717
end
1818

@@ -25,7 +25,7 @@ def example component_key, examples_hash
2525
arrow_enable :example
2626

2727
def param component_key, param_type, name, type, required, schema = { }
28-
return unless schema = process_schema_input(type, schema, name)
28+
return unless (schema = process_schema_input(type, schema, name))
2929
self[:parameters][component_key] = ParamObj.new(name, param_type, type, required, schema).process
3030
end
3131

lib/open_api/dsl/helpers.rb

+8-14
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,20 @@ module DSL
1515
module Helpers
1616
extend ActiveSupport::Concern
1717

18-
def load_schema(model) # TODO: test
19-
return unless Config.model_base && model.try(:superclass) == Config.model_base
20-
model.columns.map do |column|
21-
type = column.sql_type_metadata.type.to_s.camelize
22-
type = 'DateTime' if type == 'Datetime'
23-
[ column.name.to_sym, Object.const_get(type) ]
24-
end.to_h rescue ''
25-
end
26-
2718
def _combined_schema(one_of: nil, all_of: nil, any_of: nil, not: nil, **other)
2819
input = (_not = binding.local_variable_get(:not)) || one_of || all_of || any_of
2920
CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, not: _not) if input
3021
end
3122

32-
def process_schema_input(schema_type, schema, name, model: nil)
33-
schema = { type: schema } unless schema.is_a?(Hash)
23+
def process_schema_input(schema_type, schema, name)
24+
if schema.is_a?(Hash)
25+
schema[:type] ||= schema_type
26+
else
27+
schema = { type: schema }
28+
end
3429
combined_schema = _combined_schema(**schema)
35-
type = schema[:type] ||= schema_type
36-
return Tip.param_no_type(name) if type.nil? && combined_schema.nil?
37-
combined_schema || SchemaObj.new(type, load_schema(model) || schema)
30+
return Tip.param_no_type(name) if schema[:type].nil? && combined_schema.nil?
31+
combined_schema || SchemaObj.new(schema[:type], schema)
3832
end
3933

4034
# Arrow Writing:

lib/open_api/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module OpenApi
4-
VERSION = '2.1.5'
4+
VERSION = "2.2.0"
55
end

zero-rails_openapi.gemspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
2121
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
2222
spec.require_paths = ['lib']
2323

24-
spec.required_ruby_version = '>= 2.3.0'
24+
spec.required_ruby_version = '>= 3.0.0'
2525

2626
spec.add_development_dependency 'bundler'
2727
spec.add_development_dependency 'rake'

0 commit comments

Comments
 (0)