rusty_json_schema 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Cargo.toml +1 -0
- data/README.md +25 -4
- data/lib/ext/json_schema.dll +0 -0
- data/lib/ext/json_schema.dll.exp +0 -0
- data/lib/ext/json_schema.dll.lib +0 -0
- data/lib/ext/json_schema.pdb +0 -0
- data/lib/ext/libjson_schema.dylib +0 -0
- data/lib/ext/libjson_schema.so +0 -0
- data/lib/rusty_json_schema.rb +25 -38
- data/lib/rusty_json_schema/binding.rb +28 -0
- data/lib/rusty_json_schema/nodes_array.rb +26 -0
- data/lib/rusty_json_schema/validator.rb +30 -0
- data/lib/rusty_json_schema/version.rb +1 -1
- data/rusty_json_schema.gemspec +1 -0
- data/src/lib.rs +164 -14
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd6b9fde168fe809a7285e76360ae1a87c55c3e0603d4e4901b76f1b4c101674
|
4
|
+
data.tar.gz: '08b4831a5dff32132d473d17470fc992c4b6a453472366eca4f7b511b84fea2a'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b45b35d8d14862cf402215993c2075885ad014a2c80a41394bf9959495a4ecb5993d17bb31d479260f83746325e6c1b3527dfaa630af8967a884f4413ef9f5f
|
7
|
+
data.tar.gz: a70e61c95d6f55d66da0848fa4edc0a78dad1fa08da140eca8c2f0af8d0365f51eff7f8ee7dfdb855ffe6de1488b0c1499b0bddf3a357a9e34e89a0c4b414404
|
data/Cargo.toml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# RustyJSONSchema
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/rusty_json_schema.svg)](https://badge.fury.io/rb/rusty_json_schema)
|
4
|
+
|
5
|
+
FFI wrapper around [`jsonschema`](https://github.com/Stranger6667/jsonschema-rs) Rust library. Props go to original project.
|
4
6
|
|
5
7
|
Currently during heavy development.
|
6
8
|
|
@@ -14,11 +16,15 @@ gem "rusty_json_schema"
|
|
14
16
|
|
15
17
|
And then execute:
|
16
18
|
|
17
|
-
|
19
|
+
```
|
20
|
+
$ bundle install
|
21
|
+
```
|
18
22
|
|
19
23
|
Or install it yourself as:
|
20
24
|
|
21
|
-
|
25
|
+
```
|
26
|
+
$ gem install rusty_json_schema
|
27
|
+
```
|
22
28
|
|
23
29
|
## Usage
|
24
30
|
|
@@ -32,13 +38,28 @@ Validate events like
|
|
32
38
|
|
33
39
|
```ruby
|
34
40
|
validator.valid?(event_json)
|
41
|
+
# => true/false
|
42
|
+
```
|
43
|
+
|
44
|
+
To get validation errors
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
validator.validate(event_json)
|
48
|
+
# => ["invalid...", ...]
|
35
49
|
```
|
36
50
|
|
37
51
|
## Development
|
38
52
|
|
39
53
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
40
54
|
|
41
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
55
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
56
|
+
|
57
|
+
To release a new version:
|
58
|
+
|
59
|
+
- update version number in `version.rb` & `CHANGELOG.md`
|
60
|
+
- create GitHub release with tag being new version prefixed with `v`, i.e. for `VERSION="0.1.0"` it would be `v0.1.0`
|
61
|
+
- pull `*.gem` artifact from release build
|
62
|
+
- `gem push *.gem` in order to publish it in [rubygems.org](https://rubygems.org).
|
42
63
|
|
43
64
|
## Contributing
|
44
65
|
|
data/lib/ext/json_schema.dll
CHANGED
Binary file
|
data/lib/ext/json_schema.dll.exp
CHANGED
Binary file
|
data/lib/ext/json_schema.dll.lib
CHANGED
Binary file
|
data/lib/ext/json_schema.pdb
CHANGED
Binary file
|
Binary file
|
data/lib/ext/libjson_schema.so
CHANGED
Binary file
|
data/lib/rusty_json_schema.rb
CHANGED
@@ -1,62 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "ffi"
|
4
|
+
require "json"
|
4
5
|
|
5
|
-
|
6
|
+
require "rusty_json_schema/version"
|
7
|
+
require "rusty_json_schema/nodes_array"
|
8
|
+
require "rusty_json_schema/validator"
|
9
|
+
require "rusty_json_schema/binding"
|
6
10
|
|
7
11
|
# JSON Schema validation
|
8
12
|
#
|
9
13
|
# ## Example
|
10
14
|
#
|
11
|
-
# validator = RustyJSONSchema.build(schema)
|
12
|
-
#
|
15
|
+
# validator = RustyJSONSchema.build(schema)
|
16
|
+
#
|
17
|
+
# validator.valid?(event)
|
13
18
|
# # => true/false
|
14
19
|
#
|
20
|
+
# validator.validate(event)
|
21
|
+
# # => [] / ["...error messages", ...]
|
22
|
+
#
|
15
23
|
module RustyJSONSchema
|
16
24
|
|
17
|
-
def self.build(schema)
|
18
|
-
RustyJSONSchema::Validator::Binding.new(schema)
|
19
|
-
end
|
20
|
-
|
21
25
|
class Error < StandardError; end
|
22
26
|
|
23
|
-
|
24
|
-
# with Ruby GC. This way we can intialize validator
|
25
|
-
# in Rust, and hold a reference in Ruby.
|
26
|
-
#
|
27
|
-
class Validator < FFI::AutoPointer
|
27
|
+
class << self
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
Binding.free(pointer)
|
29
|
+
attr_writer :processor
|
30
|
+
|
31
|
+
def processor
|
32
|
+
@processor ||= JSON
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
def dump(data)
|
36
|
+
case data
|
37
|
+
when String then data
|
38
|
+
else processor.dump(data)
|
39
|
+
end
|
40
40
|
end
|
41
41
|
|
42
|
-
#
|
42
|
+
# Helper method that returns new instance of pointer
|
43
|
+
# to Validator struct.
|
43
44
|
#
|
44
|
-
|
45
|
-
|
46
|
-
extend FFI::Library
|
47
|
-
|
48
|
-
lib_name =
|
49
|
-
case ::FFI::Platform::LIBSUFFIX
|
50
|
-
when "so", "dylib" then "libjson_schema"
|
51
|
-
when "dll" then "json_schema"
|
52
|
-
end
|
53
|
-
|
54
|
-
ffi_lib File.expand_path("ext/#{lib_name}.#{::FFI::Platform::LIBSUFFIX}", __dir__)
|
55
|
-
|
56
|
-
attach_function :new, :validator_new, [:string], Validator
|
57
|
-
attach_function :free, :validator_free, [Validator], :void
|
58
|
-
attach_function :is_valid, :validator_is_valid, [Validator, :string], :bool
|
59
|
-
|
45
|
+
def build(schema)
|
46
|
+
RustyJSONSchema::Binding.new(dump(schema))
|
60
47
|
end
|
61
48
|
|
62
49
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RustyJSONSchema
|
4
|
+
|
5
|
+
# Integration point between Rust jsonschema wrapper
|
6
|
+
# and RustyJSONSchema.
|
7
|
+
#
|
8
|
+
module Binding
|
9
|
+
|
10
|
+
extend FFI::Library
|
11
|
+
|
12
|
+
lib_name =
|
13
|
+
case ::FFI::Platform::LIBSUFFIX
|
14
|
+
when "so", "dylib" then "libjson_schema"
|
15
|
+
when "dll" then "json_schema"
|
16
|
+
end
|
17
|
+
|
18
|
+
ffi_lib File.expand_path("../ext/#{lib_name}.#{::FFI::Platform::LIBSUFFIX}", __dir__)
|
19
|
+
|
20
|
+
attach_function :new, :validator_new, [:string], Validator
|
21
|
+
attach_function :free, :validator_free, [Validator], :void
|
22
|
+
attach_function :free_array, :array_free, [NodesArray], :void
|
23
|
+
attach_function :is_valid, :validator_is_valid, [Validator, :string], :bool
|
24
|
+
attach_function :validate, :validator_validate, [Validator, :string], NodesArray.by_ref
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RustyJSONSchema
|
4
|
+
|
5
|
+
# Struct representing list of errors returned from
|
6
|
+
# our wrapper library. Use ManagedStruct in order to
|
7
|
+
# properly release nested strings which would otherwise
|
8
|
+
# leak and pollute the memory.
|
9
|
+
#
|
10
|
+
class NodesArray < FFI::ManagedStruct
|
11
|
+
|
12
|
+
layout :data, :pointer,
|
13
|
+
:len, :uint,
|
14
|
+
:cap, :uint
|
15
|
+
|
16
|
+
def to_a
|
17
|
+
self[:data].get_array_of_string(0, self[:len]).compact
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.release(ptr)
|
21
|
+
Binding.free_array(ptr)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RustyJSONSchema
|
4
|
+
|
5
|
+
# Handles release of the pointer automatically
|
6
|
+
# with Ruby GC. This way we can intialize validator
|
7
|
+
# in Rust, and hold a reference in Ruby.
|
8
|
+
#
|
9
|
+
class Validator < FFI::AutoPointer
|
10
|
+
|
11
|
+
# Custom GC flow for our validator, freeing
|
12
|
+
# the object within Rust
|
13
|
+
#
|
14
|
+
def self.release(pointer)
|
15
|
+
Binding.free(pointer)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Simple validation without actual error messages
|
19
|
+
#
|
20
|
+
def valid?(event)
|
21
|
+
Binding.is_valid(self, RustyJSONSchema.dump(event))
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate(event)
|
25
|
+
Binding.validate(self, RustyJSONSchema.dump(event)).to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/rusty_json_schema.gemspec
CHANGED
data/src/lib.rs
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
extern crate libc;
|
2
|
+
|
1
3
|
use jsonschema::JSONSchema;
|
2
4
|
use serde_json::Value;
|
3
5
|
|
4
|
-
use std::ffi::CStr;
|
5
|
-
use std::os::raw::c_char;
|
6
|
+
use std::ffi::{CStr, CString};
|
7
|
+
use std::os::raw::{c_char, c_uint};
|
6
8
|
|
7
9
|
/*
|
8
10
|
* Our wrapper struct for schema and schema value,
|
@@ -22,7 +24,8 @@ impl Validator {
|
|
22
24
|
*/
|
23
25
|
fn new(schema: Value) -> Validator {
|
24
26
|
let boxed_schema: &'static Value = Box::leak(Box::new(schema));
|
25
|
-
let boxed_compile: &'static JSONSchema<'static> =
|
27
|
+
let boxed_compile: &'static JSONSchema<'static> =
|
28
|
+
Box::leak(Box::new(JSONSchema::compile(boxed_schema).unwrap()));
|
26
29
|
|
27
30
|
Validator {
|
28
31
|
schema: boxed_compile,
|
@@ -33,6 +36,18 @@ impl Validator {
|
|
33
36
|
fn is_valid(&self, event: &Value) -> bool {
|
34
37
|
self.schema.is_valid(event)
|
35
38
|
}
|
39
|
+
|
40
|
+
fn validate(&self, event: &Value) -> Vec<String> {
|
41
|
+
let mut errors: Vec<String> = vec![];
|
42
|
+
|
43
|
+
if let Err(validation_errors) = self.schema.validate(event) {
|
44
|
+
for error in validation_errors {
|
45
|
+
errors.push(error.to_string());
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
errors
|
50
|
+
}
|
36
51
|
}
|
37
52
|
|
38
53
|
impl Drop for Validator {
|
@@ -48,6 +63,36 @@ impl Drop for Validator {
|
|
48
63
|
}
|
49
64
|
}
|
50
65
|
|
66
|
+
#[repr(C)]
|
67
|
+
pub struct Array {
|
68
|
+
data: *mut *mut c_char,
|
69
|
+
len: c_uint,
|
70
|
+
cap: c_uint,
|
71
|
+
}
|
72
|
+
|
73
|
+
impl Array {
|
74
|
+
fn from_vec(from: Vec<String>) -> Self {
|
75
|
+
let mut converted: Vec<*mut c_char> = from
|
76
|
+
.into_iter()
|
77
|
+
.map(|s| CString::new(s).unwrap().into_raw())
|
78
|
+
.collect();
|
79
|
+
|
80
|
+
converted.shrink_to_fit();
|
81
|
+
|
82
|
+
let len = converted.len();
|
83
|
+
let cap = converted.capacity();
|
84
|
+
let result = Array {
|
85
|
+
data: converted.as_mut_ptr(),
|
86
|
+
len: len as c_uint,
|
87
|
+
cap: cap as c_uint,
|
88
|
+
};
|
89
|
+
|
90
|
+
std::mem::forget(converted);
|
91
|
+
|
92
|
+
result
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
51
96
|
fn to_string(ptr: *const c_char) -> &'static CStr {
|
52
97
|
unsafe {
|
53
98
|
assert!(!ptr.is_null());
|
@@ -57,7 +102,7 @@ fn to_string(ptr: *const c_char) -> &'static CStr {
|
|
57
102
|
|
58
103
|
#[no_mangle]
|
59
104
|
pub extern "C" fn validator_new(c_schema: *const c_char) -> *mut Validator {
|
60
|
-
let raw_schema
|
105
|
+
let raw_schema = to_string(c_schema);
|
61
106
|
let schema = serde_json::from_slice(raw_schema.to_bytes()).unwrap();
|
62
107
|
let validator = Validator::new(schema);
|
63
108
|
|
@@ -65,6 +110,7 @@ pub extern "C" fn validator_new(c_schema: *const c_char) -> *mut Validator {
|
|
65
110
|
}
|
66
111
|
|
67
112
|
#[no_mangle]
|
113
|
+
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
68
114
|
pub extern "C" fn validator_free(ptr: *mut Validator) {
|
69
115
|
if ptr.is_null() {
|
70
116
|
return;
|
@@ -76,6 +122,7 @@ pub extern "C" fn validator_free(ptr: *mut Validator) {
|
|
76
122
|
}
|
77
123
|
|
78
124
|
#[no_mangle]
|
125
|
+
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
79
126
|
pub extern "C" fn validator_is_valid(ptr: *const Validator, event: *const c_char) -> bool {
|
80
127
|
let validator = unsafe {
|
81
128
|
assert!(!ptr.is_null());
|
@@ -88,31 +135,134 @@ pub extern "C" fn validator_is_valid(ptr: *const Validator, event: *const c_char
|
|
88
135
|
validator.is_valid(&event)
|
89
136
|
}
|
90
137
|
|
138
|
+
#[no_mangle]
|
139
|
+
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
140
|
+
pub extern "C" fn validator_validate(ptr: *const Validator, event: *const c_char) -> *mut Array {
|
141
|
+
let validator = unsafe {
|
142
|
+
assert!(!ptr.is_null());
|
143
|
+
&*ptr
|
144
|
+
};
|
145
|
+
|
146
|
+
let raw_event = to_string(event);
|
147
|
+
let event: Value = serde_json::from_slice(raw_event.to_bytes()).unwrap();
|
148
|
+
let errors = validator.validate(&event);
|
149
|
+
let result = Array::from_vec(errors);
|
150
|
+
let boxed = Box::new(result);
|
151
|
+
|
152
|
+
Box::into_raw(boxed)
|
153
|
+
}
|
154
|
+
|
155
|
+
#[no_mangle]
|
156
|
+
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
157
|
+
pub extern "C" fn array_free(ptr: *mut Array) {
|
158
|
+
if ptr.is_null() {
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
unsafe {
|
163
|
+
let array = Box::from_raw(ptr);
|
164
|
+
let data = Vec::from_raw_parts(array.data, array.len as usize, array.cap as usize);
|
165
|
+
|
166
|
+
for string in data {
|
167
|
+
let _ = CString::from_raw(string);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
91
172
|
#[cfg(test)]
|
92
173
|
mod tests {
|
93
174
|
// Note this useful idiom: importing names from outer (for mod tests) scope.
|
94
175
|
use super::*;
|
95
176
|
use std::ffi::CString;
|
96
|
-
use std::{thread, time};
|
97
177
|
|
98
178
|
/*
|
99
179
|
* Simple sanity check if everything works together
|
100
180
|
*/
|
101
181
|
#[test]
|
102
182
|
fn test_valid_event() {
|
103
|
-
let
|
104
|
-
|
105
|
-
|
183
|
+
let validator = validator_new(helper_c_schema().as_ptr());
|
184
|
+
|
185
|
+
assert!(validator_is_valid(validator, helper_c_valid().as_ptr()));
|
186
|
+
|
187
|
+
assert!(!validator_is_valid(validator, helper_c_invalid().as_ptr()));
|
188
|
+
|
189
|
+
validator_free(validator);
|
190
|
+
}
|
191
|
+
|
192
|
+
#[test]
|
193
|
+
fn test_validate_event_when_valid() {
|
194
|
+
let validator = validator_new(helper_c_schema().as_ptr());
|
195
|
+
let raw_result = validator_validate(validator, helper_c_valid().as_ptr());
|
196
|
+
let result = unsafe { helper_validate_result_as_vec(raw_result) };
|
197
|
+
|
198
|
+
let expectation: Vec<String> = vec![];
|
199
|
+
|
200
|
+
assert_eq!(result, expectation);
|
106
201
|
|
107
|
-
|
108
|
-
|
109
|
-
|
202
|
+
validator_free(validator);
|
203
|
+
}
|
204
|
+
|
205
|
+
#[test]
|
206
|
+
fn test_validate_event_when_invalid() {
|
207
|
+
let validator = validator_new(helper_c_schema().as_ptr());
|
208
|
+
let raw_result = validator_validate(validator, helper_c_invalid().as_ptr());
|
209
|
+
let result = unsafe { helper_validate_result_as_vec(raw_result) };
|
110
210
|
|
111
|
-
let
|
211
|
+
let expectation: Vec<String> = vec![
|
212
|
+
String::from("\'\"rusty\"\' is not of type \'number\'"),
|
213
|
+
String::from("\'1\' is not of type \'string\'"),
|
214
|
+
String::from("\'baz\' is a required property"),
|
215
|
+
];
|
112
216
|
|
113
|
-
|
114
|
-
assert!(!validator_is_valid(validator, c_invalid_event_ptr));
|
217
|
+
assert_eq!(result, expectation);
|
115
218
|
|
116
219
|
validator_free(validator);
|
117
220
|
}
|
221
|
+
|
222
|
+
/*
|
223
|
+
* Test helpers
|
224
|
+
*/
|
225
|
+
fn helper_c_schema() -> CString {
|
226
|
+
CString::new(
|
227
|
+
r#"{
|
228
|
+
"properties":{
|
229
|
+
"foo": {"type": "string"},
|
230
|
+
"bar": {"type": "number"},
|
231
|
+
"baz": {}
|
232
|
+
},
|
233
|
+
"required": ["baz"]
|
234
|
+
}"#,
|
235
|
+
)
|
236
|
+
.unwrap()
|
237
|
+
}
|
238
|
+
|
239
|
+
fn helper_c_valid() -> CString {
|
240
|
+
CString::new(
|
241
|
+
r#"{
|
242
|
+
"foo": "rusty",
|
243
|
+
"bar": 1,
|
244
|
+
"baz": "rusty"
|
245
|
+
}"#,
|
246
|
+
)
|
247
|
+
.unwrap()
|
248
|
+
}
|
249
|
+
|
250
|
+
fn helper_c_invalid() -> CString {
|
251
|
+
CString::new(
|
252
|
+
r#"{
|
253
|
+
"foo": 1,
|
254
|
+
"bar": "rusty"
|
255
|
+
}"#,
|
256
|
+
)
|
257
|
+
.unwrap()
|
258
|
+
}
|
259
|
+
|
260
|
+
unsafe fn helper_validate_result_as_vec(result: *mut Array) -> Vec<String> {
|
261
|
+
let raw = Box::from_raw(result);
|
262
|
+
|
263
|
+
Vec::from_raw_parts(raw.data, raw.len as usize, raw.cap as usize)
|
264
|
+
.into_iter()
|
265
|
+
.map(|x| CString::from_raw(x).into_string().unwrap())
|
266
|
+
.collect()
|
267
|
+
}
|
118
268
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rusty_json_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leszek Zalewski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
27
41
|
description: |2
|
28
42
|
FFI wrapper around https://github.com/Stranger6667/jsonschema-rs Rust library.
|
29
43
|
|
@@ -45,6 +59,9 @@ files:
|
|
45
59
|
- lib/ext/libjson_schema.dylib
|
46
60
|
- lib/ext/libjson_schema.so
|
47
61
|
- lib/rusty_json_schema.rb
|
62
|
+
- lib/rusty_json_schema/binding.rb
|
63
|
+
- lib/rusty_json_schema/nodes_array.rb
|
64
|
+
- lib/rusty_json_schema/validator.rb
|
48
65
|
- lib/rusty_json_schema/version.rb
|
49
66
|
- rusty_json_schema.gemspec
|
50
67
|
- src/lib.rs
|