transitions_listener 0.2.1 → 0.3.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: b80f1e14787d8e9fb36dbecdf16ab61ee0af545aad73e6eb6264ed88a676187c
4
- data.tar.gz: dbb6ec94ee53192ed571d61467a0805d3e67369953033fd1461ba89460a60a9c
3
+ metadata.gz: 89990d2302710513e08eca9a6131e56e7ce160a51d6a2beee7e78d49671d1050
4
+ data.tar.gz: 4e1996531fd05f0ef6f1796a97776517a6462b22dcbf050a5e69a27bf245f195
5
5
  SHA512:
6
- metadata.gz: a576d7536337cbfeea23b48061d974f3670cf9002dfc3fb0b05bc1e52daa1739e1fdb3775c2331eb96dd83c5227ca90be4d544d6a5c2141435a986acd8a4a31d
7
- data.tar.gz: 455b5e5d04dc184f769c4afe3e29c808488cc7eb5815667f14411015cccd8e655dcc2bd8d20bfd78659d5c37be91fc2148eacf23aa3c16a73eeb3fd1fa62b5c9
6
+ metadata.gz: 273301a304e5a9c724ab99cbcdb9b71d7a610ee0f0ef1e8a35138f83a07a8835bd1c6bce130af8171f83161c5d00824c30ae2dbc6732a903297d82479190705b
7
+ data.tar.gz: 6a24b40fb750518661fe4e18e0cb7dceb93122cb18feeeca701a107711383ce836691744a5fdf411943e90a7b28e99cbfba9bc8ce123b370831646e8ec682c21
@@ -1,3 +1,6 @@
1
+ # Release 0.3.0 (May 5, 2020)
2
+ - reformat: reformat state definitions to define using from:, to: (more understandable)
3
+
1
4
  # Release 0.2.1 (April 24, 2020)
2
5
  - Method callback does not receive transition info
3
6
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- transitions_listener (0.2.1)
4
+ transitions_listener (0.3.0)
5
5
  activerecord
6
6
  activesupport
7
7
 
data/README.md CHANGED
@@ -26,35 +26,54 @@ And then execute: ```bundle install```
26
26
  class Article < ActiveRecord::Base
27
27
  include TransitionsListener
28
28
  listen_transitions :state do
29
- after_transition active: :inactive do |article, transition|
29
+ after_transition from: :active, to: :inactive do |article, transition|
30
30
  # article.send_inactive_email
31
31
  end
32
- before_transition any => :deleted do |article, transition|
32
+ before_transition from: any, to: :deleted do |article, transition|
33
33
  # article.errors.add(:base, "not possible") if article.active_carts.any?
34
34
  end
35
35
 
36
- before_transition({ any => any }, :any_to_any_callback)
36
+ before_transition({ from: any, to: any }, if: :valid_article?, unless: :destroyed?, callback: :any_to_any_callback)
37
37
  end
38
38
 
39
39
  def any_to_any_callback
40
40
  puts "any to any callback called"
41
41
  end
42
+
43
+ def valid_article?
44
+ true
45
+ end
46
+
47
+ def destroyed?
48
+ false
49
+ end
42
50
  end
43
51
  ```
44
52
 
45
53
  ## API
46
- - ````listen_transitions(attr_name){block}```` permit to define state transitions listener for a specific model attribute
47
- - ````before_transition(states){block}```` permit to listen transitions before the new state is saved (Before update)
48
- - ````after_transition(states){block}```` permit to listen transitions after the new state was saved (After update)
49
- - ````before_transition(states, :callback_name)```` model method to listen transition callbacks
50
- - ````after_transition(states, :callback_name)```` model method to listen transition callbacks
54
+ - ````listen_transitions(attr_name){block}````
55
+ permit to define state transitions listener for a specific model attribute
56
+
57
+ - Before update
58
+ ````before_transition(states, if: :action?, unless: :action?, callback: :action) { block }````
59
+ Permit to listen transitions before the new state is saved
60
+ * states: (Mandatory) State Transition(s) to listen for
61
+ * if: (Optional) Positive conditional action(s) to execute callback. Sample: ```if: :deleted? | if: [:deleted?, :ready?]```
62
+ * unless: (Optional) Negative conditional action(s) to execute callback. Sample: ```unless: :deleted? | unless: [:deleted?, :ready?]```
63
+ * callback: (Optional) Model method to be called as a callback (Will be overridden If block is defined)
64
+
65
+ - After update (Args are similar to before update)
66
+ ````after_transition(states, if: :action?, unless: :action?, callback: :action){ block }````
67
+ permit to listen transitions after the new state was saved
68
+
51
69
 
52
70
  States can be defined as the following:
53
- - ```before_transition(any => any){}``` block will be called when attr value is changed from any value to any value
54
- - ```before_transition(any => :active){}``` block will be called when attr value is changed from any value to :active
55
- - ```before_transition(:active => any){}``` block will be called when attr value is changed from :active value to any value
56
- - ```before_transition(%i[active inactive] => %i[deleted cancelled]){}``` block will be called when attr value is changed from :active or inactive to :deleted or :cancelled
57
- - ```before_transition(active: :inactive, inactive: :deleted){}``` block will be called when attr value is changed from :active to :inactive or :inactive to :deleted
71
+ - ```before_transition(from: any, to: any){}``` block will be called when attr value is changed from any value to any value
72
+ - ```before_transition(from: any, to: :active){}``` block will be called when attr value is changed from any value to :active
73
+ - ```before_transition(from: :active, to: any){}``` block will be called when attr value is changed from :active value to any value
74
+ - ```before_transition(from: %i[active inactive], to: %i[deleted cancelled]){}``` block will be called when attr value is changed from :active or inactive to :deleted or :cancelled
75
+ - ```before_transition([{ from: :active, to: :inactive }, { from: :inactive: :deleted }]){}``` block will be called when attr value is changed from :active to :inactive or :inactive to :deleted
76
+ - ```before_transition([{ active: :inactive, inactive: :deleted }]){}``` block will be called when attr value is changed from :active to :inactive or :inactive to :deleted (Shorter state definitions. Same as above)
58
77
 
59
78
  ## Development
60
79
 
@@ -24,13 +24,11 @@ module TransitionsListener
24
24
 
25
25
  def perform_transition_listeners(model, kind = :before)
26
26
  transition_listeners.each do |listener|
27
- c_transition = current_transition_for(model, listener.attr)
28
- listener.filter_transitions(kind, c_transition).each do |transition|
29
- if transition[:block].is_a?(Proc)
30
- transition[:block].call(model, c_transition.merge(transition))
31
- else # method name
32
- model.public_send(transition[:block])
33
- end
27
+ c_trans = current_transition_for(model, listener.attr)
28
+ listener.filter_transitions(kind, model, c_trans).each do |trans|
29
+ block = trans[:args][:callback]
30
+ args = c_trans.dup.merge(trans)
31
+ block.is_a?(Proc) ? block.call(model, args) : model.public_send(block)
34
32
  end
35
33
  end
36
34
  end
@@ -8,30 +8,55 @@ module TransitionsListener
8
8
  instance_eval(&block)
9
9
  end
10
10
 
11
- def before_transition(states, callback_method = nil, &block)
12
- before_transitions(states: states, block: callback_method || block)
11
+ # @param states: (Array) Array of transitions [{ from:, to: }, {}, ...]
12
+ # Multiple transitions: [{ from: [..], to: [..] }, ...]
13
+ # Single transitions: [{ from: :state, to: :new_state }, ...]
14
+ # Single transition: { from: :state, to: :new_state }
15
+ # @param args (Hash): { callback: nil, if: nil, unless: nil }
16
+ # callback: (Sym) Method name to be used as the callback
17
+ # if: (Sym) conditional methods
18
+ # else: (Sym) conditional methods
19
+ def before_transition(states, args = {}, &block)
20
+ args[:callback] ||= block if block
21
+ before_transitions(states: parse_states(states), args: args)
13
22
  end
14
23
 
15
- def after_transition(states, callback_method = nil, &block)
16
- after_transitions(states: states, block: callback_method || block)
24
+ # @param states (Array): Same as before transitions
25
+ # @param args (Hash): Same as before args
26
+ def after_transition(states, args = {}, &block)
27
+ args[:callback] ||= block if block
28
+ after_transitions(states: parse_states(states), args: args)
17
29
  end
18
30
 
19
- def filter_transitions(kind, from:, to:)
31
+ def filter_transitions(kind, model, from:, to:)
20
32
  transitions = kind == :before ? before_transitions : after_transitions
21
33
  transitions.select do |transition|
22
- match_states?(transition[:states], from, to)
34
+ match_conditions?(model, transition) &&
35
+ match_states?(transition, from, to)
23
36
  end
24
37
  end
25
38
 
26
39
  private
27
40
 
28
- def match_states?(states, from_state, to_state)
29
- parse_states(states).any? do |t_from, t_to|
41
+ def match_states?(transition, from_state, to_state)
42
+ transition[:states].any? do |state|
43
+ t_from = state[:from]
44
+ t_to = state[:to]
30
45
  (t_from == [any] || t_from.include?(from_state.to_s)) &&
31
46
  (t_to == [any] || t_to.include?(to_state.to_s))
32
47
  end
33
48
  end
34
49
 
50
+ def match_conditions?(model, transition)
51
+ args = transition[:args]
52
+ yes_actions = Array(args[:if])
53
+ no_actions = Array(args[:unless])
54
+ return false unless yes_actions.all? { |action| model.send(action) }
55
+ return false unless no_actions.all? { |action| !model.send(action) }
56
+
57
+ true
58
+ end
59
+
35
60
  def any
36
61
  'any_transition_key'
37
62
  end
@@ -49,11 +74,15 @@ module TransitionsListener
49
74
  end
50
75
 
51
76
  def parse_states(states)
52
- states.map do |from, to|
53
- from = [from] unless from.is_a? Array
54
- to = [to] unless to.is_a? Array
55
- [from.map(&:to_s), to.map(&:to_s)]
56
- end.to_h
77
+ is_shorter_definition = states.is_a?(Hash) && !states[:from]
78
+ states = states.map { |k, v| { from: k, to: v } } if is_shorter_definition
79
+ is_single_definition = !states.is_a?(Array)
80
+ states = [states] if is_single_definition
81
+ states.map do |trans|
82
+ from = Array(trans[:from]).map(&:to_s)
83
+ to = Array(trans[:to]).map(&:to_s)
84
+ { from: from, to: to }
85
+ end
57
86
  end
58
87
  end
59
88
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TransitionsListener
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transitions_listener
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-24 00:00:00.000000000 Z
11
+ date: 2020-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord