meta-api 0.0.3 → 0.0.4
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 +5 -0
- data/Gemfile.lock +1 -1
- data/docs//346/225/231/347/250/213.md +29 -1
- data/examples/rails_app/Gemfile.lock +1 -1
- data/lib/meta/application/linked_action.rb +18 -0
- data/lib/meta/application/route.rb +4 -5
- data/lib/meta/json_schema/builders/array_schema_builder.rb +4 -9
- data/lib/meta/json_schema/schemas/base_schema.rb +15 -2
- data/lib/meta/json_schema/support/schema_options.rb +0 -9
- data/lib/meta/route_dsl/application_builder.rb +16 -10
- data/lib/meta/route_dsl/around_action_builder.rb +53 -0
- data/lib/meta/route_dsl/route_builder.rb +8 -5
- data/meta-api.gemspec +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc6f6c3dddfd1e683cae7147be60bd7ead57e46b097700fc1db4113d12f08965
|
4
|
+
data.tar.gz: 476caee521969debd84614433ab41be89fbe7d1e5b074f46a6c8df40ca2d2c43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e213a983004b7fed1d15c2e0b41c9746584d259af6f969c631669b7efbb63f5573ee67b61ca5cb95888738925ca525e2ae4045502a7998c57c96432c12e3fd7
|
7
|
+
data.tar.gz: b575cf5145a3693ceb14296178c25c1ab1f8bf23e2a7dac92e9cc131a82dd79649d101f066c716069a5cb99114c138842b7bde89734790f217095fd459bf8fb4
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -118,7 +118,7 @@ class DemoApp < Meta::Application
|
|
118
118
|
end
|
119
119
|
```
|
120
120
|
|
121
|
-
###
|
121
|
+
### 钩子
|
122
122
|
|
123
123
|
*(如果不涉及到钩子和异常拦截,嵌套路由将毫无意义。)*
|
124
124
|
|
@@ -142,6 +142,34 @@ class DemoApp < Meta::Application
|
|
142
142
|
end
|
143
143
|
```
|
144
144
|
|
145
|
+
同时还支持 `around` 钩子(*试验特性*):
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class DemoApp < Meta::Application
|
149
|
+
before { puts 1 }
|
150
|
+
before { puts 2 }
|
151
|
+
around { |next_action|
|
152
|
+
puts 3
|
153
|
+
next_action.execute(self)
|
154
|
+
puts 5
|
155
|
+
}
|
156
|
+
after { puts 6 }
|
157
|
+
after { puts 7 }
|
158
|
+
|
159
|
+
get '/request' do
|
160
|
+
puts 4
|
161
|
+
end
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
所有钩子的执行顺序是:
|
166
|
+
|
167
|
+
1. 首先执行 `before` 钩子,按照定义的顺序执行。
|
168
|
+
2. 然后执行 `around` 钩子的前半部分,按照定义的顺序执行。
|
169
|
+
3. 然后执行路由方法。
|
170
|
+
4. 然后执行 `around` 钩子的后半部分,按照定义的顺序执行。
|
171
|
+
5. 最后执行 `after` 钩子,按照定义的顺序执行。
|
172
|
+
|
145
173
|
### 异常拦截
|
146
174
|
|
147
175
|
在 `namespace` 中使用 `rescue_error` 拦截异常。
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# 洋葱圈模型的链式调用,需要结合 Meta::RouteDSL::AroundActionBuilder 才可以看到它奇效。
|
4
|
+
|
5
|
+
module Meta
|
6
|
+
module RouteDSL
|
7
|
+
class LinkedAction
|
8
|
+
def initialize(current_proc, next_action)
|
9
|
+
@current_proc = current_proc
|
10
|
+
@next_action = next_action
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(execution)
|
14
|
+
execution.instance_exec(@next_action, &@current_proc)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -8,24 +8,23 @@ module Meta
|
|
8
8
|
class Route
|
9
9
|
include PathMatchingMod.new(path_method: :path, matching_mode: :full)
|
10
10
|
|
11
|
-
attr_reader :path, :method, :meta, :
|
11
|
+
attr_reader :path, :method, :meta, :action
|
12
12
|
|
13
|
-
def initialize(path: '', method: :all, meta: {},
|
13
|
+
def initialize(path: '', method: :all, meta: {}, action: nil)
|
14
14
|
@path = Utils::Path.normalize_path(path)
|
15
15
|
@method = method
|
16
16
|
@meta = Metadata.new(meta)
|
17
|
-
@
|
17
|
+
@action = action
|
18
18
|
end
|
19
19
|
|
20
20
|
def execute(execution, remaining_path)
|
21
21
|
path_matching.merge_path_params(remaining_path, execution.request)
|
22
22
|
|
23
|
-
# 依次执行这个环境
|
24
23
|
begin
|
25
24
|
execution.parse_parameters(@meta[:parameters]) if @meta[:parameters]
|
26
25
|
execution.parse_request_body(@meta[:request_body]) if @meta[:request_body]
|
27
26
|
|
28
|
-
|
27
|
+
action.execute(execution) if action
|
29
28
|
|
30
29
|
render_entity(execution) if @meta[:responses]
|
31
30
|
rescue Execution::Abort
|
@@ -5,15 +5,10 @@ module Meta
|
|
5
5
|
class ArraySchemaBuilder
|
6
6
|
def initialize(options, &block)
|
7
7
|
options = options.dup
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
elsif options[:dynamic_ref]
|
13
|
-
items_options = { dynamic_ref: options.delete(:dynamic_ref) }
|
14
|
-
else
|
15
|
-
items_options = {}
|
16
|
-
end
|
8
|
+
items_options = options.delete(:items) || {}
|
9
|
+
items_options[:ref] = options.delete(:ref) if options[:ref]
|
10
|
+
items_options[:dynamic_ref] = options.delete(:dynamic_ref) if options[:dynamic_ref]
|
11
|
+
|
17
12
|
@items_schema = SchemaBuilderTool.build(items_options, &block)
|
18
13
|
@base_options = options
|
19
14
|
end
|
@@ -6,6 +6,12 @@ require_relative '../support/schema_options'
|
|
6
6
|
module Meta
|
7
7
|
module JsonSchema
|
8
8
|
class BaseSchema
|
9
|
+
OPTIONS_CHECKER = Utils::KeywordArgs::Builder.build do
|
10
|
+
key :type, :items, :description, :presenter, :value, :default, :properties, :convert
|
11
|
+
key :validate, :required, :format, :allowable
|
12
|
+
key :param, :render
|
13
|
+
end
|
14
|
+
|
9
15
|
# `options` 包含了转换器、验证器、文档、选项。
|
10
16
|
#
|
11
17
|
# 由于本对象可继承,基于不同的继承可分别表示基本类型、对象和数组,所以该属
|
@@ -16,11 +22,12 @@ module Meta
|
|
16
22
|
attr_reader :options
|
17
23
|
|
18
24
|
def initialize(options = {})
|
25
|
+
options = OPTIONS_CHECKER.check(options)
|
19
26
|
@options = SchemaOptions.normalize(options)
|
20
27
|
end
|
21
28
|
|
22
29
|
USER_OPTIONS_CHECKER = Utils::KeywordArgs::Builder.build do
|
23
|
-
key :stage, :execution, :object_value, :type_conversion, :validation
|
30
|
+
key :stage, :execution, :object_value, :type_conversion, :validation, :user_data
|
24
31
|
|
25
32
|
# 以下三个是 ObjectSchema 需要的选项
|
26
33
|
key :discard_missing, :exclude, :scope
|
@@ -57,7 +64,13 @@ module Meta
|
|
57
64
|
|
58
65
|
def resolve_value(user_options)
|
59
66
|
value_proc = options[:value]
|
60
|
-
|
67
|
+
if value_proc.lambda?
|
68
|
+
value_proc_params = []
|
69
|
+
value_proc_params << user_options[:object_value] if value_proc.arity >= 1
|
70
|
+
value_proc_params << user_options[:user_data] if value_proc.arity >= 2
|
71
|
+
else
|
72
|
+
value_proc_params = [user_options[:object_value], user_options[:user_data]]
|
73
|
+
end
|
61
74
|
|
62
75
|
if user_options[:execution]
|
63
76
|
user_options[:execution].instance_exec(*value_proc_params, &value_proc)
|
@@ -5,13 +5,6 @@ require_relative '../../utils/kwargs/builder'
|
|
5
5
|
module Meta
|
6
6
|
module JsonSchema
|
7
7
|
module SchemaOptions
|
8
|
-
OPTIONS_CHECKER = Utils::KeywordArgs::Builder.build do
|
9
|
-
key :type, :items, :description, :presenter, :value, :format, :required, :default, :validate, :allowable, :properties, :convert
|
10
|
-
key :using, normalizer: ->(value) { value.is_a?(Proc) ? { resolve: value } : value }
|
11
|
-
key :param
|
12
|
-
key :render
|
13
|
-
end
|
14
|
-
|
15
8
|
@default_options = {
|
16
9
|
scope: [],
|
17
10
|
required: false
|
@@ -34,8 +27,6 @@ module Meta
|
|
34
27
|
end
|
35
28
|
|
36
29
|
def normalize(options)
|
37
|
-
options = OPTIONS_CHECKER.check(options)
|
38
|
-
|
39
30
|
# 只要 options 中设置为 nil 的选项没有明确的意义,则下行代码是永远有效的
|
40
31
|
options = (@default_options.compact).merge(options.compact)
|
41
32
|
if options[:using]
|
@@ -10,8 +10,7 @@ module Meta
|
|
10
10
|
|
11
11
|
def initialize(prefix = nil, &block)
|
12
12
|
@mod_prefix = prefix
|
13
|
-
@
|
14
|
-
@after_callbacks = []
|
13
|
+
@callbacks = { before: [], after: [], around: [] }
|
15
14
|
@error_guards = []
|
16
15
|
@meta_builder = MetaBuilder.new
|
17
16
|
@mod_builders = []
|
@@ -20,7 +19,7 @@ module Meta
|
|
20
19
|
instance_exec &block if block_given?
|
21
20
|
end
|
22
21
|
|
23
|
-
def build(parent_path: '', meta: {},
|
22
|
+
def build(parent_path: '', meta: {}, callbacks: {})
|
24
23
|
# 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
|
25
24
|
meta2 = (meta || {}).merge(@meta_builder.build)
|
26
25
|
if meta[:parameters] && meta2[:parameters]
|
@@ -28,9 +27,12 @@ module Meta
|
|
28
27
|
end
|
29
28
|
|
30
29
|
# 构建子模块
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
callbacks = { # 合并父级传递过来的 callbacks
|
31
|
+
before: (callbacks[:before] || []) + @callbacks[:before],
|
32
|
+
around: (callbacks[:around] || []) + @callbacks[:around],
|
33
|
+
after: @callbacks[:after] + (callbacks[:after] || []),
|
34
|
+
}
|
35
|
+
mods = @mod_builders.map { |builder| builder.build(parent_path: Utils::Path.join(parent_path, @mod_prefix), meta: meta2, callbacks: callbacks) }
|
34
36
|
|
35
37
|
Application.new(
|
36
38
|
prefix: @mod_prefix,
|
@@ -64,11 +66,15 @@ module Meta
|
|
64
66
|
|
65
67
|
# 定义模块内的公共逻辑
|
66
68
|
def before(&block)
|
67
|
-
@
|
69
|
+
@callbacks[:before] << block
|
68
70
|
end
|
69
71
|
|
70
72
|
def after(&block)
|
71
|
-
@
|
73
|
+
@callbacks[:after] << block
|
74
|
+
end
|
75
|
+
|
76
|
+
def around(&block)
|
77
|
+
@callbacks[:around] << block
|
72
78
|
end
|
73
79
|
|
74
80
|
def rescue_error(error_class, &block)
|
@@ -94,13 +100,13 @@ module Meta
|
|
94
100
|
@meta = meta
|
95
101
|
end
|
96
102
|
|
97
|
-
def build(parent_path: '', meta: {},
|
103
|
+
def build(parent_path: '', meta: {}, **kwargs)
|
98
104
|
# 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
|
99
105
|
meta2 = (meta || {}).merge(@meta)
|
100
106
|
if meta[:parameters] && meta2[:parameters]
|
101
107
|
meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
|
102
108
|
end
|
103
|
-
@builder.build(parent_path: parent_path, meta: meta2,
|
109
|
+
@builder.build(parent_path: parent_path, meta: meta2, **kwargs)
|
104
110
|
end
|
105
111
|
end
|
106
112
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../application/linked_action'
|
4
|
+
|
5
|
+
module Meta
|
6
|
+
module RouteDSL
|
7
|
+
class AroundActionBuilder
|
8
|
+
def initialize
|
9
|
+
@around = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def around(&block)
|
13
|
+
@around << block
|
14
|
+
end
|
15
|
+
|
16
|
+
def build
|
17
|
+
# 从后向前构建
|
18
|
+
@around.reverse.reduce(nil) do |following, p|
|
19
|
+
LinkedAction.new(p, following)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# 使用 before、after、around 系列和当前 action 共同构建洋葱圈模型。
|
24
|
+
# 构建成功后,执行顺序是:
|
25
|
+
#
|
26
|
+
# - before 序列
|
27
|
+
# - around 序列的前半部分
|
28
|
+
# - action
|
29
|
+
# - around 序列的后半部分
|
30
|
+
# - after 序列
|
31
|
+
#
|
32
|
+
def self.build(before: [], after: [], around: [], action: nil)
|
33
|
+
builder = AroundActionBuilder.new
|
34
|
+
|
35
|
+
# 首先构建 before 序列,保证它最先执行
|
36
|
+
builder.around do |next_action|
|
37
|
+
before.each { |p| self.instance_exec(&p) }
|
38
|
+
next_action.execute(self)
|
39
|
+
end unless before.empty?
|
40
|
+
# 然后构建 after 序列,保证它最后执行
|
41
|
+
builder.around do |next_action|
|
42
|
+
next_action.execute(self)
|
43
|
+
after.each { |p| self.instance_exec(&p) }
|
44
|
+
end unless after.empty?
|
45
|
+
# 接着应用洋葱圈模型,依次构建 around 序列、action
|
46
|
+
around.each { |p| builder.around(&p) }
|
47
|
+
builder.around { self.instance_exec(&action) } unless action.nil?
|
48
|
+
|
49
|
+
builder.build
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -7,6 +7,7 @@ require_relative 'helpers'
|
|
7
7
|
require_relative 'chain_builder'
|
8
8
|
require_relative 'action_builder'
|
9
9
|
require_relative 'meta_builder'
|
10
|
+
require_relative 'around_action_builder'
|
10
11
|
|
11
12
|
module Meta
|
12
13
|
module RouteDSL
|
@@ -24,7 +25,7 @@ module Meta
|
|
24
25
|
instance_exec &block if block_given?
|
25
26
|
end
|
26
27
|
|
27
|
-
def build(parent_path: '', meta: {},
|
28
|
+
def build(parent_path: '', meta: {}, callbacks: {})
|
28
29
|
# 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
|
29
30
|
meta2 = (meta || {}).merge(@meta_builder.build)
|
30
31
|
if meta[:parameters] && meta2[:parameters]
|
@@ -45,15 +46,17 @@ module Meta
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
|
-
#
|
49
|
-
action =
|
50
|
-
|
49
|
+
# 构建洋葱圈模型的 LinkedAction
|
50
|
+
action = AroundActionBuilder.build(
|
51
|
+
action: @action_builder&.build,
|
52
|
+
**callbacks
|
53
|
+
)
|
51
54
|
|
52
55
|
Route.new(
|
53
56
|
path: @path,
|
54
57
|
method: @method,
|
55
58
|
meta: meta2,
|
56
|
-
|
59
|
+
action: action
|
57
60
|
)
|
58
61
|
end
|
59
62
|
|
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yetrun
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 一个 Web API 框架,该框架采用定义元信息的方式编写 API,并同步生成 API 文档
|
14
14
|
email:
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- lib/meta/application.rb
|
82
82
|
- lib/meta/application/application.rb
|
83
83
|
- lib/meta/application/execution.rb
|
84
|
+
- lib/meta/application/linked_action.rb
|
84
85
|
- lib/meta/application/metadata.rb
|
85
86
|
- lib/meta/application/parameters.rb
|
86
87
|
- lib/meta/application/path_matching_mod.rb
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- lib/meta/rails.rb
|
111
112
|
- lib/meta/route_dsl/action_builder.rb
|
112
113
|
- lib/meta/route_dsl/application_builder.rb
|
114
|
+
- lib/meta/route_dsl/around_action_builder.rb
|
113
115
|
- lib/meta/route_dsl/chain_builder.rb
|
114
116
|
- lib/meta/route_dsl/helpers.rb
|
115
117
|
- lib/meta/route_dsl/meta_builder.rb
|