estate 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0777265b6deae44f96eb4fbc8f150bb73b1f2d98849107b9750eeb0ac025ca49
4
- data.tar.gz: 916c2a835c05ed793d87e25883cb6999ebf87687c260f39eba90e994cf0aa228
3
+ metadata.gz: 71bb34f3ba838cee7a69c1c149e10fa539f074d887503dc97e02818a05c8712b
4
+ data.tar.gz: 97e67199bd544a360a0b7da92a6321144d1bfce380d15463c929c540713ffcce
5
5
  SHA512:
6
- metadata.gz: 37e595f2f4451386df31a2b563af980037c90f91786760c9c88f9090418ffd3b640473bc5c2d16a1826c3646302d2041b151a0807d106e1dbc6c85dc126bbfbd
7
- data.tar.gz: f939381283ace662a7d97169cc7e0bf26ad8d05a78eb40585f456e84768bda4474c1ae0501d5f7d232eb401d577341d2ce09f4fa3b02137adca8019e87c65114
6
+ metadata.gz: a1efa655c9bf89e4a19bd4b5840e816ad048418c509b267e569e0040f793ab2bfad11b817d7d97b19ee8cf777455da1e040cfb5e0be8abdf36900d10301a093d
7
+ data.tar.gz: 93f161f47890608d3a2ec5a92195524c6fe884a1d3a140557908f0c76402f2effcf9b5b687347b0eec07d414eca7dc2a85bf3ec87e291f6d6fccdf2573dbdcfd
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Estate Gem
4
4
 
5
- Estate is a Ruby gem designed to simplify state management in both ActiveRecord and Sequel models. The primary focus of this gem is to provide a straightforward way to define states and transitions using a clean syntax.
5
+ Estate is a Ruby gem designed to simplify state management in models, including ActiveRecord, Sequel, as well as plain Ruby objects. The primary focus of this gem is to provide a straightforward way to define states and transitions using a clean syntax.
6
6
 
7
7
  ## Installation
8
8
 
@@ -2,16 +2,6 @@
2
2
 
3
3
  module Estate
4
4
  module Configuration
5
- class << self
6
- def init_config(column_name, allow_empty_initial_state, raise_on_error)
7
- @column_name = column_name
8
- @allow_empty_initial_state = allow_empty_initial_state
9
- @raise_on_error = raise_on_error
10
- end
11
-
12
- attr_reader :column_name, :allow_empty_initial_state, :raise_on_error
13
- end
14
-
15
5
  module Defaults
16
6
  COLUMN_NAME = :state
17
7
  ALLOW_EMPTY_INITIAL_STATE = false
@@ -2,9 +2,10 @@
2
2
 
3
3
  module Estate
4
4
  module Constants
5
- module Orm
5
+ module Adapters
6
6
  ACTIVE_RECORD = 'active_record'
7
7
  SEQUEL = 'sequel'
8
+ PLAIN_RUBY_OBJECT = 'plain_ruby_object'
8
9
  end
9
10
  end
10
11
  end
data/lib/estate/estate.rb CHANGED
@@ -3,28 +3,25 @@
3
3
  module Estate
4
4
  def self.included(base)
5
5
  base.extend Estate::ClassMethods
6
-
7
- Estate::Requirements.check_requirements(base)
8
- Estate::StateMachine.create_store
9
- Estate::Setup.call(base)
10
6
  end
11
7
 
12
8
  module ClassMethods
13
9
  def estate(column: Estate::Configuration::Defaults::COLUMN_NAME,
14
10
  empty_initial_state: Estate::Configuration::Defaults::ALLOW_EMPTY_INITIAL_STATE,
15
11
  raise_on_error: Estate::Configuration::Defaults::RAISE_ON_ERROR)
16
- Estate::Configuration.init_config(column, empty_initial_state, raise_on_error)
12
+ Estate::StateMachine.init(name, column, empty_initial_state, raise_on_error)
13
+ Estate::Setup.call(self)
17
14
 
18
15
  yield if block_given?
19
16
  end
20
17
 
21
- def state(name = nil)
22
- raise(StandardError, 'state must be a Symbol or a String') unless Estate::StateMachine.argument_valid?(name)
18
+ def state(state_name = nil)
19
+ raise(StandardError, 'state must be a Symbol or a String') unless Estate::StateMachine.argument_valid?(state_name)
23
20
 
24
- if Estate::StateMachine.state_exists?(name)
25
- raise(StandardError, "state `:#{name}` is already defined")
21
+ if Estate::StateMachine.state_exists?(name, state_name)
22
+ raise(StandardError, "state `:#{state_name}` is already defined")
26
23
  else
27
- Estate::StateMachine.register_state(name)
24
+ Estate::StateMachine.register_state(name, state_name)
28
25
  end
29
26
  end
30
27
 
@@ -35,15 +32,15 @@ module Estate
35
32
 
36
33
  raise(StandardError, 'argument `to` must be a Symbol or a String') unless Estate::StateMachine.argument_valid?(to)
37
34
 
38
- raise(StandardError, "state `#{from}` is not defined") unless Estate::StateMachine.state_exists?(from)
35
+ raise(StandardError, "state `#{from}` is not defined") unless Estate::StateMachine.state_exists?(name, from)
39
36
 
40
- raise(StandardError, "state `#{to}` is not defined") unless Estate::StateMachine.state_exists?(to)
37
+ raise(StandardError, "state `#{to}` is not defined") unless Estate::StateMachine.state_exists?(name, to)
41
38
 
42
- if Estate::StateMachine.transition_exists?(from, to)
39
+ if Estate::StateMachine.transition_exists?(name, from, to)
43
40
  raise(StandardError, "`transition from: :#{from}, to: :#{to}` already defined")
44
41
  end
45
42
 
46
- Estate::StateMachine.register_transition(from, to)
43
+ Estate::StateMachine.register_transition(name, from, to)
47
44
  end
48
45
  end
49
46
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'estate/logic/common_logic'
4
+ require 'estate/logic/active_record/specific_logic'
5
+
3
6
  module Estate
4
7
  module Logic
5
8
  module ActiveRecord
@@ -9,7 +12,9 @@ module Estate
9
12
  def call(base)
10
13
  base.class_eval do
11
14
  public_send(:before_validation) do
12
- Estate::Logic::Core.call(Estate::Constants::Orm::ACTIVE_RECORD, self)
15
+ extend Estate::Logic::CommonLogic
16
+ extend Estate::Logic::ActiveRecord::SpecificLogic
17
+ validate_state_changes(self, *get_states(self))
13
18
  end
14
19
  end
15
20
  end
@@ -1,17 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'estate/logic/common_logic'
4
-
5
3
  module Estate
6
4
  module Logic
7
5
  module ActiveRecord
8
6
  module SpecificLogic
9
- extend Estate::Logic::CommonLogic
10
-
11
7
  module_function
12
8
 
13
9
  def add_error(instance, message, attribute: :base)
14
- if Estate::Configuration.raise_on_error
10
+ if config_for(instance)[:raise_on_error]
15
11
  exception_message = attribute == :base ? message : "#{attribute}: #{message}"
16
12
  raise(StandardError, exception_message)
17
13
  else
@@ -20,8 +16,8 @@ module Estate
20
16
  end
21
17
 
22
18
  def get_states(instance)
23
- from_state = instance.public_send("#{Estate::Configuration.column_name}_was")
24
- to_state = instance.public_send(Estate::Configuration.column_name)
19
+ from_state = instance.public_send("#{config_for(instance)[:column_name]}_was")
20
+ to_state = instance.public_send(config_for(instance)[:column_name])
25
21
  [from_state, to_state]
26
22
  end
27
23
  end
@@ -4,22 +4,29 @@ module Estate
4
4
  module Logic
5
5
  module CommonLogic
6
6
  def validate_state_changes(instance, from_state, to_state)
7
+ state_machine_name = instance.class.name
8
+
7
9
  if from_state == to_state
8
- if from_state.nil? && !Estate::Configuration.allow_empty_initial_state
9
- add_error(instance, "empty `#{Estate::Configuration.column_name}` is not allowed")
10
+ if from_state.nil? && !config_for(instance)[:empty_initial_state]
11
+ add_error(instance, "empty `#{config_for(instance)[:column_name]}` is not allowed")
10
12
  end
11
13
  elsif to_state.nil?
12
14
  add_error(instance, 'transition to empty state is not allowed')
13
- elsif !Estate::StateMachine.state_exists?(to_state)
15
+ elsif !Estate::StateMachine.state_exists?(state_machine_name, to_state)
14
16
  add_error(instance, "state `#{to_state}` is not defined")
15
- elsif !transition_allowed?(from_state, to_state)
17
+ elsif !transition_allowed?(state_machine_name, from_state, to_state)
16
18
  add_error(instance, "transition from `#{from_state}` to `#{to_state}` is not allowed",
17
- attribute: Estate::Configuration.column_name)
19
+ attribute: config_for(instance)[:column_name])
18
20
  end
19
21
  end
20
22
 
21
- def transition_allowed?(from_state, to_state)
22
- from_state.nil? || Estate::StateMachine.transition_exists?(from_state, to_state)
23
+ def transition_allowed?(state_machine_name, from_state, to_state)
24
+ from_state.nil? || Estate::StateMachine.transition_exists?(state_machine_name, from_state, to_state)
25
+ end
26
+
27
+ def config_for(klass)
28
+ state_machine_name = klass.is_a?(Class) ? klass.name : klass.class.name
29
+ Estate::StateMachine.state_machines[state_machine_name][:config]
23
30
  end
24
31
  end
25
32
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'estate/logic/common_logic'
4
+ require 'estate/logic/plain_ruby_object/specific_logic'
5
+
6
+ module Estate
7
+ module Logic
8
+ module PlainRubyObject
9
+ module Setup
10
+ module_function
11
+
12
+ def call(base)
13
+ base.prepend(Module.new do
14
+ extend Estate::Logic::CommonLogic
15
+
16
+ define_method("#{config_for(base)[:column_name]}=") do |new_value|
17
+ extend Estate::Logic::CommonLogic
18
+ extend Estate::Logic::PlainRubyObject::SpecificLogic
19
+
20
+ validate_state_changes(self, state, new_value)
21
+
22
+ super(new_value)
23
+ end
24
+ end)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Estate
4
+ module Logic
5
+ module PlainRubyObject
6
+ module SpecificLogic
7
+ module_function
8
+
9
+ def add_error(_, message, attribute: :base)
10
+ exception_message = attribute == :base ? message : "#{attribute}: #{message}"
11
+ raise(StandardError, exception_message)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'estate/logic/common_logic'
4
+ require 'estate/logic/sequel/specific_logic'
5
+
3
6
  module Estate
4
7
  module Logic
5
8
  module Sequel
@@ -11,7 +14,9 @@ module Estate
11
14
  def validate
12
15
  super
13
16
 
14
- Estate::Logic::Core.call(Estate::Constants::Orm::SEQUEL, self)
17
+ extend Estate::Logic::CommonLogic
18
+ extend Estate::Logic::Sequel::SpecificLogic
19
+ validate_state_changes(self, *get_states(self))
15
20
  end
16
21
  end
17
22
  end
@@ -1,13 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'estate/logic/common_logic'
4
-
5
3
  module Estate
6
4
  module Logic
7
5
  module Sequel
8
6
  module SpecificLogic
9
- extend Estate::Logic::CommonLogic
10
-
11
7
  module_function
12
8
 
13
9
  # TODO: remove :base
@@ -16,8 +12,8 @@ module Estate
16
12
  end
17
13
 
18
14
  def get_states(instance)
19
- from_state, = instance.column_change(Estate::Configuration.column_name)
20
- to_state = instance.values[Estate::Configuration.column_name]
15
+ from_state, = instance.column_change(config_for(instance)[:column_name])
16
+ to_state = instance.values[config_for(instance)[:column_name]]
21
17
  [from_state, to_state]
22
18
  end
23
19
  end
data/lib/estate/setup.rb CHANGED
@@ -5,12 +5,16 @@ module Estate
5
5
  module_function
6
6
 
7
7
  def call(base)
8
- if base.ancestors.map(&:to_s).include? 'ActiveRecord::Base'
8
+ ancestors = base.ancestors.map(&:to_s)
9
+ if ancestors.include? 'ActiveRecord::Base'
9
10
  require File.join(File.dirname(__FILE__), 'logic', 'active_record', 'setup')
10
11
  Estate::Logic::ActiveRecord::Setup.call(base)
11
- else
12
+ elsif ancestors.include? 'Sequel::Model'
12
13
  require File.join(File.dirname(__FILE__), 'logic', 'sequel', 'setup')
13
14
  Estate::Logic::Sequel::Setup.call(base)
15
+ else
16
+ require File.join(File.dirname(__FILE__), 'logic', 'plain_ruby_object', 'setup')
17
+ Estate::Logic::PlainRubyObject::Setup.call(base)
14
18
  end
15
19
  end
16
20
  end
@@ -3,34 +3,42 @@
3
3
  module Estate
4
4
  class StateMachine
5
5
  class << self
6
- def create_store
7
- @states = {}
8
- @transitions = {}
6
+ def init(state_machine_name, column_name, empty_initial_state, raise_on_error)
7
+ @state_machines ||= {}
8
+ @state_machines[state_machine_name] = {
9
+ config: {
10
+ column_name: column_name,
11
+ empty_initial_state: empty_initial_state, # TODO: allow_empty_initial_state ?
12
+ raise_on_error: raise_on_error
13
+ },
14
+ states: {},
15
+ transitions: {}
16
+ }
9
17
  end
10
18
 
11
- def state_exists?(state)
12
- states.key?(state.to_sym)
19
+ def state_exists?(state_machine_name, state_name)
20
+ state_machines[state_machine_name][:states].key?(state_name.to_sym)
13
21
  end
14
22
 
15
- def register_state(state)
16
- states[state.to_sym] = nil
23
+ def register_state(state_machine_name, state_name)
24
+ state_machines[state_machine_name][:states][state_name.to_sym] = nil
17
25
  end
18
26
 
19
- def transition_exists?(from_state, to_state)
27
+ def transition_exists?(state_machine_name, from_state, to_state)
20
28
  transition_key = { from: from_state.to_sym, to: to_state.to_sym }
21
- transitions.key?(transition_key)
29
+ state_machines[state_machine_name][:transitions].key?(transition_key)
22
30
  end
23
31
 
24
- def register_transition(from_state, to_state)
32
+ def register_transition(state_machine_name, from_state, to_state)
25
33
  transition_key = { from: from_state.to_sym, to: to_state.to_sym }
26
- transitions[transition_key] = nil
34
+ state_machines[state_machine_name][:transitions][transition_key] = nil
27
35
  end
28
36
 
29
37
  def argument_valid?(argument)
30
38
  argument.is_a?(Symbol) || argument.is_a?(String)
31
39
  end
32
40
 
33
- attr_reader :states, :transitions
41
+ attr_reader :state_machines
34
42
  end
35
43
  end
36
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Estate
4
- VERSION = '0.1.1'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/estate.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'estate/configuration'
4
- require 'estate/constants/orm'
4
+ require 'estate/constants/adapters'
5
5
  require 'estate/estate'
6
- require 'estate/logic/core'
7
- require 'estate/requirements'
8
6
  require 'estate/setup'
9
7
  require 'estate/state_machine'
10
8
  require 'estate/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: estate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Korepanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-29 00:00:00.000000000 Z
11
+ date: 2024-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -80,9 +80,9 @@ dependencies:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.22.0
83
- description: Estate is a Ruby gem designed to simplify state management in ActiveRecord
84
- models
85
- email: noemail@example.com
83
+ description: Estate is a Ruby gem designed to simplify state management in models,
84
+ as well as plain Ruby objects
85
+ email: korepanovigor87@gmail.com
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
@@ -91,15 +91,15 @@ files:
91
91
  - README.md
92
92
  - lib/estate.rb
93
93
  - lib/estate/configuration.rb
94
- - lib/estate/constants/orm.rb
94
+ - lib/estate/constants/adapters.rb
95
95
  - lib/estate/estate.rb
96
96
  - lib/estate/logic/active_record/setup.rb
97
97
  - lib/estate/logic/active_record/specific_logic.rb
98
98
  - lib/estate/logic/common_logic.rb
99
- - lib/estate/logic/core.rb
99
+ - lib/estate/logic/plain_ruby_object/setup.rb
100
+ - lib/estate/logic/plain_ruby_object/specific_logic.rb
100
101
  - lib/estate/logic/sequel/setup.rb
101
102
  - lib/estate/logic/sequel/specific_logic.rb
102
- - lib/estate/requirements.rb
103
103
  - lib/estate/setup.rb
104
104
  - lib/estate/state_machine.rb
105
105
  - lib/estate/version.rb
@@ -125,5 +125,5 @@ requirements: []
125
125
  rubygems_version: 3.2.22
126
126
  signing_key:
127
127
  specification_version: 4
128
- summary: State machine for Rails models
128
+ summary: State machine for Rails models and plain Ruby objects
129
129
  test_files: []
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Estate
4
- module Logic
5
- module Core
6
- module_function
7
-
8
- def call(orm, instance)
9
- require 'estate/logic/common_logic'
10
- require File.join(File.dirname(__FILE__), orm, 'specific_logic')
11
-
12
- extend Estate::Logic::CommonLogic
13
- extend "Estate::Logic::#{orm.classify}::SpecificLogic".safe_constantize
14
-
15
- validate_state_changes(instance, *get_states(instance))
16
- end
17
- end
18
- end
19
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Estate
4
- module Requirements
5
- def check_requirements(base)
6
- ancestors = base.ancestors.map(&:to_s)
7
-
8
- unless 'Sequel::Model'.in?(ancestors) || 'ActiveRecord::Base'.in?(ancestors)
9
- raise(StandardError, 'Estate requires ActiveRecord or Sequel')
10
- end
11
- end
12
-
13
- module_function :check_requirements
14
- end
15
- end