meta-api 0.0.6 → 0.0.7
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 +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/config/locales/zh-CN.yml +1 -1
- data/docs//346/225/231/347/250/213.md +53 -5
- data/docs//347/264/242/345/274/225.md +10 -0
- data/examples/rails_app/Gemfile.lock +1 -1
- data/lib/meta/application/execution.rb +25 -10
- data/lib/meta/application/linked_action.rb +7 -9
- data/lib/meta/application/metadata.rb +5 -3
- data/lib/meta/application/parameters.rb +1 -1
- data/lib/meta/application/route.rb +19 -7
- data/lib/meta/config.rb +8 -3
- data/lib/meta/json_schema/builders/schema_builder_tool.rb +7 -1
- data/lib/meta/json_schema/schemas/base_schema.rb +17 -5
- data/lib/meta/json_schema/schemas/object_schema.rb +1 -1
- data/lib/meta/json_schema/schemas/properties.rb +11 -2
- data/lib/meta/json_schema/support/validators.rb +1 -1
- data/lib/meta/route_dsl/application_builder.rb +18 -25
- data/lib/meta/route_dsl/around_action_builder.rb +37 -27
- data/lib/meta/route_dsl/meta_builder.rb +16 -9
- data/lib/meta/route_dsl/parameters_builder.rb +29 -6
- data/lib/meta/route_dsl/route_builder.rb +10 -44
- data/lib/meta/route_dsl/uniformed_params_builder.rb +27 -9
- data/lib/meta/swagger_doc.rb +2 -2
- data/lib/meta/utils/kwargs/builder.rb +4 -2
- data/lib/meta/utils/kwargs/checker.rb +36 -0
- data/lib/meta/utils/path.rb +8 -2
- data/lib/meta/utils/route_dsl_builders.rb +30 -0
- data/meta-api.gemspec +1 -1
- metadata +8 -7
- data/lib/meta/route_dsl/helpers.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c114ab0d95b902ecefcd5e720f0c38fbcc420b2839194842c2974d2d073505fd
|
4
|
+
data.tar.gz: 994b7e975626f9907467edfe4283875aa113957edc860b74ed1b29e27560f196
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b62b24879f309c6cc67e45bc9bfd250b47ec8ad6c25f5fe1e9f5098b970ff8466f239b8799b4e653ebdc5568cbbb87fdd7c086703a99ef8525945ce24c44617
|
7
|
+
data.tar.gz: edec25f4ea37588611af7dceca41a443c5cb6d83586096f51f9f27ce75fdf290ec7085e4f27bf87043779e1ed289f7cbaa0a7e9568839e2ed206eef1d7d4f4b7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# 更新日志
|
2
2
|
|
3
|
+
## 0.0.7(2023 年 7 月 14 日)
|
4
|
+
|
5
|
+
1. 定义 parameters 宏时能够自动识别 `path` 参数。
|
6
|
+
2. 定义 params 宏时能够自动识别 `GET` 路由,此时参数的 `in` 默认为 `query`.
|
7
|
+
3. JsonSchema: `default:` 选项可以是一个块。
|
8
|
+
4. 有且只有一个 `status` 宏定义时,不需要显示地设置 `response.status`.
|
9
|
+
5. `Meta.config` 添加一个新的选析 `default_locked_scope`,借助它可以设置一个默认的 `locked_scope` 值。
|
10
|
+
6. `JsonSchema` 的 `filter` 方法添加一个新的选项 `extra_properties:`,当设定值为 `:ignore` 时可以允许额外的属性。
|
11
|
+
7. 添加新的选项 `config.json_schema_user_options`、`config.json_schema_param_stage_options`、`config.json_schema_render_stage_options`. 借助这三个选项可以对 `JsonSchema#filter` 方法的选项进行设置。同时废弃了 `render_type_conversion`、`render_validation` 等零散的选项。
|
12
|
+
8. `meta` 宏的父级、子级的合并规则调整:parameters、params、responses 都有所合并。
|
13
|
+
|
3
14
|
## 0.0.6(2023 年 5 月 26 日)
|
4
15
|
|
5
16
|
1. 添加了 Meta::Execution#abort_execution! 方法。
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
data/config/locales/zh-CN.yml
CHANGED
@@ -1064,7 +1064,8 @@ end
|
|
1064
1064
|
|
1065
1065
|
```ruby
|
1066
1066
|
params do
|
1067
|
-
param :age, default: 18
|
1067
|
+
param :age, default: 18 # 通过值设定
|
1068
|
+
param :name, default: -> { 'Jim' } # 通过块设定
|
1068
1069
|
end
|
1069
1070
|
```
|
1070
1071
|
|
@@ -1451,15 +1452,62 @@ DemoApp.to_swagger_doc(
|
|
1451
1452
|
|
1452
1453
|
## 全局配置
|
1453
1454
|
|
1454
|
-
###
|
1455
|
+
### 定义默认的 `locked_scope`
|
1455
1456
|
|
1456
|
-
|
1457
|
+
```ruby
|
1458
|
+
Meta.config.default_locked_scope = 'default'
|
1459
|
+
```
|
1460
|
+
|
1461
|
+
当 `Meta::Entity` 被引用时,其没有被锁定 `scope`. 如果我们如上设定了默认的 `scope`,则
|
1462
|
+
|
1463
|
+
```ruby
|
1464
|
+
param :user, ref: UserEntity
|
1465
|
+
```
|
1466
|
+
|
1467
|
+
的效果等价于
|
1468
|
+
|
1469
|
+
```ruby
|
1470
|
+
param :user, ref: UserEntity.lock_scope('default')
|
1471
|
+
```
|
1472
|
+
|
1473
|
+
这样做对生成文档有帮助。因为我们没有锁定 `UserEntity`,则文档中它的所有属性都会被列出来,而在实际执行时却不能得到带有 `scope` 标记的字段,这样往往在造成文档和实际情况的不一致。
|
1474
|
+
|
1475
|
+
### 定义 `JsonSchema#filter` 方法的 `user_options`
|
1476
|
+
|
1477
|
+
```ruby
|
1478
|
+
Meta.config.json_schema_user_options = {...}
|
1479
|
+
Meta.config.json_schema_param_stage_options = {...}
|
1480
|
+
Meta.config.json_schema_render_stage_options = {...}
|
1481
|
+
```
|
1482
|
+
|
1483
|
+
**示例一:关闭渲染时验证**
|
1484
|
+
|
1485
|
+
渲染时不执行类型转换和数据验证:
|
1486
|
+
```ruby
|
1487
|
+
Meta.config.json_schema_render_stage_options = {
|
1488
|
+
type_conversion: false,
|
1489
|
+
render_validation: false
|
1490
|
+
}
|
1491
|
+
```
|
1492
|
+
|
1493
|
+
**示例二:默认使用 `discard_missing: true` 方案**
|
1457
1494
|
|
1458
1495
|
```ruby
|
1459
|
-
Meta.config.
|
1460
|
-
|
1496
|
+
Meta.config.json_schema_user_options = {
|
1497
|
+
discard_missing: true
|
1498
|
+
}
|
1461
1499
|
```
|
1462
1500
|
|
1501
|
+
或仅在参数阶段使用 `discard_missing: true` 方案:
|
1502
|
+
|
1503
|
+
```ruby
|
1504
|
+
Meta.config.json_schema_param_stage_options = {
|
1505
|
+
discard_missing: true
|
1506
|
+
}
|
1507
|
+
```
|
1508
|
+
|
1509
|
+
> 提示:可以传入一切 `JsonSchema#filter` 支持的选项,参考 [JsonSchema#filter 支持的选项](索引.md)。
|
1510
|
+
|
1463
1511
|
## 特殊用法举例
|
1464
1512
|
|
1465
1513
|
### 路由中实体定义的特殊用法
|
@@ -171,3 +171,13 @@ end
|
|
171
171
|
```
|
172
172
|
|
173
173
|
面对这两种使用方式,有何使用上的建议呢?我的建议是,你习惯用哪种就用哪种。
|
174
|
+
|
175
|
+
## `JsonSchema#filter` 方法的用户选项
|
176
|
+
|
177
|
+
### `discard_missing:`
|
178
|
+
|
179
|
+
规定是否忽略缺失的属性。所谓缺失的属性,是指在 `ObjectSchema` 实体宏中定义,但数据中不包含这个键值的属性。你可以将 `discard_missing: true` 视为 HTTP Patch 方法,`discard_missing: false` 视为 HTTP Put 方法。
|
180
|
+
|
181
|
+
### `extra_properties:`
|
182
|
+
|
183
|
+
规定多余的属性的处理办法。所谓多余的属性,是指未在 `ObjectSchema` 实体宏中定义,但数据中依然存在这个键值的属性。一般来讲我们允许前端传递一些多余的属性,但可能在内部测试时设定为更严格的条件。
|
@@ -9,7 +9,7 @@ module Meta
|
|
9
9
|
|
10
10
|
def initialize(request)
|
11
11
|
@request = request
|
12
|
-
@response = Rack::Response.new
|
12
|
+
@response = Rack::Response.new([], 0) # 状态码初始为 0,代表一个未设置状态
|
13
13
|
@parameters = {}
|
14
14
|
end
|
15
15
|
|
@@ -75,11 +75,6 @@ module Meta
|
|
75
75
|
self.parameters = parameters_meta.filter(request).freeze
|
76
76
|
end
|
77
77
|
|
78
|
-
# parse_params 不再解析参数了,而只是设置 @params_schema,并清理父路由解析的变量
|
79
|
-
def parse_params(params_schema)
|
80
|
-
@params_schema = params_schema
|
81
|
-
end
|
82
|
-
|
83
78
|
def parse_request_body(schema)
|
84
79
|
@request_body_schema = schema
|
85
80
|
end
|
@@ -99,7 +94,12 @@ module Meta
|
|
99
94
|
options = {}
|
100
95
|
end
|
101
96
|
|
102
|
-
new_hash = entity_schema.filter(hash,
|
97
|
+
new_hash = entity_schema.filter(hash,
|
98
|
+
**Meta.config.json_schema_user_options,
|
99
|
+
**Meta.config.json_schema_render_stage_options,
|
100
|
+
**options,
|
101
|
+
execution: self, stage: :render
|
102
|
+
)
|
103
103
|
response.content_type = 'application/json' if response.content_type.nil?
|
104
104
|
response.body = [JSON.generate(new_hash)]
|
105
105
|
else
|
@@ -109,7 +109,12 @@ module Meta
|
|
109
109
|
renders.each do |key, render_content|
|
110
110
|
raise Errors::RenderingError, "渲染的键名 `#{key}` 不存在,请检查实体定义以确认是否有拼写错误" unless entity_schema.properties.key?(key)
|
111
111
|
schema = entity_schema.properties[key].schema(:render)
|
112
|
-
final_value[key] = schema.filter(render_content[:value],
|
112
|
+
final_value[key] = schema.filter(render_content[:value],
|
113
|
+
**Meta.config.json_schema_user_options,
|
114
|
+
**Meta.config.json_schema_render_stage_options,
|
115
|
+
**render_content[:options],
|
116
|
+
execution: self, stage: :render
|
117
|
+
)
|
113
118
|
rescue JsonSchema::ValidationErrors => e
|
114
119
|
# 错误信息再度绑定 key
|
115
120
|
errors.merge! e.errors.transform_keys! { |k| k.empty? ? key : "#{key}.#{k}" }
|
@@ -148,13 +153,23 @@ module Meta
|
|
148
153
|
end
|
149
154
|
|
150
155
|
def parse_request_body_for_replacing
|
151
|
-
request_body_schema.filter(
|
156
|
+
request_body_schema.filter(
|
157
|
+
params(:raw),
|
158
|
+
**Meta.config.json_schema_user_options,
|
159
|
+
**Meta.config.json_schema_param_stage_options,
|
160
|
+
execution: self, stage: :param
|
161
|
+
)
|
152
162
|
rescue JsonSchema::ValidationErrors => e
|
153
163
|
raise Errors::ParameterInvalid.new(e.errors)
|
154
164
|
end
|
155
165
|
|
156
166
|
def parse_request_body_for_updating
|
157
|
-
request_body_schema.filter(
|
167
|
+
request_body_schema.filter(
|
168
|
+
params(:raw),
|
169
|
+
**Meta.config.json_schema_user_options,
|
170
|
+
**Meta.config.json_schema_param_stage_options,
|
171
|
+
execution: self, stage: :param, discard_missing: true
|
172
|
+
)
|
158
173
|
rescue JsonSchema::ValidationErrors => e
|
159
174
|
raise Errors::ParameterInvalid.new(e.errors)
|
160
175
|
end
|
@@ -3,16 +3,14 @@
|
|
3
3
|
# 洋葱圈模型的链式调用,需要结合 Meta::RouteDSL::AroundActionBuilder 才可以看到它奇效。
|
4
4
|
|
5
5
|
module Meta
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
class LinkedAction
|
7
|
+
def initialize(current_proc, next_action)
|
8
|
+
@current_proc = current_proc
|
9
|
+
@next_action = next_action
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
12
|
+
def execute(execution)
|
13
|
+
execution.instance_exec(@next_action, &@current_proc)
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
@@ -11,7 +11,7 @@ module Meta
|
|
11
11
|
@tags = tags
|
12
12
|
@parameters = parameters.is_a?(Parameters) ? parameters : Parameters.new(parameters)
|
13
13
|
@request_body = request_body
|
14
|
-
@responses = responses || { 204 => nil }
|
14
|
+
@responses = responses || {} # || { 204 => nil }
|
15
15
|
end
|
16
16
|
|
17
17
|
def [](key)
|
@@ -54,8 +54,10 @@ module Meta
|
|
54
54
|
operation_object.compact
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
class << self
|
58
|
+
def new(meta = {})
|
59
|
+
meta.is_a?(Metadata) ? meta : super(**meta)
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
@@ -10,6 +10,7 @@ module Meta
|
|
10
10
|
|
11
11
|
attr_reader :path, :method, :meta, :action
|
12
12
|
|
13
|
+
# path 是局部 path,不包含由父级定义的前缀
|
13
14
|
def initialize(path: '', method: :all, meta: {}, action: nil)
|
14
15
|
@path = Utils::Path.normalize_path(path)
|
15
16
|
@method = method
|
@@ -25,9 +26,10 @@ module Meta
|
|
25
26
|
|
26
27
|
action.execute(execution) if action
|
27
28
|
|
29
|
+
set_status(execution)
|
28
30
|
render_entity(execution) if @meta[:responses]
|
29
31
|
rescue Execution::Abort
|
30
|
-
|
32
|
+
execution.response.status = 200 if execution.response.status == 0
|
31
33
|
end
|
32
34
|
|
33
35
|
def match?(execution, remaining_path)
|
@@ -42,14 +44,24 @@ module Meta
|
|
42
44
|
|
43
45
|
private
|
44
46
|
|
47
|
+
def set_status(execution)
|
48
|
+
response_definitions = @meta[:responses]
|
49
|
+
response = execution.response
|
50
|
+
if response.status == 0
|
51
|
+
response.status = (response_definitions&.length > 0) ? response_definitions.keys[0] : 200
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
45
55
|
def render_entity(execution)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
56
|
+
response_definitions = @meta[:responses]
|
57
|
+
return if response_definitions.empty? # 未设定 status 宏时不需要执行 render_entity 方法
|
58
|
+
|
59
|
+
# 查找 entity schema
|
60
|
+
entity_schema = response_definitions[execution.response.status]
|
61
|
+
return if entity_schema.nil?
|
50
62
|
|
51
|
-
|
52
|
-
execution.render_entity(entity_schema)
|
63
|
+
# 执行面向 schema 的渲染
|
64
|
+
execution.render_entity(entity_schema)
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
data/lib/meta/config.rb
CHANGED
@@ -2,11 +2,16 @@
|
|
2
2
|
|
3
3
|
module Meta
|
4
4
|
class Config
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :default_locked_scope,
|
6
|
+
:json_schema_user_options,
|
7
|
+
:json_schema_param_stage_options,
|
8
|
+
:json_schema_render_stage_options
|
6
9
|
|
7
10
|
def initialize
|
8
|
-
@
|
9
|
-
@
|
11
|
+
@default_locked_scope = nil
|
12
|
+
@json_schema_user_options = {}
|
13
|
+
@json_schema_param_stage_options = {}
|
14
|
+
@json_schema_render_stage_options = {}
|
10
15
|
end
|
11
16
|
end
|
12
17
|
|
@@ -12,7 +12,13 @@ module Meta
|
|
12
12
|
SCHEMA_BUILDER_OPTIONS = Utils::KeywordArgs::Builder.build do
|
13
13
|
permit_extras true
|
14
14
|
|
15
|
-
key :ref, alias_names: [:using]
|
15
|
+
key :ref, alias_names: [:using], normalizer: ->(entity) {
|
16
|
+
if Meta.config.default_locked_scope && entity.is_a?(Class) && entity < Meta::Entity
|
17
|
+
entity.locked(scope: Meta.config.default_locked_scope)
|
18
|
+
else
|
19
|
+
entity
|
20
|
+
end
|
21
|
+
}
|
16
22
|
key :dynamic_ref, alias_names: [:dynamic_using], normalizer: ->(value) { value.is_a?(Proc) ? { resolve: value } : value }
|
17
23
|
end
|
18
24
|
def build(options = {}, &block)
|
@@ -25,14 +25,16 @@ module Meta
|
|
25
25
|
options = OPTIONS_CHECKER.check(options)
|
26
26
|
raise '不允许 BaseSchema 直接接受 array 类型,必须通过继承使用 ArraySchema' if options[:type] == 'array' && self.class == BaseSchema
|
27
27
|
|
28
|
-
@options = SchemaOptions.normalize(options)
|
28
|
+
@options = SchemaOptions.normalize(options).freeze
|
29
29
|
end
|
30
30
|
|
31
31
|
USER_OPTIONS_CHECKER = Utils::KeywordArgs::Builder.build do
|
32
|
-
key :
|
32
|
+
key :execution, :object_value, :type_conversion, :validation, :user_data
|
33
|
+
key :stage, validator: ->(value) { raise ArgumentError, "stage 只能取值为 :param 或 :render" unless [:param, :render].include?(value) }
|
33
34
|
|
34
|
-
#
|
35
|
-
|
35
|
+
# 以下是 ObjectSchema 需要的选项
|
36
|
+
# extra_properties 只能取值为 :ignore、:raise_error
|
37
|
+
key :discard_missing, :extra_properties, :exclude, :scope
|
36
38
|
end
|
37
39
|
|
38
40
|
def filter(value, user_options = {})
|
@@ -40,7 +42,7 @@ module Meta
|
|
40
42
|
|
41
43
|
value = resolve_value(user_options) if options[:value]
|
42
44
|
value = JsonSchema::Presenters.present(options[:presenter], value) if options[:presenter]
|
43
|
-
value = options[:default] if value.nil? && options.key?(:default)
|
45
|
+
value = resolve_default_value(options[:default]) if value.nil? && options.key?(:default)
|
44
46
|
value = options[:convert].call(value) if options[:convert]
|
45
47
|
|
46
48
|
# 第一步,转化值。
|
@@ -110,6 +112,16 @@ module Meta
|
|
110
112
|
validator&.call(value, option, stage_options)
|
111
113
|
end
|
112
114
|
end
|
115
|
+
|
116
|
+
def resolve_default_value(default_resolver)
|
117
|
+
if default_resolver.respond_to?(:call)
|
118
|
+
default_resolver.call
|
119
|
+
elsif default_resolver.respond_to?(:dup)
|
120
|
+
default_resolver.dup
|
121
|
+
else
|
122
|
+
default_resolver
|
123
|
+
end
|
124
|
+
end
|
113
125
|
end
|
114
126
|
end
|
115
127
|
end
|
@@ -92,7 +92,7 @@ module Meta
|
|
92
92
|
object = {}
|
93
93
|
errors = {}
|
94
94
|
filtered_properties.each do |name, property_schema|
|
95
|
-
value = resolve_property_value(object_value, name, property_schema
|
95
|
+
value = resolve_property_value(object_value, name, property_schema)
|
96
96
|
|
97
97
|
begin
|
98
98
|
object[name] = property_schema.filter(value, **user_options, object_value: object_value)
|
@@ -101,6 +101,11 @@ module Meta
|
|
101
101
|
end
|
102
102
|
end.to_h
|
103
103
|
|
104
|
+
# 第三步,检测是否有剩余的属性
|
105
|
+
if user_options[:extra_properties] == :raise_error && !(object_value.keys.map(&:to_sym) - properties.keys).empty?
|
106
|
+
raise JsonSchema::ValidationError, '遇到多余的属性'
|
107
|
+
end
|
108
|
+
|
104
109
|
if errors.empty?
|
105
110
|
object
|
106
111
|
else
|
@@ -122,6 +127,10 @@ module Meta
|
|
122
127
|
# 程序中有些地方用到了这三个方法
|
123
128
|
def_delegators :@properties, :empty?, :key?, :[]
|
124
129
|
|
130
|
+
def merge(properties)
|
131
|
+
self.class.new(@properties.merge(properties.instance_eval { @properties }))
|
132
|
+
end
|
133
|
+
|
125
134
|
def self.build_property(*args)
|
126
135
|
StagingProperty.build(*args)
|
127
136
|
end
|
@@ -143,7 +152,7 @@ module Meta
|
|
143
152
|
end
|
144
153
|
end
|
145
154
|
|
146
|
-
def resolve_property_value(object_value, name, property_schema
|
155
|
+
def resolve_property_value(object_value, name, property_schema)
|
147
156
|
if property_schema.value?
|
148
157
|
nil
|
149
158
|
elsif object_value.is_a?(Hash) || object_value.is_a?(ObjectWrapper)
|
@@ -28,7 +28,7 @@ module Meta
|
|
28
28
|
},
|
29
29
|
allowable: proc { |value, allowable_values|
|
30
30
|
next if value.nil?
|
31
|
-
raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.allowable') unless allowable_values.include?(value)
|
31
|
+
raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.allowable', allowable_values: allowable_values) unless allowable_values.include?(value)
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
@@ -2,39 +2,36 @@
|
|
2
2
|
|
3
3
|
require_relative 'route_builder'
|
4
4
|
require_relative 'meta_builder'
|
5
|
+
require_relative '../utils/route_dsl_builders'
|
5
6
|
|
6
7
|
module Meta
|
7
8
|
module RouteDSL
|
8
9
|
class ApplicationBuilder
|
9
10
|
include MetaBuilder::Delegator
|
10
11
|
|
11
|
-
def initialize(
|
12
|
-
@
|
12
|
+
def initialize(full_prefix = '/', &block)
|
13
|
+
@full_prefix = full_prefix
|
13
14
|
@callbacks = []
|
14
15
|
@error_guards = []
|
15
|
-
@meta_builder = MetaBuilder.new
|
16
|
+
@meta_builder = MetaBuilder.new(route_full_path: full_prefix)
|
16
17
|
@mod_builders = []
|
17
18
|
@shared_mods = []
|
18
19
|
|
19
20
|
instance_exec &block if block_given?
|
20
21
|
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
parent_before = callbacks.filter { |cb| cb[:lifecycle] == :before || cb[:lifecycle] == :around }
|
32
|
-
parent_after = callbacks.filter { |cb| cb[:lifecycle] == :after }
|
33
|
-
callbacks = parent_before + @callbacks + parent_after
|
34
|
-
mods = @mod_builders.map { |builder| builder.build(parent_path: Utils::Path.join(parent_path, @mod_prefix), meta: meta2, callbacks: callbacks) }
|
23
|
+
# meta 和 callbacks 是父级传递过来的,需要合并到当前模块或子模块中。
|
24
|
+
#
|
25
|
+
# 为什么一定要动态传递 meta_options 参数?由于 OpenAPI 文档是面向路由的,parameters、request_body、
|
26
|
+
# responses 都存在于路由文档中,对应地 Metadata 对象最终只存在于路由文档中。因此,在构建过程中,需要将父
|
27
|
+
# 级传递过来的 Metadata 对象合并到当前模块,再层层合并到子模块。
|
28
|
+
def build(meta_options: {}, callbacks: [])
|
29
|
+
meta_options = Utils::RouteDSLBuilders.merge_meta_options(meta_options, @meta_builder.build)
|
30
|
+
callbacks = Utils::RouteDSLBuilders.merge_callbacks(callbacks, @callbacks)
|
31
|
+
mods = @mod_builders.map { |builder| builder.build(meta_options: meta_options, callbacks: callbacks) }
|
35
32
|
|
36
33
|
Application.new(
|
37
|
-
prefix: @
|
34
|
+
prefix: @full_prefix,
|
38
35
|
mods: mods,
|
39
36
|
shared_mods: @shared_mods,
|
40
37
|
error_guards: @error_guards
|
@@ -48,7 +45,7 @@ module Meta
|
|
48
45
|
|
49
46
|
# 定义路由块
|
50
47
|
def route(path, method = nil, &block)
|
51
|
-
route_builder =
|
48
|
+
route_builder = RouteBuilder.new(path, method, parent_path: @full_prefix, &block)
|
52
49
|
@mod_builders << route_builder
|
53
50
|
route_builder
|
54
51
|
end
|
@@ -108,13 +105,9 @@ module Meta
|
|
108
105
|
@meta = meta
|
109
106
|
end
|
110
107
|
|
111
|
-
def build(
|
112
|
-
|
113
|
-
|
114
|
-
if meta[:parameters] && meta2[:parameters]
|
115
|
-
meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
|
116
|
-
end
|
117
|
-
@builder.build(parent_path: parent_path, meta: meta2, **kwargs)
|
108
|
+
def build(meta_options: {}, **kwargs)
|
109
|
+
meta_options = Utils::RouteDSLBuilders.merge_meta_options(meta_options, @meta)
|
110
|
+
@builder.build(meta_options: meta_options, **kwargs)
|
118
111
|
end
|
119
112
|
end
|
120
113
|
end
|
@@ -45,35 +45,45 @@ module Meta
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
48
|
+
class << self
|
49
|
+
# 使用 before、after、around 系列和当前 action 共同构建洋葱圈模型。
|
50
|
+
# Note: 该方法已被废弃!
|
51
|
+
#
|
52
|
+
# 构建成功后,执行顺序是:
|
53
|
+
#
|
54
|
+
# - before 序列
|
55
|
+
# - around 序列的前半部分
|
56
|
+
# - action
|
57
|
+
# - around 序列的后半部分
|
58
|
+
# - after 序列
|
59
|
+
#
|
60
|
+
def build(before: [], after: [], around: [], action: nil)
|
61
|
+
builder = AroundActionBuilder.new
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
63
|
+
# 首先构建 before 序列,保证它最先执行
|
64
|
+
builder.around do |next_action|
|
65
|
+
before.each { |p| self.instance_exec(&p) }
|
66
|
+
next_action.execute(self)
|
67
|
+
end unless before.empty?
|
68
|
+
# 然后构建 after 序列,保证它最后执行
|
69
|
+
builder.around do |next_action|
|
70
|
+
next_action.execute(self)
|
71
|
+
after.each { |p| self.instance_exec(&p) }
|
72
|
+
end unless after.empty?
|
73
|
+
# 接着应用洋葱圈模型,依次构建 around 序列、action
|
74
|
+
around.each { |p| builder.around(&p) }
|
75
|
+
builder.around { self.instance_exec(&action) } unless action.nil?
|
75
76
|
|
76
|
-
|
77
|
+
builder.build
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_from_callbacks(callbacks: [])
|
81
|
+
around_action_builder = AroundActionBuilder.new
|
82
|
+
callbacks.each do |cb|
|
83
|
+
around_action_builder.send(cb[:lifecycle], &cb[:proc]) if cb[:proc]
|
84
|
+
end
|
85
|
+
around_action_builder.build
|
86
|
+
end
|
77
87
|
end
|
78
88
|
end
|
79
89
|
end
|
@@ -6,32 +6,39 @@ require_relative 'uniformed_params_builder'
|
|
6
6
|
module Meta
|
7
7
|
module RouteDSL
|
8
8
|
class MetaBuilder
|
9
|
-
def initialize(&block)
|
9
|
+
def initialize(route_full_path:, route_method: :all, &block)
|
10
|
+
@route_full_path = route_full_path
|
11
|
+
@method = route_method
|
10
12
|
@meta = {}
|
13
|
+
@parameters_builder = ParametersBuilder.new(route_full_path: route_full_path, route_method: route_method) # 默认给一个空的参数构建器,它只会处理 path 参数
|
11
14
|
|
12
15
|
instance_exec &block if block_given?
|
13
16
|
end
|
14
17
|
|
15
18
|
def build
|
16
|
-
@meta
|
19
|
+
meta = @meta
|
20
|
+
if @meta[:parameters].nil? && @route_full_path =~ /[:*].+/
|
21
|
+
meta[:parameters] = ParametersBuilder.new(route_full_path: @route_full_path, route_method: @method).build
|
22
|
+
end
|
23
|
+
meta
|
17
24
|
end
|
18
25
|
|
19
26
|
def parameters(&block)
|
20
|
-
@meta[:parameters] = ParametersBuilder.new(&block).build
|
27
|
+
@meta[:parameters] = ParametersBuilder.new(route_full_path: @route_full_path, route_method: @method, &block).build
|
21
28
|
end
|
22
29
|
|
23
30
|
def request_body(options = {}, &block)
|
24
|
-
@meta[:request_body] = JsonSchema::SchemaBuilderTool.build(options, &block)
|
31
|
+
@meta[:request_body] = JsonSchema::SchemaBuilderTool.build(options, &block).to_schema
|
25
32
|
end
|
26
33
|
|
27
34
|
# params 宏是一个遗留的宏,它在一个宏定义块内同时定义 parameters 和 request_body
|
28
35
|
def params(&block)
|
29
|
-
@meta[:parameters], @meta[:request_body] = UniformedParamsBuilder.new(&block).build
|
36
|
+
@meta[:parameters], @meta[:request_body] = UniformedParamsBuilder.new(route_full_path: @route_full_path, route_method: @method, &block).build
|
30
37
|
end
|
31
38
|
|
32
|
-
def status(code, *other_codes, &block)
|
39
|
+
def status(code, *other_codes, **options, &block)
|
33
40
|
codes = [code, *other_codes]
|
34
|
-
entity_schema = JsonSchema::SchemaBuilderTool.build(&block)
|
41
|
+
entity_schema = JsonSchema::SchemaBuilderTool.build(options, &block)
|
35
42
|
@meta[:responses] = @meta[:responses] || {}
|
36
43
|
codes.each { |code| @meta[:responses][code] = entity_schema }
|
37
44
|
end
|
@@ -47,8 +54,8 @@ module Meta
|
|
47
54
|
module Delegator
|
48
55
|
method_names = MetaBuilder.public_instance_methods(false) - ['build']
|
49
56
|
method_names.each do |method_name|
|
50
|
-
define_method(method_name) do |*args, &block|
|
51
|
-
@meta_builder.send(method_name, *args, &block) and self
|
57
|
+
define_method(method_name) do |*args, **kwargs, &block|
|
58
|
+
@meta_builder.send(method_name, *args, **kwargs, &block) and self
|
52
59
|
end
|
53
60
|
end
|
54
61
|
end
|
@@ -1,24 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require_relative '../application/parameters'
|
4
|
+
require_relative '../utils/kwargs/checker'
|
3
5
|
|
4
6
|
module Meta
|
5
7
|
module RouteDSL
|
6
8
|
class ParametersBuilder
|
7
|
-
def initialize(&block)
|
8
|
-
@
|
9
|
+
def initialize(route_full_path:, route_method:, &block)
|
10
|
+
@route_full_path = route_full_path || ''
|
11
|
+
@route_method = route_method
|
12
|
+
@parameter_options = {}
|
9
13
|
|
10
14
|
instance_exec &block if block_given?
|
11
15
|
end
|
12
16
|
|
13
|
-
def param(name, options)
|
17
|
+
def param(name, options = {})
|
18
|
+
# 修正 path 参数的选项
|
14
19
|
options = options.dup
|
15
|
-
|
20
|
+
if path_param_names.include?(name) # path 参数
|
21
|
+
options = Utils::KeywordArgs::Checker.fix!(options, in: 'path', required: true)
|
22
|
+
else
|
23
|
+
options = Utils::KeywordArgs::Checker.merge_defaults!(options, in: 'query')
|
24
|
+
end
|
16
25
|
|
17
|
-
|
26
|
+
in_op = options.delete(:in)
|
27
|
+
@parameter_options[name] = { in: in_op, schema: JsonSchema::BaseSchema.new(options) }
|
18
28
|
end
|
19
29
|
|
20
30
|
def build
|
21
|
-
|
31
|
+
# 补充未声明的 path 参数
|
32
|
+
(path_param_names - @parameter_options.keys).each do |name|
|
33
|
+
@parameter_options[name] = { in: 'path', schema: JsonSchema::BaseSchema.new(required: true) }
|
34
|
+
end
|
35
|
+
|
36
|
+
Parameters.new(@parameter_options)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def path_param_names
|
42
|
+
@_path_param_names ||= @route_full_path.split('/')
|
43
|
+
.filter { |part| part =~ /[:*].+/ }
|
44
|
+
.map { |part| part[1..-1].to_sym }
|
22
45
|
end
|
23
46
|
end
|
24
47
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'json'
|
4
4
|
require_relative '../entity'
|
5
5
|
require_relative '../application/route'
|
6
|
-
require_relative 'helpers'
|
7
6
|
require_relative 'chain_builder'
|
8
7
|
require_relative 'action_builder'
|
9
8
|
require_relative 'meta_builder'
|
@@ -16,52 +15,27 @@ module Meta
|
|
16
15
|
|
17
16
|
alias :if_status :status
|
18
17
|
|
19
|
-
|
18
|
+
# 这里的 path 局部的路径,也就是由 route 宏命令定义的路径
|
19
|
+
def initialize(path, method = :all, parent_path: '',&block)
|
20
|
+
route_full_path = Utils::Path.join(parent_path, path)
|
21
|
+
|
20
22
|
@path = path || ''
|
21
23
|
@method = method || :all
|
22
24
|
@action_builder = nil
|
23
|
-
@meta_builder = MetaBuilder.new
|
25
|
+
@meta_builder = MetaBuilder.new(route_full_path: route_full_path, route_method: method)
|
24
26
|
|
25
27
|
instance_exec &block if block_given?
|
26
28
|
end
|
27
29
|
|
28
|
-
def build(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
|
33
|
-
end
|
34
|
-
|
35
|
-
# 合并 parameters 参数
|
36
|
-
meta2[:parameters] ||= {}
|
37
|
-
path_params = Utils::Path.join(parent_path, @path).split('/')
|
38
|
-
.filter { |part| part =~ /[:*].+/ }
|
39
|
-
.map { |part| part[1..-1].to_sym }
|
40
|
-
path_params.each do |name|
|
41
|
-
unless meta2[:parameters].key?(name)
|
42
|
-
meta2[:parameters][name] = {
|
43
|
-
in: 'path',
|
44
|
-
schema: JsonSchema::BaseSchema.new(required: true)
|
45
|
-
}
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# 构建洋葱圈模型的 LinkedAction
|
50
|
-
# 合并父级传递过来的 callbacks,将 before 和 around 放在前面,after 放在后面
|
51
|
-
parent_before = callbacks.filter { |cb| cb[:lifecycle] == :before || cb[:lifecycle] == :around }
|
52
|
-
parent_after = callbacks.filter { |cb| cb[:lifecycle] == :after }
|
53
|
-
callbacks = parent_before + [{ lifecycle: :before, proc: @action_builder&.build }] + parent_after
|
54
|
-
# 使用 AroundActionBuilder 构建洋葱圈模型
|
55
|
-
around_action_builder = AroundActionBuilder.new
|
56
|
-
callbacks.each do |cb|
|
57
|
-
around_action_builder.send(cb[:lifecycle], &cb[:proc]) if cb[:proc]
|
58
|
-
end
|
59
|
-
action = around_action_builder.build
|
30
|
+
def build(meta_options: {}, callbacks: {})
|
31
|
+
meta_options = Utils::RouteDSLBuilders.merge_meta_options(meta_options, @meta_builder.build)
|
32
|
+
callbacks = Utils::RouteDSLBuilders.merge_callbacks(callbacks, [{ lifecycle: :before, proc: @action_builder&.build }])
|
33
|
+
action = AroundActionBuilder.build_from_callbacks(callbacks: callbacks)
|
60
34
|
|
61
35
|
Route.new(
|
62
36
|
path: @path,
|
63
37
|
method: @method,
|
64
|
-
meta:
|
38
|
+
meta: meta_options,
|
65
39
|
action: action
|
66
40
|
)
|
67
41
|
end
|
@@ -81,14 +55,6 @@ module Meta
|
|
81
55
|
self
|
82
56
|
end
|
83
57
|
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def clone_meta(meta)
|
88
|
-
meta = meta.clone
|
89
|
-
meta[:responses] = meta[:responses].clone if meta[:responses]
|
90
|
-
meta
|
91
|
-
end
|
92
58
|
end
|
93
59
|
end
|
94
60
|
end
|
@@ -3,31 +3,49 @@
|
|
3
3
|
module Meta
|
4
4
|
module RouteDSL
|
5
5
|
class UniformedParamsBuilder
|
6
|
-
def initialize(&block)
|
7
|
-
@
|
8
|
-
@
|
6
|
+
def initialize(route_full_path:, route_method:, &block)
|
7
|
+
@route_full_path = route_full_path
|
8
|
+
@route_method = route_method
|
9
|
+
@parameters_builder = ParametersBuilder.new(route_full_path: @route_full_path, route_method: @route_method)
|
10
|
+
|
11
|
+
@parameter_options = {}
|
9
12
|
|
10
13
|
instance_exec &block if block_given?
|
11
14
|
end
|
12
15
|
|
13
16
|
def param(name, options = {}, &block)
|
14
|
-
options = options.dup
|
15
|
-
|
17
|
+
options = (options || {}).dup
|
18
|
+
in_op = options.delete(:in) || \
|
19
|
+
if path_param_names.include?(name)
|
20
|
+
'path'
|
21
|
+
elsif @route_method == :get
|
22
|
+
'query'
|
23
|
+
else
|
24
|
+
'body'
|
25
|
+
end
|
16
26
|
|
17
|
-
if
|
27
|
+
if in_op == 'body'
|
18
28
|
property name, options, &block
|
19
29
|
else
|
20
|
-
@
|
30
|
+
@parameters_builder.param name, options
|
21
31
|
end
|
22
32
|
end
|
23
33
|
|
24
34
|
def property(name, options = {}, &block)
|
35
|
+
@request_body_builder ||= JsonSchema::ObjectSchemaBuilder.new
|
25
36
|
@request_body_builder.property name, options, &block
|
26
37
|
end
|
27
38
|
|
28
39
|
def build
|
29
|
-
|
30
|
-
|
40
|
+
[@parameters_builder.build, @request_body_builder&.to_schema]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def path_param_names
|
46
|
+
@_path_param_names ||= @route_full_path.split('/')
|
47
|
+
.filter { |part| part =~ /[:*].+/ }
|
48
|
+
.map { |part| part[1..-1].to_sym }
|
31
49
|
end
|
32
50
|
end
|
33
51
|
end
|
data/lib/meta/swagger_doc.rb
CHANGED
@@ -47,13 +47,13 @@ module Meta
|
|
47
47
|
# ]
|
48
48
|
def get_paths_and_routes!(application, prefix = '', store_routes = [])
|
49
49
|
if (application.is_a?(Class) && application < Application) || application.is_a?(Application)
|
50
|
-
prefix =
|
50
|
+
prefix = Utils::Path.join(prefix, application.prefix)
|
51
51
|
(application.routes + application.applications).each do |mod|
|
52
52
|
get_paths_and_routes!(mod, prefix, store_routes)
|
53
53
|
end
|
54
54
|
elsif application.is_a?(Route)
|
55
55
|
route = application
|
56
|
-
route_path = route.path == :all ? prefix :
|
56
|
+
route_path = route.path == :all ? prefix : Utils::Path.join(prefix, route.path)
|
57
57
|
store_routes << [route_path, route] unless route.method == :all
|
58
58
|
else
|
59
59
|
raise "Param application must be a Application instance, Application module or a Route instance, but it got a `#{application}`"
|
@@ -55,10 +55,11 @@ module Meta
|
|
55
55
|
class Argument
|
56
56
|
DEFAULT_TRANSFORMER = ->(value) { value }
|
57
57
|
|
58
|
-
def initialize(name:, normalizer: DEFAULT_TRANSFORMER, alias_names: [])
|
58
|
+
def initialize(name:, normalizer: DEFAULT_TRANSFORMER, validator: nil, default: nil, alias_names: [])
|
59
59
|
@key_name = name
|
60
60
|
@consumer_names = [name] + alias_names
|
61
|
-
@normalizer = normalizer
|
61
|
+
@normalizer = default ? ->(value) { normalizer.call(value || default) } : normalizer
|
62
|
+
@validator = validator
|
62
63
|
end
|
63
64
|
|
64
65
|
def consume(final_args, args)
|
@@ -71,6 +72,7 @@ module Meta
|
|
71
72
|
def consume_name(final_args, args, consumer_name)
|
72
73
|
if args.key?(consumer_name)
|
73
74
|
value = @normalizer.call(args.delete(consumer_name))
|
75
|
+
@validator.call(value) if @validator
|
74
76
|
final_args[@key_name] = value
|
75
77
|
true
|
76
78
|
else
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meta
|
4
|
+
module Utils
|
5
|
+
class KeywordArgs
|
6
|
+
module Checker
|
7
|
+
class << self
|
8
|
+
# 将 options 内的值修正为固定值,该方法会原地修改 options 选项。
|
9
|
+
# 如果 options 中的缺失相应的值,则使用 fixed_values 中的值补充;如果 options 中的值不等于 fixed_values 中对应的值,则抛出异常。
|
10
|
+
# 示例:
|
11
|
+
# (1)fix!({}, { a: 1, b: 2 }) # => { a: 1, b: 2 }
|
12
|
+
# (2)fix!({ a: 1 }, { a: 2 }) # raise error
|
13
|
+
def fix!(options, fixed_values)
|
14
|
+
fixed_values.each do |key, value|
|
15
|
+
if options.include?(key)
|
16
|
+
if options[key] != value
|
17
|
+
raise ArgumentError, "关键字参数 #{key} 的值不正确,必须为 #{value}"
|
18
|
+
end
|
19
|
+
else
|
20
|
+
options[key] = value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
options
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge_defaults!(options, defaults)
|
27
|
+
defaults.each do |key, value|
|
28
|
+
options[key] = value unless options[key]
|
29
|
+
end
|
30
|
+
options
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/meta/utils/path.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
#
|
2
3
|
|
3
4
|
module Meta
|
4
5
|
module Utils
|
5
6
|
class Path
|
6
7
|
class << self
|
8
|
+
# 规范化 path 结构,确保 path 以 '/' 开头,不以 '/' 结尾。
|
9
|
+
# 仅有一个例外,如果 path 为 nil 或空字符串,则返回空字符串 ''.
|
7
10
|
def normalize_path(path)
|
8
11
|
path = '/' unless path
|
9
12
|
path = '/' + path unless path.start_with?('/')
|
@@ -11,8 +14,11 @@ module Meta
|
|
11
14
|
path
|
12
15
|
end
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
# 合并两个 path. 有且只有一个例外,如果 p1 或 p2 其中之一为 '/',则返回另一个。
|
18
|
+
def join(*parts)
|
19
|
+
parts = parts.map { |p| (p || '').delete_prefix('/').delete_suffix('/') }
|
20
|
+
parts = parts.reject { |p| p.nil? || p.empty? }
|
21
|
+
'/' + parts.join('/')
|
16
22
|
end
|
17
23
|
end
|
18
24
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meta
|
4
|
+
module Utils
|
5
|
+
class RouteDSLBuilders
|
6
|
+
class << self
|
7
|
+
def merge_meta_options(options1, options2)
|
8
|
+
final_options = (options1 || {}).merge(options2 || {})
|
9
|
+
if options1[:parameters] && options2[:parameters]
|
10
|
+
final_options[:parameters] = options1[:parameters].merge(options2[:parameters])
|
11
|
+
end
|
12
|
+
if options1[:request_body].is_a?(Meta::JsonSchema::ObjectSchema) && options2[:request_body].is_a?(Meta::JsonSchema::ObjectSchema)
|
13
|
+
final_options[:request_body] = options1[:request_body].merge_other_properties(options2[:request_body].properties)
|
14
|
+
end
|
15
|
+
if options1[:responses] && options2[:responses]
|
16
|
+
final_options[:responses] = options1[:responses].merge(options2[:responses])
|
17
|
+
end
|
18
|
+
final_options
|
19
|
+
end
|
20
|
+
|
21
|
+
def merge_callbacks(parent_callbacks, current_callbacks)
|
22
|
+
# 合并父级传递过来的 callbacks,将 before 和 around 放在前面,after 放在后面
|
23
|
+
parent_before = parent_callbacks.filter { |cb| cb[:lifecycle] == :before || cb[:lifecycle] == :around }
|
24
|
+
parent_after = parent_callbacks.filter { |cb| cb[:lifecycle] == :after }
|
25
|
+
parent_before + current_callbacks + parent_after
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/meta-api.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meta-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yetrun
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 一个 Web API 框架,该框架采用定义元信息的方式编写 API,并同步生成 API 文档
|
14
14
|
email:
|
@@ -113,7 +113,6 @@ files:
|
|
113
113
|
- lib/meta/route_dsl/application_builder.rb
|
114
114
|
- lib/meta/route_dsl/around_action_builder.rb
|
115
115
|
- lib/meta/route_dsl/chain_builder.rb
|
116
|
-
- lib/meta/route_dsl/helpers.rb
|
117
116
|
- lib/meta/route_dsl/meta_builder.rb
|
118
117
|
- lib/meta/route_dsl/parameters_builder.rb
|
119
118
|
- lib/meta/route_dsl/route_builder.rb
|
@@ -121,7 +120,9 @@ files:
|
|
121
120
|
- lib/meta/swagger_doc.rb
|
122
121
|
- lib/meta/utils/kwargs/builder.rb
|
123
122
|
- lib/meta/utils/kwargs/check.rb
|
123
|
+
- lib/meta/utils/kwargs/checker.rb
|
124
124
|
- lib/meta/utils/path.rb
|
125
|
+
- lib/meta/utils/route_dsl_builders.rb
|
125
126
|
- meta-api.gemspec
|
126
127
|
homepage: https://github.com/yetrun/web-frame
|
127
128
|
licenses:
|
@@ -130,7 +131,7 @@ metadata:
|
|
130
131
|
allowed_push_host: https://rubygems.org
|
131
132
|
homepage_uri: https://github.com/yetrun/web-frame
|
132
133
|
source_code_uri: https://github.com/yetrun/web-frame.git
|
133
|
-
post_install_message:
|
134
|
+
post_install_message:
|
134
135
|
rdoc_options: []
|
135
136
|
require_paths:
|
136
137
|
- lib
|
@@ -145,8 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
146
|
- !ruby/object:Gem::Version
|
146
147
|
version: '0'
|
147
148
|
requirements: []
|
148
|
-
rubygems_version: 3.
|
149
|
-
signing_key:
|
149
|
+
rubygems_version: 3.4.15
|
150
|
+
signing_key:
|
150
151
|
specification_version: 4
|
151
152
|
summary: 一个 Web API 框架
|
152
153
|
test_files: []
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Meta
|
4
|
-
module RouteDSL
|
5
|
-
module Helpers
|
6
|
-
class << self
|
7
|
-
def join_path(*parts)
|
8
|
-
parts = parts.map { |p| (p || '').delete_prefix('/').delete_suffix('/') }
|
9
|
-
parts = parts.reject { |p| p.nil? || p.empty? }
|
10
|
-
'/' + parts.join('/')
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|