scheming 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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