scheming 0.5.0 → 0.7.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: b21c99fc59c9fe7da35644b47be93b2d6bba2f13f4ef814008a64c92f2235323
4
- data.tar.gz: c0ff8026a852f0b8e4c91bf86aa4a172502a12b3c89dcd693527863dc7cf58aa
3
+ metadata.gz: 670c2fce2ac13e3ae6d64790ef6fbcad0f0de413c06bb2fc3300e24686315495
4
+ data.tar.gz: 599cd2a5d28aed9215a011b896a7eb5a207f14f2a7ca55dcd9299abed4100e32
5
5
  SHA512:
6
- metadata.gz: 93fa8e2cd04de2c77495754fe04aa2cbd84070a862835c83ef535a7830b6e41337b401f2e35dbf297434397523e24b50c8cb97063745fe58d61f881114187424
7
- data.tar.gz: 61c3cf8462b6d9075e593d00fa76921bbb7958e1ac2590f2a4683ff5c2aeac40b28209e579270eff279cea0261d6d1ea8194a0a87d2ebd3b56f93f8bfc8a2966
6
+ metadata.gz: fb6bc063479d9b7fc4f3769d966102b0c9fccc971727bb5e72962186227dfb55d3921b40b3a26b5454defc36f1f48cf1afba680b6221ed4b84bee12ae16cce5f
7
+ data.tar.gz: 711e2a1f8b035ff4aa33dca7955f810cbd7e11774d221f7a2ad0da59623ce5424e4fc02a92fefac78117a1ed37b35fa3a24799547121e97daaebd523a722ef63
data/.rubocop.yml CHANGED
@@ -18,3 +18,6 @@ Style/ClassAndModuleChildren:
18
18
 
19
19
  Layout/LineLength:
20
20
  Max: 90
21
+
22
+ Lint/EmptyClass:
23
+ AllowComments: true
data/.solargraph.yml ADDED
@@ -0,0 +1,28 @@
1
+ ---
2
+ include:
3
+ - "**/*.rb"
4
+ exclude:
5
+ - spec/**/*
6
+ - test/**/*
7
+ - vendor/**/*
8
+ - ".bundle/**/*"
9
+ require: []
10
+ domains: []
11
+ reporters:
12
+ - rubocop
13
+ - require_not_found
14
+ - typecheck
15
+ formatter:
16
+ rubocop:
17
+ cops: safe
18
+ except: []
19
+ only: []
20
+ extra_args: []
21
+ require_paths: [
22
+ 'factory_bot',
23
+ 'json_schemer',
24
+ 'pry',
25
+ 'set'
26
+ ]
27
+ plugins: []
28
+ max_files: 5000
data/CHANGELOG.md CHANGED
@@ -1,12 +1,108 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.7.0] - 2024-05-10
4
+
5
+ ### Added
6
+
7
+ - `Tuple` type added
8
+
9
+ #### Example
10
+ ```ruby
11
+ EmailTemplate = Scheming.object do
12
+ attribute :id, Integer
13
+ attribute :data, Tuple(String, Array(String))
14
+ end
15
+
16
+ Scheming::Schema.json(EmailTemplate)
17
+ # =>
18
+ {
19
+ type: 'object',
20
+ additionalProperties: false,
21
+ required: %w[id data],
22
+ properties: {
23
+ id: { type: 'integer' },
24
+ data: {
25
+ type: 'array',
26
+ prefixItems: [
27
+ { type: 'string' },
28
+ {
29
+ type: 'array',
30
+ items: { type: 'string' }
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Enhancement
39
+
40
+ - Added `solorgraph` to the development process and added
41
+ it's typecheck to the default `rake` task.
42
+
43
+ - Reduced string allocations when generating required field
44
+ names for objects with the JSON schema format.
45
+
46
+ ### Bugfix
47
+
48
+ - Incorrect type syntax corrected as reported by `solargraph`.
49
+
50
+ ## [0.6.0] - 2024-05-04
51
+
52
+ ### Added
53
+
54
+ - `Union` type added
55
+
56
+ #### Example
57
+ ```ruby
58
+ Order = Scheming.object do
59
+ attribute :id, Union(String, Integer)
60
+ end
61
+
62
+ Scheming::Schema.json(Order)
63
+ # =>
64
+ {
65
+ type: 'object',
66
+ additionalProperties: false,
67
+ required: %w[id],
68
+ properties: {
69
+ id: {
70
+ oneOf: [
71
+ { type: 'string' },
72
+ { type: 'integer' }
73
+ ]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Fixed
80
+
81
+ - Incorrect YARD comment tags and syntax.
82
+
83
+ ### Breaking Change
84
+
85
+ - Switch from `json-schema` to `json_schemer`
86
+
87
+ > TL;DR
88
+ required object properties for the JSON schema
89
+ are now strings instead of symbols
90
+
91
+ After doing to research I've found that `json_schemer` is
92
+ more maintained than what was currently being used. It has
93
+ a smaller footprint and is much faster at validation.
94
+
95
+ As a consequence the `required` properties needed to be
96
+ changed from symbols to strings in the generated JSON schema.
97
+
98
+
3
99
  ## [0.5.0] - 2024-05-02
4
100
 
5
101
  ### Added
6
102
 
7
103
  - Support for `generic` definitions
8
104
 
9
- # Example
105
+ #### Example
10
106
  ```ruby
11
107
  Point = Scheming.generic do |(type)|
12
108
  Object(x: type, y: type)
data/Gemfile CHANGED
@@ -6,8 +6,9 @@ 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'
13
13
  gem 'rubocop', '~> 1.21'
14
+ gem 'solargraph'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scheming (0.5.0)
4
+ scheming (0.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -16,27 +16,40 @@ 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)
20
+ backport (1.2.0)
22
21
  base64 (0.2.0)
22
+ benchmark (0.3.0)
23
23
  bigdecimal (3.1.7)
24
24
  coderay (1.1.3)
25
25
  concurrent-ruby (1.2.3)
26
26
  connection_pool (2.4.1)
27
27
  diff-lcs (1.5.1)
28
28
  drb (2.2.1)
29
+ e2mmap (0.1.0)
29
30
  factory_bot (6.4.6)
30
31
  activesupport (>= 5.0.0)
32
+ hana (1.3.7)
31
33
  i18n (1.14.4)
32
34
  concurrent-ruby (~> 1.0)
35
+ jaro_winkler (1.5.6)
33
36
  json (2.7.2)
34
- json-schema (4.3.0)
35
- addressable (>= 2.8)
37
+ json_schemer (2.2.1)
38
+ base64
39
+ bigdecimal
40
+ hana (~> 1.3)
41
+ regexp_parser (~> 2.0)
42
+ simpleidn (~> 0.2)
43
+ kramdown (2.4.0)
44
+ rexml
45
+ kramdown-parser-gfm (1.1.0)
46
+ kramdown (~> 2.0)
36
47
  language_server-protocol (3.17.0.3)
37
48
  method_source (1.1.0)
38
49
  minitest (5.22.3)
39
50
  mutex_m (0.2.0)
51
+ nokogiri (1.16.4-x86_64-linux)
52
+ racc (~> 1.4)
40
53
  parallel (1.24.0)
41
54
  parser (3.3.1.0)
42
55
  ast (~> 2.4.1)
@@ -44,11 +57,13 @@ GEM
44
57
  pry (0.14.2)
45
58
  coderay (~> 1.1)
46
59
  method_source (~> 1.0)
47
- public_suffix (5.0.5)
48
60
  racc (1.7.3)
49
61
  rainbow (3.1.1)
50
62
  rake (13.2.1)
63
+ rbs (2.8.4)
51
64
  regexp_parser (2.9.0)
65
+ reverse_markdown (2.1.1)
66
+ nokogiri
52
67
  rexml (3.2.6)
53
68
  rspec (3.13.0)
54
69
  rspec-core (~> 3.13.0)
@@ -77,21 +92,46 @@ GEM
77
92
  rubocop-ast (1.31.2)
78
93
  parser (>= 3.3.0.4)
79
94
  ruby-progressbar (1.13.0)
95
+ simpleidn (0.2.2)
96
+ unf (~> 0.1.4)
97
+ solargraph (0.50.0)
98
+ backport (~> 1.2)
99
+ benchmark
100
+ bundler (~> 2.0)
101
+ diff-lcs (~> 1.4)
102
+ e2mmap
103
+ jaro_winkler (~> 1.5)
104
+ kramdown (~> 2.3)
105
+ kramdown-parser-gfm (~> 1.1)
106
+ parser (~> 3.0)
107
+ rbs (~> 2.0)
108
+ reverse_markdown (~> 2.0)
109
+ rubocop (~> 1.38)
110
+ thor (~> 1.0)
111
+ tilt (~> 2.0)
112
+ yard (~> 0.9, >= 0.9.24)
113
+ thor (1.3.1)
114
+ tilt (2.3.0)
80
115
  tzinfo (2.0.6)
81
116
  concurrent-ruby (~> 1.0)
117
+ unf (0.1.4)
118
+ unf_ext
119
+ unf_ext (0.0.9.1)
82
120
  unicode-display_width (2.5.0)
121
+ yard (0.9.36)
83
122
 
84
123
  PLATFORMS
85
124
  x86_64-linux
86
125
 
87
126
  DEPENDENCIES
88
127
  factory_bot (~> 6.4)
89
- json-schema (~> 4.3)
128
+ json_schemer
90
129
  pry (~> 0.14.2)
91
130
  rake (~> 13.0)
92
131
  rspec (~> 3.0)
93
132
  rubocop (~> 1.21)
94
133
  scheming!
134
+ solargraph
95
135
 
96
136
  BUNDLED WITH
97
137
  2.4.5
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
@@ -45,16 +45,21 @@ Scheming::Schema.json(Receipt)
45
45
  {
46
46
  type: 'object',
47
47
  additionalProperties: false,
48
- required: %i[line_items total location],
48
+ required: %w[line_items total location],
49
49
  properties: {
50
50
  line_items: {
51
51
  type: 'array',
52
52
  items: {
53
53
  type: 'object',
54
54
  additionalProperties: false,
55
- required: %i[id name taxable price],
55
+ required: %w[id name taxable price],
56
56
  properties: {
57
- id: { type: 'integer' },
57
+ id: {
58
+ oneOf: [
59
+ { type: 'integer' },
60
+ { type: 'string' }
61
+ ]
62
+ },
58
63
  name: { type: 'string' },
59
64
  taxable: { type: 'boolean' },
60
65
  desc: {
@@ -75,7 +80,7 @@ Scheming::Schema.json(Receipt)
75
80
  location: {
76
81
  type: 'object',
77
82
  additionalProperties: false,
78
- required: %i[x y],
83
+ required: %w[x y],
79
84
  properties: {
80
85
  x: { type: 'number' },
81
86
  y: { type: 'number' }
data/Rakefile CHANGED
@@ -9,4 +9,9 @@ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[spec rubocop]
12
+ desc 'Run the type checker'
13
+ task :typecheck do
14
+ sh 'bundle exec solargraph typecheck --level typed'
15
+ end
16
+
17
+ task default: %i[spec rubocop typecheck]
@@ -36,6 +36,7 @@ class Scheming::Attribute::List
36
36
  end
37
37
  alias [] attr
38
38
 
39
+ # @return [Array<Scheming::Attribute>]
39
40
  def required = each.select(&:is_required)
40
41
 
41
42
  # @return [Hash<Symbol, Scheming::Attribute>]
@@ -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(
@@ -9,8 +9,8 @@ class Scheming::DSL::Tagging
9
9
  # creation of an [Scheming::Attribute]
10
10
  #
11
11
  class Tag
12
- # @param name [Symbo]
13
- # @data [Hash<Symbol, Object>]
12
+ # @param name [Symbol]
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,18 @@ 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
36
+
37
+ def Tuple(*type_specs) # rubocop:disable Naming/MethodName
38
+ types = type_specs.map do |type_spec|
39
+ Scheming::DSL::TypeResolver.resolve(type_spec)
40
+ end
41
+ Scheming::Type::Tuple.new(types.freeze)
42
+ end
29
43
  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.name }
35
+ .freeze
33
36
  end
34
37
 
35
38
  def properties
@@ -39,6 +42,25 @@ 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
+
52
+ refine Scheming::Type::Tuple do
53
+ # @!attribute [r] types
54
+ # @return [Array<Scheming::Type::Base>]
55
+
56
+ def schema
57
+ {
58
+ type: 'array',
59
+ prefixItems: types.map(&:schema).freeze
60
+ }.freeze
61
+ end
62
+ end
63
+
42
64
  refine Scheming::Type::Nullable do
43
65
  # @!attribute [r] type
44
66
  # @return [Scheming::Type::Base]
data/lib/scheming/type.rb CHANGED
@@ -1,5 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # This is a redundant require statement; however,
4
+ # for some reason Solargraph will not honor the
5
+ # path for `set` in it's config. For this reson
6
+ # we need to require it here to prevent typecheck
7
+ # errors.
8
+ require 'set' # rubocop:disable Lint/RedundantRequireStatement
9
+
3
10
  # = Type
4
11
  #
5
12
  # Everything needed to describe and work
@@ -11,7 +18,11 @@ module Scheming::Type
11
18
  # Any and all shared functionality comes from
12
19
  # this base type definition.
13
20
  #
14
- Base = Class.new
21
+ class Base
22
+ # This class left empty on purpose. Acts
23
+ # merely as a tag which all types inherit
24
+ # back to.
25
+ end
15
26
 
16
27
  # = Object Type Definition
17
28
  #
@@ -30,6 +41,25 @@ module Scheming::Type
30
41
  end
31
42
  end
32
43
 
44
+ # = Tuple Type Definition
45
+ #
46
+ # Specifies a type which specifies specific types
47
+ # in a fixed order. Another way to think of it is
48
+ # like an [Scheming::Type::Object] but without named
49
+ # attribute fields.
50
+ #
51
+ class Tuple < Base
52
+ # @return [Array<Scheming::Type::Base>]
53
+ attr_reader :types
54
+
55
+ # @param types [Array<Scheming::Type::Base>]
56
+ def initialize(types)
57
+ super()
58
+ @types = types
59
+ freeze
60
+ end
61
+ end
62
+
33
63
  # = Nullable Type Definition
34
64
  #
35
65
  # Type wrapper that describes a type can be either
@@ -47,6 +77,23 @@ module Scheming::Type
47
77
  end
48
78
  end
49
79
 
80
+ # = Union Type Definition
81
+ #
82
+ # In cases where a value can be of many different
83
+ # types a union is how to describe this.
84
+ #
85
+ class Union < Base
86
+ # @return [Array<Scheming::Type::Base>]
87
+ attr_reader :types
88
+
89
+ # @param types [Array<Scheming::Type::Base>]
90
+ def initialize(types)
91
+ super()
92
+ @types = types
93
+ freeze
94
+ end
95
+ end
96
+
50
97
  # = Enumeration Type Definition
51
98
  #
52
99
  # 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.5.0'
4
+ VERSION = '0.7.0'
5
5
  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.5.0
4
+ version: 0.7.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-03 00:00:00.000000000 Z
11
+ date: 2024-05-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ergonomic Data Design for the Masses
14
14
  email:
@@ -19,6 +19,7 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - ".rspec"
21
21
  - ".rubocop.yml"
22
+ - ".solargraph.yml"
22
23
  - CHANGELOG.md
23
24
  - Gemfile
24
25
  - Gemfile.lock