scheming 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a71514dd3a8b1f9640a40adf0bbfd928cab9abe7b6981fad8ac0e25a1c7add01
4
+ data.tar.gz: edad4ab18d9c22efebbdc39b9a7c74d451e9a41b9b85892a743bb0dc726301b2
5
+ SHA512:
6
+ metadata.gz: daaff46c5331a1dd747fadfd50701f497225d05104d443dce75c0b8d244445943cea917e5d2ad39a2daf2fbe271ea08edd0930ac351a12dd1ff552c05b6fb590
7
+ data.tar.gz: 28f7756667869ff46d076f74dc89849d65a5fc3609c2c472d85f02cfe16143c74936ac7d16bb2d577650b53df159d9402d34926999f6e8aa3808d721dec2afc9
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ AllCops:
2
+ SuggestExtensions: false
3
+ NewCops: enable
4
+
5
+ Style/StringLiterals:
6
+ Enabled: true
7
+ EnforcedStyle: single_quotes
8
+
9
+ Metrics/BlockLength:
10
+ AllowedMethods: ['define', 'describe', 'it', 'context', 'let']
11
+
12
+ Style/StringLiteralsInInterpolation:
13
+ Enabled: true
14
+ EnforcedStyle: double_quotes
15
+
16
+ Style/ClassAndModuleChildren:
17
+ Enabled: false
18
+
19
+ Layout/LineLength:
20
+ Max: 90
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-04-26
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in dee_tea_ohh.gemspec
6
+ gemspec
7
+
8
+ gem 'factory_bot', '~> 6.4'
9
+ gem 'pry', '~> 0.14.2'
10
+ gem 'rake', '~> 13.0'
11
+ gem 'rspec', '~> 3.0'
12
+ gem 'rubocop', '~> 1.21'
data/Gemfile.lock ADDED
@@ -0,0 +1,91 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ scheming (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activesupport (7.1.3.2)
10
+ base64
11
+ bigdecimal
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ connection_pool (>= 2.2.5)
14
+ drb
15
+ i18n (>= 1.6, < 2)
16
+ minitest (>= 5.1)
17
+ mutex_m
18
+ tzinfo (~> 2.0)
19
+ ast (2.4.2)
20
+ base64 (0.2.0)
21
+ bigdecimal (3.1.7)
22
+ coderay (1.1.3)
23
+ concurrent-ruby (1.2.3)
24
+ connection_pool (2.4.1)
25
+ diff-lcs (1.5.1)
26
+ drb (2.2.1)
27
+ factory_bot (6.4.6)
28
+ activesupport (>= 5.0.0)
29
+ i18n (1.14.4)
30
+ concurrent-ruby (~> 1.0)
31
+ json (2.7.2)
32
+ language_server-protocol (3.17.0.3)
33
+ method_source (1.1.0)
34
+ minitest (5.22.3)
35
+ mutex_m (0.2.0)
36
+ parallel (1.24.0)
37
+ parser (3.3.1.0)
38
+ ast (~> 2.4.1)
39
+ racc
40
+ pry (0.14.2)
41
+ coderay (~> 1.1)
42
+ method_source (~> 1.0)
43
+ racc (1.7.3)
44
+ rainbow (3.1.1)
45
+ rake (13.2.1)
46
+ regexp_parser (2.9.0)
47
+ rexml (3.2.6)
48
+ rspec (3.13.0)
49
+ rspec-core (~> 3.13.0)
50
+ rspec-expectations (~> 3.13.0)
51
+ rspec-mocks (~> 3.13.0)
52
+ rspec-core (3.13.0)
53
+ rspec-support (~> 3.13.0)
54
+ rspec-expectations (3.13.0)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.13.0)
57
+ rspec-mocks (3.13.0)
58
+ diff-lcs (>= 1.2.0, < 2.0)
59
+ rspec-support (~> 3.13.0)
60
+ rspec-support (3.13.1)
61
+ rubocop (1.63.3)
62
+ json (~> 2.3)
63
+ language_server-protocol (>= 3.17.0)
64
+ parallel (~> 1.10)
65
+ parser (>= 3.3.0.2)
66
+ rainbow (>= 2.2.2, < 4.0)
67
+ regexp_parser (>= 1.8, < 3.0)
68
+ rexml (>= 3.2.5, < 4.0)
69
+ rubocop-ast (>= 1.31.1, < 2.0)
70
+ ruby-progressbar (~> 1.7)
71
+ unicode-display_width (>= 2.4.0, < 3.0)
72
+ rubocop-ast (1.31.2)
73
+ parser (>= 3.3.0.4)
74
+ ruby-progressbar (1.13.0)
75
+ tzinfo (2.0.6)
76
+ concurrent-ruby (~> 1.0)
77
+ unicode-display_width (2.5.0)
78
+
79
+ PLATFORMS
80
+ x86_64-linux
81
+
82
+ DEPENDENCIES
83
+ factory_bot (~> 6.4)
84
+ pry (~> 0.14.2)
85
+ rake (~> 13.0)
86
+ rspec (~> 3.0)
87
+ rubocop (~> 1.21)
88
+ scheming!
89
+
90
+ BUNDLED WITH
91
+ 2.4.5
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Ben Falk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # Scheming
2
+
3
+ Ergonomically define and work with data in Ruby
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem 'scheming'
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Simple Schema
14
+
15
+ Definition:
16
+ ```ruby
17
+ LineItem = Scheming.object do
18
+ attribute :id, Integer
19
+ attribute :name, String
20
+ attribute :taxable, :bool
21
+ attribute :desc, Nullable(String)
22
+ attribute :price, Float
23
+ attribute :type, Enum('entertainment', 'staple')
24
+ end
25
+
26
+ Receipt = Scheming.object do
27
+ attribute :line_items, Array(LineItem)
28
+ attribute :total, Float
29
+ end
30
+ ```
31
+
32
+ Example:
33
+ ```ruby
34
+ Scheming::Schema.json(Receipt)
35
+ # =>
36
+ {
37
+ type: 'object',
38
+ additionalProperties: false,
39
+ required: %i[line_items total],
40
+ properties: {
41
+ line_items: {
42
+ type: 'array',
43
+ items: {
44
+ type: 'object',
45
+ additionalProperties: false,
46
+ required: %i[id name taxable desc price item_type],
47
+ properties: {
48
+ id: { type: 'integer' },
49
+ name: { type: 'string' },
50
+ taxable: { type: 'boolean' },
51
+ desc: {
52
+ oneOf: [
53
+ { type: 'string' },
54
+ { type: 'null' }
55
+ ]
56
+ },
57
+ price: { type: 'numeric' },
58
+ item_type: {
59
+ type: 'string',
60
+ enum: %w[entertainment staple].to_set
61
+ }
62
+ }
63
+ }
64
+ },
65
+ total: { type: 'numeric' }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Development
71
+
72
+ ### Getting Started
73
+
74
+ To get going the following commands are helpful:
75
+
76
+ ```bash
77
+ git clone https://github.com/benfalk/scheming.git
78
+ ./scheming/setup
79
+ cd scheming
80
+ bundle exec rake
81
+ ```
82
+
83
+ ### Installing Locally
84
+
85
+ To install this gem onto your local machine:
86
+
87
+ ```bash
88
+ bundle exec rake install
89
+ ```
90
+
91
+ ## Contributing
92
+
93
+ Bug reports and pull requests are welcome
94
+ on GitHub at https://github.com/benfalk/scheming.
95
+
96
+ ## License
97
+
98
+ The gem is available as open source under the terms of
99
+ the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Attribute Collection
4
+ #
5
+ class Scheming::Attribute::List
6
+ class MissingAttribute < Scheming::Error; end
7
+ include Enumerable
8
+
9
+ # @return [Scheming::Attribute::List]
10
+ def self.empty = @empty ||= new([])
11
+
12
+ # @param attributes [Array<Scheming::Attribute>]
13
+ def initialize(attributes = [])
14
+ @attributes = attributes.uniq(&:field_name).freeze
15
+
16
+ # @type [Hash<Symbol, Scheming::Attribute>]
17
+ @lookup =
18
+ @attributes
19
+ .each_with_object({}) do |attr, lookup|
20
+ lookup[attr.field_name] = attr
21
+ end
22
+ .freeze
23
+ freeze
24
+ end
25
+
26
+ # @param key [Symbol]
27
+ # @return [Scheming::Attribute]
28
+ def attr(key)
29
+ @lookup.fetch(key) do |attr_key|
30
+ raise MissingAttribute, <<~MSG.strip!
31
+ Missing Attribute [#{attr_key}]
32
+ Available Fields:
33
+ #{@attributes.map(&:field_name).join("\n ")}
34
+ MSG
35
+ end
36
+ end
37
+ alias [] attr
38
+
39
+ def required = each.select(&:is_required)
40
+
41
+ # @return [Hash<Symbol, Scheming::Attribute>]
42
+ def to_h = @lookup
43
+
44
+ # Interface for Enumerable
45
+ # @yieldparam [Scheming::Attribute]
46
+ def each(&)
47
+ return enum_for(:each) unless block_given?
48
+
49
+ @attributes.each(&)
50
+ end
51
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Attribute Collection Builder
4
+ #
5
+ class Scheming::Attribute::ListBuilder
6
+ # @param attributes [Array<Scheming::Attribute>]
7
+ def initialize(attributes = [])
8
+ @attributes = attributes
9
+ freeze
10
+ end
11
+
12
+ # @param field_name [Symbol]
13
+ # @param type [Scheming::Type::Base]
14
+ # @return [Scheming::Attribute::ListBuilder]
15
+ def attribute(field_name, type:, is_required: true)
16
+ attr = Scheming::Attribute.new(
17
+ field_name:,
18
+ type:,
19
+ is_required:
20
+ )
21
+ self.class.new(@attributes + [attr])
22
+ end
23
+
24
+ # @return [Scheming::Attribute::List]
25
+ def build = Scheming::Attribute::List.new(@attributes)
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Attribute
4
+ #
5
+ class Scheming::Attribute
6
+ # @return [Symbol]
7
+ attr_reader :field_name
8
+
9
+ # @return [Scheming::Type::Base]
10
+ attr_reader :type
11
+
12
+ # @return [Boolean]
13
+ attr_reader :is_required
14
+
15
+ # @param field_name [Symbol]
16
+ # @param type [Scheming::Type::Base]
17
+ def initialize(
18
+ field_name:,
19
+ type:,
20
+ is_required: true
21
+ )
22
+ @field_name = field_name
23
+ @type = type
24
+ @is_required = is_required
25
+ freeze
26
+ end
27
+
28
+ require_relative 'attribute/list'
29
+ require_relative 'attribute/list_builder'
30
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Data Builder
4
+ class Scheming::DSL::DataBuilder
5
+ include Scheming::DSL::TypeSpecs
6
+
7
+ def initialize(builder = Scheming::Attribute::ListBuilder.new)
8
+ @builder = builder
9
+ @resolver = Scheming::DSL::TypeResolver
10
+ end
11
+
12
+ # @param field_name [Symbol]
13
+ # @param type_spec [Object]
14
+ # @param null [Boolean]
15
+ # @return [void]
16
+ def attribute(field_name, type_spec)
17
+ type = @resolver.resolve(type_spec)
18
+ @builder = @builder.attribute(field_name, type:)
19
+ nil
20
+ end
21
+
22
+ # @return [Class]
23
+ def build
24
+ list = @builder.build
25
+ dto_type = Scheming::Type::Object.new(list)
26
+
27
+ data = ::Data.define(*list.map(&:field_name))
28
+ data.instance_variable_set(:@dto_type, dto_type)
29
+ data.include(Scheming::DSL::ObjectTypeDef)
30
+ data
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Object Definition Tag
4
+ #
5
+ # This serves as a tag for produced
6
+ # transformation object definitions.
7
+ #
8
+ module Scheming::DSL::ObjectTypeDef
9
+ # @private
10
+ module ClassMethods
11
+ # @return [Scheming::Type::Object]
12
+ def dto_type = @dto_type
13
+
14
+ def inherited(klass)
15
+ super
16
+ klass.extend(ClassMethods)
17
+ klass.instance_variable_set(
18
+ :@dto_type,
19
+ dto_type
20
+ )
21
+ end
22
+
23
+ # @return [Class<Data>]
24
+ def extend_with(&)
25
+ list = Scheming::Attribute::ListBuilder.new(
26
+ dto_type.attributes.to_a
27
+ )
28
+ builder = Scheming::DSL::DataBuilder.new(list)
29
+ builder.instance_exec(&)
30
+ builder.build
31
+ end
32
+ end
33
+ private_constant :ClassMethods
34
+
35
+ def self.included(klass) = klass.extend(ClassMethods)
36
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Type Resolver
4
+ module Scheming::DSL::TypeResolver
5
+ module Constants
6
+ STRING = Scheming::Type::String.new.freeze
7
+ FLOAT = Scheming::Type::Float.new.freeze
8
+ INTEGER = Scheming::Type::Integer.new.freeze
9
+ BOOLEAN = Scheming::Type::Boolean.new.freeze
10
+ end
11
+ private_constant :Constants
12
+
13
+ refine Kernel do
14
+ import_methods Scheming::DSL::TypeSpecs
15
+ end
16
+
17
+ refine Symbol do
18
+ def dto_type
19
+ case self
20
+ when :int, :integer then Scheming::Type::Integer.new
21
+ when :str, :string then Scheming::Type::String.new
22
+ when :float then Scheming::Type::Float.new
23
+ when :bool then Scheming::Type::Boolean.new
24
+ end
25
+ end
26
+ end
27
+
28
+ refine Scheming::Type::Base do
29
+ def dto_type = self
30
+ end
31
+
32
+ refine Array do
33
+ def dto_type
34
+ # TODO: Error Handling
35
+ Scheming::Type::Array.new(first.dto_type)
36
+ end
37
+ end
38
+
39
+ refine Scheming::DSL::ObjectTypeDef do
40
+ def dto_type = self.class.dto_type
41
+ end
42
+
43
+ refine ::String.singleton_class do
44
+ def dto_type = Constants::STRING
45
+ end
46
+
47
+ refine ::String do
48
+ def dto_type = Constants::STRING
49
+ end
50
+
51
+ refine ::Float.singleton_class do
52
+ def dto_type = Constants::FLOAT
53
+ end
54
+
55
+ refine ::Float do
56
+ def dto_type = Constants::FLOAT
57
+ end
58
+
59
+ refine ::Integer.singleton_class do
60
+ def dto_type = Constants::INTEGER
61
+ end
62
+
63
+ refine ::Integer do
64
+ def dto_type = Constants::INTEGER
65
+ end
66
+
67
+ refine ::TrueClass do
68
+ def dto_type = Constants::BOOLEAN
69
+ end
70
+
71
+ refine ::FalseClass do
72
+ def dto_type = Constants::BOOLEAN
73
+ end
74
+
75
+ refine ::Set do
76
+ def dto_type
77
+ # TODO: Type checking of all values
78
+ Scheming::Type::Enum.new(
79
+ first.dto_type,
80
+ values: dup.freeze
81
+ )
82
+ end
83
+ end
84
+
85
+ using self
86
+
87
+ module_function
88
+
89
+ def resolve(any) = any.dto_type
90
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Type Specifications
4
+ #
5
+ # These helpers allow for a more ergonomic
6
+ # resolution of types
7
+ #
8
+ module Scheming::DSL::TypeSpecs
9
+ def Enum(*values) # rubocop:disable Naming/MethodName
10
+ Scheming::DSL::TypeResolver.resolve(values.to_set)
11
+ end
12
+
13
+ def Object(**attributes) # rubocop:disable Naming/MethodName
14
+ attrs = attributes.map do |field_name, type_spec|
15
+ Scheming::Attribute.new(
16
+ field_name:,
17
+ type: Scheming::DSL::TypeResolver.resolve(type_spec),
18
+ is_required: true
19
+ )
20
+ end
21
+ list = Scheming::Attribute::List.new(attrs)
22
+ Scheming::Type::Object.new(list)
23
+ end
24
+
25
+ def Nullable(type_spec) # rubocop:disable Naming/MethodName
26
+ type = Scheming::DSL::TypeResolver.resolve(type_spec)
27
+ Scheming::Type::Nullable.new(type)
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Domain Specific Language
4
+ #
5
+ # Everyone loves magic; I myself enjoy dabling in
6
+ # the dark arts from time to time. Having said that,
7
+ # this magic is best if it's understandable for those
8
+ # who need to know.
9
+ #
10
+ module Scheming::DSL
11
+ require_relative 'dsl/type_specs'
12
+ require_relative 'dsl/data_builder'
13
+ require_relative 'dsl/object_type_def'
14
+ require_relative 'dsl/type_resolver'
15
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scheming::Schema
4
+ # @private
5
+ module JSON
6
+ module Constants
7
+ NULL = { type: 'null' }.freeze
8
+ INTEGER = { type: 'integer' }.freeze
9
+ FLOAT = { type: 'numeric' }.freeze
10
+ STRING = { type: 'string' }.freeze
11
+ BOOLEAN = { type: 'boolean' }.freeze
12
+ end
13
+ private_constant :Constants
14
+
15
+ refine Scheming::Type::Object do
16
+ # @!attribute [r] attributes
17
+ # @return [Scheming::Attribute::List]
18
+
19
+ # @return [Hash]
20
+ def schema
21
+ {
22
+ type: 'object',
23
+ additionalProperties: false,
24
+ required:,
25
+ properties:
26
+ }.freeze
27
+ end
28
+
29
+ private
30
+
31
+ def required
32
+ attributes.required.map!(&:field_name).freeze
33
+ end
34
+
35
+ def properties
36
+ attributes.to_h.transform_values do |attr|
37
+ attr.type.schema
38
+ end.freeze
39
+ end
40
+ end
41
+
42
+ refine Scheming::Type::Nullable do
43
+ # @!attribute [r] type
44
+ # @return [Scheming::Type::Base]
45
+
46
+ # @return [Hash]
47
+ def schema
48
+ {
49
+ oneOf: [
50
+ type.schema,
51
+ Constants::NULL
52
+ ].freeze
53
+ }.freeze
54
+ end
55
+ end
56
+
57
+ refine Scheming::Type::Array do
58
+ # @!attribute [r] type
59
+ # @return [Scheming::Type::Base]
60
+
61
+ def schema
62
+ {
63
+ type: 'array',
64
+ items: type.schema
65
+ }.freeze
66
+ end
67
+ end
68
+
69
+ refine Scheming::Type::Enum do
70
+ def schema
71
+ type.schema.merge(enum: values).freeze
72
+ end
73
+ end
74
+
75
+ refine Scheming::Type::String do
76
+ # @return [Hash]
77
+ def schema = Constants::STRING
78
+ end
79
+
80
+ refine Scheming::Type::Integer do
81
+ # @return [Hash]
82
+ def schema = Constants::INTEGER
83
+ end
84
+
85
+ refine Scheming::Type::Float do
86
+ # @return [Hash]
87
+ def schema = Constants::FLOAT
88
+ end
89
+
90
+ refine Scheming::Type::Boolean do
91
+ # @return [Hash]
92
+ def schema = Constants::BOOLEAN
93
+ end
94
+
95
+ using self
96
+
97
+ module_function
98
+
99
+ # @param type [Scheming::Type::Base]
100
+ # @return [Hash]
101
+ def schema(type) = type.schema
102
+ end
103
+ private_constant :JSON
104
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scheming
4
+ # = Schema
5
+ #
6
+ # Responsible for producing different schema
7
+ # formats which describe the data type provided
8
+ # to it.
9
+ #
10
+ module Schema
11
+ require_relative 'schema/json'
12
+
13
+ module_function
14
+
15
+ # @param raw_type [Scheming::Type::Base]
16
+ # @return [Hash]
17
+ def json(raw_type)
18
+ type = Scheming::DSL::TypeResolver.resolve(raw_type)
19
+ JSON.schema(type)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ # = Type
4
+ #
5
+ # Everything needed to describe and work
6
+ # with defining types to encode to.
7
+ #
8
+ module Scheming::Type
9
+ # = Base Type Definition
10
+ #
11
+ # Any and all shared functionality comes from
12
+ # this base type definition.
13
+ #
14
+ Base = Class.new
15
+
16
+ # = Object Type Definition
17
+ #
18
+ # Holds any number of named fields and the
19
+ # types that they hold
20
+ #
21
+ class Object < Base
22
+ # @return [Scheming::Attribute::List]
23
+ attr_reader :attributes
24
+
25
+ # @param attributes [Scheming::Attribute::List]
26
+ def initialize(attributes = Scheming::Attribute::List.empty)
27
+ super()
28
+ @attributes = attributes
29
+ freeze
30
+ end
31
+ end
32
+
33
+ # = Nullable Type Definition
34
+ #
35
+ # Type wrapper that describes a type can be either
36
+ # the type provided OR it may be Null
37
+ #
38
+ class Nullable < Base
39
+ # @return [Scheming::Type::Base]
40
+ attr_reader :type
41
+
42
+ # @param type [Scheming::Type::Base]
43
+ def initialize(type)
44
+ super()
45
+ @type = type
46
+ freeze
47
+ end
48
+ end
49
+
50
+ # = Enumeration Type Definition
51
+ #
52
+ # The wrapper that describes a type and holds
53
+ # a discrete set of values of that type.
54
+ #
55
+ class Enum < Base
56
+ # @return [Scheming::Type::Base]
57
+ attr_reader :type
58
+
59
+ # @return [Set<Object>]
60
+ attr_reader :values
61
+
62
+ # @param type [Scheming::Type::Base]
63
+ # @param values [Set<Object>]
64
+ def initialize(type, values:)
65
+ super()
66
+ @type = type
67
+ @values = values
68
+ freeze
69
+ end
70
+ end
71
+
72
+ # = Array Type Definition
73
+ #
74
+ # Type wrapper which describes an array of zero
75
+ # or more of the provided type.
76
+ #
77
+ class Array < Base
78
+ # @return [Scheming::Type::Base]
79
+ attr_reader :type
80
+
81
+ # @param type [Scheming::Type::Base]
82
+ def initialize(type)
83
+ super()
84
+ @type = type
85
+ freeze
86
+ end
87
+ end
88
+
89
+ # = Integer Type Definition
90
+ class Integer < Base; end
91
+
92
+ # = Float Type Definition
93
+ class Float < Base; end
94
+
95
+ # = String Type Definition
96
+ class String < Base; end
97
+
98
+ # = Boolean Type Definition
99
+ class Boolean < Base; end
100
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scheming
4
+ VERSION = '0.1.0'
5
+ end
data/lib/scheming.rb ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'scheming/version'
4
+
5
+ # = Scheming
6
+ #
7
+ module Scheming
8
+ class Error < StandardError; end
9
+
10
+ require_relative 'scheming/attribute'
11
+ require_relative 'scheming/type'
12
+ require_relative 'scheming/schema'
13
+ require_relative 'scheming/dsl'
14
+
15
+ # @return [Class]
16
+ def self.object(&)
17
+ builder = Scheming::DSL::DataBuilder.new
18
+ builder.instance_exec(&)
19
+ builder.build
20
+ end
21
+ end
data/sig/scheming.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Scheming
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scheming
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Falk
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-05-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ergonomic Data Design for the Masses
14
+ email:
15
+ - benjamin.falk@yahoo.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rspec"
21
+ - ".rubocop.yml"
22
+ - CHANGELOG.md
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - lib/scheming.rb
29
+ - lib/scheming/attribute.rb
30
+ - lib/scheming/attribute/list.rb
31
+ - lib/scheming/attribute/list_builder.rb
32
+ - lib/scheming/dsl.rb
33
+ - lib/scheming/dsl/data_builder.rb
34
+ - lib/scheming/dsl/object_type_def.rb
35
+ - lib/scheming/dsl/type_resolver.rb
36
+ - lib/scheming/dsl/type_specs.rb
37
+ - lib/scheming/schema.rb
38
+ - lib/scheming/schema/json.rb
39
+ - lib/scheming/type.rb
40
+ - lib/scheming/version.rb
41
+ - sig/scheming.rbs
42
+ homepage:
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ rubygems_mfa_required: 'true'
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '3.2'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.4.5
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Designing Data
66
+ test_files: []