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..7a1e081 100644 --- a/lib/enummer/enummer_type.rb +++ b/lib/enummer/enummer_type.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require "active_record/type" +require 'active_record/type' 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 @@ -13,7 +14,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 @@ -31,7 +32,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 e1c881b..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 = {} @@ -27,7 +30,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) } @@ -59,7 +62,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