scheming 0.3.0 → 0.5.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: bc01781074d4363c7a93440ca775680ad40e390eadf0dd84501501f96aad242f
4
- data.tar.gz: c5356c5b7beb9d74f6489db0d4024973755fc5c2b6a5c015a97d4b21d612191c
3
+ metadata.gz: b21c99fc59c9fe7da35644b47be93b2d6bba2f13f4ef814008a64c92f2235323
4
+ data.tar.gz: c0ff8026a852f0b8e4c91bf86aa4a172502a12b3c89dcd693527863dc7cf58aa
5
5
  SHA512:
6
- metadata.gz: d5ebcaf385cbf2148e37d326c06bd49bd6aa584c9d419096dbb8a7e5f909c191c93b1bc1a294c2a4589c9bf2a9902bf775d73679c440134ebae600ce25e9f110
7
- data.tar.gz: 169ff09cbed7450f5d22754db231e98b5752d98fc00b8dfd2613cb0f0054c59efa24e4b8e86331b32823e76341de46685b8a45abda5416396cdd3b81f8809890
6
+ metadata.gz: 93fa8e2cd04de2c77495754fe04aa2cbd84070a862835c83ef535a7830b6e41337b401f2e35dbf297434397523e24b50c8cb97063745fe58d61f881114187424
7
+ data.tar.gz: 61c3cf8462b6d9075e593d00fa76921bbb7958e1ac2590f2a4683ff5c2aeac40b28209e579270eff279cea0261d6d1ea8194a0a87d2ebd3b56f93f8bfc8a2966
data/CHANGELOG.md CHANGED
@@ -1,14 +1,39 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2024-04-26
3
+ ## [0.5.0] - 2024-05-02
4
4
 
5
- - Initial release
5
+ ### Added
6
6
 
7
- ## [0.2.0] - 2024-05-01
7
+ - Support for `generic` definitions
8
8
 
9
- ### Added
9
+ # Example
10
+ ```ruby
11
+ Point = Scheming.generic do |(type)|
12
+ Object(x: type, y: type)
13
+ end
10
14
 
11
- - Support for `optional` fields
15
+ Scheming::Schema.json(Point)
16
+ # =>
17
+ {
18
+ type: 'object',
19
+ additionalProperties: false,
20
+ required: %i[x y],
21
+ properties: {
22
+ x: { type: 'number' },
23
+ y: { type: 'number' }
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## [0.4.0] - 2024-05-02
29
+
30
+ ### Breaking Change
31
+
32
+ - Opting for a `tag` system to work with attributes instead
33
+ of a blanket lexical scope like `optional` to work with
34
+ attributes. The long term goal is to expand out the tagging
35
+ system so that it can support much more than we can
36
+ anticipate today.
12
37
 
13
38
  # Example:
14
39
  ```ruby
@@ -18,12 +43,12 @@
18
43
  attribute :taxable, :bool
19
44
  attribute :price, Float
20
45
 
21
- optional
22
-
46
+ tag(:optional)
23
47
  attribute :desc, Nullable(String)
48
+
49
+ tag(:optional)
24
50
  attribute :item_type, Enum('entertainment', 'staple')
25
51
  end
26
- ```
27
52
 
28
53
  ## [0.3.0] - 2024-05-01
29
54
 
@@ -36,3 +61,28 @@
36
61
  ### Enhancement
37
62
 
38
63
  - Ensure all types produce valid JSON Schema
64
+
65
+ ## [0.2.0] - 2024-05-01
66
+
67
+ ### Added
68
+
69
+ - Support for `optional` fields
70
+
71
+ # Example:
72
+ ```ruby
73
+ LineItem = Scheming.object do
74
+ attribute :id, Integer
75
+ attribute :name, String
76
+ attribute :taxable, :bool
77
+ attribute :price, Float
78
+
79
+ optional
80
+
81
+ attribute :desc, Nullable(String)
82
+ attribute :item_type, Enum('entertainment', 'staple')
83
+ end
84
+ ```
85
+
86
+ ## [0.1.0] - 2024-04-26
87
+
88
+ - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scheming (0.3.0)
4
+ scheming (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -20,15 +20,21 @@ LineItem = Scheming.object do
20
20
  attribute :taxable, :bool
21
21
  attribute :price, Float
22
22
 
23
- optional
24
-
23
+ tag(:optional)
25
24
  attribute :desc, Nullable(String)
25
+
26
+ tag(:optional)
26
27
  attribute :item_type, Enum('entertainment', 'staple')
27
28
  end
28
29
 
30
+ Point = Scheming.generic do |(type)|
31
+ Object(x: type, y: type)
32
+ end
33
+
29
34
  Receipt = Scheming.object do
30
35
  attribute :line_items, Array(LineItem)
31
36
  attribute :total, Float
37
+ attribute :location, Point[Float]
32
38
  end
33
39
  ```
34
40
 
@@ -39,7 +45,7 @@ Scheming::Schema.json(Receipt)
39
45
  {
40
46
  type: 'object',
41
47
  additionalProperties: false,
42
- required: %i[line_items total],
48
+ required: %i[line_items total location],
43
49
  properties: {
44
50
  line_items: {
45
51
  type: 'array',
@@ -60,12 +66,21 @@ Scheming::Schema.json(Receipt)
60
66
  price: { type: 'number' },
61
67
  item_type: {
62
68
  type: 'string',
63
- enum: ['intertainment', 'staple']
69
+ enum: %w[entertainment staple]
64
70
  }
65
71
  }
66
72
  }
67
73
  },
68
- total: { type: 'number' }
74
+ total: { type: 'number' },
75
+ location: {
76
+ type: 'object',
77
+ additionalProperties: false,
78
+ required: %i[x y],
79
+ properties: {
80
+ x: { type: 'number' },
81
+ y: { type: 'number' }
82
+ }
83
+ }
69
84
  }
70
85
  }
71
86
  ```
@@ -7,7 +7,7 @@ class Scheming::DSL::DataBuilder
7
7
  def initialize(builder = Scheming::Attribute::ListBuilder.new)
8
8
  @builder = builder
9
9
  @resolver = Scheming::DSL::TypeResolver
10
- @required = true
10
+ @tagging = Scheming::DSL::Tagging.new
11
11
  end
12
12
 
13
13
  # @param field_name [Symbol]
@@ -18,14 +18,17 @@ class Scheming::DSL::DataBuilder
18
18
  @builder = @builder.attribute(
19
19
  field_name,
20
20
  type: @resolver.resolve(type_spec),
21
- is_required: @required
21
+ **@tagging.attribute_params
22
22
  )
23
+ @tagging.reset!
23
24
  nil
24
25
  end
25
26
 
26
- # Mark all arrtibutes after this as optional
27
- def optional
28
- @required = false
27
+ # @param name [Symbol]
28
+ # @param args [Hash<Symbol, Object>]
29
+ def tag(name, **args)
30
+ @tagging.tag!(name, args)
31
+ nil
29
32
  end
30
33
 
31
34
  # @return [Class]
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Type Resolver
4
+ class Scheming::DSL::Tagging
5
+ # = Attribute Tag
6
+ #
7
+ # Simple representation of a concept
8
+ # that can be used to aid in the
9
+ # creation of an [Scheming::Attribute]
10
+ #
11
+ class Tag
12
+ # @param name [Symbo]
13
+ # @data [Hash<Symbol, Object>]
14
+ def initialize(name, data)
15
+ @name = name
16
+ @data = data
17
+ end
18
+ end
19
+ private_constant :Tag
20
+
21
+ def initialize
22
+ # @type [Hash<Symbol, Tag>]
23
+ @tags = {}
24
+ end
25
+
26
+ # @return [void]
27
+ def reset!
28
+ @tags.clear
29
+ nil
30
+ end
31
+
32
+ # @param taglist [Hash<Symbol, Object>]
33
+ # @param name [Symbol]
34
+ # @return [Tag]
35
+ def tag!(name, data)
36
+ @tags[name] = Tag.new(name, data)
37
+ end
38
+
39
+ def attribute_params
40
+ {
41
+ is_required: missing?(:optional)
42
+ }
43
+ end
44
+
45
+ def missing?(name) = !has?(name)
46
+ def has?(name) = @tags.key?(name)
47
+ end
data/lib/scheming/dsl.rb CHANGED
@@ -8,6 +8,7 @@
8
8
  # who need to know.
9
9
  #
10
10
  module Scheming::DSL
11
+ require_relative 'dsl/tagging'
11
12
  require_relative 'dsl/type_specs'
12
13
  require_relative 'dsl/data_builder'
13
14
  require_relative 'dsl/object_type_def'
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Scheming
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.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.3.0
4
+ version: 0.5.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-01 00:00:00.000000000 Z
11
+ date: 2024-05-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ergonomic Data Design for the Masses
14
14
  email:
@@ -32,8 +32,10 @@ files:
32
32
  - lib/scheming/dsl.rb
33
33
  - lib/scheming/dsl/data_builder.rb
34
34
  - lib/scheming/dsl/object_type_def.rb
35
+ - lib/scheming/dsl/tagging.rb
35
36
  - lib/scheming/dsl/type_resolver.rb
36
37
  - lib/scheming/dsl/type_specs.rb
38
+ - lib/scheming/generic.rb
37
39
  - lib/scheming/schema.rb
38
40
  - lib/scheming/schema/json.rb
39
41
  - lib/scheming/type.rb