Skip to content

Commit

Permalink
Merge pull request #3 from betacraft/specs_with_temping_gem
Browse files Browse the repository at this point in the history
Use Temping gem to test against ActiveRecord models
  • Loading branch information
harunkumars authored Apr 29, 2024
2 parents 5fad07b + f1349c3 commit 438287a
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 11 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
env:
RUBY_VERSION: 3.2.2

name: RichEnums CI
on:
pull_request:
paths-ignore:
- .gitignore
- CHANGELOG.md
- CONTRIBUTING.md
- README.md
push:
paths-ignore:
- .gitignore
- CHANGELOG.md
- CONTRIBUTING.md
- README.md

jobs:
rspec-test:
name: Run tests (ruby ${{ matrix.ruby }}, rails ${{ matrix.rails }})
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- ruby: '3.2'
rails: '7.1'
- ruby: '3.2'
rails: '7.0'
- ruby: '3.2'
rails: '6.1'
- ruby: '3.1'
rails: '6.1'
env:
BUNDLE_GEMFILE: gemfiles/activerecord_${{ matrix.rails }}.gemfile
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- name: Gem cache
uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-gem-use-ruby-${{ hashFiles('**/Gemfile.lock') }}
- name: Install dependencies
run: |
gem install bundler --version 2.3.25 --no-document
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Run tests
run: bundle exec rake spec
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.1.1
29 changes: 28 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
PATH
remote: .
specs:
rich_enums (0.1.3)
rich_enums (0.1.4)
activerecord (>= 6.1, < 8.0)

GEM
remote: https://rubygems.org/
specs:
activemodel (6.1.7.7)
activesupport (= 6.1.7.7)
activerecord (6.1.7.7)
activemodel (= 6.1.7.7)
activesupport (= 6.1.7.7)
activesupport (6.1.7.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
concurrent-ruby (1.2.3)
diff-lcs (1.5.0)
i18n (1.14.4)
concurrent-ruby (~> 1.0)
mini_portile2 (2.8.6)
minitest (5.22.3)
rake (12.3.3)
rspec (3.11.0)
rspec-core (~> 3.11.0)
Expand All @@ -21,6 +38,14 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-support (3.11.0)
sqlite3 (1.7.3)
mini_portile2 (~> 2.8.0)
temping (4.1.1)
activerecord (>= 6.0, < 7.2)
activesupport (>= 6.0, < 7.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
zeitwerk (2.6.13)

PLATFORMS
ruby
Expand All @@ -29,6 +54,8 @@ DEPENDENCIES
rake (~> 12.0)
rich_enums!
rspec (~> 3.0)
sqlite3 (~> 1.4)
temping (~> 4.1)

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

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

# Specify your gem's dependencies in rich_enums.gemspec
gemspec path: "../"
8 changes: 8 additions & 0 deletions gemfiles/activerecord_7.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source "https://rubygems.org"

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

# Specify your gem's dependencies in rich_enums.gemspec
gemspec path: "../"
8 changes: 8 additions & 0 deletions gemfiles/activerecord_7.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source "https://rubygems.org"

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

# Specify your gem's dependencies in rich_enums.gemspec
gemspec path: "../"
16 changes: 12 additions & 4 deletions lib/rich_enums.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,30 @@ def rich_enum(column_symbol_value_string_options)
# e.learner_payment_path_name --> "P.O. / Check" -> our custom method that returns the string/description
# TODO: explore if enum options in Array format instead of Hash format will need to be handled

raise 'rich_enum error' unless column_symbol_value_string_options.keys.count.positive?
unless column_symbol_value_string_options.is_a? Hash
raise RichEnums::Error
end
if column_symbol_value_string_options.keys.count.zero?
raise RichEnums::Error
end

# extract out the column
column = column_symbol_value_string_options.keys.first

# extract the Enum options for the column which may be in standard enum hash format or our custom format
symbol_value_string = column_symbol_value_string_options.delete(column)

raise RichEnums::Error unless symbol_value_string.is_a? Hash

# at this point, only the enum options like _prefix etc. are present in the original argument
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) || 'alt_name'
alt = options.delete(:alt).to_s || 'alt_name'

# 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.first : value_string
obj[:for_display][symbol.to_s] = value_string.is_a?(Array) ? value_string.second : symbol.to_s
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
end

# 1. Define the Enum
Expand Down
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.3'
VERSION = '0.1.4'
end
3 changes: 3 additions & 0 deletions rich_enums.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ DESC
spec.metadata['source_code_uri'] = 'https://github.com/betacraft/rich_enums'
spec.metadata['changelog_uri'] = 'https://github.com/betacraft/rich_enums/README.md'

spec.add_development_dependency 'sqlite3', '~> 1.4'
spec.add_development_dependency 'temping', '~> 4.1'
spec.add_runtime_dependency 'activerecord', '>= 6.1', '< 8.0'
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
Expand Down
149 changes: 144 additions & 5 deletions spec/rich_enums_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,149 @@
require "spec_helper"

RSpec.describe RichEnums do
it "has a version number" do
expect(RichEnums::VERSION).not_to be nil
describe "error scenarios" do
it "raises an error if the argument to rich_enum is not a Hash" do
expect do
Temping.create(:course_class) do
include RichEnums
rich_enum([])
end
end.to raise_error(RichEnums::Error)
end

it "raises an error if an empty Hash is passed to rich_enum" do
expect do
Temping.create(:course_class) do
include RichEnums
rich_enum({})
end
end.to raise_error(RichEnums::Error)
end

it "raises an error if the enum definition uses the Array form" do
# This is not supported yet
expect do
Temping.create(:course_class) do
include RichEnums
rich_enum({status: [:active, :inactive]})
end
end.to raise_error(RichEnums::Error)
end
end

it "does something useful" do
# TODO write tests
expect(false).to eq(true)
describe "rich_enum usage" do
context "it calls the ActiveRecord::Enum.enum method" do
let(:course_class) do
Temping.create(:course_class) do
with_columns do |t|
t.integer :status
t.string :category
end

include RichEnums
end
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, 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

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

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)
end
end

context "with only an alternate name specified without additional mapping" do
let(:course_class) do
Temping.create(:course_class) do
with_columns do |t|
t.integer :status
t.string :category
end

include RichEnums
rich_enum status: { active: 0, inactive: 1 }, alt: :name
end
end
let(:test_instance) { course_class.new }

it "defines a class method for each enum" do
expect(course_class).to respond_to(:status_names)
end

it "returns a hash of enum values and names" do
expect(course_class.status_names).to eq({"active"=>"active", "inactive"=>"inactive"})
end

it "defines an instance method for each enum" do
expect(test_instance).to respond_to(:status_name)
end

it "returns the value in response to alternate name" do
test_instance.status = 0
expect(test_instance.status_name).to eq(test_instance.status)
test_instance.status = 1
expect(test_instance.status_name).to eq(test_instance.status)
test_instance.status = :active
expect(test_instance.status_name).to eq(test_instance.status)
test_instance.status = 'inactive'
expect(test_instance.status_name).to eq(test_instance.status)
end
end

context "with an alternate name and mapping specified" do
let(:course_class) do
Temping.create(:course_class) do
with_columns do |t|
t.string :status
end

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

let(:test_instance) { course_class.new }

it "defines a class method for each enum" do
expect(course_class).to respond_to(:status_names)
end

it "returns a hash of enum values and names" do
expect(course_class.status_names).to eq({"active"=>"LIVE", "inactive"=>"NOT_LIVE"})
end

it "defines an instance method for each enum" do
expect(test_instance).to respond_to(:status_name)
end

it "returns the alternate name of the enum value" do
test_instance.status = 0
expect(test_instance.status_name).to eq("LIVE")
test_instance.status = 1
expect(test_instance.status_name).to eq("NOT_LIVE")
test_instance.status = :active
expect(test_instance.status_name).to eq("LIVE")
test_instance.status = 'inactive'
expect(test_instance.status_name).to eq("NOT_LIVE")
end
end
end
end
12 changes: 12 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "bundler/setup"
require "rich_enums"
require "temping"

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
Expand All @@ -11,4 +12,15 @@
config.expect_with :rspec do |c|
c.syntax = :expect
end

config.before(:all) do
ActiveRecord::Base.establish_connection(
adapter: "sqlite3",
database: ":memory:"
)
end

config.after do
Temping.teardown
end
end

0 comments on commit 438287a

Please sign in to comment.