meta-api 0.0.5 → 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 +18 -1
- data/Gemfile.lock +1 -1
- data/README.md +32 -21
- data/config/locales/zh-CN.yml +1 -1
- data/docs//346/225/231/347/250/213.md +566 -175
- 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 +48 -24
- data/lib/meta/application/linked_action.rb +7 -9
- data/lib/meta/application/metadata.rb +5 -3
- data/lib/meta/application/parameters.rb +16 -8
- data/lib/meta/application/route.rb +24 -14
- data/lib/meta/config.rb +8 -3
- data/lib/meta/errors.rb +1 -1
- data/lib/meta/json_schema/builders/schema_builder_tool.rb +8 -2
- data/lib/meta/json_schema/schemas/base_schema.rb +19 -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/type_converter.rb +2 -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 +5 -4
- data/lib/meta/route_dsl/helpers.rb +0 -15
@@ -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,23 +94,47 @@ 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
|
+
response.content_type = 'application/json' if response.content_type.nil?
|
103
104
|
response.body = [JSON.generate(new_hash)]
|
104
105
|
else
|
105
106
|
# 渲染多键值结点
|
106
|
-
|
107
|
+
errors = {}
|
108
|
+
final_value = {}
|
109
|
+
renders.each do |key, render_content|
|
107
110
|
raise Errors::RenderingError, "渲染的键名 `#{key}` 不存在,请检查实体定义以确认是否有拼写错误" unless entity_schema.properties.key?(key)
|
108
111
|
schema = entity_schema.properties[key].schema(:render)
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
+
)
|
118
|
+
rescue JsonSchema::ValidationErrors => e
|
119
|
+
# 错误信息再度绑定 key
|
120
|
+
errors.merge! e.errors.transform_keys! { |k| k.empty? ? key : "#{key}.#{k}" }
|
112
121
|
end.to_h
|
113
|
-
|
122
|
+
|
123
|
+
if errors.empty?
|
124
|
+
response.content_type = 'application/json' if response.content_type.nil?
|
125
|
+
response.body = [JSON.generate(final_value)]
|
126
|
+
else
|
127
|
+
raise Errors::RenderingInvalid.new(errors)
|
128
|
+
end
|
114
129
|
end
|
115
130
|
rescue JsonSchema::ValidationErrors => e
|
116
131
|
raise Errors::RenderingInvalid.new(e.errors)
|
117
132
|
end
|
118
133
|
|
134
|
+
def abort_execution!
|
135
|
+
raise Abort
|
136
|
+
end
|
137
|
+
|
119
138
|
private
|
120
139
|
|
121
140
|
def parse_raw_params
|
@@ -134,22 +153,28 @@ module Meta
|
|
134
153
|
end
|
135
154
|
|
136
155
|
def parse_request_body_for_replacing
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
+
)
|
162
|
+
rescue JsonSchema::ValidationErrors => e
|
163
|
+
raise Errors::ParameterInvalid.new(e.errors)
|
142
164
|
end
|
143
165
|
|
144
166
|
def parse_request_body_for_updating
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
+
)
|
173
|
+
rescue JsonSchema::ValidationErrors => e
|
174
|
+
raise Errors::ParameterInvalid.new(e.errors)
|
150
175
|
end
|
151
176
|
|
152
|
-
class Abort <
|
177
|
+
class Abort < Exception
|
153
178
|
end
|
154
179
|
|
155
180
|
# 使得能够处理 Execution 的类作为 Rack 中间件
|
@@ -162,7 +187,6 @@ module Meta
|
|
162
187
|
execute(execution, request.path)
|
163
188
|
|
164
189
|
response = execution.response
|
165
|
-
response.content_type = 'application/json' unless response.no_content?
|
166
190
|
response.to_a
|
167
191
|
end
|
168
192
|
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
|
@@ -7,19 +7,27 @@ module Meta
|
|
7
7
|
attr_reader :parameters
|
8
8
|
|
9
9
|
def initialize(parameters)
|
10
|
-
@parameters = parameters
|
10
|
+
@parameters = parameters.dup
|
11
11
|
end
|
12
12
|
|
13
13
|
def filter(request)
|
14
|
-
|
14
|
+
errors = {}
|
15
|
+
final_value = {}
|
16
|
+
|
17
|
+
parameters.each do |name, options|
|
15
18
|
schema = options[:schema]
|
16
19
|
value = if options[:in] == 'header'
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
[name
|
22
|
-
|
20
|
+
schema.filter(request.get_header('HTTP_' + name.to_s.upcase.gsub('-', '_')))
|
21
|
+
else
|
22
|
+
schema.filter(request.params[name.to_s])
|
23
|
+
end
|
24
|
+
final_value[name] = value
|
25
|
+
rescue JsonSchema::ValidationError => e
|
26
|
+
errors[name] = e.message
|
27
|
+
end
|
28
|
+
raise Errors::ParameterInvalid.new(errors) unless errors.empty?
|
29
|
+
|
30
|
+
final_value
|
23
31
|
end
|
24
32
|
|
25
33
|
def to_swagger_doc
|
@@ -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
|
@@ -20,16 +21,15 @@ module Meta
|
|
20
21
|
def execute(execution, remaining_path)
|
21
22
|
path_matching.merge_path_params(remaining_path, execution.request)
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
execution.parse_request_body(@meta[:request_body]) if @meta[:request_body]
|
24
|
+
execution.parse_parameters(@meta[:parameters]) if @meta[:parameters]
|
25
|
+
execution.parse_request_body(@meta[:request_body]) if @meta[:request_body]
|
26
26
|
|
27
|
-
|
27
|
+
action.execute(execution) if action
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
set_status(execution)
|
30
|
+
render_entity(execution) if @meta[:responses]
|
31
|
+
rescue Execution::Abort
|
32
|
+
execution.response.status = 200 if execution.response.status == 0
|
33
33
|
end
|
34
34
|
|
35
35
|
def match?(execution, remaining_path)
|
@@ -44,14 +44,24 @@ module Meta
|
|
44
44
|
|
45
45
|
private
|
46
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
|
+
|
47
55
|
def render_entity(execution)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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?
|
52
62
|
|
53
|
-
|
54
|
-
execution.render_entity(entity_schema)
|
63
|
+
# 执行面向 schema 的渲染
|
64
|
+
execution.render_entity(entity_schema)
|
55
65
|
end
|
56
66
|
end
|
57
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
|
|
data/lib/meta/errors.rb
CHANGED
@@ -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)
|
@@ -34,7 +40,7 @@ module Meta
|
|
34
40
|
private
|
35
41
|
|
36
42
|
def apply_array_schema?(options, block)
|
37
|
-
options[:type] == 'array'
|
43
|
+
options[:type] == 'array'
|
38
44
|
end
|
39
45
|
|
40
46
|
def apply_object_schema?(options, block)
|
@@ -23,14 +23,18 @@ module Meta
|
|
23
23
|
|
24
24
|
def initialize(options = {})
|
25
25
|
options = OPTIONS_CHECKER.check(options)
|
26
|
-
|
26
|
+
raise '不允许 BaseSchema 直接接受 array 类型,必须通过继承使用 ArraySchema' if options[:type] == 'array' && self.class == BaseSchema
|
27
|
+
|
28
|
+
@options = SchemaOptions.normalize(options).freeze
|
27
29
|
end
|
28
30
|
|
29
31
|
USER_OPTIONS_CHECKER = Utils::KeywordArgs::Builder.build do
|
30
|
-
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) }
|
31
34
|
|
32
|
-
#
|
33
|
-
|
35
|
+
# 以下是 ObjectSchema 需要的选项
|
36
|
+
# extra_properties 只能取值为 :ignore、:raise_error
|
37
|
+
key :discard_missing, :extra_properties, :exclude, :scope
|
34
38
|
end
|
35
39
|
|
36
40
|
def filter(value, user_options = {})
|
@@ -38,7 +42,7 @@ module Meta
|
|
38
42
|
|
39
43
|
value = resolve_value(user_options) if options[:value]
|
40
44
|
value = JsonSchema::Presenters.present(options[:presenter], value) if options[:presenter]
|
41
|
-
value = options[:default] if value.nil? && options.key?(:default)
|
45
|
+
value = resolve_default_value(options[:default]) if value.nil? && options.key?(:default)
|
42
46
|
value = options[:convert].call(value) if options[:convert]
|
43
47
|
|
44
48
|
# 第一步,转化值。
|
@@ -108,6 +112,16 @@ module Meta
|
|
108
112
|
validator&.call(value, option, stage_options)
|
109
113
|
end
|
110
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
|
111
125
|
end
|
112
126
|
end
|
113
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)
|
@@ -96,9 +96,9 @@ module Meta
|
|
96
96
|
@object_converters = {
|
97
97
|
[Object] => lambda do |value|
|
98
98
|
if [TrueClass, FalseClass, Integer, Float, String].any? { |ruby_type| value.is_a?(ruby_type) }
|
99
|
-
raise TypeConvertError, I18n.t(:'json_schema.errors.type_convert.object', value: value, real_type: I18n.t(:'json_schema.
|
99
|
+
raise TypeConvertError, I18n.t(:'json_schema.errors.type_convert.object', value: value, real_type: I18n.t(:'json_schema.type_names.basic'))
|
100
100
|
elsif value.is_a?(Array)
|
101
|
-
raise TypeConvertError, I18n.t(:'json_schema.errors.type_convert.object', value: value, real_type: I18n.t(:'json_schema.
|
101
|
+
raise TypeConvertError, I18n.t(:'json_schema.errors.type_convert.object', value: value, real_type: I18n.t(:'json_schema.type_names.array'))
|
102
102
|
end
|
103
103
|
|
104
104
|
ObjectWrapper.new(value)
|
@@ -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
|