jsi 0.0.4 → 0.4.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +3 -1
  3. data/CHANGELOG.md +48 -0
  4. data/LICENSE.md +613 -0
  5. data/README.md +84 -45
  6. data/jsi.gemspec +11 -14
  7. data/lib/jsi.rb +31 -12
  8. data/lib/jsi/base.rb +310 -344
  9. data/lib/jsi/base/to_rb.rb +2 -0
  10. data/lib/jsi/jsi_coder.rb +91 -0
  11. data/lib/jsi/json-schema-fragments.rb +3 -135
  12. data/lib/jsi/json.rb +3 -0
  13. data/lib/jsi/json/node.rb +72 -197
  14. data/lib/jsi/json/pointer.rb +419 -0
  15. data/lib/jsi/metaschema.rb +7 -0
  16. data/lib/jsi/metaschema_node.rb +218 -0
  17. data/lib/jsi/pathed_node.rb +118 -0
  18. data/lib/jsi/schema.rb +168 -223
  19. data/lib/jsi/schema_classes.rb +158 -0
  20. data/lib/jsi/simple_wrap.rb +12 -0
  21. data/lib/jsi/typelike_modules.rb +71 -45
  22. data/lib/jsi/util.rb +47 -57
  23. data/lib/jsi/version.rb +1 -1
  24. data/lib/schemas/json-schema.org/draft-04/schema.rb +7 -0
  25. data/lib/schemas/json-schema.org/draft-06/schema.rb +7 -0
  26. data/resources/icons/AGPL-3.0.png +0 -0
  27. data/test/base_array_test.rb +210 -84
  28. data/test/base_hash_test.rb +201 -58
  29. data/test/base_test.rb +212 -121
  30. data/test/jsi_coder_test.rb +85 -0
  31. data/test/jsi_json_arraynode_test.rb +26 -25
  32. data/test/jsi_json_hashnode_test.rb +40 -39
  33. data/test/jsi_json_node_test.rb +95 -126
  34. data/test/jsi_json_pointer_test.rb +102 -0
  35. data/test/jsi_typelike_as_json_test.rb +53 -0
  36. data/test/metaschema_node_test.rb +19 -0
  37. data/test/schema_module_test.rb +21 -0
  38. data/test/schema_test.rb +109 -97
  39. data/test/spreedly_openapi_test.rb +8 -0
  40. data/test/test_helper.rb +42 -8
  41. data/test/util_test.rb +14 -14
  42. metadata +54 -25
  43. data/LICENSE.txt +0 -21
  44. data/lib/jsi/schema_instance_json_coder.rb +0 -83
  45. data/lib/jsi/struct_json_coder.rb +0 -30
  46. data/test/schema_instance_json_coder_test.rb +0 -121
  47. data/test/struct_json_coder_test.rb +0 -130
@@ -0,0 +1,8 @@
1
+ require_relative 'test_helper'
2
+
3
+ require 'spreedly_openapi'
4
+ describe 'spreedly openapi' do
5
+ it 'instantiates the spreedly openapi doc' do
6
+ SpreedlyOpenAPI::Document.inspect
7
+ end
8
+ end
@@ -2,8 +2,12 @@ require 'coveralls'
2
2
  if Coveralls.will_run?
3
3
  Coveralls.wear!
4
4
  end
5
-
6
5
  require 'simplecov'
6
+
7
+ require 'bundler/setup'
8
+
9
+ require 'byebug'
10
+
7
11
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
8
12
  require 'jsi'
9
13
 
@@ -16,8 +20,6 @@ require 'minitest/reporters'
16
20
 
17
21
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
18
22
 
19
- require 'byebug'
20
-
21
23
  class JSISpec < Minitest::Spec
22
24
  if ENV['JSI_TEST_ALPHA']
23
25
  # :nocov:
@@ -26,9 +28,41 @@ class JSISpec < Minitest::Spec
26
28
  end
27
29
 
28
30
  def assert_equal exp, act, msg = nil
29
- msg = message(msg, E) { diff exp, act }
31
+ msg = message(msg, E) do
32
+ [].tap do |ms|
33
+ ms << diff(exp, act)
34
+ ms << "#{ANSI.red { 'expected' }}: #{exp.inspect}"
35
+ ms << "#{ANSI.green { 'actual' }}: #{act.inspect}"
36
+ if exp.respond_to?(:to_str) && act.respond_to?(:to_str)
37
+ ms << "#{ANSI.red { 'expected (str)' }}:"
38
+ ms << exp
39
+ ms << "#{ANSI.green { 'actual (str)' }}:"
40
+ ms << act
41
+ end
42
+ end.join("\n")
43
+ end
30
44
  assert exp == act, msg
31
45
  end
46
+
47
+ def assert_match matcher, obj, msg = nil
48
+ msg = message(msg) do
49
+ [].tap do |ms|
50
+ ms << "Expected match."
51
+ ms << "#{ANSI.red { 'matcher' }}: #{mu_pp matcher}"
52
+ ms << "#{ANSI.green { 'object' }}: #{mu_pp obj}"
53
+ ms << "#{ANSI.yellow { 'escaped' }}: #{Regexp.new(Regexp.escape(obj)).inspect}" if obj.is_a?(String)
54
+ end.join("\n")
55
+ end
56
+ assert_respond_to matcher, :"=~"
57
+ matcher = Regexp.new Regexp.escape matcher if String === matcher
58
+ assert matcher =~ obj, msg
59
+ end
60
+
61
+ def assert_is_a mod, obj, msg = nil
62
+ msg = message(msg) { "Expected instance of #{mod}. received #{obj.class}: #{mu_pp(obj)}" }
63
+
64
+ assert obj.is_a?(mod), msg
65
+ end
32
66
  end
33
67
 
34
68
  # register this to be the base class for specs instead of Minitest::Spec
@@ -42,8 +76,8 @@ class SortOfHash
42
76
  def to_hash
43
77
  @hash
44
78
  end
45
- include JSI::FingerprintHash
46
- def fingerprint
79
+ include JSI::Util::FingerprintHash
80
+ def jsi_fingerprint
47
81
  {class: self.class, hash: @hash}
48
82
  end
49
83
  end
@@ -56,8 +90,8 @@ class SortOfArray
56
90
  def to_ary
57
91
  @ary
58
92
  end
59
- include JSI::FingerprintHash
60
- def fingerprint
93
+ include JSI::Util::FingerprintHash
94
+ def jsi_fingerprint
61
95
  {class: self.class, ary: @ary}
62
96
  end
63
97
  end
@@ -6,24 +6,24 @@ describe JSI::Util do
6
6
  assert_equal({'a' => 'b', 'c' => 'd', nil => 3}, JSI.stringify_symbol_keys({a: 'b', 'c' => 'd', nil => 3}))
7
7
  end
8
8
  it 'stringifies HashNode keys' do
9
- actual = JSI.stringify_symbol_keys(JSI::JSON::HashNode.new({a: 'b', 'c' => 'd', nil => 3}, []))
10
- expected = JSI::JSON::HashNode.new({'a' => 'b', 'c' => 'd', nil => 3}, [])
9
+ actual = JSI.stringify_symbol_keys(JSI::JSON::Node.new_doc({a: 'b', 'c' => 'd', nil => 3}))
10
+ expected = JSI::JSON::Node.new_doc({'a' => 'b', 'c' => 'd', nil => 3})
11
11
  assert_equal(expected, actual)
12
12
  end
13
13
  it 'stringifies JSI hash keys' do
14
- klass = JSI.class_for_schema(type: 'object')
15
- expected = JSI.stringify_symbol_keys(klass.new(JSI::JSON::HashNode.new({a: 'b', 'c' => 'd', nil => 3}, [])))
16
- actual = klass.new(JSI::JSON::HashNode.new({'a' => 'b', 'c' => 'd', nil => 3}, []))
14
+ schema = JSI::Schema.new({type: 'object'})
15
+ expected = JSI.stringify_symbol_keys(schema.new_jsi({a: 'b', 'c' => 'd', nil => 3}))
16
+ actual = schema.new_jsi({'a' => 'b', 'c' => 'd', nil => 3})
17
17
  assert_equal(expected, actual)
18
18
  end
19
19
  describe 'non-hash-like argument' do
20
20
  it 'errors' do
21
21
  err = assert_raises(ArgumentError) { JSI.stringify_symbol_keys(nil) }
22
22
  assert_equal("expected argument to be a hash; got NilClass: nil", err.message)
23
- err = assert_raises(ArgumentError) { JSI.stringify_symbol_keys(JSI::JSON::Node.new(3, [])) }
24
- assert_equal("expected argument to be a hash; got JSI::JSON::Node: #<JSI::JSON::Node fragment=\"#\" 3>", err.message)
25
- err = assert_raises(ArgumentError) { JSI.stringify_symbol_keys(JSI.class_for_schema({}).new(JSI::JSON::Node.new(3, []))) }
26
- assert_match(%r(\Aexpected argument to be a hash; got JSI::SchemaClasses\["[^"]+#"\]: #<JSI::SchemaClasses\["[^"]+#"\]\n #<JSI::JSON::Node fragment="#" 3>\n>\z)m, err.message)
23
+ err = assert_raises(ArgumentError) { JSI.stringify_symbol_keys(JSI::JSON::Node.new_doc(3)) }
24
+ assert_equal("expected argument to be a hash; got JSI::JSON::Node: #<JSI::JSON::Node # 3>", err.message)
25
+ err = assert_raises(ArgumentError) { JSI.stringify_symbol_keys(JSI::Schema.new({}).new_jsi(3)) }
26
+ assert_equal("expected argument to be a hash; got (JSI Schema Class: #): #<JSI 3>", err.message)
27
27
  end
28
28
  end
29
29
  end
@@ -48,14 +48,14 @@ describe JSI::Util do
48
48
  assert_equal(expected, actual)
49
49
  end
50
50
  it 'deep stringifies HashNode keys' do
51
- actual = JSI.deep_stringify_symbol_keys(JSI::JSON::HashNode.new({a: 'b', 'c' => {d: 0}, nil => 3}, []))
52
- expected = JSI::JSON::HashNode.new({'a' => 'b', 'c' => {'d' => 0}, nil => 3}, [])
51
+ actual = JSI.deep_stringify_symbol_keys(JSI::JSON::Node.new_doc({a: 'b', 'c' => {d: 0}, nil => 3}))
52
+ expected = JSI::JSON::Node.new_doc({'a' => 'b', 'c' => {'d' => 0}, nil => 3})
53
53
  assert_equal(expected, actual)
54
54
  end
55
55
  it 'deep stringifies JSI instance' do
56
- klass = JSI.class_for_schema(type: 'object')
57
- actual = JSI.deep_stringify_symbol_keys(klass.new(JSI::JSON::HashNode.new({a: 'b', 'c' => {d: 0}, nil => 3}, [])))
58
- expected = klass.new(JSI::JSON::HashNode.new({'a' => 'b', 'c' => {'d' => 0}, nil => 3}, []))
56
+ schema = JSI::Schema.new(type: 'object')
57
+ actual = JSI.deep_stringify_symbol_keys(schema.new_jsi(JSI::JSON::Node.new_doc({a: 'b', 'c' => {d: 0}, nil => 3})))
58
+ expected = schema.new_jsi(JSI::JSON::Node.new_doc({'a' => 'b', 'c' => {'d' => 0}, nil => 3}))
59
59
  assert_equal(expected, actual)
60
60
  end
61
61
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-27 00:00:00.000000000 Z
11
+ date: 2020-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema
@@ -28,30 +28,30 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '5.0'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: minitest-around
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,10 +80,24 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: JSI represents json-schemas as ruby classes and json-schema instances
84
- as instances of those classes
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'
97
+ description: JSI offers an Object-Oriented representation for JSON data using JSON
98
+ Schemas
85
99
  email:
86
- - ethan@unth
100
+ - ethan.jsi@unth.net
87
101
  executables: []
88
102
  extensions: []
89
103
  extra_rdoc_files: []
@@ -91,37 +105,49 @@ files:
91
105
  - ".simplecov"
92
106
  - ".yardopts"
93
107
  - CHANGELOG.md
94
- - LICENSE.txt
108
+ - LICENSE.md
95
109
  - README.md
96
110
  - Rakefile.rb
97
111
  - jsi.gemspec
98
112
  - lib/jsi.rb
99
113
  - lib/jsi/base.rb
100
114
  - lib/jsi/base/to_rb.rb
115
+ - lib/jsi/jsi_coder.rb
101
116
  - lib/jsi/json-schema-fragments.rb
102
117
  - lib/jsi/json.rb
103
118
  - lib/jsi/json/node.rb
119
+ - lib/jsi/json/pointer.rb
120
+ - lib/jsi/metaschema.rb
121
+ - lib/jsi/metaschema_node.rb
122
+ - lib/jsi/pathed_node.rb
104
123
  - lib/jsi/schema.rb
105
- - lib/jsi/schema_instance_json_coder.rb
106
- - lib/jsi/struct_json_coder.rb
124
+ - lib/jsi/schema_classes.rb
125
+ - lib/jsi/simple_wrap.rb
107
126
  - lib/jsi/typelike_modules.rb
108
127
  - lib/jsi/util.rb
109
128
  - lib/jsi/version.rb
129
+ - lib/schemas/json-schema.org/draft-04/schema.rb
130
+ - lib/schemas/json-schema.org/draft-06/schema.rb
131
+ - resources/icons/AGPL-3.0.png
110
132
  - test/base_array_test.rb
111
133
  - test/base_hash_test.rb
112
134
  - test/base_test.rb
135
+ - test/jsi_coder_test.rb
113
136
  - test/jsi_json_arraynode_test.rb
114
137
  - test/jsi_json_hashnode_test.rb
115
138
  - test/jsi_json_node_test.rb
139
+ - test/jsi_json_pointer_test.rb
116
140
  - test/jsi_test.rb
117
- - test/schema_instance_json_coder_test.rb
141
+ - test/jsi_typelike_as_json_test.rb
142
+ - test/metaschema_node_test.rb
143
+ - test/schema_module_test.rb
118
144
  - test/schema_test.rb
119
- - test/struct_json_coder_test.rb
145
+ - test/spreedly_openapi_test.rb
120
146
  - test/test_helper.rb
121
147
  - test/util_test.rb
122
148
  homepage: https://github.com/notEthan/jsi
123
149
  licenses:
124
- - MIT
150
+ - AGPL-3.0
125
151
  metadata: {}
126
152
  post_install_message:
127
153
  rdoc_options: []
@@ -138,21 +164,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
164
  - !ruby/object:Gem::Version
139
165
  version: '0'
140
166
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.7.8
167
+ rubygems_version: 3.0.6
143
168
  signing_key:
144
169
  specification_version: 4
145
- summary: 'JSI: JSON-Schema instantiation'
170
+ summary: 'JSI: JSON Schema Instantiation'
146
171
  test_files:
147
172
  - test/base_array_test.rb
148
173
  - test/base_hash_test.rb
149
174
  - test/base_test.rb
175
+ - test/jsi_coder_test.rb
150
176
  - test/jsi_json_arraynode_test.rb
151
177
  - test/jsi_json_hashnode_test.rb
152
178
  - test/jsi_json_node_test.rb
179
+ - test/jsi_json_pointer_test.rb
153
180
  - test/jsi_test.rb
154
- - test/schema_instance_json_coder_test.rb
181
+ - test/jsi_typelike_as_json_test.rb
182
+ - test/metaschema_node_test.rb
183
+ - test/schema_module_test.rb
155
184
  - test/schema_test.rb
156
- - test/struct_json_coder_test.rb
185
+ - test/spreedly_openapi_test.rb
157
186
  - test/test_helper.rb
158
187
  - test/util_test.rb
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2016 Ethan
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
@@ -1,83 +0,0 @@
1
- module JSI
2
- # this is a ActiveRecord serialization class intended to store JSON in the
3
- # database column and expose a ruby class once loaded on a model instance.
4
- # this allows for better ruby idioms to access to properties, and definition
5
- # of related methods on the loaded class.
6
- #
7
- # the first argument, `loaded_class`, is the class which will be used to
8
- # instantiate the column data. properties of the loaded class will correspond
9
- # to keys of the json object in the database.
10
- #
11
- # the column data may be either a single instance of the loaded class
12
- # (represented as one json object) or an array of them (represented as a json
13
- # array of json objects), indicated by the keyword argument `array`.
14
- #
15
- # the column behind the attribute may be an actual JSON column (postgres json
16
- # or jsonb - hstore should work too if you only have string attributes) or a
17
- # serialized string, indicated by the keyword argument `string`.
18
- class ObjectJSONCoder
19
- class Error < StandardError
20
- end
21
- class LoadError < Error
22
- end
23
- class DumpError < Error
24
- end
25
-
26
- def initialize(loaded_class, string: false, array: false, next_coder: nil)
27
- @loaded_class = loaded_class
28
- # this notes the order of the keys as they were in the json, used by dump_object to generate
29
- # json that is equivalent to the json/jsonifiable that came in, so that AR's #changed_attributes
30
- # can tell whether the attribute has been changed.
31
- @loaded_class.send(:attr_accessor, :object_json_coder_keys_order)
32
- @string = string
33
- @array = array
34
- @next_coder = next_coder
35
- end
36
-
37
- def load(column_data)
38
- return nil if column_data.nil?
39
- data = @string ? ::JSON.parse(column_data) : column_data
40
- object = if @array
41
- unless data.respond_to?(:to_ary)
42
- raise TypeError, "expected array-like column data; got: #{data.class}: #{data.inspect}"
43
- end
44
- data.map { |el| load_object(el) }
45
- else
46
- load_object(data)
47
- end
48
- object = @next_coder.load(object) if @next_coder
49
- object
50
- end
51
-
52
- def dump(object)
53
- object = @next_coder.dump(object) if @next_coder
54
- return nil if object.nil?
55
- jsonifiable = begin
56
- if @array
57
- unless object.respond_to?(:to_ary)
58
- raise DumpError, "expected array-like attribute; got: #{object.class}: #{object.inspect}"
59
- end
60
- object.map do |el|
61
- dump_object(el)
62
- end
63
- else
64
- dump_object(object)
65
- end
66
- end
67
- @string ? ::JSON.generate(jsonifiable) : jsonifiable
68
- end
69
- end
70
- # this is a ActiveRecord serialization class intended to store JSON in the
71
- # database column and expose a given JSI::Base subclass once loaded
72
- # on a model instance.
73
- class SchemaInstanceJSONCoder < ObjectJSONCoder
74
- private
75
- def load_object(data)
76
- @loaded_class.new(data)
77
- end
78
-
79
- def dump_object(object)
80
- JSI::Typelike.as_json(object)
81
- end
82
- end
83
- end
@@ -1,30 +0,0 @@
1
- module JSI
2
- # this is a ActiveRecord serialization class intended to store JSON in the
3
- # database column and expose a Struct subclass once loaded on a model instance.
4
- class StructJSONCoder < ObjectJSONCoder
5
- private
6
- def load_object(data)
7
- if data.is_a?(Hash)
8
- good_keys = @loaded_class.members.map(&:to_s)
9
- bad_keys = data.keys - good_keys
10
- unless bad_keys.empty?
11
- raise LoadError, "expected keys #{good_keys}; got unrecognized keys: #{bad_keys}"
12
- end
13
- instance = @loaded_class.new(*@loaded_class.members.map { |m| data[m.to_s] })
14
- instance.object_json_coder_keys_order = data.keys
15
- instance
16
- else
17
- raise LoadError, "expected instance(s) of #{Hash}; got: #{data.class}: #{data.inspect}"
18
- end
19
- end
20
-
21
- def dump_object(object)
22
- if object.is_a?(@loaded_class)
23
- keys = (object.object_json_coder_keys_order || []) | @loaded_class.members.map(&:to_s)
24
- keys.map { |member| {member => object[member]} }.inject({}, &:update)
25
- else
26
- raise TypeError, "expected instance(s) of #{@loaded_class}; got: #{object.class}: #{object.inspect}"
27
- end
28
- end
29
- end
30
- end