diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b4ea5ba --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog +All notable changes to this project will be documented in this file. + +This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.1.2 + +### Added + +- basic tests for a library + +### Changed + +- #ensure__may_transition_to! method now actually verifies that an attribute can transition to a new state. + +## 0.1.1 + +### Added + +- Provide real authorts of this gem. + +## 0.1.0 + +- Initial release diff --git a/Gemfile.lock b/Gemfile.lock index a1ea20d..0e710c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,12 +1,18 @@ PATH remote: . specs: - state_machine_enum (0.1.1) - activesupport (>= 6.0) + state_machine_enum (0.1.2) + activesupport (~> 7) GEM remote: https://rubygems.org/ specs: + activemodel (7.1.3.3) + activesupport (= 7.1.3.3) + activerecord (7.1.3.3) + activemodel (= 7.1.3.3) + activesupport (= 7.1.3.3) + timeout (>= 0.4.0) activesupport (7.1.3.3) base64 bigdecimal @@ -28,6 +34,7 @@ GEM json (2.7.2) language_server-protocol (3.17.0.3) lint_roller (1.1.0) + mini_portile2 (2.8.7) minitest (5.23.1) mutex_m (0.2.0) parallel (1.24.0) @@ -57,6 +64,9 @@ GEM rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (1.13.0) + sqlite3 (1.7.3) + mini_portile2 (~> 2.8.0) + sqlite3 (1.7.3-arm64-darwin) standard (1.36.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) @@ -70,6 +80,7 @@ GEM lint_roller (~> 1.1) rubocop-performance (~> 1.21.0) strscan (3.1.0) + timeout (0.4.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) @@ -79,8 +90,10 @@ PLATFORMS ruby DEPENDENCIES + activerecord (~> 7) minitest (~> 5.16) rake (~> 13.0) + sqlite3 (~> 1.4) standard (~> 1.3) state_machine_enum! diff --git a/lib/state_machine_enum.rb b/lib/state_machine_enum.rb index 88e0e20..03b3120 100644 --- a/lib/state_machine_enum.rb +++ b/lib/state_machine_enum.rb @@ -114,6 +114,7 @@ def state_machine_enum(attribute_name, **options_for_enum) define_method(:"ensure_#{attribute_name}_may_transition_to!") do |next_state| val = self[attribute_name] raise InvalidState, "#{attribute_name} already is #{val.inspect}" if next_state.to_s == val + raise InvalidState, "#{attribute_name} may not transition from #{val.inspect} to #{next_state.inspect}" unless collector.may_transition?(val, next_state) end define_method(:"#{attribute_name}_may_transition_to?") do |next_state| diff --git a/lib/state_machine_enum/version.rb b/lib/state_machine_enum/version.rb index fa74b91..b9ae0cd 100644 --- a/lib/state_machine_enum/version.rb +++ b/lib/state_machine_enum/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module StateMachineEnum - VERSION = "0.1.1" + VERSION = "0.1.2" end diff --git a/state_machine_enum.gemspec b/state_machine_enum.gemspec index 9ace760..c4637d9 100644 --- a/state_machine_enum.gemspec +++ b/state_machine_enum.gemspec @@ -14,11 +14,9 @@ Gem::Specification.new do |spec| spec.license = "MIT" spec.required_ruby_version = ">= 3.0.0" - # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" - spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = "https://github.com/cheddar-me/state_machine_enum" - #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." + spec.metadata["changelog_uri"] = "https://github.com/cheddar-me/state_machine_enum/blob/main/CHANGELOG.md" # 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. @@ -29,9 +27,9 @@ Gem::Specification.new do |spec| f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) end end - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_dependency "activesupport", ">= 6.0" + spec.add_dependency "activesupport", "~> 7" + spec.add_development_dependency "sqlite3", "~> 1.4" + spec.add_development_dependency "activerecord", "~> 7" end diff --git a/test/test_helper.rb b/test/test_helper.rb index 18a5dd3..8a8c55e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -4,3 +4,22 @@ require "state_machine_enum" require "minitest/autorun" +require "active_support" +require "active_support/test_case" +require "active_record" + +class ActiveSupport::TestCase + def setup + ActiveRecord::Migration.verbose = false + ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") + ActiveRecord::Schema.define do + create_table :users, force: true do |t| + t.string :state, default: "registered" + end + end + end + + def teardown + ActiveRecord::Base.connection.disconnect! + end +end diff --git a/test/test_state_machine_enum.rb b/test/test_state_machine_enum.rb index c5c1dc2..1bf2456 100644 --- a/test/test_state_machine_enum.rb +++ b/test/test_state_machine_enum.rb @@ -2,12 +2,72 @@ require "test_helper" -class TestStateMachineEnum < Minitest::Test - def test_that_it_has_a_version_number - refute_nil ::StateMachineEnum::VERSION +class TestStateMachineEnum < ActiveSupport::TestCase + class User < ActiveRecord::Base + include StateMachineEnum + + state_machine_enum :state do |s| + s.permit_transition(:registered, :active) + s.permit_transition(:active, :banned) + s.permit_transition(:banned, :active) + s.permit_transition(:active, :deleted) + end + end + + def test_state_transitions + u = User.create! + + assert u.active! + assert u.banned! + assert u.active! + assert u.deleted! + end + + def test_callbacks + u = User.create! + + assert u.active! + error = assert_raises(ActiveRecord::RecordInvalid) { u.registered! } + assert_equal("Validation failed: State Invalid transition from active to registered", error.message) + + error = assert_raises(ArgumentError) { u.update!(state: "missing") } + assert_equal("'missing' is not a valid state", error.message) + end + + def test_ensure_state_may_transition_to! + u = User.create!(state: "active") + + assert_nil u.ensure_state_may_transition_to!(:banned) + + assert_raises(StateMachineEnum::InvalidState) { u.ensure_state_may_transition_to!("active") } + error = assert_raises(StateMachineEnum::InvalidState) { u.ensure_state_may_transition_to!(:active) } + assert_equal("state already is \"active\"", error.message) + + error = assert_raises(StateMachineEnum::InvalidState) { u.ensure_state_may_transition_to!(:registered) } + assert_equal("state may not transition from \"active\" to :registered", error.message) + end + + def test_ensure_state_one_of! + u = User.create!(state: "active") + + assert_nil u.ensure_state_one_of!(:active, :banned) + assert_nil u.ensure_state_one_of!("active", "banned") + + error = assert_raises(StateMachineEnum::InvalidState) { u.ensure_state_one_of!(:banned, :deleted) } + assert_equal("state must be one of [:banned, :deleted] but was \"active\"", error.message) + + error = assert_raises(StateMachineEnum::InvalidState) { u.ensure_state_one_of!("banned", "deleted") } + assert_equal("state must be one of [\"banned\", \"deleted\"] but was \"active\"", error.message) end - def test_it_does_something_useful - assert false + def test_may_transition_to? + u = User.create! + + assert u.active! + + assert u.state_may_transition_to?(:banned) + assert u.state_may_transition_to?("banned") + refute u.state_may_transition_to?(:registered) + refute u.state_may_transition_to?(:missing) end end