meta-api 0.0.1

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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/.autoenv.zsh +1 -0
  3. data/.gitignore +6 -0
  4. data/.rubocop.yml +28 -0
  5. data/Gemfile +18 -0
  6. data/Gemfile.lock +66 -0
  7. data/LICENSE.txt +502 -0
  8. data/README.md +149 -0
  9. data/Rakefile +3 -0
  10. data/config/locales/zh-CN.yml +6 -0
  11. data/docs//345/220/215/347/247/260/347/224/261/346/235/245.md +7 -0
  12. data/docs//346/225/231/347/250/213.md +1199 -0
  13. data/docs//347/264/242/345/274/225.md +173 -0
  14. data/examples/lobster.rb +71 -0
  15. data/examples/rack_app/README.md +3 -0
  16. data/examples/rack_app/config.ru +6 -0
  17. data/examples/rack_app/hello.rb +6 -0
  18. data/examples/rack_app/timing.rb +15 -0
  19. data/lib/meta/api.rb +3 -0
  20. data/lib/meta/application/application.rb +63 -0
  21. data/lib/meta/application/execution.rb +178 -0
  22. data/lib/meta/application/meta.rb +71 -0
  23. data/lib/meta/application/path_matching_mod.rb +53 -0
  24. data/lib/meta/application/route.rb +58 -0
  25. data/lib/meta/application.rb +42 -0
  26. data/lib/meta/entity.rb +59 -0
  27. data/lib/meta/errors.rb +29 -0
  28. data/lib/meta/json_schema/builders/array_schema_builder.rb +29 -0
  29. data/lib/meta/json_schema/builders/object_schema_builder.rb +120 -0
  30. data/lib/meta/json_schema/builders/schema_builder_tool.rb +29 -0
  31. data/lib/meta/json_schema/schemas/array_schema.rb +40 -0
  32. data/lib/meta/json_schema/schemas/base_schema.rb +110 -0
  33. data/lib/meta/json_schema/schemas/object_schema.rb +161 -0
  34. data/lib/meta/json_schema/schemas.rb +12 -0
  35. data/lib/meta/json_schema/support/errors.rb +38 -0
  36. data/lib/meta/json_schema/support/presenters.rb +35 -0
  37. data/lib/meta/json_schema/support/schema_options.rb +55 -0
  38. data/lib/meta/json_schema/support/type_converter.rb +137 -0
  39. data/lib/meta/json_schema/support/validators.rb +54 -0
  40. data/lib/meta/load_i18n.rb +8 -0
  41. data/lib/meta/route_dsl/action_builder.rb +15 -0
  42. data/lib/meta/route_dsl/application_builder.rb +108 -0
  43. data/lib/meta/route_dsl/chain_builder.rb +48 -0
  44. data/lib/meta/route_dsl/helpers.rb +15 -0
  45. data/lib/meta/route_dsl/meta_builder.rb +57 -0
  46. data/lib/meta/route_dsl/parameters_builder.rb +24 -0
  47. data/lib/meta/route_dsl/route_builder.rb +85 -0
  48. data/lib/meta/route_dsl/uniformed_params_builder.rb +34 -0
  49. data/lib/meta/swagger_doc.rb +86 -0
  50. data/lib/meta/utils/path.rb +20 -0
  51. data/meta-api.gemspec +23 -0
  52. metadata +96 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module JsonSchema
5
+ class ValidationErrors < StandardError
6
+ attr_reader :errors
7
+
8
+ def initialize(errors, message = nil)
9
+ raise ArgumentError, '参数 errors 应传递一个 Hash' unless errors.is_a?(Hash)
10
+
11
+ super(message)
12
+ @errors = errors
13
+ end
14
+
15
+ def prepend_root(root)
16
+ errors_prepend_root = errors.transform_keys do |name|
17
+ return name.to_s if root.empty?
18
+
19
+ path = name[0] == '[' ? "#{root}#{name}" : "#{root}.#{name}"
20
+ path = path[1..] if path[0] == '.'
21
+ path = path[0..-2] if path[-1] == '.'
22
+ path
23
+ end
24
+ ValidationErrors.new(errors_prepend_root)
25
+ end
26
+ end
27
+
28
+ class ValidationError < ValidationErrors
29
+ def initialize(message)
30
+ super('' => message)
31
+ end
32
+
33
+ def message
34
+ errors['']
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module JsonSchema
5
+ module Presenters
6
+ @presenter_handlers = []
7
+
8
+ class << self
9
+ def register(presenter_handler)
10
+ @presenter_handlers << presenter_handler
11
+ end
12
+
13
+ def unregister(presenter_handler)
14
+ @presenter_handlers.delete(presenter_handler)
15
+ end
16
+
17
+ def present(presenter, value)
18
+ @presenter_handlers.each do |presenter_handler|
19
+ next unless presenter_handler.handle?(presenter)
20
+
21
+ return presenter_handler.present(presenter, value)
22
+ end
23
+ end
24
+
25
+ def to_schema_doc(presenter, other_options)
26
+ @presenter_handlers.each do |presenter_handler|
27
+ next unless presenter_handler.handle?(presenter)
28
+
29
+ return presenter_handler.to_schema_doc(presenter, other_options)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module JsonSchema
5
+ module SchemaOptions
6
+ @default_options = {
7
+ scope: [],
8
+ required: false
9
+ }
10
+ @allowable_options = (
11
+ %i[type description in value using default presenter convert scope items] +
12
+ @default_options.keys +
13
+ JsonSchema::Validators.keys
14
+ ).uniq
15
+
16
+ class << self
17
+ def normalize_to_param_and_render(options)
18
+ common_opts = (options || {}).dup
19
+ param_opts = common_opts.delete(:param)
20
+ render_opts = common_opts.delete(:render)
21
+
22
+ param_opts = merge_common_to_stage(common_opts, param_opts)
23
+ render_opts = merge_common_to_stage(common_opts, render_opts)
24
+ [param_opts, render_opts]
25
+ end
26
+
27
+ def merge_common_to_stage(common_opts, stage_opts)
28
+ stage_opts = {} if stage_opts.nil? || stage_opts == true
29
+ stage_opts = common_opts.merge(stage_opts) if stage_opts
30
+ stage_opts = normalize(stage_opts) if stage_opts
31
+ stage_opts
32
+ end
33
+
34
+ def normalize(options)
35
+ # 只要 options 中设置为 nil 的选项没有明确的意义,则下行代码是永远有效的
36
+ options = (@default_options.compact).merge(options.compact)
37
+ options[:scope] = [options[:scope]] unless options[:scope].is_a?(Array)
38
+ if options[:using]
39
+ if options[:type].nil?
40
+ options[:type] = 'object'
41
+ elsif options[:type] != 'object' && options[:type] != 'array'
42
+ raise "当使用 using 时,type 必须声明为 object 或 array"
43
+ end
44
+ end
45
+
46
+ # 处理 validators
47
+ unknown_validators = options.keys - @allowable_options
48
+ raise "未知的选项:#{unknown_validators.join(', ')}" unless unknown_validators.empty?
49
+
50
+ options
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module JsonSchema
5
+ class ObjectWrapper
6
+ def initialize(target)
7
+ @target = target
8
+ end
9
+
10
+ def __target__
11
+ @target
12
+ end
13
+
14
+ def key?(key)
15
+ @target.respond_to?(key)
16
+ end
17
+
18
+ def [](key)
19
+ @target.__send__(key)
20
+ end
21
+
22
+ def method_missing(method, *args)
23
+ @target.__send__(method, *args)
24
+ end
25
+ end
26
+
27
+ module TypeConverter
28
+ # 定义客户类型对应的 Ruby 类型
29
+ @definity_types = {
30
+ 'boolean' => [TrueClass, FalseClass],
31
+ 'integer' => [Integer],
32
+ 'number' => [Integer, Float],
33
+ 'string' => [String],
34
+ 'array' => [Array],
35
+ 'object' => [Hash, ObjectWrapper]
36
+ }
37
+
38
+ # 定义从 Ruby 类型转化为对应类型的逻辑
39
+ @boolean_converters = {
40
+ [String] => lambda do |value|
41
+ unless %w[true True TRUE false False FALSE].include?(value)
42
+ raise TypeConvertError, "类型转化失败,期望得到一个 `boolean` 类型,但值 `#{value}` 无法转化"
43
+ end
44
+
45
+ value.downcase == 'true'
46
+ end
47
+ }
48
+
49
+ @integer_converters = {
50
+ [String] => lambda do |value|
51
+ # 允许的格式:+34、-34、34、34.0 等
52
+ unless value =~ /^[+-]?\d+(\.0+)?$/
53
+ raise TypeConvertError, "类型转化失败,期望得到一个 `integer` 类型,但值 `#{value}` 无法转化"
54
+ end
55
+
56
+ value.to_i
57
+ end,
58
+ [Float] => lambda do |value|
59
+ unless value.to_i == value
60
+ raise TypeConvertError, "类型转化失败,期望得到一个 `integer` 类型,但值 `#{value}` 无法转化"
61
+ end
62
+
63
+ value.to_i
64
+ end
65
+ }
66
+
67
+ @number_converters = {
68
+ [String] => lambda do |value|
69
+ unless value =~ /^[+-]?\d+(\.\d+)?$/
70
+ raise TypeConvertError, "类型转化失败,期望得到一个 `number` 类型,但值 `#{value}` 无法转化"
71
+ end
72
+
73
+ float = value.to_f
74
+ float.to_i == float ? float.to_i : float
75
+ end
76
+ }
77
+
78
+ @string_converters = {
79
+ [Object] => lambda do |value|
80
+ value.to_s
81
+ end
82
+ }
83
+
84
+ @array_converters = {
85
+ [Object] => lambda do |value|
86
+ unless value.respond_to?(:to_a)
87
+ raise TypeConvertError, "转化为数组类型时期望对象拥有 `to_a` 方法"
88
+ end
89
+
90
+ value.to_a
91
+ end
92
+ }
93
+
94
+ @object_converters = {
95
+ [Object] => lambda do |value|
96
+ if [TrueClass, FalseClass, Integer, Float, String].any? { |ruby_type| value.is_a?(ruby_type) }
97
+ raise TypeConvertError, "类型转化失败,期望得到一个 `object` 类型,但值 `#{value}` 是一个基本类型"
98
+ elsif value.is_a?(Array)
99
+ raise TypeConvertError, "类型转化失败,期望得到一个 `object` 类型,但值 `#{value}` 是一个 `array` 类型"
100
+ end
101
+
102
+ ObjectWrapper.new(value)
103
+ end
104
+ }
105
+
106
+ class << self
107
+ def convert_value(value, target_type)
108
+ return nil if value.nil?
109
+ raise JsonSchema::TypeConvertError, "未知的目标类型 `#{target_type}`" unless @definity_types.keys.include?(target_type)
110
+ return value if match_definity_types?(value, target_type)
111
+
112
+ convert_to_definity_type(value, target_type)
113
+ end
114
+
115
+ private
116
+
117
+ def match_definity_types?(value, target_type)
118
+ ruby_types = @definity_types[target_type]
119
+ return ruby_types.any?{ |ruby_type| value.is_a?(ruby_type) }
120
+ end
121
+
122
+ def convert_to_definity_type(value, target_type)
123
+ converters = instance_variable_get(:"@#{target_type}_converters")
124
+ converters.each do |ruby_types, converter|
125
+ if ruby_types.any?{ |ruby_type| value.is_a?(ruby_type) }
126
+ return converter.call(value)
127
+ end
128
+ end
129
+ raise TypeConvertError, "类型转化失败,期望得到一个 `#{target_type}` 类型,但值 `#{value}` 无法转化"
130
+ end
131
+ end
132
+ end
133
+
134
+ class TypeConvertError < StandardError
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module JsonSchema
5
+ module Validators
6
+ @validators = {
7
+ validate: proc { |value, p|
8
+ next if value.nil?
9
+ p.call(value)
10
+ },
11
+ required: proc { |value, options, full_options|
12
+ next if options == false
13
+
14
+ full_options ||= {}
15
+ options = {} if options == true
16
+ raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.required') if value.nil?
17
+
18
+ if full_options[:type] == 'string' && (!options[:allow_empty]) && value.empty?
19
+ raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.required')
20
+ end
21
+ if full_options[:type] == 'array' && (options[:allow_empty] == false) && value.empty?
22
+ raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.required')
23
+ end
24
+ },
25
+ format: proc { |value, format|
26
+ next if value.nil?
27
+ raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.format') unless value =~ format
28
+ },
29
+ allowable: proc { |value, allowable_values|
30
+ next if value.nil?
31
+ raise JsonSchema::ValidationError, I18n.t(:'json_schema.errors.allowable') unless allowable_values.include?(value)
32
+ }
33
+ }
34
+
35
+ class << self
36
+ def [](key)
37
+ @validators[key]
38
+ end
39
+
40
+ def []=(key, validator)
41
+ @validators[key] = validator
42
+ end
43
+
44
+ def delete(key)
45
+ @validators.delete(key)
46
+ end
47
+
48
+ def keys
49
+ @validators.keys
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,8 @@
1
+ require 'pathname'
2
+ require 'i18n'
3
+ require "i18n/backend/fallbacks"
4
+
5
+ I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
6
+ I18n.fallbacks.map(:'zh-CN' => [:zh, :en])
7
+
8
+ I18n.load_path << Pathname.new(__dir__).join('../../config/locales/zh-CN.yml')
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module RouteDSL
5
+ class ActionBuilder
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ def build
11
+ @block
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'route_builder'
4
+ require_relative 'meta_builder'
5
+
6
+ module Meta
7
+ module RouteDSL
8
+ class ApplicationBuilder
9
+ include MetaBuilder::Delegator
10
+
11
+ def initialize(prefix = nil, &block)
12
+ @mod_prefix = prefix
13
+ @before_callbacks = []
14
+ @after_callbacks = []
15
+ @error_guards = []
16
+ @meta_builder = MetaBuilder.new
17
+ @mod_builders = []
18
+ @shared_mods = []
19
+
20
+ instance_exec &block if block_given?
21
+ end
22
+
23
+ def build(parent_path: '', meta: {}, before_callbacks: [], after_callbacks: [])
24
+ # 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
25
+ meta2 = (meta || {}).merge(@meta_builder.build)
26
+ if meta[:parameters] && meta2[:parameters]
27
+ meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
28
+ end
29
+
30
+ # 构建子模块
31
+ before_callbacks += @before_callbacks
32
+ after_callbacks = @after_callbacks + after_callbacks
33
+ mods = @mod_builders.map { |builder| builder.build(parent_path: Utils::Path.join(parent_path, @mod_prefix), meta: meta2, before_callbacks: before_callbacks, after_callbacks: after_callbacks) }
34
+
35
+ Application.new(
36
+ prefix: @mod_prefix,
37
+ mods: mods,
38
+ shared_mods: @shared_mods,
39
+ error_guards: @error_guards
40
+ )
41
+ end
42
+
43
+ def shared(*mods, &block)
44
+ @shared_mods += mods
45
+ @shared_mods << Module.new(&block) if block_given?
46
+ end
47
+
48
+ # 定义路由块
49
+ def route(path, method = nil, &block)
50
+ route_builder = RouteDSL::RouteBuilder.new(path, method, &block)
51
+ @mod_builders << route_builder
52
+ route_builder
53
+ end
54
+
55
+ # 定义子模块
56
+ def namespace(path, &block)
57
+ @mod_builders << ApplicationBuilder.new(path, &block)
58
+ end
59
+
60
+ # 应用另一个模块
61
+ def apply(builder, tags: nil)
62
+ @mod_builders << BindingMeta.new(builder, tags ? { tags: tags } : {})
63
+ end
64
+
65
+ # 定义模块内的公共逻辑
66
+ def before(&block)
67
+ @before_callbacks << block
68
+ end
69
+
70
+ def after(&block)
71
+ @after_callbacks << block
72
+ end
73
+
74
+ def rescue_error(error_class, &block)
75
+ @error_guards << { error_class: error_class, caller: block }
76
+ end
77
+
78
+ # 定义应用到子模块的公共逻辑
79
+ def meta(&block)
80
+ @meta_builder.instance_exec &block
81
+ end
82
+
83
+ # 添加 get、post、put、patch、delete 路由方法
84
+ [:get, :post, :put, :patch, :delete].each do |method|
85
+ define_method(method) do |path = '', &block|
86
+ route(path, method, &block)
87
+ end
88
+ end
89
+
90
+ # 绑定 Meta,绑定的 Meta 会覆盖父级的 Meta,用于 Application.apply 方法
91
+ class BindingMeta
92
+ def initialize(builder, meta)
93
+ @builder = builder
94
+ @meta = meta
95
+ end
96
+
97
+ def build(parent_path: '', meta: {}, before_callbacks: [], after_callbacks: [])
98
+ # 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
99
+ meta2 = (meta || {}).merge(@meta)
100
+ if meta[:parameters] && meta2[:parameters]
101
+ meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
102
+ end
103
+ @builder.build(parent_path: parent_path, meta: meta2, before_callbacks: before_callbacks, after_callbacks: after_callbacks)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module RouteDSL
5
+ class ChainBuilder
6
+ def initialize
7
+ @blocks = []
8
+ end
9
+
10
+ def build
11
+ blocks = @blocks
12
+ proc do
13
+ blocks.each { |b| instance_exec &b }
14
+ end
15
+ end
16
+
17
+ def do_any(&block)
18
+ @blocks << block
19
+
20
+ self
21
+ end
22
+
23
+ def resource(&block)
24
+ do_any {
25
+ resource = instance_exec(&block)
26
+
27
+ raise Errors::ResourceNotFound if resource.nil?
28
+
29
+ # 为 execution 添加一个 resource 方法
30
+ define_singleton_method(:resource) { resource }
31
+ }
32
+ end
33
+
34
+ def authorize(&block)
35
+ do_any {
36
+ permitted = instance_eval(&block)
37
+ raise Errors::NotAuthorized unless permitted
38
+ }
39
+ end
40
+
41
+ def set_status(&block)
42
+ do_any {
43
+ response.status = instance_exec(&block)
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,15 @@
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
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'parameters_builder'
4
+ require_relative 'uniformed_params_builder'
5
+
6
+ module Meta
7
+ module RouteDSL
8
+ class MetaBuilder
9
+ def initialize(&block)
10
+ @meta = {}
11
+
12
+ instance_exec &block if block_given?
13
+ end
14
+
15
+ def build
16
+ @meta
17
+ end
18
+
19
+ def parameters(&block)
20
+ @meta[:parameters] = ParametersBuilder.new(&block).build
21
+ end
22
+
23
+ def request_body(options = {}, &block)
24
+ @meta[:request_body] = JsonSchema::SchemaBuilderTool.build(options, &block)
25
+ end
26
+
27
+ # params 宏是一个遗留的宏,它在一个宏定义块内同时定义 parameters 和 request_body
28
+ def params(&block)
29
+ @meta[:parameters], @meta[:request_body] = UniformedParamsBuilder.new(&block).build
30
+ end
31
+
32
+ def status(code, *other_codes, &block)
33
+ codes = [code, *other_codes]
34
+ entity_schema = JsonSchema::SchemaBuilderTool.build(&block)
35
+ @meta[:responses] = @meta[:responses] || {}
36
+ codes.each { |code| @meta[:responses][code] = entity_schema }
37
+ end
38
+
39
+ [:tags, :title, :description].each do |method_name|
40
+ define_method(method_name) do |value|
41
+ @meta[method_name] = value
42
+ end
43
+ end
44
+
45
+ # 别的模块引入该模块时可直接调用 MetaBuilder 的方法。
46
+ # 由于该模块是动态实现的,其务必要在 MetaBuilder 类构建完毕后再声明,故而放在文件的最后声明。
47
+ module Delegator
48
+ method_names = MetaBuilder.public_instance_methods(false) - ['build']
49
+ method_names.each do |method_name|
50
+ define_method(method_name) do |*args, &block|
51
+ @meta_builder.send(method_name, *args, &block) and self
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meta
4
+ module RouteDSL
5
+ class ParametersBuilder
6
+ def initialize(&block)
7
+ @parameters = {}
8
+
9
+ instance_exec &block if block_given?
10
+ end
11
+
12
+ def param(name, options)
13
+ options = options.dup
14
+ op_in = options.delete(:in) || 'query'
15
+
16
+ @parameters[name] = { in: op_in, schema: JsonSchema::BaseSchema.new(options) }
17
+ end
18
+
19
+ def build
20
+ @parameters
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative '../entity'
5
+ require_relative '../application/route'
6
+ require_relative 'helpers'
7
+ require_relative 'chain_builder'
8
+ require_relative 'action_builder'
9
+ require_relative 'meta_builder'
10
+
11
+ module Meta
12
+ module RouteDSL
13
+ class RouteBuilder
14
+ include MetaBuilder::Delegator
15
+
16
+ alias :if_status :status
17
+
18
+ def initialize(path = '', method = :all, &block)
19
+ @path = path || ''
20
+ @method = method || :all
21
+ @action_builder = nil
22
+ @meta_builder = MetaBuilder.new
23
+
24
+ instance_exec &block if block_given?
25
+ end
26
+
27
+ def build(parent_path: '', meta: {}, before_callbacks: [], after_callbacks: [])
28
+ # 合并 meta 时不仅仅是覆盖,比如 parameters 参数需要合并
29
+ meta2 = (meta || {}).merge(@meta_builder.build)
30
+ if meta[:parameters] && meta2[:parameters]
31
+ meta2[:parameters] = meta[:parameters].merge(meta2[:parameters])
32
+ end
33
+
34
+ # 合并 parameters 参数
35
+ meta2[:parameters] ||= {}
36
+ path_params = Utils::Path.join(parent_path, @path).split('/')
37
+ .filter { |part| part =~ /[:*].+/ }
38
+ .map { |part| part[1..-1].to_sym }
39
+ path_params.each do |name|
40
+ unless meta2[:parameters].key?(name)
41
+ meta2[:parameters][name] = {
42
+ in: 'path',
43
+ schema: JsonSchema::BaseSchema.new(required: true)
44
+ }
45
+ end
46
+ end
47
+
48
+ # 将 before_callbacks、action、after_callbacks 合并为 actions
49
+ action = @action_builder&.build
50
+ actions = before_callbacks + (action ? [action] : []) + after_callbacks
51
+
52
+ Route.new(
53
+ path: @path,
54
+ method: @method,
55
+ meta: meta2,
56
+ actions: actions
57
+ )
58
+ end
59
+
60
+ def chain
61
+ @action_builder || @action_builder = ChainBuilder.new
62
+ end
63
+
64
+ def action(&block)
65
+ @action_builder = ActionBuilder.new(&block)
66
+ end
67
+
68
+ # 将 chain 的方法转交给 ChainBuilder
69
+ [:do_any, :resource, :authorize, :set_status].each do |method_name|
70
+ define_method(method_name) do |&block|
71
+ chain.send(method_name, &block)
72
+ self
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def clone_meta(meta)
79
+ meta = meta.clone
80
+ meta[:responses] = meta[:responses].clone if meta[:responses]
81
+ meta
82
+ end
83
+ end
84
+ end
85
+ end