katachi 0.0.1.3 → 0.0.2.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.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/Rakefile +9 -1
- data/cspell.config.yaml +2 -0
- data/docs/HASH_COMPARISON_DESIGN.md +3 -3
- data/lib/katachi/comparator.rb +5 -0
- data/lib/katachi/comparison_result.rb +2 -1
- data/lib/katachi/minitest.rb +21 -0
- data/lib/katachi/predefined_shapes.rb +2 -0
- data/lib/katachi/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb4f96db6d56228c268dd8c0a247528714414d1ebe4d60e0f7cb377b00323a61
|
4
|
+
data.tar.gz: 1112a9919b574b8c8755e44bcfb711d2f08dbc9d2f67ef2e5343554f5400fb4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99587618b46fcb57fd8ebe9c383e447cb0e56ce81758c508b7979ee16828f086f43fc15534f806662d0b5e0268b1a5c1e5f937b841e866d40513d75033bc2573
|
7
|
+
data.tar.gz: 1976286dc99e9c797e6f9bc5bf1533823a66a1c460f02c7f5705f256b6a862aa2c165f2924f77691449dc3874eba713b42b064385c1a6872f70f5af6ae8d8377
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|

|
2
|
+
[](https://coveralls.io/github/jtannas/katachi?branch=main)
|
2
3
|
|
3
4
|
# Katachi
|
4
5
|
|
@@ -241,6 +242,21 @@ expect('abc').to have_shape(String)
|
|
241
242
|
expect('abc').to have_shape('abc').with_code(:exact_match)
|
242
243
|
```
|
243
244
|
|
245
|
+
### Minitest Integration
|
246
|
+
|
247
|
+
We provide both custom assertions and expectations for Minitest.
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
require 'katachi/minitest'
|
251
|
+
|
252
|
+
shape = [1, 2, 3]
|
253
|
+
assert_shape(shape, [1, 2, 3])
|
254
|
+
refute_shape(shape, [1, 2, 4])
|
255
|
+
|
256
|
+
_([1, 2, 3]).must_match_shape(shape)
|
257
|
+
_([1, 2, 4]).wont_match_shape(shape)
|
258
|
+
```
|
259
|
+
|
244
260
|
### Detailed Diagnostics
|
245
261
|
|
246
262
|
All comparisons return a `Katachi::Result` object that contains detailed information about the comparison.
|
@@ -275,13 +291,11 @@ RESULT
|
|
275
291
|
- [ ] Docusaurus github pages for documentation
|
276
292
|
- [ ] More output formats (e.g. `to_json`, `to_hash`, etc...)
|
277
293
|
- [ ] Custom shape codes (e.g. `:email_is_invalid`)
|
278
|
-
- [ ] Minitest integration
|
279
294
|
- [ ] Rails integration (e.g. `validates_shape_of`)
|
280
295
|
- [ ] Shape-to-TypeScript conversion
|
281
296
|
- [ ] Shape-to-Zod conversion
|
282
297
|
- [ ] Shape-to-OpenAPI conversion
|
283
|
-
- [ ]
|
284
|
-
- [ ] `katachi-rspec-api` for testing+documenting APIs in a way inspired [RSwag](https://github.com/rswag/rswag)
|
298
|
+
- [ ] `katachi-rspec-api` for testing+documenting APIs in a way inspired by [RSwag](https://github.com/rswag/rswag)
|
285
299
|
|
286
300
|
## Installation
|
287
301
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
4
5
|
require "rspec/core/rake_task"
|
5
6
|
|
6
7
|
RSpec::Core::RakeTask.new(:spec)
|
@@ -9,7 +10,7 @@ require "rubocop/rake_task"
|
|
9
10
|
|
10
11
|
RuboCop::RakeTask.new
|
11
12
|
|
12
|
-
task default: %i[spec rubocop]
|
13
|
+
task default: %i[test spec rubocop]
|
13
14
|
|
14
15
|
desc "Opens a console with Katachi loaded for easier experimentation"
|
15
16
|
task :console do
|
@@ -24,3 +25,10 @@ desc "All the steps necessary to get the project ready for development"
|
|
24
25
|
task :setup do
|
25
26
|
system "bundle install"
|
26
27
|
end
|
28
|
+
|
29
|
+
desc "Test the minitest integration"
|
30
|
+
Rake::TestTask.new do |t|
|
31
|
+
t.libs << "test"
|
32
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
33
|
+
t.verbose = true
|
34
|
+
end
|
data/cspell.config.yaml
CHANGED
@@ -12,7 +12,7 @@ Here's the story of how they led to the design of Katachi's hash comparison:
|
|
12
12
|
OpenAPI has handled `null` values a few different ways over the years.
|
13
13
|
|
14
14
|
- OpenAPI 2.0 (Swagger) didn't support `null` values at all, so people used `x-nullable: true`
|
15
|
-
- OpenAPI 3.0
|
15
|
+
- OpenAPI 3.0 made this official by supporting `nullable: true`
|
16
16
|
- OpenAPI 3.1 found a much simpler way by treating `null` as a type: `type: ["string", "null"]`
|
17
17
|
|
18
18
|
I like the 3.1 approach of treating `null` as just another possible type.
|
@@ -140,7 +140,7 @@ Another problem with using `Object => Object` for extra keys is that it's means
|
|
140
140
|
|
141
141
|
If the comparison threw a `:hash_mismatch` when the user's hash didn't literally have a key-value pair `Object => Object`, that'd ruin that whole feature.
|
142
142
|
|
143
|
-
The lazy solution was to just ignore `Object => Object`, but what if users
|
143
|
+
The lazy solution was to just ignore `Object => Object`, but what if users want to be a bit stricter about their extra keys?
|
144
144
|
|
145
145
|
- `Symbol => String` is a normal data structure to enforce.
|
146
146
|
- `:$email => User` is an excellent description for a lookup hash.
|
@@ -231,7 +231,7 @@ But it makes for an awesome user experience :)
|
|
231
231
|
|
232
232
|
```ruby
|
233
233
|
shape = {
|
234
|
-
:$
|
234
|
+
:$uuid => {
|
235
235
|
email: :$email,
|
236
236
|
first_name: String,
|
237
237
|
last_name: String,
|
data/lib/katachi/comparator.rb
CHANGED
@@ -18,6 +18,7 @@ module Katachi::Comparator
|
|
18
18
|
retrieved_shape = Katachi::Shapes[shape]
|
19
19
|
return retrieved_shape.kt_compare(value) if retrieved_shape.respond_to?(:kt_compare)
|
20
20
|
return compare_equalities(value:, shape: retrieved_shape) if retrieved_shape.is_a?(Proc)
|
21
|
+
return object_class_universal_match(value:) if retrieved_shape == Object
|
21
22
|
|
22
23
|
case value
|
23
24
|
when Array then compare_array(value:, shape: retrieved_shape)
|
@@ -40,4 +41,8 @@ module Katachi::Comparator
|
|
40
41
|
end
|
41
42
|
Katachi::ComparisonResult.new(value:, shape:, code:)
|
42
43
|
end
|
44
|
+
|
45
|
+
private_class_method def self.object_class_universal_match(value:)
|
46
|
+
Katachi::ComparisonResult.new(value:, shape: Object, code: :object_class_universal_match)
|
47
|
+
end
|
43
48
|
end
|
@@ -9,10 +9,11 @@ class Katachi::ComparisonResult
|
|
9
9
|
# For example, :match is considered a match, while :mismatch is not.
|
10
10
|
CODES = {
|
11
11
|
# General
|
12
|
+
class_mismatch: false,
|
12
13
|
exact_match: true,
|
13
14
|
match: true,
|
14
15
|
mismatch: false,
|
15
|
-
|
16
|
+
object_class_universal_match: true,
|
16
17
|
# AnyOf
|
17
18
|
any_of_match: true,
|
18
19
|
any_of_mismatch: false,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest/assertions"
|
4
|
+
require "katachi"
|
5
|
+
|
6
|
+
# Minitest assertions for shape matching
|
7
|
+
module Minitest::Assertions
|
8
|
+
def assert_shape(expected, actual)
|
9
|
+
assert Katachi.compare(shape: expected, value: actual).match?, "Expected #{actual} to match #{expected}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def refute_shape(expected, actual)
|
13
|
+
refute Katachi.compare(shape: expected, value: actual).match?, "Expected #{actual} not to match #{expected}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Minitest expectations for shape matching
|
18
|
+
module Minitest::Expectations
|
19
|
+
infect_an_assertion :assert_shape, :must_match_shape
|
20
|
+
infect_an_assertion :refute_shape, :wont_match_shape
|
21
|
+
end
|
data/lib/katachi/version.rb
CHANGED
metadata
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: katachi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Tannas
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-19 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: |
|
13
13
|
== Description
|
14
14
|
|
15
15
|
A tool for describing and validating objects as intuitively as possible.
|
16
16
|
Easier to read and write than JSON Schema, and more powerful than a simple hash comparison.
|
17
|
+
|
17
18
|
Example usage:
|
18
19
|
|
19
20
|
shape = {
|
20
|
-
:$
|
21
|
+
:$uuid => {
|
21
22
|
email: :$email,
|
22
23
|
first_name: String,
|
23
24
|
last_name: String,
|
@@ -54,6 +55,7 @@ files:
|
|
54
55
|
- lib/katachi/comparator/compare_hash.rb
|
55
56
|
- lib/katachi/comparator/compare_kv.rb
|
56
57
|
- lib/katachi/comparison_result.rb
|
58
|
+
- lib/katachi/minitest.rb
|
57
59
|
- lib/katachi/predefined_shapes.rb
|
58
60
|
- lib/katachi/rspec.rb
|
59
61
|
- lib/katachi/shapes.rb
|