Class: Meta::JsonSchema::BaseSchema

Inherits:
Object
  • Object
show all
Defined in:
lib/meta/json_schema/schemas/base_schema.rb

Overview

表示一个基本类型的 Schema,或继承自该类表示一个拥有其他扩展能力的 Schema.

该类包含了通用 JsonSchema 思维的基本逻辑,比如 stage 和 scope. 其他 Schema 类应当主动地继承自该类,这样就会自动获得 stage 和 scope 的能力。

该类剩余的逻辑是提供一个 options 属性,用于描述该 Schema. 因此,直接实例化该类可以用于表示基本类型,而继承该类可以用于表示还有内部递归处理的对象和数组类型。这时,应当在子类的构造函数中调用父类的构造方法,以便初始化 options 属性。并且在子类中重写 filter_internal 方法,实现内部递归处理的逻辑。这种模式的案例主要是 ObjectSchemaArraySchema.

如果是组合模式,也应当继承自该类,以便获得 stage 和 scope 的能力。但是,组合模式的 options 调用是非法的,因此不应当在构造函数中调用父类的构造方法。此时 options 为 nil,这样用到 options 的地方都会抛出异常(NoMethodError: undefined method ‘[]’ for nil:NilClass)。这种模式的案例很多,包括 StagingSchema、RefSchema 等。

Constant Summary collapse

OPTIONS_CHECKER =
Utils::KeywordArgs::Builder.build do
  key :type, :items, :description, :presenter, :value, :default, :properties, :convert
  key :validate, :required, :format, :allowable
  key :before, :after
  key :if
end
USER_OPTIONS_CHECKER =
Utils::KeywordArgs::Builder.build do
  key :execution, :object_value, :type_conversion, :validation, :user_data
  key :stage, validator: ->(value) { raise ArgumentError, "stage 只能取值为 :param 或 :render" unless [:param, :render].include?(value) }

  # 以下是 ObjectSchema 需要的选项
  # extra_properties 只能取值为 :ignore、:raise_error
  key :discard_missing, :extra_properties, :exclude, :scope
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ BaseSchema

Returns a new instance of BaseSchema.

Raises:

  • (ArgumentError)


48
49
50
51
52
53
54
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 48

def initialize(options = {})
  raise ArgumentError, 'options 必须是 Hash 类型' unless options.is_a?(Hash)
  options = OPTIONS_CHECKER.check(options)
  raise '不允许 BaseSchema 直接接受 array 类型,必须通过继承使用 ArraySchema' if options[:type] == 'array' && self.class == BaseSchema

  @options = SchemaOptions.normalize(options).freeze
end

Instance Attribute Details

#optionsObject (readonly)

options 包含了转换器、验证器、文档、选项。

由于本对象可继承,基于不同的继承可分别表示基本类型、对象和数组,所以该属性可用在不同类型的对象上。需要时刻留意的是,无论是用在哪种类型的对象内,options 属性都是描述该对象的本身,而不是深层的属性。

较常出现错误的是数组,options 是描述数组的,而不是描述数组内部元素的。



46
47
48
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 46

def options
  @options
end

Instance Method Details

#filter(value, user_options = {}) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 60

def filter(value, user_options = {})
  user_options = USER_OPTIONS_CHECKER.check(user_options)

  value = value_callback(user_options) if options[:value]
  value = before_callback(value, user_options) if options[:before]
  value = JsonSchema::Presenters.present(options[:presenter], value) if options[:presenter]
  value = resolve_default_value(options[:default]) if value.nil? && options.key?(:default)
  value = options[:convert].call(value) if options[:convert]

  # 第一步,转化值。
  # 需要注意的是,对象也可能被转换,因为并没有深层次的结构被声明。
  type = options[:type]
  unless user_options[:type_conversion] == false || type.nil? || value.nil?
    begin
      value = JsonSchema::TypeConverter.convert_value(value, type)
    rescue JsonSchema::TypeConvertError => e
      raise JsonSchema::ValidationError.new(e.message)
    end
  end

  # 第二步,做校验。
  validate!(value, options) unless user_options[:validation] == false

  # 第三步,如果存在内部属性,递归调用。
  value = filter_internal(value, user_options) unless value.nil?

  # 最后,返回 value
  value = after_callback(value, user_options) if options[:after]
  value
end

#filter?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 56

def filter?
  true
end

#find_schema(scope:, stage:) ⇒ Object

返回能够处理 scope 和 stage 的 schema(可以是 self),否则应返回 UnsupportedStageSchema 或 nil.



92
93
94
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 92

def find_schema(scope:, stage:)
  staged(stage)&.scoped(scope)
end

#if?(user_options) ⇒ Boolean

执行 if: 选项,返回 true 或 false

Returns:

  • (Boolean)


107
108
109
110
111
112
113
114
115
116
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 107

def if?(user_options)
  return true if options[:if].nil?

  execution = user_options[:execution]
  if execution
    execution.instance_exec(&options[:if])
  else
    options[:if]&.call
  end
end

#scoped(scope) ⇒ Object

返回能够处理 scope 的 schema(可以是 self),否则返回 nil.



102
103
104
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 102

def scoped(scope)
  self
end

#staged(stage) ⇒ Object

返回能够处理 stage 的 schema(可以是 self),否则返回 UnsupportedStageSchema.



97
98
99
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 97

def staged(stage)
  self
end

#to_schemaObject



139
140
141
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 139

def to_schema
  self
end

#to_schema_doc(**user_options) ⇒ Object

生成 Swagger 文档的 schema 格式。

选项:

  • stage: 传递 :param 或 :render

  • schemas: 用于保存已经生成的 Schema

  • presenter: 兼容 Grape 框架的实体类



128
129
130
131
132
133
134
135
136
137
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 128

def to_schema_doc(**user_options)
  return Presenters.to_schema_doc(options[:presenter], options) if options[:presenter]

  schema = {}
  schema[:type] = options[:type] if options[:type]
  schema[:description] = options[:description] if options[:description]
  schema[:enum] = options[:allowable] if options[:allowable]

  schema
end

#value?Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/meta/json_schema/schemas/base_schema.rb', line 118

def value?
  options[:value] != nil
end