transitionable 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 933fdeae6a75c7c493a085742ae3beae2743a188
4
- data.tar.gz: 12a92da1cdf7e2d9e55bdcbb0f1922f88036a9c0
3
+ metadata.gz: 952f7bc9e470346c073f9e6ea3a57dfe99cdd95c
4
+ data.tar.gz: c3160957e7b0ab4084c17ca8df4e23eb2ab53717
5
5
  SHA512:
6
- metadata.gz: aa9d445044fb373bd20ac7bc2e65c0a3cf2a3d1200e3c51c4b4b44acd5dd001e5f160c37f3fc03e4b591271f43faaee7cf3b9dd2a6f617dd6a381a15204d73a3
7
- data.tar.gz: 1a064aef3e18dc2632c145d39abd84908b29e5ac53137c51d804eba47cb42d26fecd53504c3aca754ca2a2c50595232e1c9ba1dda02d660d0296accef059c2c0
6
+ metadata.gz: 8179578162e736f2a85b4a24d0e8ad7f5d8b7662b0f4581ed8cf5cf962111d262e103d4867403a829e0aa5781fbdc5bbbc724f6f896c1cd06db1a68fb477fa39
7
+ data.tar.gz: 9dba3437433e2ffd449623790055c8427d3a343d6cc99bc0bfd1854ca13a6e2cb558fbacf567e685e137421def9f140328e952d3d6c63a2e09a598bce2fe460f
data/Gemfile.lock CHANGED
@@ -1,22 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- transitionable (0.1.1)
4
+ transitionable (0.2.0)
5
5
  activesupport (~> 5.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (5.2.0)
10
+ activesupport (5.2.1)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  i18n (>= 0.7, < 2)
13
13
  minitest (~> 5.1)
14
14
  tzinfo (~> 1.1)
15
+ coderay (1.1.2)
15
16
  concurrent-ruby (1.0.5)
16
17
  diff-lcs (1.3)
17
- i18n (1.0.1)
18
+ i18n (1.1.1)
18
19
  concurrent-ruby (~> 1.0)
20
+ method_source (0.9.2)
19
21
  minitest (5.11.3)
22
+ pry (0.12.0)
23
+ coderay (~> 1.1.0)
24
+ method_source (~> 0.9.0)
20
25
  rake (10.5.0)
21
26
  rspec (3.8.0)
22
27
  rspec-core (~> 3.8.0)
@@ -40,6 +45,7 @@ PLATFORMS
40
45
 
41
46
  DEPENDENCIES
42
47
  bundler (~> 1.16)
48
+ pry
43
49
  rake (~> 10.0)
44
50
  rspec (~> 3.7)
45
51
  transitionable!
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A convention-based state machine that complements your models without stealing the show.
4
4
 
5
+ Multiple state machines are supported.
6
+
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
@@ -16,10 +18,12 @@ And then execute:
16
18
 
17
19
  ## Usage
18
20
 
21
+ ### Single state machine in model
22
+
19
23
  ```ruby
20
24
  class Event
21
25
 
22
- # Requires including class to define the following constants BEFORE including this module:
26
+ # By default, Transitionable assumes including class defines the following constants BEFORE including this module:
23
27
  #
24
28
  # * STATES
25
29
  # * TRANSITIONS
@@ -61,6 +65,63 @@ event.validate_transition!(target_state: 'new_state')
61
65
  # => returns true or raises Transitionable::InvalidStateTransition exception
62
66
  ```
63
67
 
68
+ ### Multiple state machines in model
69
+
70
+ ```ruby
71
+ class Event
72
+
73
+ DELIVERY_STATES = {
74
+ STAGED: 'staged',
75
+ STARTED: 'started',
76
+ COMPLETED: 'completed'
77
+ }.freeze
78
+
79
+ PREP_STATES = {
80
+ COOKING: 'cooking',
81
+ COOKED: 'cooked'
82
+ }.freeze
83
+
84
+ DELIVERY_TRANSITIONS = [
85
+ { from: DELIVERY_STATES[:STAGED], to: DELIVERY_STATES[:STARTED] },
86
+ { from: DELIVERY_STATES[:STARTED], to: DELIVERY_STATES[:COMPLETED] }
87
+ ].freeze
88
+
89
+ PREP_TRANSITIONS = [
90
+ { from: PREP_STATES[:COOKING], to: PREP_STATES[:COOKED] }
91
+ ]
92
+
93
+ include Transitionable
94
+
95
+ transition :delivery_state, DELIVERY_STATES, DELIVERY_TRANSITIONS
96
+ transition :prep_state, PREP_STATES, PREP_TRANSITIONS
97
+
98
+ end
99
+ ```
100
+
101
+ Provides the following helpers
102
+
103
+ ```ruby
104
+ event.staged?
105
+ event.started?
106
+ event.completed?
107
+ event.cooking?
108
+ event.cooked?
109
+ ```
110
+
111
+ Provides 2 validation methods
112
+
113
+ ```ruby
114
+ event.validate_transition(target_state: 'new_state')
115
+ # => returns true or false
116
+
117
+ event.validate_transition!(target_state: 'new_state')
118
+ # => returns true or raises Transitionable::InvalidStateTransition exception
119
+ ```
120
+
121
+ #### Important assumptions with multiple state machines:
122
+ * Each state must be unique across all state machines in the model. Otherwise, `InvalidStateTransition` exception will thrown as Transitionable attempts to define the same helper method multiple times.
123
+ * For the same reason, `"#{state}?"` must not be defined in your model for each of your state.
124
+
64
125
  ## Development
65
126
 
66
127
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,3 +1,3 @@
1
1
  module Transitionable
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -8,39 +8,56 @@ module Transitionable
8
8
 
9
9
  class InvalidStateTransition < StandardError
10
10
  def initialize(from_state, to_state)
11
- msg = "Can't transition from #{from_state} to #{to_state}."
11
+ msg = from_state ?
12
+ "Can't transition from #{from_state} to #{to_state}." :
13
+ "Can't transition to #{to_state}."
12
14
  super(msg)
13
15
  end
14
16
  end
15
17
 
16
18
  module ClassMethods
17
- attr_accessor :trans_column
18
-
19
- def transition(column)
20
- self.trans_column = column
21
- self::STATES.values.each do |this_state|
19
+ attr_accessor :state_machines
20
+
21
+ # This assumes states is a hash
22
+ def transition(name, states = self::STATES, transitions = self::TRANSITIONS)
23
+ self.state_machines ||= {}
24
+ self.state_machines[name] = { states: states.values, transitions: transitions }
25
+ self.state_machines[name][:states].each do |this_state|
26
+ raise 'Method already defined' if self.new.respond_to? this_state
22
27
  define_method "#{this_state}?" do
23
- transitionable_state == this_state
28
+ current_state_based_on(this_state) == this_state
24
29
  end
25
30
  end
26
31
  end
27
32
  end
28
33
 
29
- def transitionable_state
30
- self.send(self.class.trans_column)
31
- end
32
-
33
34
  def validate_transition!(target_state:)
35
+ current_state = current_state_based_on(target_state)
34
36
  unless validate_transition(target_state: target_state)
35
- raise InvalidStateTransition.new(transitionable_state, target_state)
37
+ raise InvalidStateTransition.new(current_state, target_state)
36
38
  end
37
39
  true
38
40
  end
39
41
 
40
42
  def validate_transition(target_state:)
41
- self.class::TRANSITIONS.detect do |transition|
42
- transition[:from] == transitionable_state && transition[:to] == target_state
43
- end.present? ? true : false
43
+ self.class.state_machines.each do |machine_name, machine|
44
+ next unless machine[:states].include?(target_state)
45
+ current_state = send(machine_name)
46
+ matched_transition = machine[:transitions].detect do |transition|
47
+ transition[:from] == current_state && transition[:to] == target_state
48
+ end
49
+ return matched_transition.present?
50
+ end
51
+ raise InvalidStateTransition.new(nil, target_state)
52
+ end
53
+
54
+ private
55
+
56
+ def current_state_based_on(target_state)
57
+ self.class.state_machines.each do |machine_name, machine|
58
+ return send(machine_name) if machine[:states].include?(target_state)
59
+ end
60
+ raise InvalidStateTransition.new(nil, target_state)
44
61
  end
45
62
 
46
63
  end
@@ -35,5 +35,6 @@ Gem::Specification.new do |spec|
35
35
  spec.add_development_dependency "bundler", "~> 1.16"
36
36
  spec.add_development_dependency "rake", "~> 10.0"
37
37
  spec.add_development_dependency "rspec", "~> 3.7"
38
+ spec.add_development_dependency 'pry'
38
39
  spec.add_dependency "activesupport", "~>5.2"
39
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transitionable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - zino
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-02 00:00:00.000000000 Z
11
+ date: 2018-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: activesupport
57
71
  requirement: !ruby/object:Gem::Requirement