From ffc336c9e2012189c5ad2e5fb2cc5cf2e3f8faac Mon Sep 17 00:00:00 2001 From: Jamie Schembri Date: Wed, 30 Jul 2025 10:13:15 +0200 Subject: [PATCH 1/4] chore(lint): apply autocorrections --- Gemfile | 20 +++++----- Rakefile | 4 +- enummer.gemspec | 29 ++++++++------- lib/enummer.rb | 8 ++-- lib/enummer/enummer_type.rb | 4 +- lib/enummer/extension.rb | 2 +- lib/enummer/railtie.rb | 2 +- lib/enummer/version.rb | 2 +- test/enummer_test.rb | 74 ++++++++++++++++++------------------- test/test_helper.rb | 18 ++++----- 10 files changed, 82 insertions(+), 81 deletions(-) diff --git a/Gemfile b/Gemfile index 787260a..eb46e7a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,29 +1,29 @@ # frozen_string_literal: true -source "https://rubygems.org" +source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in enummer.gemspec. gemspec -gem "rubocop-rails" -gem "bundler-audit" -gem "standard" -gem "rails", "~> 7.1.0" +gem 'bundler-audit' +gem 'rails', '~> 7.1.0' +gem 'rubocop-rails' +gem 'standard' group :test do - gem "simplecov", require: false - gem "simplecov-cobertura", require: false + gem 'simplecov', require: false + gem 'simplecov-cobertura', require: false end group :postgres do - gem "pg" + gem 'pg' end group :mysql do - gem "mysql2" + gem 'mysql2' end group :sqlite do - gem "sqlite3", "~> 1.4" + gem 'sqlite3', '~> 1.4' end diff --git a/Rakefile b/Rakefile index 33669d1..1df0f4d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ # frozen_string_literal: true -require "bundler/setup" +require 'bundler/setup' -require "bundler/gem_tasks" +require 'bundler/gem_tasks' diff --git a/enummer.gemspec b/enummer.gemspec index 0c8b6b2..4ddd30d 100644 --- a/enummer.gemspec +++ b/enummer.gemspec @@ -1,25 +1,26 @@ # frozen_string_literal: true -require_relative "lib/enummer/version" +require_relative 'lib/enummer/version' Gem::Specification.new do |spec| - spec.name = "enummer" + spec.name = 'enummer' spec.version = Enummer::VERSION - spec.authors = ["Jamie Schembri"] - spec.email = ["jamie@schembri.me"] - spec.homepage = "https://github.com/shkm/enummer" - spec.summary = "Multi-value enums for Rails." - spec.description = "Enummer implements multi-value enums with bitwise operations." - spec.license = "MIT" + spec.authors = ['Jamie Schembri'] + spec.email = ['jamie@schembri.me'] + spec.homepage = 'https://github.com/shkm/enummer' + spec.summary = 'Multi-value enums for Rails.' + spec.description = 'Enummer implements multi-value enums with bitwise operations.' + spec.license = 'MIT' - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "https://github.com/shkm/enummer" - spec.metadata["changelog_uri"] = "https://github.com/shkm/enummer/CHANGELOG.md" + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://github.com/shkm/enummer' + spec.metadata['changelog_uri'] = 'https://github.com/shkm/enummer/CHANGELOG.md' spec.files = Dir.chdir(File.expand_path(__dir__)) do - Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] + Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md'] end - spec.required_ruby_version = ">= 3.1" - spec.add_dependency "rails", ">= 7.0.0" + spec.required_ruby_version = '>= 3.1' + spec.add_dependency 'rails', '>= 7.0.0' + spec.metadata['rubygems_mfa_required'] = 'true' end diff --git a/lib/enummer.rb b/lib/enummer.rb index c68755d..3e8777b 100644 --- a/lib/enummer.rb +++ b/lib/enummer.rb @@ -2,7 +2,7 @@ module Enummer; end -require "enummer/version" -require "enummer/enummer_type" -require "enummer/extension" -require "enummer/railtie" +require 'enummer/version' +require 'enummer/enummer_type' +require 'enummer/extension' +require 'enummer/railtie' diff --git a/lib/enummer/enummer_type.rb b/lib/enummer/enummer_type.rb index d39e761..3e113d0 100644 --- a/lib/enummer/enummer_type.rb +++ b/lib/enummer/enummer_type.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "active_record/type" +require 'active_record/type' module Enummer class EnummerType < ::ActiveRecord::Type::Value @@ -13,7 +13,7 @@ def initialize(values:) # @example # :enummer[read|write|execute] def type - :"enummer[#{@values.keys.join("|")}]" + :"enummer[#{@values.keys.join('|')}]" end # @param [Symbol|Array] value Current value represented as one or more symbols diff --git a/lib/enummer/extension.rb b/lib/enummer/extension.rb index e1c881b..90efec1 100644 --- a/lib/enummer/extension.rb +++ b/lib/enummer/extension.rb @@ -59,7 +59,7 @@ def _enummer_method_name(attribute_name, value_name, options) prefix = _enummer_affix(attribute_name, options[:_prefix]) suffix = _enummer_affix(attribute_name, options[:_suffix]) - [prefix, value_name, suffix].compact.join("_") + [prefix, value_name, suffix].compact.join('_') end def _enummer_affix(attribute_name, value) diff --git a/lib/enummer/railtie.rb b/lib/enummer/railtie.rb index b6e58ef..17b4dd6 100644 --- a/lib/enummer/railtie.rb +++ b/lib/enummer/railtie.rb @@ -2,7 +2,7 @@ module Enummer class Railtie < ::Rails::Railtie - initializer "enummer" do + initializer 'enummer' do ActiveSupport.on_load(:active_record) do ActiveRecord::Type.register(:enummer, EnummerType) extend Enummer::Extension diff --git a/lib/enummer/version.rb b/lib/enummer/version.rb index 9544213..44b925a 100644 --- a/lib/enummer/version.rb +++ b/lib/enummer/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Enummer - VERSION = "1.1.0" + VERSION = '1.1.0' end diff --git a/test/enummer_test.rb b/test/enummer_test.rb index 3c7d8f2..6a86095 100644 --- a/test/enummer_test.rb +++ b/test/enummer_test.rb @@ -1,62 +1,62 @@ # frozen_string_literal: true -require "test_helper" +require 'test_helper' class EnummerTest < ActiveSupport::TestCase def setup @user1 = User.new(permissions: %i[read write execute], - facial_features: %i[nose], - diets: %i[cigarettes alcohol], - transport: %i[submarine], - home: %i[box]) + facial_features: %i[nose], + diets: %i[cigarettes alcohol], + transport: %i[submarine], + home: %i[box]) @user2 = User.new(permissions: %i[read write], diets: %i[cigarettes]) @user3 = User.new(permissions: %i[execute]) [@user1, @user2, @user3].map { |user| user.save && user.reload } end - test "it has a version number" do + test 'it has a version number' do assert Enummer::VERSION end - test "get list of all valid values" do + test 'get list of all valid values' do assert_equal %i[read write execute], User.permissions end - test "plain scopes return users with those values set" do + test 'plain scopes return users with those values set' do assert_equal [@user1, @user2], User.read assert_equal [@user1, @user2], User.write assert_equal [@user1, @user3], User.execute end - test "with_ scope returns users with all of those bits set" do + test 'with_ scope returns users with all of those bits set' do assert_equal [@user1], User.with_permissions(%i[execute read write]) assert_equal [@user1], User.with_permissions(%w[execute read write]) - assert_equal [@user1, @user2], User.with_permissions(["read", :write]) + assert_equal [@user1, @user2], User.with_permissions(['read', :write]) assert_equal [@user1, @user2], User.with_diets(%i[cigarettes]) end - test "not scopes return users without those bits set" do + test 'not scopes return users without those bits set' do assert_equal [@user3], User.not_read assert_equal [@user3], User.not_write assert_equal [@user2], User.not_execute end - test "it serializes into a numeric" do + test 'it serializes into a numeric' do assert_equal 3, @user2.permissions_before_type_cast end - test "it deserializes into an array of values" do + test 'it deserializes into an array of values' do assert_equal %i[read write], @user2.permissions end - test "it generates object query methods" do + test 'it generates object query methods' do assert @user2.read? assert @user2.write? - refute @user2.execute? + assert_not @user2.execute? end - test "setting a setter to true adds the value" do + test 'setting a setter to true adds the value' do @user3.read = true assert_equal %i[execute read], @user3.permissions @@ -66,7 +66,7 @@ def setup assert_equal %i[execute read].sort, @user3.permissions.sort end - test "setting a setter to false removes the value" do + test 'setting a setter to false removes the value' do @user1.write = false assert_equal %i[read execute], @user1.permissions @@ -76,57 +76,57 @@ def setup assert_equal %i[read execute].sort, @user1.permissions.sort end - test "setting the attribute with strings adds the values" do + test 'setting the attribute with strings adds the values' do @user3.update(permissions: %w[read write]) assert_equal %i[read write], @user3.permissions updated = false - callback = lambda { |_name, _start, _finish, _id, payload| updated = true if payload[:sql].starts_with?("UPDATE") } + callback = ->(_name, _start, _finish, _id, payload) { updated = true if payload[:sql].starts_with?('UPDATE') } - ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do + ActiveSupport::Notifications.subscribed(callback, 'sql.active_record') do @user3.update(permissions: %w[read write]) end - refute updated, "subsequent updates with the same values should be idempotent" + assert_not updated, 'subsequent updates with the same values should be idempotent' end - test "using a bang method properly updates the persisted field" do + test 'using a bang method properly updates the persisted field' do @user3.read! @user3.reload assert_equal %i[read execute], @user3.permissions end - test "methods respect _prefix" do + test 'methods respect _prefix' do assert @user1.facial_features_nose? - refute @user1.facial_features_mouth? - refute @user1.facial_features_eyes? + assert_not @user1.facial_features_mouth? + assert_not @user1.facial_features_eyes? assert @user1.consumes_cigarettes? assert @user1.consumes_alcohol? - refute @user1.consumes_greens? + assert_not @user1.consumes_greens? end - test "update with prefix" do + test 'update with prefix' do assert @user1.consumes_cigarettes? - refute @user1.consumes_greens? + assert_not @user1.consumes_greens? @user1.update!(consumes_cigarettes: true) - refute @user1.consumes_greens? + assert_not @user1.consumes_greens? end - test "recognizes boolean params" do - @user1.update!(ActionController::Parameters.new({"consumes_cigarettes" => "false"}).permit(:consumes_cigarettes)) - refute @user1.consumes_cigarettes? + test 'recognizes boolean params' do + @user1.update!(ActionController::Parameters.new({ 'consumes_cigarettes' => 'false' }).permit(:consumes_cigarettes)) + assert_not @user1.consumes_cigarettes? end - test "methods respect _suffix" do - refute @user1.car_transport? - refute @user1.truck_transport? + test 'methods respect _suffix' do + assert_not @user1.car_transport? + assert_not @user1.truck_transport? assert @user1.submarine_transport? assert @user1.box_home? - refute @user1.apartment_home? - refute @user1.house_home? + assert_not @user1.apartment_home? + assert_not @user1.house_home? end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 2c682a6..60ecf94 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,26 +1,26 @@ # frozen_string_literal: true -require "simplecov" +require 'simplecov' SimpleCov.start do enable_coverage :branch - add_filter "/test/dummy/" + add_filter '/test/dummy/' - if ENV["CI"] - require "simplecov-cobertura" + if ENV['CI'] + require 'simplecov-cobertura' SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter end end # Configure Rails Environment -ENV["RAILS_ENV"] = "test" +ENV['RAILS_ENV'] = 'test' -require_relative "../test/dummy/config/environment" -ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)] -require "rails/test_help" +require_relative '../test/dummy/config/environment' +ActiveRecord::Migrator.migrations_paths = [File.expand_path('../test/dummy/db/migrate', __dir__)] +require 'rails/test_help' # Load fixtures from the engine if ActiveSupport::TestCase.respond_to?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) + ActiveSupport::TestCase.fixture_path = File.expand_path('fixtures', __dir__) ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path ActiveSupport::TestCase.file_fixture_path = "#{ActiveSupport::TestCase.fixture_path}/files" ActiveSupport::TestCase.fixtures :all From d239f261e0c1c3d8b8e8c4e0b7c3e37b634640a2 Mon Sep 17 00:00:00 2001 From: Jamie Schembri Date: Wed, 30 Jul 2025 10:15:15 +0200 Subject: [PATCH 2/4] fix: minor stylistic changes These should *not* affect behaviour, however this is Ruby. --- lib/enummer/enummer_type.rb | 2 +- lib/enummer/extension.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/enummer/enummer_type.rb b/lib/enummer/enummer_type.rb index 3e113d0..334c8f0 100644 --- a/lib/enummer/enummer_type.rb +++ b/lib/enummer/enummer_type.rb @@ -31,7 +31,7 @@ def deserialize(value) return [] if value.to_i.zero? @values.each_with_object([]) do |(pair_name, pair_value), value_names| - next if (value & pair_value).zero? + next if value.nobits?(pair_value) value_names << pair_name end diff --git a/lib/enummer/extension.rb b/lib/enummer/extension.rb index 90efec1..6c8acd6 100644 --- a/lib/enummer/extension.rb +++ b/lib/enummer/extension.rb @@ -27,7 +27,7 @@ def enummer(values) def _enummer_build_with_scope(attribute_name, values) scope "with_#{attribute_name}", lambda { |desired| - expected = Array.wrap(desired).sum(0) { |value| values[value.to_sym] } + expected = Array.wrap(desired).sum { |value| values[value.to_sym] } where("#{attribute_name} & :expected = :expected", expected: expected) } From d21ecdf110b9bd9e3934b944583c8b0ea001bd41 Mon Sep 17 00:00:00 2001 From: Jamie Schembri Date: Wed, 30 Jul 2025 10:17:22 +0200 Subject: [PATCH 3/4] chore: line length fix --- lib/enummer/extension.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/enummer/extension.rb b/lib/enummer/extension.rb index 6c8acd6..dd86595 100644 --- a/lib/enummer/extension.rb +++ b/lib/enummer/extension.rb @@ -2,10 +2,13 @@ module Enummer module Extension - # @param [Hash] values The attribute name to options mapping for an multi-option enum - # @option values [Boolean|String] :_prefix The prefix to give to generated methods. If true, uses the attribute name. - # @option values [Boolean|String] :_suffix The suffix to give to generated methods. If true, uses the attribute name. - # @example Defining an enummer with a prefix. This would generate `#can_read?`, `#can_read=`, `#can_read!`, `.can_read`, etc. + # @param [Hash] values The attribute name to options mapping for a multi-option enum + # @option values [Boolean|String] :_prefix The prefix to give to generated methods. If true, uses the + # attribute name. + # @option values [Boolean|String] :_suffix The suffix to give to generated methods. If true, uses the + # attribute name. + # @example Defining an enummer with a prefix. This would generate `#can_read?`, `#can_read=`, `#can_read!`, + # `.can_read`, etc. # enummer permissions: %i[read write execute], :_prefix: 'can' def enummer(values) options = {} From a25b7a4e1abd1f117d5a96fbc25a7880d4c3a4c5 Mon Sep 17 00:00:00 2001 From: Jamie Schembri Date: Wed, 30 Jul 2025 10:17:49 +0200 Subject: [PATCH 4/4] fix: call super on enummer type initialize --- lib/enummer/enummer_type.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/enummer/enummer_type.rb b/lib/enummer/enummer_type.rb index 334c8f0..7a1e081 100644 --- a/lib/enummer/enummer_type.rb +++ b/lib/enummer/enummer_type.rb @@ -6,6 +6,7 @@ module Enummer class EnummerType < ::ActiveRecord::Type::Value # @param [Array] values hash with bit-value pairs for all possible values for this type def initialize(values:) + super @values = values end