Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support STI and inheritance(with test) #34

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

unasuke
Copy link

@unasuke unasuke commented May 11, 2018

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>'
=========================================================================================================

@amatsuda
Copy link
Owner

@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).

@unasuke
Copy link
Author

unasuke commented Jun 18, 2018

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants