jsi 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +36 -0
  4. data/LICENSE.md +613 -0
  5. data/README.md +153 -52
  6. data/lib/jsi/base.rb +485 -338
  7. data/lib/jsi/jsi_coder.rb +24 -18
  8. data/lib/jsi/metaschema.rb +7 -0
  9. data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
  10. data/lib/jsi/metaschema_node.rb +245 -0
  11. data/lib/jsi/pathed_node.rb +49 -46
  12. data/lib/jsi/ptr.rb +292 -0
  13. data/lib/jsi/schema/application/child_application/contains.rb +16 -0
  14. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  15. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  16. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  17. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  18. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  19. data/lib/jsi/schema/application/child_application.rb +40 -0
  20. data/lib/jsi/schema/application/draft04.rb +8 -0
  21. data/lib/jsi/schema/application/draft06.rb +8 -0
  22. data/lib/jsi/schema/application/draft07.rb +8 -0
  23. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  24. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  25. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  26. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  27. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  28. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  29. data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
  30. data/lib/jsi/schema/application/inplace_application.rb +46 -0
  31. data/lib/jsi/schema/application.rb +12 -0
  32. data/lib/jsi/schema/draft04.rb +14 -0
  33. data/lib/jsi/schema/draft06.rb +14 -0
  34. data/lib/jsi/schema/draft07.rb +14 -0
  35. data/lib/jsi/schema/issue.rb +36 -0
  36. data/lib/jsi/schema/ref.rb +159 -0
  37. data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
  38. data/lib/jsi/schema/validation/array.rb +69 -0
  39. data/lib/jsi/schema/validation/const.rb +20 -0
  40. data/lib/jsi/schema/validation/contains.rb +25 -0
  41. data/lib/jsi/schema/validation/core.rb +39 -0
  42. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  43. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  44. data/lib/jsi/schema/validation/draft04.rb +112 -0
  45. data/lib/jsi/schema/validation/draft06.rb +122 -0
  46. data/lib/jsi/schema/validation/draft07.rb +159 -0
  47. data/lib/jsi/schema/validation/enum.rb +25 -0
  48. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  49. data/lib/jsi/schema/validation/items.rb +54 -0
  50. data/lib/jsi/schema/validation/not.rb +20 -0
  51. data/lib/jsi/schema/validation/numeric.rb +121 -0
  52. data/lib/jsi/schema/validation/object.rb +45 -0
  53. data/lib/jsi/schema/validation/pattern.rb +34 -0
  54. data/lib/jsi/schema/validation/properties.rb +101 -0
  55. data/lib/jsi/schema/validation/property_names.rb +32 -0
  56. data/lib/jsi/schema/validation/ref.rb +40 -0
  57. data/lib/jsi/schema/validation/required.rb +27 -0
  58. data/lib/jsi/schema/validation/someof.rb +90 -0
  59. data/lib/jsi/schema/validation/string.rb +47 -0
  60. data/lib/jsi/schema/validation/type.rb +49 -0
  61. data/lib/jsi/schema/validation.rb +51 -0
  62. data/lib/jsi/schema.rb +528 -233
  63. data/lib/jsi/schema_classes.rb +238 -51
  64. data/lib/jsi/schema_registry.rb +141 -0
  65. data/lib/jsi/schema_set.rb +141 -0
  66. data/lib/jsi/simple_wrap.rb +8 -3
  67. data/lib/jsi/typelike_modules.rb +75 -68
  68. data/lib/jsi/util/attr_struct.rb +106 -0
  69. data/lib/jsi/util.rb +167 -64
  70. data/lib/jsi/validation/error.rb +34 -0
  71. data/lib/jsi/validation/result.rb +210 -0
  72. data/lib/jsi/validation.rb +15 -0
  73. data/lib/jsi/version.rb +3 -1
  74. data/lib/jsi.rb +72 -9
  75. data/lib/schemas/json-schema.org/draft-04/schema.rb +12 -0
  76. data/lib/schemas/json-schema.org/draft-06/schema.rb +12 -0
  77. data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
  78. data/readme.rb +138 -0
  79. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  80. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  81. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  82. metadata +80 -107
  83. data/.simplecov +0 -1
  84. data/LICENSE.txt +0 -21
  85. data/Rakefile.rb +0 -9
  86. data/jsi.gemspec +0 -31
  87. data/lib/jsi/base/to_rb.rb +0 -126
  88. data/lib/jsi/json/node.rb +0 -243
  89. data/lib/jsi/json/pointer.rb +0 -330
  90. data/lib/jsi/json-schema-fragments.rb +0 -59
  91. data/lib/jsi/json.rb +0 -8
  92. data/test/base_array_test.rb +0 -209
  93. data/test/base_hash_test.rb +0 -204
  94. data/test/base_test.rb +0 -422
  95. data/test/jsi_coder_test.rb +0 -85
  96. data/test/jsi_json_arraynode_test.rb +0 -150
  97. data/test/jsi_json_hashnode_test.rb +0 -132
  98. data/test/jsi_json_node_test.rb +0 -310
  99. data/test/jsi_json_pointer_test.rb +0 -106
  100. data/test/jsi_test.rb +0 -11
  101. data/test/jsi_typelike_as_json_test.rb +0 -53
  102. data/test/schema_test.rb +0 -196
  103. data/test/spreedly_openapi_test.rb +0 -8
  104. data/test/test_helper.rb +0 -63
  105. data/test/util_test.rb +0 -62
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Validation
5
+ Error = Util::AttrStruct[*%w(
6
+ message
7
+ keyword
8
+ schema
9
+ instance_ptr
10
+ instance_document
11
+ )]
12
+
13
+ # a validation error of a schema instance against a schema
14
+ #
15
+ # @!attribute message
16
+ # a message describing the error
17
+ # @return [String]
18
+ # @!attribute keyword
19
+ # the keyword of the schema which failed to validate.
20
+ # this may be absent if the error is not from a schema keyword (i.e, `false` schema).
21
+ # @return [String]
22
+ # @!attribute schema
23
+ # the schema against which the instance failed to validate
24
+ # @return [JSI::Schema]
25
+ # @!attribute instance_ptr
26
+ # pointer to the instance in instance_document
27
+ # @return [JSI::Ptr]
28
+ # @!attribute instance_document
29
+ # document containing the instance at instance_ptr
30
+ # @return [Object]
31
+ class Error
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Validation
5
+ # a result of validating an instance against schemas which describe it.
6
+ # virtual base class.
7
+ class Result
8
+ include Util::Virtual
9
+
10
+ Builder = Util::AttrStruct[*%w(
11
+ result
12
+ schema
13
+ instance_ptr
14
+ instance_document
15
+ validate_only
16
+ visited_refs
17
+ )]
18
+
19
+ # @private
20
+ # a structure used to build a Result. virtual base class.
21
+ class Builder
22
+ def instance
23
+ instance_ptr.evaluate(instance_document)
24
+ end
25
+
26
+ def schema_issue(*_)
27
+ virtual_method
28
+ end
29
+
30
+ def schema_error(message, keyword = nil)
31
+ schema_issue(:error, message, keyword)
32
+ end
33
+
34
+ def schema_warning(message, keyword = nil)
35
+ schema_issue(:warning, message, keyword)
36
+ end
37
+
38
+ # @param subschema_ptr [JSI::Ptr, #to_ary]
39
+ # @return [JSI::Validation::Result]
40
+ def inplace_subschema_validate(subschema_ptr)
41
+ subresult = schema.subschema(subschema_ptr).internal_validate_instance(
42
+ instance_ptr,
43
+ instance_document,
44
+ validate_only: validate_only,
45
+ visited_refs: visited_refs,
46
+ )
47
+ merge_schema_issues(subresult)
48
+ subresult
49
+ end
50
+
51
+ # @param subschema_ptr [JSI::Ptr, #to_ary]
52
+ # @param subinstance_ptr [JSI::Ptr, #to_ary]
53
+ # @return [JSI::Validation::Result]
54
+ def child_subschema_validate(subschema_ptr, subinstance_ptr)
55
+ subresult = schema.subschema(subschema_ptr).internal_validate_instance(
56
+ instance_ptr + subinstance_ptr,
57
+ instance_document,
58
+ validate_only: validate_only,
59
+ )
60
+ merge_schema_issues(subresult)
61
+ subresult
62
+ end
63
+
64
+ # @param other_result [JSI::Validation::Result]
65
+ # @return [void]
66
+ def merge_schema_issues(other_result)
67
+ unless validate_only
68
+ # schema_issues are always merged from subschema results (not depending on validation results)
69
+ result.schema_issues.merge(other_result.schema_issues)
70
+ end
71
+ nil
72
+ end
73
+ end
74
+
75
+ def builder(schema, instance_ptr, instance_document, validate_only, visited_refs)
76
+ self.class::Builder.new(
77
+ result: self,
78
+ schema: schema,
79
+ instance_ptr: instance_ptr,
80
+ instance_document: instance_document,
81
+ validate_only: validate_only,
82
+ visited_refs: visited_refs,
83
+ )
84
+ end
85
+
86
+ # is the instance valid against its schemas?
87
+ # @return [Boolean]
88
+ def valid?
89
+ # :nocov:
90
+ virtual_method
91
+ # :nocov:
92
+ end
93
+
94
+ include Util::FingerprintHash
95
+ end
96
+
97
+ # a full result of validating an instance against its schemas, with each validation error
98
+ class FullResult < Result
99
+ # @private
100
+ class Builder < Result::Builder
101
+ def validate(
102
+ valid,
103
+ message,
104
+ keyword: nil,
105
+ results: []
106
+ )
107
+ results.each { |res| result.schema_issues.merge(res.schema_issues) }
108
+ if !valid
109
+ results.each { |res| result.validation_errors.merge(res.validation_errors) }
110
+ result.validation_errors << Validation::Error.new({
111
+ message: message,
112
+ keyword: keyword,
113
+ schema: schema,
114
+ instance_ptr: instance_ptr,
115
+ instance_document: instance_document,
116
+ })
117
+ end
118
+ end
119
+
120
+ def schema_issue(level, message, keyword = nil)
121
+ result.schema_issues << Schema::Issue.new({
122
+ level: level,
123
+ message: message,
124
+ keyword: keyword,
125
+ schema: schema,
126
+ })
127
+ end
128
+ end
129
+
130
+ def initialize
131
+ @validation_errors = Set.new
132
+ @schema_issues = Set.new
133
+ end
134
+
135
+ attr_reader :validation_errors
136
+ attr_reader :schema_issues
137
+
138
+ def valid?
139
+ validation_errors.empty?
140
+ end
141
+
142
+ def freeze
143
+ @validation_errors.each(&:freeze)
144
+ @schema_issues.each(&:freeze)
145
+ @validation_errors.freeze
146
+ @schema_issues.freeze
147
+ super
148
+ end
149
+
150
+ def merge(result)
151
+ unless result.is_a?(FullResult)
152
+ raise(TypeError, "not a #{FullResult.name}: #{result.pretty_inspect.chomp}")
153
+ end
154
+ validation_errors.merge(result.validation_errors)
155
+ schema_issues.merge(result.schema_issues)
156
+ self
157
+ end
158
+
159
+ def +(result)
160
+ FullResult.new.merge(self).merge(result)
161
+ end
162
+
163
+ # @private
164
+ def jsi_fingerprint
165
+ {
166
+ class: self.class,
167
+ validation_errors: validation_errors,
168
+ schema_issues: schema_issues,
169
+ }
170
+ end
171
+ end
172
+
173
+ # a result indicating only whether an instance is valid against its schemas
174
+ class ValidityResult < Result
175
+ # @private
176
+ class Builder < Result::Builder
177
+ def validate(
178
+ valid,
179
+ message,
180
+ keyword: nil,
181
+ results: []
182
+ )
183
+ if !valid
184
+ throw(:jsi_validation_result, INVALID)
185
+ end
186
+ end
187
+
188
+ def schema_issue(*_)
189
+ # noop
190
+ end
191
+ end
192
+
193
+ def initialize(valid)
194
+ @valid = valid
195
+ end
196
+
197
+ def valid?
198
+ @valid
199
+ end
200
+
201
+ # @private
202
+ def jsi_fingerprint
203
+ {
204
+ class: self.class,
205
+ valid: valid?,
206
+ }
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ module Validation
5
+ autoload :Error, 'jsi/validation/error'
6
+
7
+ autoload :Result, 'jsi/validation/result'
8
+ autoload :FullResult, 'jsi/validation/result'
9
+ autoload :ValidityResult, 'jsi/validation/result'
10
+
11
+ VALID = ValidityResult.new(true).freeze
12
+
13
+ INVALID = ValidityResult.new(false).freeze
14
+ end
15
+ end
data/lib/jsi/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSI
2
- VERSION = "0.2.0".freeze
4
+ VERSION = "0.6.0".freeze
3
5
  end
data/lib/jsi.rb CHANGED
@@ -1,33 +1,96 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "jsi/version"
2
4
  require "pp"
3
5
  require "set"
4
- require "jsi/json-schema-fragments"
6
+ require "json"
7
+ require "pathname"
8
+ require "bigdecimal"
9
+ require "addressable/uri"
10
+
5
11
  require "jsi/util"
12
+ require "jsi/typelike_modules"
6
13
 
7
14
  module JSI
8
15
  # generally put in code paths that are not expected to be valid control flow paths.
9
16
  # rather a NotImplementedCorrectlyError. but that's too long.
17
+ #
18
+ # if you've found this class because JSI has raised this error, please open an issue with the backtrace
19
+ # and any context you can provide at https://github.com/notEthan/jsi/issues
10
20
  class Bug < NotImplementedError
11
21
  end
12
22
 
13
- autoload :JSON, 'jsi/json'
23
+ # @private
24
+ ROOT_PATH = Pathname.new(__FILE__).dirname.parent.expand_path
25
+
26
+ # @private
27
+ RESOURCES_PATH = ROOT_PATH.join('{resources}')
28
+
29
+ # @private
30
+ SCHEMAS_PATH = RESOURCES_PATH.join('schemas')
31
+
32
+ autoload :Ptr, 'jsi/ptr'
33
+
34
+ # @private
35
+ # @deprecated
36
+ module JSON
37
+ Pointer = Ptr
38
+ end
39
+
14
40
  autoload :PathedNode, 'jsi/pathed_node'
15
41
  autoload :Typelike, 'jsi/typelike_modules'
16
42
  autoload :Hashlike, 'jsi/typelike_modules'
17
43
  autoload :Arraylike, 'jsi/typelike_modules'
18
44
  autoload :Schema, 'jsi/schema'
45
+ autoload :SchemaSet, 'jsi/schema_set'
19
46
  autoload :Base, 'jsi/base'
20
- autoload :BaseArray, 'jsi/base'
21
- autoload :BaseHash, 'jsi/base'
47
+ autoload :Metaschema, 'jsi/metaschema'
48
+ autoload :MetaschemaNode, 'jsi/metaschema_node'
22
49
  autoload :SchemaClasses, 'jsi/schema_classes'
50
+ autoload :SchemaRegistry, 'jsi/schema_registry'
51
+ autoload :Validation, 'jsi/validation'
23
52
  autoload :JSICoder, 'jsi/jsi_coder'
24
53
 
54
+ autoload :JSONSchemaOrgDraft04, 'schemas/json-schema.org/draft-04/schema'
55
+ autoload :JSONSchemaOrgDraft06, 'schemas/json-schema.org/draft-06/schema'
56
+ autoload :JSONSchemaOrgDraft07, 'schemas/json-schema.org/draft-07/schema'
57
+
25
58
  autoload :SimpleWrap, 'jsi/simple_wrap'
26
59
 
27
- # @return [Class subclassing JSI::Base] a JSI class which represents the
28
- # given schema. instances of the class represent JSON Schema instances
29
- # for the given schema.
30
- def self.class_for_schema(*a, &b)
31
- SchemaClasses.class_for_schema(*a, &b)
60
+ # instantiates a given schema object as a JSI Schema.
61
+ #
62
+ # see {JSI::Schema.new_schema}
63
+ #
64
+ # @param (see JSI::Schema.new_schema)
65
+ # @return (see JSI::Schema.new_schema)
66
+ def self.new_schema(schema_object, **kw)
67
+ JSI::Schema.new_schema(schema_object, **kw)
68
+ end
69
+
70
+ # instantiates a given schema object as a JSI Schema and returns its JSI Schema Module.
71
+ #
72
+ # shortcut to chain {JSI::Schema.new_schema} + {Schema#jsi_schema_module}.
73
+ #
74
+ # @param (see JSI::Schema.new_schema)
75
+ # @return [Module, JSI::SchemaModule] the JSI Schema Module of the schema
76
+ def self.new_schema_module(schema_object, **kw)
77
+ JSI::Schema.new_schema(schema_object, **kw).jsi_schema_module
78
+ end
79
+
80
+ # @private @deprecated
81
+ def self.class_for_schemas(schemas)
82
+ SchemaClasses.class_for_schemas(schemas.map { |schema| JSI.new_schema(schema) })
83
+ end
84
+
85
+ # `JSI.schema_registry` is the {JSI::SchemaRegistry} in which schemas are registered.
86
+ #
87
+ # @return [JSI::SchemaRegistry]
88
+ def self.schema_registry
89
+ return @schema_registry if instance_variable_defined?(:@schema_registry)
90
+ @schema_registry = SchemaRegistry.new
32
91
  end
33
92
  end
93
+
94
+ JSI.schema_registry.autoload_uri("http://json-schema.org/draft-04/schema") { JSI::JSONSchemaOrgDraft04.schema }
95
+ JSI.schema_registry.autoload_uri("http://json-schema.org/draft-06/schema") { JSI::JSONSchemaOrgDraft06.schema }
96
+ JSI.schema_registry.autoload_uri("http://json-schema.org/draft-07/schema") { JSI::JSONSchemaOrgDraft07.schema }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-04/schema.json').read)
5
+ JSONSchemaOrgDraft04 = MetaschemaNode.new(metaschema_document,
6
+ metaschema_instance_modules: [JSI::Schema::Draft04],
7
+ ).jsi_schema_module
8
+
9
+ # the JSI schema module for `http://json-schema.org/draft-04/schema`
10
+ module JSONSchemaOrgDraft04
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-06/schema.json').read)
5
+ JSONSchemaOrgDraft06 = MetaschemaNode.new(metaschema_document,
6
+ metaschema_instance_modules: [JSI::Schema::Draft06],
7
+ ).jsi_schema_module
8
+
9
+ # the JSI schema module for `http://json-schema.org/draft-06/schema`
10
+ module JSONSchemaOrgDraft06
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-07/schema.json').read)
5
+ JSONSchemaOrgDraft07 = MetaschemaNode.new(metaschema_document,
6
+ metaschema_instance_modules: [JSI::Schema::Draft07],
7
+ ).jsi_schema_module
8
+
9
+ # the JSI schema module for `http://json-schema.org/draft-07/schema`
10
+ module JSONSchemaOrgDraft07
11
+ end
12
+ end
data/readme.rb ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # a small script following the code samples in the README
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
7
+ require 'jsi'
8
+
9
+ puts "creating a schema and assigning its schema module to a constant"
10
+ puts
11
+
12
+ contact_schema = JSI.new_schema({
13
+ "$schema" => "http://json-schema.org/draft-07/schema",
14
+ "description" => "A Contact",
15
+ "type" => "object",
16
+ "properties" => {
17
+ "name" => {
18
+ "type" => "string",
19
+ },
20
+ "phone" => {
21
+ "type" => "array",
22
+ "items" => {
23
+ "type" => "object",
24
+ "properties" => {
25
+ "location" => {
26
+ "type" => "string",
27
+ },
28
+ "number" => {
29
+ "type" => "string",
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ })
36
+
37
+ print 'contact_schema: '
38
+ pp contact_schema
39
+
40
+ print 'contact_schema.jsi_schema_module: '
41
+ pp contact_schema.jsi_schema_module
42
+
43
+ puts "constant assignment: Contact = contact_schema.jsi_schema_module"
44
+ Contact = contact_schema.jsi_schema_module
45
+
46
+ print 'contact_schema.jsi_schema_module: '
47
+ pp contact_schema.jsi_schema_module
48
+
49
+ puts
50
+ puts "creating and using an instance described by the schema"
51
+ puts
52
+
53
+ bill = Contact.new_jsi({
54
+ "name" => "bill",
55
+ "phone" => [
56
+ {
57
+ "location" => "home",
58
+ "number" => "555",
59
+ }
60
+ ],
61
+ "nickname" => "big b",
62
+ })
63
+
64
+ print 'bill: '
65
+ pp bill
66
+
67
+ print 'bill.name: '
68
+ pp bill.name
69
+
70
+ print 'bill.phone.map(&:location): '
71
+ pp bill.phone.map(&:location)
72
+
73
+ print 'bill.jsi_valid?: '
74
+ pp bill.jsi_valid?
75
+
76
+ bad = Contact.new_jsi({'phone' => [{'number' => [5, 5, 5]}]})
77
+
78
+ print 'bad: '
79
+ pp bad
80
+
81
+ print 'bad.phone.jsi_validate: '
82
+ pp bad.phone.jsi_validate
83
+
84
+ print 'bill.transform_values(&:size): '
85
+ pp bill.transform_values(&:size)
86
+
87
+ print "bill['nickname']: "
88
+ pp bill['nickname']
89
+
90
+ puts
91
+ puts "OOP: application-defined methods on schema modules apply to their instances"
92
+ puts
93
+
94
+ module Contact
95
+ def phone_numbers
96
+ phone.map(&:number)
97
+ end
98
+ def name
99
+ super + ' esq.'
100
+ end
101
+ def name=(name)
102
+ super(name.chomp(' esq.'))
103
+ end
104
+ end
105
+
106
+ print 'bill.name: '
107
+ pp bill.name
108
+
109
+ puts "bill.name = 'rob esq.'"
110
+ bill.name = 'rob esq.'
111
+
112
+ print "bill['name']: "
113
+ pp bill['name']
114
+
115
+ print 'bill.phone_numbers: '
116
+ pp bill.phone_numbers
117
+
118
+ puts
119
+ puts "OOP on subschemas"
120
+ puts
121
+
122
+ print "Contact.properties['phone'].items: "
123
+ pp Contact.properties['phone'].items
124
+
125
+ module Contact
126
+ Phone = properties['phone'].items
127
+ module Phone
128
+ def number_with_dashes
129
+ number.split(//).join('-')
130
+ end
131
+ end
132
+ end
133
+
134
+ print "Contact.properties['phone'].items: "
135
+ pp Contact.properties['phone'].items
136
+
137
+ print 'bill.phone.first.number_with_dashes: '
138
+ pp bill.phone.first.number_with_dashes
@@ -0,0 +1,149 @@
1
+ {
2
+ "id": "http://json-schema.org/draft-04/schema#",
3
+ "$schema": "http://json-schema.org/draft-04/schema#",
4
+ "description": "Core schema meta-schema",
5
+ "definitions": {
6
+ "schemaArray": {
7
+ "type": "array",
8
+ "minItems": 1,
9
+ "items": { "$ref": "#" }
10
+ },
11
+ "positiveInteger": {
12
+ "type": "integer",
13
+ "minimum": 0
14
+ },
15
+ "positiveIntegerDefault0": {
16
+ "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
17
+ },
18
+ "simpleTypes": {
19
+ "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
20
+ },
21
+ "stringArray": {
22
+ "type": "array",
23
+ "items": { "type": "string" },
24
+ "minItems": 1,
25
+ "uniqueItems": true
26
+ }
27
+ },
28
+ "type": "object",
29
+ "properties": {
30
+ "id": {
31
+ "type": "string"
32
+ },
33
+ "$schema": {
34
+ "type": "string"
35
+ },
36
+ "title": {
37
+ "type": "string"
38
+ },
39
+ "description": {
40
+ "type": "string"
41
+ },
42
+ "default": {},
43
+ "multipleOf": {
44
+ "type": "number",
45
+ "minimum": 0,
46
+ "exclusiveMinimum": true
47
+ },
48
+ "maximum": {
49
+ "type": "number"
50
+ },
51
+ "exclusiveMaximum": {
52
+ "type": "boolean",
53
+ "default": false
54
+ },
55
+ "minimum": {
56
+ "type": "number"
57
+ },
58
+ "exclusiveMinimum": {
59
+ "type": "boolean",
60
+ "default": false
61
+ },
62
+ "maxLength": { "$ref": "#/definitions/positiveInteger" },
63
+ "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
64
+ "pattern": {
65
+ "type": "string",
66
+ "format": "regex"
67
+ },
68
+ "additionalItems": {
69
+ "anyOf": [
70
+ { "type": "boolean" },
71
+ { "$ref": "#" }
72
+ ],
73
+ "default": {}
74
+ },
75
+ "items": {
76
+ "anyOf": [
77
+ { "$ref": "#" },
78
+ { "$ref": "#/definitions/schemaArray" }
79
+ ],
80
+ "default": {}
81
+ },
82
+ "maxItems": { "$ref": "#/definitions/positiveInteger" },
83
+ "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
84
+ "uniqueItems": {
85
+ "type": "boolean",
86
+ "default": false
87
+ },
88
+ "maxProperties": { "$ref": "#/definitions/positiveInteger" },
89
+ "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
90
+ "required": { "$ref": "#/definitions/stringArray" },
91
+ "additionalProperties": {
92
+ "anyOf": [
93
+ { "type": "boolean" },
94
+ { "$ref": "#" }
95
+ ],
96
+ "default": {}
97
+ },
98
+ "definitions": {
99
+ "type": "object",
100
+ "additionalProperties": { "$ref": "#" },
101
+ "default": {}
102
+ },
103
+ "properties": {
104
+ "type": "object",
105
+ "additionalProperties": { "$ref": "#" },
106
+ "default": {}
107
+ },
108
+ "patternProperties": {
109
+ "type": "object",
110
+ "additionalProperties": { "$ref": "#" },
111
+ "default": {}
112
+ },
113
+ "dependencies": {
114
+ "type": "object",
115
+ "additionalProperties": {
116
+ "anyOf": [
117
+ { "$ref": "#" },
118
+ { "$ref": "#/definitions/stringArray" }
119
+ ]
120
+ }
121
+ },
122
+ "enum": {
123
+ "type": "array",
124
+ "minItems": 1,
125
+ "uniqueItems": true
126
+ },
127
+ "type": {
128
+ "anyOf": [
129
+ { "$ref": "#/definitions/simpleTypes" },
130
+ {
131
+ "type": "array",
132
+ "items": { "$ref": "#/definitions/simpleTypes" },
133
+ "minItems": 1,
134
+ "uniqueItems": true
135
+ }
136
+ ]
137
+ },
138
+ "format": { "type": "string" },
139
+ "allOf": { "$ref": "#/definitions/schemaArray" },
140
+ "anyOf": { "$ref": "#/definitions/schemaArray" },
141
+ "oneOf": { "$ref": "#/definitions/schemaArray" },
142
+ "not": { "$ref": "#" }
143
+ },
144
+ "dependencies": {
145
+ "exclusiveMaximum": [ "maximum" ],
146
+ "exclusiveMinimum": [ "minimum" ]
147
+ },
148
+ "default": {}
149
+ }