lib//meta/json_schema/support/schema_options.rb in meta-api-0.1.2 vs lib//meta/json_schema/support/schema_options.rb in meta-api-0.2.0
- old
+ new
@@ -3,46 +3,115 @@
require_relative '../../utils/kwargs/builder'
module Meta
module JsonSchema
module SchemaOptions
- @default_options = {
- scope: [],
- required: false
- }
+ BaseBuildOptions = Utils::Kwargs::Builder.build do
+ key :type, :items, :description, :presenter, :value, :default, :properties, :convert
+ key :validate, :required, :format
+ key :enum, alias_names: [:allowable]
+ key :ref, alias_names: [:using], normalizer: ->(entity) { entity }
+ key :dynamic_ref, alias_names: [:dynamic_using], normalizer: ->(value) { value.is_a?(Proc) ? { resolve: value } : value }
+ key :before, :after
+ key :if
+ end
+ module UserOptions
+ Common = Utils::Kwargs::Builder.build do
+ key :stage
+ key :scope, normalizer: ->(value) {
+ raise ArgumentError, 'scope 选项不可传递 nil' if value.nil?
+ value = [value] unless value.is_a?(Array)
+ value.map do |v|
+ # 只要加入了 Meta::Scope::Base 模块,就有与 Meta::Scope 一样的行为
+ next v if v.is_a?(Meta::Scope::Base)
+
+ # 将 v 类名化
+ scope_name = v.to_s.split('_').map(&:capitalize).join
+ # 如果符号对应的类名不存在,就报错
+ if !defined?(::Scopes) || !::Scopes.const_defined?(scope_name)
+ raise NameError, "未找到常量 Scopes::#{scope_name}。如果你用的是命名 Scope(字符串或符号),则检查一下是不是拼写错误"
+ end
+ # 返回对应的常量
+ ::Scopes.const_get(scope_name)
+ end.compact
+ }
+
+ handle_extras :merged
+ end
+ ToDoc = Utils::Kwargs::Builder.build(Common) do
+ key :schema_docs_mapping, :defined_scopes_mapping
+ end
+ Filter = Utils::Kwargs::Builder.build(Common) do
+ key :discard_missing, :exclude, :extra_properties, :type_conversion, :validation
+ key :execution, :user_data, :object_value
+ end
+ end
+
class << self
+ def fix_type_option!(options)
+ if options[:type].is_a?(Class)
+ # 修复 type 为自定义类的情形
+ the_class = options[:type]
+ # 修复 param 选项
+ options[:param] = {} if options[:param].nil?
+ make_after_cast_to_class(options[:param], the_class) if options[:param]
+ # 修复 render 选项
+ options[:render] = {} if options[:render].nil?
+ make_before_match_to_class(options[:render], the_class) if options[:render]
+ # 最终确保 type 为 object
+ options.merge!(type: 'object')
+ end
+ end
+
def divide_to_param_and_render(options)
common_opts = (options || {}).dup
param_opts = common_opts.delete(:param)
render_opts = common_opts.delete(:render)
param_opts = merge_common_to_stage(common_opts, param_opts)
render_opts = merge_common_to_stage(common_opts, render_opts)
[param_opts, render_opts, common_opts]
end
- def normalize(options)
- # 只要 options 中设置为 nil 的选项没有明确的意义,则下行代码是永远有效的
- options = (@default_options.compact).merge(options.compact)
- if options[:using]
- if options[:type].nil?
- options[:type] = 'object'
- elsif options[:type] != 'object' && options[:type] != 'array'
- raise "当使用 using 时,type 必须声明为 object 或 array"
- end
- end
-
- options
- end
-
private
def merge_common_to_stage(common_opts, stage_opts)
stage_opts = {} if stage_opts.nil? || stage_opts == true
stage_opts = common_opts.merge(stage_opts) if stage_opts
stage_opts
end
+
+ def make_after_cast_to_class(options, the_class)
+ if options[:after].nil?
+ options[:after] = ->(value) { the_class.new(value) }
+ else
+ # 如果用户自定义了 after,那么我们需要在 after 之后再包一层
+ original_after_block = options[:after]
+ options[:after] = ->(value) do
+ value = instance_exec(value, &original_after_block)
+ the_class.new(value)
+ end
+ end
+ end
+
+ def make_before_match_to_class(options, the_class)
+ match_class = ->(value) do
+ raise ValidationError, "value 必须是 #{the_class} 类型" unless value.is_a?(the_class)
+ value
+ end
+ if options[:before].nil?
+ options[:before] = match_class
+ else
+ # 如果用户自定义了 before,那么我们需要在 before 之前再包一层
+ original_before_block = options[:before]
+ options[:before] = ->(value) do
+ value = match_class.call(value)
+ instance_exec(value, &original_before_block)
+ end
+ end
+ end
+
end
end
end
end