rusty_json_schema 0.3.0-x64-mingw32

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ef776b75f005158065c0c6a7d41f89fee9abcb565f71d4268e15ddfd9f8afe67
4
+ data.tar.gz: 529d0e8fd559c0d103c6a451e074d41415cf06807a26990d5a545a29706acccf
5
+ SHA512:
6
+ metadata.gz: fddf71983ca50ca850292390aea7d8cb9f39dfc0ffd9a4b10d122a8d31c2d407b2c1a53a9e6588511c5eecbfb690dd0443099b75cbef37bb13582bbc5e61ff8a
7
+ data.tar.gz: d51b14c7c352ceb284be2bb852f27d88d793f6678683ea827c2088e18e3ca356117c99d2d0e63ecce8915bc2391a1bf5349ecb48b494712b6dc40af17a7c8586
@@ -0,0 +1,14 @@
1
+ [package]
2
+ name = "json_schema"
3
+ version = "0.3.0"
4
+ authors = ["Leszek Zalewski <leszekzalewski@fastmail.fm>"]
5
+ edition = "2018"
6
+
7
+ [lib]
8
+ name = "json_schema"
9
+ crate-type = ["cdylib"]
10
+
11
+ [dependencies]
12
+ libc = "0.2.81"
13
+ jsonschema = "0.4.3"
14
+ serde_json = "1.0"
@@ -0,0 +1,74 @@
1
+ # RustyJSONSchema
2
+
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.
6
+
7
+ Currently during heavy development.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem "rusty_json_schema"
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```
20
+ $ bundle install
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```
26
+ $ gem install rusty_json_schema
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Initialize schema validator
32
+
33
+ ```ruby
34
+ validator = RustyJSONSchema.build(json_schema)
35
+ ```
36
+
37
+ Validate events like
38
+
39
+ ```ruby
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...", ...]
49
+ ```
50
+
51
+ ## Development
52
+
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.
54
+
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).
63
+
64
+ ## Contributing
65
+
66
+ Bug reports and pull requests are welcome on GitHub at https://github.com/driv3r/rusty_json_schema. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/driv3r/rusty_json_schema/blob/master/CODE_OF_CONDUCT.md).
67
+
68
+ ## License
69
+
70
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
71
+
72
+ ## Code of Conduct
73
+
74
+ Everyone interacting in the RustyJSONSchema project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/driv3r/rusty_json_schema/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thermite/tasks"
4
+ require_relative "../lib/tasks/thermite_dir_patch"
5
+
6
+ project_dir = File.dirname(File.dirname(__FILE__))
7
+ thermite = Thermite::Tasks.new(cargo_project_path: project_dir,
8
+ ruby_project_path: project_dir,
9
+ optional_rust_extension: true)
10
+
11
+ namespace :thermite do
12
+ desc "Try to build extension if cargo is available or setup default lib"
13
+ task :build_or_default do
14
+ if thermite.cargo
15
+ profile = ENV.fetch("CARGO_PROFILE", "release")
16
+ thermite.run_cargo_rustc(profile)
17
+
18
+ FileUtils.cp(thermite.config.cargo_target_path(profile, thermite.config.cargo_shared_library),
19
+ thermite.config.ruby_extension_path)
20
+ else
21
+ puts "NOTE: Defaults to pre-build binary => your mileage may vary."
22
+
23
+ FileUtils.mv("#{thermite.config.ruby_extension_path}.default",
24
+ thermite.config.ruby_extension_path)
25
+
26
+ thermite.inform_user_about_cargo
27
+ end
28
+ end
29
+
30
+ desc "Cleanup cargo artifacts"
31
+ task :cargo_clean do
32
+ thermite.run_cargo_if_exists "clean", *thermite.cargo_manifest_path_args
33
+ end
34
+ end
35
+
36
+ task default: %w[thermite:build_or_default thermite:cargo_clean]
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+ require "json"
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"
10
+
11
+ # JSON Schema validation
12
+ #
13
+ # ## Example
14
+ #
15
+ # validator = RustyJSONSchema.build(schema)
16
+ #
17
+ # validator.valid?(event)
18
+ # # => true/false
19
+ #
20
+ # validator.validate(event)
21
+ # # => [] / ["...error messages", ...]
22
+ #
23
+ module RustyJSONSchema
24
+
25
+ class Error < StandardError; end
26
+
27
+ class << self
28
+
29
+ attr_writer :processor
30
+
31
+ def processor
32
+ @processor ||= JSON
33
+ end
34
+
35
+ def dump(data)
36
+ case data
37
+ when String then data
38
+ else processor.dump(data)
39
+ end
40
+ end
41
+
42
+ # Helper method that returns new instance of pointer
43
+ # to Validator struct.
44
+ #
45
+ def build(schema)
46
+ RustyJSONSchema::Binding.new(dump(schema))
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,22 @@
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
+ ffi_lib File.expand_path("../../ext/json_schema.so", __dir__)
13
+
14
+ attach_function :new, :validator_new, [:string], Validator
15
+ attach_function :free, :validator_free, [Validator], :void
16
+ attach_function :free_array, :array_free, [NodesArray], :void
17
+ attach_function :is_valid, :validator_is_valid, [Validator, :string], :bool
18
+ attach_function :validate, :validator_validate, [Validator, :string], NodesArray.by_ref
19
+
20
+ end
21
+
22
+ 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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RustyJSONSchema
4
+
5
+ VERSION = "0.3.0"
6
+
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Update where this option is configurable
4
+ # is not yet released
5
+ module ThermiteDirPatch
6
+
7
+ def ruby_extension_path
8
+ ruby_path("ext", shared_library)
9
+ end
10
+
11
+ end
12
+
13
+ Thermite::Config.prepend(ThermiteDirPatch)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/rusty_json_schema/version"
4
+
5
+ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
6
+ spec.name = "rusty_json_schema"
7
+ spec.version = RustyJSONSchema::VERSION
8
+ spec.authors = ["Leszek Zalewski"]
9
+ spec.email = ["leszekzalewski@fastmail.fm"]
10
+ spec.license = "MIT"
11
+ spec.homepage = "https://github.com/driv3r/rusty_json_schema"
12
+ spec.summary = "FFI wrapper around jsonschema-rs Rust library."
13
+ spec.description = <<-STR
14
+ FFI wrapper around https://github.com/Stranger6667/jsonschema-rs Rust library.
15
+
16
+ Currently during heavy development.
17
+ STR
18
+
19
+ spec.platform = Gem::Platform::CURRENT if ENV.key?("PER_PLATFORM_BUILD")
20
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
21
+
22
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
+ spec.metadata["homepage_uri"] = spec.homepage
24
+ spec.metadata["source_code_uri"] = spec.homepage
25
+ spec.metadata["changelog_uri"] = "https://github.com/driv3r/rusty_json_schema/blob/main/CHANGELOG.md"
26
+
27
+ spec.files = Dir[
28
+ "lib/**/*",
29
+ "src/**/*.rs",
30
+ "rusty_json_schema.gemspec",
31
+ "Cargo.toml",
32
+ "LICENSE",
33
+ "README.md",
34
+ "ext/Rakefile",
35
+ "ext/json_schema.so.default"
36
+ ]
37
+
38
+ spec.require_paths = ["lib"]
39
+
40
+ spec.extensions << "ext/Rakefile"
41
+ spec.add_runtime_dependency "thermite", "~> 0"
42
+
43
+ # Uncomment to register a new dependency of your gem
44
+ spec.add_dependency "ffi", "~> 1.14"
45
+ spec.add_dependency "json", ">= 1.0"
46
+ end
@@ -0,0 +1,268 @@
1
+ extern crate libc;
2
+
3
+ use jsonschema::JSONSchema;
4
+ use serde_json::Value;
5
+
6
+ use std::ffi::{CStr, CString};
7
+ use std::os::raw::{c_char, c_uint};
8
+
9
+ /*
10
+ * Our wrapper struct for schema and schema value,
11
+ * we need to hold onto value in order to not have
12
+ * it freed up, as JSONSchema uses it as reference.
13
+ */
14
+ pub struct Validator {
15
+ schema: &'static JSONSchema<'static>,
16
+ schema_value: &'static Value,
17
+ }
18
+
19
+ impl Validator {
20
+ /*
21
+ * With Box::leak we avoid freeing up of schema
22
+ * and schema value, we free them up separately
23
+ * in the Drop implementation
24
+ */
25
+ fn new(schema: Value) -> Validator {
26
+ let boxed_schema: &'static Value = Box::leak(Box::new(schema));
27
+ let boxed_compile: &'static JSONSchema<'static> =
28
+ Box::leak(Box::new(JSONSchema::compile(boxed_schema).unwrap()));
29
+
30
+ Validator {
31
+ schema: boxed_compile,
32
+ schema_value: boxed_schema,
33
+ }
34
+ }
35
+
36
+ fn is_valid(&self, event: &Value) -> bool {
37
+ self.schema.is_valid(event)
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
+ }
51
+ }
52
+
53
+ impl Drop for Validator {
54
+ /*
55
+ * Free up schema with value by "materializing" them,
56
+ * otherwise they will leak memory.
57
+ */
58
+ fn drop(&mut self) {
59
+ unsafe {
60
+ Box::from_raw(self.schema as *const _ as *mut JSONSchema);
61
+ Box::from_raw(self.schema_value as *const _ as *mut Value);
62
+ }
63
+ }
64
+ }
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
+
96
+ fn to_string(ptr: *const c_char) -> &'static CStr {
97
+ unsafe {
98
+ assert!(!ptr.is_null());
99
+ CStr::from_ptr(ptr)
100
+ }
101
+ }
102
+
103
+ #[no_mangle]
104
+ pub extern "C" fn validator_new(c_schema: *const c_char) -> *mut Validator {
105
+ let raw_schema = to_string(c_schema);
106
+ let schema = serde_json::from_slice(raw_schema.to_bytes()).unwrap();
107
+ let validator = Validator::new(schema);
108
+
109
+ Box::into_raw(Box::new(validator))
110
+ }
111
+
112
+ #[no_mangle]
113
+ #[allow(clippy::not_unsafe_ptr_arg_deref)]
114
+ pub extern "C" fn validator_free(ptr: *mut Validator) {
115
+ if ptr.is_null() {
116
+ return;
117
+ }
118
+
119
+ unsafe {
120
+ Box::from_raw(ptr);
121
+ }
122
+ }
123
+
124
+ #[no_mangle]
125
+ #[allow(clippy::not_unsafe_ptr_arg_deref)]
126
+ pub extern "C" fn validator_is_valid(ptr: *const Validator, event: *const c_char) -> bool {
127
+ let validator = unsafe {
128
+ assert!(!ptr.is_null());
129
+ &*ptr
130
+ };
131
+
132
+ let raw_event = to_string(event);
133
+ let event: Value = serde_json::from_slice(raw_event.to_bytes()).unwrap();
134
+
135
+ validator.is_valid(&event)
136
+ }
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
+
172
+ #[cfg(test)]
173
+ mod tests {
174
+ // Note this useful idiom: importing names from outer (for mod tests) scope.
175
+ use super::*;
176
+ use std::ffi::CString;
177
+
178
+ /*
179
+ * Simple sanity check if everything works together
180
+ */
181
+ #[test]
182
+ fn test_valid_event() {
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);
201
+
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) };
210
+
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
+ ];
216
+
217
+ assert_eq!(result, expectation);
218
+
219
+ validator_free(validator);
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
+ }
268
+ }
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rusty_json_schema
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: x64-mingw32
6
+ authors:
7
+ - Leszek Zalewski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thermite
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ffi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.14'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ description: |2
56
+ FFI wrapper around https://github.com/Stranger6667/jsonschema-rs Rust library.
57
+
58
+ Currently during heavy development.
59
+ email:
60
+ - leszekzalewski@fastmail.fm
61
+ executables: []
62
+ extensions:
63
+ - ext/Rakefile
64
+ extra_rdoc_files: []
65
+ files:
66
+ - Cargo.toml
67
+ - README.md
68
+ - ext/Rakefile
69
+ - ext/json_schema.so.default
70
+ - lib/rusty_json_schema.rb
71
+ - lib/rusty_json_schema/binding.rb
72
+ - lib/rusty_json_schema/nodes_array.rb
73
+ - lib/rusty_json_schema/validator.rb
74
+ - lib/rusty_json_schema/version.rb
75
+ - lib/tasks/thermite_dir_patch.rb
76
+ - rusty_json_schema.gemspec
77
+ - src/lib.rs
78
+ homepage: https://github.com/driv3r/rusty_json_schema
79
+ licenses:
80
+ - MIT
81
+ metadata:
82
+ allowed_push_host: https://rubygems.org
83
+ homepage_uri: https://github.com/driv3r/rusty_json_schema
84
+ source_code_uri: https://github.com/driv3r/rusty_json_schema
85
+ changelog_uri: https://github.com/driv3r/rusty_json_schema/blob/main/CHANGELOG.md
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.5.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.7.3
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: FFI wrapper around jsonschema-rs Rust library.
106
+ test_files: []