From 4cdd1bb71e4fea5b157e159698db05e03fbe52f1 Mon Sep 17 00:00:00 2001 From: Lars Vonk Date: Thu, 14 Nov 2024 09:15:19 +0100 Subject: [PATCH 1/3] Use gli and tty-prompt to improve sequent cli We can use colors and leverage the possibility of those gems. --- README.md | 3 - bin/sequent | 248 +------------------------ gemfiles/ar_7_1.gemfile.lock | 24 ++- gemfiles/ar_7_2.gemfile.lock | 24 ++- lib/sequent/cli/app.rb | 132 +++++++++++++ lib/sequent/cli/sequent_8_migration.rb | 180 ++++++++++++++++++ sequent.gemspec | 4 +- 7 files changed, 361 insertions(+), 254 deletions(-) create mode 100644 lib/sequent/cli/app.rb create mode 100644 lib/sequent/cli/sequent_8_migration.rb diff --git a/README.md b/README.md index 62fb106b..48ad82c4 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,6 @@ Then run `rake release`. A git tag will be created and pushed, and the new versi Increase version to new working version, update the sequent version for all the `gemfiles`: ``` -BUNDLE_GEMFILE=gemfiles/ar_6_0.gemfile bundle update sequent --conservative -BUNDLE_GEMFILE=gemfiles/ar_6_1.gemfile bundle update sequent --conservative -BUNDLE_GEMFILE=gemfiles/ar_7_0.gemfile bundle update sequent --conservative BUNDLE_GEMFILE=gemfiles/ar_7_1.gemfile bundle update sequent --conservative BUNDLE_GEMFILE=gemfiles/ar_7_2.gemfile bundle update sequent --conservative ``` diff --git a/bin/sequent b/bin/sequent index a5b06794..bf48055f 100755 --- a/bin/sequent +++ b/bin/sequent @@ -1,246 +1,10 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require_relative '../lib/sequent/generator' +require 'gli' +require 'tty-prompt' +require './lib/version' +require './lib/sequent/cli/app' -command = ARGV[0].to_s.strip -args = (ARGV[1..-1] || []).map(&:to_s).map(&:strip) - -if command.empty? - abort <<~EOS - Usage: #{$PROGRAM_NAME} command arguments... - - Please specify a command, for example `sequent new myapp`. Available commands: - - new appname Generate a new project from the Sequent template - project - generate type arguments... Generate a new aggregate, command, or event - - migrate Migrate a Sequent 7.1 database to Sequent 8 - EOS -end - -def new_project(name = nil, *args) - abort('Please specify a directory name. i.e. `sequent new myapp`') if name.empty? - abort("Unknown arguments '#{args.join(' ')}', aborting") unless args.empty? - - Sequent::Generator::Project.new(name).execute - puts <<~NEXTSTEPS - - Success! - - Your brand spanking new sequent app is waiting for you in: - #{File.expand_path(name, Dir.pwd)} - - To finish setting up your app: - cd #{name} - bundle install - bundle exec rake sequent:db:create - bundle exec rake sequent:db:create_view_schema - bundle exec rake sequent:migrate:online - bundle exec rake sequent:migrate:offline - - Run the example specs: - SEQUENT_ENV=test bundle exec rake sequent:db:create - bundle exec rspec spec - - To generate new aggregates use: - sequent generate . e.g. sequent generate address - - For more information see: - https://www.sequent.io - - Happy coding! - - NEXTSTEPS -rescue TargetAlreadyExists - abort("Target '#{name}' already exists, aborting") -end - -def generate_aggregate(aggregate_name = nil, *args) - abort('Please specify an aggregate name. i.e. `sequent g aggregate user`') unless args_valid?(aggregate_name) - abort("Unknown arguments '#{args.join(' ')}', aborting") unless args.empty? - - Sequent::Generator::Aggregate.new(aggregate_name).execute - puts "#{aggregate_name} aggregate has been generated" -rescue TargetAlreadyExists - abort("Target '#{aggregate_name}' already exists, aborting") -end - -def generate_command(aggregate_name = nil, command_name = nil, *attrs) - unless args_valid?(aggregate_name, command_name) - abort('Please specify an aggregate name and command name. i.e. `sequent g command User AddUser`') - end - Sequent::Generator::Command.new(aggregate_name, command_name, attrs).execute - puts "#{command_name} command has been added to #{aggregate_name}" -rescue NoAggregateFound - abort("Aggregate '#{aggregate_name}' not found, aborting") -end - -def generate_event(aggregate_name = nil, event_name = nil, *attrs) - abort('Please specify an aggregate name and event name. i.e. `sequent g event User UserAdded`') unless args_valid?( - aggregate_name, event_name - ) - Sequent::Generator::Event.new(aggregate_name, event_name, attrs).execute - puts "#{event_name} event has been added to #{aggregate_name}" -rescue NoAggregateFound - abort("Aggregate '#{aggregate_name}' not found, aborting") -end - -def generate(entity = nil, *args) - case entity - when 'aggregate' - generate_aggregate(*args) - when 'command' - generate_command(*args) - when 'event' - generate_event(*args) - else - abort <<~EOS - Unknown type for `generate`. Try `sequent g aggregate User`. Available options: - - generate aggregate Name - Generates the aggregate `Name` - - generate command Aggregate Command attributes... - Generates the command `Command` for aggregate `Aggregate` - - generate event Aggregate Event attributes... - Generates the event `Event` for aggregate `Aggregate` - EOS - end -end - -def confirm_or_abort - loop do - puts 'Enter `yes` to continue, `abort` to abort' - - line = $stdin.readline - puts - - abort('Aborted by user') if line.strip == 'abort' - - break if %w[y yes].include? line.strip.downcase - end -rescue EOFError - abort('Aborted by user') -end - -def migrate(*args) - abort("Unknown arguments '#{args.join(' ')}', aborting") unless args.empty? - - copy_schema, sequent_gem_dir = - begin - [true, Gem::Specification.find_by_name('sequent').gem_dir] - rescue Gem::MissingSpecError - [false, File.expand_path('..', __dir__)] - end - - puts <<~EOS - This script will guide you through upgrading your Sequent application to Sequent 8. - - The Sequent 8 database has been further optimized for disk usage and - performance. In addition it supports partitioning the tables for aggregates, - commands, and events, making it easier to manage the database (VACUUM, - CLUSTER) since these can work on the smaller partition tables. - - It is highly recommended to test this upgrade on a copy of your production database first. - - This script will guide you through the following steps: - - Step 1: Copy the Sequent 8 database schema and - migration files to your project's `db/` directory. When this step is completed you - can customize these files to your liking and commit the changes. - - One decision you need to make is whether you want to define partitions. This is - mainly useful when your database tables are larger than 10 gigabytes or so. By - default Sequent 8 uses a single "default" partition. - - The `db/sequent_schema_partitions.sql` file contains the database partitions for - the `aggregates`, `commands`, and `events` tables, you can customize your - partitions here. - - Step 2: Shutdown your application and the migration script. The script starts a transaction but DOES NOT - commit the results. - - Step 3: Check the results and COMMIT or ROLLBACK the result. If you COMMIT, - you must perform a VACUUM ANALYZE to ensure PostgreSQL can efficiently query - the new tables - - Step 4: Now you can deploy your Sequent 8 based application and start it again. - - EOS - - step = 0 - - if copy_schema - puts <<~EOS - #{step += 1}. First a copy of the Sequent 8 database schema and migration scripts are - added to your db/ directory. - - WARNING: this may overwrite your existing scripts, please use your version control - system to commit or abort any of the changes! - EOS - confirm_or_abort - - FileUtils.copy_entry("#{sequent_gem_dir}/db", 'db') - - puts <<~EOS - WARNING: The schema files have been copied, please verify and adjust the contents - before committing and continuing. - EOS - confirm_or_abort - end - - puts "#{step += 1}. Please shut down your existing application." - confirm_or_abort - - puts <<~EOS - #{step += 1}. Open a `psql` connection to the database you wish to migrate: - - ``` - psql -U myapp_user myapp_db - ``` - EOS - confirm_or_abort - - puts <<~EOS - #{step += 1}. Run the database migration. If you have a large database this - can take some time: - - ``` - psql> \\i db/sequent_8_migration.sql - ``` - EOS - confirm_or_abort - - puts <<~EOS - #{step += 1}. After checking everything went OK, COMMIT and optimize the - database: - - ``` - psql> COMMIT; VACUUM VERBOSE ANALYZE; - ``` - EOS - confirm_or_abort - - puts "#{step}. Deploy your Sequent 8 based application and start it." - confirm_or_abort - - puts 'Congratulations! You are now running your application on Sequent 8!' -end - -def args_valid?(*args) - args.none?(&:empty?) -end - -case command -when 'new' - new_project(*args) -when 'generate', 'g' - generate(*args) -when 'migrate' - migrate(*args) -else - abort("Unknown command #{command}. Try `sequent new myapp`") -end +exit_code = Sequent::Cli::App.run(ARGV) +exit(exit_code) diff --git a/gemfiles/ar_7_1.gemfile.lock b/gemfiles/ar_7_1.gemfile.lock index 98705402..ea9766a7 100644 --- a/gemfiles/ar_7_1.gemfile.lock +++ b/gemfiles/ar_7_1.gemfile.lock @@ -6,6 +6,7 @@ PATH activerecord (>= 7.1.3) bcrypt (~> 3.1) csv (~> 3.3) + gli (~> 2.22) i18n logger (~> 1.6) oj (~> 3.3) @@ -14,6 +15,7 @@ PATH pg (~> 1.2) postgresql_cursor (~> 0.6) thread_safe (~> 0.3.6) + tty-prompt (~> 0.23.1) tzinfo (>= 1.1) GEM @@ -46,9 +48,10 @@ GEM diff-lcs (1.5.1) docile (1.4.1) drb (2.2.1) + gli (2.22.0) i18n (1.14.6) concurrent-ruby (~> 1.0) - json (2.7.2) + json (2.8.1) language_server-protocol (3.17.0.3) logger (1.6.1) method_source (1.1.0) @@ -62,6 +65,8 @@ GEM parser (3.3.5.0) ast (~> 2.4.1) racc + pastel (0.8.0) + tty-color (~> 0.5) pg (1.5.8) postgresql_cursor (0.6.9) activerecord (>= 6.0) @@ -88,7 +93,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.1) - rubocop (1.67.0) + rubocop (1.68.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -98,7 +103,7 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) + rubocop-ast (1.36.1) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) simplecov (0.22.0) @@ -110,9 +115,20 @@ GEM thread_safe (0.3.6) timecop (0.9.10) timeout (0.4.1) + tty-color (0.6.0) + tty-cursor (0.7.1) + tty-prompt (0.23.1) + pastel (~> 0.8) + tty-reader (~> 0.8) + tty-reader (0.9.0) + tty-cursor (~> 0.7) + tty-screen (~> 0.8) + wisper (~> 2.0) + tty-screen (0.8.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) + wisper (2.0.1) PLATFORMS arm64-darwin-22 @@ -129,7 +145,7 @@ DEPENDENCIES rspec (~> 3.10) rspec-collection_matchers (~> 1.2) rspec-mocks (~> 3.10) - rubocop (~> 1.56, >= 1.56.3) + rubocop (~> 1.68.0) sequent! simplecov (~> 0.21) timecop (~> 0.9) diff --git a/gemfiles/ar_7_2.gemfile.lock b/gemfiles/ar_7_2.gemfile.lock index 3a182559..c24c784f 100644 --- a/gemfiles/ar_7_2.gemfile.lock +++ b/gemfiles/ar_7_2.gemfile.lock @@ -6,6 +6,7 @@ PATH activerecord (>= 7.1.3) bcrypt (~> 3.1) csv (~> 3.3) + gli (~> 2.22) i18n logger (~> 1.6) oj (~> 3.3) @@ -14,6 +15,7 @@ PATH pg (~> 1.2) postgresql_cursor (~> 0.6) thread_safe (~> 0.3.6) + tty-prompt (~> 0.23.1) tzinfo (>= 1.1) GEM @@ -47,9 +49,10 @@ GEM diff-lcs (1.5.1) docile (1.4.1) drb (2.2.1) + gli (2.22.0) i18n (1.14.6) concurrent-ruby (~> 1.0) - json (2.7.2) + json (2.8.1) language_server-protocol (3.17.0.3) logger (1.6.1) method_source (1.1.0) @@ -62,6 +65,8 @@ GEM parser (3.3.5.0) ast (~> 2.4.1) racc + pastel (0.8.0) + tty-color (~> 0.5) pg (1.5.8) postgresql_cursor (0.6.9) activerecord (>= 6.0) @@ -88,7 +93,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-support (3.13.1) - rubocop (1.67.0) + rubocop (1.68.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -98,7 +103,7 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) + rubocop-ast (1.36.1) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) securerandom (0.3.1) @@ -111,9 +116,20 @@ GEM thread_safe (0.3.6) timecop (0.9.10) timeout (0.4.1) + tty-color (0.6.0) + tty-cursor (0.7.1) + tty-prompt (0.23.1) + pastel (~> 0.8) + tty-reader (~> 0.8) + tty-reader (0.9.0) + tty-cursor (~> 0.7) + tty-screen (~> 0.8) + wisper (~> 2.0) + tty-screen (0.8.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) + wisper (2.0.1) PLATFORMS arm64-darwin-23 @@ -129,7 +145,7 @@ DEPENDENCIES rspec (~> 3.10) rspec-collection_matchers (~> 1.2) rspec-mocks (~> 3.10) - rubocop (~> 1.56, >= 1.56.3) + rubocop (~> 1.68.0) sequent! simplecov (~> 0.21) timecop (~> 0.9) diff --git a/lib/sequent/cli/app.rb b/lib/sequent/cli/app.rb new file mode 100644 index 00000000..205435f3 --- /dev/null +++ b/lib/sequent/cli/app.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +require_relative '../generator' +require_relative './sequent8_migration' +module Sequent + module Cli + class App + extend GLI::App + + program_desc 'Sequent Command Line Interface (CLI)' + + version Sequent::VERSION + on_error do |_error| + true + end + + desc 'Generate a directory structure for a Sequent project' + command :new do |c| + prompt = TTY::Prompt.new(interrupt: :exit) + + c.arg_name 'project_name' + c.action do |_global, _options, args| + help_now!('can only specify one single argument e.g. `sequent new project_name`') if args&.length != 1 + + project_name = args[0] + Sequent::Generator::Project.new(project_name).execute + prompt.say(<<~EOS) + Success! + + Your brand spanking new sequent app is waiting for you in: + #{File.expand_path(project_name, Dir.pwd)} + + To finish setting up your app: + cd #{project_name} + bundle install + bundle exec rake sequent:db:create + bundle exec rake sequent:db:create_view_schema + bundle exec rake sequent:migrate:online + bundle exec rake sequent:migrate:offline + + Run the example specs: + SEQUENT_ENV=test bundle exec rake sequent:db:create + bundle exec rspec spec + + To generate new aggregates use: + sequent generate . e.g. sequent generate address + + For more information see: + https://www.sequent.io + + Happy coding! + EOS + rescue TargetAlreadyExists + prompt.error("Target '#{project_name}' already exists, aborting") + end + end + + desc 'Generate a new aggregate, command, or event' + command [:generate, :g] do |c| + prompt = TTY::Prompt.new(interrupt: :exit) + + c.arg_name 'aggregate_name' + c.desc 'Generate an aggregate' + c.command :aggregate do |a| + a.action do |_global, _options, args| + if args&.length != 1 + help_now!('must specify one single argument e.g. `sequent generate aggregate Employee`') + end + + aggregate_name = args[0] + + Sequent::Generator::Aggregate.new(aggregate_name).execute + + prompt.say(<<~EOS) + #{aggregate_name} aggregate has been generated + EOS + end + end + + c.desc 'Generate a command' + c.arg_name 'aggregate_name command_name' + c.command :command do |command| + command.action do |_global, _options, args| + if args&.length&.< 2 + help_now!('must specify at least two arguments e.g. `sequent generate command Employee CreateEmployee`') + end + + aggregate_name, command_name, *attributes = args + + Sequent::Generator::Command.new(aggregate_name, command_name, attributes).execute + prompt.say(<<~EOS) + "#{command_name} command has been added to #{aggregate_name}" + EOS + rescue NoAggregateFound + prompt.error("Aggregate '#{aggregate_name}' not found, aborting") + end + end + + c.desc 'Generate an Event' + c.arg_name 'aggregate_name event_name' + c.command :event do |command| + command.action do |_global, _options, args| + if args&.length&.< 2 + help_now!('must specify at least two arguments e.g. `sequent generate event Employee EmployeeCreated`') + end + + aggregate_name, event_name, *attributes = args + + Sequent::Generator::Command.new(aggregate_name, event_name, attributes).execute + prompt.say(<<~EOS) + "#{event_name} event has been added to #{aggregate_name}" + EOS + rescue NoAggregateFound + prompt.error("Aggregate '#{aggregate_name}' not found, aborting") + end + end + end + + desc 'Migrates a Sequent 7 project to Sequent 8' + command :migrate do |c| + prompt = TTY::Prompt.new(interrupt: :exit) + c.action do |_global, _options, _args| + Sequent8Migration.new(prompt).execute + rescue Gem::MissingSpecError + prompt.error('Sequent gem not found. Please check your Gemfile.') + rescue Sequent8Migration::Stop => e + prompt.error(e.message) + end + end + end + end +end diff --git a/lib/sequent/cli/sequent_8_migration.rb b/lib/sequent/cli/sequent_8_migration.rb new file mode 100644 index 00000000..6e07e46b --- /dev/null +++ b/lib/sequent/cli/sequent_8_migration.rb @@ -0,0 +1,180 @@ +# frozen_string_literal: true + +module Sequent + module Cli + class Sequent8Migration + class Stop < StandardError; end + + def initialize(prompt) + @prompt = prompt + end + + # @raise Gem::MissingSpecError + def execute + print_introduction + abort_if_no('Do you wish to start the migration?') + copy_schema_files + abort_if_no('Do you which to continue?') + stop_application + migrate_data + prompt.ask('Press if the migration is done and you checked the results?') + migrated = commit_or_rollback + + if migrated + prompt.say <<~EOS + + Step 5. Deploy your Sequent 8 based application and start it. + + Congratulations! You are now running your application on Sequent 8! + EOS + else + prompt.say <<~EOS + + We are sorry the migration did not succeed. If you think this is a bug in Sequent don't hesitate to reach + out and submit an issue on Github: https://github.com/zilverline/sequent. + + Don't forget to start your application again! + EOS + end + end + + private + + attr_reader :prompt + + def print_introduction + prompt.say <<~EOS + This script will guide you through upgrading your Sequent application to Sequent 8. + + The Sequent 8 database has been further optimized for disk usage and + performance. In addition it supports partitioning the tables for aggregates, + commands, and events, making it easier to manage the database (VACUUM, + CLUSTER) since these can work on the smaller partition tables. + + It is highly recommended to test this upgrade on a copy of your production database first. + + This script consists of the following steps: + + Step 1: Copy the Sequent 8 database schema and + migration files to your project's `db/` directory. When this step is completed you + can customize these files to your liking and commit the changes. + + One decision you need to make is whether you want to define partitions. This is + mainly useful when your database tables are larger than 10 gigabytes or so. By + default Sequent 8 uses a single "default" partition. + + The `db/sequent_schema_partitions.sql` file contains the database partitions for + the `aggregates`, `commands`, and `events` tables, you can customize your + partitions here. + + Step 2: Shutdown your application. + + Step 3: Run the migration script. The script starts a transaction but DOES NOT + commit the results. + + Step 4: Check the results and COMMIT or ROLLBACK the result. If you COMMIT, + you must perform a VACUUM ANALYZE to ensure PostgreSQL can efficiently query + the new tables + + Step 5: Now you can deploy your Sequent 8 based application and start it again. + + EOS + end + + def copy_schema_files + prompt.say <<~EOS + + Step 1. First a copy of the Sequent 8 database schema and migration scripts are + added to your db/ directory. + EOS + prompt.warn <<~EOS + + WARNING: this may overwrite your existing scripts, please use your version control system to commit or abort any of the changes! + EOS + + abort_if_no('Do you which to continue?') + + FileUtils.copy_entry("#{sequent_gem_dir}/db", 'db') + + prompt.warn <<~EOS + + WARNING: The schema files have been copied, please verify and adjust the contents before committing and continuing. + EOS + end + + def stop_application + prompt.say <<~EOS + + Step 2. Please shut down your existing application. + EOS + + abort_if_no(<<~EOS) + Only proceed once your application is stopped. Is your application stopped and do you want to continue? + EOS + end + + def migrate_data + prompt.say <<~EOS + + Step 3. Open a `psql` connection to the database you wish to migrate. + EOS + prompt.warn <<~EOS + + It is highly recommended to test this on a copy of your production database first! + EOS + + prompt.say <<~EOS + + Depending on the size of your database the migration can take a long time. Open the `psql` connection from a screen session if needed. + If you run this from a screen session from another server you will need to copy all needed sql files to that server. + + ``` + psql -U myapp_user myapp_db + ``` + EOS + + prompt.ask('Press to read the next instructions once you connected to the database...') + + prompt.say <<~EOS + + Run the database migration. This doesn't commit anything yet so you can check the results first. + + ``` + psql> \\i db/sequent_8_migration.sql + ``` + EOS + end + + def commit_or_rollback + answer = prompt.yes? 'Did the migration succeed?' + if answer + prompt.say <<~EOS + + Step 4. After checking everything went OK, COMMIT and optimize the database: + + ``` + psql> COMMIT; VACUUM VERBOSE ANALYZE; + ``` + EOS + else + prompt.say <<~EOS + + Step 4. Rollback the migration: + + ``` + psql> ROLLBACK; + ``` + EOS + end + answer + end + + def sequent_gem_dir = Gem::Specification.find_by_name('sequent').gem_dir + + def abort_if_no(message, abort_message: 'Stopped at your request. You can restart this migration at any time.') + answer = prompt.yes?(message) + fail Stop, abort_message unless answer + end + end + end +end diff --git a/sequent.gemspec b/sequent.gemspec index d8ca9279..1ab5b920 100644 --- a/sequent.gemspec +++ b/sequent.gemspec @@ -31,6 +31,7 @@ Gem::Specification.new do |s| s.add_dependency 'activerecord', active_star_version s.add_dependency 'bcrypt', '~> 3.1' s.add_dependency 'csv', '~> 3.3' + s.add_dependency 'gli', '~> 2.22' s.add_dependency 'i18n' s.add_dependency 'logger', '~> 1.6' s.add_dependency 'oj', '~> 3.3' @@ -39,6 +40,7 @@ Gem::Specification.new do |s| s.add_dependency 'pg', '~> 1.2' s.add_dependency 'postgresql_cursor', '~> 0.6' s.add_dependency 'thread_safe', '~> 0.3.6' + s.add_dependency 'tty-prompt', '~> 0.23.1' s.add_dependency 'tzinfo', '>= 1.1' s.add_development_dependency 'prop_check', '~> 1.0' s.add_development_dependency 'pry', '~> 0.13' @@ -46,7 +48,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'rspec', rspec_version s.add_development_dependency 'rspec-collection_matchers', '~> 1.2' s.add_development_dependency 'rspec-mocks', rspec_version - s.add_development_dependency 'rubocop', '~> 1.56', '>= 1.56.3' + s.add_development_dependency 'rubocop', '~> 1.68.0' s.add_development_dependency 'simplecov', '~> 0.21' s.add_development_dependency 'timecop', '~> 0.9' end From 79996bc2e9713e43ef00837daf46172c38d4665c Mon Sep 17 00:00:00 2001 From: Lars Vonk Date: Thu, 14 Nov 2024 12:08:08 +0100 Subject: [PATCH 2/3] Enable all new rubocops And fix the warnings. --- .rubocop.yml | 195 +----------------- .../config/environments/production.rb | 2 +- .../rails-app/spec/rails_helper.rb | 2 +- lib/sequent/cli/app.rb | 2 +- lib/sequent/core/helpers/array_with_type.rb | 2 +- .../core/helpers/association_validator.rb | 4 +- lib/sequent/core/helpers/attribute_support.rb | 15 +- lib/sequent/core/helpers/equal_support.rb | 6 +- .../helpers/message_matchers/has_attrs.rb | 2 + lib/sequent/core/helpers/message_router.rb | 4 +- lib/sequent/core/helpers/param_support.rb | 4 +- lib/sequent/core/helpers/string_support.rb | 2 +- .../persistors/active_record_persistor.rb | 2 +- .../replay_optimized_postgres_persistor.rb | 7 +- lib/sequent/core/projector.rb | 2 +- lib/sequent/generator.rb | 2 +- lib/sequent/migrations/grouper.rb | 4 +- lib/sequent/migrations/view_schema.rb | 12 +- lib/sequent/test/time_comparison.rb | 2 +- sequent.gemspec | 1 + spec/database.rb | 6 +- spec/lib/sequent/configuration_spec.rb | 4 +- .../helpers/association_validator_spec.rb | 4 +- spec/lib/sequent/core/projector_spec.rb | 2 +- spec/spec_helper.rb | 2 +- 25 files changed, 49 insertions(+), 241 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 65e12ae3..4a60737e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -14,6 +14,7 @@ AllCops: SuggestExtensions: rubocop-rake: false rubocop-rspec: false + NewCops: enable Exclude: # default - '**/node_modules/**/*' @@ -308,219 +309,29 @@ Style/SoleNestedConditional: Style/EvalWithLocation: Enabled: false - -Layout/SpaceBeforeBrackets: # (new in 1.7) - Enabled: false -Lint/AmbiguousAssignment: # (new in 1.7) - Enabled: false -Lint/DeprecatedConstants: # (new in 1.8) - Enabled: false -Lint/DuplicateBranch: # (new in 1.3) - Enabled: false -Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1) - Enabled: false Lint/EmptyBlock: # (new in 1.1) Enabled: false Lint/EmptyClass: # (new in 1.3) Enabled: false -Lint/LambdaWithoutLiteralBlock: # (new in 1.8) - Enabled: false -Lint/NoReturnInBeginEndBlocks: # (new in 1.2) - Enabled: false -Lint/NumberedParameterAssignment: # (new in 1.9) - Enabled: false -Lint/OrAssignmentToConstant: # (new in 1.9) - Enabled: false -Lint/RedundantDirGlobSort: # (new in 1.8) - Enabled: false Lint/SymbolConversion: # (new in 1.9) Enabled: false -Lint/ToEnumArguments: # (new in 1.1) - Enabled: false -Lint/TripleQuotes: # (new in 1.9) - Enabled: false -Lint/UnexpectedBlockArity: # (new in 1.5) - Enabled: false -Lint/UnmodifiedReduceAccumulator: # (new in 1.1) - Enabled: false Style/ArgumentsForwarding: # (new in 1.1) Enabled: false -Style/CollectionCompact: # (new in 1.2) - Enabled: false Style/DocumentDynamicEvalDefinition: # (new in 1.1) Enabled: false -Style/EndlessMethod: # (new in 1.8) - Enabled: false -Style/HashExcept: # (new in 1.7) - Enabled: false -Style/IfWithBooleanLiteralBranches: # (new in 1.9) - Enabled: false Style/NegatedIfElseCondition: # (new in 1.2) Enabled: false -Style/NilLambda: # (new in 1.3) - Enabled: false -Style/RedundantArgument: # (new in 1.4) - Enabled: false -Style/SwapValues: # (new in 1.1) - Enabled: false -Style/StringConcatenation: - Enabled: false -Style/HashEachMethods: - Enabled: false -Lint/RedundantSafeNavigation: - Enabled: false -Style/HashTransformValues: - Enabled: false -Lint/FloatComparison: - Enabled: false Style/ClassVars: Enabled: false -Layout/LineEndStringConcatenationIndentation: # new in 1.18 - Enabled: false -Lint/AmbiguousRange: # new in 1.19 - Enabled: false -Lint/EmptyInPattern: # new in 1.16 - Enabled: false -Naming/InclusiveLanguage: # new in 1.18 - Enabled: false -Style/HashConversion: # new in 1.10 - Enabled: false -Style/InPatternThen: # new in 1.16 - Enabled: false -Style/MultilineInPatternThen: # new in 1.16 - Enabled: false -Style/QuotedSymbols: # new in 1.16 - Enabled: false -Style/RedundantSelfAssignmentBranch: # new in 1.19 - Enabled: false -Style/StringChars: # new in 1.12 - Enabled: false -# new since rubny 3.2 -Gemspec/DeprecatedAttributeAssignment: # new in 1.30 - Enabled: false Gemspec/DevelopmentDependencies: # new in 1.44 Enabled: false -Gemspec/RequireMFA: # new in 1.23 - Enabled: false -Layout/LineContinuationLeadingSpace: # new in 1.31 - Enabled: false -Layout/LineContinuationSpacing: # new in 1.31 - Enabled: false -Lint/AmbiguousOperatorPrecedence: # new in 1.21 - Enabled: false -Lint/ConstantOverwrittenInRescue: # new in 1.31 - Enabled: false -Lint/DuplicateMagicComment: # new in 1.37 - Enabled: false -Lint/DuplicateMatchPattern: # new in 1.50 - Enabled: false -Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21 - Enabled: false -Lint/MixedCaseRange: # new in 1.53 - Enabled: false -Lint/NonAtomicFileOperation: # new in 1.31 - Enabled: false -Lint/RedundantRegexpQuantifiers: # new in 1.53 - Enabled: false -Lint/RefinementImportMethods: # new in 1.27 - Enabled: false -Lint/RequireRangeParentheses: # new in 1.32 - Enabled: false -Lint/RequireRelativeSelfPath: # new in 1.22 - Enabled: false -Lint/UselessRescue: # new in 1.43 - Enabled: false -Lint/UselessRuby2Keywords: # new in 1.23 - Enabled: false -Metrics/CollectionLiteralLength: # new in 1.47 - Enabled: false Naming/BlockForwarding: # new in 1.24 Enabled: false Security/CompoundHash: # new in 1.28 Enabled: false -Security/IoMethods: # new in 1.22 - Enabled: false -Style/ArrayIntersect: # new in 1.40 - Enabled: false -Style/ComparableClamp: # new in 1.44 - Enabled: false -Style/ConcatArrayLiterals: # new in 1.41 - Enabled: false -Style/DataInheritance: # new in 1.49 - Enabled: false -Style/DirEmpty: # new in 1.48 - Enabled: false -Style/EmptyHeredoc: # new in 1.32 - Enabled: false -Style/EnvHome: # new in 1.29 - Enabled: false -Style/ExactRegexpMatch: # new in 1.51 - Enabled: false Style/FetchEnvVar: # new in 1.28 Enabled: false -Style/FileEmpty: # new in 1.48 - Enabled: false -Style/FileRead: # new in 1.24 - Enabled: false -Style/FileWrite: # new in 1.24 - Enabled: false -Style/MagicCommentFormat: # new in 1.35 - Enabled: false -Style/MapCompactWithConditionalBlock: # new in 1.30 - Enabled: false -Style/MapToHash: # new in 1.24 - Enabled: false -Style/MapToSet: # new in 1.42 - Enabled: false -Style/MinMaxComparison: # new in 1.42 - Enabled: false -Style/NestedFileDirname: # new in 1.26 - Enabled: false -Style/NumberedParameters: # new in 1.22 - Enabled: false -Style/NumberedParametersLimit: # new in 1.22 - Enabled: false Style/ObjectThen: # new in 1.28 Enabled: false -Style/OpenStructUse: # new in 1.23 - Enabled: false -Style/OperatorMethodCall: # new in 1.37 - Enabled: false -Style/RedundantArrayConstructor: # new in 1.52 - Enabled: false -Style/RedundantConstantBase: # new in 1.40 - Enabled: false -Style/RedundantCurrentDirectoryInPath: # new in 1.53 - Enabled: false -Style/RedundantDoubleSplatHashBraces: # new in 1.41 - Enabled: false -Style/RedundantEach: # new in 1.38 - Enabled: false -Style/RedundantFilterChain: # new in 1.52 - Enabled: false -Style/RedundantHeredocDelimiterQuotes: # new in 1.45 - Enabled: false -Style/RedundantInitialize: # new in 1.27 - Enabled: false -Style/RedundantLineContinuation: # new in 1.49 - Enabled: false -Style/RedundantRegexpArgument: # new in 1.53 - Enabled: false -Style/RedundantRegexpConstructor: # new in 1.52 - Enabled: false -Style/RedundantStringEscape: # new in 1.37 - Enabled: false -Style/ReturnNilInPredicateMethodDefinition: # new in 1.53 - Enabled: false -Style/SelectByRegexp: # new in 1.22 - Enabled: false -Style/YAMLFileRead: # new in 1.53 - Enabled: false -Style/HashSyntax: - Enabled: false -Lint/RedundantRequireStatement: - Enabled: false -Lint/AmbiguousRegexpLiteral: - Enabled: false -Style/SafeNavigation: - Enabled: false +Style/SafeNavigationChainLength: + Enabled: false \ No newline at end of file diff --git a/integration-specs/rails-app/config/environments/production.rb b/integration-specs/rails-app/config/environments/production.rb index 14032033..a9501c09 100644 --- a/integration-specs/rails-app/config/environments/production.rb +++ b/integration-specs/rails-app/config/environments/production.rb @@ -78,7 +78,7 @@ config.active_support.report_deprecations = false # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new # Use a different logger for distributed setups. # require "syslog/logger" diff --git a/integration-specs/rails-app/spec/rails_helper.rb b/integration-specs/rails-app/spec/rails_helper.rb index a5c3a0d3..485afb09 100644 --- a/integration-specs/rails-app/spec/rails_helper.rb +++ b/integration-specs/rails-app/spec/rails_helper.rb @@ -33,7 +33,7 @@ end RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.fixture_path = "#{Rails.root}/spec/fixtures" # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false diff --git a/lib/sequent/cli/app.rb b/lib/sequent/cli/app.rb index 205435f3..854f752e 100644 --- a/lib/sequent/cli/app.rb +++ b/lib/sequent/cli/app.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative '../generator' -require_relative './sequent8_migration' +require_relative 'sequent8_migration' module Sequent module Cli class App diff --git a/lib/sequent/core/helpers/array_with_type.rb b/lib/sequent/core/helpers/array_with_type.rb index 0c6393ac..6d20501c 100644 --- a/lib/sequent/core/helpers/array_with_type.rb +++ b/lib/sequent/core/helpers/array_with_type.rb @@ -13,7 +13,7 @@ def initialize(item_type) end def deserialize_from_json(value) - value.nil? ? nil : value.map { |item| item_type.deserialize_from_json(item) } + value&.map { |item| item_type.deserialize_from_json(item) } end def to_s diff --git a/lib/sequent/core/helpers/association_validator.rb b/lib/sequent/core/helpers/association_validator.rb index 3e79f060..8b16f015 100644 --- a/lib/sequent/core/helpers/association_validator.rb +++ b/lib/sequent/core/helpers/association_validator.rb @@ -35,7 +35,7 @@ def validate(record) value = record.instance_variable_get("@#{association}") if value && incorrect_type?(value, record, association) record.errors.add(association, "is not of type #{describe_type(record.class.types[association])}") - elsif value&.is_a?(Array) + elsif value.is_a?(Array) item_type = record.class.types.fetch(association).item_type record.errors.add(association, 'is invalid') unless validate_all(value, item_type).all? elsif value&.invalid? @@ -47,7 +47,7 @@ def validate(record) private def incorrect_type?(value, record, association) - return unless record.class.respond_to?(:types) + return false unless record.class.respond_to?(:types) type = record.class.types[association] if type.respond_to?(:candidate?) diff --git a/lib/sequent/core/helpers/attribute_support.rb b/lib/sequent/core/helpers/attribute_support.rb index 83545a9a..1173491c 100644 --- a/lib/sequent/core/helpers/attribute_support.rb +++ b/lib/sequent/core/helpers/attribute_support.rb @@ -63,12 +63,11 @@ def attrs(args) Sequent::Core::Helpers::DefaultValidators.for(type).add_validations_for(self, attribute) end - if type.instance_of?(Sequent::Core::Helpers::ArrayWithType) - associations << attribute - elsif included_modules.include?(ActiveModel::Validations) && - type.included_modules.include?(Sequent::Core::Helpers::AttributeSupport) - associations << attribute - end + next unless type.instance_of?(Sequent::Core::Helpers::ArrayWithType) || + (included_modules.include?(ActiveModel::Validations) && + type.included_modules.include?(Sequent::Core::Helpers::AttributeSupport)) + + associations << attribute end if included_modules.include?(ActiveModel::Validations) && associations.present? validates_with Sequent::Core::Helpers::AssociationValidator, associations: associations @@ -168,7 +167,7 @@ def self.included(host_class) def attributes hash = HashWithIndifferentAccess.new - self.class.types.each do |name, _| + self.class.types.each_key do |name| value = instance_variable_get("@#{name}") hash[name] = if value.respond_to?(:attributes) value.attributes @@ -181,7 +180,7 @@ def attributes def as_json(opts = {}) hash = HashWithIndifferentAccess.new - self.class.types.each do |name, _| + self.class.types.each_key do |name| value = instance_variable_get("@#{name}") hash[name] = if value.respond_to?(:as_json) value.as_json(opts) diff --git a/lib/sequent/core/helpers/equal_support.rb b/lib/sequent/core/helpers/equal_support.rb index d0a327ca..5ed7bd48 100644 --- a/lib/sequent/core/helpers/equal_support.rb +++ b/lib/sequent/core/helpers/equal_support.rb @@ -13,7 +13,7 @@ def ==(other) return false if other.nil? return false if self.class != other.class - self.class.types.each do |name, _| + self.class.types.each_key do |name| self_value = send(name) other_value = other.send(name) if self_value.class == DateTime && other_value.class == DateTime @@ -28,8 +28,8 @@ def ==(other) def hash hash = 17 - self.class.types.each do |name, _| - hash = hash * 31 + send(name).hash + self.class.types.each_key do |name| + hash = (hash * 31) + send(name).hash end hash end diff --git a/lib/sequent/core/helpers/message_matchers/has_attrs.rb b/lib/sequent/core/helpers/message_matchers/has_attrs.rb index b17043c0..0b21c8f7 100644 --- a/lib/sequent/core/helpers/message_matchers/has_attrs.rb +++ b/lib/sequent/core/helpers/message_matchers/has_attrs.rb @@ -20,10 +20,12 @@ def matches_message?(message) end def to_s + # rubocop:disable Layout/LineEndStringConcatenationIndentation 'has_attrs(' \ "#{MessageMatchers::ArgumentSerializer.serialize_value(message_matcher)}, " \ "#{AttrMatchers::ArgumentSerializer.serialize_value(expected_attrs)}" \ ')' + # rubocop:enable Layout/LineEndStringConcatenationIndentation end private diff --git a/lib/sequent/core/helpers/message_router.rb b/lib/sequent/core/helpers/message_router.rb index c45e247c..f898c728 100644 --- a/lib/sequent/core/helpers/message_router.rb +++ b/lib/sequent/core/helpers/message_router.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative './attr_matchers/attr_matchers' -require_relative './message_matchers/message_matchers' +require_relative 'attr_matchers/attr_matchers' +require_relative 'message_matchers/message_matchers' module Sequent module Core diff --git a/lib/sequent/core/helpers/param_support.rb b/lib/sequent/core/helpers/param_support.rb index 4f794d34..d2c38589 100644 --- a/lib/sequent/core/helpers/param_support.rb +++ b/lib/sequent/core/helpers/param_support.rb @@ -79,9 +79,7 @@ def as_params def value_to_string(val) if val.is_a?(Sequent::Core::ValueObject) val.as_params - elsif val.is_a? DateTime - val.iso8601 - elsif val.is_a? Date + elsif val.is_a?(DateTime) || val.is_a?(Date) val.iso8601 elsif val.is_a? Time val.iso8601(Sequent.configuration.time_precision) diff --git a/lib/sequent/core/helpers/string_support.rb b/lib/sequent/core/helpers/string_support.rb index 9094f2c0..b19ed2b1 100644 --- a/lib/sequent/core/helpers/string_support.rb +++ b/lib/sequent/core/helpers/string_support.rb @@ -15,7 +15,7 @@ def to_s value = instance_variable_get(name.to_s) s += "#{name}=[#{value}], " end - '{' + s.chomp(', ') + '}' + "{#{s.chomp(', ')}}" end end end diff --git a/lib/sequent/core/persistors/active_record_persistor.rb b/lib/sequent/core/persistors/active_record_persistor.rb index b281110b..9581c8f7 100644 --- a/lib/sequent/core/persistors/active_record_persistor.rb +++ b/lib/sequent/core/persistors/active_record_persistor.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'active_record' -require_relative './persistor' +require_relative 'persistor' module Sequent module Core diff --git a/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb b/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb index 0ccea2df..4bbbc384 100644 --- a/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb +++ b/lib/sequent/core/persistors/replay_optimized_postgres_persistor.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true -require 'set' require 'active_record' require 'csv' -require_relative './persistor' +require_relative 'persistor' module Sequent module Core @@ -177,7 +176,7 @@ def initialize(insert_with_csv_size = 50, indices = {}, default_indexed_columns end indices.each do |record_class, indexed_columns| - columns = indexed_columns.flatten(1).map(&:to_sym).to_set + default_indexed_columns + columns = indexed_columns.flatten(1).to_set(&:to_sym) + default_indexed_columns @record_index[record_class] = Index.new(columns & record_class.column_names.map(&:to_sym)) end @@ -358,7 +357,7 @@ def commit def clear @record_store.clear - @record_index.values.each(&:clear) + @record_index.each_value(&:clear) end private diff --git a/lib/sequent/core/projector.rb b/lib/sequent/core/projector.rb index a69558a9..9f93949e 100644 --- a/lib/sequent/core/projector.rb +++ b/lib/sequent/core/projector.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative 'helpers/message_handler' -require_relative './persistors/active_record_persistor' +require_relative 'persistors/active_record_persistor' module Sequent module Core diff --git a/lib/sequent/generator.rb b/lib/sequent/generator.rb index affa0183..0b066d1f 100644 --- a/lib/sequent/generator.rb +++ b/lib/sequent/generator.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -require_relative './generator/generator' +require_relative 'generator/generator' diff --git a/lib/sequent/migrations/grouper.rb b/lib/sequent/migrations/grouper.rb index 6ba14a8b..b8548635 100644 --- a/lib/sequent/migrations/grouper.rb +++ b/lib/sequent/migrations/grouper.rb @@ -56,7 +56,7 @@ def self.group_partitions(partitions, target_group_size) current_size = 0 else taken = target_group_size - current_size - upper_bound = partition.lower_bound + UUID_COUNT * taken / partition.original_size + upper_bound = partition.lower_bound + (UUID_COUNT * taken / partition.original_size) result << (current_start..GroupEndpoint.new(partition.key, number_to_uuid(upper_bound - 1))) @@ -79,7 +79,7 @@ def self.number_to_uuid(number) end def self.uuid_to_number(uuid) - Integer(uuid.gsub(/-/, ''), 16) + Integer(uuid.gsub('-', ''), 16) end UUID_COUNT = 2**128 diff --git a/lib/sequent/migrations/view_schema.rb b/lib/sequent/migrations/view_schema.rb index 4b32c610..9540a782 100644 --- a/lib/sequent/migrations/view_schema.rb +++ b/lib/sequent/migrations/view_schema.rb @@ -8,7 +8,7 @@ require_relative '../sequent' require_relative '../util/timer' require_relative '../util/printer' -require_relative './projectors' +require_relative 'projectors' require_relative 'planner' require_relative 'executor' require_relative 'sql' @@ -205,17 +205,15 @@ def migrate_online Versions.end_online!(Sequent.new_version) end Sequent.logger.info("Done migrate_online for version #{Sequent.new_version}") - rescue ConcurrentMigration - # Do not rollback the migration when this is a concurrent migration as the other one is running - raise - rescue InvalidMigrationDefinition - # Do not rollback the migration when since there is nothing to rollback + rescue ConcurrentMigration, InvalidMigrationDefinition + # ConcurrentMigration: Do not rollback the migration when this is a concurrent migration + # as the other one is running + # InvalidMigrationDefinition: Do not rollback the migration when since there is nothing to rollback raise rescue Exception => e # rubocop:disable Lint/RescueException rollback_migration raise e end - ## # Last part of a view schema migration # diff --git a/lib/sequent/test/time_comparison.rb b/lib/sequent/test/time_comparison.rb index 76689757..8c41e368 100644 --- a/lib/sequent/test/time_comparison.rb +++ b/lib/sequent/test/time_comparison.rb @@ -16,7 +16,7 @@ module Compare # omit nsec in datetime comparisons def <=>(other) - if other&.is_a?(DateTimePatches::Normalize) + if other.is_a?(DateTimePatches::Normalize) precision = Sequent.configuration.time_precision return normalize.iso8601(precision) <=> other.normalize.iso8601(precision) end diff --git a/sequent.gemspec b/sequent.gemspec index 1ab5b920..4bcfd5ce 100644 --- a/sequent.gemspec +++ b/sequent.gemspec @@ -51,4 +51,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'rubocop', '~> 1.68.0' s.add_development_dependency 'simplecov', '~> 0.21' s.add_development_dependency 'timecop', '~> 0.9' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/spec/database.rb b/spec/database.rb index 4a63a22b..a489bda4 100644 --- a/spec/database.rb +++ b/spec/database.rb @@ -29,8 +29,8 @@ def test_config(database_name: 'sequent_spec_db') username: 'sequent', password: 'sequent', database: database_name, - schema_search_path: "#{Sequent.configuration.view_schema_name},"\ - "#{Sequent.configuration.event_store_schema_name},public", + schema_search_path: "#{Sequent.configuration.view_schema_name}," \ + "#{Sequent.configuration.event_store_schema_name},public", advisory_locks: false, }, }, @@ -43,7 +43,7 @@ def test_config(database_name: 'sequent_spec_db') username: 'sequent', password: 'sequent', database: database_name, - schema_search_path: "#{Sequent.configuration.view_schema_name},"\ + schema_search_path: "#{Sequent.configuration.view_schema_name}," \ "#{Sequent.configuration.event_store_schema_name},public", advisory_locks: false, }, diff --git a/spec/lib/sequent/configuration_spec.rb b/spec/lib/sequent/configuration_spec.rb index 4d4e40c2..3261675f 100644 --- a/spec/lib/sequent/configuration_spec.rb +++ b/spec/lib/sequent/configuration_spec.rb @@ -68,7 +68,7 @@ def repository config.enable_autoregistration = true config.command_handlers = [command_handler_class.new] end - end.to raise_error /is registered 2 times. A CommandHandler can only be registered once/ + end.to raise_error(/is registered 2 times. A CommandHandler can only be registered once/) end end @@ -82,7 +82,7 @@ def repository config.enable_autoregistration = true config.event_handlers = [event_handler_class.new] end - end.to raise_error /is registered 2 times. An EventHandler can only be registered once/ + end.to raise_error(/is registered 2 times. An EventHandler can only be registered once/) end end end diff --git a/spec/lib/sequent/core/helpers/association_validator_spec.rb b/spec/lib/sequent/core/helpers/association_validator_spec.rb index 19c76c9d..8b8a023f 100644 --- a/spec/lib/sequent/core/helpers/association_validator_spec.rb +++ b/spec/lib/sequent/core/helpers/association_validator_spec.rb @@ -7,12 +7,12 @@ let(:subject) { Sequent::Core::Helpers::AssociationValidator.new(options) } it 'fails when providing no associations' do - expect { subject }.to raise_error /Must provide ':associations' to validate/ + expect { subject }.to raise_error(/Must provide ':associations' to validate/) end it 'fails when provind an empty list of associations' do options[:associations] = [] - expect { subject }.to raise_error /Must provide ':associations' to validate/ + expect { subject }.to raise_error(/Must provide ':associations' to validate/) end context 'validating an array with simple types' do diff --git a/spec/lib/sequent/core/projector_spec.rb b/spec/lib/sequent/core/projector_spec.rb index e7397f04..f07a67e8 100644 --- a/spec/lib/sequent/core/projector_spec.rb +++ b/spec/lib/sequent/core/projector_spec.rb @@ -9,6 +9,6 @@ class TestProjector1 < Sequent::Core::Projector end expect do Sequent.configuration.event_handlers << TestProjector1.new - end.to raise_error /A Projector must manage at least one table/ + end.to raise_error(/A Projector must manage at least one table/) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1a2db7a0..28c0e80f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,7 +9,7 @@ require 'timecop' require_relative '../lib/sequent' require_relative '../lib/sequent/generator' -require_relative './lib/sequent/fixtures/fixtures' +require_relative 'lib/sequent/fixtures/fixtures' require './lib/sequent/test/database_helpers' require 'simplecov' SimpleCov.start if ENV['COVERAGE'] From 4ccb60f289c1391754dad8f8383fde250e79c261 Mon Sep 17 00:00:00 2001 From: Lars Vonk Date: Fri, 15 Nov 2024 14:04:09 +0100 Subject: [PATCH 3/3] Simplify unless to if --- lib/sequent/core/helpers/attribute_support.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/sequent/core/helpers/attribute_support.rb b/lib/sequent/core/helpers/attribute_support.rb index 1173491c..034c3b65 100644 --- a/lib/sequent/core/helpers/attribute_support.rb +++ b/lib/sequent/core/helpers/attribute_support.rb @@ -63,12 +63,13 @@ def attrs(args) Sequent::Core::Helpers::DefaultValidators.for(type).add_validations_for(self, attribute) end - next unless type.instance_of?(Sequent::Core::Helpers::ArrayWithType) || - (included_modules.include?(ActiveModel::Validations) && - type.included_modules.include?(Sequent::Core::Helpers::AttributeSupport)) + is_array = type.instance_of?(Sequent::Core::Helpers::ArrayWithType) + needs_validation = !is_array && included_modules.include?(ActiveModel::Validations) && + type.included_modules.include?(Sequent::Core::Helpers::AttributeSupport) - associations << attribute + associations << attribute if is_array || needs_validation end + if included_modules.include?(ActiveModel::Validations) && associations.present? validates_with Sequent::Core::Helpers::AssociationValidator, associations: associations end