Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: betacraft/rich_enums
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.1.4
Choose a base ref
...
head repository: betacraft/rich_enums
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.1.5
Choose a head ref
  • 7 commits
  • 10 files changed
  • 3 contributors

Commits on Jul 5, 2024

  1. Add alt_name_to_ids method for enum value to string mapping

    aldinrozario committed Jul 5, 2024
    Copy the full SHA
    b58c26d View commit details
  2. Merge pull request #4 from aldinrozario/feature/alt-name-to-ids-metho…

    …d-for-mapping
    
    Add alt_name_to_ids method for enum value to string mapping
    harunkumars authored Jul 5, 2024
    Copy the full SHA
    5ef7213 View commit details

Commits on Aug 21, 2024

  1. Copy the full SHA
    16b0de1 View commit details
  2. Copy the full SHA
    d403fe2 View commit details
  3. Copy the full SHA
    9003239 View commit details
  4. feature(spec) validate that the enum was indeed defined on the model …

    …with both old and new syntax
    harunkumars committed Aug 21, 2024
    Copy the full SHA
    26c8e45 View commit details
  5. Merge pull request #7 from betacraft/address_rails_8_enum_syntax_depr…

    …ecation
    
    Address rails 8 enum syntax deprecation
    harunkumars authored Aug 21, 2024
    Copy the full SHA
    fb7d848 View commit details
Showing with 253 additions and 29 deletions.
  1. +2 −0 .github/workflows/ci.yml
  2. +1 −1 .ruby-version
  3. +1 −1 Gemfile.lock
  4. +2 −0 README.md
  5. +72 −0 gemfiles/activerecord_7.1.gemfile.lock
  6. +8 −0 gemfiles/activerecord_7.2.gemfile
  7. +74 −0 gemfiles/activerecord_7.2.gemfile.lock
  8. +24 −7 lib/rich_enums.rb
  9. +1 −1 lib/rich_enums/version.rb
  10. +68 −19 spec/rich_enums_spec.rb
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ jobs:
strategy:
matrix:
include:
- ruby: '3.3'
rails: '7.2'
- ruby: '3.2'
rails: '7.1'
- ruby: '3.2'
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.1
3.3.4
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
rich_enums (0.1.4)
rich_enums (0.1.5)
activerecord (>= 6.1, < 8.0)

GEM
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ user.role_code # => 'ROLE001'
user.role_for_database # => 1
User.roles # => {"admin"=>1, "user"=>2}
User.role_codes # => {"admin"=>"ROLE001", "user"=>"ROLE101"}
User.role_alt_name_to_ids # => {"ROLE001"=>1, "ROLE101"=>2}

```

@@ -61,6 +62,7 @@ user.role_alt_name # => 'ROLE001'
user.role_for_database # => 1
User.roles # => {"admin"=>1, "user"=>2}
User.role_alt_names # => {"admin"=>"ROLE001", "user"=>"ROLE101"}
User.role_alt_name_to_ids # => {"ROLE001"=>1, "ROLE101"=>2}
ExternalSystem.sync(user.external_id, role_code: user.role_alt_name)
```
Any arguments other than 'alt' are forwarded to the default enum definition.
72 changes: 72 additions & 0 deletions gemfiles/activerecord_7.1.gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
PATH
remote: ..
specs:
rich_enums (0.1.5)
activerecord (>= 6.1, < 8.0)

GEM
remote: https://rubygems.org/
specs:
activemodel (7.1.3.2)
activesupport (= 7.1.3.2)
activerecord (7.1.3.2)
activemodel (= 7.1.3.2)
activesupport (= 7.1.3.2)
timeout (>= 0.4.0)
activesupport (7.1.3.2)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
base64 (0.2.0)
bigdecimal (3.1.7)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
diff-lcs (1.5.1)
drb (2.2.1)
i18n (1.14.4)
concurrent-ruby (~> 1.0)
minitest (5.22.3)
mutex_m (0.2.0)
rake (12.3.3)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
sqlite3 (1.7.3-arm64-darwin)
sqlite3 (1.7.3-x86_64-darwin)
temping (4.1.1)
activerecord (>= 6.0, < 7.2)
activesupport (>= 6.0, < 7.2)
timeout (0.4.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)

PLATFORMS
arm64-darwin-23
x86_64-darwin-21

DEPENDENCIES
activerecord (~> 7.1)
rake (~> 12.0)
rich_enums!
rspec (~> 3.0)
sqlite3 (~> 1.4)
temping (~> 4.1)

BUNDLED WITH
2.5.16
8 changes: 8 additions & 0 deletions gemfiles/activerecord_7.2.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source "https://rubygems.org"

gem "activerecord", "~> 7.2"
gem "rake", "~> 12.0"
gem "rspec", "~> 3.0"

# Specify your gem's dependencies in rich_enums.gemspec
gemspec path: "../"
74 changes: 74 additions & 0 deletions gemfiles/activerecord_7.2.gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
PATH
remote: ..
specs:
rich_enums (0.1.5)
activerecord (>= 6.1, < 8.0)

GEM
remote: https://rubygems.org/
specs:
activemodel (7.2.0)
activesupport (= 7.2.0)
activerecord (7.2.0)
activemodel (= 7.2.0)
activesupport (= 7.2.0)
timeout (>= 0.4.0)
activesupport (7.2.0)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
base64 (0.2.0)
bigdecimal (3.1.8)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
diff-lcs (1.5.1)
drb (2.2.1)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
logger (1.6.0)
minitest (5.25.1)
rake (12.3.3)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
securerandom (0.3.1)
sqlite3 (1.7.3-arm64-darwin)
sqlite3 (1.7.3-x86_64-darwin)
temping (4.2.0)
activerecord (>= 6.0, < 7.3)
activesupport (>= 6.0, < 7.3)
timeout (0.4.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)

PLATFORMS
arm64-darwin-23
x86_64-darwin-21

DEPENDENCIES
activerecord (~> 7.2)
rake (~> 12.0)
rich_enums!
rspec (~> 3.0)
sqlite3 (~> 1.4)
temping (~> 4.1)

BUNDLED WITH
2.5.16
31 changes: 24 additions & 7 deletions lib/rich_enums.rb
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ def rich_enum(column_symbol_value_string_options)
# and
# 2. Class method "column1_names" that will map the enum values to the full String description
# and can be accessed by ClassName.<column>_names which will return a hash like { symbol1: string1, symbol2: string2 ...}
# 3. Class method "column1_alt_name_to_ids" will map the enum values the string values and can
# be accessed by ClassName.<column>_alt_name_to_ids which will return a hash like { string1: value1, string2: value2 ...}
# e.g.
# class Enrollment
# include RichEnums
@@ -31,6 +33,9 @@ def rich_enum(column_symbol_value_string_options)
# Calling learner_payment_path_names returns
# {"greenfig_online"=>"GreenFig Online", "partner"=>"Partner", "partner_online"=>"Partner Online",
# "po_check"=>"P.O. / Check", "other"=>"Other"}
# iii. a class method called learner_payment_path_alt_name_to_ids
# Calling learner_payment_path_alt_name_to_ids returns
# {"GreenFig Online"=>10, "Partner"=>20, "Partner Online"=>30, "P.O. / Check"=>40, "Other"=>100}
# 3. Instance method "column1_name" will return the String associated with the enum value
# e = Enrollment.new
# e.learner_payment_path_po_check! -> normal enum method to update the object with enum value
@@ -57,21 +62,33 @@ def rich_enum(column_symbol_value_string_options)
options = column_symbol_value_string_options
# we allow for an option called alt: to allow the users to tag the alternate mapping. Defaults to 'alt_name'
alt = options.delete(:alt).to_s || 'alt_name'
alt_map_method = 'alt_name_to_ids'

# create two hashes from the provided input - 1 to be used to define the enum and the other for the name map
split_hash = symbol_value_string.each_with_object({ for_enum: {}, for_display: {} }) do |(symbol, value_string), obj|
obj[:for_enum][symbol] = value_string.is_a?(Array) ? value_string[0] : value_string
obj[:for_display][symbol.to_s] = value_string.is_a?(Array) ? value_string[1] : symbol.to_s
split_hash = symbol_value_string.each_with_object({ for_enum: {}, for_display: {}, for_filter: {} }) do |(symbol, value_string), obj|
value = value_string.is_a?(Array) ? value_string.first : value_string
display_string = value_string.is_a?(Array) ? value_string.second : symbol.to_s

obj[:for_enum][symbol] = value
obj[:for_display][symbol.to_s] = display_string
obj[:for_filter][display_string] = value
end

# 1. Define the Enum
enum "#{column}": split_hash[:for_enum], **options
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('7.2')
enum column, split_hash[:for_enum], **options
else
enum "#{column}": split_hash[:for_enum], **options
end

# 2. Define our custom class method
# - the data to be returned by our custom method is available os a class instance variable
# 2. Define our custom class methods
# - the data to be returned by our custom methods is available as a class instance variable
instance_variable_set("@#{column}_#{alt.pluralize}", split_hash[:for_display])
# - the custom method is just a getter for the class instance variable
instance_variable_set("@#{column}_#{alt_map_method}", split_hash[:for_filter])

# - the custom methods are just a getter for the class instance variables
define_singleton_method("#{column}_#{alt.pluralize}") { instance_variable_get("@#{column}_#{alt.pluralize}") }
define_singleton_method("#{column}_#{alt_map_method}") { instance_variable_get("@#{column}_#{alt_map_method}") }

# 3. Define our custom instance method to show the String associated with the enum value
define_method("#{column}_#{alt}") { self.class.send("#{column}_#{alt.pluralize}")[send(column.to_s)] }
2 changes: 1 addition & 1 deletion lib/rich_enums/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module RichEnums
VERSION = '0.1.4'
VERSION = '0.1.5'
end
87 changes: 68 additions & 19 deletions spec/rich_enums_spec.rb
Original file line number Diff line number Diff line change
@@ -44,29 +44,54 @@
end
end

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('7.2')
it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original

course_class.rich_enum status: { active: 0, inactive: 1 }, alt: :name
# it passes only the necessary arguments to the enum method, stripping out the alt: option
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 })
end
course_class.rich_enum status: { active: 0, inactive: 1 }, alt: :name
expect(course_class).to have_received(:enum).with(:status, { active: 0, inactive: 1 })
expect(course_class.defined_enums).to include("status")
end

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original
it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original

course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, alt: :name
# it passes only the necessary arguments to the enum method,
# stripping out the alternate names LIVE and NOT_LIVE and the alt: option
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 })
end
course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, alt: :name
expect(course_class).to have_received(:enum).with(:status, { active: 0, inactive: 1 })
expect(course_class.defined_enums).to include("status")
end

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original
course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, prefix: true, alt: 'state'

expect(course_class).to have_received(:enum).with(:status, { active: 0, inactive: 1 }, prefix: true)
expect(course_class.defined_enums).to include("status")
end
else
it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original

course_class.rich_enum status: { active: 0, inactive: 1 }, alt: :name
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 })
expect(course_class.defined_enums).to include("status")
end

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original

course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, alt: :name
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 })
expect(course_class.defined_enums).to include("status")
end

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original
course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, _prefix: true, alt: 'state'

it "invokes the enum method with the correct arguments" do
allow(course_class).to receive(:enum).and_call_original
course_class.rich_enum status: { active: [0, 'LIVE'], inactive: [1, 'NOT_LIVE'] }, _prefix: true, alt: 'state'
# it passes only the necessary arguments to the enum method,
# stripping out the alternate names LIVE and NOT_LIVE and the alt: option
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 }, _prefix: true)
expect(course_class).to have_received(:enum).with(status: { active: 0, inactive: 1 }, _prefix: true)
expect(course_class.defined_enums).to include("status")
end
end
end

@@ -145,5 +170,29 @@
expect(test_instance.status_name).to eq("NOT_LIVE")
end
end

context "alternate name to ID mapping" do
let(:test_class) do
Temping.create(:test_class) do
with_columns do |t|
t.integer :status
end

include RichEnums
rich_enum status: {
active: [0, 'LIVE'],
inactive: [1, 'NOT_LIVE']
}, alt: 'name'
end
end

it "returns correct mapping of alternate names to enum values" do
expected_mapping = {
"LIVE" => 0,
"NOT_LIVE" => 1
}
expect(test_class.status_alt_name_to_ids).to eq(expected_mapping)
end
end
end
end