From f3166c9779729072e4708cb7664810aca1e3d011 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 26 Sep 2024 12:53:56 +0200 Subject: [PATCH 01/18] Handling Arrays as the root node --- lib/scheemer/params.rb | 11 +++++++++-- spec/scheemer/params_spec.rb | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index d548602..f5315ee 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -39,14 +39,21 @@ def to_h def method_missing(name, *args, &) key_name = name.to_sym.camelcase - return @params.fetch(key_name) if @params.key?(key_name) + return @params.fetch(key_name) if internal_property?(key_name) super end def respond_to_missing?(name, include_private = false) key_name = name.camelcase - @params.key?(key_name) || super + + internal_property?(name) || super + end + + def internal_property?(name) + return unless @params.is_a?(Hash) + + @params.key?(name.camelcase) end end end diff --git a/spec/scheemer/params_spec.rb b/spec/scheemer/params_spec.rb index cced0ea..9d21f12 100644 --- a/spec/scheemer/params_spec.rb +++ b/spec/scheemer/params_spec.rb @@ -21,6 +21,20 @@ expect(record.someValue).to eql("testing") end end + + context "with a list root node" do + let(:klass) do + Class.new do + extend Scheemer::Params::DSL + end + end + + subject(:record) { klass.new([{ name: "testing" }]) } + + it "does not resolve" do + expect(record.respond_to?(:name)).to be false + end + end end describe ".on_missing" do From 0586b973673c1cf9409e04e2e6659c86ca07ffea Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 26 Sep 2024 12:56:19 +0200 Subject: [PATCH 02/18] Removing unused variable --- lib/scheemer/params.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index f5315ee..9b053b5 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -45,8 +45,6 @@ def method_missing(name, *args, &) end def respond_to_missing?(name, include_private = false) - key_name = name.camelcase - internal_property?(name) || super end From e8a91cb675bf9819229454ea18dc4d02cc5fe388 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 26 Sep 2024 13:34:15 +0200 Subject: [PATCH 03/18] Bumping version to 3.0.1 --- lib/scheemer/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index 164ff42..d3e8395 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.0.0" + VERSION = "3.0.1" end From 9afd658bac4871ccc1e4e6f495439adceea53038 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Sat, 5 Oct 2024 13:41:14 +0200 Subject: [PATCH 04/18] Allows direct access to Schema Error violation values --- lib/scheemer/errors.rb | 12 +++++++- lib/scheemer/extensions/string.rb | 18 ++++++------ lib/scheemer/schema.rb | 4 +-- spec/scheemer/fallbacker_spec.rb | 2 +- spec/scheemer/invalid_schema_error_spec.rb | 33 ++++++++++++++++++++++ 5 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 spec/scheemer/invalid_schema_error_spec.rb diff --git a/lib/scheemer/errors.rb b/lib/scheemer/errors.rb index 10a4d43..ed4c3f0 100644 --- a/lib/scheemer/errors.rb +++ b/lib/scheemer/errors.rb @@ -13,8 +13,18 @@ def message end class InvalidSchemaError < Error + def initialize(result) + super + + @result = result + end + def message - "#{title}: #{super}" + "#{title}: #{violations}" + end + + def violations + @result.errors.to_h end private diff --git a/lib/scheemer/extensions/string.rb b/lib/scheemer/extensions/string.rb index 3d14769..cdb4053 100644 --- a/lib/scheemer/extensions/string.rb +++ b/lib/scheemer/extensions/string.rb @@ -8,30 +8,30 @@ module CaseModifier [first, rest.collect(&:capitalize)].join end UNDERSCORER = lambda do |value| - value.gsub(/::/, '/'). - gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). - gsub(/([a-z\d])([A-Z])/,'\1_\2'). - tr("-", "_"). - downcase + value.gsub(/::/, "/") + .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr("-", "_") + .downcase end refine Symbol do def camelcase - CAMELCASER.(self).to_sym + CAMELCASER.call(self).to_sym end def underscore - UNDERSCORER.(self).to_sym + UNDERSCORER.call(self).to_sym end end refine String do def camelcase - CAMELCASER.(self) + CAMELCASER.call(self) end def underscore - UNDERSCORER.(self) + UNDERSCORER.call(self) end end end diff --git a/lib/scheemer/schema.rb b/lib/scheemer/schema.rb index 2cf2f91..0a684fe 100644 --- a/lib/scheemer/schema.rb +++ b/lib/scheemer/schema.rb @@ -4,7 +4,7 @@ Dry::Schema.load_extensions(:hints, :json_schema) -require_relative "./errors" +require_relative "errors" module Scheemer class Schema @@ -52,7 +52,7 @@ def validate!(params) validate(params).tap do |result| next if result.success? - raise InvalidSchemaError, result.messages.to_h + raise InvalidSchemaError, result end end diff --git a/spec/scheemer/fallbacker_spec.rb b/spec/scheemer/fallbacker_spec.rb index 41961ed..f1bccfd 100644 --- a/spec/scheemer/fallbacker_spec.rb +++ b/spec/scheemer/fallbacker_spec.rb @@ -61,7 +61,7 @@ subject(:data) do described_class.apply( { content: { key: "old-key" } }, - { "content.new_key" => lambda { "dynamic-value" } } + { "content.new_key" => -> { "dynamic-value" } } ) end diff --git a/spec/scheemer/invalid_schema_error_spec.rb b/spec/scheemer/invalid_schema_error_spec.rb new file mode 100644 index 0000000..3327354 --- /dev/null +++ b/spec/scheemer/invalid_schema_error_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Scheemer::InvalidSchemaError do + let(:result) do + Struct.new(:errors).new( + { + record: { + name: ["is missing"] + } + } + ) + end + + subject(:error) { described_class.new(result) } + + it "compiles a semi-readable developer message" do + expect(error.message).to eql(<<~MSG.tr("\n", "")) + The submitted request does not satisfy the following requirements: {:record=>{:name=>["is missing"]}} + MSG + end + + it "allows access to the violations" do + expect(error.violations).to eql( + { + record: { + name: ["is missing"] + } + } + ) + end +end From 2e18253926bacbc6d0a0644c3e358f47090617a9 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Sat, 5 Oct 2024 13:44:19 +0200 Subject: [PATCH 05/18] Bumping to 3.1.0 --- lib/scheemer/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index d3e8395..3d7bbab 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.0.1" + VERSION = "3.1.0" end From f55a7905be356eb5eeb1b8b5d7403ef601aab7d6 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Mon, 2 Dec 2024 17:19:53 +0100 Subject: [PATCH 06/18] Linting --- lib/scheemer.rb | 2 +- lib/scheemer/params.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/scheemer.rb b/lib/scheemer.rb index cfd5d3f..97ffe37 100644 --- a/lib/scheemer.rb +++ b/lib/scheemer.rb @@ -16,7 +16,7 @@ def initialize(params, data = {}) root_node = permitted.to_h.values.first - super root_node, data.to_h + super(root_node, data.to_h) end end end diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index 9b053b5..9505579 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require_relative "./fallbacker" +require_relative "fallbacker" -require_relative "./extensions/string" +require_relative "extensions/string" module Scheemer # This handles the conversion from the HTTP linguo (camelCase) From 8821455e0607152baa20f81d9fc81e3dd2aa466e Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Mon, 2 Dec 2024 17:20:45 +0100 Subject: [PATCH 07/18] Allow passing in underscored keys --- lib/scheemer/extensions/string.rb | 2 +- lib/scheemer/params.rb | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/scheemer/extensions/string.rb b/lib/scheemer/extensions/string.rb index cdb4053..399e6d6 100644 --- a/lib/scheemer/extensions/string.rb +++ b/lib/scheemer/extensions/string.rb @@ -21,7 +21,7 @@ def camelcase end def underscore - UNDERSCORER.call(self).to_sym + UNDERSCORER.call(to_s).to_sym end end diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index 9505579..9ab008c 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -37,21 +37,30 @@ def to_h @params.to_h.transform_keys { |key| key.to_s.underscore } end + def multi_slice(key, &block) + return unless @params.is_a?(Hash) + + slices = [ + ->(name) { name.underscore }, + ->(name) { name.camelcase }, + ->(name) { name } + ].map { |a| @params.slice(a.call(key)) } + .reject(&:empty?) + + return if slices.empty? + + slices.first + end + def method_missing(name, *args, &) - key_name = name.to_sym.camelcase - return @params.fetch(key_name) if internal_property?(key_name) + slice = multi_slice(name.to_sym) + return slice.values.first if slice&.any? super end def respond_to_missing?(name, include_private = false) - internal_property?(name) || super - end - - def internal_property?(name) - return unless @params.is_a?(Hash) - - @params.key?(name.camelcase) + multi_slice(name.to_sym)&.any? || super end end end From e1ad4e691af551132461891ef0d21f4fe9481dcf Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Tue, 6 May 2025 14:41:32 +0200 Subject: [PATCH 08/18] Allow exporting loose JSON Schemas --- lib/scheemer/schema.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/scheemer/schema.rb b/lib/scheemer/schema.rb index 0a684fe..94ff3e9 100644 --- a/lib/scheemer/schema.rb +++ b/lib/scheemer/schema.rb @@ -25,8 +25,8 @@ def validate_schema!(params) @schema.validate!(params) end - def json_schema - @schema.json_schema + def json_schema(loose: false) + @schema.json_schema(loose:) end private @@ -56,8 +56,8 @@ def validate!(params) end end - def json_schema - @definitions.json_schema + def json_schema(loose: false) + @definitions.json_schema(loose:) end end end From 5b6f0e59e93a71214b0d9633b6bdd756a695121c Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Tue, 6 May 2025 14:43:10 +0200 Subject: [PATCH 09/18] Bumping version to 3.2.0 --- lib/scheemer/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index 3d7bbab..5d0952d 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.1.0" + VERSION = "3.2.0" end From 00dc06629cfaa88cc03273a2428e1d7df58bfe1e Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Wed, 7 May 2025 14:48:00 +0200 Subject: [PATCH 10/18] Adding Pry --- Gemfile | 2 ++ Gemfile.lock | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index fa6f2c7..cbbe87e 100644 --- a/Gemfile +++ b/Gemfile @@ -9,3 +9,5 @@ gem "rake", "~> 13.0" gem "rspec", "~> 3.0" gem "rubocop", "~> 1.21" gem "rubocop-rspec", "~> 2.12.1" + +gem "pry-nav", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index d3112e7..cf51d76 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,14 @@ PATH remote: . specs: - scheemer (3.0.0) + scheemer (3.2.0) dry-schema (~> 1.13) GEM remote: https://rubygems.org/ specs: ast (2.4.2) + coderay (1.1.3) concurrent-ruby (1.2.2) diff-lcs (1.5.0) dry-configurable (1.0.1) @@ -37,9 +38,15 @@ GEM dry-logic (~> 1.4) zeitwerk (~> 2.6) json (2.6.3) + method_source (1.1.0) parallel (1.23.0) parser (3.2.2.1) ast (~> 2.4.1) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-nav (1.0.0) + pry (>= 0.9.10, < 0.15) rainbow (3.1.1) rake (13.0.6) regexp_parser (2.8.0) @@ -79,6 +86,7 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES + pry-nav (~> 1.0) rake (~> 13.0) rspec (~> 3.0) rubocop (~> 1.21) From a1db80c76c87dbd5b1972be2ce03c93f6f631522 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Wed, 7 May 2025 14:48:28 +0200 Subject: [PATCH 11/18] Updating Compose config --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3682b04..8b92daa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3" services: scheemer: image: "scheemer:latest" From 883a741d41520e416fe3e89ff2e6a5cc23d40f1c Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Wed, 7 May 2025 14:49:24 +0200 Subject: [PATCH 12/18] Allow iterating through the parameters --- lib/scheemer/params.rb | 8 +++++ spec/scheemer/params_spec.rb | 52 ++++++++++++++++++++++++++---- spec/scheemer/schema_spec.rb | 2 +- spec/scheemer_spec.rb | 62 ++++++++++++++++++++++++++++++++++-- 4 files changed, 115 insertions(+), 9 deletions(-) diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index 9ab008c..47f584e 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -27,6 +27,8 @@ def params_fallbacks end module InstanceMethods + include Enumerable + def initialize(params, data = {}) @params = Fallbacker.apply(params, self.class.params_fallbacks) @@ -37,6 +39,12 @@ def to_h @params.to_h.transform_keys { |key| key.to_s.underscore } end + def each(&block) + return enum_for(:each) unless block_given? + + @params.each(&block) + end + def multi_slice(key, &block) return unless @params.is_a?(Hash) diff --git a/spec/scheemer/params_spec.rb b/spec/scheemer/params_spec.rb index 9d21f12..610df30 100644 --- a/spec/scheemer/params_spec.rb +++ b/spec/scheemer/params_spec.rb @@ -11,7 +11,7 @@ end end - subject(:record) { klass.new({ someValue: "testing" }) } + subject(:record) { klass.new({someValue: "testing"}) } it "allows access to fields using underscored accessors" do expect(record.some_value).to eql("testing") @@ -22,14 +22,14 @@ end end - context "with a list root node" do + context "with a list node" do let(:klass) do Class.new do extend Scheemer::Params::DSL end end - subject(:record) { klass.new([{ name: "testing" }]) } + subject(:record) { klass.new([{name: "testing"}]) } it "does not resolve" do expect(record.respond_to?(:name)).to be false @@ -37,20 +37,60 @@ end end + describe "#each" do + let(:klass) do + Class.new do + extend Scheemer::Params::DSL + end + end + + subject(:record) { klass.new({"someKey" => ["testing"]}) } + + it { expect(record.respond_to?(:each)).to be_truthy } + + it "can iterate through the params" do + expect(record.map(&:to_a)).to eql([["someKey", ["testing"]]]) + end + end + + describe "#to_h" do + let(:klass) do + Class.new do + extend Scheemer::Params::DSL + end + end + + context "with a hash node" do + subject(:record) { klass.new({"someKey" => ["testing"]}) } + + it "can iterate through the params" do + expect(record.to_h).to eql({"some_key" => ["testing"]}) + end + end + + context "with a list node" do + subject(:record) { klass.new([{name: "someKey"}, {name: "testing"}]) } + + it "can iterate through the params" do + expect { record.to_h }.to raise_error(TypeError) + end + end + end + describe ".on_missing" do context "with a single level key" do let(:klass) do Class.new do extend Scheemer::Params::DSL - on_missing path: "content", fallback_to: { fall: "back" } + on_missing path: "content", fallback_to: {fall: "back"} end end - subject(:record) { klass.new({ someValue: "testing" }) } + subject(:record) { klass.new({someValue: "testing"}) } it "allows access to fields using underscored accessors" do - expect(record.content).to eql({ fall: "back" }) + expect(record.content).to eql({fall: "back"}) expect(record.someValue).to eql("testing") end end diff --git a/spec/scheemer/schema_spec.rb b/spec/scheemer/schema_spec.rb index 86021a7..3017480 100644 --- a/spec/scheemer/schema_spec.rb +++ b/spec/scheemer/schema_spec.rb @@ -12,7 +12,7 @@ context "with the required data" do it do - expect { schema.validate!({ test: "something" }) } + expect { schema.validate!({test: "something"}) } .not_to raise_error end end diff --git a/spec/scheemer_spec.rb b/spec/scheemer_spec.rb index ec30500..7bbcf15 100644 --- a/spec/scheemer_spec.rb +++ b/spec/scheemer_spec.rb @@ -21,7 +21,7 @@ end end - subject(:record) { klass.new({ root: { someValue: "testing" } }) } + subject(:record) { klass.new({root: {someValue: "testing"}}) } it "allows access to fields using underscored accessors" do expect(record.some_value).to eql("testing") @@ -45,7 +45,7 @@ expect_any_instance_of(klass) .to receive(:validate!).with(other_data: "it works!") - klass.new({ root: { someValue: "testing" } }, other_data: "it works!") + klass.new({root: {someValue: "testing"}}, other_data: "it works!") end end @@ -59,4 +59,62 @@ it { expect { klass.new({}) }.to raise_error(NotImplementedError) } end end + + describe "#each" do + context "with a flat hash" do + let(:klass) do + Class.new do + extend Scheemer::DSL + + schema do + required(:root).hash do + required(:name).filled(:string) + end + end + end + end + + subject(:record) { klass.new({root: {name: "testing"}}) } + + it { expect(record.respond_to?(:each)).to be_truthy } + end + + context "with a list as the root node" do + let(:klass) do + Class.new do + extend Scheemer::DSL + + schema do + required(:root).hash do + required(:children).array(:string) + end + end + end + end + + subject(:record) { klass.new({root: {children: ["testing"]}}) } + + it "can iterate through the params" do + expect(record.map(&:to_a)).to eql([[:children, ["testing"]]]) + end + end + + context "with a hash as the root node" do + let(:klass) do + Class.new do + extend Scheemer::DSL + + schema do + required(:children).array(:hash) + end + end + end + + subject(:record) { klass.new({children: [{name: "testing"}]}) } + + it "can iterate through the params" do + expect(record.first).to eql({name: "testing"}) + end + end + end end From 0a615b92aca0d0bca028f12bd0ac2f99221550d1 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Wed, 7 May 2025 14:49:59 +0200 Subject: [PATCH 13/18] Bumping to 3.3.0 --- Gemfile.lock | 2 +- lib/scheemer/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cf51d76..b78154e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - scheemer (3.2.0) + scheemer (3.3.0) dry-schema (~> 1.13) GEM diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index 5d0952d..2109855 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.2.0" + VERSION = "3.3.0" end From f207ddd7d6da6c7521c84677353bc1fd2464da85 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 22 May 2025 10:54:21 +0200 Subject: [PATCH 14/18] Adding UUID v7 as a custom type --- lib/scheemer/schema.rb | 11 +++++++++++ spec/scheemer/schema_spec.rb | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/scheemer/schema.rb b/lib/scheemer/schema.rb index 94ff3e9..dcfe78e 100644 --- a/lib/scheemer/schema.rb +++ b/lib/scheemer/schema.rb @@ -38,8 +38,19 @@ def check_schema_exists! end end + module Types + include Dry::Types() + + UUID_V7 = Strict::String.constrained(format: %r{^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-7[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}$}) + end + + TypeContainer = ::Dry::Schema::TypeContainer.new + TypeContainer.register("params.uuid_v7", Types::UUID_V7) + def initialize(&) @definitions = ::Dry::Schema.Params do + config.types = TypeContainer + instance_eval(&) end end diff --git a/spec/scheemer/schema_spec.rb b/spec/scheemer/schema_spec.rb index 3017480..cc16fd3 100644 --- a/spec/scheemer/schema_spec.rb +++ b/spec/scheemer/schema_spec.rb @@ -7,6 +7,7 @@ subject(:schema) do described_class.new do required(:test) + optional(:id).filled(:uuid_v7) end end @@ -23,5 +24,27 @@ .to raise_error(Scheemer::InvalidSchemaError) end end + + context "when using the UUID v7 custom type" do + subject(:schema) do + described_class.new do + required(:id).filled(:uuid_v7) + end + end + + context "with a valid value" do + it do + expect { schema.validate!({id: "0196d94e-dde8-74d3-a42e-ee38fa6442a8"}) } + .not_to raise_error + end + end + + context "with an invalid value" do + it do + expect { schema.validate!({id: "asd"}) } + .to raise_error(Scheemer::InvalidSchemaError) + end + end + end end end From 400bde928a639143b87d2f27d4f73a24cf5bddf3 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 22 May 2025 10:54:51 +0200 Subject: [PATCH 15/18] Linting --- lib/scheemer/params.rb | 10 +++++----- lib/scheemer/schema.rb | 2 +- spec/scheemer/invalid_schema_error_spec.rb | 8 ++++---- spec/scheemer/params_spec.rb | 20 ++++++++++---------- spec/scheemer/schema_spec.rb | 6 +++--- spec/scheemer_spec.rb | 14 +++++++------- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index 47f584e..71a521b 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -39,21 +39,21 @@ def to_h @params.to_h.transform_keys { |key| key.to_s.underscore } end - def each(&block) + def each(&) return enum_for(:each) unless block_given? - @params.each(&block) + @params.each(&) end - def multi_slice(key, &block) + def multi_slice(key) return unless @params.is_a?(Hash) slices = [ ->(name) { name.underscore }, ->(name) { name.camelcase }, - ->(name) { name } + ->(name) { name }, ].map { |a| @params.slice(a.call(key)) } - .reject(&:empty?) + .reject(&:empty?) return if slices.empty? diff --git a/lib/scheemer/schema.rb b/lib/scheemer/schema.rb index dcfe78e..e6a4f10 100644 --- a/lib/scheemer/schema.rb +++ b/lib/scheemer/schema.rb @@ -41,7 +41,7 @@ def check_schema_exists! module Types include Dry::Types() - UUID_V7 = Strict::String.constrained(format: %r{^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-7[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}$}) + UUID_V7 = Strict::String.constrained(format: /^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-7[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}$/) end TypeContainer = ::Dry::Schema::TypeContainer.new diff --git a/spec/scheemer/invalid_schema_error_spec.rb b/spec/scheemer/invalid_schema_error_spec.rb index 3327354..60e7650 100644 --- a/spec/scheemer/invalid_schema_error_spec.rb +++ b/spec/scheemer/invalid_schema_error_spec.rb @@ -7,8 +7,8 @@ Struct.new(:errors).new( { record: { - name: ["is missing"] - } + name: ["is missing"], + }, } ) end @@ -25,8 +25,8 @@ expect(error.violations).to eql( { record: { - name: ["is missing"] - } + name: ["is missing"], + }, } ) end diff --git a/spec/scheemer/params_spec.rb b/spec/scheemer/params_spec.rb index 610df30..2aa4d4c 100644 --- a/spec/scheemer/params_spec.rb +++ b/spec/scheemer/params_spec.rb @@ -11,7 +11,7 @@ end end - subject(:record) { klass.new({someValue: "testing"}) } + subject(:record) { klass.new({ someValue: "testing" }) } it "allows access to fields using underscored accessors" do expect(record.some_value).to eql("testing") @@ -29,7 +29,7 @@ end end - subject(:record) { klass.new([{name: "testing"}]) } + subject(:record) { klass.new([{ name: "testing" }]) } it "does not resolve" do expect(record.respond_to?(:name)).to be false @@ -44,9 +44,9 @@ end end - subject(:record) { klass.new({"someKey" => ["testing"]}) } + subject(:record) { klass.new({ "someKey" => ["testing"] }) } - it { expect(record.respond_to?(:each)).to be_truthy } + it { expect(record).to respond_to(:each) } it "can iterate through the params" do expect(record.map(&:to_a)).to eql([["someKey", ["testing"]]]) @@ -61,15 +61,15 @@ end context "with a hash node" do - subject(:record) { klass.new({"someKey" => ["testing"]}) } + subject(:record) { klass.new({ "someKey" => ["testing"] }) } it "can iterate through the params" do - expect(record.to_h).to eql({"some_key" => ["testing"]}) + expect(record.to_h).to eql({ "some_key" => ["testing"] }) end end context "with a list node" do - subject(:record) { klass.new([{name: "someKey"}, {name: "testing"}]) } + subject(:record) { klass.new([{ name: "someKey" }, { name: "testing" }]) } it "can iterate through the params" do expect { record.to_h }.to raise_error(TypeError) @@ -83,14 +83,14 @@ Class.new do extend Scheemer::Params::DSL - on_missing path: "content", fallback_to: {fall: "back"} + on_missing path: "content", fallback_to: { fall: "back" } end end - subject(:record) { klass.new({someValue: "testing"}) } + subject(:record) { klass.new({ someValue: "testing" }) } it "allows access to fields using underscored accessors" do - expect(record.content).to eql({fall: "back"}) + expect(record.content).to eql({ fall: "back" }) expect(record.someValue).to eql("testing") end end diff --git a/spec/scheemer/schema_spec.rb b/spec/scheemer/schema_spec.rb index cc16fd3..460a269 100644 --- a/spec/scheemer/schema_spec.rb +++ b/spec/scheemer/schema_spec.rb @@ -13,7 +13,7 @@ context "with the required data" do it do - expect { schema.validate!({test: "something"}) } + expect { schema.validate!({ test: "something" }) } .not_to raise_error end end @@ -34,14 +34,14 @@ context "with a valid value" do it do - expect { schema.validate!({id: "0196d94e-dde8-74d3-a42e-ee38fa6442a8"}) } + expect { schema.validate!({ id: "0196d94e-dde8-74d3-a42e-ee38fa6442a8" }) } .not_to raise_error end end context "with an invalid value" do it do - expect { schema.validate!({id: "asd"}) } + expect { schema.validate!({ id: "asd" }) } .to raise_error(Scheemer::InvalidSchemaError) end end diff --git a/spec/scheemer_spec.rb b/spec/scheemer_spec.rb index 7bbcf15..903c692 100644 --- a/spec/scheemer_spec.rb +++ b/spec/scheemer_spec.rb @@ -21,7 +21,7 @@ end end - subject(:record) { klass.new({root: {someValue: "testing"}}) } + subject(:record) { klass.new({ root: { someValue: "testing" } }) } it "allows access to fields using underscored accessors" do expect(record.some_value).to eql("testing") @@ -45,7 +45,7 @@ expect_any_instance_of(klass) .to receive(:validate!).with(other_data: "it works!") - klass.new({root: {someValue: "testing"}}, other_data: "it works!") + klass.new({ root: { someValue: "testing" } }, other_data: "it works!") end end @@ -74,9 +74,9 @@ end end - subject(:record) { klass.new({root: {name: "testing"}}) } + subject(:record) { klass.new({ root: { name: "testing" } }) } - it { expect(record.respond_to?(:each)).to be_truthy } + it { expect(record).to respond_to(:each) } end context "with a list as the root node" do @@ -92,7 +92,7 @@ end end - subject(:record) { klass.new({root: {children: ["testing"]}}) } + subject(:record) { klass.new({ root: { children: ["testing"] } }) } it "can iterate through the params" do expect(record.map(&:to_a)).to eql([[:children, ["testing"]]]) @@ -110,10 +110,10 @@ end end - subject(:record) { klass.new({children: [{name: "testing"}]}) } + subject(:record) { klass.new({ children: [{ name: "testing" }] }) } it "can iterate through the params" do - expect(record.first).to eql({name: "testing"}) + expect(record.first).to eql({ name: "testing" }) end end end From 8c7f18743205c9132578bbe19bd2164561f7f297 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Thu, 22 May 2025 10:56:28 +0200 Subject: [PATCH 16/18] Bumping to 3.4.0 --- lib/scheemer/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index 2109855..f4cd7fc 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.3.0" + VERSION = "3.4.0" end From 148e580686570d7988ff1f9813160f74173436aa Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Mon, 22 Jun 2026 09:22:36 +0200 Subject: [PATCH 17/18] Updating dependencies - Ruby 3.2 - DrySchema 1.16 --- .rubocop.yml | 13 +++- Dockerfile | 2 +- Gemfile | 8 +- Gemfile.lock | 119 +++++++++++++++++------------- lib/scheemer/extensions/string.rb | 2 +- lib/scheemer/fallbacker.rb | 4 +- lib/scheemer/params.rb | 6 +- lib/scheemer/schema.rb | 2 + scheemer.gemspec | 4 +- 9 files changed, 91 insertions(+), 69 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 8d2ddb3..9460bc1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,8 +1,8 @@ -require: +plugins: - rubocop-rspec AllCops: - TargetRubyVersion: 3.1 + TargetRubyVersion: 3.2 NewCops: enable Exclude: - bin/**/* @@ -21,13 +21,18 @@ Metrics/BlockLength: - spec/**/* Metrics/MethodLength: - CountAsOne: [hash, array, heredoc] + CountAsOne: + - hash + - array + - heredoc RSpec/AnyInstance: Enabled: false RSpec/ExampleLength: - CountAsOne: [hash, array] + CountAsOne: + - hash + - array RSpec/LeadingSubject: Enabled: false diff --git a/Dockerfile b/Dockerfile index bb3da4b..783783a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.1-alpine +FROM ruby:3.2-alpine RUN apk add --no-cache --update git build-base diff --git a/Gemfile b/Gemfile index cbbe87e..9e82957 100644 --- a/Gemfile +++ b/Gemfile @@ -5,9 +5,9 @@ source "https://rubygems.org" # Specify your gem's dependencies in scheemer.gemspec gemspec -gem "rake", "~> 13.0" -gem "rspec", "~> 3.0" -gem "rubocop", "~> 1.21" -gem "rubocop-rspec", "~> 2.12.1" +gem "rake", "~> 13.4" +gem "rspec", "~> 3.13" +gem "rubocop", "~> 1.88" +gem "rubocop-rspec", "~> 3.10" gem "pry-nav", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index b78154e..c3febc9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,96 +1,111 @@ PATH remote: . specs: - scheemer (3.3.0) - dry-schema (~> 1.13) + scheemer (3.4.0) + dry-schema (~> 1.16) GEM remote: https://rubygems.org/ specs: - ast (2.4.2) + ast (2.4.3) + bigdecimal (4.1.2) coderay (1.1.3) - concurrent-ruby (1.2.2) - diff-lcs (1.5.0) - dry-configurable (1.0.1) - dry-core (~> 1.0, < 2) + concurrent-ruby (1.3.7) + diff-lcs (1.6.2) + dry-configurable (1.3.0) + dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-core (1.0.0) + dry-core (1.2.0) concurrent-ruby (~> 1.0) + logger zeitwerk (~> 2.6) - dry-inflector (1.0.0) - dry-initializer (3.1.1) - dry-logic (1.5.0) + dry-inflector (1.3.1) + dry-initializer (3.2.0) + dry-logic (1.6.0) + bigdecimal concurrent-ruby (~> 1.0) - dry-core (~> 1.0, < 2) + dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-schema (1.13.1) + dry-schema (1.16.0) concurrent-ruby (~> 1.0) dry-configurable (~> 1.0, >= 1.0.1) - dry-core (~> 1.0, < 2) - dry-initializer (~> 3.0) - dry-logic (>= 1.4, < 2) - dry-types (>= 1.7, < 2) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-logic (~> 1.6) + dry-types (~> 1.9, >= 1.9.1) zeitwerk (~> 2.6) - dry-types (1.7.1) + dry-types (1.9.1) + bigdecimal (>= 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) dry-logic (~> 1.4) zeitwerk (~> 2.6) - json (2.6.3) + json (2.19.9) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + logger (1.7.0) method_source (1.1.0) - parallel (1.23.0) - parser (3.2.2.1) + parallel (1.28.0) + parser (3.3.11.1) ast (~> 2.4.1) + racc + prism (1.9.0) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) pry-nav (1.0.0) pry (>= 0.9.10, < 0.15) + racc (1.8.1) rainbow (3.1.1) - rake (13.0.6) - regexp_parser (2.8.0) - rexml (3.2.5) - rspec (3.12.0) - rspec-core (~> 3.12.0) - rspec-expectations (~> 3.12.0) - rspec-mocks (~> 3.12.0) - rspec-core (3.12.2) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) + rake (13.4.2) + regexp_parser (2.12.0) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-mocks (3.12.5) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-support (3.12.0) - rubocop (1.51.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.7) + rubocop (1.88.0) json (~> 2.3) - parallel (~> 1.10) - parser (>= 3.2.0.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (>= 1.10) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.28.1) - parser (>= 3.2.1.0) - rubocop-rspec (2.12.1) - rubocop (~> 1.31) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.1) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-rspec (3.10.2) + lint_roller (~> 1.1) + regexp_parser (>= 2.0) + rubocop (~> 1.86, >= 1.86.2) ruby-progressbar (1.13.0) - unicode-display_width (2.4.2) - zeitwerk (2.6.8) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + zeitwerk (2.8.2) PLATFORMS x86_64-linux-musl DEPENDENCIES pry-nav (~> 1.0) - rake (~> 13.0) - rspec (~> 3.0) - rubocop (~> 1.21) - rubocop-rspec (~> 2.12.1) + rake (~> 13.4) + rspec (~> 3.13) + rubocop (~> 1.88) + rubocop-rspec (~> 3.10) scheemer! BUNDLED WITH diff --git a/lib/scheemer/extensions/string.rb b/lib/scheemer/extensions/string.rb index 399e6d6..91ea5cc 100644 --- a/lib/scheemer/extensions/string.rb +++ b/lib/scheemer/extensions/string.rb @@ -8,7 +8,7 @@ module CaseModifier [first, rest.collect(&:capitalize)].join end UNDERSCORER = lambda do |value| - value.gsub(/::/, "/") + value.gsub("::", "/") .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') .gsub(/([a-z\d])([A-Z])/, '\1_\2') .tr("-", "_") diff --git a/lib/scheemer/fallbacker.rb b/lib/scheemer/fallbacker.rb index a539a39..ba8647f 100644 --- a/lib/scheemer/fallbacker.rb +++ b/lib/scheemer/fallbacker.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative "./extensions/hash" +require_relative "extensions/hash" module Scheemer module Fallbacker @@ -8,7 +8,7 @@ module Fallbacker using Extensions::Bury - def apply(params, fallbacks) + def apply(params, fallbacks) # rubocop:todo Metrics/MethodLength cloned_params = params.dup fallbacks.each do |(path, value)| diff --git a/lib/scheemer/params.rb b/lib/scheemer/params.rb index 71a521b..e3c47a5 100644 --- a/lib/scheemer/params.rb +++ b/lib/scheemer/params.rb @@ -49,11 +49,11 @@ def multi_slice(key) return unless @params.is_a?(Hash) slices = [ - ->(name) { name.underscore }, - ->(name) { name.camelcase }, + lambda(&:underscore), + lambda(&:camelcase), ->(name) { name }, ].map { |a| @params.slice(a.call(key)) } - .reject(&:empty?) + .reject(&:empty?) return if slices.empty? diff --git a/lib/scheemer/schema.rb b/lib/scheemer/schema.rb index e6a4f10..2561358 100644 --- a/lib/scheemer/schema.rb +++ b/lib/scheemer/schema.rb @@ -41,7 +41,9 @@ def check_schema_exists! module Types include Dry::Types() + # rubocop:todo Layout/LineLength UUID_V7 = Strict::String.constrained(format: /^[0-9(a-f|A-F)]{8}-[0-9(a-f|A-F)]{4}-7[0-9(a-f|A-F)]{3}-[89ab][0-9(a-f|A-F)]{3}-[0-9(a-f|A-F)]{12}$/) + # rubocop:enable Layout/LineLength end TypeContainer = ::Dry::Schema::TypeContainer.new diff --git a/scheemer.gemspec b/scheemer.gemspec index eceae48..73bae8f 100644 --- a/scheemer.gemspec +++ b/scheemer.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| spec.summary = "Request Parameter schema enforment for Assembly Voting systems" spec.homepage = "https://github.com/aion-dk/scheemer" spec.license = "MIT" - spec.required_ruby_version = ">= 3.1" + spec.required_ruby_version = ">= 3.2" # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" @@ -31,7 +31,7 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] # Uncomment to register a new dependency of your gem - spec.add_dependency "dry-schema", "~> 1.13" + spec.add_dependency "dry-schema", "~> 1.16" # For more information and examples about making a new gem, check out our # guide at: https://bundler.io/guides/creating_gem.html From 16398e2328feef606de968699dccbd69b85000e1 Mon Sep 17 00:00:00 2001 From: Lukas Alexandre Date: Mon, 22 Jun 2026 09:27:20 +0200 Subject: [PATCH 18/18] Bumping version to 3.5.0 --- Gemfile.lock | 2 +- lib/scheemer/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c3febc9..69fe52e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - scheemer (3.4.0) + scheemer (3.5.0) dry-schema (~> 1.16) GEM diff --git a/lib/scheemer/version.rb b/lib/scheemer/version.rb index f4cd7fc..379aeb7 100644 --- a/lib/scheemer/version.rb +++ b/lib/scheemer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Scheemer - VERSION = "3.4.0" + VERSION = "3.5.0" end