jsi 0.4.0 → 0.7.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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +33 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +114 -42
  6. data/jsi.gemspec +14 -12
  7. data/lib/jsi/base/node.rb +183 -0
  8. data/lib/jsi/base.rb +388 -220
  9. data/lib/jsi/jsi_coder.rb +8 -7
  10. data/lib/jsi/metaschema.rb +0 -1
  11. data/lib/jsi/metaschema_node/bootstrap_schema.rb +101 -0
  12. data/lib/jsi/metaschema_node.rb +159 -135
  13. data/lib/jsi/ptr.rb +303 -0
  14. data/lib/jsi/schema/application/child_application/contains.rb +25 -0
  15. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  16. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  17. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  18. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  19. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  20. data/lib/jsi/schema/application/child_application.rb +38 -0
  21. data/lib/jsi/schema/application/draft04.rb +8 -0
  22. data/lib/jsi/schema/application/draft06.rb +8 -0
  23. data/lib/jsi/schema/application/draft07.rb +8 -0
  24. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  25. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  26. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  27. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  28. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  29. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  30. data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
  31. data/lib/jsi/schema/application/inplace_application.rb +41 -0
  32. data/lib/jsi/schema/application.rb +12 -0
  33. data/lib/jsi/schema/draft04.rb +14 -0
  34. data/lib/jsi/schema/draft06.rb +14 -0
  35. data/lib/jsi/schema/draft07.rb +14 -0
  36. data/lib/jsi/schema/issue.rb +36 -0
  37. data/lib/jsi/schema/ref.rb +160 -0
  38. data/lib/jsi/schema/schema_ancestor_node.rb +113 -0
  39. data/lib/jsi/schema/validation/array.rb +69 -0
  40. data/lib/jsi/schema/validation/const.rb +20 -0
  41. data/lib/jsi/schema/validation/contains.rb +25 -0
  42. data/lib/jsi/schema/validation/core.rb +39 -0
  43. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  44. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  45. data/lib/jsi/schema/validation/draft04.rb +112 -0
  46. data/lib/jsi/schema/validation/draft06.rb +122 -0
  47. data/lib/jsi/schema/validation/draft07.rb +159 -0
  48. data/lib/jsi/schema/validation/enum.rb +25 -0
  49. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  50. data/lib/jsi/schema/validation/items.rb +54 -0
  51. data/lib/jsi/schema/validation/not.rb +20 -0
  52. data/lib/jsi/schema/validation/numeric.rb +121 -0
  53. data/lib/jsi/schema/validation/object.rb +45 -0
  54. data/lib/jsi/schema/validation/pattern.rb +34 -0
  55. data/lib/jsi/schema/validation/properties.rb +101 -0
  56. data/lib/jsi/schema/validation/property_names.rb +32 -0
  57. data/lib/jsi/schema/validation/ref.rb +40 -0
  58. data/lib/jsi/schema/validation/required.rb +27 -0
  59. data/lib/jsi/schema/validation/someof.rb +90 -0
  60. data/lib/jsi/schema/validation/string.rb +47 -0
  61. data/lib/jsi/schema/validation/type.rb +49 -0
  62. data/lib/jsi/schema/validation.rb +51 -0
  63. data/lib/jsi/schema.rb +508 -149
  64. data/lib/jsi/schema_classes.rb +199 -59
  65. data/lib/jsi/schema_registry.rb +151 -0
  66. data/lib/jsi/schema_set.rb +181 -0
  67. data/lib/jsi/simple_wrap.rb +23 -4
  68. data/lib/jsi/util/private/attr_struct.rb +127 -0
  69. data/lib/jsi/util/private.rb +204 -0
  70. data/lib/jsi/util/typelike.rb +229 -0
  71. data/lib/jsi/util.rb +89 -53
  72. data/lib/jsi/validation/error.rb +34 -0
  73. data/lib/jsi/validation/result.rb +210 -0
  74. data/lib/jsi/validation.rb +15 -0
  75. data/lib/jsi/version.rb +3 -1
  76. data/lib/jsi.rb +44 -14
  77. data/lib/schemas/json-schema.org/draft-04/schema.rb +10 -3
  78. data/lib/schemas/json-schema.org/draft-06/schema.rb +10 -3
  79. data/lib/schemas/json-schema.org/draft-07/schema.rb +14 -0
  80. data/readme.rb +138 -0
  81. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  82. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  83. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  84. metadata +75 -122
  85. data/.simplecov +0 -3
  86. data/Rakefile.rb +0 -9
  87. data/lib/jsi/base/to_rb.rb +0 -128
  88. data/lib/jsi/json/node.rb +0 -203
  89. data/lib/jsi/json/pointer.rb +0 -419
  90. data/lib/jsi/json-schema-fragments.rb +0 -61
  91. data/lib/jsi/json.rb +0 -10
  92. data/lib/jsi/pathed_node.rb +0 -118
  93. data/lib/jsi/typelike_modules.rb +0 -240
  94. data/resources/icons/AGPL-3.0.png +0 -0
  95. data/test/base_array_test.rb +0 -323
  96. data/test/base_hash_test.rb +0 -337
  97. data/test/base_test.rb +0 -486
  98. data/test/jsi_coder_test.rb +0 -85
  99. data/test/jsi_json_arraynode_test.rb +0 -150
  100. data/test/jsi_json_hashnode_test.rb +0 -132
  101. data/test/jsi_json_node_test.rb +0 -257
  102. data/test/jsi_json_pointer_test.rb +0 -102
  103. data/test/jsi_test.rb +0 -11
  104. data/test/jsi_typelike_as_json_test.rb +0 -53
  105. data/test/metaschema_node_test.rb +0 -19
  106. data/test/schema_module_test.rb +0 -21
  107. data/test/schema_test.rb +0 -208
  108. data/test/spreedly_openapi_test.rb +0 -8
  109. data/test/test_helper.rb +0 -97
  110. data/test/util_test.rb +0 -62
metadata CHANGED
@@ -1,99 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-06 00:00:00.000000000 Z
11
+ date: 2023-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: json-schema
14
+ name: addressable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.8'
19
+ version: '2.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.8'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: minitest-around
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: minitest-reporters
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: scorpio
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
26
+ version: '2.3'
97
27
  description: JSI offers an Object-Oriented representation for JSON data using JSON
98
28
  Schemas
99
29
  email:
@@ -102,54 +32,93 @@ executables: []
102
32
  extensions: []
103
33
  extra_rdoc_files: []
104
34
  files:
105
- - ".simplecov"
106
35
  - ".yardopts"
107
36
  - CHANGELOG.md
108
37
  - LICENSE.md
109
38
  - README.md
110
- - Rakefile.rb
111
39
  - jsi.gemspec
112
40
  - lib/jsi.rb
113
41
  - lib/jsi/base.rb
114
- - lib/jsi/base/to_rb.rb
42
+ - lib/jsi/base/node.rb
115
43
  - lib/jsi/jsi_coder.rb
116
- - lib/jsi/json-schema-fragments.rb
117
- - lib/jsi/json.rb
118
- - lib/jsi/json/node.rb
119
- - lib/jsi/json/pointer.rb
120
44
  - lib/jsi/metaschema.rb
121
45
  - lib/jsi/metaschema_node.rb
122
- - lib/jsi/pathed_node.rb
46
+ - lib/jsi/metaschema_node/bootstrap_schema.rb
47
+ - lib/jsi/ptr.rb
123
48
  - lib/jsi/schema.rb
49
+ - lib/jsi/schema/application.rb
50
+ - lib/jsi/schema/application/child_application.rb
51
+ - lib/jsi/schema/application/child_application/contains.rb
52
+ - lib/jsi/schema/application/child_application/draft04.rb
53
+ - lib/jsi/schema/application/child_application/draft06.rb
54
+ - lib/jsi/schema/application/child_application/draft07.rb
55
+ - lib/jsi/schema/application/child_application/items.rb
56
+ - lib/jsi/schema/application/child_application/properties.rb
57
+ - lib/jsi/schema/application/draft04.rb
58
+ - lib/jsi/schema/application/draft06.rb
59
+ - lib/jsi/schema/application/draft07.rb
60
+ - lib/jsi/schema/application/inplace_application.rb
61
+ - lib/jsi/schema/application/inplace_application/dependencies.rb
62
+ - lib/jsi/schema/application/inplace_application/draft04.rb
63
+ - lib/jsi/schema/application/inplace_application/draft06.rb
64
+ - lib/jsi/schema/application/inplace_application/draft07.rb
65
+ - lib/jsi/schema/application/inplace_application/ifthenelse.rb
66
+ - lib/jsi/schema/application/inplace_application/ref.rb
67
+ - lib/jsi/schema/application/inplace_application/someof.rb
68
+ - lib/jsi/schema/draft04.rb
69
+ - lib/jsi/schema/draft06.rb
70
+ - lib/jsi/schema/draft07.rb
71
+ - lib/jsi/schema/issue.rb
72
+ - lib/jsi/schema/ref.rb
73
+ - lib/jsi/schema/schema_ancestor_node.rb
74
+ - lib/jsi/schema/validation.rb
75
+ - lib/jsi/schema/validation/array.rb
76
+ - lib/jsi/schema/validation/const.rb
77
+ - lib/jsi/schema/validation/contains.rb
78
+ - lib/jsi/schema/validation/core.rb
79
+ - lib/jsi/schema/validation/dependencies.rb
80
+ - lib/jsi/schema/validation/draft04.rb
81
+ - lib/jsi/schema/validation/draft04/minmax.rb
82
+ - lib/jsi/schema/validation/draft06.rb
83
+ - lib/jsi/schema/validation/draft07.rb
84
+ - lib/jsi/schema/validation/enum.rb
85
+ - lib/jsi/schema/validation/ifthenelse.rb
86
+ - lib/jsi/schema/validation/items.rb
87
+ - lib/jsi/schema/validation/not.rb
88
+ - lib/jsi/schema/validation/numeric.rb
89
+ - lib/jsi/schema/validation/object.rb
90
+ - lib/jsi/schema/validation/pattern.rb
91
+ - lib/jsi/schema/validation/properties.rb
92
+ - lib/jsi/schema/validation/property_names.rb
93
+ - lib/jsi/schema/validation/ref.rb
94
+ - lib/jsi/schema/validation/required.rb
95
+ - lib/jsi/schema/validation/someof.rb
96
+ - lib/jsi/schema/validation/string.rb
97
+ - lib/jsi/schema/validation/type.rb
124
98
  - lib/jsi/schema_classes.rb
99
+ - lib/jsi/schema_registry.rb
100
+ - lib/jsi/schema_set.rb
125
101
  - lib/jsi/simple_wrap.rb
126
- - lib/jsi/typelike_modules.rb
127
102
  - lib/jsi/util.rb
103
+ - lib/jsi/util/private.rb
104
+ - lib/jsi/util/private/attr_struct.rb
105
+ - lib/jsi/util/typelike.rb
106
+ - lib/jsi/validation.rb
107
+ - lib/jsi/validation/error.rb
108
+ - lib/jsi/validation/result.rb
128
109
  - lib/jsi/version.rb
129
110
  - lib/schemas/json-schema.org/draft-04/schema.rb
130
111
  - lib/schemas/json-schema.org/draft-06/schema.rb
131
- - resources/icons/AGPL-3.0.png
132
- - test/base_array_test.rb
133
- - test/base_hash_test.rb
134
- - test/base_test.rb
135
- - test/jsi_coder_test.rb
136
- - test/jsi_json_arraynode_test.rb
137
- - test/jsi_json_hashnode_test.rb
138
- - test/jsi_json_node_test.rb
139
- - test/jsi_json_pointer_test.rb
140
- - test/jsi_test.rb
141
- - test/jsi_typelike_as_json_test.rb
142
- - test/metaschema_node_test.rb
143
- - test/schema_module_test.rb
144
- - test/schema_test.rb
145
- - test/spreedly_openapi_test.rb
146
- - test/test_helper.rb
147
- - test/util_test.rb
112
+ - lib/schemas/json-schema.org/draft-07/schema.rb
113
+ - readme.rb
114
+ - "{resources}/schemas/json-schema.org/draft-04/schema.json"
115
+ - "{resources}/schemas/json-schema.org/draft-06/schema.json"
116
+ - "{resources}/schemas/json-schema.org/draft-07/schema.json"
148
117
  homepage: https://github.com/notEthan/jsi
149
118
  licenses:
150
119
  - AGPL-3.0
151
120
  metadata: {}
152
- post_install_message:
121
+ post_install_message:
153
122
  rdoc_options: []
154
123
  require_paths:
155
124
  - lib
@@ -164,24 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
133
  - !ruby/object:Gem::Version
165
134
  version: '0'
166
135
  requirements: []
167
- rubygems_version: 3.0.6
168
- signing_key:
136
+ rubygems_version: 3.1.6
137
+ signing_key:
169
138
  specification_version: 4
170
139
  summary: 'JSI: JSON Schema Instantiation'
171
- test_files:
172
- - test/base_array_test.rb
173
- - test/base_hash_test.rb
174
- - test/base_test.rb
175
- - test/jsi_coder_test.rb
176
- - test/jsi_json_arraynode_test.rb
177
- - test/jsi_json_hashnode_test.rb
178
- - test/jsi_json_node_test.rb
179
- - test/jsi_json_pointer_test.rb
180
- - test/jsi_test.rb
181
- - test/jsi_typelike_as_json_test.rb
182
- - test/metaschema_node_test.rb
183
- - test/schema_module_test.rb
184
- - test/schema_test.rb
185
- - test/spreedly_openapi_test.rb
186
- - test/test_helper.rb
187
- - test/util_test.rb
140
+ test_files: []
data/.simplecov DELETED
@@ -1,3 +0,0 @@
1
- SimpleCov.start do
2
- coverage_dir '{coverage}'
3
- end
data/Rakefile.rb DELETED
@@ -1,9 +0,0 @@
1
- require "rake/testtask"
2
-
3
- Rake::TestTask.new(:test) do |t|
4
- t.libs << "test"
5
- t.libs << "lib"
6
- t.test_files = FileList["test/**/*_test.rb"]
7
- end
8
-
9
- task :default => :test
@@ -1,128 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JSI
4
- class Base
5
- class << self
6
- def class_comment
7
- lines = []
8
-
9
- description = schema &&
10
- schema['description'].respond_to?(:to_str) &&
11
- schema['description'].to_str
12
- if description
13
- description.split("\n", -1).each do |descline|
14
- lines << "# " + descline
15
- end
16
- lines << "#"
17
- end
18
-
19
- schema.described_object_property_names.each_with_index do |propname, i|
20
- lines << "#" unless i == 0
21
- lines << "# @!attribute [rw] #{propname}"
22
-
23
- property_schema = schema['properties'].respond_to?(:to_hash) &&
24
- schema['properties'][propname].respond_to?(:to_hash) &&
25
- schema['properties'][propname]
26
-
27
- required = property_schema && property_schema['required']
28
- required ||= schema['required'].respond_to?(:to_ary) && schema['required'].include?(propname)
29
- lines << "# @required" if required
30
-
31
- type = property_schema &&
32
- property_schema['type'].respond_to?(:to_str) &&
33
- property_schema['type'].to_str
34
- simple = {'string' => 'String', 'number' => 'Numeric', 'boolean' => 'Boolean', 'null' => 'nil'}
35
- rettypes = []
36
- if simple.key?(type)
37
- rettypes << simple[type]
38
- elsif type == 'object' || type == 'array'
39
- rettypes = []
40
- schema_class = JSI.class_for_schema(property_schema)
41
- unless schema_class.name =~ /\AJSI::SchemaClasses::/
42
- rettypes << schema_class.name
43
- end
44
- rettypes << {'object' => '#to_hash', 'array' => '#to_ary'}[type]
45
- elsif type
46
- # not really valid, but there's some information in there. whatever it is.
47
- rettypes << type
48
- end
49
- # we'll add Object to all because the accessor methods have no enforcement that their value is
50
- # of the specified type, and may return anything really. TODO: consider if this is of any value?
51
- rettypes << 'Object'
52
- lines << "# @return [#{rettypes.join(', ')}]"
53
-
54
- description = property_schema &&
55
- property_schema['description'].respond_to?(:to_str) &&
56
- property_schema['description'].to_str
57
- if description
58
- description.split("\n", -1).each do |descline|
59
- lines << "# " + descline
60
- end
61
- end
62
- end
63
- lines.join("\n")
64
- end
65
-
66
- def to_rb
67
- lines = []
68
- description = schema &&
69
- schema['description'].respond_to?(:to_str) &&
70
- schema['description'].to_str
71
- if description
72
- description.split("\n", -1).each do |descline|
73
- lines << "# " + descline
74
- end
75
- end
76
- lines << "class #{name}"
77
- schema.described_object_property_names.each_with_index do |propname, i|
78
- lines << "" unless i == 0
79
- property_schema = schema['properties'].respond_to?(:to_hash) &&
80
- schema['properties'][propname].respond_to?(:to_hash) &&
81
- schema['properties'][propname]
82
- description = property_schema &&
83
- property_schema['description'].respond_to?(:to_str) &&
84
- property_schema['description'].to_str
85
- if description
86
- description.split("\n", -1).each do |descline|
87
- lines << " # " + descline
88
- end
89
- lines << " #" # blank comment line between description and @return
90
- end
91
-
92
- required = property_schema && property_schema['required']
93
- required ||= schema['required'].respond_to?(:to_ary) && schema['required'].include?(propname)
94
- lines << " # @required" if required
95
-
96
- type = property_schema &&
97
- property_schema['type'].respond_to?(:to_str) &&
98
- property_schema['type'].to_str
99
- simple = {'string' => 'String', 'number' => 'Numeric', 'boolean' => 'Boolean', 'null' => 'nil'}
100
- rettypes = []
101
- if simple.key?(type)
102
- rettypes << simple[type]
103
- elsif type == 'object' || type == 'array'
104
- rettypes = []
105
- schema_class = JSI.class_for_schema(property_schema)
106
- unless schema_class.name =~ /\AJSI::SchemaClasses::/
107
- rettypes << schema_class.name
108
- end
109
- rettypes << {'object' => '#to_hash', 'array' => '#to_ary'}[type]
110
- elsif type
111
- # not really valid, but there's some information in there. whatever it is.
112
- rettypes << type
113
- end
114
- # we'll add Object to all because the accessor methods have no enforcement that their value is
115
- # of the specified type, and may return anything really. TODO: consider if this is of any value?
116
- rettypes << 'Object'
117
- lines << " # @return [#{rettypes.join(', ')}]"
118
-
119
- lines << " def #{propname}"
120
- lines << " super"
121
- lines << " end"
122
- end
123
- lines << "end"
124
- lines.join("\n")
125
- end
126
- end
127
- end
128
- end
data/lib/jsi/json/node.rb DELETED
@@ -1,203 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JSI
4
- module JSON
5
- # JSI::JSON::Node is an abstraction of a node within a JSON document.
6
- # it aims to act like the underlying data type of the node's content
7
- # (generally Hash or Array-like) in most cases.
8
- #
9
- # the main advantage offered by using a Node over the underlying data
10
- # is in dereferencing. if a Node consists of a hash with a $ref property
11
- # pointing within the same document, then the Node will transparently
12
- # follow the ref and return the referenced data.
13
- #
14
- # in most other respects, a Node aims to act like a Hash when the content
15
- # is Hash-like, an Array when the content is Array-like. methods of Hash
16
- # and Array are defined and delegated to the node's content.
17
- #
18
- # however, destructive methods are for the most part not implemented.
19
- # at the moment only #[]= is implemented. since Node thinly wraps the
20
- # underlying data, you can change the data and it will be reflected in
21
- # the node. implementations of destructive methods are planned.
22
- #
23
- # methods that return a modified copy such as #merge are defined, and
24
- # return a copy of the document with the content of the node modified.
25
- # the original node's document and content are untouched.
26
- class Node
27
- include Enumerable
28
- include PathedNode
29
-
30
- def self.new_doc(node_document)
31
- new_by_type(node_document, JSI::JSON::Pointer.new([]))
32
- end
33
-
34
- # if the content of the document at the given pointer is Hash-like, returns
35
- # a HashNode; if Array-like, returns ArrayNode. otherwise returns a
36
- # regular Node, although Nodes are for the most part instantiated from
37
- # Hash or Array-like content.
38
- def self.new_by_type(node_document, node_ptr)
39
- content = node_ptr.evaluate(node_document)
40
- if content.respond_to?(:to_hash)
41
- HashNode.new(node_document, node_ptr)
42
- elsif content.respond_to?(:to_ary)
43
- ArrayNode.new(node_document, node_ptr)
44
- else
45
- Node.new(node_document, node_ptr)
46
- end
47
- end
48
-
49
- # a Node represents the content of a document at a given pointer.
50
- def initialize(node_document, node_ptr)
51
- unless node_ptr.is_a?(JSI::JSON::Pointer)
52
- raise(TypeError, "node_ptr must be a JSI::JSON::Pointer. got: #{node_ptr.pretty_inspect.chomp} (#{node_ptr.class})")
53
- end
54
- if node_document.is_a?(JSI::JSON::Node)
55
- raise(TypeError, "node_document of a Node should not be another JSI::JSON::Node: #{node_document.inspect}")
56
- end
57
- @node_document = node_document
58
- @node_ptr = node_ptr
59
- end
60
-
61
- # the document containing this Node at our pointer
62
- attr_reader :node_document
63
-
64
- # JSI::JSON::Pointer pointing to this node within its document
65
- attr_reader :node_ptr
66
-
67
- # returns content at the given subscript - call this the subcontent.
68
- #
69
- # if the content cannot be subscripted, raises TypeError.
70
- #
71
- # if the subcontent is Hash-like, it is wrapped as a JSI::JSON::HashNode before being returned.
72
- # if the subcontent is Array-like, it is wrapped as a JSI::JSON::ArrayNode before being returned.
73
- #
74
- # if this node's content is a $ref - that is, a hash with a $ref attribute - and the subscript is
75
- # not a key of the hash, then the $ref is followed before returning the subcontent.
76
- def [](subscript)
77
- ptr = self.node_ptr
78
- content = self.node_content
79
- unless content.respond_to?(:[])
80
- if content.respond_to?(:to_hash)
81
- content = content.to_hash
82
- elsif content.respond_to?(:to_ary)
83
- content = content.to_ary
84
- else
85
- raise(NoMethodError, "undefined method `[]`\nsubscripting with #{subscript.pretty_inspect.chomp} (#{subscript.class}) from #{content.class.inspect}. content is: #{content.pretty_inspect.chomp}")
86
- end
87
- end
88
- begin
89
- subcontent = content[subscript]
90
- rescue TypeError => e
91
- raise(e.class, e.message + "\nsubscripting with #{subscript.pretty_inspect.chomp} (#{subscript.class}) from #{content.class.inspect}. content is: #{content.pretty_inspect.chomp}", e.backtrace)
92
- end
93
- if subcontent.respond_to?(:to_hash)
94
- HashNode.new(node_document, ptr[subscript])
95
- elsif subcontent.respond_to?(:to_ary)
96
- ArrayNode.new(node_document, ptr[subscript])
97
- else
98
- subcontent
99
- end
100
- end
101
-
102
- # assigns the given subscript of the content to the given value. the document is modified in place.
103
- def []=(subscript, value)
104
- if value.is_a?(Node)
105
- node_content[subscript] = value.node_content
106
- else
107
- node_content[subscript] = value
108
- end
109
- end
110
-
111
- # returns a Node, dereferencing a $ref attribute if possible. if this node is not hash-like,
112
- # does not have a $ref, or if what its $ref cannot be found, this node is returned.
113
- #
114
- # currently only $refs pointing within the same document are followed.
115
- #
116
- # @yield [Node] if a block is given (optional), this will yield a deref'd node. if this
117
- # node is not a $ref object, the block is not called. if we are a $ref which cannot be followed
118
- # (e.g. a $ref to an external document, which is not yet supported), the block is not called.
119
- # @return [JSI::JSON::Node] dereferenced node, or this node
120
- def deref(&block)
121
- node_ptr_deref do |deref_ptr|
122
- return Node.new_by_type(node_document, deref_ptr).tap(&(block || Util::NOOP))
123
- end
124
- return self
125
- end
126
-
127
- # a Node at the root of the document
128
- def document_root_node
129
- Node.new_doc(node_document)
130
- end
131
-
132
- # the parent of this node. if this node is the document root, raises
133
- # JSI::JSON::Pointer::ReferenceError.
134
- def parent_node
135
- Node.new_by_type(node_document, node_ptr.parent)
136
- end
137
-
138
- # returns a jsonifiable representation of this node's content
139
- def as_json(*opt)
140
- Typelike.as_json(node_content, *opt)
141
- end
142
-
143
- # takes a block. the block is yielded the content of this node. the block MUST return a modified
144
- # copy of that content (and NOT modify the object it is given).
145
- def modified_copy(&block)
146
- Node.new_by_type(node_ptr.modified_document_copy(node_document, &block), node_ptr)
147
- end
148
-
149
- def dup
150
- modified_copy(&:dup)
151
- end
152
-
153
- # meta-information about the object, outside the content. used by #inspect / #pretty_print
154
- # @return [Array<String>]
155
- def object_group_text
156
- [
157
- self.class.inspect,
158
- node_ptr.uri.to_s,
159
- ] + (node_content.respond_to?(:object_group_text) ? node_content.object_group_text : [])
160
- end
161
-
162
- # a string representing this node
163
- def inspect
164
- "\#<#{object_group_text.join(' ')} #{node_content.inspect}>"
165
- end
166
-
167
- # pretty-prints a representation this node to the given printer
168
- def pretty_print(q)
169
- q.text '#<'
170
- q.text object_group_text.join(' ')
171
- q.group_sub {
172
- q.nest(2) {
173
- q.breakable ' '
174
- q.pp node_content
175
- }
176
- }
177
- q.breakable ''
178
- q.text '>'
179
- end
180
-
181
- # fingerprint for equality (see FingerprintHash). two nodes are equal if they are both nodes
182
- # (regardless of type, e.g. one may be a Node and the other may be a HashNode) within equal
183
- # documents at equal pointers. note that this means two nodes with the same content may not be
184
- # considered equal.
185
- def jsi_fingerprint
186
- {class: JSI::JSON::Node, node_document: node_document, node_ptr: node_ptr}
187
- end
188
- include Util::FingerprintHash
189
- end
190
-
191
- # a JSI::JSON::Node whose content is Array-like (responds to #to_ary)
192
- # and includes Array methods from Arraylike
193
- class ArrayNode < Node
194
- include PathedArrayNode
195
- end
196
-
197
- # a JSI::JSON::Node whose content is Hash-like (responds to #to_hash)
198
- # and includes Hash methods from Hashlike
199
- class HashNode < Node
200
- include PathedHashNode
201
- end
202
- end
203
- end