jsi 0.2.0 → 0.6.0

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 (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
+ }