stateful_enum
stateful_enum copied to clipboard
Support STI and inheritance(with test)
dups #29 .But I wrote test.
Original pull request description is below.
I used the gem on a STI class and got an error which would be solved with using on self.class => self.class.base_class.
It would be nice if you could do a patch release with this fix.
Thank you in advance!!
If use stateful_enum on STI model, raise that error.
/home/unasuke/src/github.com/unasuke/stateful_enum/test/mechanic_machine_test.rb:18:in `test_transition_to_sti'
15: special_bug = SpecialBug.new
16: assert_equal 'unassigned', special_bug.status
17: special_bug.assigned_to = User.create!(name: 'user 1')
=> 18: special_bug.assign
19: assert_equal 'assigned', special_bug.status
20: end
21:
/home/unasuke/src/github.com/unasuke/stateful_enum/lib/stateful_enum/machine.rb:56:in `block (2 levels) in initialize'
/home/unasuke/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.2.0/lib/active_support/callbacks.rb:98:in `run_callbacks'
/home/unasuke/src/github.com/unasuke/stateful_enum/lib/stateful_enum/machine.rb:57:in `block (3 levels) in initialize'
/home/unasuke/src/github.com/unasuke/stateful_enum/lib/stateful_enum/machine.rb:57:in `instance_method'
Error: test_transition_to_sti(StatefulEnumTest): NameError: undefined method `assigned!' for module `#<Module:0x0000564443546130>'
=========================================================================================================
@raskhadafi @unasuke Nice, but what's gonna happen if we created multiple STI child classes, and then declared enums on each of these? e.g.
class Bug < ActiveRecord::Base
self.abstract_class = true
end
class NormalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3} do
...
end
end
class CriticalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3, released: 4} do
...
end
end
So, maybe we can fallback to base_class only if the current class has no enum declared?
Moreover, there can be enums with the same name on BOTH parent and children classes, and I'm not sure what's the desired behavior in such case. You're proposing to fallback on the parent class' method, but I guess that's not how AR built-in enum works (I guess. I mean, I just guess. Haven't actually tried).
I confirmed the current behavior of stateful_enum and it seems good for me. (STI doesn't work when base_class is an abstract class)
How do you think @amatsuda ? Is it test cases lack some edge-case?
and... @raskhadafi, do you think about this?
class Bug < ActiveRecord::Base
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3} do
event :assign do
transition :unassigned => :assigned
end
end
end
class NormalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3} do
event :assign do
transition :closed => :assigned
end
event :resolve do
transition [:unassigned, :assigned] => :resolved
end
end
end
class CriticalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3, released: 4} do
event :assign do
transition :closed => :assigned
end
event :release do
transition :resolved => :released
end
end
end
class BugTest < Minitest::Test
def test_bug_cannnot_resolve
bug = Bug.create!(status: :unassigned)
assert_raises(NoMethodError) do
bug.resolve
end
end
def test_normal_bug_can_resolve
normal_bug = NormalBug.create!(status: :unassigned)
normal_bug.resolve
assert_equal 'resolved', normal_bug.status
end
def test_unassigned_critical_big_cannot_assign
critical_bug = CriticalBug.create!(status: :unassigned)
critical_bug.assign
assert_equal 'unassigned', critical_bug.status
end
end
sample code(full)
# frozen_string_literal: true
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
#gem "rails", github: "rails/rails"
gem "rails", '5.2.0'
gem "sqlite3"
gem 'stateful_enum', git: 'https://github.com/unasuke/stateful_enum.git', ref: '6f6e18b1d'
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :bugs, force: true do |t|
t.integer :status
t.string :type
end
end
class Bug < ActiveRecord::Base
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3} do
event :assign do
transition :unassigned => :assigned
end
end
end
class NormalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3} do
event :assign do
transition :closed => :assigned
end
event :resolve do
transition [:unassigned, :assigned] => :resolved
end
end
end
class CriticalBug < Bug
enum status: {unassigned: 0, assigned: 1, resolved: 2, closed: 3, released: 4} do
event :assign do
transition :closed => :assigned
end
event :release do
transition :resolved => :released
end
end
end
class BugTest < Minitest::Test
def test_bug_cannnot_resolve
bug = Bug.create!(status: :unassigned)
assert_raises(NoMethodError) do
bug.resolve
end
end
def test_normal_bug_can_resolve
normal_bug = NormalBug.create!(status: :unassigned)
normal_bug.resolve
assert_equal 'resolved', normal_bug.status
end
def test_unassigned_critical_big_cannot_assign
critical_bug = CriticalBug.create!(status: :unassigned)
critical_bug.assign
assert_equal 'unassigned', critical_bug.status
end
end