jsi 0.0.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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