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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +32 -21
  5. data/config/locales/zh-CN.yml +1 -1
  6. data/docs//346/225/231/347/250/213.md +566 -175
  7. data/docs//347/264/242/345/274/225.md +10 -0
  8. data/examples/rails_app/Gemfile.lock +1 -1
  9. data/lib/meta/application/execution.rb +48 -24
  10. data/lib/meta/application/linked_action.rb +7 -9
  11. data/lib/meta/application/metadata.rb +5 -3
  12. data/lib/meta/application/parameters.rb +16 -8
  13. data/lib/meta/application/route.rb +24 -14
  14. data/lib/meta/config.rb +8 -3
  15. data/lib/meta/errors.rb +1 -1
  16. data/lib/meta/json_schema/builders/schema_builder_tool.rb +8 -2
  17. data/lib/meta/json_schema/schemas/base_schema.rb +19 -5
  18. data/lib/meta/json_schema/schemas/object_schema.rb +1 -1
  19. data/lib/meta/json_schema/schemas/properties.rb +11 -2
  20. data/lib/meta/json_schema/support/type_converter.rb +2 -2
  21. data/lib/meta/json_schema/support/validators.rb +1 -1
  22. data/lib/meta/route_dsl/application_builder.rb +18 -25
  23. data/lib/meta/route_dsl/around_action_builder.rb +37 -27
  24. data/lib/meta/route_dsl/meta_builder.rb +16 -9
  25. data/lib/meta/route_dsl/parameters_builder.rb +29 -6
  26. data/lib/meta/route_dsl/route_builder.rb +10 -44
  27. data/lib/meta/route_dsl/uniformed_params_builder.rb +27 -9
  28. data/lib/meta/swagger_doc.rb +2 -2
  29. data/lib/meta/utils/kwargs/builder.rb +4 -2
  30. data/lib/meta/utils/kwargs/checker.rb +36 -0
  31. data/lib/meta/utils/path.rb +8 -2
  32. data/lib/meta/utils/route_dsl_builders.rb +30 -0
  33. data/meta-api.gemspec +1 -1
  34. metadata +5 -4
  35. 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` 实体宏中定义,但数据中依然存在这个键值的属性。一般来讲我们允许前端传递一些多余的属性,但可能在内部测试时设定为更严格的条件。
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /home/run/workspace/personal/web-frame
3
3
  specs:
4
- meta-api (0.0.4)
4
+ meta-api (0.0.6)
5
5
 
6
6
  GEM
7
7
  remote: https://gems.ruby-china.com/
@@ -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, **options, execution: self, stage: :render, validation: ::Meta.config.render_validation, type_conversion: ::Meta.config.render_type_conversion)
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
- new_hash = renders.map do |key, render_content|
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
- filtered = schema.filter(render_content[:value], **render_content[:options], execution: self, stage: :render)
111
- [key, filtered]
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
- response.body = [JSON.generate(new_hash)]
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
- begin
138
- request_body_schema.filter(params(:raw), stage: :param)
139
- rescue JsonSchema::ValidationErrors => e
140
- raise Errors::ParameterInvalid.new(e.errors)
141
- end
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
- begin
146
- request_body_schema.filter(params(:raw), stage: :param, discard_missing: true)
147
- rescue JsonSchema::ValidationErrors => e
148
- raise Errors::ParameterInvalid.new(e.errors)
149
- end
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 < StandardError
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
- module RouteDSL
7
- class LinkedAction
8
- def initialize(current_proc, next_action)
9
- @current_proc = current_proc
10
- @next_action = next_action
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
- def execute(execution)
14
- execution.instance_exec(@next_action, &@current_proc)
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
- def self.new(meta = {})
58
- meta.is_a?(Metadata) ? meta : super(**meta)
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
- parameters.map do |name, options|
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
- schema.filter(request.get_header('HTTP_' + name.to_s.upcase.gsub('-', '_')))
18
- else
19
- schema.filter(request.params[name.to_s])
20
- end
21
- [name, value]
22
- end.to_h
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
- begin
24
- execution.parse_parameters(@meta[:parameters]) if @meta[:parameters]
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
- action.execute(execution) if action
27
+ action.execute(execution) if action
28
28
 
29
- render_entity(execution) if @meta[:responses]
30
- rescue Execution::Abort
31
- execution
32
- end
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
- responses = @meta[:responses]
49
- status = execution.response.status
50
- codes = responses.keys
51
- return unless codes.include?(status)
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
- entity_schema = responses[status]
54
- execution.render_entity(entity_schema) if 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 :render_validation, :render_type_conversion
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
- @render_type_conversion = true
9
- @render_validation = true
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
@@ -13,7 +13,7 @@ module Meta
13
13
  end
14
14
 
15
15
  class RenderingInvalid < JsonSchema::ValidationErrors
16
- def initialize(errors)
16
+ def initialize(errors = {})
17
17
  super(errors, "渲染实体异常:#{errors}")
18
18
  end
19
19
  end
@@ -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' && (options[:items] || options[:ref] || options[:dynamic_ref] || block)
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
- @options = SchemaOptions.normalize(options)
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 :stage, :execution, :object_value, :type_conversion, :validation, :user_data
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
- # 以下三个是 ObjectSchema 需要的选项
33
- key :discard_missing, :exclude, :scope
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
@@ -48,7 +48,7 @@ module Meta
48
48
  end
49
49
 
50
50
  # 合并其他的属性,并返回一个新的 ObjectSchema
51
- def merge(properties)
51
+ def merge_other_properties(properties)
52
52
  ObjectSchema.new(properties: self.properties.merge(properties))
53
53
  end
54
54
 
@@ -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, stage)
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, stage)
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.type_description.basic'))
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.type_description.array'))
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(prefix = nil, &block)
12
- @mod_prefix = prefix
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
- def build(parent_path: '', meta: {}, callbacks: [])
23
- # 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
24
- meta2 = (meta || {}).merge(@meta_builder.build)
25
- if meta[:parameters] && meta2[:parameters]
26
- meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
27
- end
28
-
29
- # 构建子模块
30
- # 合并父级传递过来的 callbacks,将 before around 放在前面,after 放在后面
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: @mod_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 = RouteDSL::RouteBuilder.new(path, method, &block)
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(parent_path: '', meta: {}, **kwargs)
112
- # 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
113
- meta2 = (meta || {}).merge(@meta)
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
- # 使用 before、after、around 系列和当前 action 共同构建洋葱圈模型。
49
- # Note: 该方法可能被废弃!
50
- #
51
- # 构建成功后,执行顺序是:
52
- #
53
- # - before 序列
54
- # - around 序列的前半部分
55
- # - action
56
- # - around 序列的后半部分
57
- # - after 序列
58
- #
59
- def self.build(before: [], after: [], around: [], action: nil)
60
- builder = AroundActionBuilder.new
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
- # 首先构建 before 序列,保证它最先执行
63
- builder.around do |next_action|
64
- before.each { |p| self.instance_exec(&p) }
65
- next_action.execute(self)
66
- end unless before.empty?
67
- # 然后构建 after 序列,保证它最后执行
68
- builder.around do |next_action|
69
- next_action.execute(self)
70
- after.each { |p| self.instance_exec(&p) }
71
- end unless after.empty?
72
- # 接着应用洋葱圈模型,依次构建 around 序列、action
73
- around.each { |p| builder.around(&p) }
74
- builder.around { self.instance_exec(&action) } unless action.nil?
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
- builder.build
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