scheming 0.4.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9200950b341609a10673661255198aacf8012bdb89b89868d66eed91aa11c395
4
- data.tar.gz: 175243bb9bd5204b93b5f59f2e0b403163c86ed745a01a23c2e987bc2aab2813
3
+ metadata.gz: c861bcba1706b9ffe842a7d13cb55b047479d57a1c7e44a6e7fa7a934c83819a
4
+ data.tar.gz: 8837b76f3fa1c0c334387432a8c466085a96064482b4ff1dd00bbabc2b69c1ae
5
5
  SHA512:
6
- metadata.gz: 9c83e51b6db0200f0d222250e690696061ecf581bad11e4c5916df828cfef2d6ae01da50349d7a1cdea2097b7a235fe19950c48ec0b11f628522ed734a100e48
7
- data.tar.gz: b35ebaf5d8d1a30b1538471d153a7da1ed648037c84c89ec2132742bad94fcfee0b0d4744b0c82b3f36de924d30a39579e881a812f4d1ba6fc3bff9c46283415
6
+ metadata.gz: c8d822270972cb4abc4837c89fa8084b78132af50acc829e7b610fe74cb5ce6bc517ea579528b489b774daa4aec17dd971704ad7f54c3113589d0fee225b22ed
7
+ data.tar.gz: 3c72a5b224d4d345ee050045d75f72ae74413e1bb78be6f1203795b4ed015f5327ca2e998a05712e086aef4b5d4925818c09c3afb98c5ffb1ac94ba1b6374296
data/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0]
4
+
5
+ ### Added
6
+
7
+ - `Union` type added
8
+
9
+ # Example
10
+ ```ruby
11
+ Order = Scheming.object do
12
+ attribute :id, Union(String, Integer)
13
+ end
14
+
15
+ Scheming::Schema.json(Order)
16
+ # =>
17
+ {
18
+ oneOf: [
19
+ { type: 'string' },
20
+ { type: 'integer' }
21
+ ]
22
+ }
23
+ ```
24
+
25
+ ### Fixed
26
+
27
+ - Incorrect YARD comment tags and syntax.
28
+
29
+ ### Breaking Change
30
+
31
+ - Switch from `json-schema` to `json_schemer`
32
+
33
+ > TL;DR
34
+ required object properties for the JSON schema
35
+ are now strings instead of symbols
36
+
37
+ After doing to research I've found that `json_schemer` is
38
+ more maintained than what was currently being used. It has
39
+ a smaller footprint and is much faster at validation.
40
+
41
+ As a consequence the `required` properties needed to be
42
+ changed from symbols to strings in the generated JSON schema.
43
+
44
+
45
+ ## [0.5.0] - 2024-05-02
46
+
47
+ ### Added
48
+
49
+ - Support for `generic` definitions
50
+
51
+ # Example
52
+ ```ruby
53
+ Point = Scheming.generic do |(type)|
54
+ Object(x: type, y: type)
55
+ end
56
+
57
+ Scheming::Schema.json(Point)
58
+ # =>
59
+ {
60
+ type: 'object',
61
+ additionalProperties: false,
62
+ required: %i[x y],
63
+ properties: {
64
+ x: { type: 'number' },
65
+ y: { type: 'number' }
66
+ }
67
+ }
68
+ ```
69
+
3
70
  ## [0.4.0] - 2024-05-02
4
71
 
5
72
  ### Breaking Change
@@ -35,6 +102,8 @@
35
102
 
36
103
  ### Enhancement
37
104
 
105
+ - Ensure all types produce valid JSON Schema
106
+
38
107
  ## [0.2.0] - 2024-05-01
39
108
 
40
109
  ### Added
@@ -56,8 +125,6 @@
56
125
  end
57
126
  ```
58
127
 
59
- - Ensure all types produce valid JSON Schema
60
-
61
128
  ## [0.1.0] - 2024-04-26
62
129
 
63
130
  - Initial release
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  gem 'factory_bot', '~> 6.4'
9
- gem 'json-schema', '~> 4.3'
9
+ gem 'json_schemer'
10
10
  gem 'pry', '~> 0.14.2'
11
11
  gem 'rake', '~> 13.0'
12
12
  gem 'rspec', '~> 3.0'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scheming (0.4.0)
4
+ scheming (0.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -16,8 +16,6 @@ GEM
16
16
  minitest (>= 5.1)
17
17
  mutex_m
18
18
  tzinfo (~> 2.0)
19
- addressable (2.8.6)
20
- public_suffix (>= 2.0.2, < 6.0)
21
19
  ast (2.4.2)
22
20
  base64 (0.2.0)
23
21
  bigdecimal (3.1.7)
@@ -28,11 +26,16 @@ GEM
28
26
  drb (2.2.1)
29
27
  factory_bot (6.4.6)
30
28
  activesupport (>= 5.0.0)
29
+ hana (1.3.7)
31
30
  i18n (1.14.4)
32
31
  concurrent-ruby (~> 1.0)
33
32
  json (2.7.2)
34
- json-schema (4.3.0)
35
- addressable (>= 2.8)
33
+ json_schemer (2.2.1)
34
+ base64
35
+ bigdecimal
36
+ hana (~> 1.3)
37
+ regexp_parser (~> 2.0)
38
+ simpleidn (~> 0.2)
36
39
  language_server-protocol (3.17.0.3)
37
40
  method_source (1.1.0)
38
41
  minitest (5.22.3)
@@ -44,7 +47,6 @@ GEM
44
47
  pry (0.14.2)
45
48
  coderay (~> 1.1)
46
49
  method_source (~> 1.0)
47
- public_suffix (5.0.5)
48
50
  racc (1.7.3)
49
51
  rainbow (3.1.1)
50
52
  rake (13.2.1)
@@ -77,8 +79,13 @@ GEM
77
79
  rubocop-ast (1.31.2)
78
80
  parser (>= 3.3.0.4)
79
81
  ruby-progressbar (1.13.0)
82
+ simpleidn (0.2.2)
83
+ unf (~> 0.1.4)
80
84
  tzinfo (2.0.6)
81
85
  concurrent-ruby (~> 1.0)
86
+ unf (0.1.4)
87
+ unf_ext
88
+ unf_ext (0.0.9.1)
82
89
  unicode-display_width (2.5.0)
83
90
 
84
91
  PLATFORMS
@@ -86,7 +93,7 @@ PLATFORMS
86
93
 
87
94
  DEPENDENCIES
88
95
  factory_bot (~> 6.4)
89
- json-schema (~> 4.3)
96
+ json_schemer
90
97
  pry (~> 0.14.2)
91
98
  rake (~> 13.0)
92
99
  rspec (~> 3.0)
data/README.md CHANGED
@@ -15,7 +15,7 @@ gem 'scheming'
15
15
  Definition:
16
16
  ```ruby
17
17
  LineItem = Scheming.object do
18
- attribute :id, Integer
18
+ attribute :id, Union(Integer, String)
19
19
  attribute :name, String
20
20
  attribute :taxable, :bool
21
21
  attribute :price, Float
@@ -27,9 +27,14 @@ LineItem = Scheming.object do
27
27
  attribute :item_type, Enum('entertainment', 'staple')
28
28
  end
29
29
 
30
+ Point = Scheming.generic do |(type)|
31
+ Object(x: type, y: type)
32
+ end
33
+
30
34
  Receipt = Scheming.object do
31
35
  attribute :line_items, Array(LineItem)
32
36
  attribute :total, Float
37
+ attribute :location, Point[Float]
33
38
  end
34
39
  ```
35
40
 
@@ -40,16 +45,21 @@ Scheming::Schema.json(Receipt)
40
45
  {
41
46
  type: 'object',
42
47
  additionalProperties: false,
43
- required: %i[line_items total],
48
+ required: %w[line_items total location],
44
49
  properties: {
45
50
  line_items: {
46
51
  type: 'array',
47
52
  items: {
48
53
  type: 'object',
49
54
  additionalProperties: false,
50
- required: %i[id name taxable price],
55
+ required: %w[id name taxable price],
51
56
  properties: {
52
- id: { type: 'integer' },
57
+ id: {
58
+ oneOf: [
59
+ { type: 'integer' },
60
+ { type: 'string' }
61
+ ]
62
+ },
53
63
  name: { type: 'string' },
54
64
  taxable: { type: 'boolean' },
55
65
  desc: {
@@ -61,12 +71,21 @@ Scheming::Schema.json(Receipt)
61
71
  price: { type: 'number' },
62
72
  item_type: {
63
73
  type: 'string',
64
- enum: ['intertainment', 'staple']
74
+ enum: %w[entertainment staple]
65
75
  }
66
76
  }
67
77
  }
68
78
  },
69
- total: { type: 'number' }
79
+ total: { type: 'number' },
80
+ location: {
81
+ type: 'object',
82
+ additionalProperties: false,
83
+ required: %w[x y],
84
+ properties: {
85
+ x: { type: 'number' },
86
+ y: { type: 'number' }
87
+ }
88
+ }
70
89
  }
71
90
  }
72
91
  ```
@@ -12,7 +12,6 @@ class Scheming::DSL::DataBuilder
12
12
 
13
13
  # @param field_name [Symbol]
14
14
  # @param type_spec [Object]
15
- # @param null [Boolean]
16
15
  # @return [void]
17
16
  def attribute(field_name, type_spec)
18
17
  @builder = @builder.attribute(
@@ -10,7 +10,7 @@ class Scheming::DSL::Tagging
10
10
  #
11
11
  class Tag
12
12
  # @param name [Symbo]
13
- # @data [Hash<Symbol, Object>]
13
+ # @param data [Hash<Symbol, Object>]
14
14
  def initialize(name, data)
15
15
  @name = name
16
16
  @data = data
@@ -29,8 +29,8 @@ class Scheming::DSL::Tagging
29
29
  nil
30
30
  end
31
31
 
32
- # @param taglist [Hash<Symbol, Object>]
33
32
  # @param name [Symbol]
33
+ # @param data [Hash<Symbol, Object>]
34
34
  # @return [Tag]
35
35
  def tag!(name, data)
36
36
  @tags[name] = Tag.new(name, data)
@@ -26,4 +26,11 @@ module Scheming::DSL::TypeSpecs
26
26
  type = Scheming::DSL::TypeResolver.resolve(type_spec)
27
27
  Scheming::Type::Nullable.new(type)
28
28
  end
29
+
30
+ def Union(*type_specs) # rubocop:disable Naming/MethodName
31
+ types = type_specs.map do |type_spec|
32
+ Scheming::DSL::TypeResolver.resolve(type_spec)
33
+ end
34
+ Scheming::Type::Union.new(types)
35
+ end
29
36
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Generic
4
+ #
5
+ # Many types can be "templated" in a way where
6
+ # some types get swapped in and out. Perhaps
7
+ # the most common example for this is with a
8
+ # two dimensional `Point` structure. We could
9
+ # have a point with `Float` coordinates OR they
10
+ # could also be `Integer`:
11
+ #
12
+ # ```ruby
13
+ # Object(x: Float, y: Float)
14
+ # Object(x: Integer, y: Integer)
15
+ # ```
16
+ #
17
+ # Instead of having two defintions we can have
18
+ # a single generic that defins both:
19
+ #
20
+ # ```ruby
21
+ # Point = Scheming::Generic.new do |(t)|
22
+ # Object(x: t, y: t)
23
+ # end
24
+ #
25
+ # Point[Float]
26
+ #
27
+ # Point[Integer]
28
+ # ```
29
+ #
30
+ class Scheming::Generic
31
+ def initialize(&proto_type)
32
+ @proto_type = proto_type
33
+ end
34
+
35
+ # @param types [Scheming::Type::Base]
36
+ def [](*types)
37
+ Scheming::DSL::DataBuilder
38
+ .new
39
+ .instance_exec(types, &@proto_type)
40
+ end
41
+ end
@@ -29,7 +29,10 @@ module Scheming::Schema
29
29
  private
30
30
 
31
31
  def required
32
- attributes.required.map!(&:field_name).freeze
32
+ attributes
33
+ .required
34
+ .map! { |attr| attr.field_name.to_s.freeze }
35
+ .freeze
33
36
  end
34
37
 
35
38
  def properties
@@ -39,6 +42,13 @@ module Scheming::Schema
39
42
  end
40
43
  end
41
44
 
45
+ refine Scheming::Type::Union do
46
+ # @!attribute [r] types
47
+ # @return [Array<Scheming::Type::Base>]
48
+
49
+ def schema = { oneOf: types.map(&:schema).freeze }
50
+ end
51
+
42
52
  refine Scheming::Type::Nullable do
43
53
  # @!attribute [r] type
44
54
  # @return [Scheming::Type::Base]
data/lib/scheming/type.rb CHANGED
@@ -47,6 +47,23 @@ module Scheming::Type
47
47
  end
48
48
  end
49
49
 
50
+ # = Union Type Definition
51
+ #
52
+ # In cases where a value can be of many different
53
+ # types a union is how to describe this.
54
+ #
55
+ class Union < Base
56
+ # @return [Array<Scheming::Type::Base>]
57
+ attr_reader :types
58
+
59
+ # @param types [Array<Scheming::Type::Base>]
60
+ def initialize(types)
61
+ super()
62
+ @types = types
63
+ freeze
64
+ end
65
+ end
66
+
50
67
  # = Enumeration Type Definition
51
68
  #
52
69
  # The wrapper that describes a type and holds
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Scheming
4
- VERSION = '0.4.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/scheming.rb CHANGED
@@ -10,6 +10,7 @@ module Scheming
10
10
  require_relative 'scheming/attribute'
11
11
  require_relative 'scheming/type'
12
12
  require_relative 'scheming/schema'
13
+ require_relative 'scheming/generic'
13
14
  require_relative 'scheming/dsl'
14
15
 
15
16
  # @return [Class]
@@ -18,4 +19,7 @@ module Scheming
18
19
  builder.instance_exec(&)
19
20
  builder.build
20
21
  end
22
+
23
+ # @return [Scheming::Generic]
24
+ def self.generic(&) = Scheming::Generic.new(&)
21
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scheming
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Falk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-02 00:00:00.000000000 Z
11
+ date: 2024-05-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ergonomic Data Design for the Masses
14
14
  email:
@@ -35,6 +35,7 @@ files:
35
35
  - lib/scheming/dsl/tagging.rb
36
36
  - lib/scheming/dsl/type_resolver.rb
37
37
  - lib/scheming/dsl/type_specs.rb
38
+ - lib/scheming/generic.rb
38
39
  - lib/scheming/schema.rb
39
40
  - lib/scheming/schema/json.rb
40
41
  - lib/scheming/type.rb